aboutsummaryrefslogtreecommitdiff
path: root/tests/unit/libutil/pool.cc
blob: 3ad4ed3aa3aff33607b60c2174a30d2b63db0459 (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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
#include "pool.hh"
#include <gtest/gtest.h>

namespace nix {

    struct TestResource
    {

        TestResource() {
            static int counter = 0;
            num = counter++;
        }

        int dummyValue = 1;
        bool good = true;
        int num;
    };

    /* ----------------------------------------------------------------------------
     * Pool
     * --------------------------------------------------------------------------*/

    TEST(Pool, freshPoolHasZeroCountAndSpecifiedCapacity) {
        auto isGood = [](const ref<TestResource> & r) { return r->good; };
        auto createResource = []() { return make_ref<TestResource>(); };

        Pool<TestResource> pool = Pool<TestResource>((size_t)1, createResource, isGood);

        ASSERT_EQ(pool.count(), 0);
        ASSERT_EQ(pool.capacity(), 1);
    }

    TEST(Pool, freshPoolCanGetAResource) {
        auto isGood = [](const ref<TestResource> & r) { return r->good; };
        auto createResource = []() { return make_ref<TestResource>(); };

        Pool<TestResource> pool = Pool<TestResource>((size_t)1, createResource, isGood);
        ASSERT_EQ(pool.count(), 0);

        TestResource r = *(pool.get());

        ASSERT_EQ(pool.count(), 1);
        ASSERT_EQ(pool.capacity(), 1);
        ASSERT_EQ(r.dummyValue, 1);
        ASSERT_EQ(r.good, true);
    }

    TEST(Pool, capacityCanBeIncremented) {
        auto isGood = [](const ref<TestResource> & r) { return r->good; };
        auto createResource = []() { return make_ref<TestResource>(); };

        Pool<TestResource> pool = Pool<TestResource>((size_t)1, createResource, isGood);
        ASSERT_EQ(pool.capacity(), 1);
        pool.incCapacity();
        ASSERT_EQ(pool.capacity(), 2);
    }

    TEST(Pool, capacityCanBeDecremented) {
        auto isGood = [](const ref<TestResource> & r) { return r->good; };
        auto createResource = []() { return make_ref<TestResource>(); };

        Pool<TestResource> pool = Pool<TestResource>((size_t)1, createResource, isGood);
        ASSERT_EQ(pool.capacity(), 1);
        pool.decCapacity();
        ASSERT_EQ(pool.capacity(), 0);
    }

    // Test that the resources we allocate are being reused when they are still good.
    TEST(Pool, reuseResource) {
        auto isGood = [](const ref<TestResource> & r) { return true; };
        auto createResource = []() { return make_ref<TestResource>(); };

        Pool<TestResource> pool = Pool<TestResource>((size_t)1, createResource, isGood);

        // Compare the instance counter between the two handles. We expect them to be equal
        // as the pool should hand out the same (still) good one again.
        int counter = -1;
        {
            Pool<TestResource>::Handle h = pool.get();
            counter = h->num;
        } // the first handle goes out of scope

        { // the second handle should contain the same resource (with the same counter value)
            Pool<TestResource>::Handle h = pool.get();
            ASSERT_EQ(h->num, counter);
        }
    }

    // Test that the resources we allocate are being thrown away when they are no longer good.
    TEST(Pool, badResourceIsNotReused) {
        auto isGood = [](const ref<TestResource> & r) { return false; };
        auto createResource = []() { return make_ref<TestResource>(); };

        Pool<TestResource> pool = Pool<TestResource>((size_t)1, createResource, isGood);

        // Compare the instance counter between the two handles. We expect them
        // to *not* be equal as the pool should hand out a new instance after
        // the first one was returned.
        int counter = -1;
        {
            Pool<TestResource>::Handle h = pool.get();
            counter = h->num;
        } // the first handle goes out of scope

        {
          // the second handle should contain a different resource (with a
          //different counter value)
            Pool<TestResource>::Handle h = pool.get();
            ASSERT_NE(h->num, counter);
        }
    }

    TEST(Pool, throwingOperationDropsResource)
    {
        auto createResource = []() { return make_ref<TestResource>(); };

        Pool<TestResource> pool = Pool<TestResource>((size_t)1, createResource);

        ASSERT_THROW({
            auto _r = pool.get();
            ASSERT_EQ(pool.count(), 1);
            throw 1;
        }, int);

        ASSERT_EQ(pool.count(), 0);
    }
}