<commit_before>/*******************************************************************************
 * Copyright 2015 See AUTHORS file.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 ******************************************************************************/
#include "../TestBase.hpp"
#include <ecstasy/systems/SortedIteratingSystem.hpp>
#include <deque>

namespace SortedIteratingSystemTests {
	float deltaTime = 0.16f;

	struct ComponentB : public Component<ComponentB> {};
	struct ComponentC : public Component<ComponentC> {};

	struct OrderComponent : public Component<OrderComponent> {
		std::string name;
		int zLayer;
		OrderComponent(std::string name, int zLayer) : name(name), zLayer(zLayer) {}
	};

	struct SpyComponent : public Component<SpyComponent> {
		int updates = 0;
	};

	struct IndexComponent : public Component<IndexComponent> {
		int index;
		IndexComponent(int index) : index(index) {}
	};

	bool comparator(Entity* a, Entity* b) {
		auto ac = a->get<OrderComponent>();
		auto bc = b->get<OrderComponent>();
		return ac->zLayer < bc->zLayer;
	}

	struct Less {
		bool operator () (Entity* a, Entity* b) {
			auto ac = a->get<OrderComponent>();
			auto bc = b->get<OrderComponent>();
			return ac->zLayer < bc->zLayer;
		}
	};

	class SortedIteratingSystemMock : public SortedIteratingSystem<SortedIteratingSystemMock, Less> {
	public:
		std::deque<std::string> expectedNames;

		SortedIteratingSystemMock(const Family &family) : SortedIteratingSystem(family, Less()) {}

		void update(float deltaTime) override {
			SortedIteratingSystem::update(deltaTime);
			REQUIRE(expectedNames.empty());
		}

		void processEntity(Entity* entity, float deltaTime) override {
			auto component = entity->get<OrderComponent>();
			REQUIRE(component);
			REQUIRE(!expectedNames.empty());
			REQUIRE(expectedNames.front() == component->name);
			expectedNames.pop_front();
		}
	};

	class IteratingComponentRemovalSystem : public SortedIteratingSystem<IteratingComponentRemovalSystem, Less> {
	public:
		IteratingComponentRemovalSystem()
			:SortedIteratingSystem(Family::all<SpyComponent, IndexComponent>().get(), Less()) {
		}

		void processEntity (Entity* entity, float deltaTime) override {
			int index = entity->get<IndexComponent>()->index;
			if (index % 2 == 0) {
				entity->remove<SpyComponent>();
				entity->remove<IndexComponent>();
			} else {
				entity->get<SpyComponent>()->updates++;
			}
		}

	};

class IteratingRemovalSystem : public SortedIteratingSystem<IteratingRemovalSystem, Less> {

	public:
		Engine* engine;
		IteratingRemovalSystem()
			: SortedIteratingSystem(Family::all<SpyComponent, IndexComponent>().get(), Less()) {}

		void addedToEngine(Engine* engine) override {
			SortedIteratingSystem::addedToEngine(engine);
			this->engine = engine;
		}

		void processEntity(Entity* entity, float deltaTime) override {
			int index = entity->get<IndexComponent>()->index;
			if (index % 2 == 0)
				engine->removeEntity(entity);
			else
				entity->get<SpyComponent>()->updates++;
		}
	};

	TEST_CASE("shouldIterateSortedEntitiesWithCorrectFamily") {
		Engine engine;

		auto &family = Family::all<OrderComponent, ComponentB>().get();
		auto system = engine.emplaceSystem<SortedIteratingSystemMock>(family);
		Entity* e = engine.createEntity();
		engine.addEntity(e);

		// When entity has OrderComponent
	 	e->emplace<OrderComponent>("A", 0);
		engine.update(deltaTime);

		// When entity has OrderComponent and ComponentB
		e->emplace<ComponentB>();
		system->expectedNames.push_back("A");
		engine.update(deltaTime);

		// When entity has OrderComponent, ComponentB and ComponentC
		e->emplace<ComponentC>();
		system->expectedNames.push_back("A");
		engine.update(deltaTime);

		// When entity has ComponentB and ComponentC
		e->remove<OrderComponent>();
		engine.update(deltaTime);
	}

	TEST_CASE("entityRemovalWhileSortedIterating") {
		Engine engine;
		auto entities = engine.getEntitiesFor(Family::all<SpyComponent, IndexComponent>().get());

		engine.emplaceSystem<IteratingRemovalSystem>();

		int numEntities = 10;

		for (int i = 0; i < numEntities; ++i) {
			auto e = engine.createEntity();
			e->emplace<SpyComponent>();
			e->emplace<OrderComponent>("" + i, i);
			e->emplace<IndexComponent>(i + 1);

			engine.addEntity(e);
		}

		engine.update(deltaTime);

		REQUIRE((numEntities / 2) == entities->size());

		for (auto e: *entities) {
			REQUIRE(1 == e->get<SpyComponent>()->updates);
		}
	}

