Beispiel #1
0
    def test_empty_return(self, capsys):
        """
        This test looks like test_return_in_the_middle, but instead or returning n, it
        will return nothing.
        """
        statement = [
            "fun count(n) {",
            "  while (n < 100) {",
            "    if (n == 3) return; // <--",
            "    print n;",
            "    n = n + 1;",
            "  }",
            "}",
            "",
            "print count(1);",
        ]
        source = "\n".join(statement)
        yaplox = Yaplox()
        yaplox.run(source)

        assert not yaplox.had_error
        assert not yaplox.had_runtime_error

        captured = capsys.readouterr()
        assert captured.out == "1\n2\nnil\n"
Beispiel #2
0
    def test_if_or(self, capsys):
        statement = [
            "var a = 4;",
            "var b = 3;",
            'if (a == 3 or b == 3) { print "or b == 3"; } ',
            'if (a == 3 or b == 4) { print ""; } else { print "both false"; } ',
            'if (a == 4 or b == 3) { print "or true"; } else { print ""; } ',
            'if (a == 4 or b == 4) { print "only a true"; } else { print ""; } ',
            'if (a == 4 and b == 3) { print "a and b"; } else { print ""; } ',
            'if (a == 3 and b == 3) { print ""; } else { print "a != 3"; } ',
        ]
        source = "\n".join(statement)
        yaplox = Yaplox()
        yaplox.run(source)

        assert not yaplox.had_error
        assert not yaplox.had_runtime_error

        captured = capsys.readouterr()
        assert captured.out == (
            "or b == 3\n"
            "both false\n"
            "or true\n"
            "only a true\n"
            "a and b\n"
            "a != 3\n"
        )
Beispiel #3
0
    def test_recursive_fibonacci(self, capsys):
        """
        Example from crafting interpreters, a recursive Fibonacci function
        """
        statement = [
            "fun fib(n) {",
            "  if (n <= 1) return n;",
            "  return fib(n - 2) + fib(n - 1);",
            "}",
            "",
            "for (var i = 0; i < 20; i = i + 1) {",
            "  print fib(i);",
            "}",
        ]
        source = "\n".join(statement)
        yaplox = Yaplox()
        yaplox.run(source)

        assert not yaplox.had_error
        assert not yaplox.had_runtime_error

        captured = capsys.readouterr()

        # We expect the first 20 numbers:
        # fmt: off
        fibonacci = [
            0, 1, 1, 2, 3,
            5, 8, 13, 21, 34,
            55, 89, 144, 233, 377,
            610, 987, 1597, 2584, 4181,
        ]
        # fmt: on

        expected_str_output = "\n".join([str(nr) for nr in fibonacci]) + "\n"
        assert captured.out == expected_str_output
Beispiel #4
0
    def test_return_in_the_middle(self, capsys):
        """
        Test that we can return from a function in the middle of a loop.
        It runs until 100, but will exit when n == 3, before printing n
        """
        statement = [
            "fun count(n) {",
            "  while (n < 100) {",
            "    if (n == 3) return n; // <--",
            "    print n;",
            "    n = n + 1;",
            "  }",
            "}",
            "",
            "count(1);",
        ]
        source = "\n".join(statement)
        yaplox = Yaplox()
        yaplox.run(source)

        assert not yaplox.had_error
        assert not yaplox.had_runtime_error

        captured = capsys.readouterr()
        assert captured.out == "1\n2\n"
Beispiel #5
0
    def test_fibonacci_sequence(self, capsys):
        """ Compute fibonacci numbers """
        source = [
            "var a = 0;",
            "var b = 1;",
            "",
            "while (a < 10000) {",
            "  print a;",
            "  var temp = a;",
            "  a = b;",
            "  b = temp + b;",
            "}",
        ]
        source = "\n".join(source)
        yaplox = Yaplox()
        yaplox.run(source)

        assert not yaplox.had_error
        assert not yaplox.had_runtime_error

        captured = capsys.readouterr()

        # We expect the first 21 numbers:
        # fmt: off
        fibonacci = [
            0, 1, 1, 2, 3,
            5, 8, 13, 21, 34,
            55, 89, 144, 233, 377,
            610, 987, 1597, 2584, 4181,
            6765,
        ]
        # fmt: on
        expected_str_output = "\n".join([str(nr) for nr in fibonacci]) + "\n"

        assert captured.out == expected_str_output
