aboutsummaryrefslogtreecommitdiff
path: root/unit_tests/deep_tests.cpp
blob: e21072c670e177e45011f80384420a4477dd8b90 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
#include "_pch.hpp"
#include "shared.h"

// yeah it's dirty, I will do better someday
#include "../deep_userdata_example/deep_userdata_example.cpp"


// #################################################################################################
// #################################################################################################

TEST_CASE("misc.deep_userdata.example")
{
    LuaState S{ LuaState::WithBaseLibs{ true }, LuaState::WithFixture{ true } };
    S.requireSuccess(
        " lanes = require 'lanes'.configure()"
        " fixture = require 'fixture'"
        " due = require 'deep_userdata_example'"
    );

    SECTION("garbage collection collects")
    {
        S.requireSuccess("assert(true)");
        S.requireFailure("assert(false)");
        if constexpr (LUA_VERSION_NUM >= 503) { // Lua < 5.3 only supports a table uservalue
            S.requireSuccess(
                // create a deep userdata object without referencing it. First uservalue is a function, and should be called on __gc
                " due.new_deep(1):setuv(1, function() collected = collected and collected + 1 or 1 end)"
                " due.new_deep(1):setuv(1, function() collected = collected and collected + 1 or 1 end)"
                " collectgarbage()"                         // and collect it
                " assert(collected == 2)"
            );
        }
    }

    // ---------------------------------------------------------------------------------------------

    SECTION("reference counting")
    {
        S.requireSuccess(
            " d = due.new_deep(1)"                         // create a deep userdata object
            " d:set(42)"                                   // set some value
            " assert(d:refcount() == 1)"
        );
        S.requireSuccess(
            " l = lanes.linda()"
            " b, s = l:set('k', d, d)"                     // store it twice in the linda
            " assert(b == false and s == 'under')"         // no waking, under capacity
            " assert(d:refcount() == 2)"                   // 1 ref here, 1 in the keeper (even if we sent it twice)
        );
        S.requireSuccess(
            " n, d = l:get('k')"                           // pull it out of the linda
            " assert(n == 1 and type(d) == 'userdata')"    // got 1 item out of the linda
            " assert(d:get() == 42 and d:refcount() == 2)" // 1 ref here, 1 in the keeper (even if we sent it twice)
        );
        S.requireSuccess(
            " l = nil"
            " collectgarbage()"                            // clears the linda, removes its storage from the keeper
            " lanes.collectgarbage()"                      // collect garbage inside the keepers too, to finish cleanup
            " assert(d:refcount() == 1)"                   // 1 ref here
        );
        if constexpr (LUA_VERSION_NUM >= 503) { // Lua < 5.3 only supports a table uservalue
            S.requireSuccess(
                " d:setuv(1, function() collected = collected and collected + 1 or 1 end)"
                " d = nil"                                 // clear last reference
                " collectgarbage()"                        // force collection
                " assert(collected == 1)"                  // we should see it
            );
        }
    }

    // ---------------------------------------------------------------------------------------------

    SECTION("collection from inside a Linda")
    {
        S.requireSuccess(
            " d = due.new_deep(1)"                         // create a deep userdata object
            " d:set(42)"                                   // set some value
            " assert(d:refcount() == 1)"
        );
        S.requireSuccess(
            " l = lanes.linda()"
            " b, s = l:set('k', d, d)"                     // store it twice in the linda
            " assert(b == false and s == 'under')"         // no waking, under capacity
            " assert(d:refcount() == 2)"                   // 1 ref here, 1 in the keeper (even if we sent it twice)
        );
        S.requireSuccess(
            " d = nil"
            " collectgarbage()"                            // force collection
            " l = nil"
            " collectgarbage()"                            // clears the linda, removes its storage from the keeper
            " lanes.collectgarbage()"                      // collect garbage inside the keepers too, to finish cleanup
            " assert(due.get_deep_count() == 0)"
        );
    }
}