aboutsummaryrefslogtreecommitdiff
path: root/src/tests/common/unique_function.cpp
blob: 3112725068ca172b8b98ff919f6924d42ec8a7e5 (plain) (blame)
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
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include <string>

#include <catch2/catch.hpp>

#include "common/unique_function.h"

namespace {
struct Noisy {
    Noisy() : state{"Default constructed"} {}
    Noisy(Noisy&& rhs) noexcept : state{"Move constructed"} {
        rhs.state = "Moved away";
    }
    Noisy& operator=(Noisy&& rhs) noexcept {
        state = "Move assigned";
        rhs.state = "Moved away";
        return *this;
    }
    Noisy(const Noisy&) : state{"Copied constructed"} {}
    Noisy& operator=(const Noisy&) {
        state = "Copied assigned";
        return *this;
    }

    std::string state;
};
} // Anonymous namespace

TEST_CASE("UniqueFunction", "[common]") {
    SECTION("Capture reference") {
        int value = 0;
        Common::UniqueFunction<void> func = [&value] { value = 5; };
        func();
        REQUIRE(value == 5);
    }
    SECTION("Capture pointer") {
        int value = 0;
        int* pointer = &value;
        Common::UniqueFunction<void> func = [pointer] { *pointer = 5; };
        func();
        REQUIRE(value == 5);
    }
    SECTION("Move object") {
        Noisy noisy;
        REQUIRE(noisy.state == "Default constructed");

        Common::UniqueFunction<void> func = [noisy = std::move(noisy)] {
            REQUIRE(noisy.state == "Move constructed");
        };
        REQUIRE(noisy.state == "Moved away");
        func();
    }
    SECTION("Move construct function") {
        int value = 0;
        Common::UniqueFunction<void> func = [&value] { value = 5; };
        Common::UniqueFunction<void> new_func = std::move(func);
        new_func();
        REQUIRE(value == 5);
    }
    SECTION("Move assign function") {
        int value = 0;
        Common::UniqueFunction<void> func = [&value] { value = 5; };
        Common::UniqueFunction<void> new_func;
        new_func = std::move(func);
        new_func();
        REQUIRE(value == 5);
    }
    SECTION("Default construct then assign function") {
        int value = 0;
        Common::UniqueFunction<void> func;
        func = [&value] { value = 5; };
        func();
        REQUIRE(value == 5);
    }
    SECTION("Pass arguments") {
        int result = 0;
        Common::UniqueFunction<void, int, int> func = [&result](int a, int b) { result = a + b; };
        func(5, 4);
        REQUIRE(result == 9);
    }
    SECTION("Pass arguments and return value") {
        Common::UniqueFunction<int, int, int> func = [](int a, int b) { return a + b; };
        REQUIRE(func(5, 4) == 9);
    }
    SECTION("Destructor") {
        int num_destroyed = 0;
        struct Foo {
            Foo(int* num_) : num{num_} {}
            Foo(Foo&& rhs) : num{std::exchange(rhs.num, nullptr)} {}
            Foo(const Foo&) = delete;

            ~Foo() {
                if (num) {
                    ++*num;
                }
            }

            int* num = nullptr;
        };
        Foo object{&num_destroyed};
        {
            Common::UniqueFunction<void> func = [object = std::move(object)] {};
            REQUIRE(num_destroyed == 0);
        }
        REQUIRE(num_destroyed == 1);
    }
}