Beispiel #6
0
    def test_closures(self, capsys):
        """
        Test closures, where a function in a function must have access to variables that
        are created in the first function.

        """
        statement = [
            "fun makeCounter() {",
            "  var i = 0;",
            "  fun count() {",
            "    i = i + 1;",
            "    print i;",
            "  }",
            "",
            "  return count;",
            "}",
            "",
            "var counter = makeCounter();",
            "counter(); // 1.",
            "counter(); // 2.",
        ]
        source = "\n".join(statement)
        yaplox = Yaplox()
        yaplox.run(source)

        assert not yaplox.had_error
        assert not yaplox.had_runtime_error

        captured = capsys.readouterr()
        assert captured.out == "1\n2\n"
Beispiel #7
0
 def test_main_file_too_many_arg(self):
     # Must crash
     with patch.object(sys, "argv",
                       ["yaplox.py", "test2.lox", "test2.lox"]):
         with pytest.raises(SystemExit) as pytest_wrapped_e:
             yaplox = Yaplox()
             yaplox.main()
         assert pytest_wrapped_e.value.code == 64
         assert pytest_wrapped_e.type == SystemExit
Beispiel #8
0
    def test_call_string(self, capsys):
        """
        Try to call a string. This must fail cleanly
        """
        source = '"ThisIsAstring"();'
        yaplox = Yaplox()
        yaplox.run(source)

        assert not yaplox.had_error
        assert yaplox.had_runtime_error

        captured = capsys.readouterr()
        assert captured.err == "Can only call functions and classes. in line [line1]\n"
Beispiel #9
0
    def test_empty_else(self, capsys):
        statement = [
            "var a = 4;",
            "if (a == 4) {} else {}",
            "if (a == 5) {} else {}",
            "if (a) {} else {}",
            "if (!a) {} else {}",
        ]
        source = "\n".join(statement)
        yaplox = Yaplox()
        yaplox.run(source)

        assert not yaplox.had_error
        assert not yaplox.had_runtime_error
Beispiel #10
0
    def test_for_missing_increment(self, capsys):
        """ Missing increment should still work """
        source = [
            "for(var a = 0;  a <= 5;) {",
            "    print a;",
            "    a = a + 1;" "}",
        ]
        source = "\n".join(source)
        yaplox = Yaplox()
        yaplox.run(source)

        assert not yaplox.had_error
        assert not yaplox.had_runtime_error

        captured = capsys.readouterr()
        expected_str_output = "\n".join([str(n) for n in range(6)]) + "\n"

        assert captured.out == expected_str_output

        # But the trailing ; must be present
        source = source.replace("5;)", "5)")
        yaplox = Yaplox()
        yaplox.run(source)

        assert yaplox.had_error
        assert not yaplox.had_runtime_error

        captured = capsys.readouterr()

        assert "Expect ';' after loop condition." in captured.err
Beispiel #11
0
    def test_main_file_file_arg(self, monkeypatch):
        # Mustn't crash
        # We mock the file loading, that's part of integration testing

        @staticmethod
        def mocked_load_file(file):
            print("In mocked load file")
            assert file == "source.lox"
            return "print(3+4);"

        monkeypatch.setattr(Yaplox, "_load_file", mocked_load_file)

        with patch.object(sys, "argv", ["yaplox.py", "source.lox"]):
            yaplox = Yaplox()
            yaplox.main()
Beispiel #12
0
    def test_print_function(self, capsys):
        """ Test printing a function, and test if an empty body works """
        statement = [
            "fun my_function() {}",
            "",
            "print my_function;",
        ]
        source = "\n".join(statement)
        yaplox = Yaplox()
        yaplox.run(source)

        assert not yaplox.had_error
        assert not yaplox.had_runtime_error

        captured = capsys.readouterr()
        assert captured.out == "<fn my_function>\n"
Beispiel #13
0
    def code_lines(lines: List[str]) -> capsys:

        lines = "\n".join(lines)
        Yaplox().run(lines)
        captured = capsys.readouterr()

        return captured
Beispiel #14
0
    def test_clock(self, capsys):
        """
        Test the clock function, should return a time.
        Since this will return the actual time, we just validate that it's an number
        """
        source = "print clock();"
        yaplox = Yaplox()
        yaplox.run(source)

        assert not yaplox.had_error
        assert not yaplox.had_runtime_error

        captured = capsys.readouterr()
        # Remove the newlines
        time_float = float(captured.out)
        assert isinstance(time_float, float)
