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