From bd5f2d733e6fd1d4a4f8adf1bfa4296bc0e7f4cb Mon Sep 17 00:00:00 2001 From: Melvic Ybanez Date: Sun, 29 Oct 2023 00:24:01 +0800 Subject: [PATCH] Add tests about the following: - Closing over of later variables - Closing over method parameters - Closed closure in functions --- README.md | 2 +- tests/test_assignment.dry | 24 +++++++-------- tests/test_closures.dry | 63 ++++++++++++++++++++++++++++++++++----- 3 files changed, 68 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index c96f5fe..0b4b00b 100644 --- a/README.md +++ b/README.md @@ -168,7 +168,7 @@ If everything works correctly, your console should print a bunch of assertion re [Success] Ducks should quack! [Success] Denji should say 'Woof!' [Success] Class properties should be updated -Ran 92 tests. Successful: 92. Failed: 0. +Ran 96 tests. Successful: 96. Failed: 0. ``` The tests themselves are written in Dry (while the `testDry` command is written in Scala). You can see the directory containing them here: https://github.com/melvic-ybanez/dry/tree/main/tests. All the files in that directory that start with `test_` and have the Dry extension will be picked up by the `testDry` command. diff --git a/tests/test_assignment.dry b/tests/test_assignment.dry index b9893d8..827df43 100644 --- a/tests/test_assignment.dry +++ b/tests/test_assignment.dry @@ -5,21 +5,21 @@ def test_associativity() { // assignment is right-associative a = b = c; - assert_equals("a is equal to c", a, c); - assert_equals("b is equal to c", b, c); - assert_equals("c is equal to c", c, c); + assert_equals("Leftmost equals rightmost", a, c); + assert_equals("Middle equals rightmost", b, c); + assert_equals("Rightmost equals rightmost", c, c); } def test_rhs() { let a = "before"; let c = a = "after"; - assert_equals("a = 'after'", a, "after"); - assert_equals("c = 'after'", c, "after"); + assert_equals("Middle gets the RHS value", a, "after"); + assert_equals("Leftmost gets the RHS value", c, "after"); } def test_lhs() { - assert_error("rhs should not be an undefined variable", Errors.UNDEFINED_VARIABLE, + assert_error("RHS should not be an undefined variable", Errors.UNDEFINED_VARIABLE, lambda() { unknown = "what"; }); } @@ -29,18 +29,18 @@ test_lhs(); // global let a = "before"; -assert_equals("a = 'before'", a, "before"); +assert_equals("Global init value", a, "before"); a = "after"; -assert_equals("a = 'after'", a, "after"); +assert_equals("Global update value", a, "after"); // local { let a = "before"; - assert_equals("a = 'before'", a, "before"); + assert_equals("Local init value", a, "before"); a = "after"; - assert_equals("a = 'after'", a, "after"); + assert_equals("Local updated value", a, "after"); - assert_equals("a = 'arg'", a = "arg", "arg"); - assert_equals("a = 'arg'", a, "arg"); + assert_equals("Assignment returned value", a = "arg", "arg"); + assert_equals("Local updated via assignment", a, "arg"); } \ No newline at end of file diff --git a/tests/test_closures.dry b/tests/test_closures.dry index a47ea46..ec6e148 100644 --- a/tests/test_closures.dry +++ b/tests/test_closures.dry @@ -5,16 +5,16 @@ def test_assign_to_closure() { { let local = "local"; def f_() { - assert_equals("`local` should be 'local'", local, "local"); + assert_equals("Capture var", local, "local"); local = "after f"; - assert_equals("`local` should be 'after f'", local, "after f"); + assert_equals("Updated captured var ", local, "after f"); } f = f_; def g_() { - assert_equals("`local` should be 'after f'", local, "after f"); + assert_equals("Capture updated var", local, "after f"); local = "after g"; - assert_equals("`local` should be 'after g'", local, "after g"); + assert_equals("Update updated var", local, "after g"); } g = g_; } @@ -33,10 +33,10 @@ def test_assign_to_shadowed_later() { let a = "inner"; assign(); - assert_equals("`a` should be 'inner'", a, "inner"); + assert_equals("Var declared after closure", a, "inner"); } - assert_equals("`a` should be 'assigned'", a, "assigned"); + assert_equals("Var updated due to closure", a, "assigned"); } def test_close_over_function_param() { @@ -44,7 +44,7 @@ def test_close_over_function_param() { def foo(param) { def f_() { - assert_equals("Expected parameter value: 'param'", param, "param"); + assert_equals("Close over function param", param, "param"); } f = f_; } @@ -52,6 +52,53 @@ def test_close_over_function_param() { f(); } +// see the comment in the following source file for the explanation: +// https://github.com/munificent/craftinginterpreters/blob/master/test/closure/close_over_later_variable.lox +def test_close_over_later_variable() { + let a = "a"; + let b = "b"; + + def g() { + assert_equals("Close over later var", b, "b"); + assert_equals("Close over earlier var", a, "a"); + } + + g(); +} + +def test_close_over_method_param() { + let f; + + class Foo { + def method(param) { + def f_() { + assert_equals("Close over method param", param, "param"); + } + f = f_; + } + } + + Foo().method("param"); + f(); +} + +def test_closed_closure_in_function() { + let f; + + { + let local = "local"; + def f_() { + assert_equals("Closed closure in function", local, "local"); + } + f = f_; + } + + f(); +} + test_assign_to_closure(); test_assign_to_shadowed_later(); -test_close_over_function_param(); \ No newline at end of file +test_close_over_function_param(); +test_close_over_later_variable(); +test_close_over_method_param(); +test_closed_closure_in_function(); \ No newline at end of file