Beispiel #15
0
    def test_for(self, capsys):
        source = [
            "for(var a = 0;  a <= 5; a = a + 1) {",
            "    print a;",
            "}",
        ]
        source = "\n".join(source)
        yaplox = Yaplox()
        yaplox.run(source)

        assert not yaplox.had_error
        assert not yaplox.had_runtime_error

        captured = capsys.readouterr()
        expected_str_output = "\n".join([str(n) for n in range(6)]) + "\n"

        assert captured.out == expected_str_output
Beispiel #16
0
    def test_no_arguments(self, capsys):
        statement = [
            "fun say_no_args() {",
            '  print "Hi, I have no arguments";',
            "}",
            "",
            "say_no_args();",
        ]
        source = "\n".join(statement)
        yaplox = Yaplox()
        yaplox.run(source)

        assert not yaplox.had_error
        assert not yaplox.had_runtime_error

        captured = capsys.readouterr()
        assert captured.out == "Hi, I have no arguments\n"
Beispiel #17
0
    def test_return_nothing(self, capsys):
        """
        Test a function that returns nothing
        """
        statement = [
            "fun return_nothing() { }",
            "print return_nothing();",
        ]
        source = "\n".join(statement)
        yaplox = Yaplox()
        yaplox.run(source)

        assert not yaplox.had_error
        assert not yaplox.had_runtime_error

        captured = capsys.readouterr()
        assert captured.out == "nil\n"
Beispiel #18
0
    def test_no_arguments_still_arguments_given(self, capsys):
        statement = [
            "fun say_no_args() {",
            '  print "Hi, I have no arguments";',
            "}",
            "",
            'say_no_args("But", "here", "We", "Are");',
        ]
        source = "\n".join(statement)
        yaplox = Yaplox()
        yaplox.run(source)

        assert not yaplox.had_error
        assert yaplox.had_runtime_error

        captured = capsys.readouterr()
        assert captured.out == ""
        assert captured.err == "Expected 0 arguments but got 4. in line [line5]\n"
Beispiel #19
0
    def test_too_many_arguments_in_call(self, capsys):
        arguments = ", ".join([f"arg_{n:03}" for n in range(256)])

        statement = ["fun sayHi() {", '  print "Hi!";', "}" "", f"sayHi({arguments});"]

        source = "\n".join(statement)
        yaplox = Yaplox()
        yaplox.run(source)

        # This should give a parse error
        assert yaplox.had_error
        assert not yaplox.had_runtime_error

        captured = capsys.readouterr()
        assert captured.out == ""
        # This must give the error about too many arguments.
        assert (
            "[line 4] Error  at 'arg_255' : Cannot have more than 255 arguments."
            in captured.err
        )
Beispiel #20
0
    def test_say_hi(self, capsys):
        """ "
        The example function that is in chapter 10.4.1
        """
        statement = [
            "fun sayHi(first, last) {",
            '  print "Hi, " + first + " " + last + "!";',
            "}",
            "",
            'sayHi("Dear", "Reader");',
        ]
        source = "\n".join(statement)
        yaplox = Yaplox()
        yaplox.run(source)

        assert not yaplox.had_error
        assert not yaplox.had_runtime_error

        captured = capsys.readouterr()
        assert captured.out == "Hi, Dear Reader!\n"
Beispiel #21
0
    def test_arguments_but_none_given(self, capsys):
        statement = [
            "fun sayHi(first, last) {",
            '  print "Hi, " + first + " " + last + "!";',
            "}",
            "",
            "// Prince doesn't have a last name...",
            'sayHi("Prince");',
        ]

        source = "\n".join(statement)
        yaplox = Yaplox()
        yaplox.run(source)

        assert not yaplox.had_error
        assert yaplox.had_runtime_error

        captured = capsys.readouterr()
        assert captured.out == ""
        assert captured.err == "Expected 2 arguments but got 1. in line [line6]\n"
Beispiel #22
0
    def test_if_else(self, capsys):
        statement = [
            "var a = 4;",
            "if (a == 4) {",
            '    print "a == 4";',
            "}",
            "if (a != 5) {",
            '    print "a != 5";',
            "} else {",
            '    print "a == 5";',
            "}",
        ]
        source = "\n".join(statement)
        yaplox = Yaplox()
        yaplox.run(source)

        assert not yaplox.had_error
        assert not yaplox.had_runtime_error

        captured = capsys.readouterr()
        assert captured.out == "a == 4\na != 5\n"
Beispiel #23
0
    def test_simple_while(self, capsys):
        source = [
            "var a = 0;",
            "",
            "while (a < 10) {",
            "    print a;",
            "    a = a + 1;",
            "}",
        ]

        source = "\n".join(source)
        yaplox = Yaplox()
        yaplox.run(source)

        assert not yaplox.had_error
        assert not yaplox.had_runtime_error

        captured = capsys.readouterr()
        expected_str_output = "\n".join([str(n) for n in range(10)]) + "\n"

        assert captured.out == expected_str_output
Beispiel #24
0
    def test_recursion(self, capsys):
        """
        Test that a function can all itself.
        This code example is also from the crafting interpreters book
        """
        statement = [
            "fun count(n) {",
            "  if (n > 1) count(n - 1);",
            "  print n;",
            "}",
            "",
            "count(3);",
        ]
        source = "\n".join(statement)
        yaplox = Yaplox()
        yaplox.run(source)

        assert not yaplox.had_error
        assert not yaplox.had_runtime_error

        captured = capsys.readouterr()
        assert captured.out == "1\n2\n3\n"
Beispiel #25
0
    def test_return(self, capsys):
        """
        Test that a function can all itself.
        This code example is also from the crafting interpreters book
        """
        statement = [
            "fun add(a, b) {",
            "    var result =  (a - 1) + (b - 1);",
            "    return result + 2 ;",
            "}",
            "",
            "print add(3, 5);",
        ]
        source = "\n".join(statement)
        yaplox = Yaplox()
        yaplox.run(source)

        assert not yaplox.had_error
        assert not yaplox.had_runtime_error

        captured = capsys.readouterr()
        assert captured.out == "8\n"
Beispiel #26
0
    def test_too_many_parameters_in_definition(self, capsys):
        parameters = ", ".join([f"arg_{n:03}" for n in range(256)])

        statement = [
            f"fun sayHi({parameters}) {{",
            '  print "Hi!";',
            "}",
        ]

        source = "\n".join(statement)
        yaplox = Yaplox()
        yaplox.run(source)

        # This should give a parse error
        assert yaplox.had_error
        assert not yaplox.had_runtime_error

        captured = capsys.readouterr()
        assert captured.out == ""
        # This must give the error about too many parameters.
        assert (
            "[line 1] Error  at 'arg_255' : Cannot have more than 255 parameters."
            in captured.err
        )
Beispiel #27
0
 def test_main_file_arg(self, mocker):
     # Mustn't crash
     with patch.object(sys, "argv", ["yaplox.py"]):
         yaplox = Yaplox()
         yaplox.main()
Beispiel #28
0
 def test_main(self):
     # Mustn't crash
     with patch.object(sys, "argv", []):
         yaplox = Yaplox()
         yaplox.main()
Beispiel #29
0
    def code_block(block: str) -> capsys:

        Yaplox().run(block)
        captured = capsys.readouterr()

        return captured
Beispiel #30
0
    def test_missing_paren(self, capsys):
        """ Test missing ( and ) in if statements"""
        complete_statement = [
            "var a = 4;" "if (a == 4) {",
            '    print "Four!";',
            "}",
        ]

        source = "\n".join(complete_statement)
        left_missing = source.replace("(", "")
        right_missing = source.replace(")", "")

        # Test a valid statement
        yaplox = Yaplox()
        yaplox.run(source)

        assert not yaplox.had_error
        assert not yaplox.had_runtime_error

        captured = capsys.readouterr()
        assert captured.out == "Four!\n"

        # Test with left ( missing error, on a clean yaplox instance
        yaplox = Yaplox()
        yaplox.run(left_missing)

        assert yaplox.had_error

        captured = capsys.readouterr()
        assert "Expect '(' after 'if'." in captured.err

        # Test with right ) missing error, on a clean yaplox instance
        yaplox = Yaplox()
        yaplox.run(right_missing)

        assert yaplox.had_error

        captured = capsys.readouterr()
        assert "Expect ')' after if condition." in captured.err