// Copyright (c) 2011-2016 The Cryptonote developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include #include #include #include #include #include #include #include using namespace System; class TimerTests : public testing::Test { public: TimerTests() : contextGroup(dispatcher) { } Dispatcher dispatcher; ContextGroup contextGroup; }; TEST_F(TimerTests, timerIsWorking) { bool done = false; contextGroup.spawn([&]() { done = true; }); ASSERT_FALSE(done); Timer(dispatcher).sleep(std::chrono::milliseconds(10)); ASSERT_TRUE(done); } TEST_F(TimerTests, movedTimerIsWorking) { Timer t{Timer{dispatcher}}; bool done = false; contextGroup.spawn([&]() { done = true; }); ASSERT_FALSE(done); t.sleep(std::chrono::milliseconds(10)); ASSERT_TRUE(done); } TEST_F(TimerTests, movedAndStoopedTimerIsWorking) { contextGroup.spawn([&] { Timer src(dispatcher); contextGroup.interrupt(); Timer t(std::move(src)); ASSERT_ANY_THROW(t.sleep(std::chrono::milliseconds(1))); }); } TEST_F(TimerTests, doubleTimerTest) { auto begin = std::chrono::high_resolution_clock::now(); Event first(dispatcher); Event second(dispatcher); Context<> context(dispatcher, [&] { Timer(dispatcher).sleep(std::chrono::milliseconds(100)); first.set(); }); Context<> contextSecond(dispatcher, [&] { Timer(dispatcher).sleep(std::chrono::milliseconds(200)); second.set(); }); first.wait(); second.wait(); ASSERT_GE(std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - begin).count(), 150); ASSERT_TRUE((std::chrono::high_resolution_clock::now() - begin) < std::chrono::milliseconds(275)); } TEST_F(TimerTests, doubleTimerTestGroup) { auto begin = std::chrono::high_resolution_clock::now(); Event first(dispatcher); Event second(dispatcher); contextGroup.spawn([&] { Timer(dispatcher).sleep(std::chrono::milliseconds(100)); first.set(); }); contextGroup.spawn([&] { Timer(dispatcher).sleep(std::chrono::milliseconds(200)); second.set(); }); first.wait(); second.wait(); ASSERT_GE(std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - begin).count(), 150); ASSERT_TRUE((std::chrono::high_resolution_clock::now() - begin) < std::chrono::milliseconds(250)); } TEST_F(TimerTests, doubleTimerTestGroupWait) { auto begin = std::chrono::high_resolution_clock::now(); contextGroup.spawn([&] { Timer(dispatcher).sleep(std::chrono::milliseconds(100)); }); contextGroup.spawn([&] { Timer(dispatcher).sleep(std::chrono::milliseconds(200)); }); contextGroup.wait(); ASSERT_GE(std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - begin).count(), 150); ASSERT_TRUE((std::chrono::high_resolution_clock::now() - begin) < std::chrono::milliseconds(250)); } TEST_F(TimerTests, doubleTimerTestTwoGroupsWait) { auto begin = std::chrono::high_resolution_clock::now(); ContextGroup cg(dispatcher); cg.spawn([&] { Timer(dispatcher).sleep(std::chrono::milliseconds(100)); }); contextGroup.spawn([&] { Timer(dispatcher).sleep(std::chrono::milliseconds(200)); }); contextGroup.wait(); ASSERT_GE(std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - begin).count(), 150); ASSERT_TRUE((std::chrono::high_resolution_clock::now() - begin) < std::chrono::milliseconds(275)); } TEST_F(TimerTests, movedTimerIsWorking2) { bool done = false; contextGroup.spawn([&] { Timer t(dispatcher); t = Timer{dispatcher}; //contextGroup.spawn([&]() { done = true; }); ASSERT_FALSE(done); t.sleep(std::chrono::milliseconds(10)); ASSERT_TRUE(done); }); contextGroup.spawn([&]() { done = true; }); contextGroup.wait(); } TEST_F(TimerTests, movedAndStoopedTimerIsWorking2) { contextGroup.spawn([&] { Timer src(dispatcher); contextGroup.interrupt(); Timer t(dispatcher); t = std::move(src); ASSERT_ANY_THROW(t.sleep(std::chrono::milliseconds(1))); }); } TEST_F(TimerTests, movedTimerIsTheSame) { contextGroup.spawn([&] { Timer timer(dispatcher); auto timerPtr1 = &timer; Timer srcEvent(dispatcher); timer = std::move(srcEvent); auto timerPtr2 = &timer; ASSERT_EQ(timerPtr1, timerPtr2); }); } TEST_F(TimerTests, timerStartIsWorking) { contextGroup.spawn([&] { Timer t(dispatcher); contextGroup.interrupt(); ASSERT_ANY_THROW(t.sleep(std::chrono::milliseconds(1))); ASSERT_NO_THROW(t.sleep(std::chrono::milliseconds(1))); }); } TEST_F(TimerTests, timerStopBeforeSleep) { contextGroup.spawn([&] { Timer t(dispatcher); contextGroup.interrupt(); ASSERT_THROW(t.sleep(std::chrono::milliseconds(1)), InterruptedException); contextGroup.interrupt(); ASSERT_THROW(t.sleep(std::chrono::milliseconds(1)), InterruptedException); }); } TEST_F(TimerTests, timerIsCancelable) { contextGroup.spawn([&] { Timer t(dispatcher); ASSERT_THROW(t.sleep(std::chrono::milliseconds(100)), InterruptedException); }); contextGroup.spawn([&]() { contextGroup.interrupt(); }); } // Disabled, because on OS X it is currently impossible to distinguish timer timeout and interrupt TEST_F(TimerTests, DISABLED_sleepThrowsOnlyIfTimerIsStoppedBeforeTime1) { contextGroup.spawn([&] { Timer t(dispatcher); ASSERT_NO_THROW(t.sleep(std::chrono::milliseconds(1))); ASSERT_THROW(t.sleep(std::chrono::milliseconds(1)), InterruptedException); }); contextGroup.spawn([&]() { std::this_thread::sleep_for(std::chrono::milliseconds(10)); contextGroup.interrupt(); }); } TEST_F(TimerTests, sleepIsSleepingAtLeastTakenTime) { auto timepoint1 = std::chrono::high_resolution_clock::now(); contextGroup.spawn([&] { Timer(dispatcher).sleep(std::chrono::milliseconds(100)); }); contextGroup.wait(); auto timepoint2 = std::chrono::high_resolution_clock::now(); ASSERT_LE(95, std::chrono::duration_cast(timepoint2 - timepoint1).count()); } TEST_F(TimerTests, timerIsReusable) { Timer t(dispatcher); auto timepoint1 = std::chrono::high_resolution_clock::now(); contextGroup.spawn([&] { ASSERT_NO_THROW(t.sleep(std::chrono::seconds(1))); }); contextGroup.wait(); auto timepoint2 = std::chrono::high_resolution_clock::now(); contextGroup.spawn([&] { ASSERT_NO_THROW(t.sleep(std::chrono::seconds(1))); }); contextGroup.wait(); auto timepoint3 = std::chrono::high_resolution_clock::now(); ASSERT_LE(950, std::chrono::duration_cast(timepoint2 - timepoint1).count()); ASSERT_LE(950, std::chrono::duration_cast(timepoint3 - timepoint2).count()); } TEST_F(TimerTests, timerIsReusableAfterInterrupt) { contextGroup.spawn([&] { Timer t(dispatcher); contextGroup.interrupt(); auto timepoint1 = std::chrono::high_resolution_clock::now(); ASSERT_THROW(t.sleep(std::chrono::seconds(1)), InterruptedException); auto timepoint2 = std::chrono::high_resolution_clock::now(); ASSERT_NO_THROW(t.sleep(std::chrono::seconds(1))); auto timepoint3 = std::chrono::high_resolution_clock::now(); ASSERT_LE(0, std::chrono::duration_cast(timepoint2 - timepoint1).count()); ASSERT_LE(950, std::chrono::duration_cast(timepoint3 - timepoint2).count()); }); } TEST_F(TimerTests, timerWithZeroTimeIsYielding) { bool done = false; contextGroup.spawn([&]() { done = true; }); ASSERT_FALSE(done); Timer(dispatcher).sleep(std::chrono::milliseconds(0)); ASSERT_TRUE(done); }