blob: 46a6baf120f2d8c95d369b42cf7736a1afe20694 [file] [log] [blame]
bobv@google.coma29cb152011-04-08 14:17:10 +00001/*
2 * Copyright 2011 Google Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5 * use this file except in compliance with the License. You may obtain a copy of
6 * the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 * License for the specific language governing permissions and limitations under
14 * the License.
15 */
bobv@google.comb0068d72011-04-18 09:42:06 +000016package com.google.web.bindery.autobean.shared;
bobv@google.coma29cb152011-04-08 14:17:10 +000017
bobv@google.comb0068d72011-04-18 09:42:06 +000018import com.google.web.bindery.autobean.gwt.client.impl.JsoSplittable;
19import com.google.web.bindery.autobean.shared.impl.AutoBeanCodexImpl;
20import com.google.web.bindery.autobean.shared.impl.AutoBeanCodexImpl.Coder;
21import com.google.web.bindery.autobean.shared.impl.AutoBeanCodexImpl.EncodeState;
22import com.google.web.bindery.autobean.shared.impl.SplittableList;
23import com.google.web.bindery.autobean.shared.impl.SplittableSimpleMap;
24import com.google.web.bindery.autobean.shared.impl.StringQuoter;
bobv@google.coma29cb152011-04-08 14:17:10 +000025import com.google.gwt.core.client.GWT;
26import com.google.gwt.junit.client.GWTTestCase;
27
28import java.util.Arrays;
29import java.util.HashSet;
30import java.util.List;
31import java.util.Map;
32
33/**
34 * Tests for the underlying Splittable implementation. This test class is not
35 * indicative of code that users would write, it's simply doing spot-checks of
36 * functionality that AbstractAutoBean depends on.
37 */
38public class SplittableTest extends GWTTestCase {
39
40 /**
41 *
42 */
43 private static final EncodeState testState = EncodeState.forTesting();
44
45 @Override
46 public String getModuleName() {
bobv@google.comb0068d72011-04-18 09:42:06 +000047 return "com.google.web.bindery.autobean.AutoBean";
bobv@google.coma29cb152011-04-08 14:17:10 +000048 }
49
50 public void testBasicProperties() {
51 Splittable data = StringQuoter.split("{\"a\":true, \"b\":3, \"c\":\"string\", \"d\":null}");
52 assertTrue("isBoolean", data.get("a").isBoolean());
53 assertTrue("asBoolean", data.get("a").asBoolean());
54 assertTrue("isNumber", data.get("b").isNumber());
55 assertEquals(3.0, data.get("b").asNumber());
56 assertTrue("isString", data.get("c").isString());
57 assertEquals("string", data.get("c").asString());
58 assertTrue("isNull", data.isNull("d"));
59 assertNull("should be null", data.get("d"));
60 }
61
62 /**
63 * Ensure that hashcodes don't leak into the payload.
64 */
65 public void testHashCode() {
66 Splittable data = StringQuoter.split("{\"a\":\"b\"}");
67 int hash = data.hashCode();
68 String payload = data.getPayload();
69 assertFalse(payload, payload.contains("$H"));
70 assertFalse(payload, payload.contains(String.valueOf(hash)));
71 assertEquals(hash, data.hashCode());
72 }
73
74 /**
75 * Splittables are implemented by a couple of different concrete types. We'll
76 * use this method to make sure that the correct implementation type is being
77 * used in various circumstances.
78 */
79 public void testImplementationChoice() {
80 Splittable s = StringQuoter.split("[1,false,\"true\"]");
81 if (GWT.isScript()) {
82 assertTrue("s should be JsoSplittable", s instanceof JsoSplittable);
83 assertTrue("s[0] should be JsoSplittable", s.get(0) instanceof JsoSplittable);
84 assertTrue("s[1] should be JsoSplittable", s.get(1) instanceof JsoSplittable);
85 assertTrue("s[2] should be JsoSplittable", s.get(2) instanceof JsoSplittable);
86 } else {
87 // Using the same types in both pure-JRE and DevMode to avoid JSNI
88 // overhead
89 assertTrue("s should be JsonSplittable", s.getClass().getName().endsWith("JsonSplittable"));
90 assertTrue("s[0] should be JsonSplittable", s.get(0).getClass().getName().endsWith(
91 "JsonSplittable"));
92 assertTrue("s[1] should be JsonSplittable", s.get(1).getClass().getName().endsWith(
93 "JsonSplittable"));
94 assertTrue("s[2] should be JsonSplittable", s.get(2).getClass().getName().endsWith(
95 "JsonSplittable"));
96 }
97 }
98
99 public void testIndexed() {
100 Splittable s = StringQuoter.createIndexed();
101 assertTrue(s.isIndexed());
102 assertFalse(s.isKeyed());
103 assertFalse(s.isString());
104 assertEquals(0, s.size());
105
106 string("foo").assign(s, 0);
107 string("bar").assign(s, 1);
108 string("baz").assign(s, 2);
109
110 assertEquals(3, s.size());
111 assertEquals("[\"foo\",\"bar\",\"baz\"]", s.getPayload());
112
113 string("quux").assign(s, 1);
114 assertEquals("[\"foo\",\"quux\",\"baz\"]", s.getPayload());
115
116 Splittable s2 = s.deepCopy();
117 assertNotSame(s, s2);
118 assertEquals(s.size(), s2.size());
119 for (int i = 0, j = s.size(); i < j; i++) {
120 assertEquals(s.get(i).asString(), s2.get(i).asString());
121 }
122
123 s.setSize(2);
124 assertEquals(2, s.size());
125 assertEquals("[\"foo\",\"quux\"]", s.getPayload());
126
127 // Make sure reified values aren't in the payload
128 Object o = new Object();
129 s.setReified("reified", o);
130 assertFalse(s.getPayload().contains("reified"));
131 assertFalse(s.getPayload().contains("__s"));
132 assertSame(o, s.getReified("reified"));
133 }
134
135 public void testKeyed() {
136 Splittable s = StringQuoter.createSplittable();
137 assertFalse(s.isIndexed());
138 assertTrue(s.isKeyed());
139 assertFalse(s.isString());
140 assertTrue(s.getPropertyKeys().isEmpty());
141
142 string("bar").assign(s, "foo");
143 string("quux").assign(s, "baz");
144
145 // Actual iteration order is undefined
146 assertEquals(new HashSet<String>(Arrays.asList("foo", "baz")), new HashSet<String>(s
147 .getPropertyKeys()));
148
149 assertFalse(s.isNull("foo"));
150 assertTrue(s.isNull("bar"));
151
152 assertEquals("bar", s.get("foo").asString());
153 assertEquals("quux", s.get("baz").asString());
154
155 String payload = s.getPayload();
156 assertTrue(payload.startsWith("{"));
157 assertTrue(payload.endsWith("}"));
158 assertTrue(payload.contains("\"foo\":\"bar\""));
159 assertTrue(payload.contains("\"baz\":\"quux\""));
160
161 Splittable s2 = s.deepCopy();
162 assertNotSame(s, s2);
163 assertEquals("bar", s2.get("foo").asString());
164 assertEquals("quux", s2.get("baz").asString());
165
166 // Make sure reified values aren't in the payload
167 Object o = new Object();
168 s.setReified("reified", o);
169 assertFalse("Should not see reified in " + s.getPayload(), s.getPayload().contains("reified"));
170 assertFalse("Should not see __s in " + s.getPayload(), s.getPayload().contains("__s"));
171 assertSame(o, s.getReified("reified"));
172 }
173
174 public void testNested() {
175 Splittable s = StringQuoter.split("{\"a\":{\"foo\":\"bar\"}}");
176 Splittable a = s.get("a");
177 assertNotNull(a);
178 assertEquals("bar", a.get("foo").asString());
179 assertSame(a, s.get("a"));
180 assertEquals(a, s.get("a"));
181 }
182
183 /**
184 * Tests attributes of the {@link Splittable#NULL} field.
185 */
186 public void testNull() {
187 Splittable n = Splittable.NULL;
188 if (GWT.isScript()) {
189 assertNull(n);
190 } else {
191 assertNotNull(n);
192 }
193 assertFalse("boolean", n.isBoolean());
194 assertFalse("indexed", n.isIndexed());
195 assertFalse("keyed", n.isKeyed());
196 assertFalse("string", n.isString());
197 assertEquals("null", n.getPayload());
198 }
199
200 /**
201 * Extra tests in here due to potential to confuse {@code false} and
202 * {@code null} values.
203 */
204 public void testSplittableListBoolean() {
205 Coder boolCoder = AutoBeanCodexImpl.valueCoder(Boolean.class);
206 Splittable s = StringQuoter.createIndexed();
207 bool(false).assign(s, 0);
208 assertFalse("0 should not be null", s.isNull(0));
209 assertTrue("s[0] should be a boolean", s.get(0).isBoolean());
210 assertFalse("s[0] should be false", s.get(0).asBoolean());
211 assertNotNull("Null decode", ValueCodex.decode(Boolean.class, s.get(0)));
212 Object decodedBoolean = boolCoder.decode(testState, s.get(0));
213 assertNotNull("decode should not return null", decodedBoolean);
214 assertFalse("decoded value should be false", (Boolean) decodedBoolean);
215
216 bool(true).assign(s, 1);
217 assertTrue("s[1] should be a boolean", s.get(1).isBoolean());
218 assertTrue("s[1] should be true", s.get(1).asBoolean());
219 assertTrue("boolCoder 1", (Boolean) boolCoder.decode(testState, s.get(1)));
220
221 Splittable.NULL.assign(s, 2);
222 assertTrue("3 should be null", s.isNull(3));
223 assertEquals("payload", "[false,true,null]", s.getPayload());
224 List<Boolean> boolList = new SplittableList<Boolean>(s, boolCoder, testState);
225 assertEquals("boolList", Arrays.<Boolean> asList(false, true, null), boolList);
226 }
227
228 /**
229 * Extra tests in here due to potential to confuse 0 and {@code null} values.
230 */
231 public void testSplittableListNumbers() {
232 Coder intCoder = AutoBeanCodexImpl.valueCoder(Integer.class);
233 Coder doubleCoder = AutoBeanCodexImpl.valueCoder(Double.class);
234 Splittable s = StringQuoter.createIndexed();
235 number(0).assign(s, 0);
236 assertFalse("0 should not be null", s.isNull(0));
237 assertTrue("s[0] should be a number", s.get(0).isNumber());
238 assertNotNull("Null decode", ValueCodex.decode(Integer.class, s.get(0)));
239 Object decodedInt = intCoder.decode(testState, s.get(0));
240 assertNotNull("decode should not return null", decodedInt);
241 assertEquals("intCoder 0", Integer.valueOf(0), decodedInt);
242 assertEquals("doubleCoder 0", Double.valueOf(0), doubleCoder.decode(testState, s.get(0)));
243
244 number(3.141592).assign(s, 1);
245 assertEquals("intCoder 1", Integer.valueOf(3), intCoder.decode(testState, s.get(1)));
246 assertEquals("doubleCoder 1", Double.valueOf(3.141592), doubleCoder.decode(testState, s.get(1)));
247
248 number(42).assign(s, 2);
249 Splittable.NULL.assign(s, 3);
250 assertTrue("3 should be null", s.isNull(3));
251 assertEquals("payload", "[0,3.141592,42,null]", s.getPayload());
252 List<Double> doubleList = new SplittableList<Double>(s, doubleCoder, testState);
253 assertEquals(Double.valueOf(0), doubleList.get(0));
254 assertEquals("doubleList", Arrays.<Double> asList(0d, 3.141592, 42d, null), doubleList);
255
256 // Don't share backing data between lists
257 s = StringQuoter.split("[0,3.141592,42,null]");
258 List<Integer> intList = new SplittableList<Integer>(s, intCoder, testState);
259 assertEquals("intList", Arrays.<Integer> asList(0, 3, 42, null), intList);
260 }
261
262 public void testSplittableListString() {
263 Splittable data = StringQuoter.split("[\"Hello\",\"World\"]");
264 SplittableList<String> list =
265 new SplittableList<String>(data, AutoBeanCodexImpl.valueCoder(String.class), testState);
266 assertEquals(2, list.size());
267 assertEquals(Arrays.asList("Hello", "World"), list);
268 list.set(0, "Goodbye");
269 assertEquals(Arrays.asList("Goodbye", "World"), list);
270 assertEquals("[\"Goodbye\",\"World\"]", data.getPayload());
271 list.remove(0);
272 assertEquals(Arrays.asList("World"), list);
273 assertEquals("[\"World\"]", data.getPayload());
274 list.add("Wide");
275 list.add("Web");
276 assertEquals(Arrays.asList("World", "Wide", "Web"), list);
277 assertEquals("[\"World\",\"Wide\",\"Web\"]", data.getPayload());
278 }
279
280 public void testSplittableMapStringString() {
281 Splittable data = StringQuoter.split("{\"foo\":\"bar\",\"baz\":\"quux\",\"isNull\":null}");
282 assertTrue("isNull should be null", data.isNull("isNull"));
283 assertFalse("isNull should not be undefined", data.isUndefined("isNull"));
284 Map<String, String> map =
285 new SplittableSimpleMap<String, String>(data, AutoBeanCodexImpl.valueCoder(String.class),
286 AutoBeanCodexImpl.valueCoder(String.class), testState);
287 assertEquals(3, map.size());
288 assertEquals("bar", map.get("foo"));
289 assertEquals("quux", map.get("baz"));
290 assertTrue("Map should have isNull key", map.containsKey("isNull"));
291 assertNull(map.get("isNull"));
292 assertFalse("Map should not have unknown key", map.containsKey("unknown"));
293
294 map.put("bar", "foo2");
295 assertEquals("foo2", map.get("bar"));
296 String payload = data.getPayload();
297 assertTrue(payload.contains("\"bar\":\"foo2\""));
298 assertTrue(payload.contains("\"isNull\":null"));
299 }
300
301 public void testString() {
302 Splittable s = string("Hello '\" World!");
303 assertFalse(s.isIndexed());
304 assertFalse(s.isKeyed());
305 assertTrue(s.isString());
306 assertEquals("Hello '\" World!", s.asString());
307 assertEquals("\"Hello '\\\" World!\"", s.getPayload());
308 }
309
310 public void testStringEmpty() {
311 Splittable s = string("");
312 assertFalse(s.isIndexed());
313 assertFalse(s.isKeyed());
314 assertTrue(s.isString());
315 assertEquals("", s.asString());
316 assertEquals("\"\"", s.getPayload());
317 }
318
319 private Splittable bool(boolean value) {
320 return StringQuoter.split(String.valueOf(value));
321 }
322
323 private Splittable number(double number) {
324 return StringQuoter.split(String.valueOf(number));
325 }
326
327 private Splittable string(String value) {
328 return StringQuoter.split(StringQuoter.quote(value));
329 }
330}