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