Completed
Push — develop ( c26b5c...7b6e62 )
by Mathieu
02:52
created

DBObjectTest::getCategoryDBOject()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 17
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 10
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 17
rs 9.9332
1
<?php
2
require_once 'stubs/Category.php';
3
4
class DBObjectTest extends \PHPUnit\Framework\TestCase
5
{
6
    protected $tableName = 'users';
7
    public function testContructor()
8
    {
9
        $classname = '\Suricate\DBObject';
10
11
        // Get mock, without the constructor being called
12
        $mock = $this->getMockBuilder($classname)
13
            ->disableOriginalConstructor()
14
            ->setMethods(array('setRelations'))
15
            ->getMockForAbstractClass();
16
17
        // set expectations for constructor calls
18
        $mock->expects($this->once())
19
            ->method('setRelations');
20
21
        // now call the constructor
22
        $reflectedClass = new ReflectionClass($classname);
23
        $constructor = $reflectedClass->getConstructor();
24
        $constructor->invoke($mock);
25
    }
26
27
    public function testGetTableName()
28
    {
29
        $testName = 'my_sql_table';
30
31
        $testDBO = new \Suricate\DBObject();
32
        self::mockProperty($testDBO, 'tableName', $testName);
33
        $this->assertEquals($testName, $testDBO->getTableName());
34
    }
35
36
    public function testGetTableIndex()
37
    {
38
        $testIndex = 'id';
39
40
        $testDBO = new \Suricate\DBObject();
41
        self::mockProperty($testDBO, 'tableIndex', $testIndex);
42
        $this->assertEquals($testIndex, $testDBO->getTableIndex());
43
    }
44
45
    public function testGetDBConfig()
46
    {
47
        $testConfigName = 'my_config';
48
49
        $testDBO = new \Suricate\DBObject();
50
        self::mockProperty($testDBO, 'DBConfig', $testConfigName);
51
        $this->assertEquals($testConfigName, $testDBO->getDBConfig());
52
    }
53
54
    public function testUndefinedGet()
55
    {
56
        $testDBO = new \Suricate\DBObject();
57
        self::mockProperty($testDBO, 'dbVariables', ['id', 'name', 'last_update']);
58
        $this->expectException(\InvalidArgumentException::class);
59
        
60
        $testDBO->undefinedVar;
0 ignored issues
show
Bug Best Practice introduced by
The property undefinedVar does not exist on Suricate\DBObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
61
    }
62
63
    public function testDBProperty()
64
    {
65
        $testDBO = new \Suricate\DBObject();
66
        $testDBO->regularProperty = 42;
0 ignored issues
show
Bug Best Practice introduced by
The property regularProperty does not exist on Suricate\DBObject. Since you implemented __set, consider adding a @property annotation.
Loading history...
67
        self::mockProperty($testDBO, 'dbVariables', ['id', 'name', 'not_loaded_var']);
68
        self::mockProperty($testDBO, 'dbValues', ['id' => 1, 'name' => 'test name']);
69
        $this->assertEquals($testDBO->id, 1);
0 ignored issues
show
Bug Best Practice introduced by
The property id does not exist on Suricate\DBObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
70
        $this->assertNotEquals($testDBO->name, 'test name edited');
0 ignored issues
show
Bug Best Practice introduced by
The property name does not exist on Suricate\DBObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
71
        $this->assertNull($testDBO->not_loaded_var);
0 ignored issues
show
Bug Best Practice introduced by
The property not_loaded_var does not exist on Suricate\DBObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
72
73
        $this->assertTrue($testDBO->isDBVariable('id'));
74
        $this->assertFalse($testDBO->isDBVariable('regularProperty'));
75
76
        $this->assertTrue($testDBO->propertyExists('regularProperty'));
77
        $this->assertTrue($testDBO->propertyExists('id'));
78
        $this->assertFalse($testDBO->propertyExists('unknownProperty'));
79
    }
80
81
    public function testIsset()
82
    {
83
        $testDBO = new \Suricate\DBObject();
84
        self::mockProperty($testDBO, 'dbVariables', ['id', 'name', 'not_loaded_var']);
85
        self::mockProperty($testDBO, 'dbValues', ['id' => 1, 'name' => 'test name']);
86
87
        $this->assertTrue(isset($testDBO->id));
0 ignored issues
show
Bug Best Practice introduced by
The property id does not exist on Suricate\DBObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
88
        $this->assertFalse(isset($testDBO->undefVar));
0 ignored issues
show
Bug Best Practice introduced by
The property undefVar does not exist on Suricate\DBObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
89
    }
90
91
    public function testIsLoaded()
92
    {
93
        $testIndex = 'id';
94
95
        $testDBO = new \Suricate\DBObject();
96
        self::mockProperty($testDBO, 'tableIndex', $testIndex);
97
        self::mockProperty($testDBO, 'dbVariables', [$testIndex, 'name', 'not_loaded_var']);
98
        $this->assertFalse($testDBO->isLoaded());
99
100
        self::mockProperty($testDBO, 'dbValues', [$testIndex => 1, 'name' => 'test name']);
101
        $this->assertFalse($testDBO->isLoaded());
102
103
        $this->setupData();
104
        $dbo = $this->getDBOject();
105
        $this->assertFalse($dbo->isLoaded());
106
        $dbo->load(1);
107
        $this->assertTrue($dbo->isLoaded());
108
        $dbo->load(999);
109
        $this->assertFalse($dbo->isLoaded());
110
    }
111
112
    public function testInstanciate()
113
    {
114
        $testDBO = Category::instanciate([
115
            'id' => 1,
116
            'name' => 'test record',
117
        ]);
118
119
        $reflector = new ReflectionClass(Category::class);
120
        $property = $reflector->getProperty('dbValues');
121
        $property->setAccessible(true);
122
        $this->assertEquals([
123
            'id' => 1,
124
            'name' => 'test record',
125
        ], $property->getValue($testDBO));
126
127
        $this->assertFalse($testDBO->isLoaded());
128
    }
129
130
    public function testHydrate()
131
    {
132
        $testDBO = new \Suricate\DBObject();
133
        $testDBO->realProperty = '';
0 ignored issues
show
Bug Best Practice introduced by
The property realProperty does not exist on Suricate\DBObject. Since you implemented __set, consider adding a @property annotation.
Loading history...
134
135
        self::mockProperty($testDBO, 'dbVariables', ['id', 'name']);
136
        $testDBO->hydrate([
137
            'id' => 1,
138
            'name' => 'test record',
139
            'add_column' => 'test value',
140
            'realProperty' => 'my string',
141
        ]);
142
143
        $this->assertEquals($testDBO->realProperty, 'my string');
0 ignored issues
show
Bug Best Practice introduced by
The property realProperty does not exist on Suricate\DBObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
144
145
        $reflector = new ReflectionClass(get_class($testDBO));
146
        $property = $reflector->getProperty('dbValues');
147
        $property->setAccessible(true);
148
        $this->assertEquals([
149
            'id' => 1,
150
            'name' => 'test record',
151
        ], $property->getValue($testDBO));
152
153
        $this->assertFalse($testDBO->isLoaded());
154
    }
155
156
    public function testWakeup()
157
    {
158
        $mock = $this->getMockBuilder(\Suricate\DBObject::class)
159
            ->setMethods(['setRelations'])
160
            ->getMock();
161
162
        $mock
163
            ->expects($this->once())
164
            ->method('setRelations');
165
        
166
        $mock->__wakeup();
0 ignored issues
show
Bug introduced by
The method __wakeup() does not exist on PHPUnit\Framework\MockObject\MockObject. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

166
        $mock->/** @scrutinizer ignore-call */ 
167
               __wakeup();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
167
    }
168
169
    public function testRelations()
170
    {
171
        $relations = [
172
            'category' => [
173
                'type' => \Suricate\DBObject::RELATION_ONE_ONE,
174
                'source' => 'category_id',
175
                'target' => 'Category'
176
            ]
177
        ];
178
        // Prepare database
179
        $this->setupData();
180
        $mock = $this->getMockBuilder(\Suricate\DBObject::class)
181
            ->setMethods(['setRelations', 'getRelation'])
182
            ->getMock();
183
184
        // Prepare setup DBObject
185
        $testDBO = $this->getDBOject();
186
        $reflector = new ReflectionClass($mock);
187
        $property = $reflector->getProperty('relations');
188
        $property->setAccessible(true);
189
        $property->setValue($testDBO, $relations);
190
191
        // get relation values
192
        $reflector = new ReflectionClass($testDBO);
193
        $relationValuesRef = $reflector->getProperty('relationValues');
194
        $relationValuesRef->setAccessible(true);
195
196
        $loadedRelationsRef = $reflector->getProperty('loadedRelations');
197
        $loadedRelationsRef->setAccessible(true);
198
199
        // Load
200
        $testDBO->load(1);
201
        $relationsValues = $relationValuesRef->getValue($testDBO);
202
        $loadedRelations = $loadedRelationsRef->getValue($testDBO);
203
204
        // No relation values at first
205
        $this->assertSame([], $relationsValues);
206
        $this->assertSame([], $loadedRelations);
207
        $this->assertEquals('Admin', $testDBO->category->name);
0 ignored issues
show
Bug Best Practice introduced by
The property category does not exist on Suricate\DBObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
208
        $this->assertInstanceOf('\Suricate\DBObject', $testDBO->category);
209
210
211
        $relationsValues = $relationValuesRef->getValue($testDBO);
212
        $loadedRelations = $loadedRelationsRef->getValue($testDBO);
213
214
        // Check relation cache has been set
215
        $this->assertArrayHasKey('category', $relationsValues);
216
217
        // Check relation loaded flag has been set
218
        $this->assertArrayHasKey('category', $loadedRelations);
219
220
        // Check return type of relation
221
        $this->assertInstanceOf('\Suricate\DBObject', $relationsValues['category']);
222
223
        // Load new object
224
        $testDBO = $this->getDBOject();
225
        $reflector = new ReflectionClass($mock);
226
        $property = $reflector->getProperty('relations');
227
        $property->setAccessible(true);
228
        $property->setValue($testDBO, $relations);
229
        $testDBO->load(2);
230
        // get relation values
231
        $reflector = new ReflectionClass($testDBO);
232
        $relationValuesRef = $reflector->getProperty('relationValues');
233
        $relationValuesRef->setAccessible(true);
234
235
        $loadedRelationsRef = $reflector->getProperty('loadedRelations');
236
        $loadedRelationsRef->setAccessible(true);
237
238
        $relationsValues = $relationValuesRef->getValue($testDBO);
239
        $loadedRelations = $loadedRelationsRef->getValue($testDBO);
240
241
        // No relation values at first
242
        $this->assertSame([], $relationsValues);
243
        $this->assertSame([], $loadedRelations);
244
245
        // Isset implicit load relation, check that's been loaded
246
        $this->assertTrue(isset($testDBO->category));
247
    }
248
249
    public function testLoad()
250
    {
251
        // Prepare database
252
        $this->setupData();
253
254
        // Inject database handler
255
        $testDBO = $this->getDBOject();
256
257
        $this->assertFalse($testDBO->isLoaded());
258
        $retVal = $testDBO->load(1);
259
        $this->assertTrue($testDBO->isLoaded());
260
        $this->assertEquals(1, $testDBO->id);
0 ignored issues
show
Bug Best Practice introduced by
The property id does not exist on Suricate\DBObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
261
262
        $this->assertEquals('John', $testDBO->name);
0 ignored issues
show
Bug Best Practice introduced by
The property name does not exist on Suricate\DBObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
263
        
264
        $this->assertInstanceOf('\Suricate\DBObject', $retVal);
265
    }
266
267
    public function testLoadFromSQL()
268
    {
269
        // Prepare database
270
        $this->setupData();
271
272
        // Inject database handler
273
        $testDBO = $this->getDBOject();
274
275
        $sql = "SELECT * FROM `users` WHERE id=:id";
276
        $params = ['id' => 1];
277
        
278
        $retVal = $testDBO->loadFromSql($sql, $params);
279
        $this->assertInstanceOf('\Suricate\DBObject', $retVal);
280
        $this->assertTrue($testDBO->isLoaded());
281
282
        $params = ['id' => 100];
283
        $retVal = $testDBO->loadFromSql($sql, $params);
284
        $this->assertFalse($retVal);
285
        $this->assertFalse($testDBO->isLoaded());
286
    }
287
288
    public function testLoadOrFail()
289
    {
290
        // Prepare database
291
        $this->setupData();
292
293
        // Inject database handler
294
        $testDBO = $this->getDBOject();
295
296
        
297
        $retVal = $testDBO->loadOrFail(1);
298
        $this->assertInstanceOf('\Suricate\DBObject', $retVal);
299
300
        $this->expectException(\Suricate\Exception\ModelNotFoundException::class);
301
        $testDBO->loadOrFail(100);
302
    }
303
304
    public function testLoadOrInstanciate()
305
    {
306
        // Prepare database
307
        $this->setupData();
308
309
        $testDBO = Category::loadOrInstanciate(100);
310
311
        $comparison = $this->getCategoryDBOject();
312
        $comparison->load(100);
313
314
        $this->assertInstanceOf('\Suricate\DBObject', $testDBO);
315
        $this->assertInstanceOf('Category', $testDBO);
316
317
        $this->assertSame($comparison->id, $testDBO->id);
0 ignored issues
show
Bug Best Practice introduced by
The property id does not exist on Suricate\DBObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
318
        $this->assertSame($comparison->name, $testDBO->name);
0 ignored issues
show
Bug Best Practice introduced by
The property name does not exist on Suricate\DBObject. Since you implemented __get, consider adding a @property annotation.
Loading history...
319
        $this->assertTrue($testDBO->isLoaded());
320
321
        // non existing
322
        $testDBO = Category::loadOrInstanciate(102);
323
        $this->assertFalse($testDBO->isLoaded());
324
        $this->assertSame($testDBO->id, "102");
325
        $this->assertSame($testDBO->name, null);
326
327
        $testDBO = Category::loadOrInstanciate(['id' => 102, 'name' => 'test name']);
328
        $this->assertFalse($testDBO->isLoaded());
329
        $this->assertSame($testDBO->id, "102");
330
        $this->assertSame($testDBO->name, 'test name');
331
332
        $testDBO = Category::loadOrInstanciate(['id' => 101, 'name' => 'test name']);
333
        $this->assertFalse($testDBO->isLoaded());
334
        $this->assertSame($testDBO->id, "101");
335
        $this->assertSame($testDBO->name, 'test name');
336
337
        $testDBO = Category::loadOrInstanciate(['id' => 101, 'name' => 'Employee']);
338
        $this->assertTrue($testDBO->isLoaded());
339
        $this->assertSame($testDBO->id, "101");
340
        $this->assertSame($testDBO->name, 'Employee');
341
        
342
    }
343
344
345
    public function testToArray()
346
    {
347
        // Prepare database
348
        $this->setupData();
349
350
        // Inject database handler
351
        $testDBO = $this->getDBOject();
352
        $testDBO->load(2);
353
        
354
        $this->assertSame([
355
            'id' => '2',
356
            'category_id' => '100',
357
            'name' => 'Paul',
358
            'date_added' => '2019-01-11 00:00:00',
359
            ],
360
            $testDBO->toArray()
361
        );
362
363
        $testDBO = $this->getDBOject();
364
        $testDBO->load(2);
365
        self::mockProperty($testDBO, 'exportedVariables', [
366
            'id' => 'id', 
367
            'category_id' => 'category_id,type:integer',
368
            'name' => ',omitempty',
369
            'date_added' => '-']
370
        );
371
        $testDBO->name = '';
0 ignored issues
show
Bug Best Practice introduced by
The property name does not exist on Suricate\DBObject. Since you implemented __set, consider adding a @property annotation.
Loading history...
372
373
        $this->assertSame([
374
            'id' => '2',
375
            'category_id' => 100,
376
            ],
377
            $testDBO->toArray()
378
        );
379
    }
380
381
    public function testToJson()
382
    {
383
        // Prepare database
384
        $this->setupData();
385
386
        // Inject database handler
387
        $testDBO = $this->getDBOject();
388
        $testDBO->load(2);
389
390
        $this->assertSame(
391
            '{"id":"2","category_id":"100","name":"Paul","date_added":"2019-01-11 00:00:00"}',
392
            $testDBO->toJson()
393
        );
394
    }
395
396
    public static function mockProperty($object, string $propertyName, $value)
397
    {
398
        $reflectionClass = new \ReflectionClass($object);
399
400
        $property = $reflectionClass->getProperty($propertyName);
401
        $property->setAccessible(true);
402
        $property->setValue($object, $value);
403
        $property->setAccessible(false);
404
    }
405
406
    protected function setupData()
407
    {
408
        $pdo = new PDO('sqlite:/tmp/test.db');
409
        $pdo->exec("DROP TABLE IF EXISTS `users`");
410
        $pdo->exec("DROP TABLE IF EXISTS `categories`");
411
        $pdo->exec("CREATE TABLE `users` (`id` INTEGER PRIMARY KEY,`category_id` INTEGER, `name` varchar(50) DEFAULT NULL,`date_added` datetime NOT NULL)");
412
        $pdo->exec("CREATE TABLE `categories` (`id` INTEGER PRIMARY KEY, `name` varchar(50) DEFAULT NULL)");
413
        
414
        $stmt = $pdo->prepare("INSERT INTO `users` (name, category_id, date_added) VALUES (:name, :categoryid, :date)");
415
        $values = [
416
            ['John', 100, '2019-01-10 00:00:00'],
417
            ['Paul', 100, '2019-01-11 00:00:00'],
418
            ['Robert', 101, '2019-01-12 00:00:00']
419
        ];
420
        foreach ($values as $value) {
421
            $stmt->execute(['name' => $value[0], 'categoryid' => $value[1], 'date' => $value[2]]);
422
        }
423
424
        $stmt = $pdo->prepare("INSERT INTO `categories` (id, name) VALUES (:id, :name)");
425
        $values = [
426
            [100, 'Admin'],
427
            [101, 'Employee']
428
        ];
429
        foreach ($values as $value) {
430
            $stmt->execute(['id' => $value[0], 'name' => $value[1]]);
431
        }
432
    }
433
434
    protected function getDatabase()
435
    {
436
        $database = new \Suricate\Database();
437
        $database->configure([
438
            'type' => 'sqlite',
439
            'file' => '/tmp/test.db',
440
        ]);
441
442
        return $database;
443
    }
444
445
    protected function getDBOject()
446
    {
447
        $dbLink = $this->getDatabase();
448
        // Inject database handler
449
        $testDBO = new \Suricate\DBObject();
450
451
452
        $reflector = new ReflectionClass(get_class($testDBO));
453
        $property = $reflector->getProperty('dbLink');
454
        $property->setAccessible(true);
455
        $property->setValue($testDBO, $dbLink);
456
457
        self::mockProperty($testDBO, 'tableName', $this->tableName);
458
        self::mockProperty($testDBO, 'tableIndex', 'id');
459
        self::mockProperty($testDBO, 'dbVariables', ['id', 'category_id', 'name', 'date_added']);
460
461
        return $testDBO;
462
    }
463
464
    protected function getCategoryDBOject()
465
    {
466
        $dbLink = $this->getDatabase();
467
        // Inject database handler
468
        $testDBO = new \Suricate\DBObject();
469
470
471
        $reflector = new ReflectionClass(get_class($testDBO));
472
        $property = $reflector->getProperty('dbLink');
473
        $property->setAccessible(true);
474
        $property->setValue($testDBO, $dbLink);
475
476
        self::mockProperty($testDBO, 'tableName', 'categories');
477
        self::mockProperty($testDBO, 'tableIndex', 'id');
478
        self::mockProperty($testDBO, 'dbVariables', ['id','name']);
479
480
        return $testDBO;
481
    }
482
}
483