json/src/test/java/net/java/html/json/ModelTest.java
author Jaroslav Tulach <jtulach@netbeans.org>
Wed, 09 Dec 2015 23:58:27 +0100
changeset 1025 1122c615fffd
parent 951 5ce0aab2c03c
child 1026 cda94194f901
permissions -rw-r--r--
#257086: Use inPckName to propertly specify the name of the static method
jtulach@0
     1
/**
jaroslav@358
     2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
jtulach@0
     3
 *
jaroslav@551
     4
 * Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved.
jtulach@0
     5
 *
jaroslav@358
     6
 * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
jaroslav@358
     7
 * Other names may be trademarks of their respective owners.
jtulach@0
     8
 *
jaroslav@358
     9
 * The contents of this file are subject to the terms of either the GNU
jaroslav@358
    10
 * General Public License Version 2 only ("GPL") or the Common
jaroslav@358
    11
 * Development and Distribution License("CDDL") (collectively, the
jaroslav@358
    12
 * "License"). You may not use this file except in compliance with the
jaroslav@358
    13
 * License. You can obtain a copy of the License at
jaroslav@358
    14
 * http://www.netbeans.org/cddl-gplv2.html
jaroslav@358
    15
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
jaroslav@358
    16
 * specific language governing permissions and limitations under the
jaroslav@358
    17
 * License.  When distributing the software, include this License Header
jaroslav@358
    18
 * Notice in each file and include the License file at
jaroslav@358
    19
 * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
jaroslav@358
    20
 * particular file as subject to the "Classpath" exception as provided
jaroslav@358
    21
 * by Oracle in the GPL Version 2 section of the License file that
jaroslav@358
    22
 * accompanied this code. If applicable, add the following below the
jaroslav@358
    23
 * License Header, with the fields enclosed by brackets [] replaced by
jaroslav@358
    24
 * your own identifying information:
jaroslav@358
    25
 * "Portions Copyrighted [year] [name of copyright owner]"
jaroslav@358
    26
 *
jaroslav@358
    27
 * Contributor(s):
jaroslav@358
    28
 *
jaroslav@358
    29
 * The Original Software is NetBeans. The Initial Developer of the Original
jaroslav@551
    30
 * Software is Oracle. Portions Copyright 2013-2014 Oracle. All Rights Reserved.
jaroslav@358
    31
 *
jaroslav@358
    32
 * If you wish your version of this file to be governed by only the CDDL
jaroslav@358
    33
 * or only the GPL Version 2, indicate your decision by adding
jaroslav@358
    34
 * "[Contributor] elects to include this software in this distribution
jaroslav@358
    35
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
jaroslav@358
    36
 * single choice of license, a recipient has the option to distribute
jaroslav@358
    37
 * your version of this file under either the CDDL, the GPL Version 2 or
jaroslav@358
    38
 * to extend the choice of license to its licensees as provided above.
jaroslav@358
    39
 * However, if you add GPL Version 2 code and therefore, elected the GPL
jaroslav@358
    40
 * Version 2 license, then the option applies only if the new code is
jaroslav@358
    41
 * made subject to such option by the copyright holder.
jtulach@0
    42
 */
jtulach@0
    43
package net.java.html.json;
jtulach@0
    44
jtulach@0
    45
import java.util.ArrayList;
jtulach@0
    46
import java.util.Collections;
jtulach@0
    47
import java.util.Iterator;
jtulach@0
    48
import java.util.List;
jtulach@0
    49
import java.util.ListIterator;
jtulach@938
    50
import net.java.html.BrwsrCtx;
jtulach@838
    51
import org.netbeans.html.context.spi.Contexts;
jtulach@838
    52
import org.netbeans.html.json.spi.FunctionBinding;
jtulach@838
    53
import org.netbeans.html.json.spi.PropertyBinding;
jtulach@838
    54
import org.netbeans.html.json.spi.Technology;
jtulach@938
    55
import static org.testng.Assert.assertEquals;
jtulach@938
    56
