1+ <?php
2+
3+
4+ namespace test \unit \Ingenerator \PHPUtils \unit \DateTime \Clock ;
5+
6+ use Ingenerator \PHPUtils \DateTime \Clock \StoppedMockClock ;
7+ use PHPUnit \Framework \TestCase ;
8+
9+ class StoppedMockClockTest extends TestCase
10+ {
11+
12+ public function test_it_is_initialisable_now ()
13+ {
14+ $ clock = StoppedMockClock::atNow ();
15+ $ this ->assertEquals (
16+ new \DateTimeImmutable ,
17+ $ clock ->getDateTime (),
18+ 'Starts at the right time ' ,
19+ 1
20+ );
21+ }
22+
23+ public function provider_at_fixed ()
24+ {
25+ return [
26+ [
27+ '2019-03-04 10:02:03 ' ,
28+ new \DateTimeImmutable ('2019-03-04 10:02:03 ' ),
29+ 1551693723.0
30+ ],
31+ [
32+ new \DateTimeImmutable ('2019-03-04 10:02:03 ' ),
33+ new \DateTimeImmutable ('2019-03-04 10:02:03 ' ),
34+ 1551693723.0
35+ ],
36+ ];
37+ }
38+
39+
40+ /**
41+ * @dataProvider provider_at_fixed
42+ */
43+ public function test_it_is_initialisable_at_fixed_time_from_string_or_object ($ at_what , $ expect_time , $ expect_micro )
44+ {
45+ $ clock = StoppedMockClock::at ($ at_what );
46+ $ this ->assertEquals ($ expect_time , $ clock ->getDateTime ());
47+ $ this ->assertSame ($ expect_micro , $ clock ->getMicrotime ());
48+ }
49+
50+ public function test_it_is_initialisable_at_fixed_microtime ()
51+ {
52+ $ clock = StoppedMockClock::atMicrotime (1551693723.1239 );
53+ $ this ->assertSame (1551693723.1239 , $ clock ->getMicrotime ());
54+ $ this ->assertSame ('2019-03-04 10:02:03 ' , $ clock ->getDateTime ()->format ('Y-m-d H:i:s ' ));
55+ }
56+
57+ public function test_it_is_initialisable_at_a_date_interval_in_the_past ()
58+ {
59+ $ clock = StoppedMockClock::atTimeAgo ('P3D ' );
60+ $ ago = (new \DateTimeImmutable )->sub (new \DateInterval ('P3D ' ));
61+ $ this ->assertEquals ($ ago , $ clock ->getDateTime (), 'Time is at correct interval ' , 1 );
62+ }
63+
64+ public function test_it_holds_its_time_forever_in_real_life ()
65+ {
66+ $ clock = StoppedMockClock::atNow ();
67+ $ start_microtime = $ clock ->getMicrotime ();
68+ $ start_time = $ clock ->getDateTime ();
69+ sleep (2 );
70+ $ this ->assertEquals ($ start_time , $ clock ->getDateTime (), 'Stays at the same time ' );
71+ $ this ->assertSame ($ start_microtime , $ clock ->getMicrotime (), 'Stays at the same microtime ' );
72+ }
73+
74+ public function test_it_advances_time_after_each_tick ()
75+ {
76+ $ clock = StoppedMockClock::at ('2019-01-05 10:03:02 ' );
77+ $ this ->assertSame (1546682582.0 , $ clock ->getMicrotime (), 'Correct starting microtime ' );
78+
79+ $ clock ->tick (new \DateInterval ('P1D ' ));
80+ $ this ->assertEquals (new \DateTimeImmutable ('2019-01-06 10:03:02 ' ), $ clock ->getDateTime ());
81+ $ this ->assertSame (1546768982.0 , $ clock ->getMicrotime ());
82+ }
83+
84+ public function test_it_advances_time_after_each_tick_microseconds ()
85+ {
86+ $ clock = StoppedMockClock::atMicrotime (1546682582.150 );
87+ $ this ->assertEquals (new \DateTimeImmutable ('2019-01-05 10:03:02 ' ), $ clock ->getDateTime ());
88+
89+ $ clock ->tickMicroseconds (150000 );
90+ $ this ->assertSame (1546682582.300 , round ($ clock ->getMicrotime (), 3 ));
91+ $ this ->assertEquals (new \DateTimeImmutable ('2019-01-05 10:03:02 ' ), $ clock ->getDateTime (), 'DateTime not changed by sub-second tick ' );
92+
93+
94+ $ clock ->tickMicroseconds (750000 );
95+ $ this ->assertSame (1546682583.050 , round ($ clock ->getMicrotime (), 3 ));
96+ $ this ->assertEquals (new \DateTimeImmutable ('2019-01-05 10:03:03 ' ), $ clock ->getDateTime (), 'DateTime changed after second boundary ' );
97+ }
98+
99+ public function test_its_usleep_is_immediate_but_advances_time ()
100+ {
101+ $ clock = StoppedMockClock::atMicrotime (1546682582.05 );
102+ $ start = microtime (TRUE );
103+ $ clock ->usleep (900000 );
104+ $ real_ms = 1000 * (microtime (TRUE ) - $ start );
105+ $ this ->assertLessThan (50 , $ real_ms , 'Should not actually sleep ' );
106+ $ this ->assertSame (1546682582.95 , round ($ clock ->getMicrotime (), 3 ), 'Should update time ' );
107+ }
108+
109+ public function provider_assert_slept_fails ()
110+ {
111+ return [
112+ [
113+ function () {
114+ },
115+ [15 ],
116+ 'Never slept at all '
117+ ],
118+ [
119+ function (StoppedMockClock $ clock ) {
120+ $ clock ->usleep (150 );
121+ },
122+ [15 ],
123+ 'Wrong amount of sleep '
124+ ],
125+ [
126+ function (StoppedMockClock $ clock ) {
127+ $ clock ->usleep (150 );
128+ },
129+ [150 , 30 ],
130+ 'Incorrect number of sleeps '
131+ ],
132+ [
133+ function (StoppedMockClock $ clock ) {
134+ $ clock ->usleep (150 );
135+ $ clock ->usleep (10 );
136+ },
137+ [10 , 150 ],
138+ 'Sleeps in wrong order '
139+ ],
140+ ];
141+ }
142+
143+ /**
144+ * @dataProvider provider_assert_slept_fails
145+ */
146+ public function test_assert_slept_fails_if_not_slept_for_expected_intervals ($ callback , $ expected , $ msg )
147+ {
148+ $ clock = StoppedMockClock::atNow ();
149+ $ callback ($ clock );
150+ $ e = NULL ;
151+ try {
152+ $ clock ->assertSlept ($ expected , $ msg );
153+ } catch (\Exception $ e ) {
154+ }
155+ $ this ->assertInstanceOf (\Exception::class, $ e , 'Should have thrown ' );
156+ // Do it like this to make it type-safe for old and new phpunit
157+ $ this ->assertContains ('ExpectationFailedException ' , get_class ($ e ), 'Should be assertion exception ' );
158+ }
159+
160+ public function test_assert_slept_passes_if_slept_for_expected_intervals ()
161+ {
162+ $ clock = StoppedMockClock::atNow ();
163+ $ clock ->usleep (50000 );
164+ $ clock ->usleep (20000 );
165+ $ clock ->usleep (15000 );
166+ $ this ->assertNull (
167+ $ clock ->assertSlept ([50000 , 20000 , 15000 ])
168+ );
169+ }
170+ }
0 commit comments