Audacity 3.2.0
CompositeTest.cpp
Go to the documentation of this file.
1/* SPDX-License-Identifier: GPL-2.0-or-later */
2/*!********************************************************************
3
4 Audacity: A Digital Audio Editor
5
6 CompositeTest.cpp
7
8 Paul Licameli
9
10**********************************************************************/
11#include <catch2/catch.hpp>
12#include "Composite.h"
13#include "Callable.h"
14#include <algorithm>
15#include <array>
16#include <functional>
17#include <iterator>
18#include <numeric>
19
20using namespace Composite;
21using namespace std;
22
23namespace {
24struct Ignore{};
25
27 MyComponent(int value) : value{ value } {}
28 MyComponent(int value, Ignore ignored) : value{ value } {}
29 virtual ~MyComponent() = default;
30 const int value;
31 operator int() const { return value; }
32};
33
34constexpr auto Component = Callable::UniqueMaker<MyComponent, int>();
35
39
40inline bool operator== (int n, const unique_ptr<MyComponent> &p)
41{
42 return n == *p;
43}
44
45// Test that two sequences are equal, several ways, which also exercises
46// compilation of all the STL style accessors
47template<bool members = true, typename Container1, typename Container2>
48bool compareSequences(const Container1 &c1, const Container2 &c2)
49{
50 bool result = true;
51 if constexpr(members) {
52 result =
53 (equal(c1.begin(), c1.end(), c2.begin(), c2.end()))
54 &&
55 (equal(c1.cbegin(), c1.cend(), c2.cbegin(), c2.cend()))
56 &&
57 (equal(c1.rbegin(), c1.rend(), c2.rbegin(), c2.rend()))
58 &&
59 (equal(c1.crbegin(), c1.crend(), c2.crbegin(), c2.crend()));
60 }
61 result = result &&
62 (equal(begin(c1), end(c1), begin(c2), end(c2)))
63 &&
64 (equal(cbegin(c1), cend(c1), cbegin(c2), cend(c2)))
65 &&
66 (equal(rbegin(c1), rend(c1), rbegin(c2), rend(c2)))
67 &&
68 (equal(crbegin(c1), crend(c1), crbegin(c2), crend(c2)))
69 ;
70 return result;
71}
72}
73
74template<typename Container, auto Maker = nullptr, typename... Args>
75void DoTest(Args ...args)
76{
77 auto Make = [](int value){
78 if constexpr (!bool(Maker))
79 return Component(value, Ignore{});
80 else
81 return Maker(value);
82 };
83
84 using ComponentType = decltype(Make(0));
85
86 // CompositeBase passes constructor arguments to its Component
87 Container container{ args... };
88 REQUIRE(0 == container);
89 REQUIRE(container.empty());
90
91 constexpr int N = 4;
92
93 // Values for comparison
94 vector<int> values(N);
95 iota(values.begin(), values.end(), 1);
96
97 // Make some components
98 vector<ComponentType> components;
99 // Not yet equal
100 REQUIRE(!compareSequences(values, components));
101
102 for (size_t ii = 1; ii <= N; ++ii)
103 components.push_back(Make(ii));
104
105 // Equal values so far
106 if (!bool(Maker))
107 REQUIRE(compareSequences(values, components));
108
109 // Composite works with push_back and back_inserter
110 move(components.begin(), components.end(), back_inserter(container));
111 REQUIRE(!container.empty());
112 REQUIRE(compareSequences(values, container));
113
114 // Break equality of sequences
115 values.push_back(N + 1);
116 REQUIRE(!compareSequences(values, container));
117
118 // Restore equality (and note, Component can take more arguments)
119 container.push_back(Make(N + 1));
120 REQUIRE(compareSequences(values, container));
121}
122
123TEST_CASE("Composite::Base")
124{
125 DoTest<MyCompositeBase>(0);
126 // Also test the extra arguments of MyComponent
127 DoTest<MyCompositeBase2>(0, Ignore{});
128}
129
130namespace {
132 // Scramble the given value!!
133 MyComponentEx(int value) : MyComponent{ -value } {}
134};
135inline bool operator== (int n, const std::unique_ptr<MyComponentEx> &p)
136{
137 return n == *p;
138}
139static auto Maker (int value){return std::make_unique<MyComponentEx>(value); };
140struct MyBuilder;
141}
142
143// But define a trait that negates it again to unscramble it!
144// This specialization must be in the global namespace and precede the complete
145// definition of Builder
146template<> struct Composite::Traits<MyCompositeBase, MyBuilder> {
147 struct ItemBuilderType {
148 auto operator () (std::unique_ptr<MyComponent> ptr) const {
149 return std::make_unique<MyComponentEx>(ptr->value); };
150 auto operator () (int value) const {
151 return std::make_unique<MyComponentEx>(-value); };
152 };
153 static constexpr auto ItemBuilder = ItemBuilderType{};
154 template<typename T> static constexpr auto enables_item_type_v = true;
155};
156
157namespace {
158struct MyBuilder : Composite::Builder<MyCompositeBase, MyBuilder, int> {
159 using Builder::Builder;
160};
161}
162
163TEST_CASE("Composite::Builder")
164{
165 using namespace placeholders;
166 std::array values{ 0, 1, 2, 3, 4 };
167
168 DoTest<MyBuilder, Maker>(0);
169 // Test compilation of the variadic constructor and the overload of
170 // ItemBuilderType::operator ()
171 // Remember first 0 is not an element
172 MyBuilder builder{ 0, 0, 1, 2, 3, 4 };
173
174 REQUIRE(compareSequences(values, builder));
175
176 // Forward range
177 MyBuilder builder2{ 0, begin(values), end(values) };
178 REQUIRE(compareSequences(values, builder2));
179
180 // Transform range
181 std::array values2{ 1, 2, 3, 4, 5 };
182 MyBuilder builder3{ 0, begin(values2), end(values2),
183 bind( minus{}, _1, -1 ) };
184 REQUIRE(compareSequences(values, builder2));
185}
186
187TEST_CASE("Composite::Extension")
188{
189 struct X{};
190 using Container = Extension<MyCompositeBase, X, int>;
191 DoTest<Container>(0, X{});
193 DoTest<Container2>(0, Ignore{}, X{});
194}
195
196TEST_CASE("Composite::Extension specialized for void")
197{
199 DoTest<Container>(0);
201 DoTest<Container2>(0, Ignore{});
202}
Functions and classes that generate callable objects.
TEST_CASE("Composite::Base")
void DoTest(Args ...args)
const wxChar * values
Base< MyComponent, unique_ptr< MyComponent >, int > MyCompositeBase
bool compareSequences(const Container1 &c1, const Container2 &c2)
bool operator==(int n, const std::unique_ptr< MyComponentEx > &p)
const char * end(const char *str) noexcept
Definition: StringUtils.h:106
const char * begin(const char *str) noexcept
Definition: StringUtils.h:101
STL namespace.
Extend Base with extra fields, in a second, protected base class.
Definition: Composite.h:177
static constexpr auto ItemBuilder
Definition: Composite.h:80
static constexpr auto enables_item_type_v
Definition: Composite.h:81