2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
4 * Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved.
6 * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
7 * Other names may be trademarks of their respective owners.
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]"
29 * The Original Software is NetBeans. The Initial Developer of the Original
30 * Software is Oracle. Portions Copyright 2013-2014 Oracle. All Rights Reserved.
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.
43 package net.java.html.json.tests;
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;
56 /** Need to verify that models produce reasonable JSON objects.
58 * @author Jaroslav Tulach
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)
66 public final class JSONTest {
71 @ModelOperation static void assignFetched(JSONik m, Person p) {
76 @KOTest public void toJSONInABrowser() throws Throwable {
77 Person p = Models.bind(new Person(), newContext());
79 p.setFirstName("Jarda");
80 p.setLastName("Tulach");
84 json = parseJSON(p.toString());
85 } catch (Throwable ex) {
86 throw new IllegalStateException("Can't parse " + p).initCause(ex);
89 Person p2 = Models.fromRaw(newContext(), Person.class, json);
91 assert p2.getFirstName().equals(p.getFirstName()) :
92 "Should be the same: " + p.getFirstName() + " != " + p2.getFirstName();
95 @KOTest public void toJSONWithEscapeCharactersInABrowser() throws Throwable {
96 Person p = Models.bind(new Person(), newContext());
98 p.setFirstName("/*\n * Copyright (c) 2013");
101 final String txt = p.toString();
104 json = parseJSON(txt);
105 } catch (Throwable ex) {
106 throw new IllegalStateException("Can't parse " + txt).initCause(ex);
109 Person p2 = Models.fromRaw(newContext(), Person.class, json);
111 assert p2.getFirstName().equals(p.getFirstName()) :
112 "Should be the same: " + p.getFirstName() + " != " + p2.getFirstName();
115 @KOTest public void toJSONWithDoubleSlashInABrowser() throws Throwable {
116 Person p = Models.bind(new Person(), newContext());
118 p.setFirstName("/*\\n * Copyright (c) 2013");
121 final String txt = p.toString();
124 json = parseJSON(txt);
125 } catch (Throwable ex) {
126 throw new IllegalStateException("Can't parse " + txt).initCause(ex);
129 Person p2 = Models.fromRaw(newContext(), Person.class, json);
131 assert p2.getFirstName().equals(p.getFirstName()) :
132 "Should be the same: " + p.getFirstName() + " != " + p2.getFirstName();
135 @KOTest public void toJSONWithApostrophInABrowser() throws Throwable {
136 Person p = Models.bind(new Person(), newContext());
138 p.setFirstName("Jimmy 'Jim' Rambo");
141 final String txt = p.toString();
144 json = parseJSON(txt);
145 } catch (Throwable ex) {
146 throw new IllegalStateException("Can't parse " + txt).initCause(ex);
149 Person p2 = Models.fromRaw(newContext(), Person.class, json);
151 assert p2.getFirstName().equals(p.getFirstName()) :
152 "Should be the same: " + p.getFirstName() + " != " + p2.getFirstName();
155 private static BrwsrCtx onCallback;
157 @OnReceive(url="{url}")
158 static void fetch(JSONik model, Person p) {
160 onCallback = BrwsrCtx.findDefault(model.getClass());
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());
170 static void setMessage(JSONik m, Exception t) {
172 m.setFetchedResponse("Exception");
175 @OnReceive(url="{url}")
176 static void fetchPeople(JSONik model, People p) {
177 final int size = p.getInfo().size();
179 model.setFetched(p.getInfo().get(0));
181 model.setFetchedCount(size);
184 @OnReceive(url="{url}")
185 static void fetchPeopleAge(JSONik model, People p) {
187 for (int a : p.getAge()) {
190 model.setFetchedCount(sum);
193 @KOTest public void loadAndParseJSON() throws InterruptedException {
195 url = Utils.prepareURL(
196 JSONTest.class, "{'firstName': 'Sitar', 'sex': 'MALE'}",
199 js = Models.bind(new JSONik(), ctx = newContext());
206 Person p = js.getFetched();
208 throw new InterruptedException();
211 assert "Sitar".equals(p.getFirstName()) : "Expecting Sitar: " + p.getFirstName();
212 assert Sex.MALE.equals(p.getSex()) : "Expecting MALE: " + p.getSex();
214 assert ctx == onCallback;
217 @OnReceive(url="{url}?callme={me}", jsonp = "me")
218 static void fetchViaJSONP(JSONik model, Person p) {
222 @KOTest public void loadAndParseJSONP() throws InterruptedException, Exception {
224 url = Utils.prepareURL(
225 JSONTest.class, "$0({'firstName': 'Mitar', 'sex': 'MALE'})",
226 "application/javascript",
229 orig = scriptElements();
230 assert orig > 0 : "There should be some scripts on the page";
232 js = Models.bind(new JSONik(), newContext());
236 js.fetchViaJSONP(url);
239 Person p = js.getFetched();
241 throw new InterruptedException();
244 assert "Mitar".equals(p.getFirstName()) : "Unexpected: " + p.getFirstName();
245 assert Sex.MALE.equals(p.getSex()) : "Expecting MALE: " + p.getSex();
247 int now = scriptElements();
249 assert orig == now : "The set of elements is unchanged. Delta: " + (now - orig);
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);
260 @KOTest public void putPeopleUsesRightMethod() throws InterruptedException, Exception {
262 url = Utils.prepareURL(
263 JSONTest.class, "$0\n$1",
265 "http.method", "http.requestBody"
267 orig = scriptElements();
268 assert orig > 0 : "There should be some scripts on the page";
270 js = Models.bind(new JSONik(), newContext());
273 Person p = Models.bind(new Person(), BrwsrCtx.EMPTY);
274 p.setFirstName("Jarda");
275 js.putPerson(url, p);
278 int cnt = js.getFetchedCount();
280 throw new InterruptedException();
282 String res = js.getFetchedResponse();
283 int line = res.indexOf('\n');
286 msg = res.substring(line + 1);
287 res = res.substring(0, line);
292 assert "PUT".equals(res) : "Server was queried with PUT method: " + js.getFetchedResponse();
294 assert msg.contains("Jarda") : "Data transferred to the server: " + msg;
297 private static int scriptElements() throws Exception {
298 return ((Number)Utils.executeScript(
300 "return window.document.getElementsByTagName('script').length;")).intValue();
303 private static Object parseJSON(String s) throws Exception {
304 return Utils.executeScript(
306 "return window.JSON.parse(arguments[0]);", s);
309 @KOTest public void loadAndParseJSONSentToArray() throws InterruptedException {
311 url = Utils.prepareURL(
312 JSONTest.class, "{'firstName': 'Sitar', 'sex': 'MALE'}",
316 js = Models.bind(new JSONik(), newContext());
323 Person p = js.getFetched();
325 throw new InterruptedException();
328 assert "Sitar".equals(p.getFirstName()) : "Expecting Sitar: " + p.getFirstName();
329 assert Sex.MALE.equals(p.getSex()) : "Expecting MALE: " + p.getSex();
332 @KOTest public void loadAndParseJSONArraySingle() throws InterruptedException {
334 url = Utils.prepareURL(
335 JSONTest.class, "[{'firstName': 'Gitar', 'sex': 'FEMALE'}]",
338 js = Models.bind(new JSONik(), newContext());
345 Person p = js.getFetched();
347 throw new InterruptedException();
350 assert "Gitar".equals(p.getFirstName()) : "Expecting Gitar: " + p.getFirstName();
351 assert Sex.FEMALE.equals(p.getSex()) : "Expecting FEMALE: " + p.getSex();
354 @KOTest public void loadAndParseArrayInPeople() throws InterruptedException {
356 url = Utils.prepareURL(
357 JSONTest.class, "{'info':[{'firstName': 'Gitar', 'sex': 'FEMALE'}]}",
360 js = Models.bind(new JSONik(), newContext());
366 if (0 == js.getFetchedCount()) {
367 throw new InterruptedException();
370 assert js.getFetchedCount() == 1 : "One person loaded: " + js.getFetchedCount();
372 Person p = js.getFetched();
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();
379 @KOTest public void loadAndParseArrayOfIntegers() throws InterruptedException {
381 url = Utils.prepareURL(
382 JSONTest.class, "{'age':[1, 2, 3]}",
385 js = Models.bind(new JSONik(), newContext());
388 js.fetchPeopleAge(url);
391 if (0 == js.getFetchedCount()) {
392 throw new InterruptedException();
395 assert js.getFetchedCount() == 6 : "1 + 2 + 3 is " + js.getFetchedCount();
398 @OnReceive(url="{url}")
399 static void fetchPeopleSex(JSONik model, People p) {
400 model.setFetchedCount(1);
401 model.getFetchedSex().addAll(p.getSex());
404 @KOTest public void loadAndParseArrayOfEnums() throws InterruptedException {
406 url = Utils.prepareURL(
407 JSONTest.class, "{'sex':['FEMALE', 'MALE', 'MALE']}",
410 js = Models.bind(new JSONik(), newContext());
413 js.fetchPeopleSex(url);
416 if (0 == js.getFetchedCount()) {
417 throw new InterruptedException();
420 assert js.getFetchedCount() == 1 : "Loaded";
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();
428 @KOTest public void loadAndParseJSONArray() throws InterruptedException {
430 url = Utils.prepareURL(
431 JSONTest.class, "[{'firstName': 'Gitar', 'sex': 'FEMALE'},"
432 + "{'firstName': 'Peter', 'sex': 'MALE'}"
436 js = Models.bind(new JSONik(), newContext());
444 Person p = js.getFetched();
446 throw new InterruptedException();
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();
454 @KOTest public void loadError() throws InterruptedException {
456 js = Models.bind(new JSONik(), newContext());
460 js.fetchArray("http://127.0.0.1:54253/does/not/exist.txt");
464 if (js.getFetchedResponse() == null) {
465 throw new InterruptedException();
468 assert "Exception".equals(js.getFetchedResponse()) : js.getFetchedResponse();
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)
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();
488 @KOTest public void deserializeWrongEnum() throws Exception {
489 PrintStream prev = null;
490 ByteArrayOutputStream err = new ByteArrayOutputStream();
493 System.setErr(new PrintStream(err));
494 } catch (SecurityException e) {
497 } catch (LinkageError e) {
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();
508 assert err.toString().contains("unknown") && err.toString().contains("Sex"): "Expecting error: " + err.toString();
513 } catch (LinkageError e) {
520 private static BrwsrCtx newContext() {
521 return Utils.newContext(JSONTest.class);