Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / resources / chromeos / chromevox / common / spannable_test.unitjs
blob8a26cfeb5d33c49e0cd10ab518ac9d65c1823084
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 // Include test fixture.
6 GEN_INCLUDE(['../testing/chromevox_unittest_base.js']);
8 UnserializableSpan = function() {};
10 StatelessSerializableSpan = function() {};
12 NonStatelessSerializableSpan = function(value) {
13   this.value = value;
16 /**
17  * @param {!Object} obj object containing the
18  *     serializable representation.
19  * @return {!Object} The Spannable.
20  */
21 NonStatelessSerializableSpan.fromJson = function(obj) {
22   return new NonStatelessSerializableSpan(obj.value / 2);
25 /**
26  * @return {Object} the json serializable form.
27  */
28 NonStatelessSerializableSpan.prototype.toJson = function() {
29   return {value: this.value * 2};
32 /**
33  * Test fixture.
34  * @constructor
35  * @extends {ChromeVoxUnitTestBase}
36  */
37 function CvoxSpannableUnitTest() {}
39 CvoxSpannableUnitTest.prototype = {
40   __proto__: ChromeVoxUnitTestBase.prototype,
42   /** @override */
43   closureModuleDeps: [
44     'cvox.Spannable',
45   ],
47   /** @override */
48   setUp: function() {
49     cvox.Spannable.registerStatelessSerializableSpan(
50         StatelessSerializableSpan, 'StatelessSerializableSpan');
52     cvox.Spannable.registerSerializableSpan(
53         NonStatelessSerializableSpan, 'NonStatelessSerializableSpan',
54         NonStatelessSerializableSpan.fromJson,
55         NonStatelessSerializableSpan.prototype.toJson);
56   }
59 TEST_F('CvoxSpannableUnitTest', 'ToStringUnannotated', function() {
60   assertEquals('', new cvox.Spannable().toString());
61   assertEquals('hello world', new cvox.Spannable('hello world').toString());
62 });
64 /** Tests that toString works correctly on annotated strings. */
65 TEST_F('CvoxSpannableUnitTest', 'ToStringAnnotated', function() {
66   var spannable = new cvox.Spannable('Hello Google');
67   spannable.setSpan('http://www.google.com/', 6, 12);
68   assertEquals('Hello Google', spannable.toString());
69 });
71 /** Tests the length calculation. */
72 TEST_F('CvoxSpannableUnitTest', 'GetLength', function() {
73   var spannable = new cvox.Spannable('Hello');
74   spannable.setSpan({}, 0, 3);
75   assertEquals(5, spannable.getLength());
76   spannable.append(' world');
77   assertEquals(11, spannable.getLength());
78   spannable.append(new cvox.Spannable(' from cvox.Spannable'));
79   assertEquals(31, spannable.getLength());
80 });
82 /** Tests that a span can be added and retrieved at the beginning. */
83 TEST_F('CvoxSpannableUnitTest', 'SpanBeginning', function() {
84   var annotation = {};
85   var spannable = new cvox.Spannable('Hello world');
86   spannable.setSpan(annotation, 0, 5);
87   assertSame(annotation, spannable.getSpan(0));
88   assertSame(annotation, spannable.getSpan(3));
89   assertUndefined(spannable.getSpan(5));
90   assertUndefined(spannable.getSpan(8));
91 });
93 /** Tests that a span can be added and retrieved at the beginning. */
94 TEST_F('CvoxSpannableUnitTest', 'SpanEnd', function() {
95   var annotation = {};
96   var spannable = new cvox.Spannable('Hello world');
97   spannable.setSpan(annotation, 6, 11);
98   assertUndefined(spannable.getSpan(3));
99   assertUndefined(spannable.getSpan(5));
100   assertSame(annotation, spannable.getSpan(6));
101   assertSame(annotation, spannable.getSpan(10));
104 /** Tests that a zero-length span is not retrieved. */
105 TEST_F('CvoxSpannableUnitTest', 'SpanZeroLength', function() {
106   var annotation = {};
107   var spannable = new cvox.Spannable('Hello world');
108   spannable.setSpan(annotation, 3, 3);
109   assertUndefined(spannable.getSpan(2));
110   assertUndefined(spannable.getSpan(3));
111   assertUndefined(spannable.getSpan(4));
114 /** Tests that a removed span is not returned. */
115 TEST_F('CvoxSpannableUnitTest', 'RemoveSpan', function() {
116   var annotation = {};
117   var spannable = new cvox.Spannable('Hello world');
118   spannable.setSpan(annotation, 0, 3);
119   assertSame(annotation, spannable.getSpan(1));
120   spannable.removeSpan(annotation);
121   assertUndefined(spannable.getSpan(1));
124 /** Tests that adding a span in one place removes it from another. */
125 TEST_F('CvoxSpannableUnitTest', 'SetSpanMoves', function() {
126   var annotation = {};
127   var spannable = new cvox.Spannable('Hello world');
128   spannable.setSpan(annotation, 0, 3);
129   assertSame(annotation, spannable.getSpan(1));
130   assertUndefined(spannable.getSpan(4));
131   spannable.setSpan(annotation, 3, 6);
132   assertUndefined(spannable.getSpan(1));
133   assertSame(annotation, spannable.getSpan(4));
136 /** Tests that setSpan objects to out-of-range arguments. */
137 TEST_F('CvoxSpannableUnitTest', 'SetSpanRangeError', function() {
138   var spannable = new cvox.Spannable('Hello world');
140   // Start index out of range.
141   assertException('expected range error', function() {
142     spannable.setSpan({}, -1, 0);
143   }, 'RangeError');
145   // End index out of range.
146   assertException('expected range error', function() {
147     spannable.setSpan({}, 0, 12);
148   }, 'RangeError');
150   // End before start.
151   assertException('expected range error', function() {
152     spannable.setSpan({}, 1, 0);
153   }, 'RangeError');
157  * Tests that multiple spans can be retrieved at one point.
158  * The first one added which applies should be returned by getSpan.
159  */
160 TEST_F('CvoxSpannableUnitTest', 'MultipleSpans', function() {
161   var annotation1 = { number: 1 };
162   var annotation2 = { number: 2 };
163   assertNotSame(annotation1, annotation2);
164   var spannable = new cvox.Spannable('Hello world');
165   spannable.setSpan(annotation1, 1, 4);
166   spannable.setSpan(annotation2, 2, 7);
167   assertSame(annotation1, spannable.getSpan(1));
168   assertThat([annotation1], eqJSON(spannable.getSpans(1)));
169   assertSame(annotation1, spannable.getSpan(3));
170   assertThat([annotation1, annotation2], eqJSON(spannable.getSpans(3)));
171   assertSame(annotation2, spannable.getSpan(6));
172   assertThat([annotation2], eqJSON(spannable.getSpans(6)));
175 /** Tests that appending appends the strings. */
176 TEST_F('CvoxSpannableUnitTest', 'AppendToString', function() {
177   var spannable = new cvox.Spannable('Google');
178   assertEquals('Google', spannable.toString());
179   spannable.append(' Chrome');
180   assertEquals('Google Chrome', spannable.toString());
181   spannable.append(new cvox.Spannable('Vox'));
182   assertEquals('Google ChromeVox', spannable.toString());
186  * Tests that appending Spannables combines annotations.
187  */
188 TEST_F('CvoxSpannableUnitTest', 'AppendAnnotations', function() {
189   var annotation1 = { number: 1 };
190   var annotation2 = { number: 2 };
191   assertNotSame(annotation1, annotation2);
192   var left = new cvox.Spannable('hello');
193   left.setSpan(annotation1, 0, 3);
194   var right = new cvox.Spannable(' world');
195   right.setSpan(annotation2, 0, 3);
196   left.append(right);
197   assertSame(annotation1, left.getSpan(1));
198   assertSame(annotation2, left.getSpan(6));
202  * Tests that a span's bounds can be retrieved.
203  */
204 TEST_F('CvoxSpannableUnitTest', 'GetSpanStartAndEnd', function() {
205   var annotation = {};
206   var spannable = new cvox.Spannable('potato wedges');
207   spannable.setSpan(annotation, 8, 12);
208   assertEquals(8, spannable.getSpanStart(annotation));
209   assertEquals(12, spannable.getSpanEnd(annotation));
213  * Tests that an absent span's bounds are reported correctly.
214  */
215 TEST_F('CvoxSpannableUnitTest', 'GetSpanStartAndEndAbsent', function() {
216   var annotation = {};
217   var spannable = new cvox.Spannable('potato wedges');
218   assertUndefined(spannable.getSpanStart(annotation));
219   assertUndefined(spannable.getSpanEnd(annotation));
223  * Test that a zero length span can still be found.
224  */
225 TEST_F('CvoxSpannableUnitTest', 'GetSpanStartAndEndZeroLength', function() {
226   var annotation = {};
227   var spannable = new cvox.Spannable('potato wedges');
228   spannable.setSpan(annotation, 8, 8);
229   assertEquals(8, spannable.getSpanStart(annotation));
230   assertEquals(8, spannable.getSpanEnd(annotation));
234  * Tests that == (but not ===) objects are treated distinctly when getting
235  * span bounds.
236  */
237 TEST_F('CvoxSpannableUnitTest', 'GetSpanStartAndEndEquality', function() {
238   // Note that 0 == '' and '' == 0 in JavaScript.
239   var spannable = new cvox.Spannable('wat');
240   spannable.setSpan(0, 0, 0);
241   spannable.setSpan('', 1, 3);
242   assertEquals(0, spannable.getSpanStart(0));
243   assertEquals(0, spannable.getSpanEnd(0));
244   assertEquals(1, spannable.getSpanStart(''));
245   assertEquals(3, spannable.getSpanEnd(''));
249  * Tests that substrings have the correct character sequence.
250  */
251 TEST_F('CvoxSpannableUnitTest', 'Substring', function() {
252   var assertSubstringResult = function(expected, initial, start, opt_end) {
253     var spannable = new cvox.Spannable(initial);
254     var substring = spannable.substring(start, opt_end);
255     assertEquals(expected, substring.toString());
256   };
257   assertSubstringResult('Page', 'Google PageRank', 7, 11);
258   assertSubstringResult('Goog', 'Google PageRank', 0, 4);
259   assertSubstringResult('Rank', 'Google PageRank', 11, 15);
260   assertSubstringResult('Rank', 'Google PageRank', 11);
264  * Tests that substring arguments are validated properly.
265  */
266 TEST_F('CvoxSpannableUnitTest', 'SubstringRangeError', function() {
267   var assertRangeError = function(initial, start, opt_end) {
268     var spannable = new cvox.Spannable(initial);
269     assertException('expected range error', function() {
270       spannable.substring(start, opt_end);
271     }, 'RangeError');
272   };
273   assertRangeError('Google PageRank', -1, 5);
274   assertRangeError('Google PageRank', 0, 99);
275   assertRangeError('Google PageRank', 5, 2);
279  * Tests that spans in the substring range are preserved.
280  */
281 TEST_F('CvoxSpannableUnitTest', 'SubstringSpansIncluded', function() {
282   var assertSpanIncluded = function(expectedSpanStart, expectedSpanEnd,
283       initial, initialSpanStart, initialSpanEnd, start, opt_end) {
284     var annotation = {};
285     var spannable = new cvox.Spannable(initial);
286     spannable.setSpan(annotation, initialSpanStart, initialSpanEnd);
287     var substring = spannable.substring(start, opt_end);
288     assertEquals(expectedSpanStart, substring.getSpanStart(annotation));
289     assertEquals(expectedSpanEnd, substring.getSpanEnd(annotation));
290   };
291   assertSpanIncluded(1, 5, 'potato wedges', 8, 12, 7);
292   assertSpanIncluded(1, 5, 'potato wedges', 8, 12, 7, 13);
293   assertSpanIncluded(1, 5, 'potato wedges', 8, 12, 7, 12);
294   assertSpanIncluded(0, 4, 'potato wedges', 8, 12, 8, 12);
295   assertSpanIncluded(0, 3, 'potato wedges', 0, 3, 0);
296   assertSpanIncluded(0, 3, 'potato wedges', 0, 3, 0, 3);
297   assertSpanIncluded(0, 3, 'potato wedges', 0, 3, 0, 6);
298   assertSpanIncluded(0, 5, 'potato wedges', 8, 13, 8);
299   assertSpanIncluded(0, 5, 'potato wedges', 8, 13, 8, 13);
300   assertSpanIncluded(1, 6, 'potato wedges', 8, 13, 7, 13);
302   // Note: we should keep zero-length spans, even at the edges of the range.
303   assertSpanIncluded(0, 0, 'potato wedges', 0, 0, 0, 0);
304   assertSpanIncluded(0, 0, 'potato wedges', 0, 0, 0, 6);
305   assertSpanIncluded(1, 1, 'potato wedges', 8, 8, 7, 13);
306   assertSpanIncluded(6, 6, 'potato wedges', 6, 6, 0, 6);
310  * Tests that spans outside the range are omitted.
311  * It's fine to keep zero-length spans at the ends, though.
312  */
313 TEST_F('CvoxSpannableUnitTest', 'SubstringSpansExcluded', function() {
314   var assertSpanExcluded = function(initial, spanStart, spanEnd,
315       start, opt_end) {
316     var annotation = {};
317     var spannable = new cvox.Spannable(initial);
318     spannable.setSpan(annotation, spanStart, spanEnd);
319     var substring = spannable.substring(start, opt_end);
320     assertUndefined(substring.getSpanStart(annotation));
321     assertUndefined(substring.getSpanEnd(annotation));
322   };
323   assertSpanExcluded('potato wedges', 8, 12, 0, 6);
324   assertSpanExcluded('potato wedges', 7, 12, 0, 6);
325   assertSpanExcluded('potato wedges', 0, 6, 8);
326   assertSpanExcluded('potato wedges', 6, 6, 8);
330  * Tests that spans which cross the boundary are clipped.
331  */
332 TEST_F('CvoxSpannableUnitTest', 'SubstringSpansClipped', function() {
333   var assertSpanIncluded = function(expectedSpanStart, expectedSpanEnd,
334       initial, initialSpanStart, initialSpanEnd, start, opt_end) {
335     var annotation = {};
336     var spannable = new cvox.Spannable(initial);
337     spannable.setSpan(annotation, initialSpanStart, initialSpanEnd);
338     var substring = spannable.substring(start, opt_end);
339     assertEquals(expectedSpanStart, substring.getSpanStart(annotation));
340     assertEquals(expectedSpanEnd, substring.getSpanEnd(annotation));
341   };
342   assertSpanIncluded(0, 4, 'potato wedges', 7, 13, 8, 12);
343   assertSpanIncluded(0, 0, 'potato wedges', 0, 6, 0, 0);
344   assertSpanIncluded(0, 0, 'potato wedges', 0, 6, 6, 6);
346   // The first of the above should produce "edge".
347   assertEquals('edge',
348       new cvox.Spannable('potato wedges').substring(8, 12).toString());
352  * Tests that whitespace is trimmed.
353  */
354 TEST_F('CvoxSpannableUnitTest', 'Trim', function() {
355   var assertTrimResult = function(expected, initial) {
356     assertEquals(expected, new cvox.Spannable(initial).trim().toString());
357   };
358   assertTrimResult('John F. Kennedy', 'John F. Kennedy');
359   assertTrimResult('John F. Kennedy', '  John F. Kennedy');
360   assertTrimResult('John F. Kennedy', 'John F. Kennedy     ');
361   assertTrimResult('John F. Kennedy', '   \r\t   \nJohn F. Kennedy\n\n \n');
362   assertTrimResult('', '');
363   assertTrimResult('', '     \t\t    \n\r');
367  * Tests that trim keeps, drops and clips spans.
368  */
369 TEST_F('CvoxSpannableUnitTest', 'TrimSpans', function() {
370   var spannable = new cvox.Spannable(' \t Kennedy\n');
371   spannable.setSpan('tab', 1, 2);
372   spannable.setSpan('jfk', 3, 10);
373   spannable.setSpan('jfk-newline', 3, 11);
374   var trimmed = spannable.trim();
375   assertUndefined(trimmed.getSpanStart('tab'));
376   assertUndefined(trimmed.getSpanEnd('tab'));
377   assertEquals(0, trimmed.getSpanStart('jfk'));
378   assertEquals(7, trimmed.getSpanEnd('jfk'));
379   assertEquals(0, trimmed.getSpanStart('jfk-newline'));
380   assertEquals(7, trimmed.getSpanEnd('jfk-newline'));
384  * Tests that when a string is all whitespace, we trim off the *end*.
385  */
386 TEST_F('CvoxSpannableUnitTest', 'TrimAllWhitespace', function() {
387   var spannable = new cvox.Spannable('    ');
388   spannable.setSpan('cursor 1', 0, 0);
389   spannable.setSpan('cursor 2', 2, 2);
390   var trimmed = spannable.trim();
391   assertEquals(0, trimmed.getSpanStart('cursor 1'));
392   assertEquals(0, trimmed.getSpanEnd('cursor 1'));
393   assertUndefined(trimmed.getSpanStart('cursor 2'));
394   assertUndefined(trimmed.getSpanEnd('cursor 2'));
398  * Tests finding a span which is an instance of a given class.
399  */
400 TEST_F('CvoxSpannableUnitTest', 'GetSpanInstanceOf', function() {
401   function ExampleConstructorBase() {}
402   function ExampleConstructor1() {}
403   function ExampleConstructor2() {}
404   function ExampleConstructor3() {}
405   ExampleConstructor1.prototype = new ExampleConstructorBase();
406   ExampleConstructor2.prototype = new ExampleConstructorBase();
407   ExampleConstructor3.prototype = new ExampleConstructorBase();
408   var ex1 = new ExampleConstructor1();
409   var ex2 = new ExampleConstructor2();
410   var spannable = new cvox.Spannable('Hello world');
411   spannable.setSpan(ex1, 0, 0);
412   spannable.setSpan(ex2, 1, 1);
413   assertEquals(ex1, spannable.getSpanInstanceOf(ExampleConstructor1));
414   assertEquals(ex2, spannable.getSpanInstanceOf(ExampleConstructor2));
415   assertUndefined(spannable.getSpanInstanceOf(ExampleConstructor3));
416   assertEquals(ex1, spannable.getSpanInstanceOf(ExampleConstructorBase));
419 /** Tests trimming only left or right. */
420 TEST_F('CvoxSpannableUnitTest', 'TrimLeftOrRight', function() {
421   var spannable = new cvox.Spannable('    ');
422   spannable.setSpan('cursor 1', 0, 0);
423   spannable.setSpan('cursor 2', 2, 2);
424   var trimmed = spannable.trimLeft();
425   assertEquals(0, trimmed.getSpanStart('cursor 1'));
426   assertEquals(0, trimmed.getSpanEnd('cursor 1'));
427   assertUndefined(trimmed.getSpanStart('cursor 2'));
428   assertUndefined(trimmed.getSpanEnd('cursor 2'));
430   var spannable2 = new cvox.Spannable('0  ');
431   spannable2.setSpan('cursor 1', 0, 0);
432   spannable2.setSpan('cursor 2', 2, 2);
433   var trimmed2 = spannable2.trimLeft();
434   assertEquals(0, trimmed2.getSpanStart('cursor 1'));
435   assertEquals(0, trimmed2.getSpanEnd('cursor 1'));
436   assertEquals(2, trimmed2.getSpanStart('cursor 2'));
437   assertEquals(2, trimmed2.getSpanEnd('cursor 2'));
438   trimmed2 = trimmed2.trimRight();
439   assertEquals(0, trimmed2.getSpanStart('cursor 1'));
440   assertEquals(0, trimmed2.getSpanEnd('cursor 1'));
441   assertUndefined(trimmed2.getSpanStart('cursor 2'));
442   assertUndefined(trimmed2.getSpanEnd('cursor 2'));
444   var spannable3 = new cvox.Spannable('  0');
445   spannable3.setSpan('cursor 1', 0, 0);
446   spannable3.setSpan('cursor 2', 2, 2);
447   var trimmed3 = spannable3.trimRight();
448   assertEquals(0, trimmed3.getSpanStart('cursor 1'));
449   assertEquals(0, trimmed3.getSpanEnd('cursor 1'));
450   assertEquals(2, trimmed3.getSpanStart('cursor 2'));
451   assertEquals(2, trimmed3.getSpanEnd('cursor 2'));
452   trimmed3 = trimmed3.trimLeft();
453   assertUndefined(trimmed3.getSpanStart('cursor 1'));
454   assertUndefined(trimmed3.getSpanEnd('cursor 1'));
455   assertEquals(0, trimmed3.getSpanStart('cursor 2'));
456   assertEquals(0, trimmed3.getSpanEnd('cursor 2'));
459 TEST_F('CvoxSpannableUnitTest', 'Serialize', function() {
460   var fresh = new cvox.Spannable('text');
461   var freshStatelessSerializable = new StatelessSerializableSpan();
462   var freshNonStatelessSerializable = new NonStatelessSerializableSpan(14);
463   fresh.setSpan(new UnserializableSpan(), 0, 1);
464   fresh.setSpan(freshStatelessSerializable, 0, 2);
465   fresh.setSpan(freshNonStatelessSerializable, 3, 4);
466   var thawn = cvox.Spannable.fromJson(fresh.toJson());
467   var thawnStatelessSerializable = thawn.getSpanInstanceOf(
468       StatelessSerializableSpan);
469   var thawnNonStatelessSerializable = thawn.getSpanInstanceOf(
470       NonStatelessSerializableSpan);
471   assertThat('text', eqJSON(thawn.toString()));
472   assertUndefined(thawn.getSpanInstanceOf(UnserializableSpan));
473   assertThat(
474       fresh.getSpanStart(freshStatelessSerializable),
475       eqJSON(thawn.getSpanStart(thawnStatelessSerializable)));
476   assertThat(
477       fresh.getSpanEnd(freshStatelessSerializable),
478       eqJSON(thawn.getSpanEnd(thawnStatelessSerializable)));
479   assertThat(freshNonStatelessSerializable,
480              eqJSON(thawnNonStatelessSerializable));