| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427 | 
							- /*
 
-  * CGameStateTest.cpp, part of VCMI engine
 
-  *
 
-  * Authors: listed in file AUTHORS in main folder
 
-  *
 
-  * License: GNU General Public License v2.0 or later
 
-  * Full text of license available in license.txt file, in main folder
 
-  *
 
-  */
 
- #include "StdInc.h"
 
- #include "mock/mock_Services.h"
 
- #include "mock/mock_MapService.h"
 
- #include "mock/mock_IGameCallback.h"
 
- #include "mock/mock_spells_Problem.h"
 
- #include "../../lib/VCMIDirs.h"
 
- #include "../../lib/gameState/CGameState.h"
 
- #include "../../lib/networkPacks/PacksForClient.h"
 
- #include "../../lib/networkPacks/PacksForClientBattle.h"
 
- #include "../../lib/networkPacks/SetStackEffect.h"
 
- #include "../../lib/StartInfo.h"
 
- #include "../../lib/TerrainHandler.h"
 
- #include "../../lib/battle/BattleInfo.h"
 
- #include "../../lib/CStack.h"
 
- #include "../../lib/filesystem/ResourcePath.h"
 
- #include "../../lib/mapping/CMap.h"
 
- #include "../../lib/spells/CSpellHandler.h"
 
- #include "../../lib/spells/ISpellMechanics.h"
 
- #include "../../lib/spells/AbilityCaster.h"
 
- class CGameStateTest : public ::testing::Test, public SpellCastEnvironment, public MapListener
 
