Subversion Repositories SmartDukaan

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
16591 anikendra 1
<?php
2
/**
3
 * DboSqliteTest file
4
 *
5
 * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
6
 * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
7
 *
8
 * Licensed under The MIT License
9
 * For full copyright and license information, please see the LICENSE.txt
10
 * Redistributions of files must retain the above copyright notice.
11
 *
12
 * @copyright     Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
13
 * @link          http://cakephp.org CakePHP(tm) Project
14
 * @package       Cake.Test.Case.Model.Datasource.Database
15
 * @since         CakePHP(tm) v 1.2.0
16
 * @license       http://www.opensource.org/licenses/mit-license.php MIT License
17
 */
18
 
19
App::uses('Model', 'Model');
20
App::uses('AppModel', 'Model');
21
App::uses('Sqlite', 'Model/Datasource/Database');
22
 
23
require_once dirname(dirname(dirname(__FILE__))) . DS . 'models.php';
24
 
25
/**
26
 * DboSqliteTestDb class
27
 *
28
 * @package       Cake.Test.Case.Model.Datasource.Database
29
 */
30
class DboSqliteTestDb extends Sqlite {
31
 
32
/**
33
 * simulated property
34
 *
35
 * @var array
36
 */
37
	public $simulated = array();
38
 
39
/**
40
 * execute method
41
 *
42
 * @param mixed $sql
43
 * @return void
44
 */
45
	protected function _execute($sql, $params = array(), $prepareOptions = array()) {
46
		$this->simulated[] = $sql;
47
		return null;
48
	}
49
 
50
/**
51
 * getLastQuery method
52
 *
53
 * @return void
54
 */
55
	public function getLastQuery() {
56
		return $this->simulated[count($this->simulated) - 1];
57
	}
58
 
59
}
60
 
61
/**
62
 * DboSqliteTest class
63
 *
64
 * @package       Cake.Test.Case.Model.Datasource.Database
65
 */
