Ejemplo n.º 1
0
    def test_nested_layouts(self):
        def simple_layout_space(dispatcher, node, before, after, prev):
            yield SimpleChunk(' ')

        def nested_layout(dispatcher, node, before, after, prev):
            yield SimpleChunk('?')

        def noop(*a, **kw):
            return
            yield  # pragma: no cover

        dispatcher = Dispatcher(
            definitions={'Node': (
                Space,
                JoinAttr(Iter(), value=(Space, )),
            )},
            token_handler=noop,
            layout_handlers={
                Space: simple_layout_space,
                (Space, Space): noop,
                ((Space, Space), Space): nested_layout,
            },
            deferrable_handlers={},
        )

        n0 = Node([])
        self.assertEqual(' ', ''.join(c.text for c in walk(dispatcher, n0)))
        n1 = Node([n0])
        self.assertEqual('', ''.join(c.text for c in walk(dispatcher, n1)))
        n2 = Node([n1, n0])
        self.assertEqual('?', ''.join(c.text for c in walk(dispatcher, n2)))
Ejemplo n.º 2
0
    def test_repeated_layouts(self):
        class Block(Node):
            pass

        def space_layout(dispatcher, node, before, after, prev):
            yield SimpleChunk(' ')

        def newline_layout(dispatcher, node, before, after, prev):
            yield SimpleChunk('n')

        dispatcher = Dispatcher(
            definitions={
                'Node': (Space, ),
                'Block': (JoinAttr(Iter(), value=(Newline, )), )
            },
            token_handler=None,  # not actually produced
            layout_handlers={
                Space: space_layout,
                Newline: newline_layout,
                # drop the subsequent space
                (Newline, Space): newline_layout,
            },
            deferrable_handlers={},
        )

        n0 = Block([])
        self.assertEqual('', ''.join(c.text for c in walk(dispatcher, n0)))
        n1 = Block([Node([])] * 1)
        self.assertEqual(' ', ''.join(c.text for c in walk(dispatcher, n1)))
        n2 = Block([Node([])] * 2)
        self.assertEqual(' n', ''.join(c.text for c in walk(dispatcher, n2)))
        n3 = Block([Node([])] * 3)
        self.assertEqual(' nn', ''.join(c.text for c in walk(dispatcher, n3)))
    def test_no_resolve(self):
        # a simple test to show that an obfuscator without the initial
        # loading run executed (i.e. the one with the required handlers)
        # with the resolve added to the dispatcher will not crash, but
        # simply not have any effect.

        tree = es5(
            dedent("""
        (function() {
          var foo = 1;
          var bar = 2;
        })(this);
        """).strip())
        unparser = Unparser()
        obfuscator = Obfuscator()
        dispatcher = Dispatcher(
            unparser.definitions, token_handler_str_default, {
                Space: layout_handler_space_minimum,
                RequiredSpace: layout_handler_space_minimum,
                OpenBlock: layout_handler_openbrace,
                CloseBlock: layout_handler_closebrace,
                EndStatement: layout_handler_semicolon,
            }, {
                Resolve: obfuscator.resolve,
            })
        # see that the manually constructed minimum output works.
        self.assertEqual("(function(){var foo=1;var bar=2;})(this);",
                         ''.join(c.text for c in walk(dispatcher, tree)))
Ejemplo n.º 4
0
    def walk(self, dispatcher, node):
        """
        Walk through the node with a custom dispatcher for extraction of
        details that are required.
        """

        deferrable_handlers = {
            Declare: self.declare,
            Resolve: self.register_reference,
        }
        layout_handlers = {
            PushScope: self.push_scope,
            PopScope: self.pop_scope,
            PushCatch: self.push_catch,
            # should really be different, but given that the
            # mechanism is within the same tree, the only difference
            # would be sanity check which should have been tested in
            # the first place in the primitives anyway.
            PopCatch: self.pop_scope,
        }

        if not self.shadow_funcname:
            layout_handlers[ResolveFuncName] = self.shadow_reference

        local_dispatcher = Dispatcher(
            definitions=dict(dispatcher),
            token_handler=None,
            layout_handlers=layout_handlers,
            deferrable_handlers=deferrable_handlers,
        )
        return list(walk(local_dispatcher, node))
Ejemplo n.º 5
0
 def test_deferrable_resolve(self):
     self.setup_defaults()
     # define the replacement in the map that was set up.
     self.replacement['$'] = 'jq'
     tree = es5('var w = $(window).width();')
     recreated = ''.join(c.text for c in walk(self.dispatcher, tree))
     self.assertEqual('var w = jq(window).width();', recreated)
     self.assertEqual(['w'], self.declared_vars)