- {
 
- public:
 
- 	CGameStateTest()
 
- 		: gameCallback(new GameCallbackMock(this)),
 
- 		mapService("test/MiniTest/", this),
 
- 		map(nullptr)
 
- 	{
 
- 	}
 
- 	void SetUp() override
 
- 	{
 
- 		IObjectInterface::cb = gameCallback.get();
 
- 		gameState = std::make_shared<CGameState>();
 
- 		gameCallback->setGameState(gameState.get());
 
- 		gameState->preInit(&services);
 
- 	}
 
- 	void TearDown() override
 
- 	{
 
- 		gameState.reset();
 
- 		IObjectInterface::cb = nullptr;
 
- 	}
 
- 	bool describeChanges() const override
 
- 	{
 
- 		return true;
 
- 	}
 
- 	void apply(CPackForClient * pack) override
 
- 	{
 
- 		gameState->apply(pack);
 
- 	}
 
- 	void apply(BattleLogMessage * pack) override
 
- 	{
 
- 		gameState->apply(pack);
 
- 	}
 
- 	void apply(BattleStackMoved * pack) override
 
- 	{
 
- 		gameState->apply(pack);
 
- 	}
 
- 	void apply(BattleUnitsChanged * pack) override
 
- 	{
 
- 		gameState->apply(pack);
 
- 	}
 
- 	void apply(SetStackEffect * pack) override
 
- 	{
 
- 		gameState->apply(pack);
 
- 	}
 
- 	void apply(StacksInjured * pack) override
 
- 	{
 
- 		gameState->apply(pack);
 
- 	}
 
- 	void apply(BattleObstaclesChanged * pack) override
 
- 	{
 
- 		gameState->apply(pack);
 
- 	}
 
- 	void apply(CatapultAttack * pack) override
 
- 	{
 
- 		gameState->apply(pack);
 
- 	}
 
- 	void complain(const std::string & problem) override
 
- 	{
 
- 		FAIL() << "Server-side assertion: " << problem;
 
- 	};
 
- 	vstd::RNG * getRNG() override
 
- 	{
 
- 		return &gameState->getRandomGenerator();//todo: mock this
 
- 	}
 
- 	const CMap * getMap() const override
 
- 	{
 
- 		return map;
 
- 	}
 
- 	const CGameInfoCallback * getCb() const override
 
- 	{
 
- 		return gameState.get();
 
- 	}
 
- 	bool moveHero(ObjectInstanceID hid, int3 dst, bool teleporting) override
 
- 	{
 
- 		return false;
 
- 	}
 
- 	void genericQuery(Query * request, PlayerColor color, std::function<void(std::optional<int32_t>)> callback) override
 
- 	{
 
- 		//todo:
 
- 	}
 
- 	void mapLoaded(CMap * map) override
 
- 	{
 
- 		EXPECT_EQ(this->map, nullptr);
 
- 		this->map = map;
 
- 	}
 
- 	void startTestGame()
 
- 	{
 
- 		StartInfo si;
 
- 		si.mapname = "anything";//does not matter, map service mocked
 
- 		si.difficulty = 0;
 
- 		si.mapfileChecksum = 0;
 
- 		si.mode = StartInfo::NEW_GAME;
 
- 		si.seedToBeUsed = 42;
 
- 		std::unique_ptr<CMapHeader> header = mapService.loadMapHeader(ResourcePath(si.mapname));
 
- 		ASSERT_NE(header.get(), nullptr);
 
- 		//FIXME: this has been copied from CPreGame, but should be part of StartInfo
 
- 		for(int i = 0; i < header->players.size(); i++)
 
- 		{
 
- 			const PlayerInfo & pinfo = header->players[i];
 
- 			//neither computer nor human can play - no player
 
- 			if (!(pinfo.canHumanPlay || pinfo.canComputerPlay))
 
- 				continue;
 
- 			PlayerSettings & pset = si.playerInfos[PlayerColor(i)];
 
- 			pset.color = PlayerColor(i);
 
- 			pset.connectedPlayerIDs.insert(i);
 
- 			pset.name = "Player";
 
- 			pset.castle = pinfo.defaultCastle();
 
- 			pset.hero = pinfo.defaultHero();
 
- 			if(pset.hero != HeroTypeID::RANDOM && pinfo.hasCustomMainHero())
 
- 			{
 
- 				pset.hero = pinfo.mainCustomHeroId;
 
- 				pset.heroNameTextId = pinfo.mainCustomHeroNameTextId;
 
- 				pset.heroPortrait = HeroTypeID(pinfo.mainCustomHeroPortrait);
 
- 			}
 
- 			pset.handicap = PlayerSettings::NO_HANDICAP;
 
- 		}
 
- 		Load::ProgressAccumulator progressTracker;
 
- 		gameState->init(&mapService, &si, progressTracker, false);
 
- 		ASSERT_NE(map, nullptr);
 
- 		ASSERT_EQ(map->heroesOnMap.size(), 2);
 
- 	}
 
- 	void startTestBattle(const CGHeroInstance * attacker, const CGHeroInstance * defender)
 
- 	{
 
- 		const CGHeroInstance * heroes[2] = {attacker, defender};
 
- 		const CArmedInstance * armedInstancies[2] = {attacker, defender};
 
- 		int3 tile(4,4,0);
 
- 		const auto & t = *gameCallback->getTile(tile);
 
- 		auto terrain = t.terType->getId();
 
- 		BattleField terType(0);
 
- 		//send info about battles
 
- 		BattleInfo * battle = BattleInfo::setupBattle(tile, terrain, terType, armedInstancies, heroes, false, nullptr);
 
- 		BattleStart bs;
 
- 		bs.info = battle;
 
- 		ASSERT_EQ(gameState->currentBattles.size(), 0);
 
- 		gameCallback->sendAndApply(&bs);
 
- 		ASSERT_EQ(gameState->currentBattles.size(), 1);
 
- 	}
 
- 	std::shared_ptr<CGameState> gameState;
 
- 	std::shared_ptr<GameCallbackMock> gameCallback;
 
- 	MapServiceMock mapService;
 
- 	ServicesMock services;
 
- 	CMap * map;
 
- };
 
- //Issue #2765, Ghost Dragons can cast Age on Catapults
 
- TEST_F(CGameStateTest, DISABLED_issue2765)
 
