    1   /*
    2    * Copyright 1999-2004 The Apache Software Foundation
    3    *
    4    * Licensed under the Apache License, Version 2.0 (the "License");
    5    * you may not use this file except in compliance with the License.
    6    * You may obtain a copy of the License at
    7    *
    8    *     http://www.apache.org/licenses/LICENSE-2.0
    9    *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  package org.apache.commons.jxpath.ri.model;
    17
    18  import java.util.ArrayList;
    19  import java.util.Collections;
    20  import java.util.HashMap;
    21  import java.util.Iterator;
    22  import java.util.List;
    23  import java.util.Locale;
    24  import java.util.Map;
    25  import java.util.Vector;
    26
    27  import junit.framework.Test;
    28  import junit.framework.TestSuite;
    29  import junit.textui.TestRunner;
    30
    31  import org.apache.commons.jxpath.JXPathContext;
    32  import org.apache.commons.jxpath.JXPathTestCase;
    33  import org.apache.commons.jxpath.Pointer;
    34  import org.apache.commons.jxpath.TestBean;
    35  import org.apache.commons.jxpath.TestMixedModelBean;
    36  import org.apache.commons.jxpath.TestNull;
    37  import org.apache.commons.jxpath.Variables;
    38
    39  /***
    40   * Tests JXPath with mixed model: beans, maps, DOM etc.
    41   *
    42   * @author Dmitri Plotnikov
    43   * @version $Revision: 1.9 $ $Date: 2004/04/04 22:06:36 $
    44   */
    45
    46  public class MixedModelTest extends JXPathTestCase {
    47      private JXPathContext context;
    48
    49      /***
    50       * Construct a new instance of this test case.
    51       *
    52       * @param name Name of the test case
    53       */
    54      public MixedModelTest(String name) {
    55          super(name);
    56      }
    57
    58      public static void main(String[] args) {
    59          TestRunner.run(new MixedModelTest("testContainerWithCollection"));
    60      }
    61
    62      /***
    63       * Return the tests included in this test suite.
    64       */
    65      public static Test suite() {
    66          return (new TestSuite(MixedModelTest.class));
    67      }
    68
    69      public void setUp() {
    70          TestMixedModelBean bean = new TestMixedModelBean();
    71          context = JXPathContext.newContext(bean);
    72          context.setFactory(new TestMixedModelFactory());
    73          context.setLocale(Locale.US);
    74          Variables vars = context.getVariables();
    75          vars.declareVariable("string", bean.getString());
    76          vars.declareVariable("bean", bean.getBean());
    77          vars.declareVariable("map", bean.getMap());
    78          vars.declareVariable("list", bean.getList());
    79          vars.declareVariable("document", bean.getDocument());
    80          vars.declareVariable("element", bean.getElement());
    81          vars.declareVariable("container", bean.getContainer());
    82          vars.declareVariable("testnull", new TestNull());
    83
    84          int[][] matrix = new int[1][];
    85          matrix[0] = new int[1];
    86          matrix[0][0] = 3;
    87          vars.declareVariable("matrix", matrix);
    88      }
    89
    90      public void testVar() {
    91          context.getVariables().declareVariable("foo:bar", "baz");
    92
    93          assertXPathValueAndPointer(context,
    94              "$foo:bar",
    95              "baz",
    96              "$foo:bar");
    97
    98      }
    99
    100     public void testVarPrimitive() {
    101         assertXPathValueAndPointer(context, "$string", "string", "$string");
    102     }
    103
    104     public void testVarBean() {
    105         assertXPathValueAndPointer(
    106             context,
    107             "$bean/int",
    108             new Integer(1),
    109             "$bean/int");
    110     }
    111
    112     public void testVarMap() {
    113         assertXPathValueAndPointer(
    114             context,
    115             "$map/string",
    116             "string",
    117             "$map[@name='string']");
    118     }
    119
    120     public void testVarList() {
    121         assertXPathValueAndPointer(context, "$list[1]", "string", "$list[1]");
    122     }
    123
    124     public void testVarDocument() {
    125         assertXPathValueAndPointer(
    126             context,
    127             "$document/vendor/location/address/city",
    128             "Fruit Market",
    129             "$document/vendor[1]/location[2]/address[1]/city[1]");
    130     }
    131
    132     public void testVarElement() {
    133         assertXPathValueAndPointer(
    134             context,
    135             "$element/location/address/city",
    136             "Fruit Market",
    137             "$element/location[2]/address[1]/city[1]");
    138     }
    139
    140     public void testVarContainer() {
    141         assertXPathValueAndPointer(
    142             context,
    143             "$container/vendor/location/address/city",
    144             "Fruit Market",
    145             "$container/vendor[1]/location[2]/address[1]/city[1]");
    146     }
    147
    148     // ----------------------------------------------------------------------
    149
    150     public void testBeanPrimitive() {
    151         assertXPathValueAndPointer(context, "string", "string", "/string");
    152     }
    153
    154     public void testBeanBean() {
    155         assertXPathValueAndPointer(
    156             context,
    157             "bean/int",
    158             new Integer(1),
    159             "/bean/int");
    160     }
    161
    162     public void testBeanMap() {
    163         assertXPathValueAndPointer(
    164             context,
    165             "map/string",
    166             "string",
    167             "/map[@name='string']");
    168     }
    169
    170     public void testBeanList() {
    171         assertXPathValueAndPointer(context, "list[1]", "string", "/list[1]");
    172     }
    173
    174     public void testBeanDocument() {
    175         assertXPathValueAndPointer(
    176             context,
    177             "document/vendor/location/address/city",
    178             "Fruit Market",
    179             "/document/vendor[1]/location[2]/address[1]/city[1]");
    180     }
    181
    182     public void testBeanElement() {
    183         assertXPathValueAndPointer(
    184             context,
    185             "element/location/address/city",
    186             "Fruit Market",
    187             "/element/location[2]/address[1]/city[1]");
    188     }
    189
    190     public void testBeanContainer() {
    191         assertXPathValueAndPointer(
    192             context,
    193             "container/vendor/location/address/city",
    194             "Fruit Market",
    195             "/container/vendor[1]/location[2]/address[1]/city[1]");
    196     }
    197
    198     // ----------------------------------------------------------------------
    199
    200     public void testMapPrimitive() {
    201         assertXPathValueAndPointer(
    202             context,
    203             "map/string",
    204             "string",
    205             "/map[@name='string']");
    206     }
    207
    208     public void testMapBean() {
    209         assertXPathValueAndPointer(
    210             context,
    211             "map/bean/int",
    212             new Integer(1),
    213             "/map[@name='bean']/int");
    214     }
    215
    216     public void testMapMap() {
    217         assertXPathValueAndPointer(
    218             context,
    219             "map/map/string",
    220             "string",
    221             "/map[@name='map'][@name='string']");
    222     }
    223
    224     public void testMapList() {
    225         assertXPathValueAndPointer(
    226             context,
    227             "map/list[1]",
    228             "string",
    229             "/map[@name='list'][1]");
    230     }
    231
    232     public void testMapDocument() {
    233         assertXPathValueAndPointer(
    234             context,
    235             "map/document/vendor/location/address/city",
    236             "Fruit Market",
    237             "/map[@name='document']"
    238                 + "/vendor[1]/location[2]/address[1]/city[1]");
    239     }
    240
    241     public void testMapElement() {
    242         assertXPathValueAndPointer(
    243             context,
    244             "map/element/location/address/city",
    245             "Fruit Market",
    246             "/map[@name='element']/location[2]/address[1]/city[1]");
    247     }
    248
    249     public void testMapContainer() {
    250         assertXPathValueAndPointer(
    251             context,
    252             "map/container/vendor/location/address/city",
    253             "Fruit Market",
    254             "/map[@name='container']"
    255                 + "/vendor[1]/location[2]/address[1]/city[1]");
    256     }
    257
    258     // ----------------------------------------------------------------------
    259
    260     public void testListPrimitive() {
    261         assertXPathValueAndPointer(context, "list[1]", "string", "/list[1]");
    262     }
    263
    264     public void testListBean() {
    265         assertXPathValueAndPointer(
    266             context,
    267             "list[2]/int",
    268             new Integer(1),
    269             "/list[2]/int");
    270     }
    271
    272     public void testListMap() {
    273         assertXPathValueAndPointer(
    274             context,
    275             "list[3]/string",
    276             "string",
    277             "/list[3][@name='string']");
    278     }
    279
    280     public void testListList() {
    281         /*** @todo: what is this supposed to do? Should we stick to XPath,
    282          *  in which case [1] is simply ignored, or Java, in which case
    283          *  it is supposed to extract the first element from the list?
    284          */
    285 //        assertXPathValueAndPointer(context,
    286 //                "list[4][1]",
    287 //                "string2",
    288 //                "/list[4][1]");
    289
    290         assertXPathValueAndPointer(
    291             context,
    292             "list[4]/.[1]",
    293             "string2",
    294             "/list[4]/.[1]");
    295     }
    296
    297     public void testListDocument() {
    298         assertXPathValueAndPointer(
    299             context,
    300             "list[5]/vendor/location/address/city",
    301             "Fruit Market",
    302             "/list[5]/vendor[1]/location[2]/address[1]/city[1]");
    303     }
    304
    305     public void testListElement() {
    306         assertXPathValueAndPointer(
    307             context,
    308             "list[6]/location/address/city",
    309             "Fruit Market",
    310             "/list[6]/location[2]/address[1]/city[1]");
    311     }
    312
    313     public void testListContainer() {
    314         assertXPathValueAndPointer(
    315             context,
    316             "list[7]/vendor/location/address/city",
    317             "Fruit Market",
    318             "/list[7]/vendor[1]/location[2]/address[1]/city[1]");
    319     }
    320
    321     public void testNull() {
    322
    323         assertXPathPointerLenient(context, "$null", "$null");
    324
    325         assertXPathPointerLenient(context, "$null[3]", "$null[3]");
    326
    327         assertXPathPointerLenient(
    328             context,
    329             "$testnull/nothing",
    330             "$testnull/nothing");
    331
    332         assertXPathPointerLenient(
    333             context,
    334             "$testnull/nothing[2]",
    335             "$testnull/nothing[2]");
    336
    337         assertXPathPointerLenient(context, "beans[8]/int", "/beans[8]/int");
    338
    339         assertXPathValueIterator(
    340             context,
    341             "$testnull/nothing[1]",
    342             Collections.EMPTY_LIST);
    343
    344         JXPathContext ctx = JXPathContext.newContext(new TestNull());
    345         assertXPathValue(ctx, "nothing", null);
    346
    347         assertXPathValue(ctx, "child/nothing", null);
    348
    349         assertXPathValue(ctx, "array[2]", null);
    350
    351         assertXPathValueLenient(ctx, "nothing/something", null);
    352
    353         assertXPathValueLenient(ctx, "array[2]/something", null);
    354     }
    355
    356     public void testRootAsCollection() {
    357         assertXPathValue(context, ".[1]/string", "string");
    358     }
    359
    360     public void testCreatePath() {
    361         context = JXPathContext.newContext(new TestBean());
    362         context.setFactory(new TestMixedModelFactory());
    363
    364         TestBean bean = (TestBean) context.getContextBean();
    365         bean.setMap(null);
    366
    367         assertXPathCreatePath(
    368             context,
    369             "/map[@name='TestKey5']/nestedBean/int",
    370             new Integer(1),
    371             "/map[@name='TestKey5']/nestedBean/int");
    372
    373         bean.setMap(null);
    374         assertXPathCreatePath(
    375             context,
    376             "/map[@name='TestKey5']/beans[2]/int",
    377             new Integer(1),
    378             "/map[@name='TestKey5']/beans[2]/int");
    379     }
    380
    381     /***
    382      * Test JXPath.iterate() with map containing an array
    383      */
    384     public void testIterateArray() {
    385         Map map = new HashMap();
    386         map.put("foo", new String[] { "a", "b", "c" });
    387
    388         JXPathContext context = JXPathContext.newContext(map);
    389
    390         assertXPathValueIterator(context, "foo", list("a", "b", "c"));
    391     }
    392
    393     public void testIteratePointersArray() {
    394         Map map = new HashMap();
    395         map.put("foo", new String[] { "a", "b", "c" });
    396
    397         JXPathContext context = JXPathContext.newContext(map);
    398
    399         Iterator it = context.iteratePointers("foo");
    400         List actual = new ArrayList();
    401         while (it.hasNext()) {
    402             Pointer ptr = (Pointer) it.next();
    403             actual.add(context.getValue(ptr.asPath()));
    404         }
    405         assertEquals(
    406             "Iterating pointers <" + "foo" + ">",
    407             list("a", "b", "c"),
    408             actual);
    409     }
    410
    411     public void testIteratePointersArrayElementWithVariable() {
    412         Map map = new HashMap();
    413         map.put("foo", new String[] { "a", "b", "c" });
    414
    415         JXPathContext context = JXPathContext.newContext(map);
    416         context.getVariables().declareVariable("x", new Integer(2));
    417         Iterator it = context.iteratePointers("foo[$x]");
    418         List actual = new ArrayList();
    419         while (it.hasNext()) {
    420             Pointer ptr = (Pointer) it.next();
    421             actual.add(context.getValue(ptr.asPath()));
    422         }
    423         assertEquals("Iterating pointers <" + "foo" + ">", list("b"), actual);
    424     }
    425
    426     public void testIterateVector() {
    427         Map map = new HashMap();
    428         Vector vec = new Vector();
    429         vec.add(new HashMap());
    430         vec.add(new HashMap());
    431
    432         map.put("vec", vec);
    433         JXPathContext context = JXPathContext.newContext(map);
    434         assertXPathPointerIterator(
    435             context,
    436             "/vec",
    437             list("/.[@name='vec'][1]", "/.[@name='vec'][2]"));
    438     }
    439
    440     public void testErrorProperty() {
    441         context.getVariables().declareVariable(
    442             "e",
    443             new ExceptionPropertyTestBean());
    444
    445         boolean ex = false;
    446         try {
    447             assertXPathValue(context, "$e/errorString", null);
    448         }
    449         catch (Throwable t) {
    450             ex = true;
    451         }
    452         assertTrue("Legitimate exception accessing property", ex);
    453
    454         assertXPathPointer(context, "$e/errorString", "$e/errorString");
    455
    456         assertXPathPointerLenient(
    457             context,
    458             "$e/errorStringArray[1]",
    459             "$e/errorStringArray[1]");
    460
    461         assertXPathPointerIterator(
    462             context,
    463             "$e/errorString",
    464             list("$e/errorString"));
    465
    466         assertXPathPointerIterator(
    467             context,
    468             "$e//error",
    469             Collections.EMPTY_LIST);
    470     }
    471
    472     public void testMatrix() {
    473         assertXPathValueAndPointer(
    474             context,
    475             "$matrix[1]/.[1]",
    476             new Integer(3),
    477             "$matrix[1]/.[1]");
    478
    479         context.setValue("$matrix[1]/.[1]", new Integer(2));
    480
    481         assertXPathValueAndPointer(
    482             context,
    483             "matrix[1]/.[1]",
    484             new Integer(3),
    485             "/matrix[1]/.[1]");
    486
    487         context.setValue("matrix[1]/.[1]", "2");
    488
    489         assertXPathValue(context, "matrix[1]/.[1]", new Integer(2));
    490
    491         context.getVariables().declareVariable(
    492             "wholebean",
    493             context.getContextBean());
    494
    495         assertXPathValueAndPointer(
    496             context,
    497             "$wholebean/matrix[1]/.[1]",
    498             new Integer(2),
    499             "$wholebean/matrix[1]/.[1]");
    500
    501         boolean ex = false;
    502         try {
    503             context.setValue("$wholebean/matrix[1]/.[2]", "4");
    504         }
    505         catch (Exception e) {
    506             ex = true;
    507         }
    508         assertTrue("Exception setting value of non-existent element", ex);
    509
    510         ex = false;
    511         try {
    512             context.setValue("$wholebean/matrix[2]/.[1]", "4");
    513         }
    514         catch (Exception e) {
    515             ex = true;
    516         }
    517         assertTrue("Exception setting value of non-existent element", ex);
    518     }
    519
    520     public void testCreatePathAndSetValueWithMatrix() {
    521
    522         context.setValue("matrix", null);
    523
    524         // Calls factory.createObject(..., TestMixedModelBean, "matrix")
    525         // Calls factory.createObject(..., nestedBean, "strings", 2)
    526         assertXPathCreatePathAndSetValue(
    527             context,
    528             "/matrix[1]/.[1]",
    529             new Integer(4),
    530             "/matrix[1]/.[1]");
    531     }
    532 }