VST3: fetch midi mappings all at once, use it for note/sound-off
[carla.git] / source / modules / juce_dsp / containers / juce_FixedSizeFunction_test.cpp
blob6c4aa84a050c24a7fcff5313a84da11cec70bde5
1 /*
2 ==============================================================================
4 This file is part of the JUCE library.
5 Copyright (c) 2022 - Raw Material Software Limited
7 JUCE is an open source library subject to commercial or open-source
8 licensing.
10 By using JUCE, you agree to the terms of both the JUCE 7 End-User License
11 Agreement and JUCE Privacy Policy.
13 End User License Agreement: www.juce.com/juce-7-licence
14 Privacy Policy: www.juce.com/juce-privacy-policy
16 Or: You may also use this code under the terms of the GPL v3 (see
17 www.gnu.org/licenses).
19 JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
20 EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
21 DISCLAIMED.
23 ==============================================================================
26 #if JUCE_ENABLE_ALLOCATION_HOOKS
27 #define JUCE_FAIL_ON_ALLOCATION_IN_SCOPE const UnitTestAllocationChecker checker (*this)
28 #else
29 #define JUCE_FAIL_ON_ALLOCATION_IN_SCOPE
30 #endif
32 namespace juce
34 namespace dsp
36 namespace
39 class ConstructCounts
41 auto tie() const noexcept { return std::tie (constructions, copies, moves, calls, destructions); }
43 public:
44 int constructions = 0;
45 int copies = 0;
46 int moves = 0;
47 int calls = 0;
48 int destructions = 0;
50 ConstructCounts withConstructions (int i) const noexcept { auto c = *this; c.constructions = i; return c; }
51 ConstructCounts withCopies (int i) const noexcept { auto c = *this; c.copies = i; return c; }
52 ConstructCounts withMoves (int i) const noexcept { auto c = *this; c.moves = i; return c; }
53 ConstructCounts withCalls (int i) const noexcept { auto c = *this; c.calls = i; return c; }
54 ConstructCounts withDestructions (int i) const noexcept { auto c = *this; c.destructions = i; return c; }
56 bool operator== (const ConstructCounts& other) const noexcept { return tie() == other.tie(); }
57 bool operator!= (const ConstructCounts& other) const noexcept { return tie() != other.tie(); }
60 String& operator<< (String& str, const ConstructCounts& c)
62 return str << "{ constructions: " << c.constructions
63 << ", copies: " << c.copies
64 << ", moves: " << c.moves
65 << ", calls: " << c.calls
66 << ", destructions: " << c.destructions
67 << " }";
70 class FixedSizeFunctionTest : public UnitTest
72 static void toggleBool (bool& b) { b = ! b; }
74 struct ConstructCounter
76 explicit ConstructCounter (ConstructCounts& countsIn)
77 : counts (countsIn) {}
79 ConstructCounter (const ConstructCounter& c)
80 : counts (c.counts)
82 counts.copies += 1;
85 ConstructCounter (ConstructCounter&& c) noexcept
86 : counts (c.counts)
88 counts.moves += 1;
91 ~ConstructCounter() noexcept { counts.destructions += 1; }
93 void operator()() const noexcept { counts.calls += 1; }
95 ConstructCounts& counts;
98 public:
99 FixedSizeFunctionTest()
100 : UnitTest ("Fixed Size Function", UnitTestCategories::dsp)
103 void runTest() override
105 beginTest ("Can be constructed and called from a lambda");
107 JUCE_FAIL_ON_ALLOCATION_IN_SCOPE;
109 const auto result = 5;
110 bool wasCalled = false;
111 const auto lambda = [&] { wasCalled = true; return result; };
113 const FixedSizeFunction<sizeof (lambda), int()> fn (lambda);
114 const auto out = fn();
116 expect (wasCalled);
117 expectEquals (result, out);
120 beginTest ("void fn can be constructed from function with return value");
122 JUCE_FAIL_ON_ALLOCATION_IN_SCOPE;
124 bool wasCalled = false;
125 const auto lambda = [&] { wasCalled = true; return 5; };
126 const FixedSizeFunction<sizeof (lambda), void()> fn (lambda);
128 fn();
129 expect (wasCalled);
132 beginTest ("Can be constructed and called from a function pointer");
134 JUCE_FAIL_ON_ALLOCATION_IN_SCOPE;
136 bool state = false;
138 const FixedSizeFunction<sizeof (void*), void (bool&)> fn (toggleBool);
140 fn (state);
141 expect (state);
143 fn (state);
144 expect (! state);
146 fn (state);
147 expect (state);
150 beginTest ("Default constructed functions throw if called");
152 const auto a = FixedSizeFunction<8, void()>();
153 expectThrowsType (a(), std::bad_function_call)
155 const auto b = FixedSizeFunction<8, void()> (nullptr);
156 expectThrowsType (b(), std::bad_function_call)
159 beginTest ("Functions can be moved");
161 JUCE_FAIL_ON_ALLOCATION_IN_SCOPE;
163 ConstructCounts counts;
165 auto a = FixedSizeFunction<sizeof (ConstructCounter), void()> (ConstructCounter { counts });
166 expectEquals (counts, ConstructCounts().withMoves (1).withDestructions (1)); // The temporary gets destroyed
168 a();
169 expectEquals (counts, ConstructCounts().withMoves (1).withDestructions (1).withCalls (1));
171 const auto b = std::move (a);
172 expectEquals (counts, ConstructCounts().withMoves (2).withDestructions (1).withCalls (1));
174 b();
175 expectEquals (counts, ConstructCounts().withMoves (2).withDestructions (1).withCalls (2));
177 b();
178 expectEquals (counts, ConstructCounts().withMoves (2).withDestructions (1).withCalls (3));
181 beginTest ("Functions are destructed properly");
183 JUCE_FAIL_ON_ALLOCATION_IN_SCOPE;
185 ConstructCounts counts;
186 const ConstructCounter toCopy { counts };
189 auto a = FixedSizeFunction<sizeof (ConstructCounter), void()> (toCopy);
190 expectEquals (counts, ConstructCounts().withCopies (1));
193 expectEquals (counts, ConstructCounts().withCopies (1).withDestructions (1));
196 beginTest ("Avoid destructing functions that fail to construct");
198 struct BadConstructor
200 explicit BadConstructor (ConstructCounts& c)
201 : counts (c)
203 counts.constructions += 1;
204 throw std::runtime_error { "this was meant to happen" };
207 BadConstructor (const BadConstructor&) = default;
208 BadConstructor& operator= (const BadConstructor&) = delete;
210 ~BadConstructor() noexcept { counts.destructions += 1; }
212 void operator()() const noexcept { counts.calls += 1; }
214 ConstructCounts& counts;
217 ConstructCounts counts;
219 expectThrowsType ((FixedSizeFunction<sizeof (BadConstructor), void()> (BadConstructor { counts })),
220 std::runtime_error)
222 expectEquals (counts, ConstructCounts().withConstructions (1));
225 beginTest ("Equality checks work");
227 JUCE_FAIL_ON_ALLOCATION_IN_SCOPE;
229 FixedSizeFunction<8, void()> a;
230 expect (! bool (a));
231 expect (a == nullptr);
232 expect (nullptr == a);
233 expect (! (a != nullptr));
234 expect (! (nullptr != a));
236 FixedSizeFunction<8, void()> b ([] {});
237 expect (bool (b));
238 expect (b != nullptr);
239 expect (nullptr != b);
240 expect (! (b == nullptr));
241 expect (! (nullptr == b));
244 beginTest ("Functions can be cleared");
246 JUCE_FAIL_ON_ALLOCATION_IN_SCOPE;
248 FixedSizeFunction<8, void()> fn ([] {});
249 expect (bool (fn));
251 fn = nullptr;
252 expect (! bool (fn));
255 beginTest ("Functions can be assigned");
257 JUCE_FAIL_ON_ALLOCATION_IN_SCOPE;
259 using Fn = FixedSizeFunction<8, void()>;
261 int numCallsA = 0;
262 int numCallsB = 0;
264 Fn x;
265 Fn y;
266 expect (! bool (x));
267 expect (! bool (y));
269 x = [&] { numCallsA += 1; };
270 y = [&] { numCallsB += 1; };
271 expect (bool (x));
272 expect (bool (y));
274 x();
275 expectEquals (numCallsA, 1);
276 expectEquals (numCallsB, 0);
278 y();
279 expectEquals (numCallsA, 1);
280 expectEquals (numCallsB, 1);
282 x = std::move (y);
283 expectEquals (numCallsA, 1);
284 expectEquals (numCallsB, 1);
286 x();
287 expectEquals (numCallsA, 1);
288 expectEquals (numCallsB, 2);
291 beginTest ("Functions may mutate internal state");
293 JUCE_FAIL_ON_ALLOCATION_IN_SCOPE;
295 using Fn = FixedSizeFunction<64, void()>;
297 Fn x;
298 expect (! bool (x));
300 int numCalls = 0;
301 x = [&numCalls, counter = 0]() mutable { counter += 1; numCalls = counter; };
302 expect (bool (x));
304 expectEquals (numCalls, 0);
306 x();
307 expectEquals (numCalls, 1);
309 x();
310 expectEquals (numCalls, 2);
313 beginTest ("Functions can sink move-only parameters");
315 JUCE_FAIL_ON_ALLOCATION_IN_SCOPE;
317 using Fn = FixedSizeFunction<64, int (std::unique_ptr<int>)>;
319 auto value = 5;
320 auto ptr = std::make_unique<int> (value);
322 Fn fn = [] (std::unique_ptr<int> p) { return *p; };
324 expect (value == fn (std::move (ptr)));
327 beginTest ("Functions be converted from smaller functions");
329 JUCE_FAIL_ON_ALLOCATION_IN_SCOPE;
331 using SmallFn = FixedSizeFunction<20, void()>;
332 using LargeFn = FixedSizeFunction<21, void()>;
334 bool smallCalled = false;
335 bool largeCalled = false;
337 SmallFn small = [&smallCalled, a = std::array<char, 8>{}] { smallCalled = true; juce::ignoreUnused (a); };
338 LargeFn large = [&largeCalled, a = std::array<char, 8>{}] { largeCalled = true; juce::ignoreUnused (a); };
340 large = std::move (small);
342 large();
344 expect (smallCalled);
345 expect (! largeCalled);
350 FixedSizeFunctionTest fixedSizedFunctionTest;
355 #undef JUCE_FAIL_ON_ALLOCATION_IN_SCOPE