Example #1
0
    def test_add_step_set(self):
        ss = self.rule.step_set
        replacement_ss = StepSet()
        ss.concat = Mock(return_value=replacement_ss)

        new_step_set = StepSet()
        self.rule.add_step_set(new_step_set)
        ss.concat.assert_called_with(new_step_set)
        self.assertIs(self.rule.step_set, replacement_ss)
Example #2
0
class YamlTest(TestCase):
    def yaml_func(self, context, args):
        context.setdefault('args', {}).update(args)

    def setUp(self):
        self.step_set = StepSet()

        self.yaml_step = YamlFuncStep(self.yaml_func)
        self.step_set.add_step(self.yaml_step)

    def test_yaml_step(self):
        steps = self.step_set.parse('foo: bar\nbar: baz')
        expected = [({'foo': 'bar', 'bar': 'baz'}, self.yaml_step)]
        self.assertEqual(steps, expected)

    def test_multiple_yaml_steps(self):
        steps = self.step_set.parse('foo: bar\n...\nbar: baz\n...')
        expected = [({
            'foo': 'bar'
        }, self.yaml_step), ({
            'bar': 'baz'
        }, self.yaml_step)]
        self.assertEqual(steps, expected)
        context = self.step_set.run('foo: bar\n...\nbar: baz\n...')
        expected = {'foo': 'bar', 'bar': 'baz'}
        self.assertEqual(context.args, expected)

    def test_mixed_steps(self):
        re_step = RegexStep('%hello%')
        self.step_set.add_step(re_step)

        steps = self.step_set.parse('foo: bar\n...\n%hello%')
        expected = [({'foo': 'bar'}, self.yaml_step), ({}, re_step)]
        self.assertEqual(steps, expected)
Example #3
0
    def test_concat(self):
        rs1 = StepSet()
        rs2 = StepSet()

        @rs1.step('Step 1')
        def step1(ctx, args):
            ctx.step1 = True

        @rs2.step('Step 2')
        def step2(ctx, args):
            ctx.step2 = True

        rs3 = rs1.concat(rs2)
        context = rs3.run('Step 1\nStep 2')
        self.assertTrue(context.step1)
        self.assertTrue(context.step2)
Example #4
0
class DecoratorTest(TestCase):
    def setUp(self):
        self.step_set = StepSet()

    def test_step_decorator(self):
        @self.step_set.step('Basic step')
        def basic_step(context, args):
            self.assertEqual(args, {})
            context.basic = True

        @self.step_set.step('Arbitrary (.*)')
        def arbitrary_x(context, args):
            context.x = args[1]
            context.arb = True

        context = self.step_set.run('Basic step\nArbitrary trout')
        self.assertEqual(context.basic, True)
        self.assertEqual(context.arb, True)
        self.assertEqual(context.x, 'trout')

    def test_multiline_step_decorator(self):
        @self.step_set.multiline_step(r'(?s)\s*"""(?P<quoted>.*?)"""')
        def triple_quotes(context, args):
            context.quoted = re.sub(r'\s+', ' ', args.quoted.strip())

        @self.step_set.multiline_step(r'(?s)\s*\((?P<inparens>.*?)\)')
        def parens(context, args):
            context.inparens = re.sub(r'\s+', ' ', args.inparens.strip())

        lines = dedent('''\
            (This bit here
             is in parens.
             """ This bit is still in parens,
                 despite the fact that it is
                 also in quotes.
             """) """ This bit here, however,
                      is in quotes """
            ''')

        context = self.step_set.run(lines)
        self.assertEqual(
            context.inparens,
            'This bit here is in parens. """ This bit is still in '
            'parens, despite the fact that it is also in quotes. """')
        self.assertEqual(context.quoted,
                         'This bit here, however, is in quotes')
Example #5
0
    def setUp(self):
        self.step_set = StepSet()

        def set_x_to_y(context, args):
            context[args.x] = args.y
        self.set_step = RegexFuncStep('set (?P<x>.+) to (?P<y>.+)',
                                      set_x_to_y)
        self.step_set.add_step(self.set_step)