import static org.testng.Assert.assertFalse;
jtulach@938
    57
import static org.testng.Assert.assertNotNull;
jtulach@938
    58
import static org.testng.Assert.assertNull;
jtulach@938
    59
import static org.testng.Assert.assertTrue;
jtulach@938
    60
import static org.testng.Assert.fail;
jtulach@0
    61
import org.testng.annotations.BeforeMethod;
jtulach@0
    62
import org.testng.annotations.Test;
jtulach@0
    63
jtulach@0
    64
/**
jtulach@0
    65
 *
jtulach@790
    66
 * @author Jaroslav Tulach
jtulach@0
    67
 */
jtulach@920
    68
@Model(className = "Modelik", targetId = "", properties = {
jtulach@0
    69
    @Property(name = "value", type = int.class),
jtulach@0
    70
    @Property(name = "count", type = int.class),
jtulach@0
    71
    @Property(name = "unrelated", type = long.class),
jtulach@0
    72
    @Property(name = "names", type = String.class, array = true),
jtulach@0
    73
    @Property(name = "values", type = int.class, array = true),
jtulach@0
    74
    @Property(name = "people", type = Person.class, array = true),
jtulach@0
    75
    @Property(name = "changedProperty", type=String.class)
jtulach@0
    76
})
jtulach@0
    77