Ejemplo n.º 6
0
 def test_layouts_buffering(self):
     self.setup_defaults()
     # The buffered layout rule handler should be invoked with the
     # Node that originally queued the LayoutRuleChunk (rather, the
     # walk should have done that for the Node).
     original = 'var a = 1;'
     tree = es5(original)
     recreated = ''.join(c.text for c in walk(self.dispatcher, tree))
     # see that this at least works as expected
     self.assertEqual(original, recreated)
     # ensure that the 3 spaces have been handled as expected
     self.assertEqual(len(self.layouts_handled), 3)
     # the first Space should be derived from VarStatement
     self.assertTrue(isinstance(self.layouts_handled[0][1], VarStatement))
     # last two are in VarDecl
     self.assertTrue(isinstance(self.layouts_handled[1][1], VarDecl))
     self.assertTrue(isinstance(self.layouts_handled[2][1], VarDecl))
     self.assertEqual(['a'], self.declared_vars)
Ejemplo n.º 7
0
    def test_join_attr_issue_36(self):
        # JoinAttr defined with parameter `value=None` resulted in
        # infinite recursion due to the walker will assume that no rule
        # is provided, triggering rule lookup which would repeat the
        # work that was done.

        class Block(Node):
            pass

        token_handler, layout_handlers, deferrable_handlers, declared_vars = (
            setup_handlers(self))
        dispatcher = Dispatcher(
            definitions={
                'Block': (JoinAttr(Iter(), value=None), ),
                'Node': (Text(value='', ), ),
            },
            token_handler=token_handler,
            layout_handlers={},
            deferrable_handlers={},
        )

        nodes = Block([Node([])] * 3)
        self.assertEqual(3, len(list(walk(dispatcher, nodes))))
    def test_build_substitutions(self):
        tree = es5(
            dedent("""
        (function(root) {
          var foo = 1;
          var bar = 2;
          baz = 3;
          foo = 4;
          window.document.body.focus();
        })(this, factory);
        """).strip())
        unparser = Unparser()
        obfuscator = Obfuscator()
        # a bare dispatcher should work, as it is used for extracting
        # the definitions from.
        sub_dispatcher = Dispatcher(unparser.definitions, rule_handler_noop,
                                    {}, {})
        # only do the intial walk.
        result = obfuscator.walk(sub_dispatcher, tree)
        # should be empty list as the run should produce nothing, due to
        # the null token producer.
        self.assertEqual(result, [])

        # only one scope was defined.
        self.assertEqual(1, len(obfuscator.scopes))
        self.assertEqual(1, len(obfuscator.global_scope.children))

        # do some validation on the scope itself.
        self.assertEqual(set(), obfuscator.global_scope.declared_symbols)
        self.assertEqual({
            'factory': 1,
            'baz': 1,
            'window': 1
        }, obfuscator.global_scope.referenced_symbols)
        scope = obfuscator.global_scope.children[0]

        self.assertEqual({'root', 'foo', 'bar'}, scope.declared_symbols)
        self.assertEqual(
            {
                'root': 1,
                'foo': 2,
                'bar': 1,
                'baz': 1,
                'window': 1,
            }, scope.referenced_symbols)

        # do a trial run to show that the resolution works.
        main_dispatcher = Dispatcher(
            unparser.definitions, token_handler_unobfuscate, {
                Space: layout_handler_space_minimum,
                RequiredSpace: layout_handler_space_minimum,
                OpenBlock: layout_handler_openbrace,
                CloseBlock: layout_handler_closebrace,
                EndStatement: layout_handler_semicolon,
            }, {
                Resolve: obfuscator.resolve,
            })
        # see that the manually constructed minimum output works.
        self.assertEqual(
            "(function(root){var foo=1;var bar=2;baz=3;foo=4;"
            "window.document.body.focus();})(this,factory);",
            ''.join(c.text for c in walk(main_dispatcher, tree)))
        # since nothing was remapped.
        self.assertEqual([], [(c.text, c.name)
                              for c in walk(main_dispatcher, tree) if c.name])

        # now manually give the scope with a set of replacement names
        scope.remapped_symbols.update({
            'root': 'r',
            'foo': 'f',
            'bar': 'b',
            'baz': 'z',
        })
        self.assertEqual(
            "(function(r){var f=1;var b=2;z=3;f=4;"
            "window.document.body.focus();})(this,factory);",
            ''.join(c.text for c in walk(main_dispatcher, tree)))
        # check that the source chunks yielded contain both the original
        # text token and the original row/col location
        self.assertEqual([
            ('r', 1, 11, 'root'),
            ('f', 2, 7, 'foo'),
            ('b', 3, 7, 'bar'),
            ('z', 4, 3, 'baz'),
            ('f', 5, 3, 'foo'),
        ], [c[:4] for c in walk(main_dispatcher, tree) if c.name])