• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

ParadoxGameConverters / Vic3ToHoI4 / 19107295354

05 Nov 2025 03:33PM UTC coverage: 92.825% (-1.0%) from 93.807%
19107295354

push

github

web-flow
Update commons (#769)

* Update commons

* Fixes for coverage

25020 of 26954 relevant lines covered (92.82%)

50121.96 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

95.86
/src/hoi4_world/focus_trees/focus_tree_assembler_tests.cpp
1
#include <external/commonItems/external/googletest/googlemock/include/gmock/gmock-matchers.h>
2
#include <external/commonItems/external/googletest/googletest/include/gtest/gtest.h>
3

4
#include <sstream>
5

6
#include "src/hoi4_world/focus_trees/focus_tree_assembler.h"
7
#include "src/hoi4_world/roles/triggers/always_trigger.h"
8
#include "src/hoi4_world/roles/triggers/any_other_country_trigger.h"
9
#include "src/hoi4_world/roles/triggers/any_owned_state_trigger.h"
10
#include "src/hoi4_world/roles/triggers/or_trigger.h"
11
#include "src/hoi4_world/roles/triggers/tag_trigger.h"
12

13

14

15
namespace hoi4
16
{
17

18
TEST(Hoi4worldFocustreesFocustreeassemblerTests, TreeIsEmptyByDefault)
4✔
19
{
20
   const FocusTree focus_tree = AssembleTree({}, "", World({}));
1✔
21

22
   EXPECT_TRUE(focus_tree.shared_focuses.empty());
1✔
23
   EXPECT_TRUE(focus_tree.focuses.empty());
1✔
24
}
2✔
25

26

27
TEST(Hoi4worldFocustreesFocustreeassemblerTests, SharedFocusesAreAddedToTree)
4✔
28
{
29
   const FocusTree focus_tree = AssembleTree(
6✔
30
       {
31
           Role{{.shared_focuses = {"focus_one", "focus_two"}}},
1✔
32
           Role{{.shared_focuses = {"focus_three", "focus_four"}}},
1✔
33
       },
34
       "",
35
       World({}));
2✔
36

37
   EXPECT_THAT(focus_tree.shared_focuses, testing::ElementsAre("focus_one", "focus_two", "focus_three", "focus_four"));
1✔
38
   EXPECT_TRUE(focus_tree.focuses.empty());
1✔
39
}
7✔
40

41

42
TEST(Hoi4worldFocustreesFocustreeassemblerTests, FocusesAreAddedToTree)
4✔
43
{
44
   const FocusTree focus_tree = AssembleTree(
6✔
45
       {
46
           Role{{.focuses = {Focus{.id = "focus_one"}, Focus{.id = "focus_two"}}}},
3✔
47
           Role{{.focuses = {Focus{.id = "focus_three"}, Focus{.id = "focus_four"}}}},
3✔
48
       },
49
       "",
50
       World({}));
2✔
51

52
   EXPECT_TRUE(focus_tree.shared_focuses.empty());
1✔
53
   EXPECT_THAT(focus_tree.focuses,
9✔
54
       testing::ElementsAre(Focus{.id = "focus_one"},
55
           Focus{.id = "focus_two"},
56
           Focus{.id = "focus_three"},
57
           Focus{.id = "focus_four"}));
1✔
58
}
12✔
59

60

61
TEST(Hoi4worldFocustreesFocustreeassemblerTests, FocusesAreToTheRightOfSharedFocuses)
4✔
62
{
63
   const FocusTree focus_tree = AssembleTree(
6✔
64
       {
65
           Role{{.focuses =
66
                     {
67
                         Focus{.id = "focus_one", .tree_starter = true},
68
                         Focus{.id = "focus_two", .tree_starter = true},
69
                     }}},
3✔
70
           Role{{.shared_focuses = {"focus_three", "focus_four"}}},
1✔
71
       },
72
       "",
73
       World({}));
2✔
74

75
   EXPECT_THAT(focus_tree.shared_focuses, testing::ElementsAre("focus_three", "focus_four"));
1✔
76
   EXPECT_THAT(focus_tree.focuses,
5✔
77
       testing::ElementsAre(Focus{.id = "focus_one", .tree_starter = true, .x_position = 20},
78
           Focus{.id = "focus_two", .tree_starter = true, .x_position = 30}));
1✔
79
}
10✔
80

81

82
TEST(Hoi4worldFocustreesFocustreeassemblerTests, FocusesHaveTagSubstitutionApplied)
4✔
83
{
84
   const FocusTree focus_tree = AssembleTree(
5✔
85
       {
86
           Role{{
87
               .focuses =
88
                   {
89
                       Focus{.id = "$TAG$_focus",
90
                           .relative_position_id = "$TAG$_focus",
91
                           .ai_will_do = "$TAG$_ai_will_do"},
92
                   },
93
           }},
2✔
94
       },
95
       "REP",
96
       World({}));
2✔
97

98
   EXPECT_TRUE(focus_tree.shared_focuses.empty());
1✔
99
   EXPECT_THAT(focus_tree.focuses,
3✔
100
       testing::ElementsAre(Focus{.id = "REP_focus",
101
           .x_position = 0,
102
           .relative_position_id = "REP_focus",
103
           .ai_will_do = "REP_ai_will_do"}));
1✔
104
}
8✔
105

106

107
TEST(Hoi4worldFocustreesFocustreeassemblerTests, RepeatFocusesAreAddedToTree)
4✔
108
{
109
   std::unique_ptr<Trigger> always_trigger_one = std::make_unique<AlwaysTrigger>(true);
1✔
110
   std::vector<std::unique_ptr<Trigger>> children_one;
1✔
111
   children_one.push_back(std::move(always_trigger_one));
1✔
112
   std::unique_ptr<Trigger> any_other_country_trigger =
113
       std::make_unique<AnyOtherCountryTrigger>(std::move(children_one));
1✔
114

115
   std::unique_ptr<Trigger> always_trigger_two = std::make_unique<AlwaysTrigger>(true);
1✔
116
   std::vector<std::unique_ptr<Trigger>> children_two;
1✔
117
   children_two.push_back(std::move(always_trigger_two));
1✔
118
   std::unique_ptr<Trigger> any_owned_state_trigger = std::make_unique<AnyOwnedStateTrigger>(std::move(children_two));
1✔
119

120
   const FocusTree focus_tree = AssembleTree(
5✔
121
       {
122
           Role{{.repeat_focuses =
123
                     {
124
                         RepeatFocus(std::move(any_other_country_trigger),
1✔
125
                             {
126
                                 Focus{.id = "$TARGET_ID$_focus_one"},
127
                                 Focus{.id = "$TARGET_ID$_focus_two"},
128
                             }),
4✔
129
                         RepeatFocus(std::move(any_owned_state_trigger),
1✔
130
                             {
131
                                 Focus{.id = "$TARGET_ID$_focus_three"},
132
                                 Focus{.id = "$TARGET_ID$_focus_four"},
133
                             }),
4✔
134
                     }}},
3✔
135
       },
136
       "THR",
137
       World({
×
138
           .countries =
139
               {
140
                   {"ONE", Country({.tag = "ONE"})},
1✔
141
                   {"TWO", Country({.tag = "TWO"})},
1✔
142
                   {"THR", Country({.tag = "THR", .owned_states = {1, 2, 3}})},
1✔
143
               },
144
           .states = {.states = {State(1, {}), State(2, {}), State(3, {})}},
×
145
       }));
10✔
146

147
   EXPECT_TRUE(focus_tree.shared_focuses.empty());
1✔
148
   EXPECT_THAT(focus_tree.focuses,
21✔
149
       testing::ElementsAre(Focus{.id = "ONE_focus_one", .x_position = -1},
150
           Focus{.id = "TWO_focus_one", .x_position = 1},
151
           Focus{.id = "ONE_focus_two", .x_position = -1},
152
           Focus{.id = "TWO_focus_two", .x_position = 1},
153
           Focus{.id = "1_focus_four", .x_position = -2},
154
           Focus{.id = "2_focus_four", .x_position = 0},
155
           Focus{.id = "3_focus_four", .x_position = 2},
156
           Focus{.id = "1_focus_three", .x_position = -2},
157
           Focus{.id = "2_focus_three", .x_position = 0},
158
           Focus{.id = "3_focus_three", .x_position = 2}));
1✔
159
}
25✔
160

161

162
TEST(Hoi4worldFocustreesFocustreeassemblerTests, NoRepeatFocusesAreAddedForInvalidTag)
4✔
163
{
164
   std::unique_ptr<Trigger> always_trigger_one = std::make_unique<AlwaysTrigger>(true);
1✔
165
   std::vector<std::unique_ptr<Trigger>> children_one;
1✔
166
   children_one.push_back(std::move(always_trigger_one));
1✔
167
   std::unique_ptr<Trigger> any_other_country_trigger =
168
       std::make_unique<AnyOtherCountryTrigger>(std::move(children_one));
1✔
169

170
   std::unique_ptr<Trigger> always_trigger_two = std::make_unique<AlwaysTrigger>(true);
1✔
171
   std::vector<std::unique_ptr<Trigger>> children_two;
1✔
172
   children_two.push_back(std::move(always_trigger_two));
1✔
173
   std::unique_ptr<Trigger> any_owned_state_trigger = std::make_unique<AnyOwnedStateTrigger>(std::move(children_two));
1✔
174

175
   const FocusTree focus_tree = AssembleTree(
5✔
176
       {
177
           Role{{.repeat_focuses =
178
                     {
179
                         RepeatFocus(std::move(any_other_country_trigger),
1✔
180
                             {
181
                                 Focus{.id = "$TARGET_ID$_focus_one"},
182
                                 Focus{.id = "$TARGET_ID$_focus_two"},
183
                             }),
4✔
184
                         RepeatFocus(std::move(any_owned_state_trigger),
1✔
185
                             {
186
                                 Focus{.id = "$TARGET_ID$_focus_three"},
187
                                 Focus{.id = "$TARGET_ID$_focus_four"},
188
                             }),
4✔
189
                     }}},
3✔
190
       },
191
       "BAD",
192
       World({
×
193
           .countries =
194
               {
195
                   {"ONE", Country({.tag = "ONE"})},
1✔
196
                   {"TWO", Country({.tag = "TWO"})},
1✔
197
                   {"THR", Country({.tag = "THR", .owned_states = {1, 2, 3}})},
1✔
198
               },
199
           .states = {.states = {State(1, {}), State(2, {}), State(3, {})}},
×
200
       }));
10✔
201

202
   EXPECT_TRUE(focus_tree.shared_focuses.empty());
1✔
203
   EXPECT_TRUE(focus_tree.focuses.empty());
1✔
204
}
25✔
205

206

207
TEST(Hoi4worldFocustreesFocustreeassemblerTests, RepeatFocusesHaveTargetTagSubstitutionApplied)
4✔
208
{
209
   std::unique_ptr<Trigger> always_trigger = std::make_unique<AlwaysTrigger>(true);
1✔
210
   std::vector<std::unique_ptr<Trigger>> children;
1✔
211
   children.push_back(std::move(always_trigger));
1✔
212
   std::unique_ptr<Trigger> any_other_country_trigger = std::make_unique<AnyOtherCountryTrigger>(std::move(children));
1✔
213

214
   const FocusTree focus_tree = AssembleTree(
5✔
215
       {
216
           Role{{
217
               .repeat_focuses =
218
                   {
219
                       RepeatFocus(std::move(any_other_country_trigger),
1✔
220
                           {
221
                               Focus{
222
                                   .id = "$TARGET_ID$_focus_one",
223
                                   .prerequisites = {"$TARGET_ID$_prerequisite"},
224
                                   .relative_position_id = "$TARGET_ID$_focus",
225
                                   .available = "$TARGET_ID$_available",
226
                                   .select_effect = "$TARGET_ID$_select_effect",
227
                                   .completion_reward = "$TARGET_ID$_completion_reward",
228
                                   .ai_will_do = "$TARGET_ID$_ai_will_do",
229
                               },
230
                           }),
3✔
231
                   },
232
           }},
2✔
233
       },
234
       "TWO",
235
       World({.countries = {{"ONE", Country({.tag = "ONE"})}, {"TWO", Country({.tag = "TWO"})}}}));
6✔
236

237
   EXPECT_TRUE(focus_tree.shared_focuses.empty());
1✔
238
   EXPECT_THAT(focus_tree.focuses,
5✔
239
       testing::ElementsAre(Focus{
240
           .id = "ONE_focus_one",
241
           .prerequisites = {"ONE_prerequisite"},
242
           .x_position = 0,
243
           .relative_position_id = "ONE_focus",
244
           .available = "ONE_available",
245
           .select_effect = "ONE_select_effect",
246
           .completion_reward = "ONE_completion_reward",
247
           .ai_will_do = "ONE_ai_will_do",
248
       }));
1✔
249
}
15✔
250

251

252
TEST(Hoi4worldFocustreesFocustreeassemblerTests, RepeatFocusesAreBalancedInPosition)
4✔
253
{
254
   std::unique_ptr<Trigger> one_trigger = std::make_unique<TagTrigger>("ONE");
1✔
255
   std::unique_ptr<Trigger> three_trigger = std::make_unique<TagTrigger>("THR");
1✔
256
   std::vector<std::unique_ptr<Trigger>> countries;
1✔
257
   countries.push_back(std::move(one_trigger));
1✔
258
   countries.push_back(std::move(three_trigger));
1✔
259
   std::unique_ptr<Trigger> or_trigger = std::make_unique<OrTrigger>(std::move(countries));
1✔
260
   std::vector<std::unique_ptr<Trigger>> or_trigger_list;
1✔
261
   or_trigger_list.push_back(std::move(or_trigger));
1✔
262
   std::unique_ptr<Trigger> any_other_country_trigger_one =
263
       std::make_unique<AnyOtherCountryTrigger>(std::move(or_trigger_list));
1✔
264

265
   std::unique_ptr<Trigger> always_trigger = std::make_unique<AlwaysTrigger>(true);
1✔
266
   std::vector<std::unique_ptr<Trigger>> always_trigger_list;
1✔
267
   always_trigger_list.push_back(std::move(always_trigger));
1✔
268
   std::unique_ptr<Trigger> any_other_country_trigger_two =
269
       std::make_unique<AnyOtherCountryTrigger>(std::move(always_trigger_list));
1✔
270

271
   const FocusTree focus_tree = AssembleTree(
5✔
272
       {
273
           Role{{
274
               .repeat_focuses =
275
                   {
276
                       RepeatFocus(std::move(any_other_country_trigger_one),
1✔
277
                           {
278
                               Focus{.id = "$TARGET_ID$_focus_one"},
279
                               Focus{.id = "$TARGET_ID$_focus_two"},
280
                           }),
4✔
281
                       RepeatFocus(std::move(any_other_country_trigger_two),
1✔
282
                           {
283
                               Focus{.id = "$TARGET_ID$_focus_three"},
284
                               Focus{.id = "$TARGET_ID$_focus_four"},
285
                           }),
4✔
286
                   },
287
           }},
3✔
288
       },
289
       "FOR",
290
       World({.countries = {
×
291
                  {"ONE", Country({.tag = "ONE"})},
1✔
292
                  {"TWO", Country({.tag = "TWO"})},
1✔
293
                  {"THR", Country({.tag = "THR"})},
1✔
294
                  {"FOR", Country({.tag = "FOR"})},
1✔
295
              }}));
7✔
296

297
   EXPECT_TRUE(focus_tree.shared_focuses.empty());
1✔
298
   EXPECT_THAT(focus_tree.focuses,
21✔
299
       testing::ElementsAre(Focus{.id = "ONE_focus_one", .x_position = -1},
300
           Focus{.id = "THR_focus_one", .x_position = 1},
301
           Focus{.id = "ONE_focus_two", .x_position = -1},
302
           Focus{.id = "THR_focus_two", .x_position = 1},
303
           Focus{.id = "ONE_focus_four", .x_position = -2},
304
           Focus{.id = "THR_focus_four", .x_position = 0},
305
           Focus{.id = "TWO_focus_four", .x_position = 2},
306
           Focus{.id = "ONE_focus_three", .x_position = -2},
307
           Focus{.id = "THR_focus_three", .x_position = 0},
308
           Focus{.id = "TWO_focus_three", .x_position = 2}));
1✔
309
}
19✔
310

311

312
TEST(Hoi4worldFocustreesFocustreeassemblerTests, PrerequisitesWithRepeatFocusesAreExpanded)
4✔
313
{
314
   std::unique_ptr<Trigger> always_trigger = std::make_unique<AlwaysTrigger>(true);
1✔
315
   std::vector<std::unique_ptr<Trigger>> always_trigger_list;
1✔
316
   always_trigger_list.push_back(std::move(always_trigger));
1✔
317
   std::unique_ptr<Trigger> any_other_country_trigger =
318
       std::make_unique<AnyOtherCountryTrigger>(std::move(always_trigger_list));
1✔
319

320
   const FocusTree focus_tree = AssembleTree(
5✔
321
       {
322
           Role{{
323
               .focuses =
324
                   {
325
                       Focus{.id = "$TAG$_focus_one", .tree_starter = true},
326
                       Focus{.id = "$TAG$_focus_three", .prerequisites = {"repeat_focus = $TARGET_ID$_focus_two"}},
327
                   },
328
               .repeat_focuses =
329
                   {
330
                       RepeatFocus(std::move(any_other_country_trigger),
1✔
331
                           {
332
                               Focus{
333
                                   .id = "$TARGET_ID$_focus_two",
334
                                   .prerequisites = {"$TAG$_focus_one"},
335
                                   .relative_position_id = "$TAG$_focus_one",
336
                               },
337
                           }),
3✔
338
                   },
339
           }},
4✔
340
       },
341
       "TAG",
342
       World({.countries = {
×
343
                  {"ONE", Country({.tag = "ONE"})},
1✔
344
                  {"TWO", Country({.tag = "TWO"})},
1✔
345
                  {"TAG", Country({.tag = "TAG"})},
1✔
346
              }}));
6✔
347

348
   EXPECT_TRUE(focus_tree.shared_focuses.empty());
1✔
349
   EXPECT_THAT(focus_tree.focuses,
12✔
350
       testing::ElementsAre(
351
           Focus{
352
               .id = "TAG_focus_one",
353
               .tree_starter = true,
354
           },
355
           Focus{
356
               .id = "TAG_focus_three",
357
               .prerequisites = {"focus = ONE_focus_two focus = TWO_focus_two"},
358
               .x_position = 1,
359
               .relative_position_id = "ONE_focus_two",
360
           },
361
           Focus{
362
               .id = "ONE_focus_two",
363
               .prerequisites = {"TAG_focus_one"},
364
               .x_position = -1,
365
               .relative_position_id = "TAG_focus_one",
366
           },
367
           Focus{
368
               .id = "TWO_focus_two",
369
               .prerequisites = {"TAG_focus_one"},
370
               .x_position = 1,
371
               .relative_position_id = "TAG_focus_one",
372
           }));
1✔
373
}
18✔
374

375

376
// The previous test implicitly covers even numbers of repeat focuses, this one does odd
377
TEST(Hoi4worldFocustreesFocustreeassemblerTests, FocusesAfterRepeatFocusesAreBalanced)
4✔
378
{
379
   std::unique_ptr<Trigger> always_trigger = std::make_unique<AlwaysTrigger>(true);
1✔
380
   std::vector<std::unique_ptr<Trigger>> always_trigger_list;
1✔
381
   always_trigger_list.push_back(std::move(always_trigger));
1✔
382
   std::unique_ptr<Trigger> any_other_country_trigger =
383
       std::make_unique<AnyOtherCountryTrigger>(std::move(always_trigger_list));
1✔
384

385
   const FocusTree focus_tree = AssembleTree(
5✔
386
       {
387
           Role{{
388
               .focuses =
389
                   {
390
                       Focus{.id = "$TAG$_focus_one", .tree_starter = true},
391
                       Focus{.id = "$TAG$_focus_three", .prerequisites = {"repeat_focus = $TARGET_ID$_focus_two"}},
392
                   },
393
               .repeat_focuses =
394
                   {
395
                       RepeatFocus(std::move(any_other_country_trigger),
1✔
396
                           {
397
                               Focus{
398
                                   .id = "$TARGET_ID$_focus_two",
399
                                   .prerequisites = {"$TAG$_focus_one"},
400
                                   .relative_position_id = "$TAG$_focus_one",
401
                               },
402
                           }),
3✔
403
                   },
404
           }},
4✔
405
       },
406
       "TAG",
407
       World({.countries = {
×
408
                  {"ONE", Country({.tag = "ONE"})},
1✔
409
                  {"TWO", Country({.tag = "TWO"})},
1✔
410
                  {"THR", Country({.tag = "THR"})},
1✔
411
                  {"TAG", Country({.tag = "TAG"})},
1✔
412
              }}));
7✔
413

414
   EXPECT_TRUE(focus_tree.shared_focuses.empty());
1✔
415
   EXPECT_THAT(focus_tree.focuses,
15✔
416
       testing::ElementsAre(
417
           Focus{
418
               .id = "TAG_focus_one",
419
               .tree_starter = true,
420
           },
421
           Focus{
422
               .id = "TAG_focus_three",
423
               .prerequisites = {"focus = ONE_focus_two focus = THR_focus_two focus = TWO_focus_two"},
424
               .x_position = 0,
425
               .relative_position_id = "THR_focus_two",
426
           },
427
           Focus{
428
               .id = "ONE_focus_two",
429
               .prerequisites = {"TAG_focus_one"},
430
               .x_position = -2,
431
               .relative_position_id = "TAG_focus_one",
432
           },
433
           Focus{
434
               .id = "THR_focus_two",
435
               .prerequisites = {"TAG_focus_one"},
436
               .x_position = 0,
437
               .relative_position_id = "TAG_focus_one",
438
           },
439
           Focus{
440
               .id = "TWO_focus_two",
441
               .prerequisites = {"TAG_focus_one"},
442
               .x_position = 2,
443
               .relative_position_id = "TAG_focus_one",
444
           }));
1✔
445
}
19✔
446

447
}  // namespace hoi4
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc