The Battle for Wesnoth  1.17.5+dev
test_mp_connect.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2013 - 2022
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 
20 #include "game_config_manager.hpp"
21 #include "game_display.hpp"
24 #include "mt_rng.hpp"
25 #include "saved_game.hpp"
27 
28 /* Definitions */
29 
31 public:
33  ng::connect_engine(gamestate, true, nullptr)
34  {}
35 };
36 
37 /* Variables */
38 
39 namespace {
40 
41 std::unique_ptr<saved_game> state;
42 std::unique_ptr<randomness::mt_rng> rng;
43 
44 }
45 
46 /* Global fixture */
47 
50  dummy_args({"wesnoth", "--noaddons"}),
51  cmdline_opts(dummy_args),
52  hotkey_manager(),
53  config_manager()
54  {
55  config_manager.reset(new game_config_manager(cmdline_opts));
56  config_manager->init_game_config(game_config_manager::NO_FORCE_RELOAD);
57 
58  state.reset(new saved_game());
59  state->classification().type = campaign_type::type::multiplayer;
60  state->classification().era_id = "era_default";
61  config_manager->load_game_config_for_game(state->classification(), state->get_scenario_id());
62 
63  state->mp_settings().name = "multiplayer_The_Freelands";
64  state->mp_settings().use_map_settings = true;
65  state->mp_settings().saved_game = saved_game_mode::type::no;
66 
67  state->set_scenario(config_manager->
68  game_config().find_child("multiplayer", "id", state->mp_settings().name));
69 
70  state->mp_settings().num_turns = state->get_starting_point()["turns"];
71 
72  rng.reset(new randomness::mt_rng());
73  }
75  {
76  }
77  std::vector<std::string> dummy_args;
80  std::unique_ptr<game_config_manager> config_manager;
81 };
82 
83 
84 /* Test classes creation utilities */
85 
87 {
89  new test_connect_engine(*state);
90 
91  return connect_engine;
92 }
93 
94 static ng::side_engine* create_side_engine(const config& defaults,
96 {
97  config side_cfg = connect_engine->current_config()->child("side");
98  side_cfg.remove_attributes("faction");
99  side_cfg.clear_children("default_faction");
100  side_cfg.append(defaults);
101 
102  return new ng::side_engine(side_cfg, *connect_engine, 0);
103 }
104 
105 
106 /* Tests */
107 
109 BOOST_AUTO_TEST_SUITE( mp_connect )
110 
111 
112 BOOST_AUTO_TEST_CASE( flg_map_settings )
113 {
114  // Set up side_engine and its dependencies.
115  state->mp_settings().use_map_settings = true;
116  state->mp_settings().saved_game = saved_game_mode::type::no;
117  std::unique_ptr<test_connect_engine>
120  config side;
121 
122  // Recruit list with no faction.
123  side.clear();
124  side["recruit"] = "Elvish Archer";
125  side_engine.reset(create_side_engine(side, connect_engine.get()));
126  //BOOST_CHECK_EQUAL( side_engine->flg().choosable_factions().size(), 1 );
127  //BOOST_CHECK_EQUAL( side_engine->flg().current_faction()["id"], "Custom" );
128  BOOST_CHECK_EQUAL( side_engine->new_config()["recruit"], "Elvish Archer" );
129 
130  // Custom faction, no recruits.
131  side.clear();
132  side["faction"] = "Custom";
133  side_engine.reset(create_side_engine(side, connect_engine.get()));
134  //BOOST_CHECK_EQUAL( side_engine->flg().choosable_factions().size(), 1 );
135  BOOST_CHECK_EQUAL( side_engine->flg().current_faction()["id"], "Custom" );
136  BOOST_CHECK_EQUAL( side_engine->new_config()["recruit"].empty(), true );
137 
138  // Random faction.
139  side.clear();
140  side["faction"] = "Random";
141  side_engine.reset(create_side_engine(side, connect_engine.get()));
142  //BOOST_CHECK_EQUAL( side_engine->flg().choosable_factions().size(), 1 );
143  BOOST_CHECK_EQUAL( side_engine->flg().current_faction()["id"], "Random" );
144 
145  // Valid faction.
146  side.clear();
147  side["faction"] = "Rebels";
148  side_engine.reset(create_side_engine(side, connect_engine.get()));
149  //BOOST_CHECK_EQUAL( side_engine->flg().choosable_factions().size(), 1 );
150  BOOST_CHECK_EQUAL( side_engine->flg().current_faction()["id"], "Rebels" );
151 
152  // Invalid faction.
153  side.clear();
154  side["faction"] = "ThisFactionDoesNotExist";
155  side_engine.reset(create_side_engine(side, connect_engine.get()));
156  BOOST_CHECK( side_engine->flg().choosable_factions().size() > 1 );
157  BOOST_CHECK_EQUAL( side_engine->flg().current_faction()["id"], "Random" );
158 
159  // Faction and recruit list.
160  side.clear();
161  side["recruit"] = "Elvish Archer";
162  side["faction"] = "Undead";
163  side_engine.reset(create_side_engine(side, connect_engine.get()));
164  //BOOST_CHECK_EQUAL( side_engine->flg().choosable_factions().size(), 1 );
165  //BOOST_CHECK_EQUAL( side_engine->flg().current_faction()["id"], "Custom" );
166  //BOOST_CHECK_EQUAL( side_engine->new_config()["recruit"], "Elvish Archer" );
167 
168  // Carried over recruits.
169  side.clear();
170  side["previous_recruits"] = "Elvish Archer";
171  side_engine.reset(create_side_engine(side, connect_engine.get()));
172  //BOOST_CHECK_EQUAL( side_engine->flg().choosable_factions().size(), 1 );
173  BOOST_CHECK_EQUAL( side_engine->new_config()["previous_recruits"],
174  "Elvish Archer" );
175 
176  // Valid leader unit.
177  side.clear();
178  side["type"] = "Shadow";
179  side_engine.reset(create_side_engine(side, connect_engine.get()));
180  BOOST_CHECK_EQUAL( side_engine->flg().choosable_leaders().size(), 1 );
181  BOOST_CHECK_EQUAL( side_engine->flg().current_leader(), "Shadow" );
182  BOOST_CHECK_EQUAL( side_engine->new_config()["type"], "Shadow" );
183 
184  // Invalid leader unit.
185  side.clear();
186  side["type"] = "ThisUnitDoesNotExist";
187  side_engine.reset(create_side_engine(side, connect_engine.get()));
188  BOOST_CHECK_EQUAL( side_engine->flg().choosable_leaders().size(), 1 );
189  BOOST_CHECK_EQUAL( side_engine->flg().current_leader(), "null" );
190 
191  // No leader, Custom faction.
192  side.clear();
193  side["faction"] = "Custom";
194  side_engine.reset(create_side_engine(side, connect_engine.get()));
195  BOOST_CHECK( side_engine->flg().choosable_leaders().size() > 1 );
196  BOOST_CHECK_EQUAL( side_engine->flg().current_leader(), "random" );
197 
198  // No leader, Random faction.
199  side.clear();
200  side["faction"] = "Random";
201  side_engine.reset(create_side_engine(side, connect_engine.get()));
202  BOOST_CHECK_EQUAL( side_engine->flg().choosable_leaders().size(), 1 );
203  BOOST_CHECK_EQUAL( side_engine->flg().current_leader(), "null" );
204 
205  // No leader, regular faction.
206  side.clear();
207  side["faction"] = "Undead";
208  side_engine.reset(create_side_engine(side, connect_engine.get()));
209  BOOST_CHECK( side_engine->flg().choosable_leaders().size() > 1 );
210  BOOST_CHECK_EQUAL( side_engine->flg().current_leader(), "random" );
211 
212  // Carried over leader.
213  side.clear();
214  side["id"] = "LeaderID";
215  side["type"] = "Elvish Archer";
216  config& unit = side.add_child("unit");
217  unit["id"] = "LeaderID";
218  unit["type"] = "Elvish Ranger";
219  side_engine.reset(create_side_engine(side, connect_engine.get()));
220  BOOST_CHECK_EQUAL( side_engine->flg().choosable_leaders().size(), 1 );
221  BOOST_CHECK_EQUAL( side_engine->flg().current_leader(), "Elvish Ranger" );
222 
223  // Random leader.
224  side.clear();
225  side["type"] = "random";
226  side_engine.reset(create_side_engine(side, connect_engine.get()));
227  BOOST_CHECK_EQUAL( side_engine->flg().choosable_leaders().size(), 1 );
228 
229  // Leader with both genders.
230  side.clear();
231  side["type"] = "Elvish Archer";
232  side_engine.reset(create_side_engine(side, connect_engine.get()));
233  BOOST_CHECK_EQUAL( side_engine->flg().choosable_genders().size(), 3 );
234  BOOST_CHECK_EQUAL( side_engine->flg().current_gender(), "random" );
235 
236  // Leader with only male gender.
237  side.clear();
238  side["type"] = "Swordsman";
239  side_engine.reset(create_side_engine(side, connect_engine.get()));
240  BOOST_CHECK_EQUAL( side_engine->flg().choosable_genders().size(), 1 );
241  BOOST_CHECK_EQUAL( side_engine->flg().current_gender(), "male" );
242 
243  // Leader with only female gender.
244  side.clear();
245  side["type"] = "Elvish Druid";
246  side_engine.reset(create_side_engine(side, connect_engine.get()));
247  BOOST_CHECK_EQUAL( side_engine->flg().choosable_genders().size(), 1 );
248  BOOST_CHECK_EQUAL( side_engine->flg().current_gender(), "female" );
249 
250  // Valid leader with valid gender.
251  side.clear();
252  side["type"] = "White Mage";
253  side["gender"] = "female";
254  side_engine.reset(create_side_engine(side, connect_engine.get()));
255  //BOOST_CHECK_EQUAL( side_engine->flg().choosable_genders().size(), 1 );
256  BOOST_CHECK_EQUAL( side_engine->flg().current_gender(), "female" );
257 
258  // Valid leader with invalid gender.
259  side.clear();
260  side["type"] = "Troll";
261  side["gender"] = "female";
262  side_engine.reset(create_side_engine(side, connect_engine.get()));
263  BOOST_CHECK_EQUAL( side_engine->flg().choosable_genders().size(), 1 );
264  BOOST_CHECK_EQUAL( side_engine->flg().current_gender(), "male" );
265 
266  // Leader with random gender.
267  side.clear();
268  side["type"] = "White Mage";
269  side["gender"] = "random";
270  side_engine.reset(create_side_engine(side, connect_engine.get()));
271  //BOOST_CHECK_EQUAL( side_engine->flg().choosable_genders().size(), 1 );
272  BOOST_CHECK_EQUAL( side_engine->flg().current_gender(), "random" );
273 
274  // No leader.
275  side.clear();
276  side["leader_lock"] = true;
277  side_engine.reset(create_side_engine(side, connect_engine.get()));
278  BOOST_CHECK_EQUAL( side_engine->flg().choosable_leaders().size(), 1 );
279  BOOST_CHECK_EQUAL( side_engine->flg().current_leader(), "null" );
280 
281  // Resolve random faction.
282  side.clear();
283  side["faction"] = "Random";
284  side_engine.reset(create_side_engine(side, connect_engine.get()));
285  side_engine->resolve_random(*rng);
286  BOOST_CHECK( side_engine->flg().current_faction()["id"] != "Random" );
287  BOOST_CHECK( side_engine->flg().current_leader() != "random" &&
288  side_engine->flg().current_leader() != "null");
289  BOOST_CHECK( side_engine->flg().current_gender() != "random" &&
290  side_engine->flg().current_gender() != "null");
291 
292  // Resolve random faction with default leader.
293  side.clear();
294  side["faction"] = "Random";
295  side["type"] = "Troll";
296  side_engine.reset(create_side_engine(side, connect_engine.get()));
297  side_engine->resolve_random(*rng);
298  BOOST_CHECK( side_engine->flg().current_faction()["id"] != "Random" );
299  BOOST_CHECK_EQUAL( side_engine->flg().current_leader(), "Troll" );
300  BOOST_CHECK( side_engine->flg().current_gender() != "random" &&
301  side_engine->flg().current_gender() != "null" );
302 
303  // Resolve random faction with default leader and gender.
304  side.clear();
305  side["faction"] = "Random";
306  side["type"] = "White Mage";
307  side["gender"] = "male";
308  side_engine.reset(create_side_engine(side, connect_engine.get()));
309  side_engine->resolve_random(*rng);
310  BOOST_CHECK( side_engine->flg().current_faction()["id"] != "Random" );
311  BOOST_CHECK_EQUAL( side_engine->flg().current_leader(), "White Mage" );
312  BOOST_CHECK_EQUAL( side_engine->flg().current_gender(), "male" );
313 
314  // Resolve random leader.
315  side.clear();
316  side["type"] = "random";
317  side_engine.reset(create_side_engine(side, connect_engine.get()));
318  side_engine->resolve_random(*rng);
319  BOOST_CHECK( side_engine->flg().current_leader() != "random" );
320 }
321 
322 BOOST_AUTO_TEST_CASE( flg_no_map_settings )
323 {
324  // Set up side_engine and its dependencies.
325  state->mp_settings().use_map_settings = false;
326  state->mp_settings().saved_game = saved_game_mode::type::no;
327  const std::unique_ptr<test_connect_engine>
330  config side;
331 
332  // Recruit list with no faction.
333  side.clear();
334  side["recruit"] = "Elvish Archer";
335  side_engine.reset(create_side_engine(side, connect_engine.get()));
336  BOOST_CHECK( side_engine->flg().choosable_factions().size() > 1 );
337  //BOOST_CHECK_EQUAL( side_engine->flg().current_faction()["id"], "Custom" );
338 
339  // Custom faction, no recruits.
340  side.clear();
341  side["faction"] = "Custom";
342  side_engine.reset(create_side_engine(side, connect_engine.get()));
343  BOOST_CHECK( side_engine->flg().choosable_factions().size() > 1 );
344  BOOST_CHECK_EQUAL( side_engine->flg().current_faction()["id"], "Custom" );
345  BOOST_CHECK_EQUAL( side_engine->new_config()["recruit"].empty(), true );
346 
347  // Carried over recruits.
348  side.clear();
349  side["previous_recruits"] = "Elvish Archer";
350  side_engine.reset(create_side_engine(side, connect_engine.get()));
351  BOOST_CHECK( side_engine->flg().choosable_factions().size() > 1 );
352  BOOST_CHECK_EQUAL( side_engine->new_config()["previous_recruits"],
353  "Elvish Archer" );
354 
355  // Explicit leader for faction with multiple leaders.
356  side.clear();
357  side["type"] = "Goblin Impaler";
358  side_engine.reset(create_side_engine(side, connect_engine.get()));
359  side_engine->flg().set_current_faction("Rebels");
360  BOOST_CHECK( side_engine->flg().choosable_leaders().size() > 1 );
361 
362  // Duplicate leaders.
363  side.clear();
364  side["faction"] = "Custom";
365  side["type"] = "Swordsman";
366  side_engine.reset(create_side_engine(side, connect_engine.get()));
367  BOOST_CHECK( side_engine->flg().choosable_leaders().size() > 1 );
368  const std::vector<std::string>& leaders =
369  side_engine->flg().choosable_leaders();
370  BOOST_CHECK_EQUAL( std::count(leaders.begin(), leaders.end(), "Swordsman"),
371  1 );
372 
373  // Explicit gender for unit with both genders available.
374  side.clear();
375  side["gender"] = "female";
376  side_engine.reset(create_side_engine(side, connect_engine.get()));
377  side_engine->flg().set_current_faction("Rebels");
378  side_engine->flg().set_current_leader("Elvish Ranger");
379  BOOST_CHECK_EQUAL( side_engine->flg().current_gender(), "random" );
380 }
381 
382 BOOST_AUTO_TEST_CASE( flg_saved_game )
383 {
384  // TODO
385 }
386 
387 BOOST_AUTO_TEST_SUITE_END()
config & child(config_key_type key, int n=0)
Returns the nth child with the given key, or a reference to an invalid config if there is none...
Definition: config.cpp:402
void clear_children(T... keys)
Definition: config.hpp:556
This class represents a single unit of a specific type.
Definition: unit.hpp:120
void append(const config &cfg)
Append data from another config object to this one.
Definition: config.cpp:269
this class is initialized once at game start put all initialization and wipe code in the methods here...
void remove_attributes(T... keys)
Definition: config.hpp:521
BOOST_GLOBAL_FIXTURE(mp_connect_fixture)
Don&#39;t reload if the previous defines equal the new defines.
void clear()
Definition: config.cpp:920
static ng::side_engine * create_side_engine(const config &defaults, test_connect_engine *connect_engine)
BOOST_AUTO_TEST_CASE(flg_map_settings)
BOOST_AUTO_TEST_SUITE(filesystem)
Game configuration data as global variables.
Definition: build_info.cpp:60
std::unique_ptr< game_config_manager > config_manager
static test_connect_engine * create_test_connect_engine()
std::vector< std::string > dummy_args
std::shared_ptr< side_engine > side_engine_ptr
config & add_child(config_key_type key)
Definition: config.cpp:514
commandline_options cmdline_opts
hotkey::manager hotkey_manager
connect_engine(saved_game &state, const bool first_scenario, mp_game_metadata *metadata)
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:60
friend class side_engine
test_connect_engine(saved_game &gamestate)