The Battle for Wesnoth  1.15.1+dev
test_mp_connect.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2013 - 2018 by Andrius Silinskas <silinskas.andrius@gmail.com>
3  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13 */
14 
15 #define GETTEXT_DOMAIN "wesnoth-test"
16 
17 #include <boost/test/unit_test.hpp>
18 
19 #include "game_config_manager.hpp"
20 #include "game_display.hpp"
23 #include "mt_rng.hpp"
24 #include "saved_game.hpp"
26 
27 #include <boost/assign.hpp>
28 
29 /* Definitions */
30 
32 public:
34  ng::connect_engine(gamestate, true, nullptr)
35  {}
36 };
37 
38 /* Variables */
39 
40 namespace {
41 
42 std::unique_ptr<saved_game> state;
43 std::unique_ptr<randomness::mt_rng> rng;
44 
45 }
46 
47 /* Global fixture */
48 
51  dummy_args({"wesnoth", "--noaddons"}),
52  cmdline_opts(dummy_args),
53  hotkey_manager(),
54  config_manager()
55  {
56 
57  config_manager.reset(new game_config_manager(cmdline_opts, false));
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  config_manager->load_game_config_for_game(state->classification());
63 
64  state->mp_settings().mp_era = "era_default";
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:420
void clear_children(T... keys)
Definition: config.hpp:509
This class represents a single unit of a specific type.
Definition: unit.hpp:99
void append(const config &cfg)
Append data from another config object to this one.
Definition: config.cpp:287
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:487
BOOST_GLOBAL_FIXTURE(mp_connect_fixture)
Don&#39;t reload if the previous defines equal the new defines.
void clear()
Definition: config.cpp:863
static ng::side_engine * create_side_engine(const config &defaults, test_connect_engine *connect_engine)
BOOST_AUTO_TEST_CASE(flg_map_settings)
Default, unset return value.
Definition: retval.hpp:31
Game configuration data as global variables.
Definition: build_info.cpp:49
connect_engine(saved_game &state, const bool first_scenario, mp_campaign_info *campaign_info)
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:476
commandline_options cmdline_opts
hotkey::manager hotkey_manager
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:92
friend class side_engine
test_connect_engine(saved_game &gamestate)