EMMA Coverage Report (generated Mon Nov 01 16:48:29 PDT 2010)
[all classes][com.google.caja.render]

COVERAGE SUMMARY FOR SOURCE FILE [JsMinimalPrinterTest.java]

nameclass, %method, %block, %line, %
JsMinimalPrinterTest.java100% (2/2)100% (34/34)94%  (1139/1213)96%  (173.3/181)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class JsMinimalPrinterTest100% (1/1)100% (33/33)94%  (1080/1145)96%  (173.4/181)
<static initializer> 100% (1/1)100% (18/18)100% (5/5)
JsMinimalPrinterTest (): void 100% (1/1)100% (3/3)100% (2/2)
assertLexed (String, String): void 100% (1/1)100% (46/46)100% (11/11)
assertRendered (String, ParseTreeNode): void 100% (1/1)100% (25/25)100% (6/6)
assertRendered (String, String): void 100% (1/1)100% (34/34)100% (6/6)
assertTokens (String, String []): void 100% (1/1)100% (38/38)100% (7/7)
generateRandomTokens (Random): List 100% (1/1)96%  (195/204)95%  (39.9/42)
randomString (Random): String 100% (1/1)100% (47/47)100% (11/11)
randomWord (Random): String 100% (1/1)100% (40/40)100% (7/7)
testAdjacentBlocks (): void 100% (1/1)100% (5/5)100% (2/2)
testComments (): void 100% (1/1)100% (5/5)100% (2/2)
testConditional (): void 100% (1/1)100% (5/5)100% (2/2)
testConfusedTokenSequences (): void 100% (1/1)100% (31/31)100% (3/3)
testDivisionByRegex (): void 100% (1/1)100% (5/5)100% (2/2)
testEmptyBlock (): void 100% (1/1)100% (5/5)100% (2/2)
testJSON (): void 100% (1/1)100% (5/5)100% (2/2)
testMarkupEndStructures (): void 100% (1/1)100% (5/5)100% (2/2)
testMarkupStartStructure (): void 100% (1/1)100% (5/5)100% (2/2)
testMultipleStatements (): void 100% (1/1)100% (5/5)100% (2/2)
testNegatedNegativeNumericConstants (): void 100% (1/1)100% (17/17)100% (2/2)
testNoops (): void 100% (1/1)100% (56/56)100% (7/7)
testNumberPropertyAccess (): void 100% (1/1)100% (5/5)100% (2/2)
testNumbersAndDots (): void 100% (1/1)100% (64/64)100% (4/4)
testObjectConstructor (): void 100% (1/1)100% (5/5)100% (2/2)
testPunctuationRun (): void 100% (1/1)100% (5/5)100% (2/2)
testRestrictedSemicolonInsertion (): void 100% (1/1)100% (39/39)100% (8/8)
testRetokenization (): void 100% (1/1)62%  (93/149)77%  (19.1/25)
testSemisInsideParents (): void 100% (1/1)100% (5/5)100% (2/2)
testSimpleStatement (): void 100% (1/1)100% (5/5)100% (2/2)
testSpacingAroundBrackets1 (): void 100% (1/1)100% (58/58)100% (2/2)
testSpacingAroundBrackets2 (): void 100% (1/1)100% (62/62)100% (2/2)
testSpacingAroundBrackets3 (): void 100% (1/1)100% (62/62)100% (2/2)
testSpacingAroundBrackets4 (): void 100% (1/1)100% (82/82)100% (2/2)
     
class JsMinimalPrinterTest$1100% (1/1)100% (1/1)87%  (59/68)86%  (0.9/1)
<static initializer> 100% (1/1)87%  (59/68)86%  (0.9/1)