Example #6
0
class YamlTest(TestCase):

    def yaml_func(self, context, args):
        context.setdefault('args', {}).update(args)

    def setUp(self):
        self.step_set = StepSet()

        self.yaml_step = YamlFuncStep(self.yaml_func)
        self.step_set.add_step(self.yaml_step)

    def test_yaml_step(self):
        steps = self.step_set.parse('foo: bar\nbar: baz')
        expected = [({'foo': 'bar', 'bar': 'baz'}, self.yaml_step)]
        self.assertEqual(steps, expected)

    def test_multiple_yaml_steps(self):
        steps = self.step_set.parse('foo: bar\n...\nbar: baz\n...')
        expected = [({'foo': 'bar'}, self.yaml_step),
                    ({'bar': 'baz'}, self.yaml_step)]
        self.assertEqual(steps, expected)
        context = self.step_set.run('foo: bar\n...\nbar: baz\n...')
        expected = {
            'foo': 'bar',
            'bar': 'baz'
        }
        self.assertEqual(context.args, expected)

    def test_mixed_steps(self):
        re_step = RegexStep('%hello%')
        self.step_set.add_step(re_step)

        steps = self.step_set.parse('foo: bar\n...\n%hello%')
        expected = [
            ({'foo': 'bar'}, self.yaml_step),
            ({}, re_step)
        ]
        self.assertEqual(steps, expected)
Example #7
0
 def setUp(self):
     self.step_set = StepSet()
Example #8
0
class CallingTest(TestCase):
    def setUp(self):
        self.step_set = StepSet()

    def test_run_plaintext(self):
        def set_foo(context, args):
            self.assertEqual(args, {})
            context.foo = 'bar'
            return 'the middle'

        def set_bar(context, args):
            self.assertEqual(args, {})
            self.assertEqual(context.last_return, 'the middle')
            context.bar = 'baz'
            return 'the end'

        self.step_set.add_step(RFS('Set foo', set_foo))
        self.step_set.add_step(RFS('Set bar', set_bar))
        context = self.step_set.run('Set foo\nSet bar')
        self.assertEqual(context.foo, 'bar')
        self.assertEqual(context.last_return, 'the end')

    def test_run_with_args(self):
        def set_x_to_y(context, args):
            context[args.x] = args.y

        def add_x_to_y(context, args):
            context.sum = int(context[args.x]) + int(context[args.y])

        def x_should_equal_y(context, args):
            self.assertEqual(str(context[args.x]), args.y)

        self.step_set.add_step(RFS('Set (?P<x>.*) to (?P<y>.*)', set_x_to_y))
        self.step_set.add_step(RFS('Add (?P<x>.*) to (?P<y>.*)', add_x_to_y))
        self.step_set.add_step(
            RFS('(?P<x>.*) should equal (?P<y>.*)', x_should_equal_y))
        self.step_set.run(
            dedent("""\
            Set a to 1
            Set b to 3
            Add a to b
            sum should equal 4
            Set c to 38
            Add sum to c
            sum should equal 42"""))

    def test_run_multiline(self):
        def message(context, args):
            msg = re.sub(r'\s+', ' ', args.msg)
            messages = context.setdefault('messages', [])
            messages.append(msg)
            return msg

        step_re = r'([ /t]*)Message:\s*(?P<msg>.*(\n\1[ \t]+.+)*)'
        self.step_set.add_step(RFS(step_re, message, multiline=True))
        lines = dedent("""\
            Message: Hey there.
              This message is lots
              of lines long.
            
            Message:
              This
               is
                also
              a longer
               message.
            """)
        context = self.step_set.run(lines)
        self.assertEqual(context.messages, [
            'Hey there. This message is lots of lines long.',
            'This is also a longer message.'
        ])
Example #9
0
 def setUp(self):
     self.stepset = StepSet(does_a_plus_b_equal_c).concat(basic_step_set)
