diff options
Diffstat (limited to '')
-rw-r--r-- | unit_tests/deep_tests.cpp | 152 |
1 files changed, 73 insertions, 79 deletions
diff --git a/unit_tests/deep_tests.cpp b/unit_tests/deep_tests.cpp index c1708e1..60dadb7 100644 --- a/unit_tests/deep_tests.cpp +++ b/unit_tests/deep_tests.cpp | |||
@@ -8,94 +8,88 @@ | |||
8 | // ################################################################################################# | 8 | // ################################################################################################# |
9 | // ################################################################################################# | 9 | // ################################################################################################# |
10 | 10 | ||
11 | class DeepTests : public ::testing::Test | 11 | TEST_CASE("deep_test") |
12 | { | 12 | { |
13 | protected: | ||
14 | LuaState S{ LuaState::WithBaseLibs{ true }, LuaState::WithFixture{ true } }; | 13 | LuaState S{ LuaState::WithBaseLibs{ true }, LuaState::WithFixture{ true } }; |
14 | S.requireSuccess( | ||
15 | " lanes = require 'lanes'.configure()" | ||
16 | " fixture = require 'fixture'" | ||
17 | " deep_test = require 'deep_test'" | ||
18 | ); | ||
15 | 19 | ||
16 | void SetUp() override | 20 | SECTION("garbage collection collects") |
17 | { | 21 | { |
18 | std::ignore = S.doString("lanes = require 'lanes'.configure()"); | 22 | S.requireSuccess("assert(true)"); |
19 | std::ignore = S.doString("fixture = require 'fixture'"); | 23 | S.requireFailure("assert(false)"); |
20 | std::ignore = S.doString("deep_test = require 'deep_test'"); | 24 | if constexpr (LUA_VERSION_NUM >= 503) { // Lua < 5.3 only supports a table uservalue |
25 | S.requireSuccess( | ||
26 | // create a deep userdata object without referencing it. First uservalue is a function, and should be called on __gc | ||
27 | " deep_test.new_deep(1):setuv(1, function() collected = collected and collected + 1 or 1 end)" | ||
28 | " deep_test.new_deep(1):setuv(1, function() collected = collected and collected + 1 or 1 end)" | ||
29 | " collectgarbage()" // and collect it | ||
30 | " assert(collected == 2)" | ||
31 | ); | ||
32 | } | ||
21 | } | 33 | } |
22 | }; | ||
23 | 34 | ||
24 | // ################################################################################################# | 35 | // --------------------------------------------------------------------------------------------- |
25 | // ################################################################################################# | ||
26 | 36 | ||
27 | TEST_F(DeepTests, DeepIsCollected) | 37 | SECTION("reference counting") |
28 | { | 38 | { |
29 | ASSERT_EQ(S.doString("assert(true)"), LuaError::OK) << S; | 39 | S.requireSuccess( |
30 | ASSERT_NE(S.doString("assert(false)"), LuaError::OK) << S; | 40 | " d = deep_test.new_deep(1)" // create a deep userdata object |
31 | if constexpr (LUA_VERSION_NUM >= 503) { // Lua < 5.3 only supports a table uservalue | 41 | " d:set(42)" // set some value |
32 | ASSERT_EQ(S.doString( | 42 | " assert(d:refcount() == 1)" |
33 | // create a deep userdata object without referencing it. First uservalue is a function, and should be called on __gc | 43 | ); |
34 | " deep_test.new_deep(1):setuv(1, function() collected = collected and collected + 1 or 1 end)" | 44 | S.requireSuccess( |
35 | " deep_test.new_deep(1):setuv(1, function() collected = collected and collected + 1 or 1 end)" | 45 | " l = lanes.linda()" |
36 | " collectgarbage()" // and collect it | 46 | " b, s = l:set('k', d, d)" // store it twice in the linda |
37 | " assert(collected == 2)" | 47 | " assert(b == false and s == 'under')" // no waking, under capacity |
38 | ), LuaError::OK) << S; | 48 | " assert(d:refcount() == 2)" // 1 ref here, 1 in the keeper (even if we sent it twice) |
49 | ); | ||
50 | S.requireSuccess( | ||
51 | " n, d = l:get('k')" // pull it out of the linda | ||
52 | " assert(n == 1 and type(d) == 'userdata')" // got 1 item out of the linda | ||
53 | " assert(d:get() == 42 and d:refcount() == 2)" // 1 ref here, 1 in the keeper (even if we sent it twice) | ||
54 | ); | ||
55 | S.requireSuccess( | ||
56 | " l = nil" | ||
57 | " collectgarbage()" // clears the linda, removes its storage from the keeper | ||
58 | " lanes.collectgarbage()" // collect garbage inside the keepers too, to finish cleanup | ||
59 | " assert(d:refcount() == 1)" // 1 ref here | ||
60 | ); | ||
61 | if constexpr (LUA_VERSION_NUM >= 503) { // Lua < 5.3 only supports a table uservalue | ||
62 | S.requireSuccess( | ||
63 | " d:setuv(1, function() collected = collected and collected + 1 or 1 end)" | ||
64 | " d = nil" // clear last reference | ||
65 | " collectgarbage()" // force collection | ||
66 | " assert(collected == 1)" // we should see it | ||
67 | ); | ||
68 | } | ||
39 | } | 69 | } |
40 | } | ||
41 | 70 | ||
42 | // ################################################################################################# | 71 | // --------------------------------------------------------------------------------------------- |
43 | 72 | ||
44 | TEST_F(DeepTests, DeepRefcounting) | 73 | SECTION("collection from inside a Linda") |
45 | { | 74 | { |
46 | ASSERT_EQ(S.doString( | 75 | S.requireSuccess( |
47 | " d = deep_test.new_deep(1)" // create a deep userdata object | 76 | " d = deep_test.new_deep(1)" // create a deep userdata object |
48 | " d:set(42)" // set some value | 77 | " d:set(42)" // set some value |
49 | " assert(d:refcount() == 1)" | 78 | " assert(d:refcount() == 1)" |
50 | ), LuaError::OK) << S; | 79 | ); |
51 | ASSERT_EQ(S.doString( | 80 | S.requireSuccess( |
52 | " l = lanes.linda()" | 81 | " l = lanes.linda()" |
53 | " b, s = l:set('k', d, d)" // store it twice in the linda | 82 | " b, s = l:set('k', d, d)" // store it twice in the linda |
54 | " assert(b == false and s == 'under')" // no waking, under capacity | 83 | " assert(b == false and s == 'under')" // no waking, under capacity |
55 | " assert(d:refcount() == 2)" // 1 ref here, 1 in the keeper (even if we sent it twice) | 84 | " assert(d:refcount() == 2)" // 1 ref here, 1 in the keeper (even if we sent it twice) |
56 | ), LuaError::OK) << S; | 85 | ); |
57 | ASSERT_EQ(S.doString( | 86 | S.requireSuccess( |
58 | " n, d = l:get('k')" // pull it out of the linda | 87 | " d = nil" |
59 | " assert(n == 1 and type(d) == 'userdata')" // got 1 item out of the linda | 88 | " collectgarbage()" // force collection |
60 | " assert(d:get() == 42 and d:refcount() == 2)" // 1 ref here, 1 in the keeper (even if we sent it twice) | 89 | " l = nil" |
61 | ), LuaError::OK) << S; | 90 | " collectgarbage()" // clears the linda, removes its storage from the keeper |
62 | ASSERT_EQ(S.doString( | 91 | " lanes.collectgarbage()" // collect garbage inside the keepers too, to finish cleanup |
63 | " l = nil" | 92 | " assert(deep_test.get_deep_count() == 0)" |
64 | " collectgarbage()" // clears the linda, removes its storage from the keeper | 93 | ); |
65 | " lanes.collectgarbage()" // collect garbage inside the keepers too, to finish cleanup | ||
66 | " assert(d:refcount() == 1)" // 1 ref here | ||
67 | ), LuaError::OK) << S; | ||
68 | if constexpr (LUA_VERSION_NUM >= 503) { // Lua < 5.3 only supports a table uservalue | ||
69 | ASSERT_EQ(S.doString( | ||
70 | " d:setuv(1, function() collected = collected and collected + 1 or 1 end)" | ||
71 | " d = nil" // clear last reference | ||
72 | " collectgarbage()" // force collection | ||
73 | " assert(collected == 1)" // we should see it | ||
74 | ), LuaError::OK) << S; | ||
75 | } | 94 | } |
76 | } | ||
77 | |||
78 | // ################################################################################################# | ||
79 | |||
80 | TEST_F(DeepTests, DeepCollectedFromInsideLinda) | ||
81 | { | ||
82 | ASSERT_EQ(S.doString( | ||
83 | " d = deep_test.new_deep(1)" // create a deep userdata object | ||
84 | " d:set(42)" // set some value | ||
85 | " assert(d:refcount() == 1)" | ||
86 | ), LuaError::OK) << S; | ||
87 | ASSERT_EQ(S.doString( | ||
88 | " l = lanes.linda()" | ||
89 | " b, s = l:set('k', d, d)" // store it twice in the linda | ||
90 | " assert(b == false and s == 'under')" // no waking, under capacity | ||
91 | " assert(d:refcount() == 2)" // 1 ref here, 1 in the keeper (even if we sent it twice) | ||
92 | ), LuaError::OK) << S; | ||
93 | ASSERT_EQ(S.doString( | ||
94 | " d = nil" | ||
95 | " collectgarbage()" // force collection | ||
96 | " l = nil" | ||
97 | " collectgarbage()" // clears the linda, removes its storage from the keeper | ||
98 | " lanes.collectgarbage()" // collect garbage inside the keepers too, to finish cleanup | ||
99 | " assert(deep_test.get_deep_count() == 0)" | ||
100 | ), LuaError::OK) << S; | ||
101 | } \ No newline at end of file | 95 | } \ No newline at end of file |