66
class SqliteTest extends CakeTestCase {
67
 
68
/**
69
 * Do not automatically load fixtures for each test, they will be loaded manually using CakeTestCase::loadFixtures
70
 *
71
 * @var bool
72
 */
73
	public $autoFixtures = false;
74
 
75
/**
76
 * Fixtures
77
 *
78
 * @var object
79
 */
80
	public $fixtures = array('core.user', 'core.uuid', 'core.datatype');
81
 
82
/**
83
 * Actual DB connection used in testing
84
 *
85
 * @var DboSource
86
 */
87
	public $Dbo = null;
88
 
89
/**
90
 * Sets up a Dbo class instance for testing
91
 *
92
 * @return void
93
 */
94
	public function setUp() {
95
		parent::setUp();
96
		Configure::write('Cache.disable', true);
97
		$this->Dbo = ConnectionManager::getDataSource('test');
98
		if (!$this->Dbo instanceof Sqlite) {
99
			$this->markTestSkipped('The Sqlite extension is not available.');
100
		}
101
	}
102
 
103
/**
104
 * Sets up a Dbo class instance for testing
105
 *
106
 * @return void
107
 */
108
	public function tearDown() {
109
		parent::tearDown();
110
		Configure::write('Cache.disable', false);
111
	}
112
 
113
/**
114
 * Tests that SELECT queries from DboSqlite::listSources() are not cached
115
 *
116
 * @return void
117
 */
118
	public function testTableListCacheDisabling() {
119
		$this->assertFalse(in_array('foo_test', $this->Dbo->listSources()));
120
 
121
		$this->Dbo->query('CREATE TABLE foo_test (test VARCHAR(255))');
122
		$this->assertTrue(in_array('foo_test', $this->Dbo->listSources()));
123
 
124
		$this->Dbo->cacheSources = false;
125
		$this->Dbo->query('DROP TABLE foo_test');
126
		$this->assertFalse(in_array('foo_test', $this->Dbo->listSources()));
127
	}
128
 
129
/**
130
 * test Index introspection.
131
 *
132
 * @return void
133
 */
134
	public function testIndex() {
135
		$name = $this->Dbo->fullTableName('with_a_key', false, false);
136
		$this->Dbo->query('CREATE TABLE ' . $name . ' ("id" int(11) PRIMARY KEY, "bool" int(1), "small_char" varchar(50), "description" varchar(40) );');
137
		$this->Dbo->query('CREATE INDEX pointless_bool ON ' . $name . '("bool")');
138
		$this->Dbo->query('CREATE UNIQUE INDEX char_index ON ' . $name . '("small_char")');
139
		$expected = array(
140
			'PRIMARY' => array('column' => 'id', 'unique' => 1),
141
			'pointless_bool' => array('column' => 'bool', 'unique' => 0),
142
			'char_index' => array('column' => 'small_char', 'unique' => 1),
143
 
144
		);
145
		$result = $this->Dbo->index($name);
146
		$this->assertEquals($expected, $result);
147
		$this->Dbo->query('DROP TABLE ' . $name);
148
 
149
		$this->Dbo->query('CREATE TABLE ' . $name . ' ("id" int(11) PRIMARY KEY, "bool" int(1), "small_char" varchar(50), "description" varchar(40) );');
150
		$this->Dbo->query('CREATE UNIQUE INDEX multi_col ON ' . $name . '("small_char", "bool")');
151
		$expected = array(
152
			'PRIMARY' => array('column' => 'id', 'unique' => 1),
153
			'multi_col' => array('column' => array('small_char', 'bool'), 'unique' => 1),
154
		);
155
		$result = $this->Dbo->index($name);
156
		$this->assertEquals($expected, $result);
157
		$this->Dbo->query('DROP TABLE ' . $name);
158
	}
159
 
160
/**
161
 * Tests that cached table descriptions are saved under the sanitized key name
162
 *
163
 * @return void
164
 */
165
	public function testCacheKeyName() {
166
		Configure::write('Cache.disable', false);
167
 
168
		$dbName = 'db' . rand() . '$(*%&).db';
169
		$this->assertFalse(file_exists(TMP . $dbName));
170
 
171
		$db = new Sqlite(array_merge($this->Dbo->config, array('database' => TMP . $dbName)));
172
		$this->assertTrue(file_exists(TMP . $dbName));
173
 
174
		$db->execute("CREATE TABLE test_list (id VARCHAR(255));");
175
 
176
		$db->cacheSources = true;
177
		$this->assertEquals(array('test_list'), $db->listSources());
178
		$db->cacheSources = false;
179
 
180
		$fileName = '_' . preg_replace('/[^A-Za-z0-9_\-+]/', '_', TMP . $dbName) . '_list';
181
 
182
		$result = Cache::read($fileName, '_cake_model_');
183
		$this->assertEquals(array('test_list'), $result);
184
 
185
		Cache::delete($fileName, '_cake_model_');
186
		Configure::write('Cache.disable', true);
187
	}
188
 
189
/**
190
 * test building columns with SQLite
191
 *
192
 * @return void
193
 */
194
	public function testBuildColumn() {
195
		$data = array(
196
			'name' => 'int_field',
197
			'type' => 'integer',
198
			'null' => false,
199
		);
200
		$result = $this->Dbo->buildColumn($data);
201
		$expected = '"int_field" integer NOT NULL';
202
		$this->assertEquals($expected, $result);
203
 
204
		$data = array(
205
			'name' => 'name',
206
			'type' => 'string',
207
			'length' => 20,
208
			'null' => false,
209
		);
210
		$result = $this->Dbo->buildColumn($data);
211
		$expected = '"name" varchar(20) NOT NULL';
212
		$this->assertEquals($expected, $result);
213
 
214
		$data = array(
215
			'name' => 'testName',
216
			'type' => 'string',
217
			'length' => 20,
218
			'default' => null,
219
			'null' => true,
220
			'collate' => 'NOCASE'
221
		);
222
		$result = $this->Dbo->buildColumn($data);
223
		$expected = '"testName" varchar(20) DEFAULT NULL COLLATE NOCASE';
224
		$this->assertEquals($expected, $result);
225
 
226
		$data = array(
227
			'name' => 'testName',
228
			'type' => 'string',
229
			'length' => 20,
230
			'default' => 'test-value',
231
			'null' => false,
232
		);
233
		$result = $this->Dbo->buildColumn($data);
234
		$expected = '"testName" varchar(20) DEFAULT \'test-value\' NOT NULL';
235
		$this->assertEquals($expected, $result);
236
 
237
		$data = array(
238
			'name' => 'testName',
239
			'type' => 'integer',
240
			'length' => 10,
241
			'default' => 10,
242
			'null' => false,
243
		);
244
		$result = $this->Dbo->buildColumn($data);
245
		$expected = '"testName" integer(10) DEFAULT 10 NOT NULL';
246
		$this->assertEquals($expected, $result);
247
 
248
		$data = array(
249
			'name' => 'testName',
250
			'type' => 'integer',
251
			'length' => 10,
252
			'default' => 10,
253
			'null' => false,
254
			'collate' => 'BADVALUE'
255
		);
256
		$result = $this->Dbo->buildColumn($data);
257
		$expected = '"testName" integer(10) DEFAULT 10 NOT NULL';
258
		$this->assertEquals($expected, $result);
259
 
260
		$data = array(
261
			'name' => 'huge',
262
			'type' => 'biginteger',
263
			'length' => 20,
264
			'null' => false,
265
		);
266
		$result = $this->Dbo->buildColumn($data);
267
		$expected = '"huge" bigint(20) NOT NULL';
268
		$this->assertEquals($expected, $result);
269
 
270
		$data = array(
271
			'name' => 'id',
272
			'type' => 'biginteger',
273
			'length' => 20,
274
			'null' => false,
275
			'key' => 'primary',
276
		);
277
		$result = $this->Dbo->buildColumn($data);
278
		$expected = '"id" bigint(20) NOT NULL PRIMARY KEY';
279
		$this->assertEquals($expected, $result);
280
	}
281
 
282
/**
283
 * test describe() and normal results.
284
 *
285
 * @return void
286
 */
287
	public function testDescribe() {
288
		$this->loadFixtures('User');
289
		$Model = new Model(array(
290
			'name' => 'User',
291
			'ds' => 'test',
292
			'table' => 'users'
293
		));
294
 
295
		$this->Dbo->cacheSources = true;
296
		Configure::write('Cache.disable', false);
297
 
298
		$result = $this->Dbo->describe($Model);
299
		$expected = array(
300
			'id' => array(
301
				'type' => 'integer',
302
				'key' => 'primary',
303
				'null' => false,
304
				'default' => null,
305
				'length' => 11
306
			),
307
			'user' => array(
308
				'type' => 'string',
309
				'length' => 255,
310
				'null' => true,
311
				'default' => null
312
			),
313
			'password' => array(
314
				'type' => 'string',
315
				'length' => 255,
316
				'null' => true,
317
				'default' => null
318
			),
319
			'created' => array(
320
				'type' => 'datetime',
321
				'null' => true,
322
				'default' => null,
323
				'length' => null,
324
			),
325
			'updated' => array(
326
				'type' => 'datetime',
327
				'null' => true,
328
				'default' => null,
329
				'length' => null,
330
			)
331
		);
332
		$this->assertEquals($expected, $result);
333
 
334
		$result = $this->Dbo->describe($Model->useTable);
335
		$this->assertEquals($expected, $result);
336
 
337
		$result = Cache::read('test_users', '_cake_model_');
338
		$this->assertEquals($expected, $result);
339
	}
340
 
341
/**
342
 * Test that datatypes are reflected
343
 *
344
 * @return void
345
 */
346
	public function testDatatypes() {
347
		$this->loadFixtures('Datatype');
348
		$Model = new Model(array(
349
			'name' => 'Datatype',
350
			'ds' => 'test',
351
			'table' => 'datatypes'
352
		));
353
		$result = $this->Dbo->describe($Model);
354
		$expected = array(
355
			'id' => array(
356
				'type' => 'integer',
357
				'null' => false,
358
				'default' => '',
359
				'length' => 11,
360
				'key' => 'primary',
361
			),
362
			'float_field' => array(
363
				'type' => 'float',
364
				'null' => false,
365
				'default' => '',
366
				'length' => '5,2',
367
			),
368
			'decimal_field' => array(
369
				'type' => 'decimal',
370
				'null' => true,
371
				'default' => '0.000',
372
				'length' => '6,3',
373
			),
374
			'huge_int' => array(
375
				'type' => 'biginteger',
376
				'null' => true,
377
				'default' => null,
378
				'length' => 20,
379
			),
380
			'bool' => array(
381
				'type' => 'boolean',
382
				'null' => false,
383
				'default' => '0',
384
				'length' => null
385
			),
386
		);
387
		$this->assertSame($expected, $result);
388
	}
389
 
390
/**
391
 * test that describe does not corrupt UUID primary keys
392
 *
393
 * @return void
394
 */
395
	public function testDescribeWithUuidPrimaryKey() {
396
		$tableName = 'uuid_tests';
397
		$this->Dbo->query("CREATE TABLE {$tableName} (id VARCHAR(36) PRIMARY KEY, name VARCHAR, created DATETIME, modified DATETIME)");
398
		$Model = new Model(array('name' => 'UuidTest', 'ds' => 'test', 'table' => 'uuid_tests'));
399
		$result = $this->Dbo->describe($Model);
400
		$expected = array(
401
			'type' => 'string',
402
			'length' => 36,
403
			'null' => false,
404
			'default' => null,
405
			'key' => 'primary',
406
		);
407
		$this->assertEquals($expected, $result['id']);
408
		$this->Dbo->query('DROP TABLE ' . $tableName);
409
 
410
		$tableName = 'uuid_tests';
411
		$this->Dbo->query("CREATE TABLE {$tableName} (id CHAR(36) PRIMARY KEY, name VARCHAR, created DATETIME, modified DATETIME)");
412
		$Model = new Model(array('name' => 'UuidTest', 'ds' => 'test', 'table' => 'uuid_tests'));
413
		$result = $this->Dbo->describe($Model);
414
		$expected = array(
415
			'type' => 'string',
416
			'length' => 36,
417
			'null' => false,
418
			'default' => null,
419
			'key' => 'primary',
420
		);
421
		$this->assertEquals($expected, $result['id']);
422
		$this->Dbo->query('DROP TABLE ' . $tableName);
423
	}
424
 
425
/**
426
 * Test virtualFields with functions.
427
 *
428
 * @return void
429
 */
430
	public function testVirtualFieldWithFunction() {
431
		$this->loadFixtures('User');
432
		$User = ClassRegistry::init('User');
433
		$User->virtualFields = array('name' => 'SUBSTR(User.user, 5, LENGTH(User.user) - 4)');
434
 
435
		$result = $User->find('first', array(
436
			'conditions' => array('User.user' => 'garrett')
437
		));
438
		$this->assertEquals('ett', $result['User']['name']);
439
	}
440
 
441
/**
442
 * Test that records can be inserted with UUID primary keys, and
443
 * that the primary key is not blank
444
 *
445
 * @return void
446
 */
447
	public function testUuidPrimaryKeyInsertion() {
448
		$this->loadFixtures('Uuid');
449
		$Model = ClassRegistry::init('Uuid');
450
 
451
		$data = array(
452
			'title' => 'A UUID should work',
453
			'count' => 10
454
		);
455
		$Model->create($data);
456
		$this->assertTrue((bool)$Model->save());
457
		$result = $Model->read();
458
 
459
		$this->assertEquals($data['title'], $result['Uuid']['title']);
460
		$this->assertTrue(Validation::uuid($result['Uuid']['id']), 'Not a UUID');
461
	}
462
 
463
/**
464
 * Test nested transaction
465
 *
466
 * @return void
467
 */
468
	public function testNestedTransaction() {
469
		$this->skipIf($this->Dbo->nestedTransactionSupported() === false, 'The Sqlite version do not support nested transaction');
470
 
471
		$this->loadFixtures('User');
472
		$model = new User();
473
		$model->hasOne = $model->hasMany = $model->belongsTo = $model->hasAndBelongsToMany = array();
474
		$model->cacheQueries = false;
475
		$this->Dbo->cacheMethods = false;
476
 
477
		$this->assertTrue($this->Dbo->begin());
478
		$this->assertNotEmpty($model->read(null, 1));
479
 
480
		$this->assertTrue($this->Dbo->begin());
481
		$this->assertTrue($model->delete(1));
482
		$this->assertEmpty($model->read(null, 1));
483
		$this->assertTrue($this->Dbo->rollback());
484
		$this->assertNotEmpty($model->read(null, 1));
485
 
486
		$this->assertTrue($this->Dbo->begin());
487
		$this->assertTrue($model->delete(1));
488
		$this->assertEmpty($model->read(null, 1));
489
		$this->assertTrue($this->Dbo->commit());
490
		$this->assertEmpty($model->read(null, 1));
491
 
492
		$this->assertTrue($this->Dbo->rollback());
493
		$this->assertNotEmpty($model->read(null, 1));
494
	}
495
 
496
/**
497
 * Test the limit function.
498
 *
499
 * @return void
500
 */
501
	public function testLimit() {
502
		$db = $this->Dbo;
503
 
504
		$result = $db->limit('0');
505
		$this->assertNull($result);
506
 
507
		$result = $db->limit('10');
508
		$this->assertEquals(' LIMIT 10', $result);
509
 
510
		$result = $db->limit('FARTS', 'BOOGERS');
511
		$this->assertEquals(' LIMIT 0 OFFSET 0', $result);
512
 
513
		$result = $db->limit(20, 10);
514
		$this->assertEquals(' LIMIT 20 OFFSET 10', $result);
515
 
516
		$result = $db->limit(10, 300000000000000000000000000000);
517
		$scientificNotation = sprintf('%.1E', 300000000000000000000000000000);
518
		$this->assertNotContains($scientificNotation, $result);
519
	}
520
 
521
/**
522
 * Test that fields are parsed out in a reasonable fashion.
523
 *
524
 * @return void
525
 */
526
	public function testFetchRowColumnParsing() {
527
		$this->loadFixtures('User');
528
		$sql = 'SELECT "User"."id", "User"."user", "User"."password", "User"."created", (1 + 1) AS "two" ' .
529
			'FROM "users" AS "User" WHERE ' .
530
			'"User"."id" IN (SELECT MAX("id") FROM "users") ' .
531
			'OR "User.id" IN (5, 6, 7, 8)';
532
		$result = $this->Dbo->fetchRow($sql);
533
 
534
		$expected = array(
535
			'User' => array(
536
				'id' => 4,
537
				'user' => 'garrett',
538
				'password' => '5f4dcc3b5aa765d61d8327deb882cf99',
539
				'created' => '2007-03-17 01:22:23'
540
			),
541
 
542
				'two' => 2
543
			)
544
		);
545
		$this->assertEquals($expected, $result);
546
 
547
		$sql = 'SELECT "User"."id", "User"."user" ' .
548
			'FROM "users" AS "User" WHERE "User"."id" = 4 ' .
549
			'UNION ' .
550
			'SELECT "User"."id", "User"."user" ' .
551
			'FROM "users" AS "User" WHERE "User"."id" = 3';
552
		$result = $this->Dbo->fetchRow($sql);
553
 
554
		$expected = array(
555
			'User' => array(
556
				'id' => 3,
557
				'user' => 'larry',
558
			),
559
		);
560
		$this->assertEquals($expected, $result);
561
	}
562
 
563
/**
564
 * Test parsing more complex field names.
565
 *
566
 * @return void
567
 */
568
	public function testFetchColumnRowParsingMoreComplex() {
569
		$this->loadFixtures('User');
570
		$sql = 'SELECT
571
			COUNT(*) AS User__count,
572
			COUNT(CASE id WHEN 2 THEN 1 ELSE NULL END) as User__case,
573
			AVG(CAST("User"."id" AS BIGINT)) AS User__bigint
574
			FROM "users" AS "User"
575
			WHERE "User"."id" > 0';
576
		$result = $this->Dbo->fetchRow($sql);
577
 
578
		$expected = array(
579
			'0' => array(
580
				'User__count' => '4',
581
				'User__case' => '1',
582
				'User__bigint' => '2.5',
583
			),
584
		);
585
		$this->assertEquals($expected, $result);
586
	}
587
 
588
}