	TEST_CASE("componentRemovalWhileSortedIterating") {
		Engine engine;
		auto entities = engine.getEntitiesFor(Family::all<SpyComponent, IndexComponent>().get());

		engine.emplaceSystem<IteratingComponentRemovalSystem>();

		int numEntities = 10;

		for (int i = 0; i < numEntities; ++i) {
			auto e = engine.createEntity();
			e->emplace<SpyComponent>();
			e->emplace<OrderComponent>("" + i, i);
			e->emplace<IndexComponent>(i + 1);

			engine.addEntity(e);<commit_msg>using to_string<commit_after>/*******************************************************************************
 * Copyright 2015 See AUTHORS file.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 ******************************************************************************/
#include "../TestBase.hpp"
#include <ecstasy/systems/SortedIteratingSystem.hpp>
#include <deque>

namespace SortedIteratingSystemTests {
	float deltaTime = 0.16f;

	struct ComponentB : public Component<ComponentB> {};
	struct ComponentC : public Component<ComponentC> {};

	struct OrderComponent : public Component<OrderComponent> {
		std::string name;
		int zLayer;
		OrderComponent(std::string name, int zLayer) : name(name), zLayer(zLayer) {}
	};

	struct SpyComponent : public Component<SpyComponent> {
		int updates = 0;
	};

	struct IndexComponent : public Component<IndexComponent> {
		int index;
		IndexComponent(int index) : index(index) {}
	};

	bool comparator(Entity* a, Entity* b) {
		auto ac = a->get<OrderComponent>();
		auto bc = b->get<OrderComponent>();
		return ac->zLayer < bc->zLayer;
	}

	struct Less {
		bool operator () (Entity* a, Entity* b) {
			auto ac = a->get<OrderComponent>();
			auto bc = b->get<OrderComponent>();
			return ac->zLayer < bc->zLayer;
		}
	};

	class SortedIteratingSystemMock : public SortedIteratingSystem<SortedIteratingSystemMock, Less> {
	public:
		std::deque<std::string> expectedNames;

		SortedIteratingSystemMock(const Family &family) : SortedIteratingSystem(family, Less()) {}

		void update(float deltaTime) override {
			SortedIteratingSystem::update(deltaTime);
			REQUIRE(expectedNames.empty());
		}

		void processEntity(Entity* entity, float deltaTime) override {
			auto component = entity->get<OrderComponent>();
			REQUIRE(component);
			REQUIRE(!expectedNames.empty());
			REQUIRE(expectedNames.front() == component->name);
			expectedNames.pop_front();
		}
	};

	class IteratingComponentRemovalSystem : public SortedIteratingSystem<IteratingComponentRemovalSystem, Less> {
	public:
		IteratingComponentRemovalSystem()
			:SortedIteratingSystem(Family::all<SpyComponent, IndexComponent>().get(), Less()) {
		}

		void processEntity (Entity* entity, float deltaTime) override {
			int index = entity->get<IndexComponent>()->index;
			if (index % 2 == 0) {
				entity->remove<SpyComponent>();
				entity->remove<IndexComponent>();
			} else {
				entity->get<SpyComponent>()->updates++;
			}
		}

	};

class IteratingRemovalSystem : public SortedIteratingSystem<IteratingRemovalSystem, Less> {

	public:
		Engine* engine;
		IteratingRemovalSystem()
			: SortedIteratingSystem(Family::all<SpyComponent, IndexComponent>().get(), Less()) {}

		void addedToEngine(Engine* engine) override {
			SortedIteratingSystem::addedToEngine(engine);
			this->engine = engine;
		}

		void processEntity(Entity* entity, float deltaTime) override {
			int index = entity->get<IndexComponent>()->index;
			if (index % 2 == 0)
				engine->removeEntity(entity);
			else
				entity->get<SpyComponent>()->updates++;
		}
	};

	TEST_CASE("shouldIterateSortedEntitiesWithCorrectFamily") {
		Engine engine;

		auto &family = Family::all<OrderComponent, ComponentB>().get();
		auto system = engine.emplaceSystem<SortedIteratingSystemMock>(family);
		Entity* e = engine.createEntity();
		engine.addEntity(e);

		// When entity has OrderComponent
	 	e->emplace<OrderComponent>("A", 0);
		engine.update(deltaTime);

		// When entity has OrderComponent and ComponentB
		e->emplace<ComponentB>();
		system->expectedNames.push_back("A");
		engine.update(deltaTime);

		// When entity has OrderComponent, ComponentB and ComponentC
		e->emplace<ComponentC>();
		system->expectedNames.push_back("A");
		engine.update(deltaTime);

		// When entity has ComponentB and ComponentC
		e->remove<OrderComponent>();
		engine.update(deltaTime);
	}

	TEST_CASE("entityRemovalWhileSortedIterating") {
		Engine engine;
		auto entities = engine.getEntitiesFor(Family::all<SpyComponent, IndexComponent>().get());

		engine.emplaceSystem<IteratingRemovalSystem>();

		int numEntities = 10;

		for (int i = 0; i < numEntities; ++i) {
			auto e = engine.createEntity();
			e->emplace<SpyComponent>();
			e->emplace<OrderComponent>(std::to_string(i), i);
			e->emplace<IndexComponent>(i + 1);

			engine.addEntity(e);
		}

		engine.update(deltaTime);

		REQUIRE((numEntities / 2) == entities->size());

		for (auto e: *entities) {
			REQUIRE(1 == e->get<SpyComponent>()->updates);
		}
	}

	TEST_CASE("componentRemovalWhileSortedIterating") {
		Engine engine;
		auto entities = engine.getEntitiesFor(Family::all<SpyComponent, IndexComponent>().get());

		engine.emplaceSystem<IteratingComponentRemovalSystem>();

		int numEntities = 10;

		for (int i = 0; i < numEntities; ++i) {
			auto e = engine.createEntity();
			e->emplace<SpyComponent>();
			e->emplace<OrderComponent>(std::to_string(i), i);
			e->emplace<IndexComponent>(i + 1);

			engine.addEntity(e);
{'fraction_non_alphanumeric': 0.16005145167217935, 'fraction_numerical': 0.004961411245865491, 'mean_word_length': 5.013812154696133, 'pattern_counts': {'":': 0, '<': 93, '<?xml version=': 0, '>': 159, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4816658', 'n_tokens_mistral': 3584, 'n_tokens_neox': 3199, 'n_words': 746}