Example #10
0
class BasicHelpersTest(TestCase):
    def setUp(self):
        self.stepset = StepSet(does_a_plus_b_equal_c).concat(basic_step_set)

    def test_if_then_set(self):
        rules = """\
            Does 1 plus 2 equal 42?
            If so, then set answer to: Life,
                the universe,
                and everything.
            If not, then set insult to: You, sir,
              are bad at math.

            Does 2 plus 2 equal 4?
            If so, then set answer to: Ok.
             Who gave you the answer to that
             one?
            If not, then set insult to: Wow, you're so bad at math
             that you actually broke this program.
            """
        context = self.stepset.run(rules)
        self.assertEqual(context.answer,
                         'Ok. Who gave you the answer to that one?')
        self.assertEqual(context.insult,
                         'You, sir, are bad at math.')

    def test_if_then_append(self):
        rules = """\
            Does 1 plus 1 equal 2?
            If so, then append to answers: ok.
            Does 1 plus 2 equal 42?
            If so, then append to answers: Life,
                the universe,
                and everything.
            If not, then append to insults: You, sir,
              are bad at math.
            If not, then append to insults: I shall taunt you a second time!

            Does 2 plus 2 equal 4?
            If so, then append to answers: Ok.
             Who gave you the answer to that
             one?
            If not, then append to insults: Wow, you're so bad at math
             that you actually broke this program.
            """
        context = self.stepset.run(rules)
        self.assertEqual(context.answers,
                         ['ok.', 'Ok. Who gave you the answer to that one?'])
        self.assertEqual(context.insults,
                         ['You, sir, are bad at math.',
                          'I shall taunt you a second time!'])

    def test_if_then_set_yaml(self):
        rules = """\
            Does 1 plus 1 equal 2?
            If so, then set:
              math: ok-ish
              level: 1
            If not, then set:
              math: very bad
              level: -23

            Does 1 plus 2 equal 42?
            If so, then set:
              something: horribly broken
            If not, then set:
              numbers:
                - 1
                - 2
                - wait, what?
              hmm: ok
            """
        context = self.stepset.run(rules)
        self.assertEqual(context.math, 'ok-ish')
        self.assertEqual(context.level, 1)
        self.assertEqual(context.numbers, [1, 2, 'wait, what?'])
        self.assertEqual(context.hmm, 'ok')
        self.assertNotIn('something', context)
Example #11
0
class ParsingTest(TestCase):
    def setUp(self):
        self.step_set = StepSet()

    _ok = lambda ctx, args: True

    def test_plain_text_step(self):
        step = RegexFuncStep("I'm a step!", self._ok)
        self.step_set.add_step(step)

        parsed = self.step_set.parse("I'm a step!")
        expected = [({}, step)]
        self.assertEqual(parsed, expected)

    def test_failed_plain_text_step(self):
        step = RegexFuncStep("I'm a step!", self._ok)
        self.step_set.add_step(step)

        self.assertRaises(UnmatchedStepError, self.step_set.parse,
                          "I don't match")

    def test_plain_text_step_suffix_content(self):
        step = RegexFuncStep("I'm a step", self._ok)
        self.step_set.add_step(step)

        parsed = self.step_set.parse("I'm a step plus more")
        expected = [({'suffix_content': ' plus more'}, step)]
        self.assertEqual(parsed, expected)

    def test_plain_text_step_prefix_suffix_content(self):
        step = RegexFuncStep("I'm a step", self._ok)
        self.step_set.add_step(step)

        parsed = self.step_set.parse("Hey I'm a step plus")
        expected = [({
            'prefix_content': 'Hey ',
            'suffix_content': ' plus'
        }, step)]
        self.assertEqual(parsed, expected)

    def test_regex_nocaptures(self):
        step = RegexFuncStep('^strictly this$', self._ok)
        self.step_set.add_step(step)
        parsed = self.step_set.parse('strictly this')
        expected = [({}, step)]
        self.assertEqual(parsed, expected)

    def test_regex_extra_fail(self):
        step = RegexFuncStep('^strictly this$', self._ok)
        self.step_set.add_step(step)
        self.assertRaises(UnmatchedStepError, self.step_set.parse,
                          'strictly this plus more')
        self.assertRaises(UnmatchedStepError, self.step_set.parse,
                          'prefix and strictly this')

    def test_regex_captures(self):
        step = RegexFuncStep('one (?P<two>.*) three (?P<four>.*)', self._ok)
        self.step_set.add_step(step)
        parsed = self.step_set.parse('one 2 three 4\none hey three there')
        expected = [({
            'two': '2',
            'four': '4',
            1: '2',
            2: '4'
        }, step), ({
            'two': 'hey',
            'four': 'there',
            1: 'hey',
            2: 'there'
        }, step)]
        self.assertEqual(parsed, expected)

    def test_regex_numeric_captures(self):
        step = RegexFuncStep('one (.*) three (.*)', self._ok)
        self.step_set.add_step(step)
        parsed = self.step_set.parse('one 2 three 4\none hey three there')
        expected = [({1: '2', 2: '4'}, step), ({1: 'hey', 2: 'there'}, step)]
        self.assertEqual(parsed, expected)

    def test_multiline(self):
        step = RegexFuncStep('this: (.*)\nand this: (.*)',
                             self._ok,
                             multiline=True)
        self.step_set.add_step(step)
        parsed = self.step_set.parse('this: first\nand this: second')
        expected = [({1: 'first', 2: 'second'}, step)]
        self.assertEqual(parsed, expected)
