Completed
Push — master ( f7498d...cd0397 )
by Tomasz
02:42
created

GeneratorTest::buildSystemUnderTest()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 5

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 7
rs 9.4285
cc 1
eloc 5
nc 1
nop 0
1
<?php
2
3
use Gendoria\CruftFlake\Generator;
4
5
class GeneratorTest extends \PHPUnit_Framework_TestCase
6
{
7
    private $machineId = 1;
8
    
9
    private $timer;
10
    private $config;
11
    
12
    public function setUp()
13
    {
14
        $this->timer = $this->getMockBuilder('\Gendoria\CruftFlake\Timer\TimerInterface')
15
                            ->disableOriginalConstructor()
16
                            ->getMock();
17
        $this->config = $this->getMockBuilder('\Gendoria\CruftFlake\Config\ConfigInterface')
18
                            ->disableOriginalConstructor()
19
                            ->getMock();
20
    }
21
    
22
    private function buildSystemUnderTest()
23
    {
24
        $this->config->expects($this->once())
25
                     ->method('getMachine')
26
                     ->will($this->returnValue($this->machineId));
27
        return new Generator($this->config, $this->timer);
28
    }
29
    
30
    private function assertId($id)
31
    {
32
        $this->assertTrue(is_string($id));
33
        $this->assertTrue(ctype_digit($id));
34
    }
35
    
36
    private function assertReallyNotEquals($v1, $v2)
37
    {
38
        $this->assertTrue($v1 !== $v2);
39
    }
40
    
41
    // ---
42
    
43
    public function testConstructs()
44
    {
45
        $cf = $this->buildSystemUnderTest();
46
        $this->assertInstanceOf('\Gendoria\CruftFlake\Generator', $cf);
47
    }
48
    
49
    public function testFailsWithBadMachineIdString()
50
    {
51
        $this->setExpectedException('\InvalidArgumentException');
52
        $this->machineId = '1';
53
        $cf = $this->buildSystemUnderTest();
54
    }
55
    
56
    public function testFailsWithBadMachineIdNegative()
57
    {
58
        $this->setExpectedException('\InvalidArgumentException');
59
        $this->machineId = -1;
60
        $cf = $this->buildSystemUnderTest();
61
    }
62
63
    public function testFailsWithBadMachineIdTooBig()
64
    {
65
        $this->setExpectedException('\InvalidArgumentException');
66
        $this->machineId = 1024;
67
        $cf = $this->buildSystemUnderTest();
68
    }
69
70
    public function testFailsWithBadMachineIdFloat()
71
    {
72
        $this->setExpectedException('\InvalidArgumentException');
73
        $this->machineId = 1.1;
74
        $cf = $this->buildSystemUnderTest();
75
    }
76
77
    public function testLargestPossibleMachineId()
78
    {
79
        $this->machineId = 1023;
80
        $cf = $this->buildSystemUnderTest();
81
        $this->assertInstanceOf('\Gendoria\CruftFlake\Generator', $cf);
82
    }
83
    
84
    public function testGenerate()
85
    {
86
        $this->timer->expects($this->once())
87
                    ->method('getUnixTimestamp')
88
                    ->will($this->returnValue(1341246960000));
89
        $cf = $this->buildSystemUnderTest();
90
        $id = $cf->generate();
91
        $this->assertId($id);
92
    }
93
    
94
    public function testGenerateForPerMillisecondCollisions()
95
    {
96
        $this->timer->expects($this->any())
97
                    ->method('getUnixTimestamp')
98
                    ->will($this->returnValue(1341246960000));
99
        $cf = $this->buildSystemUnderTest();
100
        
101
        $id1 = $cf->generate();
102
        $id2 = $cf->generate();
103
        $id3 = $cf->generate();
104
        
105
        $this->assertId($id1);
106
        $this->assertId($id2);
107
        $this->assertId($id3);
108
        
109
        $this->assertReallyNotEquals($id1, $id2);
110
        $this->assertReallyNotEquals($id2, $id3);
111
    }
112
113
    public function testGenerateAsksForTimeEachTime()
114
    {
115
        $this->timer->expects($this->at(0))
116
                    ->method('getUnixTimestamp')
117
                    ->will($this->returnValue(1341246960000));
118
        $this->timer->expects($this->at(1))
119
                    ->method('getUnixTimestamp')
120
                    ->will($this->returnValue(1341246960001));
121
        $cf = $this->buildSystemUnderTest();
122
        
123
        $id1 = $cf->generate();
124
        $id2 = $cf->generate();
125
        
126
        $this->assertId($id1);
127
        $this->assertId($id2);
128
        
129
        $this->assertReallyNotEquals($id1, $id2);
130
    }
131
    
132
    public function testFailsWithTimestampBeforeEpoch()
133
    {
134
        $this->timer->expects($this->at(0))
135
                    ->method('getUnixTimestamp')
136
                    ->will($this->returnValue(1325375999999));
137
        $cf = $this->buildSystemUnderTest();
138
        
139
        $e = NULL;
140
        try {
141
            $id1 = $cf->generate();
142
        } catch (UnexpectedValueException $e) {
143
            
144
        }
145
        $this->assertInstanceOf('\UnexpectedValueException', $e);
146
        $this->assertEquals('Time is currently set before our epoch - unable to generate IDs for 1 milliseconds', $e->getMessage());
147
    }
148
    
149
    public function testFailsIfTimeRunsBackwards()
150
    {
151
        //$this->setExpectedException('\UnexpectedValueException');
152
        
153
        $this->timer->expects($this->at(0))
154
                    ->method('getUnixTimestamp')
155
                    ->will($this->returnValue(1341246960001));
156
        $this->timer->expects($this->at(1))
157
                    ->method('getUnixTimestamp')
158
                    ->will($this->returnValue(1341246960000));
159
        $cf = $this->buildSystemUnderTest();
160
        
161
        $id1 = $cf->generate();
162
        
163
        $e = NULL;
164
        try {
165
            $id2 = $cf->generate();
166
        } catch (UnexpectedValueException $e) {
167
            
168
        }
169
        $this->assertInstanceOf('\UnexpectedValueException', $e);
170
        $this->assertEquals('Time moved backwards. We cannot generate IDs for 1 milliseconds', $e->getMessage());
171
    }
172
    
173
    public function testFullSequenceRange()
174
    {
175
        $this->timer->expects($this->any())
176
                    ->method('getUnixTimestamp')
177
                    ->will($this->returnValue(1341246960000));
178
        $cf = $this->buildSystemUnderTest();
179
        
180
        $ids = array();
181
        for ($i=0; $i<4095; $i++) {
182
            $id = $cf->generate();
183
            $ids[$id] = 1;
184
        }
185
        
186
        $this->assertEquals(4095, count($ids));
187
    }
188
    
189
    public function testFailsIfSequenceOverflow()
190
    {
191
        $this->timer->expects($this->any())
192
                    ->method('getUnixTimestamp')
193
                    ->will($this->returnValue(1341246960000));
194
        $cf = $this->buildSystemUnderTest();
195
        
196
        $ids = array();
197
        for ($i=0; $i<4096; $i++) {
198
            $id = $cf->generate();
199
            $ids[$id] = 1;
200
        }
201
        
202
        $e = NULL;
203
        try {
204
            $id2 = $cf->generate();
205
        } catch (OverflowException $e) {
206
            
207
        }
208
        $this->assertInstanceOf('\OverflowException', $e);
209
        $this->assertEquals('Sequence overflow (too many IDs generated) - unable to generate IDs for 1 milliseconds', $e->getMessage());
210
    }
211
    
212
    public function testSmallestTimestampId()
213
    {
214
        $this->machineId = 0;
215
        $this->timer->expects($this->any())
216
                    ->method('getUnixTimestamp')
217
                    ->will($this->returnValue(1325376000000));
218
        $cf = $this->buildSystemUnderTest();
219
        
220
        $id1 = $cf->generate();
221
        $id2 = $cf->generate();
222
        
223
        $this->assertId($id1);
224
        $this->assertId($id2);
225
        $this->assertReallyNotEquals($id1, $id2);
226
        
227
        $this->assertEquals(0, $id1);
228
    }
229
    
230
    public function testSmallestTimestampWithMachine()
231
    {
232
        $this->timer->expects($this->any())
233
                    ->method('getUnixTimestamp')
234
                    ->will($this->returnValue(1325376000000));
235
        $cf = $this->buildSystemUnderTest();
236
        
237
        $id1 = $cf->generate();
238
        $id2 = $cf->generate();
239
        
240
        $this->assertId($id1);
241
        $this->assertId($id2);
242
        $this->assertReallyNotEquals($id1, $id2);
243
        
244
        $this->assertEquals(1 << 12, $id1);
245
        $this->assertEquals(1 << 12 | 1, $id2);
246
    }
247
248
    public function testSmallTimestampWithMachine()
249
    {
250
        $this->timer->expects($this->any())
251
                    ->method('getUnixTimestamp')
252
                    ->will($this->returnValue(1325376000001));
253
        $cf = $this->buildSystemUnderTest();
254
        
255
        $id1 = $cf->generate();
256
        $id2 = $cf->generate();
257
        
258
        $this->assertId($id1);
259
        $this->assertId($id2);
260
        $this->assertReallyNotEquals($id1, $id2);
261
        
262
        $this->assertEquals(1 << 22 | 1 << 12, $id1);
263
        $this->assertEquals(1 << 22 | 1 << 12 | 1, $id2);
264
    }
265
    
266
    public function testFailsOnTimestampOverflow()
267
    {
268
        $this->timer->expects($this->any())
269
                    ->method('getUnixTimestamp')
270
                    ->will($this->returnValue(3524399255552));
271
        $cf = $this->buildSystemUnderTest();
272
        $e = NULL;
273
        try {
274
            $id2 = $cf->generate();
275
        } catch (OverflowException $e) {
276
            
277
        }
278
        $this->assertInstanceOf('\OverflowException', $e);
279
        $this->assertEquals('Timestamp overflow (past end of lifespan) - unable to generate any more IDs', $e->getMessage());
280
    }
281
    
282
    public function testLargestTimestampWithLargestEverythingElse()
283
    {
284
        $this->machineId = 1023;
285
        $this->timer->expects($this->any())
286
                    ->method('getUnixTimestamp')
287
                    ->will($this->returnValue(3524399255551));
288
        $cf = $this->buildSystemUnderTest();
289
        
290
        $id1 = $cf->generate();
291
        $id2 = $cf->generate();
292
        
293
        $this->assertId($id1);
294
        $this->assertId($id2);
295
        $this->assertReallyNotEquals($id1, $id2);
296
        $this->assertEquals('9223372036854771712', $id1);
297
    }
298
}
299