- {
 
- 	startTestGame();
 
- 	CGHeroInstance * attacker = map->heroesOnMap[0];
 
- 	CGHeroInstance * defender = map->heroesOnMap[1];
 
- 	ASSERT_NE(attacker->tempOwner, defender->tempOwner);
 
- 	{
 
- 		CArtifactInstance * a = new CArtifactInstance();
 
- 		a->artType = const_cast<CArtifact *>(ArtifactID(ArtifactID::BALLISTA).toArtifact());
 
- 		NewArtifact na;
 
- 		na.art = a;
 
- 		gameCallback->sendAndApply(&na);
 
- 		PutArtifact pack;
 
- 		pack.al = ArtifactLocation(defender->id, ArtifactPosition::MACH1);
 
- 		pack.art = a;
 
- 		gameCallback->sendAndApply(&pack);
 
- 	}
 
- 	startTestBattle(attacker, defender);
 
- 	{
 
- 		battle::UnitInfo info;
 
- 		info.id = gameState->currentBattles.front()->battleNextUnitId();
 
- 		info.count = 1;
 
- 		info.type = CreatureID(69);
 
- 		info.side = BattleSide::ATTACKER;
 
- 		info.position = gameState->currentBattles.front()->getAvaliableHex(info.type, info.side);
 
- 		info.summoned = false;
 
- 		BattleUnitsChanged pack;
 
- 		pack.changedStacks.emplace_back(info.id, UnitChanges::EOperation::ADD);
 
- 		info.save(pack.changedStacks.back().data);
 
- 		gameCallback->sendAndApply(&pack);
 
- 	}
 
- 	const CStack * att = nullptr;
 
- 	const CStack * def = nullptr;
 
- 	for(const CStack * s : gameState->currentBattles.front()->stacks)
 
- 	{
 
- 		if(s->unitType()->getId() == CreatureID::BALLISTA && s->unitSide() == BattleSide::DEFENDER)
 
- 			def = s;
 
- 		else if(s->unitType()->getId() == CreatureID(69) && s->unitSide() == BattleSide::ATTACKER)
 
- 			att = s;
 
- 	}
 
- 	ASSERT_NE(att, nullptr);
 
- 	ASSERT_NE(def, nullptr);
 
- 	ASSERT_NE(att, def);
 
- 	EXPECT_NE(att->getMyHero(), defender);
 
- 	EXPECT_NE(def->getMyHero(), attacker);
 
- 	EXPECT_EQ(att->getMyHero(), attacker) << att->nodeName();
 
- 	EXPECT_EQ(def->getMyHero(), defender) << def->nodeName();
 
- 	{
 
- 		using namespace ::testing;
 
- 		spells::ProblemMock problemMock;
 
- //		EXPECT_CALL(problemMock, add(_));
 
- 		const CSpell * age = SpellID(SpellID::AGE).toSpell();
 
- 		ASSERT_NE(age, nullptr);
 
- 		spells::AbilityCaster caster(att, 3);
 
- 		//here tested ballista, but this applied to all war machines
 
- 		spells::BattleCast cast(gameState->currentBattles.front().get(), &caster, spells::Mode::PASSIVE, age);
 
- 		spells::Target target;
 
- 		target.emplace_back(def);
 
- 		auto m = age->battleMechanics(&cast);
 
- 		EXPECT_FALSE(m->canBeCastAt(target, problemMock));
 
- 		EXPECT_TRUE(cast.castIfPossible(this, target));//should be possible, but with no effect (change to aimed cast check?)
 
- 		EXPECT_TRUE(def->activeSpells().empty());
 
- 	}
 
- }
 
- TEST_F(CGameStateTest, DISABLED_battleResurrection)
 