Example #12
0
    def setUp(self):
        self.step_set = StepSet()

        self.yaml_step = YamlFuncStep(self.yaml_func)
        self.step_set.add_step(self.yaml_step)
Example #13
0
 def setUp(self):
     self.stepset = StepSet(does_a_plus_b_equal_c).concat(basic_step_set)
Example #14
0
class BasicHelpersTest(TestCase):
    def setUp(self):
        self.stepset = StepSet(does_a_plus_b_equal_c).concat(basic_step_set)

    def test_if_then_set(self):
        rules = """\
            Does 1 plus 2 equal 42?
            If so, then set answer to: Life,
                the universe,
                and everything.
            If not, then set insult to: You, sir,
              are bad at math.

            Does 2 plus 2 equal 4?
            If so, then set answer to: Ok.
             Who gave you the answer to that
             one?
            If not, then set insult to: Wow, you're so bad at math
             that you actually broke this program.
            """
        context = self.stepset.run(rules)
        self.assertEqual(context.answer,
                         'Ok. Who gave you the answer to that one?')
        self.assertEqual(context.insult, 'You, sir, are bad at math.')

    def test_if_then_append(self):
        rules = """\
            Does 1 plus 1 equal 2?
            If so, then append to answers: ok.
            Does 1 plus 2 equal 42?
            If so, then append to answers: Life,
                the universe,
                and everything.
            If not, then append to insults: You, sir,
              are bad at math.
            If not, then append to insults: I shall taunt you a second time!

            Does 2 plus 2 equal 4?
            If so, then append to answers: Ok.
             Who gave you the answer to that
             one?
            If not, then append to insults: Wow, you're so bad at math
             that you actually broke this program.
            """
        context = self.stepset.run(rules)
        self.assertEqual(context.answers,
                         ['ok.', 'Ok. Who gave you the answer to that one?'])
        self.assertEqual(
            context.insults,
            ['You, sir, are bad at math.', 'I shall taunt you a second time!'])

    def test_if_then_set_yaml(self):
        rules = """\
            Does 1 plus 1 equal 2?
            If so, then set:
              math: ok-ish
              level: 1
            If not, then set:
              math: very bad
              level: -23

            Does 1 plus 2 equal 42?
            If so, then set:
              something: horribly broken
            If not, then set:
              numbers:
                - 1
                - 2
                - wait, what?
              hmm: ok
            """
        context = self.stepset.run(rules)
        self.assertEqual(context.math, 'ok-ish')
        self.assertEqual(context.level, 1)
        self.assertEqual(context.numbers, [1, 2, 'wait, what?'])
        self.assertEqual(context.hmm, 'ok')
        self.assertNotIn('something', context)
Example #15
0
    def setUp(self):
        self.step_set = StepSet()

        self.yaml_step = YamlFuncStep(self.yaml_func)
        self.step_set.add_step(self.yaml_step)
