1###############################################################################
2#
3# Copyright (c) 2011-2012 Ruslan Spivak
4#
5# Permission is hereby granted, free of charge, to any person obtaining a copy
6# of this software and associated documentation files (the "Software"), to deal
7# in the Software without restriction, including without limitation the rights
8# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9# copies of the Software, and to permit persons to whom the Software is
10# furnished to do so, subject to the following conditions:
11#
12# The above copyright notice and this permission notice shall be included in
13# all copies or substantial portions of the Software.
14#
15# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21# THE SOFTWARE.
22#
23###############################################################################
24
25__author__ = 'Ruslan Spivak <ruslan.spivak@gmail.com>'
26
27import textwrap
28import unittest
29
30from slimit import ast
31from slimit.parser import Parser
32from slimit.visitors import nodevisitor
33
34
35class ParserTestCase(unittest.TestCase):
36
37    def test_line_terminator_at_the_end_of_file(self):
38        parser = Parser()
39        parser.parse('var $_ = function(x){}(window);\n')
40
41    # XXX: function expression ?
42    def _test_function_expression(self):
43        text = """
44        if (true) {
45          function() {
46            foo;
47            location = 'http://anywhere.com';
48          }
49        }
50        """
51        parser = Parser()
52        parser.parse(text)
53
54    def test_modify_tree(self):
55        text = """
56        for (var i = 0; i < 10; i++) {
57          var x = 5 + i;
58        }
59        """
60        parser = Parser()
61        tree = parser.parse(text)
62        for node in nodevisitor.visit(tree):
63            if isinstance(node, ast.Identifier) and node.value == 'i':
64                node.value = 'hello'
65        self.assertMultiLineEqual(
66            tree.to_ecma(),
67            textwrap.dedent("""
68            for (var hello = 0; hello < 10; hello++) {
69              var x = 5 + hello;
70            }
71            """).strip()
72            )
73
74    def test_bug_no_semicolon_at_the_end_of_block_plus_newline_at_eof(self):
75        # https://github.com/rspivak/slimit/issues/3
76        text = textwrap.dedent("""
77        function add(x, y) {
78          return x + y;
79        }
80        """)
81        parser = Parser()
82        tree = parser.parse(text)
83        self.assertTrue(bool(tree.children()))
84
85    def test_function_expression_is_part_of_member_expr_nobf(self):
86        # https://github.com/rspivak/slimit/issues/22
87        # The problem happened to be that function_expr was not
88        # part of member_expr_nobf rule
89        text = 'window.done_already || function () { return "slimit!" ; }();'
90        self.assertTrue(bool(Parser().parse(text).children()))
91
92    # https://github.com/rspivak/slimit/issues/29
93    def test_that_parsing_eventually_stops(self):
94        text = """var a;
95        , b;"""
96        parser = Parser()
97        self.assertRaises(SyntaxError, parser.parse, text)
98
99
100class ASITestCase(unittest.TestCase):
101    TEST_CASES = [
102        ("""
103        switch (day) {
104          case 1:
105            result = 'Mon';
106            break
107          case 2:
108            break
109        }
110        """,
111         """
112         switch (day) {
113           case 1:
114             result = 'Mon';
115             break;
116           case 2:
117             break;
118         }
119         """),
120
121        ("""
122        while (true)
123          continue
124        a = 1;
125        """,
126         """
127         while (true) continue;
128         a = 1;
129         """),
130
131        ("""
132        return
133        a;
134        """,
135        """
136         return;
137         a;
138        """),
139        # test 3
140        ("""
141        x = 5
142        """,
143         """
144         x = 5;
145         """),
146
147        ("""
148        var a, b
149        var x
150        """,
151         """
152         var a, b;
153         var x;
154         """),
155
156        ("""
157        var a, b
158        var x
159        """,
160         """
161         var a, b;
162         var x;
163         """),
164
165        # test 6
166        ("""
167        return
168        a + b
169        """,
170         """
171         return;
172         a + b;
173         """),
174
175        ('while (true) ;', 'while (true) ;'),
176
177        ("""
178        if (x) {
179          y()
180        }
181        """,
182         """
183         if (x) {
184           y();
185         }
186         """),
187
188        # test 9
189        ("""
190        for ( ; i < length; i++) {
191        }
192        """,
193         """
194         for ( ; i < length; i++) {
195
196         }
197         """),
198
199        ("""
200        var i;
201        for (i; i < length; i++) {
202        }
203        """,
204         """
205         var i;
206         for (i; i < length; i++) {
207
208         }
209         """),
210        ]
211
212    def test_throw_statement(self):
213        # expression is not optional in throw statement
214        input = textwrap.dedent("""
215        throw
216          'exc';
217        """)
218        parser = Parser()
219        # ASI at lexer level should insert ';' after throw
220        self.assertRaises(SyntaxError, parser.parse, input)
221
222
223def make_test_function(input, expected):
224
225    def test_func(self):
226        parser = Parser()
227        result = parser.parse(input).to_ecma()
228        self.assertMultiLineEqual(result, expected)
229
230    return test_func
231
232for index, (input, expected) in enumerate(ASITestCase.TEST_CASES):
233    input = textwrap.dedent(input).strip()
234    expected = textwrap.dedent(expected).strip()
235    func = make_test_function(input, expected)
236    setattr(ASITestCase, 'test_case_%d' % index, func)
237
238
239