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