1// Copyright (C) 2008 Google Inc.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//      http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14 
15package com.google.caja.render;
16 
17import com.google.caja.SomethingWidgyHappenedError;
18import com.google.caja.lexer.FilePosition;
19import com.google.caja.lexer.JsLexer;
20import com.google.caja.lexer.JsTokenQueue;
21import com.google.caja.lexer.JsTokenType;
22import com.google.caja.lexer.Keyword;
23import com.google.caja.lexer.ParseException;
24import com.google.caja.lexer.Token;
25import com.google.caja.lexer.escaping.Escaping;
26import com.google.caja.parser.ParseTreeNode;
27import com.google.caja.parser.js.IntegerLiteral;
28import com.google.caja.parser.js.Operation;
29import com.google.caja.parser.js.Operator;
30import com.google.caja.parser.js.Parser;
31import com.google.caja.parser.js.StringLiteral;
32import com.google.caja.reporting.RenderContext;
33import com.google.caja.util.CajaTestCase;
34import com.google.caja.util.MoreAsserts;
35 
36import java.util.ArrayList;
37import java.util.List;
38import java.util.Random;
39 
40public class JsMinimalPrinterTest extends CajaTestCase {
41  public final void testEmptyBlock() throws Exception {
42    assertRendered("{{}}", "{}");
43  }
44 
45  public final void testAdjacentBlocks() throws Exception {
46    assertRendered("{{}{}}", "{}{}");
47  }
48 
49  public final void testSimpleStatement() throws Exception {
50    assertRendered("{foo()}", "foo();");
51  }
52 
53  public final void testSemisInsideParents() throws Exception {
54    assertRendered(
55        "{for(var i=0,n=a.length;i<n;++i){"
56        + "bar(a[i])}}",
57        "for (var i = 0, n = a.length; i < n; ++i) {"
58        + "  bar(a[ i ]);"
59        + "}");
60  }
61 
62  public final void testObjectConstructor() throws Exception {
63    assertRendered(
64        "{foo({'x':1,'y':bar({'w':4}),'z':3})}",
65        "foo({ x: 1, y: bar({ w: 4 }), z: 3 });");
66  }
67 
68  public final void testMultipleStatements() throws Exception {
69    assertRendered(
70        "{(function(a,b,c){foo(a);bar(b);return c})(1,2,3)}",
71        "(function (a, b, c) { foo(a); bar(b); return (c); })(1, 2, 3);");
72  }
73 
74  public final void testMarkupEndStructures() throws Exception {
75    // Make sure -->, </script, and ]]> don't show up in rendered output.
76    // Preventing these in strings is handled separately.
77    assertRendered(
78        "{(i--)>j,k< /script>/,[[0]] >0/ / / *x}",
79        "i-->j, k</script>/, [[0]]>0 / / / * x;");
80  }
81 
82  public final void testMarkupStartStructure() throws Exception {
83    // Make sure <!-- and <![CDATA[ don't show up in rendered output.
84    // Preventing these in strings is handled separately.
85    assertRendered(
86        "{1< !--b&&c< ![CDATA[0]]}",
87        "1<!--b && c<![CDATA[0]]");
88  }
89 
90  public final void testJSON() throws Exception {
91    assertRendered(
92        "{({'a':[1,2,3],'b':{'c':[{}],'d':[{'e':null,'f':'foo'},null]}})}",
93        "({ a: [1,2,3], b: { c: [{}], d: [{ e: null, f: 'foo' }, null] } });");
94  }
95 
96  public final void testConditional() throws Exception {
97    assertRendered(
98        "{if(c1){foo()}else if(c2)bar();else baz()}",
99        "if (c1) { foo(); } else if (c2) bar(); else baz();");
100  }
101 
102  public final void testNumberPropertyAccess() throws Exception {
103    assertRendered("{(3).toString()}", "(3).toString();");
104  }
105 
106  public final void testComments() throws Exception {
107    assertLexed(
108        "var x=foo;function Bar(){}var baz;a+b",
109 
110        ""
111        + "var x = foo;  /* end of line */\n"
112        + "/** Own line */\n"
113        + "function Bar() {}\n"
114        + "/* Beginning */ var baz;\n"
115        + "a +  // Line comment\n"
116        + "b;");
117  }
118 
119  public final void testDivisionByRegex() throws Exception {
120    assertLexed("3/ /foo/", "3 / /foo/;");
121  }
122 
123  public final void testPunctuationRun() throws Exception {
124    assertLexed("!=|| =", "!= || =");
125  }
126 
127  public final void testNegatedNegativeNumericConstants() {
128    assertRendered(
129        "-(-3)",  // not --3
130        Operation.create(
131            FilePosition.UNKNOWN, Operator.NEGATION,
132            new IntegerLiteral(FilePosition.UNKNOWN,-3)));
133  }
134 
135  public final void testRetokenization() throws Exception {
136    long seed = Long.parseLong(
137        System.getProperty("junit.seed", "" + System.currentTimeMillis()));
138    Random rnd = new Random(seed);
139    boolean pass = false;
140    try {
141      for (int i = 1000; --i >= 0;) {
142        List<String> randomTokens = generateRandomTokens(rnd);
143        StringBuilder sb = new StringBuilder();
144        JsMinimalPrinter pp = new JsMinimalPrinter(new Concatenator(sb));
145        for (String token : randomTokens) {
146          pp.consume(token);
147        }
148        pp.noMoreTokens();
149 
150        List<String> actualTokens = new ArrayList<String>();
151        try {
152          JsLexer lex = new JsLexer(fromString(sb.toString()));
153          while (lex.hasNext()) {
154            actualTokens.add(lex.next().text);
155          }
156        } catch (ParseException ex) {
157          for (String tok : randomTokens) {
158            System.err.println(StringLiteral.toQuotedValue(tok));
159          }
160          System.err.println("<<<" + sb + ">>>");
161          throw ex;
162        }
163 
164        MoreAsserts.assertListsEqual(randomTokens, actualTokens);
165      }
166      pass = true;
167    } finally {
168      if (!pass) { System.err.println("Using seed " + seed); }
169    }
170  }
171 
172  public final void testSpacingAroundBrackets1() {
173    assertTokens("longObjectInstance.reallyLongMethodName(a,b,c,d)",
174                 "longObjectInstance", ".", "reallyLongMethodName", "(",
175                 "a", ",", "b", ",", "c", ",", "d", ")", ";");
176  }
177 
178  public final void testSpacingAroundBrackets2() {
179    assertTokens("longObjectInstance.reallyLongMethodName(a,b,c,d)",
180                 "longObjectInstance", ".", "reallyLongMethodName", "(",
181                 "a", ",", "b", ",", "c", ",", "\n", "d", ")", ";");
182  }
183 
184  public final void testSpacingAroundBrackets3() {
185    assertTokens("longObjectInstance.reallyLongMethodName(a,b,c,d)",
186                 "longObjectInstance", ".", "reallyLongMethodName", "(",
187                 "\n", "a", ",", "b", ",", "c", ",", "d", ")", ";");
188  }
189 
190  public final void testSpacingAroundBrackets4() {
191    assertTokens("var x=({'fooBar':[0,1,2,]})",
192                 "var", "x", "=", "(", "{", "'fooBar'", ":", "[",
193                 "\n", "0", ",", "1", ",", "2", ",", "]", "}", ")", ";");
194  }
195 
196  public final void testConfusedTokenSequences() {
197    assertTokens("< ! =", "<", "!", "=");
198    assertTokens("< !=", "<", "!=");
199  }
200 
201  public final void testNumbersAndDots() {
202    assertTokens("2 .toString()", "2", ".", "toString", "(", ")");
203    assertTokens("2..toString()", "2.", ".", "toString", "(", ")");
204    assertTokens("2. .5", "2.", ".5");
205  }
206 
207  public final void testRestrictedSemicolonInsertion() throws Exception {
208    ParseTreeNode node = js(fromString(
209        ""
210        // 0123456789
211        + "var x=abcd+\n"
212        + "+ef;return 1-\n"
213        + "-c;if(b)throw new\n"
214        + "Error();break label;do\n"
215        + "nothing;while(0);continue top;a-\n"
216        + "-b;number=counter++"
217        + ";number=counter--"
218        + ";number=n-++"
219        + "counter"
220        ));
221    StringBuilder out = new StringBuilder();
222    JsMinimalPrinter pp = new JsMinimalPrinter(new Concatenator(out));
223    pp.setLineLengthLimit(10);
224    node.render(new RenderContext(pp));
225    pp.noMoreTokens();
226    assertEquals(
227        "{var x=abcd+"
228        + "\n+ef;return 1-"
229        + "\n-c;if(b)throw new"
230        + "\nError();break label;do"
231        + "\nnothing;while(0);continue top;a-"
232        + "\n-b;number=counter++;number=counter--;number=n-++counter}",
233        out.toString());
234  }
235 
236  public final void testNoops() throws ParseException {
237    ParseTreeNode b = js(fromString(
238        "for (;;) {",
239        "  if (foo)",
240        "    bar();",
241        "  else",
242        "    ;",
243        "}"));
244    StringBuilder out = new StringBuilder();
245    JsMinimalPrinter pp = new JsMinimalPrinter(new Concatenator(out));
246    b.render(new RenderContext(pp));
247    pp.noMoreTokens();
248    assertEquals(
249        "{for(;;){if(foo)bar();else;}}",
250        out.toString());
251  }
252 
253  private static final JsTokenType[] TYPES = JsTokenType.values();
254  private static final String[] PUNCTUATORS;
255  static {
256    List<String> puncStrs = new ArrayList<String>();
257    JsLexer.getPunctuationTrie().toStringList(puncStrs);
258    PUNCTUATORS = puncStrs.toArray(new String[0]);
259  }
260  private static final Keyword[] KEYWORDS = Keyword.values();
261 
262  private List<String> generateRandomTokens(Random rnd) {
263    List<String> tokens = new ArrayList<String>();
264    String last = null;
265    for (int i = 10; --i >= 0;) {
266      String tok;
267      switch (TYPES[rnd.nextInt(TYPES.length)]) {
268        case COMMENT:
269          continue;
270        case STRING:
271          tok = StringLiteral.toQuotedValue(randomString(rnd));
272          break;
273        case REGEXP:
274          // Since regexps are context sensitive, make sure we're in the right
275          // context.
276          tokens.add("=");
277          StringBuilder out = new StringBuilder();
278          out.append('/');
279          Escaping.normalizeRegex(randomString(rnd), false, false, out);
280          out.append('/');
281          if (rnd.nextBoolean()) { out.append('g'); }
282          if (rnd.nextBoolean()) { out.append('m'); }
283          if (rnd.nextBoolean()) { out.append('i'); }
284          tok = out.toString();
285          break;
286        case PUNCTUATION:
287          tok = PUNCTUATORS[rnd.nextInt(PUNCTUATORS.length)];
288          if (tok.startsWith("/")) {
289            // Make sure / operators follow numbers so they're not interpreted
290            // as regular expressions.
291            tokens.add("3");
292          }
293          if ("}".equals(tok) && ";".equals(last)) {
294            tok = "{";
295          }
296          break;
297        case WORD:
298          tok = randomWord(rnd);
299          break;
300        case KEYWORD:
301          tok = KEYWORDS[rnd.nextInt(KEYWORDS.length)].toString();
302          break;
303        case INTEGER:
304          int j = rnd.nextInt(Integer.MAX_VALUE);
305          switch (rnd.nextInt(3)) {
306            case 0: tok = Integer.toString(j, 10); break;
307            case 1: tok = "0" + Integer.toString(Math.abs(j), 8); break;
308            default: tok = "0x" + Long.toString(Math.abs((long) j), 16); break;
309          }
310          break;
311        case FLOAT:
312          tok = "" + Math.abs(rnd.nextFloat());
313          break;
314        case LINE_CONTINUATION:
315          continue;
316        default:
317          throw new SomethingWidgyHappenedError();
318      }
319      tokens.add(tok);
320      last = tok;
321    }
322    while (";".equals(last)) {
323      tokens.remove(tokens.size() - 1);
324      last = tokens.isEmpty() ? null : tokens.get(tokens.size() - 1);
325    }
326    return tokens;
327  }
328 
329  private static final String WORD_CHARS
330      = "_$ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
331  private static String randomWord(Random rnd) {
332    int len = rnd.nextInt(100) + 1;
333    StringBuilder sb = new StringBuilder(len);
334    for (int i = 0; i < len; ++i) {
335      sb.append(WORD_CHARS.charAt(rnd.nextInt(WORD_CHARS.length())));
336    }
337    if (Character.isDigit(sb.charAt(0))) {
338      sb.insert(0, '_');
339    }
340    return sb.toString();
341  }
342 
343  private static String randomString(Random rnd) {
344    int minCp = 0, maxCp = 0;
345    if (rnd.nextBoolean()) {
346      minCp = 0x20;
347      maxCp = 0x7f;
348    } else {
349      minCp = 0x0;
350      maxCp = 0xd000;
351    }
352    int len = rnd.nextInt(100) + 1;
353    StringBuilder sb = new StringBuilder(len);
354    for (int i = 0; i < len; ++i) {
355      sb.appendCodePoint(rnd.nextInt(maxCp - minCp) + minCp);
356    }
357    return sb.toString();
358  }
359 
360  private void assertRendered(String golden, String input) throws Exception {
361    JsLexer lex = new JsLexer(fromString(input));
362    JsTokenQueue tq = new JsTokenQueue(lex, is);
363    ParseTreeNode node = new Parser(tq, mq).parse();
364    tq.expectEmpty();
365 
366    assertRendered(golden, node);
367  }
368 
369  private void assertRendered(String golden, ParseTreeNode node) {
370    StringBuilder out = new StringBuilder();
371    JsMinimalPrinter pp = new JsMinimalPrinter(new Concatenator(out));
372    node.render(new RenderContext(pp));
373    pp.noMoreTokens();
374 
375    assertEquals(golden, out.toString());
376  }
377 
378  private void assertLexed(String golden, String input) throws ParseException {
379    StringBuilder out = new StringBuilder();
380    JsMinimalPrinter pp = new JsMinimalPrinter(new Concatenator(out));
381 
382    JsLexer lex = new JsLexer(fromString(input));
383    while (lex.hasNext()) {
384      Token<JsTokenType> t = lex.next();
385      pp.mark(t.pos);
386      pp.consume(t.text);
387    }
388    pp.noMoreTokens();
389 
390    assertEquals(golden, out.toString());
391  }
392 
393  private void assertTokens(String golden, String... input) {
394    StringBuilder out = new StringBuilder();
395    JsMinimalPrinter pp = new JsMinimalPrinter(new Concatenator(out));
396 
397    for (String token : input) {
398      pp.consume(token);
399    }
400    pp.noMoreTokens();
401    assertEquals(golden, out.toString());
402  }
403}

[all classes][com.google.caja.render]
EMMA 2.0.5312 (C) Vladimir Roubtsov