// // Lol Engine — Unit tests // // Copyright © 2010—2018 Sam Hocevar <sam@hocevar.net> // © 2014—2015 Benjamin “Touky” Huet <huet.benjamin@gmail.com> // // Lol Engine is free software. It comes without any warranty, to // the extent permitted by applicable law. You can redistribute it // and/or modify it under the terms of the Do What the Fuck You Want // to Public License, Version 2, as published by the WTFPL Task Force. // See http://www.wtfpl.net/ for more details. // #include <lol/engine-internal.h> #include <string> #include <map> #include <lolunit.h> namespace lol { lolunit_declare_fixture(thread_test) { //FileUpdateTesterJob --------------------------------------------------------- class UnitTestJob : public ThreadJob { friend class UnitTestThreadManager; public: char const *GetName() { return "<UnitTestJob>"; } UnitTestJob() : ThreadJob(ThreadJobType::WORK_TODO) { } bool IsDone() { return m_done; } protected: virtual bool DoWork() { Timer timer; m_done = false; msg::info("%s: STARTED WORK\n", GetName()); timer.Wait(2.f); msg::info("%s: ENDED WORK\n", GetName()); m_done = true; return true; } bool m_done = false; }; //Unit test thread manager class UnitTestThreadManager : public BaseThreadManager { typedef BaseThreadManager super; struct UnitTestStatusBase : public StructSafeEnum { enum Type { NOT_QUEUED, QUEUED, RETRIEVED, DONE, }; protected: virtual bool BuildEnumMap(std::map<int64_t, std::string>& enum_map) { enum_map[NOT_QUEUED] = "NOT_QUEUED"; enum_map[QUEUED] = "QUEUED"; enum_map[RETRIEVED] = "RETRIEVED"; enum_map[DONE] = "DONE"; return true; } }; typedef SafeEnum<UnitTestStatusBase> UnitTestStatus; public: char const *GetName() { return "<UnitTestThreadManager>"; } UnitTestThreadManager() : BaseThreadManager(4, 1) { } virtual ~UnitTestThreadManager() { } void AddJob(ThreadJob* job) { msg::info("%s DISPATCHING JOB %s\n", GetName(), job->GetName()); DispatchJob(job); } bool GetWorkResult(array<ThreadJob*>& results) { results += m_job_result; m_job_result.empty(); msg::info("%s GETWORKRESULT (%i)\n", GetName(), results.count()); return results.count() > 0; } virtual void TickGame(float seconds) { switch (m_status.ToScalar()) { case UnitTestStatus::NOT_QUEUED: if (!!GetDispatchCount()) { msg::info("%s TICKGAME %s\n", GetName(), m_status.tostring().c_str()); m_status = UnitTestStatus::QUEUED; } break; case UnitTestStatus::QUEUED: #if !defined(LOL_FEATURE_THREADS) || !LOL_FEATURE_THREADS if (!GetDispatchedCount()) #else //LOL_FEATURE_THREADS if (GetDispatchedCount()) #endif { msg::info("%s TICKGAME %s\n", GetName(), m_status.tostring().c_str()); m_status = UnitTestStatus::RETRIEVED; } break; case UnitTestStatus::RETRIEVED: if (m_job_result.count() == 4) { msg::info("%s TICKGAME %s\n", GetName(), m_status.tostring().c_str()); m_status = UnitTestStatus::DONE; } break; default: break; } //Debug error fix-up #if !LOL_BUILD_RELEASE m_tickstate = STATE_PRETICK_GAME; #endif super::TickGame(seconds); } bool IsDone() { return m_status == UnitTestStatus::DONE; } int Test_GetDispatchCount() { return GetDispatchCount(); } int Test_GetDispatchedCount() { return GetDispatchedCount(); } protected: virtual void TreatResult(ThreadJob* result) { m_job_result << result; } array<ThreadJob*> m_job_result; UnitTestStatus m_status; }; UnitTestThreadManager m_manager; void setup() { } void teardown() { } lolunit_declare_test(threads) { msg::info("%s START\n", m_manager.GetName()); //Start threads manager m_manager.Start(); msg::info("%s STARTED\n", m_manager.GetName()); UnitTestJob job[4]; lolunit_assert_equal(0, m_manager.Test_GetDispatchCount()); m_manager.AddJob(&job[0]); lolunit_assert_equal(1, m_manager.Test_GetDispatchCount()); lolunit_assert_equal(false, job[0].IsDone()); bool dispatch_check = true; while (!m_manager.IsDone()) { m_manager.TickGame(1.f / 60.f); if (dispatch_check) { lolunit_assert_equal(0, m_manager.Test_GetDispatchCount()); #if !defined(LOL_FEATURE_THREADS) || !LOL_FEATURE_THREADS lolunit_assert_equal(0, m_manager.Test_GetDispatchedCount()); #else //LOL_FEATURE_THREADS lolunit_assert_equal(1, m_manager.Test_GetDispatchedCount()); #endif m_manager.AddJob(&job[1]); m_manager.AddJob(&job[2]); m_manager.AddJob(&job[3]); dispatch_check = false; } } lolunit_assert_equal(true, job[0].IsDone()); lolunit_assert_equal(true, job[1].IsDone()); lolunit_assert_equal(true, job[2].IsDone()); lolunit_assert_equal(true, job[3].IsDone()); array<ThreadJob*> results; m_manager.GetWorkResult(results); lolunit_assert_equal(4, results.count()); msg::info("%s STOP\n", m_manager.GetName()); //Stop manager m_manager.Stop(); msg::info("%s STOPPED\n", m_manager.GetName()); } lolunit_declare_test(queue_try_push) { queue<int, 1> q; bool b1 = q.try_push(0); lolunit_assert_equal(true, b1); bool b2 = q.try_push(1); lolunit_assert_equal(false, b2); } lolunit_declare_test(queue_try_pop) { queue<int, 1> q; int tmp; q.push(42); bool b1 = q.try_pop(tmp); lolunit_assert_equal(true, b1); lolunit_assert_equal(42, tmp); bool b2 = q.try_pop(tmp); lolunit_assert_equal(false, b2); lolunit_assert_equal(42, tmp); } }; } /* namespace lol */