json/src/test/java/org/netbeans/html/json/impl/DeepChangeTest.java
author Jaroslav Tulach <jtulach@netbeans.org>
Sat, 02 Aug 2014 12:59:31 +0200
changeset 790 30f20d9c0986
parent 788 f8ac4d547ad3
child 838 bdc3d696dd4a
permissions -rw-r--r--
Fixing Javadoc to succeed on JDK8
     1 /**
     2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     3  *
     4  * Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved.
     5  *
     6  * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
     7  * Other names may be trademarks of their respective owners.
     8  *
     9  * The contents of this file are subject to the terms of either the GNU
    10  * General Public License Version 2 only ("GPL") or the Common
    11  * Development and Distribution License("CDDL") (collectively, the
    12  * "License"). You may not use this file except in compliance with the
    13  * License. You can obtain a copy of the License at
    14  * http://www.netbeans.org/cddl-gplv2.html
    15  * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
    16  * specific language governing permissions and limitations under the
    17  * License.  When distributing the software, include this License Header
    18  * Notice in each file and include the License file at
    19  * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
    20  * particular file as subject to the "Classpath" exception as provided
    21  * by Oracle in the GPL Version 2 section of the License file that
    22  * accompanied this code. If applicable, add the following below the
    23  * License Header, with the fields enclosed by brackets [] replaced by
    24  * your own identifying information:
    25  * "Portions Copyrighted [year] [name of copyright owner]"
    26  *
    27  * Contributor(s):
    28  *
    29  * The Original Software is NetBeans. The Initial Developer of the Original
    30  * Software is Oracle. Portions Copyright 2013-2014 Oracle. All Rights Reserved.
    31  *
    32  * If you wish your version of this file to be governed by only the CDDL
    33  * or only the GPL Version 2, indicate your decision by adding
    34  * "[Contributor] elects to include this software in this distribution
    35  * under the [CDDL or GPL Version 2] license." If you do not indicate a
    36  * single choice of license, a recipient has the option to distribute
    37  * your version of this file under either the CDDL, the GPL Version 2 or
    38  * to extend the choice of license to its licensees as provided above.
    39  * However, if you add GPL Version 2 code and therefore, elected the GPL
    40  * Version 2 license, then the option applies only if the new code is
    41  * made subject to such option by the copyright holder.
    42  */
    43 package org.netbeans.html.json.impl;
    44 
    45 import java.io.IOException;
    46 import java.io.InputStream;
    47 import java.lang.reflect.InvocationTargetException;
    48 import java.util.HashMap;
    49 import java.util.List;
    50 import java.util.Map;
    51 import net.java.html.BrwsrCtx;
    52 import net.java.html.json.ComputedProperty;
    53 import net.java.html.json.Model;
    54 import net.java.html.json.Models;
    55 import net.java.html.json.Property;
    56 import org.apidesign.html.context.spi.Contexts;
    57 import org.apidesign.html.json.spi.FunctionBinding;
    58 import org.apidesign.html.json.spi.JSONCall;
    59 import org.apidesign.html.json.spi.PropertyBinding;
    60 import org.apidesign.html.json.spi.Technology;
    61 import org.apidesign.html.json.spi.Transfer;
    62 import static org.testng.Assert.*;
    63 import org.testng.annotations.BeforeMethod;
    64 import org.testng.annotations.Test;
    65 
    66 /**
    67  *
    68  * @author Jaroslav Tulach
    69  */
    70 public class DeepChangeTest {
    71     private MapTechnology t;
    72     private BrwsrCtx c;
    73 
    74     @BeforeMethod public void initTechnology() {
    75         t = new MapTechnology();
    76         c = Contexts.newBuilder().register(Technology.class, t, 1).
    77             register(Transfer.class, t, 1).build();
    78     }
    79     
    80     @Model(className = "MyX", properties = {
    81         @Property(name = "one", type = MyY.class),
    82         @Property(name = "all", type = MyY.class, array = true)
    83     })
    84     static class X {
    85         @ComputedProperty @Transitive(deep = true) 
    86         static String oneName(MyY one) {
    87             return one.getValue();
    88         }
    89         @ComputedProperty
    90         static String sndName(MyY one) {
    91             return one.getValue().toUpperCase();
    92         }
    93         @ComputedProperty @Transitive(deep = false) 
    94         static String noName(MyY one) {
    95             return one.getValue().toUpperCase();
    96         }
    97         @ComputedProperty @Transitive(deep = true) 
    98         static String thrdName(MyY one) {
    99             return "X" + one.getCount();
   100         }
   101         
   102         @ComputedProperty
   103         static String allNames(List<MyY> all) {
   104             StringBuilder sb = new StringBuilder();
   105             for (MyY y : all) {
   106                 sb.append(y.getValue());
   107             }
   108             return sb.toString();
   109         }
   110 
   111         @ComputedProperty @Transitive(deep = true)
   112         static String firstFromNames(List<MyY> all) {
   113             for (MyY y : all) {
   114                 if (y != null && y.getValue() != null) {
   115                     return y.getValue();
   116                 }
   117             }
   118             return null;
   119         }
   120     }
   121     @Model(className = "MyY", properties = {
   122         @Property(name = "value", type = String.class),
   123         @Property(name = "count", type = int.class)
   124     })
   125     static class Y {
   126     }
   127     @Model(className = "MyOverall", properties = {
   128         @Property(name = "x", type = MyX.class)
   129     })
   130     static class Overall {
   131         @ComputedProperty @Transitive(deep = true) 
   132         static String valueAccross(MyX x) {
   133             return x.getFirstFromNames();
   134         }
   135     }
   136     
   137     @Test public void isTransitiveChangeNotifiedProperly() throws Exception {
   138         MyX p = Models.bind(
   139             new MyX(new MyY("Ahoj", 0), new MyY("Hi", 333), new MyY("Hello", 999)
   140         ), c).applyBindings();
   141         
   142         Map m = (Map)Models.toRaw(p);
   143         Object v = m.get("oneName");
   144         assertNotNull(v, "Value should be in the map");
   145         assertEquals(v.getClass(), One.class, "It is instance of One");
   146         One o = (One)v;
   147         assertEquals(o.changes, 0, "No changes so far");
   148         assertTrue(o.pb.isReadOnly(), "Derived property");
   149         assertEquals(o.get(), "Ahoj");
   150 
   151         p.getOne().setValue("Nazdar");
   152         
   153         assertEquals(o.get(), "Nazdar");
   154         assertEquals(o.changes, 1, "One change so far");
   155     }
   156     
   157     @Test public void isTransitiveChangeInArrayNotifiedProperly() throws Exception {
   158         MyX p = Models.bind(
   159             new MyX(new MyY("Ahoj", 0), new MyY("Hi", 333), new MyY("Hello", 999)
   160         ), c).applyBindings();
   161         
   162         Map m = (Map)Models.toRaw(p);
   163         Object v = m.get("allNames");
   164         assertNotNull(v, "Value should be in the map");
   165         assertEquals(v.getClass(), One.class, "It is instance of One");
   166         One o = (One)v;
   167         assertEquals(o.changes, 0, "No changes so far");
   168         assertTrue(o.pb.isReadOnly(), "Derived property");
   169         assertEquals(o.get(), "HiHello");
   170 
   171         p.getAll().get(0).setValue("Nazdar");
   172         
   173         assertEquals(o.get(), "NazdarHello");
   174         assertEquals(o.changes, 1, "One change so far");
   175     }
   176 
   177     @Test public void addingIntoArray() throws Exception {
   178         MyX p = Models.bind(
   179             new MyX(new MyY("Ahoj", 0), new MyY("Hi", 333), new MyY("Hello", 999)
   180         ), c).applyBindings();
   181         
   182         Map m = (Map)Models.toRaw(p);
   183         Object v = m.get("allNames");
   184         assertNotNull(v, "Value should be in the map");
   185         assertEquals(v.getClass(), One.class, "It is instance of One");
   186         One o = (One)v;
   187         assertEquals(o.changes, 0, "No changes so far");
   188         assertTrue(o.pb.isReadOnly(), "Derived property");
   189         assertEquals(o.get(), "HiHello");
   190 
   191         MyY y = new MyY("Cus", 1);
   192         p.getAll().add(y);
   193         
   194         assertEquals(o.changes, 1, "One change so far");
   195         assertEquals(o.get(), "HiHelloCus");
   196         
   197         y.setValue("Nazdar");
   198         
   199         assertEquals(o.changes, 2, "2nd change so far");
   200         assertEquals(o.get(), "HiHelloNazdar");
   201         
   202         y.setValue("Zdravim");
   203 
   204         assertEquals(o.changes, 3, "3rd change so far");
   205         assertEquals(o.get(), "HiHelloZdravim");
   206     }
   207     
   208     @Test public void firstChangeInArrayNotifiedProperly() throws Exception {
   209         MyX p = Models.bind(
   210             new MyX(new MyY("Ahoj", 0), new MyY("Hi", 333), new MyY("Hello", 999)
   211         ), c).applyBindings();
   212         
   213         Map m = (Map)Models.toRaw(p);
   214         Object v = m.get("firstFromNames");
   215         assertNotNull(v, "Value should be in the map");
   216         assertEquals(v.getClass(), One.class, "It is instance of One");
   217         One o = (One)v;
   218         assertEquals(o.changes, 0, "No changes so far");
   219         assertTrue(o.pb.isReadOnly(), "Derived property");
   220         assertEquals(o.get(), "Hi");
   221 
   222         p.getAll().get(0).setValue("Nazdar");
   223         
   224         assertEquals(o.get(), "Nazdar");
   225         assertEquals(o.changes, 1, "One change so far");
   226     }
   227     
   228     @Test public void firstChangeInArrayToNull() throws Exception {
   229         MyX p = Models.bind(
   230             new MyX(new MyY("Ahoj", 0), new MyY("Hi", 333), new MyY("Hello", 999)
   231         ), c).applyBindings();
   232         
   233         Map m = (Map)Models.toRaw(p);
   234         Object v = m.get("firstFromNames");
   235         assertNotNull(v, "Value should be in the map");
   236         assertEquals(v.getClass(), One.class, "It is instance of One");
   237         One o = (One)v;
   238         assertEquals(o.changes, 0, "No changes so far");
   239         assertTrue(o.pb.isReadOnly(), "Derived property");
   240         assertEquals(o.get(), "Hi");
   241 
   242         p.getAll().get(0).setValue(null);
   243         
   244         assertEquals(o.get(), "Hello");
   245         assertEquals(o.changes, 1, "One change so far");
   246         
   247         p.getAll().get(0).setValue("Nazdar");
   248 
   249         assertEquals(o.get(), "Nazdar");
   250         assertEquals(o.changes, 2, "2nd change so far");
   251     }
   252     
   253     @Test public void firstChangeInArrayNotifiedTransitively() throws Exception {
   254         MyOverall p = Models.bind(
   255             new MyOverall(new MyX(new MyY("Ahoj", 0), new MyY("Hi", 333), new MyY("Hello", 999))
   256         ), c).applyBindings();
   257         
   258         Map m = (Map)Models.toRaw(p);
   259         Object v = m.get("valueAccross");
   260         assertNotNull(v, "Value should be in the map");
   261         assertEquals(v.getClass(), One.class, "It is instance of One");
   262         One o = (One)v;
   263         assertEquals(o.changes, 0, "No changes so far");
   264         assertTrue(o.pb.isReadOnly(), "Derived property");
   265         assertEquals(o.get(), "Hi");
   266 
   267         p.getX().getAll().get(0).setValue("Nazdar");
   268         
   269         assertEquals(o.get(), "Nazdar");
   270         assertEquals(o.changes, 1, "One change so far");
   271     }
   272     
   273     @Test public void secondChangeInArrayIgnored() throws Exception {
   274         MyX p = Models.bind(
   275             new MyX(new MyY("Ahoj", 0), new MyY("Hi", 333), new MyY("Hello", 999)
   276         ), c).applyBindings();
   277         
   278         Map m = (Map)Models.toRaw(p);
   279         Object v = m.get("firstFromNames");
   280         assertNotNull(v, "Value should be in the map");
   281         assertEquals(v.getClass(), One.class, "It is instance of One");
   282         One o = (One)v;
   283         assertEquals(o.changes, 0, "No changes so far");
   284         assertTrue(o.pb.isReadOnly(), "Derived property");
   285         assertEquals(o.get(), "Hi");
   286 
   287         p.getAll().get(1).setValue("Nazdar");
   288         
   289         assertEquals(o.get(), "Hi");
   290         assertEquals(o.changes, 0, "No change so far");
   291     }
   292     
   293     @Test public void changeInArraySizeNeedsToBeRecomputed() throws Exception {
   294         MyX p = Models.bind(
   295             new MyX(new MyY("Ahoj", 0), new MyY("Hi", 333), new MyY("Hello", 999)
   296         ), c).applyBindings();
   297         
   298         Map m = (Map)Models.toRaw(p);
   299         Object v = m.get("firstFromNames");
   300         assertNotNull(v, "Value should be in the map");
   301         assertEquals(v.getClass(), One.class, "It is instance of One");
   302         One o = (One)v;
   303         assertEquals(o.changes, 0, "No changes so far");
   304         assertTrue(o.pb.isReadOnly(), "Derived property");
   305         assertEquals(o.get(), "Hi");
   306 
   307         p.getAll().remove(1);
   308         
   309         assertEquals(o.get(), "Hi");
   310         assertEquals(o.changes, 1, "This required a change");
   311     }
   312     
   313     @Test public void doublePropertyChangeNotified() throws Exception {
   314         MyX p = Models.bind(
   315             new MyX(new MyY("Ahoj", 0), new MyY("Hi", 333), new MyY("Hello", 999)
   316         ), c).applyBindings();
   317         
   318         Map m = (Map)Models.toRaw(p);
   319         Object v = m.get("oneName");
   320         assertNotNull(v, "Value should be in the map");
   321         Object v2 = m.get("sndName");
   322         assertNotNull(v2, "Value2 should be in the map");
   323         One o = (One)v;
   324         One o2 = (One)v2;
   325         assertEquals(o.changes, 0, "No changes so far");
   326         assertEquals(o2.changes, 0, "No changes so far");
   327         assertTrue(o.pb.isReadOnly(), "Derived property");
   328         assertEquals(o.get(), "Ahoj");
   329         assertEquals(o2.get(), "AHOJ");
   330 
   331         p.getOne().setValue("Nazdar");
   332         
   333         assertEquals(o.get(), "Nazdar");
   334         assertEquals(o.changes, 1, "One change so far");
   335         assertEquals(o2.changes, 1, "One change so far");
   336         assertEquals(o2.get(), "NAZDAR");
   337     }
   338     
   339     @Test public void onlyAffectedPropertyChangeNotified() throws Exception {
   340         MyX p = Models.bind(
   341             new MyX(new MyY("Ahoj", 0), new MyY("Hi", 333), new MyY("Hello", 999)
   342         ), c).applyBindings();
   343         
   344         Map m = (Map)Models.toRaw(p);
   345         Object v = m.get("oneName");
   346         assertNotNull(v, "Value should be in the map");
   347         Object v2 = m.get("thrdName");
   348         assertNotNull(v2, "Value2 should be in the map");
   349         One o = (One)v;
   350         One o2 = (One)v2;
   351         assertEquals(o.changes, 0, "No changes so far");
   352         assertEquals(o2.changes, 0, "No changes so far");
   353         assertTrue(o.pb.isReadOnly(), "Derived property");
   354         assertEquals(o.get(), "Ahoj");
   355         assertEquals(o2.get(), "X0");
   356 
   357         p.getOne().setCount(10);
   358         
   359         assertEquals(o.get(), "Ahoj");
   360         assertEquals(o.changes, 0, "Still no change");
   361         assertEquals(o2.changes, 1, "One change so far");
   362         assertEquals(o2.get(), "X10");
   363     }
   364     
   365     @Test public void onlyDeepPropsAreNotified() throws Exception {
   366         MyX p = Models.bind(
   367             new MyX(new MyY("Ahoj", 0), new MyY("Hi", 333), new MyY("Hello", 999)
   368         ), c).applyBindings();
   369         
   370         Map m = (Map)Models.toRaw(p);
   371         Object v = m.get("oneName");
   372         assertNotNull(v, "Value should be in the map");
   373         Object v2 = m.get("noName");
   374         assertNotNull(v2, "Value2 should be in the map");
   375         One o = (One)v;
   376         One o2 = (One)v2;
   377         assertEquals(o.changes, 0, "No changes so far");
   378         assertEquals(o2.changes, 0, "No changes so far");
   379         assertTrue(o.pb.isReadOnly(), "Derived property");
   380         assertEquals(o.get(), "Ahoj");
   381         assertEquals(o2.get(), "AHOJ");
   382 
   383         p.getOne().setValue("Nazdar");
   384         
   385         assertEquals(o.get(), "Nazdar");
   386         assertEquals(o.changes, 1, "One change so far");
   387         assertEquals(o2.changes, 0, "This change is not noticed");
   388         assertEquals(o2.get(), "NAZDAR", "but property value changes when computed");
   389     }
   390 
   391     static final class One {
   392 
   393         int changes;
   394         final PropertyBinding pb;
   395         final FunctionBinding fb;
   396 
   397         One(Object m, PropertyBinding pb) throws NoSuchMethodException {
   398             this.pb = pb;
   399             this.fb = null;
   400         }
   401 
   402         One(Object m, FunctionBinding fb) throws NoSuchMethodException {
   403             this.pb = null;
   404             this.fb = fb;
   405         }
   406 
   407         Object get() throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
   408             return pb.getValue();
   409         }
   410 
   411         void set(Object v) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
   412             pb.setValue(v);
   413         }
   414     }
   415 
   416     static final class MapTechnology
   417             implements Technology<Map<String, One>>, Transfer {
   418 
   419         @Override
   420         public Map<String, One> wrapModel(Object model) {
   421             return new HashMap<String, One>();
   422         }
   423 
   424         @Override
   425         public void valueHasMutated(Map<String, One> data, String propertyName) {
   426             One p = data.get(propertyName);
   427             if (p != null) {
   428                 p.changes++;
   429             }
   430         }
   431 
   432         @Override
   433         public void bind(PropertyBinding b, Object model, Map<String, One> data) {
   434             try {
   435                 One o = new One(model, b);
   436                 data.put(b.getPropertyName(), o);
   437             } catch (NoSuchMethodException ex) {
   438                 throw new IllegalStateException(ex);
   439             }
   440         }
   441 
   442         @Override
   443         public void expose(FunctionBinding fb, Object model, Map<String, One> data) {
   444             try {
   445                 data.put(fb.getFunctionName(), new One(model, fb));
   446             } catch (NoSuchMethodException ex) {
   447                 throw new IllegalStateException(ex);
   448             }
   449         }
   450 
   451         @Override
   452         public void applyBindings(Map<String, One> data) {
   453         }
   454 
   455         @Override
   456         public Object wrapArray(Object[] arr) {
   457             return arr;
   458         }
   459 
   460         @Override
   461         public void extract(Object obj, String[] props, Object[] values) {
   462             Map<?, ?> map = obj instanceof Map ? (Map<?, ?>) obj : null;
   463             for (int i = 0; i < Math.min(props.length, values.length); i++) {
   464                 if (map == null) {
   465                     values[i] = null;
   466                 } else {
   467                     values[i] = map.get(props[i]);
   468                     if (values[i] instanceof One) {
   469                         values[i] = ((One) values[i]).pb.getValue();
   470                     }
   471                 }
   472             }
   473         }
   474 
   475         @Override
   476         public void loadJSON(JSONCall call) {
   477             call.notifyError(new UnsupportedOperationException());
   478         }
   479 
   480         @Override
   481         public <M> M toModel(Class<M> modelClass, Object data) {
   482             return modelClass.cast(data);
   483         }
   484 
   485         @Override
   486         public Object toJSON(InputStream is) throws IOException {
   487             throw new IOException();
   488         }
   489 
   490         @Override
   491         public void runSafe(Runnable r) {
   492             throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
   493         }
   494     }
   495     
   496 }