json-tck/src/main/java/net/java/html/json/tests/JSONTest.java
author Jaroslav Tulach <jtulach@netbeans.org>
Tue, 26 Aug 2014 18:13:30 +0200
changeset 838 bdc3d696dd4a
parent 790 30f20d9c0986
child 920 117b732d42d0
permissions -rw-r--r--
During the API review process (bug 246133) the reviewers decided that in order to include html4j to NetBeans Platform, we need to stop using org.apidesign namespace and switch to NetBeans one. Repackaging all SPI packages into org.netbeans.html.smthng.spi.
     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 net.java.html.json.tests;
    44 
    45 import java.io.ByteArrayInputStream;
    46 import java.io.ByteArrayOutputStream;
    47 import java.io.PrintStream;
    48 import net.java.html.BrwsrCtx;
    49 import net.java.html.json.Model;
    50 import net.java.html.json.ModelOperation;
    51 import net.java.html.json.Models;
    52 import net.java.html.json.OnReceive;
    53 import net.java.html.json.Property;
    54 import org.netbeans.html.json.tck.KOTest;
    55 
    56 /** Need to verify that models produce reasonable JSON objects.
    57  *
    58  * @author Jaroslav Tulach
    59  */
    60 @Model(className = "JSONik", properties = {
    61     @Property(name = "fetched", type = Person.class),
    62     @Property(name = "fetchedCount", type = int.class),
    63     @Property(name = "fetchedResponse", type = String.class),
    64     @Property(name = "fetchedSex", type = Sex.class, array = true)
    65 })
    66 public final class JSONTest {
    67     private JSONik js;
    68     private Integer orig;
    69     private String url;
    70     
    71     @ModelOperation static void assignFetched(JSONik m, Person p) {
    72         m.setFetched(p);
    73     }
    74     private BrwsrCtx ctx;
    75     
    76     @KOTest public void toJSONInABrowser() throws Throwable {
    77         Person p = Models.bind(new Person(), newContext());
    78         p.setSex(Sex.MALE);
    79         p.setFirstName("Jarda");
    80         p.setLastName("Tulach");
    81 
    82         Object json;
    83         try {
    84             json = parseJSON(p.toString());
    85         } catch (Throwable ex) {
    86             throw new IllegalStateException("Can't parse " + p).initCause(ex);
    87         }
    88         
    89         Person p2 = Models.fromRaw(newContext(), Person.class, json);
    90         
    91         assert p2.getFirstName().equals(p.getFirstName()) : 
    92             "Should be the same: " + p.getFirstName() + " != " + p2.getFirstName();
    93     }
    94     
    95     @KOTest public void toJSONWithEscapeCharactersInABrowser() throws Throwable {
    96         Person p = Models.bind(new Person(), newContext());
    97         p.setSex(Sex.MALE);
    98         p.setFirstName("/*\n * Copyright (c) 2013");
    99 
   100         
   101         final String txt = p.toString();
   102         Object json;
   103         try {
   104             json = parseJSON(txt);
   105         } catch (Throwable ex) {
   106             throw new IllegalStateException("Can't parse " + txt).initCause(ex);
   107         }
   108         
   109         Person p2 = Models.fromRaw(newContext(), Person.class, json);
   110         
   111         assert p2.getFirstName().equals(p.getFirstName()) : 
   112             "Should be the same: " + p.getFirstName() + " != " + p2.getFirstName();
   113     }
   114     
   115     @KOTest public void toJSONWithDoubleSlashInABrowser() throws Throwable {
   116         Person p = Models.bind(new Person(), newContext());
   117         p.setSex(Sex.MALE);
   118         p.setFirstName("/*\\n * Copyright (c) 2013");
   119 
   120         
   121         final String txt = p.toString();
   122         Object json;
   123         try {
   124             json = parseJSON(txt);
   125         } catch (Throwable ex) {
   126             throw new IllegalStateException("Can't parse " + txt).initCause(ex);
   127         }
   128         
   129         Person p2 = Models.fromRaw(newContext(), Person.class, json);
   130         
   131         assert p2.getFirstName().equals(p.getFirstName()) : 
   132             "Should be the same: " + p.getFirstName() + " != " + p2.getFirstName();
   133     }
   134     
   135     @KOTest public void toJSONWithApostrophInABrowser() throws Throwable {
   136         Person p = Models.bind(new Person(), newContext());
   137         p.setSex(Sex.MALE);
   138         p.setFirstName("Jimmy 'Jim' Rambo");
   139 
   140         
   141         final String txt = p.toString();
   142         Object json;
   143         try {
   144             json = parseJSON(txt);
   145         } catch (Throwable ex) {
   146             throw new IllegalStateException("Can't parse " + txt).initCause(ex);
   147         }
   148         
   149         Person p2 = Models.fromRaw(newContext(), Person.class, json);
   150         
   151         assert p2.getFirstName().equals(p.getFirstName()) : 
   152             "Should be the same: " + p.getFirstName() + " != " + p2.getFirstName();
   153     }
   154 
   155     private static BrwsrCtx onCallback;
   156     
   157     @OnReceive(url="{url}")
   158     static void fetch(JSONik model, Person p) {
   159         model.setFetched(p);
   160         onCallback = BrwsrCtx.findDefault(model.getClass());
   161     }
   162 
   163     @OnReceive(url="{url}", onError = "setMessage")
   164     static void fetchArray(JSONik model, Person[] p) {
   165         model.setFetchedCount(p.length);
   166         model.setFetched(p[0]);
   167         onCallback = BrwsrCtx.findDefault(model.getClass());
   168     }
   169     
   170     static void setMessage(JSONik m, Exception t) {
   171         assert t != null;
   172         m.setFetchedResponse("Exception");
   173     }
   174     
   175     @OnReceive(url="{url}")
   176     static void fetchPeople(JSONik model, People p) {
   177         final int size = p.getInfo().size();
   178         if (size > 0) {
   179             model.setFetched(p.getInfo().get(0));
   180         }
   181         model.setFetchedCount(size);
   182     }
   183 
   184     @OnReceive(url="{url}")
   185     static void fetchPeopleAge(JSONik model, People p) {
   186         int sum = 0;
   187         for (int a : p.getAge()) {
   188             sum += a;
   189         }
   190         model.setFetchedCount(sum);
   191     }
   192     
   193     @KOTest public void loadAndParseJSON() throws InterruptedException {
   194         if (js == null) {
   195             url = Utils.prepareURL(
   196                 JSONTest.class, "{'firstName': 'Sitar', 'sex': 'MALE'}",
   197                 "application/json"
   198             );
   199             js = Models.bind(new JSONik(), ctx = newContext());
   200             js.applyBindings();
   201 
   202             js.setFetched(null);
   203             js.fetch(url);
   204         }
   205     
   206         Person p = js.getFetched();
   207         if (p == null) {
   208             throw new InterruptedException();
   209         }
   210         
   211         assert "Sitar".equals(p.getFirstName()) : "Expecting Sitar: " + p.getFirstName();
   212         assert Sex.MALE.equals(p.getSex()) : "Expecting MALE: " + p.getSex();
   213         
   214         assert ctx == onCallback;
   215     }
   216     
   217     @OnReceive(url="{url}?callme={me}", jsonp = "me")
   218     static void fetchViaJSONP(JSONik model, Person p) {
   219         model.setFetched(p);
   220     }
   221     
   222     @KOTest public void loadAndParseJSONP() throws InterruptedException, Exception {
   223         if (js == null) {
   224             url = Utils.prepareURL(
   225                 JSONTest.class, "$0({'firstName': 'Mitar', 'sex': 'MALE'})", 
   226                 "application/javascript",
   227                 "callme"
   228             );
   229             orig = scriptElements();
   230             assert orig > 0 : "There should be some scripts on the page";
   231             
   232             js = Models.bind(new JSONik(), newContext());
   233             js.applyBindings();
   234 
   235             js.setFetched(null);
   236             js.fetchViaJSONP(url);
   237         }
   238     
   239         Person p = js.getFetched();
   240         if (p == null) {
   241             throw new InterruptedException();
   242         }
   243         
   244         assert "Mitar".equals(p.getFirstName()) : "Unexpected: " + p.getFirstName();
   245         assert Sex.MALE.equals(p.getSex()) : "Expecting MALE: " + p.getSex();
   246         
   247         int now = scriptElements();
   248         
   249         assert orig == now : "The set of elements is unchanged. Delta: " + (now - orig);
   250     }
   251     
   252     
   253     
   254     @OnReceive(url="{url}", method = "PUT", data = Person.class)
   255     static void putPerson(JSONik model, String reply) {
   256         model.setFetchedCount(1);
   257         model.setFetchedResponse(reply);
   258     }
   259 
   260     @KOTest public void putPeopleUsesRightMethod() throws InterruptedException, Exception {
   261         if (js == null) {
   262             url = Utils.prepareURL(
   263                 JSONTest.class, "$0\n$1", 
   264                 "text/plain",
   265                 "http.method", "http.requestBody"
   266             );
   267             orig = scriptElements();
   268             assert orig > 0 : "There should be some scripts on the page";
   269             
   270             js = Models.bind(new JSONik(), newContext());
   271             js.applyBindings();
   272 
   273             Person p = Models.bind(new Person(), BrwsrCtx.EMPTY);
   274             p.setFirstName("Jarda");
   275             js.putPerson(url, p);
   276         }
   277     
   278         int cnt = js.getFetchedCount();
   279         if (cnt == 0) {
   280             throw new InterruptedException();
   281         }
   282         String res = js.getFetchedResponse();
   283         int line = res.indexOf('\n');
   284         String msg;
   285         if (line >= 0) {
   286             msg = res.substring(line + 1);
   287             res = res.substring(0, line);
   288         } else {
   289             msg = res;
   290         }
   291         
   292         assert "PUT".equals(res) : "Server was queried with PUT method: " + js.getFetchedResponse();
   293         
   294         assert msg.contains("Jarda") : "Data transferred to the server: " + msg;
   295     }
   296     
   297     private static int scriptElements() throws Exception {
   298         return ((Number)Utils.executeScript(
   299             JSONTest.class, 
   300             "return window.document.getElementsByTagName('script').length;")).intValue();
   301     }
   302 
   303     private static Object parseJSON(String s) throws Exception {
   304         return Utils.executeScript(
   305             JSONTest.class, 
   306             "return window.JSON.parse(arguments[0]);", s);
   307     }
   308     
   309     @KOTest public void loadAndParseJSONSentToArray() throws InterruptedException {
   310         if (js == null) {
   311             url = Utils.prepareURL(
   312                 JSONTest.class, "{'firstName': 'Sitar', 'sex': 'MALE'}", 
   313                 "application/json"
   314             );
   315             
   316             js = Models.bind(new JSONik(), newContext());
   317             js.applyBindings();
   318 
   319             js.setFetched(null);
   320             js.fetchArray(url);
   321         }
   322         
   323         Person p = js.getFetched();
   324         if (p == null) {
   325             throw new InterruptedException();
   326         }
   327         
   328         assert "Sitar".equals(p.getFirstName()) : "Expecting Sitar: " + p.getFirstName();
   329         assert Sex.MALE.equals(p.getSex()) : "Expecting MALE: " + p.getSex();
   330     }
   331     
   332     @KOTest public void loadAndParseJSONArraySingle() throws InterruptedException {
   333         if (js == null) {
   334             url = Utils.prepareURL(
   335                 JSONTest.class, "[{'firstName': 'Gitar', 'sex': 'FEMALE'}]", 
   336                 "application/json"
   337             );
   338             js = Models.bind(new JSONik(), newContext());
   339             js.applyBindings();
   340         
   341             js.setFetched(null);
   342             js.fetch(url);
   343         }
   344         
   345         Person p = js.getFetched();
   346         if (p == null) {
   347             throw new InterruptedException();
   348         }
   349         
   350         assert "Gitar".equals(p.getFirstName()) : "Expecting Gitar: " + p.getFirstName();
   351         assert Sex.FEMALE.equals(p.getSex()) : "Expecting FEMALE: " + p.getSex();
   352     }
   353     
   354     @KOTest public void loadAndParseArrayInPeople() throws InterruptedException {
   355         if (js == null) {
   356             url = Utils.prepareURL(
   357                 JSONTest.class, "{'info':[{'firstName': 'Gitar', 'sex': 'FEMALE'}]}", 
   358                 "application/json"
   359             );
   360             js = Models.bind(new JSONik(), newContext());
   361             js.applyBindings();
   362         
   363             js.fetchPeople(url);
   364         }
   365         
   366         if (0 == js.getFetchedCount()) {
   367             throw new InterruptedException();
   368         }
   369 
   370         assert js.getFetchedCount() == 1 : "One person loaded: " + js.getFetchedCount();
   371         
   372         Person p = js.getFetched();
   373         
   374         assert p != null : "We should get our person back: " + p;
   375         assert "Gitar".equals(p.getFirstName()) : "Expecting Gitar: " + p.getFirstName();
   376         assert Sex.FEMALE.equals(p.getSex()) : "Expecting FEMALE: " + p.getSex();
   377     }
   378     
   379     @KOTest public void loadAndParseArrayOfIntegers() throws InterruptedException {
   380         if (js == null) {
   381             url = Utils.prepareURL(
   382                 JSONTest.class, "{'age':[1, 2, 3]}", 
   383                 "application/json"
   384             );
   385             js = Models.bind(new JSONik(), newContext());
   386             js.applyBindings();
   387         
   388             js.fetchPeopleAge(url);
   389         }
   390         
   391         if (0 == js.getFetchedCount()) {
   392             throw new InterruptedException();
   393         }
   394 
   395         assert js.getFetchedCount() == 6 : "1 + 2 + 3 is " + js.getFetchedCount();
   396     }
   397     
   398     @OnReceive(url="{url}")
   399     static void fetchPeopleSex(JSONik model, People p) {
   400         model.setFetchedCount(1);
   401         model.getFetchedSex().addAll(p.getSex());
   402     }
   403     
   404     @KOTest public void loadAndParseArrayOfEnums() throws InterruptedException {
   405         if (js == null) {
   406             url = Utils.prepareURL(
   407                 JSONTest.class, "{'sex':['FEMALE', 'MALE', 'MALE']}", 
   408                 "application/json"
   409             );
   410             js = Models.bind(new JSONik(), newContext());
   411             js.applyBindings();
   412         
   413             js.fetchPeopleSex(url);
   414         }
   415         
   416         if (0 == js.getFetchedCount()) {
   417             throw new InterruptedException();
   418         }
   419 
   420         assert js.getFetchedCount() == 1 : "Loaded";
   421         
   422         assert js.getFetchedSex().size() == 3 : "Three values " + js.getFetchedSex();
   423         assert js.getFetchedSex().get(0) == Sex.FEMALE : "Female first " + js.getFetchedSex();
   424         assert js.getFetchedSex().get(1) == Sex.MALE : "male 2nd " + js.getFetchedSex();
   425         assert js.getFetchedSex().get(2) == Sex.MALE : "male 3rd " + js.getFetchedSex();
   426     }
   427     
   428     @KOTest public void loadAndParseJSONArray() throws InterruptedException {
   429         if (js == null) {
   430             url = Utils.prepareURL(
   431                 JSONTest.class, "[{'firstName': 'Gitar', 'sex': 'FEMALE'},"
   432                 + "{'firstName': 'Peter', 'sex': 'MALE'}"
   433                 + "]", 
   434                 "application/json"
   435             );
   436             js = Models.bind(new JSONik(), newContext());
   437             js.applyBindings();
   438             js.setFetched(null);
   439             
   440             js.fetchArray(url);
   441         }
   442         
   443         
   444         Person p = js.getFetched();
   445         if (p == null) {
   446             throw new InterruptedException();
   447         }
   448         
   449         assert js.getFetchedCount() == 2 : "We got two values: " + js.getFetchedCount();
   450         assert "Gitar".equals(p.getFirstName()) : "Expecting Gitar: " + p.getFirstName();
   451         assert Sex.FEMALE.equals(p.getSex()) : "Expecting FEMALE: " + p.getSex();
   452     }
   453     
   454     @KOTest public void loadError() throws InterruptedException {
   455         if (js == null) {
   456             js = Models.bind(new JSONik(), newContext());
   457             js.applyBindings();
   458             js.setFetched(null);
   459             
   460             js.fetchArray("http://127.0.0.1:54253/does/not/exist.txt");
   461         }
   462         
   463         
   464         if (js.getFetchedResponse() == null) {
   465             throw new InterruptedException();
   466         }
   467 
   468         assert "Exception".equals(js.getFetchedResponse()) : js.getFetchedResponse();
   469     }
   470     
   471     @Model(className = "NameAndValue", properties = {
   472         @Property(name = "name", type = String.class),
   473         @Property(name = "value", type = long.class),
   474         @Property(name = "small", type = byte.class)
   475     })
   476     static class NandV {
   477     }
   478     
   479     @KOTest public void parseNullNumber() throws Exception {
   480         String txt = "{ \"name\":\"M\" }";
   481         ByteArrayInputStream is = new ByteArrayInputStream(txt.getBytes("UTF-8"));
   482         NameAndValue v = Models.parse(newContext(), NameAndValue.class, is);
   483         assert "M".equals(v.getName()) : "Name is 'M': " + v.getName();
   484         assert 0 == v.getValue() : "Value is empty: " + v.getValue();
   485         assert 0 == v.getSmall() : "Small value is empty: " + v.getSmall();
   486     }
   487 
   488     @KOTest public void deserializeWrongEnum() throws Exception {
   489         PrintStream prev = null;
   490         ByteArrayOutputStream err = new ByteArrayOutputStream();
   491         try {
   492             prev = System.err;
   493             System.setErr(new PrintStream(err));
   494         } catch (SecurityException e) {
   495             err = null;
   496             prev = null;
   497         } catch (LinkageError e) {
   498             err = null;
   499             prev = null;
   500         }
   501         
   502         String str = "{ \"sex\" : \"unknown\" }";
   503         ByteArrayInputStream is = new ByteArrayInputStream(str.getBytes("UTF-8"));
   504         Person p = Models.parse(newContext(), Person.class, is);
   505         assert p.getSex() == null : "Wrong sex means null, but was: " + p.getSex();
   506         
   507         if (err != null) {
   508             assert err.toString().contains("unknown") && err.toString().contains("Sex"): "Expecting error: " + err.toString();
   509         }
   510         if (prev != null) {
   511             try {
   512                 System.setErr(prev);
   513             } catch (LinkageError e) {
   514                 // ignore
   515             }
   516         }
   517     }
   518 
   519     
   520     private static BrwsrCtx newContext() {
   521         return Utils.newContext(JSONTest.class);
   522     }
   523     
   524 }