json-tck/src/main/java/net/java/html/json/tests/JSONTest.java
author Jaroslav Tulach <jtulach@netbeans.org>
Sat, 02 Aug 2014 12:59:31 +0200
changeset 790 30f20d9c0986
parent 650 cbffa9025961
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 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.apidesign.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 }