- {
 
- 	startTestGame();
 
- 	CGHeroInstance * attacker = map->heroesOnMap[0];
 
- 	CGHeroInstance * defender = map->heroesOnMap[1];
 
- 	ASSERT_NE(attacker->tempOwner, defender->tempOwner);
 
- 	attacker->setSecSkillLevel(SecondarySkill::EARTH_MAGIC, 3, true);
 
- 	attacker->addSpellToSpellbook(SpellID::RESURRECTION);
 
- 	attacker->setPrimarySkill(PrimarySkill::SPELL_POWER, 100, true);
 
- 	attacker->setPrimarySkill(PrimarySkill::KNOWLEDGE, 20, true);
 
- 	attacker->mana = attacker->manaLimit();
 
- 	{
 
- 		CArtifactInstance * a = new CArtifactInstance();
 
- 		a->artType = const_cast<CArtifact *>(ArtifactID(ArtifactID::SPELLBOOK).toArtifact());
 
- 		NewArtifact na;
 
- 		na.art = a;
 
- 		gameCallback->sendAndApply(&na);
 
- 		PutArtifact pack;
 
- 		pack.al = ArtifactLocation(attacker->id, ArtifactPosition::SPELLBOOK);
 
- 		pack.art = a;
 
- 		gameCallback->sendAndApply(&pack);
 
- 	}
 
- 	startTestBattle(attacker, defender);
 
- 	uint32_t unitId = gameState->currentBattles.front()->battleNextUnitId();
 
- 	{
 
- 		battle::UnitInfo info;
 
- 		info.id = unitId;
 
- 		info.count = 10;
 
- 		info.type = CreatureID(13);
 
- 		info.side = BattleSide::ATTACKER;
 
- 		info.position = gameState->currentBattles.front()->getAvaliableHex(info.type, info.side);
 
- 		info.summoned = false;
 
- 		BattleUnitsChanged pack;
 
- 		pack.changedStacks.emplace_back(info.id, UnitChanges::EOperation::ADD);
 
- 		info.save(pack.changedStacks.back().data);
 
- 		gameCallback->sendAndApply(&pack);
 
- 	}
 
- 	{
 
- 		battle::UnitInfo info;
 
- 		info.id = gameState->currentBattles.front()->battleNextUnitId();
 
- 		info.count = 10;
 
- 		info.type = CreatureID(13);
 
- 		info.side = BattleSide::DEFENDER;
 
- 		info.position = gameState->currentBattles.front()->getAvaliableHex(info.type, info.side);
 
- 		info.summoned = false;
 
- 		BattleUnitsChanged pack;
 
- 		pack.changedStacks.emplace_back(info.id, UnitChanges::EOperation::ADD);
 
- 		info.save(pack.changedStacks.back().data);
 
- 		gameCallback->sendAndApply(&pack);
 
- 	}
 
- 	CStack * unit = gameState->currentBattles.front()->getStack(unitId);
 
- 	ASSERT_NE(unit, nullptr);
 
- 	int64_t damage = unit->getMaxHealth() + 1;
 
- 	unit->damage(damage);
 
- 	EXPECT_EQ(unit->getCount(), 9);
 
- 	{
 
- 		using namespace ::testing;
 
- 		spells::ProblemMock problemMock;
 
- 		EXPECT_CALL(problemMock, add(_)).Times(AnyNumber()); //todo: do smth with problems of optional effects
 
- 		const CSpell * spell = SpellID(SpellID::RESURRECTION).toSpell();
 
- 		ASSERT_NE(spell, nullptr);
 
- 			spells::BattleCast cast(gameState->currentBattles.front().get(), attacker, spells::Mode::HERO, spell);
 
- 		spells::Target target;
 
- 		target.emplace_back(unit);
 
- 		auto m = spell->battleMechanics(&cast);
 
- 		EXPECT_TRUE(m->canBeCast(problemMock));
 
- 		EXPECT_TRUE(m->canBeCastAt(target, problemMock));
 
- 		cast.cast(this, target);
 
- //
 
- //		std::vector<std::string> expLog;
 
- //
 
- //		EXPECT_THAT(problemMock.log, ContainerEq(expLog));
 
- 	}
 
- 	EXPECT_EQ(unit->health.getCount(), 10);
 
- 	EXPECT_EQ(unit->health.getResurrected(), 0);
 
- }
 
- TEST_F(CGameStateTest, updateEntity)
 
- {
 
- 	using ::testing::SaveArg;
 
- 	using ::testing::Eq;
 
- 	using ::testing::_;
 
- 	JsonNode actual;
 
- 	EXPECT_CALL(services, updateEntity(Eq(Metatype::CREATURE), Eq(424242), _)).WillOnce(SaveArg<2>(&actual));
 
- 	gameState->updateEntity(Metatype::CREATURE, 424242, JsonUtils::stringNode("TEST"));
 
- 	EXPECT_EQ(actual.String(), "TEST");
 
- }
 
 
  |