1//! @file test_design_pattern.cpp
2//! @author ryftchen
3//! @brief The definitions (test_design_pattern) in the test module.
4//! @version 0.1.0
5//! @copyright Copyright (c) 2022-2026 ryftchen. All rights reserved.
6
7#include <gtest/gtest.h>
8#include <syncstream>
9
10#include "application/example/include/apply_design_pattern.hpp"
11
12//! @brief The test module.
13namespace test // NOLINT(modernize-concat-nested-namespaces)
14{
15//! @brief Design-pattern-testing-related functions in the test module.
16namespace tst_dp
17{
18//! @brief Print the progress of the design pattern task tests.
19//! @param title - task title
20//! @param state - task state
21//! @param align - alignment width
22static void printTaskProgress(const std::string_view title, const std::string_view state, const std::uint8_t align = 50)
23{
24 std::osyncstream(std::cout) << "TEST DESIGN PATTERN: " << std::setiosflags(std::ios_base::left) << std::setfill('.')
25 << std::setw(align) << title << state << std::resetiosflags(mask: std::ios_base::left)
26 << std::setfill(' ') << std::endl;
27}
28
29//! @brief Test base of behavioral.
30class BehavioralTestBase : public ::testing::Test
31{
32private:
33 //! @brief Alias for the showcase.
34 using Showcase = application::app_dp::behavioral::Showcase;
35
36protected:
37 //! @brief Set up the test case.
38 static void SetUpTestSuite() { printTaskProgress(title, state: "BEGIN"); }
39 //! @brief Tear down the test case.
40 static void TearDownTestSuite() { printTaskProgress(title, state: "END"); }
41
42 //! @brief Test title.
43 inline static const std::string_view title{design_pattern::behavioral::description()};
44 //! @brief System under test.
45 [[no_unique_address]] const Showcase sut{};
46 // clang-format off
47 //! @brief Expected result 1.
48 static constexpr std::string_view expRes1
49 {
50 "cannot be handled by handler 1\n"
51 "handled by handler 2\n"
52 };
53 //! @brief Expected result 2.
54 static constexpr std::string_view expRes2
55 {
56 "receiver: execute action\n"
57 };
58 //! @brief Expected result 3.
59 static constexpr std::string_view expRes3
60 {
61 "1 AND 0 = 0\n"
62 };
63 //! @brief Expected result 4.
64 static constexpr std::string_view expRes4
65 {
66 "item value: 1\n"
67 "item value: 1\n"
68 "item value: 1\n"
69 "item value: 1\n"
70 "item value: 1\n"
71 };
72 //! @brief Expected result 5.
73 static constexpr std::string_view expRes5
74 {
75 "message \"hi!\" sent by colleague 1\n"
76 "message \"hi!\" received by colleague 2\n"
77 "message \"hi!\" received by colleague 3\n"
78 "message \"hello!\" sent by colleague 3\n"
79 "message \"hello!\" received by colleague 1\n"
80 "message \"hello!\" received by colleague 2\n"
81 };
82 //! @brief Expected result 6.
83 static constexpr std::string_view expRes6
84 {
85 "set state to 1\n"
86 "save state\n"
87 "set state to 2\n"
88 "save state\n"
89 "set state to 3\n"
90 "undo state\n"
91 "actual state is 2\n"
92 };
93 //! @brief Expected result 7.
94 static constexpr std::string_view expRes7
95 {
96 "observer1 state: 1\n"
97 "observer2 state: 2\n"
98 "observer state updated\n"
99 "observer state updated\n"
100 "observer1 state: 3\n"
101 "observer2 state: 3\n"
102 };
103 //! @brief Expected result 8.
104 static constexpr std::string_view expRes8
105 {
106 "state A handled\n"
107 "state B handled\n"
108 };
109 //! @brief Expected result 9.
110 static constexpr std::string_view expRes9
111 {
112 "concrete strategy A\n"
113 "concrete strategy B\n"
114 };
115 //! @brief Expected result 10.
116 static constexpr std::string_view expRes10
117 {
118 "primitive operation 1\n"
119 "primitive operation 2\n"
120 };
121 //! @brief Expected result 11.
122 static constexpr std::string_view expRes11
123 {
124 "concrete visitor 1: element A visited\n"
125 "concrete visitor 2: element A visited\n"
126 "concrete visitor 1: element B visited\n"
127 "concrete visitor 2: element B visited\n"
128 };
129 // clang-format on
130};
131
132//! @brief Test for the chain of responsibility instance in the pattern of behavioral.
133TEST_F(BehavioralTestBase, ChainOfResponsibilityInstance)
134{
135 std::ostringstream result{};
136 ASSERT_NO_THROW(result = sut.chainOfResponsibility());
137 ASSERT_EQ(expRes1, result.str());
138}
139
140//! @brief Test for the command instance in the pattern of behavioral.
141TEST_F(BehavioralTestBase, CommandInstance)
142{
143 std::ostringstream result{};
144 ASSERT_NO_THROW(result = sut.command());
145 ASSERT_EQ(expRes2, result.str());
146}
147
148//! @brief Test for the interpreter instance in the pattern of behavioral.
149TEST_F(BehavioralTestBase, InterpreterInstance)
150{
151 std::ostringstream result{};
152 ASSERT_NO_THROW(result = sut.interpreter());
153 ASSERT_EQ(expRes3, result.str());
154}
155
156//! @brief Test for the iterator instance in the pattern of behavioral.
157TEST_F(BehavioralTestBase, IteratorInstance)
158{
159 std::ostringstream result{};
160 ASSERT_NO_THROW(result = sut.iterator());
161 ASSERT_EQ(expRes4, result.str());
162}
163
164//! @brief Test for the mediator instance in the pattern of behavioral.
165TEST_F(BehavioralTestBase, MediatorInstance)
166{
167 std::ostringstream result{};
168 ASSERT_NO_THROW(result = sut.mediator());
169 ASSERT_EQ(expRes5, result.str());
170}
171
172//! @brief Test for the memento instance in the pattern of behavioral.
173TEST_F(BehavioralTestBase, MementoInstance)
174{
175 std::ostringstream result{};
176 ASSERT_NO_THROW(result = sut.memento());
177 ASSERT_EQ(expRes6, result.str());
178}
179
180//! @brief Test for the observer instance in the pattern of behavioral.
181TEST_F(BehavioralTestBase, ObserverInstance)
182{
183 std::ostringstream result{};
184 ASSERT_NO_THROW(result = sut.observer());
185 ASSERT_EQ(expRes7, result.str());
186}
187
188//! @brief Test for the state instance in the pattern of behavioral.
189TEST_F(BehavioralTestBase, StateInstance)
190{
191 std::ostringstream result{};
192 ASSERT_NO_THROW(result = sut.state());
193 ASSERT_EQ(expRes8, result.str());
194}
195
196//! @brief Test for the strategy instance in the pattern of behavioral.
197TEST_F(BehavioralTestBase, StrategyInstance)
198{
199 std::ostringstream result{};
200 ASSERT_NO_THROW(result = sut.strategy());
201 ASSERT_EQ(expRes9, result.str());
202}
203
204//! @brief Test for the template method instance in the pattern of behavioral.
205TEST_F(BehavioralTestBase, TemplateMethodInstance)
206{
207 std::ostringstream result{};
208 ASSERT_NO_THROW(result = sut.templateMethod());
209 ASSERT_EQ(expRes10, result.str());
210}
211
212//! @brief Test for the visitor instance in the pattern of behavioral.
213TEST_F(BehavioralTestBase, VisitorInstance)
214{
215 std::ostringstream result{};
216 ASSERT_NO_THROW(result = sut.visitor());
217 ASSERT_EQ(expRes11, result.str());
218}
219
220//! @brief Test base of creational.
221class CreationalTestBase : public ::testing::Test
222{
223private:
224 //! @brief Alias for the showcase.
225 using Showcase = application::app_dp::creational::Showcase;
226
227protected:
228 //! @brief Set up the test case.
229 static void SetUpTestSuite() { printTaskProgress(title, state: "BEGIN"); }
230 //! @brief Tear down the test case.
231 static void TearDownTestSuite() { printTaskProgress(title, state: "END"); }
232
233 //! @brief Test title.
234 inline static const std::string_view title{design_pattern::creational::description()};
235 //! @brief System under test.
236 [[no_unique_address]] const Showcase sut{};
237 // clang-format off
238 //! @brief Expected result 1.
239 static constexpr std::string_view expRes1
240 {
241 "product: A-X\n"
242 "product: A-Y\n"
243 "product: B-X\n"
244 "product: B-Y\n"
245 };
246 //! @brief Expected result 2.
247 static constexpr std::string_view expRes2
248 {
249 "1st product parts: A-X B-X C-X\n"
250 "2nd product parts: A-Y B-Y C-Y\n"
251 };
252 //! @brief Expected result 3.
253 static constexpr std::string_view expRes3
254 {
255 "product: type A\n"
256 "product: type B\n"
257 };
258 //! @brief Expected result 4.
259 static constexpr std::string_view expRes4
260 {
261 "prototype: type A\n"
262 "prototype: type B\n"
263 };
264 //! @brief Expected result 5.
265 static constexpr std::string_view expRes5
266 {
267 "this is singleton\n"
268 };
269 // clang-format on
270};
271
272//! @brief Test for the abstract factory instance in the pattern of creational.
273TEST_F(CreationalTestBase, AbstractFactoryInstance)
274{
275 std::ostringstream result{};
276 ASSERT_NO_THROW(result = sut.abstractFactory());
277 ASSERT_EQ(expRes1, result.str());
278}
279
280//! @brief Test for the builder instance in the pattern of creational.
281TEST_F(CreationalTestBase, BuilderInstance)
282{
283 std::ostringstream result{};
284 ASSERT_NO_THROW(result = sut.builder());
285 ASSERT_EQ(expRes2, result.str());
286}
287
288//! @brief Test for the factory method instance in the pattern of creational.
289TEST_F(CreationalTestBase, FactoryMethodInstance)
290{
291 std::ostringstream result{};
292 ASSERT_NO_THROW(result = sut.factoryMethod());
293 ASSERT_EQ(expRes3, result.str());
294}
295
296//! @brief Test for the prototype instance in the pattern of creational.
297TEST_F(CreationalTestBase, PrototypeInstance)
298{
299 std::ostringstream result{};
300 ASSERT_NO_THROW(result = sut.prototype());
301 ASSERT_EQ(expRes4, result.str());
302}
303
304//! @brief Test for the singleton instance in the pattern of creational.
305TEST_F(CreationalTestBase, SingletonInstance)
306{
307 std::ostringstream result{};
308 ASSERT_NO_THROW(result = sut.singleton());
309 ASSERT_EQ(expRes5, result.str());
310}
311
312//! @brief Test base of structural.
313class StructuralTestBase : public ::testing::Test
314{
315private:
316 //! @brief Alias for the showcase.
317 using Showcase = application::app_dp::structural::Showcase;
318
319protected:
320 //! @brief Set up the test case.
321 static void SetUpTestSuite() { printTaskProgress(title, state: "BEGIN"); }
322 //! @brief Tear down the test case.
323 static void TearDownTestSuite() { printTaskProgress(title, state: "END"); }
324
325 //! @brief Test title.
326 inline static const std::string_view title{design_pattern::structural::description()};
327 //! @brief System under test.
328 [[no_unique_address]] const Showcase sut{};
329 // clang-format off
330 //! @brief Expected result 1.
331 static constexpr std::string_view expRes1
332 {
333 "specific request\n"
334 };
335 //! @brief Expected result 2.
336 static constexpr std::string_view expRes2
337 {
338 "concrete implementor A\n"
339 "concrete implementor B\n"
340 };
341 //! @brief Expected result 3.
342 static constexpr std::string_view expRes3
343 {
344 "leaf 1 operation\n"
345 "leaf 2 operation\n"
346 "leaf 3 operation\n"
347 "leaf 4 operation\n"
348 };
349 //! @brief Expected result 4.
350 static constexpr std::string_view expRes4
351 {
352 "concrete component operation\n"
353 "decorator A\n"
354 "decorator B\n"
355 };
356 //! @brief Expected result 5.
357 static constexpr std::string_view expRes5
358 {
359 "subsystem A method\n"
360 "subsystem B method\n"
361 "subsystem C method\n"
362 };
363 //! @brief Expected result 6.
364 static constexpr std::string_view expRes6
365 {
366 "concrete flyweight with state 1\n"
367 "concrete flyweight with state 2\n"
368 };
369 //! @brief Expected result 7.
370 static constexpr std::string_view expRes7
371 {
372 "real subject request\n"
373 };
374 // clang-format on
375};
376
377//! @brief Test for the adapter instance in the pattern of structural.
378TEST_F(StructuralTestBase, AdapterInstance)
379{
380 std::ostringstream result{};
381 ASSERT_NO_THROW(result = sut.adapter());
382 ASSERT_EQ(expRes1, result.str());
383}
384
385//! @brief Test for the bridge instance in the pattern of structural.
386TEST_F(StructuralTestBase, BridgeInstance)
387{
388 std::ostringstream result{};
389 ASSERT_NO_THROW(result = sut.bridge());
390 ASSERT_EQ(expRes2, result.str());
391}
392
393//! @brief Test for the composite instance in the pattern of structural.
394TEST_F(StructuralTestBase, CompositeInstance)
395{
396 std::ostringstream result{};
397 ASSERT_NO_THROW(result = sut.composite());
398 ASSERT_EQ(expRes3, result.str());
399}
400
401//! @brief Test for the decorator instance in the pattern of structural.
402TEST_F(StructuralTestBase, DecoratorInstance)
403{
404 std::ostringstream result{};
405 ASSERT_NO_THROW(result = sut.decorator());
406 ASSERT_EQ(expRes4, result.str());
407}
408
409//! @brief Test for the facade instance in the pattern of structural.
410TEST_F(StructuralTestBase, FacadeInstance)
411{
412 std::ostringstream result{};
413 ASSERT_NO_THROW(result = sut.facade());
414 ASSERT_EQ(expRes5, result.str());
415}
416
417//! @brief Test for the flyweight instance in the pattern of structural.
418TEST_F(StructuralTestBase, FlyweightInstance)
419{
420 std::ostringstream result{};
421 ASSERT_NO_THROW(result = sut.flyweight());
422 ASSERT_EQ(expRes6, result.str());
423}
424
425//! @brief Test for the proxy instance in the pattern of structural.
426TEST_F(StructuralTestBase, ProxyInstance)
427{
428 std::ostringstream result{};
429 ASSERT_NO_THROW(result = sut.proxy());
430 ASSERT_EQ(expRes7, result.str());
431}
432} // namespace tst_dp
433} // namespace test
434