public class ModelTest {
jaroslav@7
    78
    private MockTechnology my;
jtulach@0
    79
    private Modelik model;
jtulach@0
    80
    private static Modelik leakedModel;
jtulach@938
    81
jtulach@0
    82
    @BeforeMethod
jtulach@0
    83
    public void createModel() {
jaroslav@7
    84
        my = new MockTechnology();
jaroslav@111
    85
        final BrwsrCtx c = Contexts.newBuilder().register(Technology.class, my, 1).build();
jaroslav@111
    86
        model = Models.bind(new Modelik(), c);
jtulach@0
    87
    }
jtulach@938
    88
jtulach@0
    89
    @Test public void classGeneratedWithSetterGetter() {
jtulach@0
    90
        model.setValue(10);
jtulach@0
    91
        assertEquals(10, model.getValue(), "Value changed");
jtulach@0
    92
    }
jtulach@938
    93
jtulach@0
    94
    @Test public void computedMethod() {
jtulach@0
    95
        model.setValue(4);
jtulach@0
    96
        assertEquals(16, model.getPowerValue());
jtulach@0
    97
    }
jtulach@938
    98
jaroslav@281
    99
    @Test public void equalsAndHashCode() {
jaroslav@281
   100
        Modelik m1 = new Modelik(10, 20, 30, "changed", "firstName");
jaroslav@281
   101
        Modelik m2 = new Modelik(10, 20, 30, "changed", "firstName");
jtulach@938
   102
jaroslav@281
   103
        assertTrue(m1.equals(m2), "They are the same");
jaroslav@281
   104
        assertEquals(m1.hashCode(), m2.hashCode(), "Hashcode is the same");
jtulach@938
   105
jaroslav@281
   106
        m1.setCount(33);
jtulach@938
   107
jaroslav@281
   108
        assertFalse(m1.equals(m2), "No longer the same");
jaroslav@281
   109
        assertFalse(m1.hashCode() == m2.hashCode(), "No longe is hashcode is the same");
jaroslav@281
   110
    }
jtulach@938
   111
jtulach@0
   112
    @Test public void arrayIsMutable() {
jtulach@0
   113
        assertEquals(model.getNames().size(), 0, "Is empty");
jtulach@0
   114
        model.getNames().add("Jarda");
jtulach@0
   115
        assertEquals(model.getNames().size(), 1, "One element");
jtulach@0
   116
    }
jaroslav@6
   117
jaroslav@278
   118
    @Test public void arrayChangesNotNotifiedUntilInitied() {
jaroslav@278
   119
        model.getNames().add("Hello");
jaroslav@278
   120
        assertTrue(my.mutated.isEmpty(), "No change now " + my.mutated);
jaroslav@278
   121
        model.getNames().remove("Hello");
jaroslav@278
   122
        assertTrue(my.mutated.isEmpty(), "No change still " + my.mutated);
jaroslav@278
   123
        assertTrue(model.getNames().isEmpty(), "No empty");
jaroslav@278
   124
    }
jtulach@938
   125
jtulach@0
   126
    @Test public void arrayChangesNotified() {
jaroslav@453
   127
        Models.applyBindings(model);
jtulach@0
   128
        model.getNames().add("Hello");
jtulach@938
   129
jtulach@0
   130
        assertFalse(my.mutated.isEmpty(), "There was a change" + my.mutated);
jtulach@0
   131
        assertTrue(my.mutated.contains("names"), "Change in names property: " + my.mutated);
jtulach@0
   132
jtulach@0
   133
        my.mutated.clear();
jtulach@938
   134
jtulach@0
   135
        Iterator<String> it = model.getNames().iterator();
jtulach@0
   136
        assertEquals(it.next(), "Hello");
jtulach@0
   137
        it.remove();
jtulach@938
   138
jtulach@0
   139
        assertFalse(my.mutated.isEmpty(), "There was a change" + my.mutated);
jtulach@0
   140
        assertTrue(my.mutated.contains("names"), "Change in names property: " + my.mutated);
jtulach@0
   141
jtulach@0
   142
        my.mutated.clear();
jtulach@938
   143
jtulach@0
   144
        ListIterator<String> lit = model.getNames().listIterator();
jtulach@0
   145
        lit.add("Jarda");
jtulach@938
   146
jtulach@0
   147
        assertFalse(my.mutated.isEmpty(), "There was a change" + my.mutated);
jtulach@0
   148
        assertTrue(my.mutated.contains("names"), "Change in names property: " + my.mutated);
jtulach@0
   149
    }
jaroslav@7
   150
jtulach@0
   151
    @Test public void autoboxedArray() {
jtulach@0
   152
        model.getValues().add(10);
jtulach@938
   153
jtulach@0
   154
        assertEquals(model.getValues().get(0), Integer.valueOf(10), "Really ten");
jtulach@0
   155
    }
jtulach@0
   156
jtulach@0
   157
    @Test public void derivedArrayProp() {
jaroslav@280
   158
        model.applyBindings();
jtulach@0
   159
        model.setCount(10);
jtulach@938
   160
jtulach@0
   161
        List<String> arr = model.getRepeat();
jtulach@0
   162
        assertEquals(arr.size(), 10, "Ten items: " + arr);
jtulach@938
   163
jtulach@0
   164
        my.mutated.clear();
jtulach@938
   165
jtulach@0
   166
        model.setCount(5);
jtulach@938
   167
jtulach@0
   168
        arr = model.getRepeat();
jtulach@0
   169
        assertEquals(arr.size(), 5, "Five items: " + arr);
jtulach@0
   170
jtulach@0
   171
        assertEquals(my.mutated.size(), 2, "Two properties changed: " + my.mutated);
jtulach@0
   172
        assertTrue(my.mutated.contains("repeat"), "Array is in there: " + my.mutated);
jtulach@0
   173
        assertTrue(my.mutated.contains("count"), "Count is in there: " + my.mutated);
jtulach@0
   174
    }
jtulach@938
   175
jtulach@951
   176
    @Test public void derivedArrayPropChange() {
jtulach@951
   177
        model.applyBindings();
jtulach@951
   178
        model.setCount(5);
jtulach@951
   179
jtulach@951
   180
        List<String> arr = model.getRepeat();
jtulach@951
   181
        assertEquals(arr.size(), 5, "Five items: " + arr);
jtulach@951
   182
jtulach@951
   183
        model.setRepeat(10);
jtulach@951
   184
        assertEquals(model.getCount(), 10, "Changing repeat changes count");
jtulach@951
   185
    }
jtulach@951
   186
jtulach@0
   187
    @Test public void derivedPropertiesAreNotified() {
jaroslav@280
   188
        model.applyBindings();
jtulach@938
   189
jtulach@0
   190
        model.setValue(33);
jtulach@938
   191
jtulach@0
   192
        // not interested in change of this property
jtulach@0
   193
        my.mutated.remove("changedProperty");
jtulach@938
   194
jtulach@0
   195
        assertEquals(my.mutated.size(), 2, "Two properties changed: " + my.mutated);
jtulach@0
   196
        assertTrue(my.mutated.contains("powerValue"), "Power value is in there: " + my.mutated);
jtulach@0
   197
        assertTrue(my.mutated.contains("value"), "Simple value is in there: " + my.mutated);
jtulach@938
   198
jtulach@0
   199
        my.mutated.clear();
jtulach@938
   200
jtulach@0
   201
        model.setUnrelated(44);
jtulach@938
   202
jtulach@938
   203
jtulach@0
   204
        // not interested in change of this property
jtulach@0
   205
        my.mutated.remove("changedProperty");
jtulach@0
   206
        assertEquals(my.mutated.size(), 1, "One property changed: " + my.mutated);
jtulach@0
   207
        assertTrue(my.mutated.contains("unrelated"), "Its name is unrelated");
jtulach@0
   208
    }
jaroslav@8
   209
jtulach@0
   210
    @Test public void computedPropertyCannotWriteToModel() {
jtulach@0
   211
        leakedModel = model;
jtulach@0
   212
        try {
jtulach@0
   213
            String res = model.getNotAllowedWrite();
jtulach@0
   214
            fail("We should not be allowed to write to the model: " + res);
jtulach@0
   215
        } catch (IllegalStateException ex) {
jtulach@0
   216
            // OK, we can't read
jtulach@0
   217
        }
jtulach@0
   218
    }
jtulach@0
   219
jtulach@0
   220
    @Test public void computedPropertyCannotReadToModel() {
jtulach@0
   221
        leakedModel = model;
jtulach@0
   222
        try {
jtulach@0
   223
            String res = model.getNotAllowedRead();
jtulach@0
   224
            fail("We should not be allowed to read from the model: " + res);
jtulach@0
   225
        } catch (IllegalStateException ex) {
jtulach@0
   226
            // OK, we can't read
jtulach@0
   227
        }
jtulach@0
   228
    }
jtulach@938
   229
jaroslav@245
   230
    @OnReceive(url = "{protocol}://{host}?query={query}", data = Person.class, onError = "errorState")
jaroslav@13
   231
    static void loadPeople(Modelik thiz, People p) {
jaroslav@12
   232
        Modelik m = null;
jaroslav@14
   233
        m.applyBindings();
jaroslav@111
   234
        m.loadPeople("http", "apidesign.org", "query", new Person());
jaroslav@12
   235
    }
jtulach@938
   236
jaroslav@245
   237
    static void errorState(Modelik thiz, Exception ex) {
jtulach@938
   238
jaroslav@245
   239
    }
jaroslav@24
   240
jtulach@940
   241
    @OnReceive(url="{url}", headers={
jtulach@940
   242
        "Easy: {easy}",
jtulach@940
   243
        "H-a+r!d?e.r: {harder}",
jtulach@940
   244
        "H-a+r!d?e's\"t: {harder}",
jtulach@940
   245
        "Repeat-ed: {rep}",
jtulach@940
   246
        "Repeat+ed: {rep}",
jtulach@940
   247
        "Same-URL: {url}"
jtulach@940
   248
    })
jtulach@940
   249
    static void fetchPeopleWithHeaders(Modelik model, People p) {
jtulach@940
   250
        model.fetchPeopleWithHeaders("url", "easy", "harder", "rep");
jtulach@940
   251
    }
jtulach@940
   252
jaroslav@24
   253
    @OnReceive(url = "{protocol}://{host}?callback={back}&query={query}", jsonp = "back")
jaroslav@24
   254
    static void loadPeopleViaJSONP(Modelik thiz, People p) {
jaroslav@24
   255
        Modelik m = null;
jaroslav@24
   256
        m.applyBindings();
jaroslav@24
   257
        m.loadPeopleViaJSONP("http", "apidesign.org", "query");
jaroslav@24
   258
    }
jtulach@938
   259
jtulach@938
   260
    @OnReceive(url = "{rep}://{rep}")
jtulach@938
   261
    static void repeatedTest(Modelik thiz, People p) {
jtulach@938
   262
        thiz.repeatedTest("justOneParameterRep");
jtulach@938
   263
    }
jtulach@938
   264
jtulach@938
   265
    @Function
jtulach@0
   266
    static void doSomething() {
jtulach@0
   267
    }
jtulach@938
   268
jtulach@951
   269
    @ComputedProperty(write = "setPowerValue")
jtulach@0
   270
    static int powerValue(int value) {
jtulach@0
   271
        return value * value;
jtulach@0
   272
    }
jtulach@938
   273
jtulach@951
   274
    static void setPowerValue(Modelik m, int value) {
jtulach@951
   275
        m.setValue((int)Math.sqrt(value));
jtulach@951
   276
    }
jtulach@951
   277
jtulach@0
   278
    @OnPropertyChange({ "powerValue", "unrelated" })
jtulach@0
   279
    static void aPropertyChanged(Modelik m, String name) {
jtulach@0
   280
        m.setChangedProperty(name);
jtulach@0
   281
    }
jtulach@0
   282
jtulach@0
   283
    @OnPropertyChange({ "values" })
jtulach@0
   284
    static void anArrayPropertyChanged(String name, Modelik m) {
jtulach@0
   285
        m.setChangedProperty(name);
jtulach@0
   286
    }
jtulach@938
   287
jtulach@0
   288
    @Test public void changeAnything() {
jtulach@0
   289
        model.setCount(44);
jtulach@0
   290
        assertNull(model.getChangedProperty(), "No observed value change");
jtulach@0
   291
    }
jtulach@0
   292
    @Test public void changeValue() {
jtulach@0
   293
        model.setValue(33);
jtulach@0
   294
        assertEquals(model.getChangedProperty(), "powerValue", "power property changed");
jtulach@0
   295
    }
jtulach@951
   296
    @Test public void changePowerValue() {
jtulach@951
   297
        model.setValue(3);
jtulach@951
   298
        assertEquals(model.getPowerValue(), 9, "Square");
jtulach@951
   299
        model.setPowerValue(16);
jtulach@951
   300
        assertEquals(model.getValue(), 4, "Square root");
jtulach@951
   301
        assertEquals(model.getPowerValue(), 16, "Square changed");
jtulach@951
   302
    }
jtulach@0
   303
    @Test public void changeUnrelated() {
jtulach@0
   304
        model.setUnrelated(333);
jtulach@0
   305
        assertEquals(model.getChangedProperty(), "unrelated", "unrelated changed");
jtulach@0
   306
    }
jtulach@0
   307
jtulach@0
   308
    @Test public void changeInArray() {
jtulach@0
   309
        model.getValues().add(10);
jaroslav@278
   310
        assertNull(model.getChangedProperty(), "No change before applyBindings");
jaroslav@278
   311
        model.applyBindings();
jaroslav@278
   312
        model.getValues().add(10);
jtulach@0
   313
        assertEquals(model.getChangedProperty(), "values", "Something added into the array");
jtulach@0
   314
    }
jtulach@938
   315
jtulach@0
   316
    @ComputedProperty
jtulach@0
   317
    static String notAllowedRead() {
jtulach@0
   318
        return "Not allowed callback: " + leakedModel.getUnrelated();
jtulach@0
   319
    }
jtulach@0
   320
jtulach@0
   321
    @ComputedProperty
jtulach@0
   322
    static String notAllowedWrite() {
jtulach@0
   323
        leakedModel.setUnrelated(11);
jtulach@0
   324
        return "Not allowed callback!";
jtulach@0
   325
    }
jtulach@938
   326
jtulach@951
   327
    @ComputedProperty(write="parseRepeat")
jtulach@0
   328
    static List<String> repeat(int count) {
jtulach@0
   329
        return Collections.nCopies(count, "Hello");
jtulach@0
   330
    }
jtulach@951
   331
    static void parseRepeat(Modelik m, Object v) {
jtulach@951
   332
        m.setCount((Integer)v);
jtulach@951
   333
    }
jtulach@938
   334
jtulach@0
   335
    public @Test void hasPersonPropertyAndComputedFullName() {
jtulach@0
   336
        List<Person> arr = model.getPeople();
jtulach@0
   337
        assertEquals(arr.size(), 0, "By default empty");
jtulach@0
   338
        Person p = null;
jtulach@0
   339
        if (p != null) {
jtulach@0
   340
            String fullNameGenerated = p.getFullName();
jtulach@0
   341
            assertNotNull(fullNameGenerated);
jtulach@0
   342
        }
jtulach@0
   343
    }
jtulach@938
   344
jaroslav@562
   345
    public @Test void computedListIsOfTypeString() {
jaroslav@562
   346
        Person p = new Person("1st", "2nd", Sex.MALE);
jaroslav@562
   347
        String first = p.getBothNames().get(0);
jaroslav@562
   348
        String last = p.getBothNames().get(1);
jaroslav@562
   349
        assertEquals(first, "1st");
jaroslav@562
   350
        assertEquals(last, "2nd");
jaroslav@562
   351
    }
jtulach@1025
   352
    
jtulach@1025
   353
    @Model(className = "Inner", properties = {
jtulach@1025
   354
        @Property(name = "x", type = int.class)
jtulach@1025
   355
    })
jtulach@1025
   356
    static final class InnerCntrl {
jtulach@1025
   357
        @OnPropertyChange("x")
jtulach@1025
   358
        static void increment(Inner model) {
jtulach@1025
   359
            model.setX(model.getX() + 1);
jtulach@1025
   360
        }
jtulach@1025
   361
    }
jtulach@938
   362
jaroslav@7
   363
    private static class MockTechnology implements Technology<Object> {
jaroslav@100
   364
        private final List<String> mutated = new ArrayList<String>();
jaroslav@7
   365
jaroslav@7
   366
        @Override
jaroslav@7
   367
        public Object wrapModel(Object model) {
jaroslav@7
   368
            return this;
jaroslav@7
   369
        }
jaroslav@7
   370
jaroslav@7
   371
        @Override
jaroslav@7
   372
        public void valueHasMutated(Object data, String propertyName) {
jaroslav@7
   373
            mutated.add(propertyName);
jaroslav@7
   374
        }
jaroslav@9
   375
jaroslav@9
   376
        @Override
jaroslav@9
   377
        public void bind(PropertyBinding b, Object model, Object data) {
jaroslav@9
   378
        }
jaroslav@11
   379
jaroslav@11
   380
        @Override
jaroslav@11
   381
        public void expose(FunctionBinding fb, Object model, Object d) {
jaroslav@11
   382
        }
jaroslav@14
   383
jaroslav@14
   384
        @Override
jaroslav@14
   385
        public void applyBindings(Object data) {
jaroslav@14
   386
        }
jaroslav@17
   387
jaroslav@17
   388
        @Override
jaroslav@17
   389
        public Object wrapArray(Object[] arr) {
jaroslav@17
   390
            return arr;
jaroslav@17
   391
        }
jaroslav@38
   392
jaroslav@38
   393
        @Override
jaroslav@38
   394
        public <M> M toModel(Class<M> modelClass, Object data) {
jaroslav@38
   395
            return modelClass.cast(data);
jaroslav@38
   396
        }
jaroslav@240
   397
jaroslav@240
   398
        @Override
jaroslav@240
   399
        public void runSafe(Runnable r) {
jaroslav@240
   400
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
jaroslav@240
   401
        }
jaroslav@7
   402
    }
jtulach@0
   403
}