1
2
3
4 package net.sourceforge.pmd.lang.ecmascript.ast;
5
6 import static org.junit.Assert.assertEquals;
7 import static org.junit.Assert.assertFalse;
8 import static org.junit.Assert.assertTrue;
9
10 import java.io.Reader;
11 import java.io.StringReader;
12 import java.util.ArrayList;
13 import java.util.Arrays;
14 import java.util.List;
15
16 import net.sourceforge.pmd.PMD;
17 import net.sourceforge.pmd.RuleContext;
18 import net.sourceforge.pmd.lang.ast.Node;
19 import net.sourceforge.pmd.lang.ecmascript.Ecmascript3Parser;
20 import net.sourceforge.pmd.lang.ecmascript.EcmascriptParserOptions;
21 import net.sourceforge.pmd.lang.ecmascript.rule.AbstractEcmascriptRule;
22
23 import org.junit.Test;
24 import org.mozilla.javascript.ast.AstRoot;
25
26 public class EcmascriptParserTest extends EcmascriptParserTestBase {
27
28
29
30
31 @Test
32 public void testLineNumbers() {
33 String SOURCE_CODE =
34 "function a() {" + PMD.EOL
35 + " alert('hello');" + PMD.EOL
36 + "}" + PMD.EOL;
37 EcmascriptNode<AstRoot> node = parse(SOURCE_CODE);
38 assertEquals(1, node.getBeginLine());
39 assertEquals(1, node.getBeginColumn());
40 assertEquals(3, node.getEndLine());
41 assertEquals(1, node.getEndColumn());
42
43 Node child = node.getFirstChildOfType(ASTFunctionNode.class);
44 assertEquals(1, child.getBeginLine());
45 assertEquals(1, child.getBeginColumn());
46 assertEquals(3, child.getEndLine());
47 assertEquals(1, child.getEndColumn());
48
49 child = node.getFirstDescendantOfType(ASTFunctionCall.class);
50 assertEquals(2, child.getBeginLine());
51 assertEquals(3, child.getBeginColumn());
52 assertEquals(2, child.getEndLine());
53 assertEquals(16, child.getEndColumn());
54 }
55
56
57
58
59 @Test
60 public void testLineNumbersWithinEcmascriptRules() {
61 String source =
62 "function f(x){\n" +
63 " if (x) {\n" +
64 " return 1;\n" +
65 " } else {\n" +
66 " return 0;\n" +
67 " }\n" +
68 "}";
69 final List<String> output = new ArrayList<String>();
70
71 class MyEcmascriptRule extends AbstractEcmascriptRule {
72 public Object visit(ASTScope node, Object data) {
73 output.add("Scope from " + node.getBeginLine() + " to " + node.getEndLine());
74 return super.visit(node, data);
75 }
76 }
77
78 MyEcmascriptRule rule = new MyEcmascriptRule();
79 RuleContext ctx = new RuleContext();
80 rule.apply(Arrays.asList(parse(source)), ctx);
81
82 assertEquals("Scope from 2 to 4", output.get(0));
83 assertEquals("Scope from 4 to 6", output.get(1));
84 }
85
86
87
88
89 @Test
90 public void testArrayAccess() {
91 EcmascriptNode<AstRoot> node = parse("function a() { b['a'] = 1; c[1] = 2; }");
92 List<ASTElementGet> arrays = node.findDescendantsOfType(ASTElementGet.class);
93 assertEquals("b", arrays.get(0).getTarget().getImage());
94 assertEquals("a", arrays.get(0).getElement().getImage());
95 assertEquals("c", arrays.get(1).getTarget().getImage());
96 assertEquals("1", arrays.get(1).getElement().getImage());
97 }
98
99
100
101
102 @Test
103 public void testArrayMethod() {
104 EcmascriptNode<AstRoot> rootNode = parse("function test(){\n" +
105 " a(); // OK\n" +
106 " b.c(); // OK\n" +
107 " d[0](); // OK\n" +
108 " e[0].f(); // OK\n" +
109 " y.z[0](); // FAIL ==> java.lang.NullPointerException\n" +
110 "}");
111
112 List<ASTFunctionCall> calls = rootNode.findDescendantsOfType(ASTFunctionCall.class);
113 List<String> results = new ArrayList<String>();
114 for (ASTFunctionCall f : calls) {
115 Node node = f.getTarget();
116 results.add(getName(node));
117 }
118 assertEquals("[a, b.c, d[], e[].f, y.z[]]", results.toString());
119 }
120
121 private String getName(Node node) {
122 if( node instanceof ASTName ){
123 return ((ASTName)node).getIdentifier();
124 }
125 if( node instanceof ASTPropertyGet ){
126 final ASTPropertyGet pgNode = (ASTPropertyGet)node;
127 final String leftName = getName(pgNode.getLeft());
128 final String rightName = getName(pgNode.getRight());
129 return leftName + "." + rightName;
130 }
131 if( node instanceof ASTElementGet ){
132 return getName(((ASTElementGet)node).getTarget()) + "[]";
133 }
134 return "????";
135 }
136
137
138
139
140
141 @Test
142 public void testCaseAsIdentifier() {
143 ASTAstRoot rootNode = parse("function f(a){\n" +
144 " a.case.flag = 1;\n" +
145 " return;\n" +
146 "}");
147 ASTBlock block = rootNode.getFirstDescendantOfType(ASTBlock.class);
148 assertFalse(block.jjtGetChild(0) instanceof ASTEmptyExpression);
149 assertTrue(block.jjtGetChild(0) instanceof ASTExpressionStatement);
150 assertTrue(block.jjtGetChild(0).jjtGetChild(0) instanceof ASTAssignment);
151 }
152
153
154
155
156
157 @Test
158 public void testSuppresionComment() {
159 Ecmascript3Parser parser = new Ecmascript3Parser(new EcmascriptParserOptions());
160 Reader sourceCode = new StringReader("function(x) {\n"
161 + "x = x; //NOPMD I know what I'm doing\n"
162 + "}\n");
163 parser.parse("foo", sourceCode);
164 assertEquals(" I know what I'm doing", parser.getSuppressMap().get(2));
165 assertEquals(1, parser.getSuppressMap().size());
166
167 EcmascriptParserOptions parserOptions = new EcmascriptParserOptions();
168 parserOptions.setSuppressMarker("FOOOO");
169 parser = new Ecmascript3Parser(parserOptions);
170 sourceCode = new StringReader("function(x) {\n"
171 + "y = y; //NOPMD xyz\n"
172 + "x = x; //FOOOO I know what I'm doing\n"
173 + "}\n");
174 parser.parse("foo", sourceCode);
175 assertEquals(" I know what I'm doing", parser.getSuppressMap().get(3));
176 assertEquals(1, parser.getSuppressMap().size());
177 }
178
179
180
181
182 @Test
183 public void testVoidKeyword() {
184 ASTAstRoot rootNode = parse("function f(matchFn, fieldval, n){\n" +
185 " return (matchFn)?(matcharray = eval(matchFn+\"('\"+fieldval+\"','\"+n.id+\"')\")):void(0);\n" +
186 "}\n");
187 ASTUnaryExpression unary = rootNode.getFirstDescendantOfType(ASTUnaryExpression.class);
188 assertEquals("void", unary.getImage());
189 }
190
191
192
193
194 @Test
195 public void testXorAssignment() {
196 ASTAstRoot rootNode = parse("function f() { var x = 2; x ^= 2; x &= 2; x |= 2; "
197 + "x &&= true; x ||= false; x *= 2; x /= 2; x %= 2; x += 2; x -= 2; "
198 + "x <<= 2; x >>= 2; x >>>= 2; }");
199 ASTAssignment infix = rootNode.getFirstDescendantOfType(ASTAssignment.class);
200 assertEquals("^=", infix.getImage());
201 }
202 }