The Battle for Wesnoth 1.21.0-dev
 
Loading...
Searching...
No Matches
test_mp_connect.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2013 - 2025
3 by Andrius Silinskas <silinskas.andrius@gmail.com>
4 Part of the Battle for Wesnoth Project https://www.wesnoth.org/
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY.
12
13 See the COPYING file for more details.
14*/
15
16#define GETTEXT_DOMAIN "wesnoth-test"
17
18#include <boost/test/unit_test.hpp>
19
21#include "game_display.hpp"
24#include "mt_rng.hpp"
25#include "saved_game.hpp"
27
28/* Definitions */
29
31public:
33 ng::connect_engine(gamestate, true, nullptr)
34 {}
35};
36
37/* Global fixture */
38
70
71
72/* Test classes creation utilities */
73
75 test_connect_engine& connect_engine)
76{
77 config side_cfg = connect_engine.scenario().mandatory_child("side");
78 side_cfg.remove_attributes("faction");
79 side_cfg.clear_children("default_faction");
80 side_cfg.clear_children("leader");
81 side_cfg.append(defaults);
82
83 return { side_cfg, connect_engine, 0 };
84}
85
86
87/* Tests */
88
90
91
92BOOST_AUTO_TEST_CASE( flg_map_settings2 )
93{
94 // Set up side_engine and its dependencies.
95 state.mp_settings().use_map_settings = true;
96 state.mp_settings().saved_game = saved_game_mode::type::no;
97 test_connect_engine connect_engine{state};
98 config side;
99
100 // Recruit list with no faction.
101 side["recruit"] = "Elvish Archer";
102 ng::side_engine side_engine = create_side_engine(side, connect_engine);
103 BOOST_CHECK_EQUAL(side_engine.new_config()["recruit"], "Elvish Archer");
104}
105
106BOOST_AUTO_TEST_CASE( flg_map_settings3 )
107{
108 // Set up side_engine and its dependencies.
109 state.mp_settings().use_map_settings = true;
110 state.mp_settings().saved_game = saved_game_mode::type::no;
111 test_connect_engine connect_engine{state};
112 config side;
113
114 // Custom faction, no recruits.
115 side["faction"] = "Custom";
116 ng::side_engine side_engine = create_side_engine(side, connect_engine);
117 BOOST_CHECK_EQUAL(side_engine.flg().current_faction()["id"], "Custom");
118 BOOST_CHECK_EQUAL(side_engine.new_config()["recruit"].empty(), true);
119}
120
121BOOST_AUTO_TEST_CASE( flg_map_settings4 )
122{
123 // Set up side_engine and its dependencies.
124 state.mp_settings().use_map_settings = true;
125 state.mp_settings().saved_game = saved_game_mode::type::no;
126 test_connect_engine connect_engine{state};
127 config side;
128
129 // Random faction.
130 side["faction"] = "Random";
131 ng::side_engine side_engine = create_side_engine(side, connect_engine);
132 BOOST_CHECK_EQUAL(side_engine.flg().current_faction()["id"], "Random");
133}
134
135BOOST_AUTO_TEST_CASE( flg_map_settings5 )
136{
137 // Set up side_engine and its dependencies.
138 state.mp_settings().use_map_settings = true;
139 state.mp_settings().saved_game = saved_game_mode::type::no;
140 test_connect_engine connect_engine{state};
141 config side;
142
143 // Valid faction.
144 side["faction"] = "Rebels";
145 ng::side_engine side_engine = create_side_engine(side, connect_engine);
146 BOOST_CHECK_EQUAL(side_engine.flg().current_faction()["id"], "Rebels");
147}
148
149BOOST_AUTO_TEST_CASE( flg_map_settings6 )
150{
151 // Set up side_engine and its dependencies.
152 state.mp_settings().use_map_settings = true;
153 state.mp_settings().saved_game = saved_game_mode::type::no;
154 test_connect_engine connect_engine{state};
155 config side;
156
157 // Invalid faction.
158 side["faction"] = "ThisFactionDoesNotExist";
159 ng::side_engine side_engine = create_side_engine(side, connect_engine);
160 BOOST_CHECK(side_engine.flg().choosable_factions().size() > 1);
161 BOOST_CHECK_EQUAL(side_engine.flg().current_faction()["id"], "Random");
162}
163
164BOOST_AUTO_TEST_CASE( flg_map_settings7 )
165{
166 // Set up side_engine and its dependencies.
167 state.mp_settings().use_map_settings = true;
168 state.mp_settings().saved_game = saved_game_mode::type::no;
169 test_connect_engine connect_engine{state};
170 config side;
171
172 // Faction and recruit list.
173 side["recruit"] = "Elvish Archer";
174 side["faction"] = "Undead";
175 ng::side_engine side_engine = create_side_engine(side, connect_engine);
176}
177
178BOOST_AUTO_TEST_CASE( flg_map_settings8 )
179{
180 // Set up side_engine and its dependencies.
181 state.mp_settings().use_map_settings = true;
182 state.mp_settings().saved_game = saved_game_mode::type::no;
183 test_connect_engine connect_engine{state};
184 config side;
185
186 // Carried over recruits.
187 side["previous_recruits"] = "Elvish Archer";
188 ng::side_engine side_engine = create_side_engine(side, connect_engine);
189 BOOST_CHECK_EQUAL(side_engine.new_config()["previous_recruits"], "Elvish Archer");
190}
191
192BOOST_AUTO_TEST_CASE( flg_map_settings9 )
193{
194 // Set up side_engine and its dependencies.
195 state.mp_settings().use_map_settings = true;
196 state.mp_settings().saved_game = saved_game_mode::type::no;
197 test_connect_engine connect_engine{state};
198
199 // Valid leader unit.
200 auto side = config {
201 "leader", config {
202 "type", "Shadow",
203 },
204 };
205
206 ng::side_engine side_engine = create_side_engine(side, connect_engine);
207 BOOST_CHECK_EQUAL(side_engine.flg().choosable_leaders().size(), 1);
208 BOOST_CHECK_EQUAL(side_engine.flg().current_leader(), "Shadow");
209 BOOST_CHECK_EQUAL(side_engine.new_config().mandatory_child("leader")["type"], "Shadow");
210}
211
212BOOST_AUTO_TEST_CASE( flg_map_settings10 )
213{
214 // Set up side_engine and its dependencies.
215 state.mp_settings().use_map_settings = true;
216 state.mp_settings().saved_game = saved_game_mode::type::no;
217 test_connect_engine connect_engine{state};
218
219 // Invalid leader unit.
220 auto side = config {
221 "leader", config {
222 "type", "ThisUnitDoesNotExist",
223 },
224 };
225
226 ng::side_engine side_engine = create_side_engine(side, connect_engine);
227 BOOST_CHECK_EQUAL(side_engine.flg().choosable_leaders().size(), 1);
228 BOOST_CHECK_EQUAL(side_engine.flg().current_leader(), "null");
229}
230
231BOOST_AUTO_TEST_CASE( flg_map_settings11 )
232{
233 // Set up side_engine and its dependencies.
234 state.mp_settings().use_map_settings = true;
235 state.mp_settings().saved_game = saved_game_mode::type::no;
236 test_connect_engine connect_engine{state};
237 config side;
238
239 // No leader, Custom faction.
240 side["faction"] = "Custom";
241 ng::side_engine side_engine = create_side_engine(side, connect_engine);
242 BOOST_CHECK(side_engine.flg().choosable_leaders().size() > 1);
243 BOOST_CHECK_EQUAL(side_engine.flg().current_leader(), "random");
244}
245
246BOOST_AUTO_TEST_CASE( flg_map_settings12 )
247{
248 // Set up side_engine and its dependencies.
249 state.mp_settings().use_map_settings = true;
250 state.mp_settings().saved_game = saved_game_mode::type::no;
251 test_connect_engine connect_engine{state};
252 config side;
253
254 // No leader, Random faction.
255 side["faction"] = "Random";
256 ng::side_engine side_engine = create_side_engine(side, connect_engine);
257 BOOST_CHECK_EQUAL(side_engine.flg().choosable_leaders().size(), 1);
258 BOOST_CHECK_EQUAL(side_engine.flg().current_leader(), "null");
259}
260
261BOOST_AUTO_TEST_CASE( flg_map_settings14 )
262{
263 // Set up side_engine and its dependencies.
264 state.mp_settings().use_map_settings = true;
265 state.mp_settings().saved_game = saved_game_mode::type::no;
266 test_connect_engine connect_engine{state};
267 config side;
268
269 // No leader, regular faction.
270 side["faction"] = "Undead";
271 ng::side_engine side_engine = create_side_engine(side, connect_engine);
272 BOOST_CHECK(side_engine.flg().choosable_leaders().size() > 1);
273 BOOST_CHECK_EQUAL(side_engine.flg().current_leader(), "random");
274}
275
276BOOST_AUTO_TEST_CASE( flg_map_settings15 )
277{
278 // Set up side_engine and its dependencies.
279 state.mp_settings().use_map_settings = true;
280 state.mp_settings().saved_game = saved_game_mode::type::no;
281 test_connect_engine connect_engine{state};
282
283 // Carried over leader.
284 auto side = config {
285 "leader", config {
286 "type", "Elvish Archer",
287 "id", "LeaderID",
288 },
289 "unit", config {
290 "type", "Elvish Ranger",
291 "id", "LeaderID",
292 },
293 };
294
295 ng::side_engine side_engine = create_side_engine(side, connect_engine);
296 BOOST_CHECK_EQUAL(side_engine.flg().choosable_leaders().size(), 1);
297 BOOST_CHECK_EQUAL(side_engine.flg().current_leader(), "Elvish Ranger");
298}
299
300BOOST_AUTO_TEST_CASE( flg_map_settings17 )
301{
302 // Set up side_engine and its dependencies.
303 state.mp_settings().use_map_settings = true;
304 state.mp_settings().saved_game = saved_game_mode::type::no;
305 test_connect_engine connect_engine{state};
306
307 // Random leader.
308 auto side = config {
309 "leader", config {
310 "type", "random",
311 },
312 };
313 ng::side_engine side_engine = create_side_engine(side, connect_engine);
314 BOOST_CHECK_EQUAL(side_engine.flg().choosable_leaders().size(), 1);
315}
316
317BOOST_AUTO_TEST_CASE( flg_map_settings18 )
318{
319 // Set up side_engine and its dependencies.
320 state.mp_settings().use_map_settings = true;
321 state.mp_settings().saved_game = saved_game_mode::type::no;
322 test_connect_engine connect_engine{state};
323
324 // Leader with both genders.
325 auto side = config {
326 "leader", config {
327 "type", "Elvish Archer",
328 },
329 };
330 ng::side_engine side_engine = create_side_engine(side, connect_engine);
331 BOOST_CHECK_EQUAL(side_engine.flg().choosable_genders().size(), 3);
332 BOOST_CHECK_EQUAL(side_engine.flg().current_gender(), "random");
333}
334
335BOOST_AUTO_TEST_CASE( flg_map_settings19 )
336{
337 // Set up side_engine and its dependencies.
338 state.mp_settings().use_map_settings = true;
339 state.mp_settings().saved_game = saved_game_mode::type::no;
340 test_connect_engine connect_engine{state};
341
342 // Leader with only male gender.
343 auto side = config {
344 "leader", config {
345 "type", "Swordsman",
346 },
347 };
348 ng::side_engine side_engine = create_side_engine(side, connect_engine);
349 BOOST_CHECK_EQUAL(side_engine.flg().choosable_genders().size(), 1);
350 BOOST_CHECK_EQUAL(side_engine.flg().current_gender(), "male");
351}
352
353BOOST_AUTO_TEST_CASE( flg_map_settings20 )
354{
355 // Set up side_engine and its dependencies.
356 state.mp_settings().use_map_settings = true;
357 state.mp_settings().saved_game = saved_game_mode::type::no;
358 test_connect_engine connect_engine{state};
359
360 // Leader with only female gender.
361 auto side = config {
362 "leader", config {
363 "type", "Elvish Druid",
364 },
365 };
366 ng::side_engine side_engine = create_side_engine(side, connect_engine);
367 BOOST_CHECK_EQUAL(side_engine.flg().choosable_genders().size(), 1);
368 BOOST_CHECK_EQUAL(side_engine.flg().current_gender(), "female");
369}
370
371BOOST_AUTO_TEST_CASE( flg_map_settings21 )
372{
373 // Set up side_engine and its dependencies.
374 state.mp_settings().use_map_settings = true;
375 state.mp_settings().saved_game = saved_game_mode::type::no;
376 test_connect_engine connect_engine{state};
377
378 // Valid leader with valid gender.
379 auto side = config {
380 "leader", config {
381 "type", "White Mage",
382 "gender", "female",
383 },
384 };
385 ng::side_engine side_engine = create_side_engine(side, connect_engine);
386 BOOST_CHECK_EQUAL(side_engine.flg().current_gender(), "female");
387}
388
389BOOST_AUTO_TEST_CASE( flg_map_settings22 )
390{
391 // Set up side_engine and its dependencies.
392 state.mp_settings().use_map_settings = true;
393 state.mp_settings().saved_game = saved_game_mode::type::no;
394 test_connect_engine connect_engine{state};
395
396 // Valid leader with invalid gender.
397 auto side = config {
398 "leader", config {
399 "type", "Troll",
400 "gender", "female",
401 },
402 };
403 ng::side_engine side_engine = create_side_engine(side, connect_engine);
404 BOOST_CHECK_EQUAL(side_engine.flg().choosable_genders().size(), 1);
405 BOOST_CHECK_EQUAL(side_engine.flg().current_gender(), "male");
406}
407
408BOOST_AUTO_TEST_CASE( flg_map_settings23 )
409{
410 // Set up side_engine and its dependencies.
411 state.mp_settings().use_map_settings = true;
412 state.mp_settings().saved_game = saved_game_mode::type::no;
413 test_connect_engine connect_engine{state};
414
415 // Leader with random gender.
416 auto side = config {
417 "leader", config {
418 "type", "White Mage",
419 "gender", "random",
420 },
421 };
422 ng::side_engine side_engine = create_side_engine(side, connect_engine);
423 BOOST_CHECK_EQUAL(side_engine.flg().current_gender(), "random");
424}
425
426BOOST_AUTO_TEST_CASE( flg_map_settings25 )
427{
428 // Set up side_engine and its dependencies.
429 state.mp_settings().use_map_settings = true;
430 state.mp_settings().saved_game = saved_game_mode::type::no;
431 test_connect_engine connect_engine{state};
432 config side;
433
434 // No leader.
435 side["leader_lock"] = true;
436 ng::side_engine side_engine = create_side_engine(side, connect_engine);
437 BOOST_CHECK_EQUAL(side_engine.flg().choosable_leaders().size(), 1);
438 BOOST_CHECK_EQUAL(side_engine.flg().current_leader(), "null");
439}
440
441BOOST_AUTO_TEST_CASE( flg_map_settings26 )
442{
443 // Set up side_engine and its dependencies.
444 state.mp_settings().use_map_settings = true;
445 state.mp_settings().saved_game = saved_game_mode::type::no;
446 test_connect_engine connect_engine{state};
447 config side;
448
449 // Resolve random faction.
450 side["faction"] = "Random";
451 ng::side_engine side_engine = create_side_engine(side, connect_engine);
452 side_engine.resolve_random(rng);
453 BOOST_CHECK(side_engine.flg().current_faction()["id"] != "Random");
454 BOOST_CHECK(side_engine.flg().current_leader() != "random" && side_engine.flg().current_leader() != "null");
455 BOOST_CHECK(side_engine.flg().current_gender() != "random" && side_engine.flg().current_gender() != "null");
456}
457
458BOOST_AUTO_TEST_CASE( flg_map_settings27 )
459{
460 // Set up side_engine and its dependencies.
461 state.mp_settings().use_map_settings = true;
462 state.mp_settings().saved_game = saved_game_mode::type::no;
463 test_connect_engine connect_engine{state};
464
465 // Resolve random faction with default leader.
466 auto side = config {
467 "faction" , "Random",
468 "leader", config {
469 "type", "Troll",
470 },
471 };
472 ng::side_engine side_engine = create_side_engine(side, connect_engine);
473 side_engine.resolve_random(rng);
474 BOOST_CHECK(side_engine.flg().current_faction()["id"] != "Random");
475 BOOST_CHECK_EQUAL(side_engine.flg().current_leader(), "Troll");
476 BOOST_CHECK(side_engine.flg().current_gender() != "random" && side_engine.flg().current_gender() != "null");
477}
478
479BOOST_AUTO_TEST_CASE( flg_map_settings28 )
480{
481 // Set up side_engine and its dependencies.
482 state.mp_settings().use_map_settings = true;
483 state.mp_settings().saved_game = saved_game_mode::type::no;
484 test_connect_engine connect_engine{state};
485
486 // Resolve random faction with default leader and gender.
487 auto side = config {
488 "faction" , "Random",
489 "leader", config {
490 "type", "White Mage",
491 "gender", "male",
492 },
493 };
494 ng::side_engine side_engine = create_side_engine(side, connect_engine);
495 side_engine.resolve_random(rng);
496 BOOST_CHECK(side_engine.flg().current_faction()["id"] != "Random");
497 BOOST_CHECK_EQUAL(side_engine.flg().current_leader(), "White Mage");
498 BOOST_CHECK_EQUAL(side_engine.flg().current_gender(), "male");
499}
500
501BOOST_AUTO_TEST_CASE( flg_map_settings29 )
502{
503 // Set up side_engine and its dependencies.
504 state.mp_settings().use_map_settings = true;
505 state.mp_settings().saved_game = saved_game_mode::type::no;
506 test_connect_engine connect_engine{state};
507
508 // Resolve random leader.
509 auto side = config {
510 "leader", config {
511 "type", "random",
512 },
513 };
514 ng::side_engine side_engine = create_side_engine(side, connect_engine);
515 side_engine.resolve_random(rng);
516 BOOST_CHECK(side_engine.flg().current_leader() != "random");
517}
518
519BOOST_AUTO_TEST_CASE( flg_no_map_settings1 )
520{
521 // Set up side_engine and its dependencies.
522 state.mp_settings().use_map_settings = false;
523 state.mp_settings().saved_game = saved_game_mode::type::no;
524 test_connect_engine connect_engine{state};
525 config side;
526
527 // Recruit list with no faction.
528 side["recruit"] = "Elvish Archer";
529 ng::side_engine side_engine = create_side_engine(side, connect_engine);
530 BOOST_CHECK(side_engine.flg().choosable_factions().size() > 1);
531}
532
533BOOST_AUTO_TEST_CASE( flg_no_map_settings2 )
534{
535 // Set up side_engine and its dependencies.
536 state.mp_settings().use_map_settings = false;
537 state.mp_settings().saved_game = saved_game_mode::type::no;
538 test_connect_engine connect_engine{state};
539 config side;
540
541 // Custom faction, no recruits.
542 side["faction"] = "Custom";
543 ng::side_engine side_engine = create_side_engine(side, connect_engine);
544 BOOST_CHECK(side_engine.flg().choosable_factions().size() > 1);
545 BOOST_CHECK_EQUAL(side_engine.flg().current_faction()["id"], "Custom");
546 BOOST_CHECK_EQUAL(side_engine.new_config()["recruit"].empty(), true);
547}
548
549BOOST_AUTO_TEST_CASE( flg_no_map_settings3 )
550{
551 // Set up side_engine and its dependencies.
552 state.mp_settings().use_map_settings = false;
553 state.mp_settings().saved_game = saved_game_mode::type::no;
554 test_connect_engine connect_engine{state};
555 config side;
556
557 // Carried over recruits.
558 side["previous_recruits"] = "Elvish Archer";
559 ng::side_engine side_engine = create_side_engine(side, connect_engine);
560 BOOST_CHECK(side_engine.flg().choosable_factions().size() > 1);
561 BOOST_CHECK_EQUAL(side_engine.new_config()["previous_recruits"], "Elvish Archer");
562}
563
564BOOST_AUTO_TEST_CASE( flg_no_map_settings4 )
565{
566 // Set up side_engine and its dependencies.
567 state.mp_settings().use_map_settings = false;
568 state.mp_settings().saved_game = saved_game_mode::type::no;
569 test_connect_engine connect_engine{state};
570
571 // Explicit leader for faction with multiple leaders.
572 auto side = config {
573 "leader", config {
574 "type", "Goblin Impaler",
575 },
576 };
577 ng::side_engine side_engine = create_side_engine(side, connect_engine);
578 side_engine.flg().set_current_faction("Rebels");
579 BOOST_CHECK(side_engine.flg().choosable_leaders().size() > 1);
580}
581
582BOOST_AUTO_TEST_CASE( flg_no_map_settings5 )
583{
584 // Set up side_engine and its dependencies.
585 state.mp_settings().use_map_settings = false;
586 state.mp_settings().saved_game = saved_game_mode::type::no;
587 test_connect_engine connect_engine{state};
588
589 // Duplicate leaders.
590 auto side = config {
591 "faction" , "Custom",
592 "leader", config {
593 "type", "Swordsman",
594 },
595 };
596 ng::side_engine side_engine = create_side_engine(side, connect_engine);
597 BOOST_CHECK(side_engine.flg().choosable_leaders().size() > 1);
598 const std::vector<std::string>& leaders = side_engine.flg().choosable_leaders();
599 BOOST_CHECK_EQUAL(std::count(leaders.begin(), leaders.end(), "Swordsman"), 1);
600}
601
602BOOST_AUTO_TEST_CASE( flg_no_map_settings6 )
603{
604 // Set up side_engine and its dependencies.
605 state.mp_settings().use_map_settings = false;
606 state.mp_settings().saved_game = saved_game_mode::type::no;
607 test_connect_engine connect_engine{state};
608
609 // Explicit gender for unit with both genders available.
610 auto side = config {
611 "leader", config {
612 "gender", "female",
613 },
614 };
615 ng::side_engine side_engine = create_side_engine(side, connect_engine);
616 side_engine.flg().set_current_faction("Rebels");
617 side_engine.flg().set_current_leader("Elvish Ranger");
618 // TODO: this this really make sense? it would be nice to know the usecases for this.
619 //BOOST_CHECK_EQUAL( side_engine.flg().current_gender(), "random" );
620}
621
622BOOST_AUTO_TEST_SUITE_END()
A config object defines a single node in a WML file, with access to child nodes.
Definition config.hpp:157
void append(const config &cfg)
Append data from another config object to this one.
Definition config.cpp:188
void remove_attributes(T... keys)
Definition config.hpp:536
void clear_children(T... keys)
Definition config.hpp:601
bool empty() const
Definition config.cpp:823
config & mandatory_child(std::string_view key, int n=0)
Returns the nth child with the given key, or throws an error if there is none.
Definition config.cpp:362
campaign_type::type type
@ NO_FORCE_RELOAD
Don't reload if the previous defines equal the new defines.
bool init_game_config(FORCE_RELOAD_CONFIG force_reload)
void load_game_config_for_game(const game_classification &classification, const std::string &scenario_id)
const game_config_view & game_config() const
const config & find_mandatory_child(std::string_view key, const std::string &name, const std::string &value) const
this class is initialized once at game start put all initialization and wipe code in the methods here...
connect_engine(saved_game &state, const bool first_scenario, mp_game_metadata *metadata)
const std::vector< const config * > & choosable_factions() const
const std::vector< std::string > & choosable_leaders() const
void set_current_faction(const unsigned index)
const std::string & current_gender() const
const std::string & current_leader() const
const config & current_faction() const
void set_current_leader(const unsigned index)
const std::vector< std::string > & choosable_genders() const
void resolve_random(randomness::mt_rng &rng, const std::vector< std::string > &avoid_faction_ids=std::vector< std::string >())
flg_manager & flg()
config new_config() const
std::string get_scenario_id() const
game_classification & classification()
void set_scenario(config scenario)
config & get_starting_point()
mp_game_settings & mp_settings()
Multiplayer parameters for this game.
test_connect_engine(saved_game &gamestate)
void set_test_resolution(const int width, const int height)
Sets the dummy display resolution for use by the tests.
randomness::mt_rng rng
std::vector< std::string > dummy_args
hotkey::manager hotkey_manager
commandline_options cmdline_opts
game_config_manager config_manager
saved_game_mode::type saved_game
BOOST_FIXTURE_TEST_SUITE(test_map_location, MLFixture)
static ng::side_engine create_side_engine(const config &defaults, test_connect_engine &connect_engine)
BOOST_AUTO_TEST_CASE(flg_map_settings2)