Example #16
0
class CallingTest(TestCase):
    def setUp(self):
        self.step_set = StepSet()

    def test_run_plaintext(self):
        def set_foo(context, args):
            self.assertEqual(args, {})
            context.foo = 'bar'
            return 'the middle'

        def set_bar(context, args):
            self.assertEqual(args, {})
            self.assertEqual(context.last_return, 'the middle')
            context.bar = 'baz'
            return 'the end'

        self.step_set.add_step(RFS('Set foo', set_foo))
        self.step_set.add_step(RFS('Set bar', set_bar))
        context = self.step_set.run('Set foo\nSet bar')
        self.assertEqual(context.foo, 'bar')
        self.assertEqual(context.last_return, 'the end')

    def test_run_with_args(self):
        def set_x_to_y(context, args):
            context[args.x] = args.y

        def add_x_to_y(context, args):
            context.sum = int(context[args.x]) + int(context[args.y])

        def x_should_equal_y(context, args):
            self.assertEqual(str(context[args.x]), args.y)

        self.step_set.add_step(RFS('Set (?P<x>.*) to (?P<y>.*)', set_x_to_y))
        self.step_set.add_step(RFS('Add (?P<x>.*) to (?P<y>.*)', add_x_to_y))
        self.step_set.add_step(RFS('(?P<x>.*) should equal (?P<y>.*)',
                                   x_should_equal_y))
        self.step_set.run(dedent("""\
            Set a to 1
            Set b to 3
            Add a to b
            sum should equal 4
            Set c to 38
            Add sum to c
            sum should equal 42"""))

    def test_run_multiline(self):
        def message(context, args):
            msg = re.sub(r'\s+', ' ', args.msg)
            messages = context.setdefault('messages', [])
            messages.append(msg)
            return msg

        step_re = r'([ /t]*)Message:\s*(?P<msg>.*(\n\1[ \t]+.+)*)'
        self.step_set.add_step(RFS(step_re, message, multiline=True))
        lines = dedent("""\
            Message: Hey there.
              This message is lots
              of lines long.
            
            Message:
              This
               is
                also
              a longer
               message.
            """)
        context = self.step_set.run(lines)
        self.assertEqual(context.messages,
                         ['Hey there. This message is lots of lines long.',
                          'This is also a longer message.'])
Example #17
0
class CompositeTest(TestCase):

    def setUp(self):
        self.step_set = StepSet()

        def set_x_to_y(context, args):
            context[args.x] = args.y
        self.set_step = RegexFuncStep('set (?P<x>.+) to (?P<y>.+)',
                                      set_x_to_y)
        self.step_set.add_step(self.set_step)

    def test_predicate_step(self):
        def if_func(context, args):
            return context[args.x] == args.y
        if_step = RegexFuncStep('if (?P<x>.+) is (?P<y>.+) then', if_func)

        def set_from_yaml(context, args):
            context.update(args)
        set_from_yaml_step = YamlFuncStep(set_from_yaml)

        pred_step = PredicateStep(if_step, set_from_yaml_step)
        self.step_set.add_step(pred_step)

        rule = """\
set foo to bar
if foo is blah then
  a: 2
  b: nope
if foo is bar then
  c: 42
  d: yep
"""
        steps = self.step_set.parse(rule)
        expected = [
            ({1: 'foo', 2: 'bar', 'x': 'foo', 'y': 'bar'}, self.set_step),
            ({1: 'foo', 2: 'blah', 'x': 'foo', 'y': 'blah', 'a': 2,
              'b': 'nope'},
             pred_step),
            ({1: 'foo', 2: 'bar', 'x': 'foo', 'y': 'bar', 'c': 42,
              'd': 'yep'},
             pred_step)
        ]
        self.assertEqual(steps, expected)
        context = self.step_set.run(rule)
        expected = {
            'foo': 'bar',
            'c': 42,
            'd': 'yep',
            1: 'foo',
            2: 'bar',
            'x': 'foo',
            'y': 'bar',
            'last_return': None
        }
        self.assertEqual(context, expected)

    def test_recursive_parse_conditional(self):
        def if_func(context, args):
            return context.get(args[1]) == args[2]
        if_step = RegexFuncStep(
            r'\s*if (.+) is (\w+) ', if_func, multiline=True)

        def set_from_yaml(context, args):
            context.setdefault('args', {}).update(
                {k: v for k, v in args.items() if isinstance(k, str)})
        set_from_yaml_step = CompositeStep(PrefixStep('then set:'),
                                           YamlFuncStep(set_from_yaml))
        self.step_set.add_step(PredicateStep(if_step))
        self.step_set.add_step(set_from_yaml_step)
        rule = """
               if a is b then set:
                 x: blah
                 y: 42

               set a to b
               if a is b then set:
                 foo: x
                 bar: 0
               """
        context = self.step_set.run(rule)
        self.assertEqual(context.args, {'foo': 'x', 'bar': 0})

    def test_yaml_prefix(self):
        def yaml_func(context, args):
            context.setdefault('args', {}).update(args)

        yaml_step = YamlFuncStep(yaml_func)
        prefix_step = PrefixStep('YAML!')
        prefixed_yaml_step = CompositeStep(prefix_step, yaml_step)
        self.step_set.add_step(prefixed_yaml_step)

        rule = """YAML!
                       a: foo
                       b: bar
                    """
        expected = {'a': 'foo', 'b': 'bar'}
        context = self.step_set.run(rule)
        self.assertEqual(context.args, expected)

    def test_loop_step(self):
        self.step_set.add_step(LoopStep('For each thing ', 'things'))

        @RegexFuncStep.make('increment')
        def increment(context, args):
            context[context.it] = context.get(context.it, 0) + 1
        self.step_set.add_step(increment)

        rule = "For each thing increment"

        self.step_set.run(rule, context=Context(things=[]))
Example #18
0
class ParsingTest(TestCase):
    def setUp(self):
        self.step_set = StepSet()

    _ok = lambda ctx, args: True

    def test_plain_text_step(self):
        step = RegexFuncStep("I'm a step!", self._ok)
        self.step_set.add_step(step)

        parsed = self.step_set.parse("I'm a step!")
        expected = [({}, step)]
        self.assertEqual(parsed, expected)

    def test_failed_plain_text_step(self):
        step = RegexFuncStep("I'm a step!", self._ok)
        self.step_set.add_step(step)

        self.assertRaises(UnmatchedStepError, self.step_set.parse,
                          "I don't match")

    def test_plain_text_step_suffix_content(self):
        step = RegexFuncStep("I'm a step", self._ok)
        self.step_set.add_step(step)

        parsed = self.step_set.parse("I'm a step plus more")
        expected = [({'suffix_content': ' plus more'}, step)]
        self.assertEqual(parsed, expected)

    def test_plain_text_step_prefix_suffix_content(self):
        step = RegexFuncStep("I'm a step", self._ok)
        self.step_set.add_step(step)

        parsed = self.step_set.parse("Hey I'm a step plus")
        expected = [({'prefix_content': 'Hey ', 'suffix_content': ' plus'},
                     step)]
        self.assertEqual(parsed, expected)

    def test_regex_nocaptures(self):
        step = RegexFuncStep('^strictly this$', self._ok)
        self.step_set.add_step(step)
        parsed = self.step_set.parse('strictly this')
        expected = [({}, step)]
        self.assertEqual(parsed, expected)

    def test_regex_extra_fail(self):
        step = RegexFuncStep('^strictly this$', self._ok)
        self.step_set.add_step(step)
        self.assertRaises(UnmatchedStepError, self.step_set.parse,
                          'strictly this plus more')
        self.assertRaises(UnmatchedStepError, self.step_set.parse,
                          'prefix and strictly this')

    def test_regex_captures(self):
        step = RegexFuncStep('one (?P<two>.*) three (?P<four>.*)', self._ok)
        self.step_set.add_step(step)
        parsed = self.step_set.parse('one 2 three 4\none hey three there')
        expected = [
            ({'two': '2', 'four': '4', 1: '2', 2: '4'}, step),
            ({'two': 'hey', 'four': 'there', 1: 'hey', 2: 'there'}, step)
        ]
        self.assertEqual(parsed, expected)

    def test_regex_numeric_captures(self):
        step = RegexFuncStep('one (.*) three (.*)', self._ok)
        self.step_set.add_step(step)
        parsed = self.step_set.parse('one 2 three 4\none hey three there')
        expected = [
            ({1: '2', 2: '4'}, step),
            ({1: 'hey', 2: 'there'}, step)
        ]
        self.assertEqual(parsed, expected)

    def test_multiline(self):
        step = RegexFuncStep('this: (.*)\nand this: (.*)', self._ok,
                             multiline=True)
        self.step_set.add_step(step)
        parsed = self.step_set.parse('this: first\nand this: second')
        expected = [({1: 'first', 2: 'second'}, step)]
        self.assertEqual(parsed, expected)