diff options
author | Angie Byron <webchick@24967.no-reply.drupal.org> | 2008-08-31 11:43:41 +0000 |
---|---|---|
committer | Angie Byron <webchick@24967.no-reply.drupal.org> | 2008-08-31 11:43:41 +0000 |
commit | 382f4a8c5fc7d60dd1b27f204db16947f6198c16 (patch) | |
tree | dd28a5320ad77562b0a6a625a23026d7a50a74d2 | |
parent | df4b23bfee6f6db2226da06e937687b187b521c5 (diff) | |
download | brdo-382f4a8c5fc7d60dd1b27f204db16947f6198c16.tar.gz brdo-382f4a8c5fc7d60dd1b27f204db16947f6198c16.tar.bz2 |
#276276 by Crell and florbuit: New database system unit tests. WOOHOO! :D
-rw-r--r-- | modules/simpletest/tests/database_test.info | 8 | ||||
-rw-r--r-- | modules/simpletest/tests/database_test.install | 168 | ||||
-rw-r--r-- | modules/simpletest/tests/database_test.module | 38 | ||||
-rw-r--r-- | modules/simpletest/tests/database_test.test | 1535 |
4 files changed, 1749 insertions, 0 deletions
diff --git a/modules/simpletest/tests/database_test.info b/modules/simpletest/tests/database_test.info new file mode 100644 index 000000000..406dfbbcb --- /dev/null +++ b/modules/simpletest/tests/database_test.info @@ -0,0 +1,8 @@ +; $Id$ +name = "Database Test" +description = "Support module for Database layer tests." +core = 7.x +package = Testing +files[] = database_test.module +version = VERSION +hidden = TRUE diff --git a/modules/simpletest/tests/database_test.install b/modules/simpletest/tests/database_test.install new file mode 100644 index 000000000..e2fcb1b77 --- /dev/null +++ b/modules/simpletest/tests/database_test.install @@ -0,0 +1,168 @@ +<?php +// $Id$ + +/** + * Implementation of hook_schema(). + * + * The database tests use the database API which depends on schema + * information for certain operations on certain databases. + * Therefore, the schema must actually be declared in a normal module + * like any other, not directly in the test file. + */ +function database_test_schema() { + $schema['test'] = array( + 'description' => 'Basic test table for the database unit tests.', + 'fields' => array( + 'id' => array( + 'type' => 'serial', + 'unsigned' => TRUE, + 'not null' => TRUE, + ), + 'name' => array( + 'description' => "A person's name", + 'type' => 'varchar', + 'length' => 255, + 'not null' => TRUE, + 'default' => '', + ), + 'age' => array( + 'description' => "The person's age", + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => TRUE, + 'default' => 0), + 'job' => array( + 'description' => "The person's job", + 'type' => 'varchar', + 'length' => 255, + 'not null' => TRUE, + 'default' => 'Undefined', + ), + ), + 'primary key' => array('id'), + 'unique keys' => array( + 'name' => array('name') + ), + 'indexes' => array( + 'ages' => array('age'), + ), + ); + + // This is an alternate version of the same table that is structured the same + // but has a non-serial Primary Key. + $schema['test_people'] = array( + 'description' => 'A duplicate version of the test table, used for additional tests.', + 'fields' => array( + 'name' => array( + 'description' => "A person's name", + 'type' => 'varchar', + 'length' => 255, + 'not null' => TRUE, + 'default' => '', + ), + 'age' => array( + 'description' => "The person's age", + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => TRUE, + 'default' => 0, + ), + 'job' => array( + 'description' => "The person's job", + 'type' => 'varchar', + 'length' => 255, + 'not null' => TRUE, + 'default' => '', + ), + ), + 'primary key' => array('job'), + 'indexes' => array( + 'ages' => array('age'), + ), + ); + + $schema['test_one_blob'] = array( + 'description' => 'A simple table including a BLOB field for testing BLOB behavior.', + 'fields' => array( + 'id' => array( + 'description' => 'Simple unique ID.', + 'type' => 'serial', + 'not null' => TRUE, + ), + 'blob1' => array( + 'description' => 'A BLOB field.', + 'type' => 'blob', + ), + ), + 'primary key' => array('id'), + ); + + $schema['test_two_blobs'] = array( + 'description' => 'A simple test table with two BLOB fields.', + 'fields' => array( + 'id' => array( + 'description' => 'Simple unique ID.', + 'type' => 'serial', + 'not null' => TRUE, + ), + 'blob1' => array( + 'description' => 'A dummy BLOB field.', + 'type' => 'blob', + ), + 'blob2' => array( + 'description' => 'A second BLOB field.', + 'type' => 'blob' + ), + ), + 'primary key' => array('id'), + ); + + $schema['test_task'] = array( + 'description' => 'A task list for people in the test table.', + 'fields' => array( + 'tid' => array( + 'description' => 'Task ID, primary key.', + 'type' => 'serial', + 'not null' => TRUE, + ), + 'pid' => array( + 'description' => 'The {test_people}.pid, foreign key for the test table.', + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => TRUE, + 'default' => 0, + ), + 'task' => array( + 'description' => 'The task to be completed.', + 'type' => 'varchar', + 'length' => 255, + 'not null' => TRUE, + 'default' => '', + ), + 'priority' => array( + 'description' => 'The priority of the task.', + 'type' => 'int', + 'unsigned' => TRUE, + 'not null' => TRUE, + 'default' => 0, + ), + ), + 'primary key' => array('tid'), + ); + + return $schema; +} + +/** + * Implementation of hook_install(). + */ +function database_test_install() { + drupal_install_schema('database_test'); +} + +/** + * Implementation of hook_uninstall(). + */ +function database_test_uninstall() { + drupal_uninstall_schema('database_test'); +} diff --git a/modules/simpletest/tests/database_test.module b/modules/simpletest/tests/database_test.module new file mode 100644 index 000000000..0b6ad2ce2 --- /dev/null +++ b/modules/simpletest/tests/database_test.module @@ -0,0 +1,38 @@ +<?php +// $Id$ + +/** + * Implementation of hook_query_alter(). + */ +function database_test_query_alter(SelectQuery $query) { + + if ($query->hasTag('database_test_alter_add_range')) { + $query->range(0, 2); + } + + if ($query->hasTag('database_test_alter_remove_range')) { + $query->range(); + } + + if ($query->hasTag('database_test_alter_add_join')) { + $people_alias = $query->join('test', 'people', "test_task.pid=people.id"); + $name_field = $query->addField('people', 'name', 'name'); + $query->condition($people_alias . '.id', 2); + } + + if ($query->hasTag('database_test_alter_change_conditional')) { + $conditions =& $query->conditions(); + $conditions[0]['value'] = 2; + } + + if ($query->hasTag('database_test_alter_change_fields')) { + $fields =& $query->getFields(); + unset($fields['age']); + } + + if ($query->hasTag('database_test_alter_change_expressions')) { + $expressions =& $query->getExpressions(); + $expressions['double_age']['expression'] = 'age*3'; + } +} + diff --git a/modules/simpletest/tests/database_test.test b/modules/simpletest/tests/database_test.test new file mode 100644 index 000000000..7272320dc --- /dev/null +++ b/modules/simpletest/tests/database_test.test @@ -0,0 +1,1535 @@ +<?php +// $Id$ + +/** + * Dummy class for fetching into a class. + * + * PDO supports using a new instance of an arbitrary class for records + * rather than just a stdClass or array. This class is for testing that + * functionality. (See testQueryFetchClass() below) + */ +class FakeRecord { } + +/** + * Base test class for databases. + * + * Because all database tests share the same test data, we can centralize that + * here. + */ +class DatabaseTestCase extends DrupalWebTestCase { + + function setUp() { + parent::setUp('database_test'); + + try { + $schema['test'] = drupal_get_schema('test'); + $schema['test_people'] = drupal_get_schema('test_people'); + $schema['test_one_blob'] = drupal_get_schema('test_one_blob'); + $schema['test_two_blobs'] = drupal_get_schema('test_two_blobs'); + $schema['test_task'] = drupal_get_schema('test_task'); + + $ret = array(); + + // This ends up being a test for table drop and create, too, which is + // nice. + foreach ($schema as $name => $data) { + if (db_table_exists($name)) { + db_drop_table($ret, $name); + } + db_create_table($ret, $name, $data); + } + + foreach ($schema as $name => $data) { + $this->assertTrue(db_table_exists($name), t('Table @name created successfully.', array('@name' => $name))); + } + + $this->addSampleData(); + } + catch (Exception $e) { + $this->assertTrue(FALSE, $e->getMessage()); + } + } + + /** + * Setup our sample data. + * + * These are added using db_query(), since we're not trying to test the + * INSERT operations here, just populate. + */ + function addSampleData() { + db_query("INSERT INTO {test} (name, age, job) VALUES ('John', 25, 'Singer')"); + $john = db_last_insert_id('test', 'id'); + db_query("INSERT INTO {test} (name, age, job) VALUES ('George', 27, 'Singer')"); + $george = db_last_insert_id('test', 'id'); + db_query("INSERT INTO {test} (name, age, job) VALUES ('Ringo', 28, 'Drummer')"); + $ringo = db_last_insert_id('test', 'id'); + db_query("INSERT INTO {test} (name, age, job) VALUES ('Paul', 26, 'Songwriter')"); + $paul = db_last_insert_id('test', 'id'); + + db_query("INSERT INTO {test_people} (name, age, job) VALUES ('Meredith', 30, 'Speaker')"); + + db_query("INSERT INTO {test_task} (pid, task, priority) VALUES (:pid, :task, :priority)", array( + ':pid' => $john, + ':task' => 'eat', + ':priority' => 3, + )); + db_query("INSERT INTO {test_task} (pid, task, priority) VALUES (:pid, :task, :priority)", array( + ':pid' => $john, + ':task' => 'sleep', + ':priority' => 4, + )); + db_query("INSERT INTO {test_task} (pid, task, priority) VALUES (:pid, :task, :priority)", array( + ':pid' => $john, + ':task' => 'code', + ':priority' => 1, + )); + db_query("INSERT INTO {test_task} (pid, task, priority) VALUES (:pid, :task, :priority)", array( + ':pid' => $george, + ':task' => 'sing', + ':priority' => 2, + )); + db_query("INSERT INTO {test_task} (pid, task, priority) VALUES (:pid, :task, :priority)", array( + ':pid' => $george, + ':task' => 'sleep', + ':priority' => 2, + )); + db_query("INSERT INTO {test_task} (pid, task, priority) VALUES (:pid, :task, :priority)", array( + ':pid' => $paul, + ':task' => 'found new band', + ':priority' => 1, + )); + db_query("INSERT INTO {test_task} (pid, task, priority) VALUES (:pid, :task, :priority)", array( + ':pid' => $paul, + ':task' => 'perform at superbowl', + ':priority' => 3, + )); + } + +} + +/** + * Test fetch actions, part 1. + * + * We get timeout errors if we try to run too many tests at once. + */ +class DatabaseFetchTestCase extends DatabaseTestCase { + + function getInfo() { + return array( + 'name' => t('Fetch tests'), + 'description' => t('Test the Database system\'s various fetch capabilities.'), + 'group' => t('Database'), + ); + } + + /** + * Confirm that we can fetch a record properly in default object mode. + */ + function testQueryFetchDefault() { + + $records = array(); + $result = db_query("SELECT name FROM {test} WHERE age = :age", array(':age' => 25)); + $this->assertTrue($result instanceof DatabaseStatement, t('Result set is a Drupal statement object.')); + foreach ($result as $record) { + $records[] = $record; + $this->assertTrue(is_object($record), t('Record is an object.')); + $this->assertIdentical($record->name, 'John', t('25 year old is John.')); + } + + $this->assertIdentical(count($records), 1, t('There is only one record.')); + } + + /** + * Confirm that we can fetch a record to an object explicitly. + */ + function testQueryFetchObject() { + $records = array(); + $result = db_query("SELECT name FROM {test} WHERE age = :age", array(':age' => 25), array('fetch' => PDO::FETCH_OBJ)); + foreach ($result as $record) { + $records[] = $record; + $this->assertTrue(is_object($record), t('Record is an object.')); + $this->assertIdentical($record->name, 'John', t('25 year old is John.')); + } + + $this->assertIdentical(count($records), 1, t('There is only one record.')); + } + + /** + * Confirm that we can fetch a record to an array associative explicitly. + */ + function testQueryFetchArray() { + $records = array(); + $result = db_query("SELECT name FROM {test} WHERE age = :age", array(':age' => 25), array('fetch' => PDO::FETCH_ASSOC)); + foreach ($result as $record) { + $records[] = $record; + if ($this->assertTrue(is_array($record), t('Record is an array.'))) { + $this->assertIdentical($record['name'], 'John', t('Record can be accessed associatively.')); + } + } + + $this->assertIdentical(count($records), 1, t('There is only one record.')); + } + + /** + * Confirm that we can fetch a record into a new instance of a custom class. + * + * @see FakeRecord + */ + function testQueryFetchClass() { + $records = array(); + $result = db_query("SELECT name FROM {test} WHERE age = :age", array(':age' => 25), array('fetch' => 'FakeRecord')); + foreach ($result as $record) { + $records[] = $record; + if ($this->assertTrue($record instanceof FakeRecord, t('Record is an object of class FakeRecord.'))) { + $this->assertIdentical($record->name, 'John', t('25 year old is John.')); + } + } + + $this->assertIdentical(count($records), 1, t('There is only one record.')); + } +} + +/** + * Test fetch actions, part 2. + * + * We get timeout errors if we try to run too many tests at once. + */ +class DatabaseFetch2TestCase extends DatabaseTestCase { + + function getInfo() { + return array( + 'name' => t('Fetch tests, Part 2'), + 'description' => t('Test the Database system\'s various fetch capabilities.'), + 'group' => t('Database'), + ); + } + + function setUp() { + parent::setUp(); + } + + // Confirm that we can fetch a record into an indexed array explicitly. + function testQueryFetchNum() { + $records = array(); + $result = db_query("SELECT name FROM {test} WHERE age = :age", array(':age' => 25), array('fetch' => PDO::FETCH_NUM)); + foreach ($result as $record) { + $records[] = $record; + if ($this->assertTrue(is_array($record), t('Record is an array.'))) { + $this->assertIdentical($record[0], 'John', t('Record can be accessed numerically.')); + } + } + + $this->assertIdentical(count($records), 1, 'There is only one record'); + } + + /** + * Confirm that we can fetch a record into a doubly-keyed array explicitly. + */ + function testQueryFetchBoth() { + $records = array(); + $result = db_query("SELECT name FROM {test} WHERE age = :age", array(':age' => 25), array('fetch' => PDO::FETCH_BOTH)); + foreach ($result as $record) { + $records[] = $record; + if ($this->assertTrue(is_array($record), t('Record is an array.'))) { + $this->assertIdentical($record[0], 'John', t('Record can be accessed numerically.')); + $this->assertIdentical($record['name'], 'John', t('Record can be accessed associatively.')); + } + } + + $this->assertIdentical(count($records), 1, t('There is only one record.')); + } + + /** + * Confirm that we can fetch an entire column of a result set at once. + */ + function testQueryFetchCol() { + $records = array(); + $result = db_query("SELECT name FROM {test} WHERE age > :age", array(':age' => 25)); + $column = $result->fetchCol(); + $this->assertIdentical(count($column), 3, t('fetchCol() returns the right number of records.')); + + + $result = db_query("SELECT name FROM {test} WHERE age > :age", array(':age' => 25)); + $i = 0; + foreach ($result as $record) { + $this->assertIdentical($record->name, $column[$i++], t('Column matches direct accesss.')); + } + } +} + +/** + * Test the insert builder. + */ +class DatabaseInsertTestCase extends DatabaseTestCase { + + function getInfo() { + return array( + 'name' => t('Insert tests'), + 'description' => t('Test the Insert query builder.'), + 'group' => t('Database'), + ); + } + + /** + * Test the very basic insert functionality. + */ + function testSimpleInsert() { + try { + $num_records_before = db_query("SELECT COUNT(*) FROM {test}")->fetchField(); + + $query = db_insert('test'); + $query->fields(array( + 'name' => 'Yoko', + 'age' => '29', + )); + $query->execute(); + + $num_records_after = db_query("SELECT COUNT(*) FROM {test}")->fetchField(); + $this->assertIdentical($num_records_before + 1, (int)$num_records_after, t('Record inserts correctly.')); + + $saved_age = db_query("SELECT age FROM {test} WHERE name = :name", array(':name' => 'Yoko'))->fetchField(); + $this->assertIdentical($saved_age, '29', t('Can retrieve after inserting.')); + } + catch (Exception $e) { + $this->assertTrue(FALSE, $e->getMessage()); + } + } + + /** + * Test that we can insert multiple records in one query object. + */ + function testMultiInsert() { + try { + $num_records_before = (int) db_query("SELECT COUNT(*) FROM {test}")->fetchField(); + + $query = db_insert('test'); + $query->fields(array( + 'name' => 'Larry', + 'age' => '30', + )); + + // We should be able to specify values in any order if named. + $query->values(array( + 'age' => '31', + 'name' => 'Curly', + )); + + // We should be able to say "use the field order". + // This is not the recommended mechanism for most cases, but it should work. + $query->values(array('Moe', '32')); + $query->execute(); + + $num_records_after = (int) db_query("SELECT COUNT(*) FROM {test}")->fetchField(); + $this->assertIdentical($num_records_before + 3, $num_records_after, t('Record inserts correctly.')); + $saved_age = db_query("SELECT age FROM {test} WHERE name = :name", array(':name' => 'Larry'))->fetchField(); + $this->assertIdentical($saved_age, '30', t('Can retrieve by name.')); + $saved_age = db_query("SELECT age FROM {test} WHERE name = :name", array(':name' => 'Curly'))->fetchField(); + $this->assertIdentical($saved_age, '31', t('Can retrieve by name.')); + $saved_age = db_query("SELECT age FROM {test} WHERE name = :name", array(':name' => 'Moe'))->fetchField(); + $this->assertIdentical($saved_age, '32', t('Can retrieve by name.')); + } + catch (Exception $e) { + $this->assertTrue(FALSE, $e->getMessage()); + } + } + + /** + * Test that an insert object can be reused with new data after it executes. + */ + function testRepeatedInsert() { + try { + $num_records_before = db_query("SELECT COUNT(*) FROM {test}")->fetchField(); + + $query = db_insert('test'); + + $query->fields(array( + 'name' => 'Larry', + 'age' => '30', + )); + $query->execute(); // This should run the insert, but leave the fields intact. + + // We should be able to specify values in any order if named. + $query->values(array( + 'age' => '31', + 'name' => 'Curly', + )); + $query->execute(); + + // We should be able to say "use the field order". + $query->values(array('Moe', '32')); + $query->execute(); + + $num_records_after = db_query("SELECT COUNT(*) FROM {test}")->fetchField(); + $this->assertIdentical((int) $num_records_before + 3, (int) $num_records_after, t('Record inserts correctly.')); + $saved_age = db_query("SELECT age FROM {test} WHERE name = :name", array(':name' => 'Larry'))->fetchField(); + $this->assertIdentical($saved_age, '30', t('Can retrieve by name.')); + $saved_age = db_query("SELECT age FROM {test} WHERE name = :name", array(':name' => 'Curly'))->fetchField(); + $this->assertIdentical($saved_age, '31', t('Can retrieve by name.')); + $saved_age = db_query("SELECT age FROM {test} WHERE name = :name", array(':name' => 'Moe'))->fetchField(); + $this->assertIdentical($saved_age, '32', t('Can retrieve by name.')); + } + catch (Exception $e) { + $this->assertTrue(FALSE, $e->getMessage()); + } + } + + /** + * Test that we can specify fields without values and specify values later. + */ + function testInsertFieldOnlyDefinintion() { + // This is useful for importers, when we want to create a query and define + // its fields once, then loop over a multi-insert execution. + db_insert('test') + ->fields(array('name', 'age')) + ->values(array('Larry', '30')) + ->values(array('Curly', '31')) + ->values(array('Moe', '32')) + ->execute(); + $saved_age = db_query("SELECT age FROM {test} WHERE name = :name", array(':name' => 'Larry'))->fetchField(); + $this->assertIdentical($saved_age, '30', t('Can retrieve after inserting.')); + } + + /** + * Test that inserts return the proper auto-increment ID. + */ + function testInsertLastInsertID() { + try { + $id = db_insert('test')->fields(array( + 'name' => 'Larry', + 'age' => '30', + )) + ->execute(); + + $this->assertIdentical($id, '5', t('Auto-increment ID returned successfully.')); + } + catch (Exception $e) { + $this->assertTrue(FALSE, $e->getMessage()); + } + } +} + +/** + * Insert tests using LOB fields, which are weird on some databases. + */ +class DatabaseInsertLOBTestCase extends DatabaseTestCase { + + function getInfo() { + return array( + 'name' => t('Insert tests, LOB fields'), + 'description' => t('Test the Insert query builder with LOB fields.'), + 'group' => t('Database'), + ); + } + + /** + * Test that we can insert a single blob field successfully. + */ + function testInsertOneBlob() { + $data = "This is\000a test."; + $this->assertTrue(strlen($data) === 15, t('Test data contains a NULL.')); + $id = db_insert('test_one_blob')->fields(array('blob1' => $data))->execute(); + $res = db_query('SELECT * FROM {test_one_blob} WHERE id = :id', array(':id' => $id)); + $r = db_fetch_array($res); + $this->assertTrue($r['blob1'] === $data, t('Can insert a blob: id @id, @data.', array('@id' => $id, '@data' => serialize($r)))); + } + + /** + * Test that we can insert multiple blob fields in the same query. + */ + function testInsertMultipleBlob() { + $id = db_insert('test_two_blobs')->fields(array( + 'blob1' => 'This is', + 'blob2' => 'a test', + )) + ->execute(); + $res = db_query('SELECT * FROM {test_two_blobs} WHERE id = %d', $id); + $r = db_fetch_array($res); + $this->assertTrue($r['blob1'] === 'This is' && $r['blob2'] === 'a test', t('Can insert multiple blobs per row.')); + } +} + +/** + * Insert tests for "database default" values. + */ +class DatabaseInsertDefaultsTestCase extends DatabaseTestCase { + + function getInfo() { + return array( + 'name' => t('Insert tests, Default fields'), + 'description' => t('Test the Insert query builder with default values.'), + 'group' => t('Database'), + ); + } + + /** + * Test that we can run a query that is "default values for everything". + */ + function testDefaultInsert() { + try { + $query = db_insert('test')->useDefaults(array('job')); + $id = $query->execute(); + + $schema = drupal_get_schema('test'); + + $job = db_query("SELECT job FROM {test} WHERE id = :id", array(':id' => $id))->fetchField(); + $this->assertEqual($job, $schema['fields']['job']['default'], t('Default field value is set.')); + } + catch (Exception $e) { + $this->assertTrue(FALSE, $e->getMessage()); + } + } + + /** + * Test that we can insert fields with values and defaults in the same query. + */ + function testDefaultInsertWithFields() { + try { + $query = db_insert('test')->fields(array('name' => 'Bob'))->useDefaults(array('job')); + $id = $query->execute(); + + $schema = drupal_get_schema('test'); + + $job = db_query("SELECT job FROM {test} WHERE id = :id", array(':id' => $id))->fetchField(); + $this->assertEqual($job, $schema['fields']['job']['default'], t('Default field value is set.')); + } + catch (Exception $e) { + $this->assertTrue(FALSE, $e->getMessage()); + } + } +} + +/** + * Update builder tests. + */ +class DatabaseUpdateTestCase extends DatabaseTestCase { + + function getInfo() { + return array( + 'name' => t('Update tests'), + 'description' => t('Test the Update query builder.'), + 'group' => t('Database'), + ); + } + + /** + * Confirm that we can update a single record successfully. + */ + function testSimpleUpdate() { + $num_updated = db_update('test')->fields(array('name' => 'Tiffany'))->condition('id', 1)->execute(); + $this->assertIdentical($num_updated, 1, t('Updated 1 record.')); + + $saved_name = db_query("SELECT name FROM {test} WHERE id = :id", array(':id' => 1))->fetchField(); + $this->assertIdentical($saved_name, 'Tiffany', t('Updated name successfully.')); + } + + /** + * Confirm that we can update a multiple records successfully. + */ + function testMultiUpdate() { + $num_updated = db_update('test')->fields(array('job' => 'Musician'))->condition('job', 'Singer')->execute(); + $this->assertIdentical($num_updated, 2, t('Updated 2 records.')); + + $num_matches = db_query("SELECT count(*) FROM {test} WHERE job = :job", array(':job' => 'Musician'))->fetchField(); + $this->assertIdentical($num_matches, '2', t('Updated fields successfully.')); + } + + /** + * Confirm that we can update a multiple records with a non-equality condition. + */ + function testMultiGTUpdate() { + $num_updated = db_update('test')->fields(array('job' => 'Musician'))->condition('age', 26, '>')->execute(); + $this->assertIdentical($num_updated, 2, t('Updated 2 records.')); + + $num_matches = db_query("SELECT count(*) FROM {test} WHERE job = :job", array(':job' => 'Musician'))->fetchField(); + $this->assertIdentical($num_matches, '2', t('Updated fields successfully.')); + } + + /** + * Confirm that we can update a multiple records with a where call. + */ + function testWhereUpdate() { + $num_updated = db_update('test')->fields(array('job' => 'Musician'))->where('age > :age', array(':age' => 26))->execute(); + $this->assertIdentical($num_updated, 2, t('Updated 2 records.')); + + $num_matches = db_query("SELECT COUNT(*) FROM {test} WHERE job = :job", array(':job' => 'Musician'))->fetchField(); + $this->assertIdentical($num_matches, '2', t('Updated fields successfully.')); + } + + /** + * Confirm that we can stack condition and where calls. + */ + function testWhereAndConditionUpdate() { + $update = db_update('test')->fields(array('job' => 'Musician'))->where('age > :age', array(':age' => 26))->condition('name', 'Ringo'); + $num_updated = $update->execute(); + $this->assertIdentical($num_updated, 1, t('Updated 1 record.')); + + $num_matches = db_query("SELECT count(*) FROM {test} WHERE job = :job", array(':job' => 'Musician'))->fetchField(); + $this->assertIdentical($num_matches, '1', t('Updated fields successfully.')); + } +} + +/** + * Tests for more complex update statements. + */ +class DatabaseUpdateComplexTestCase extends DatabaseTestCase { + + function getInfo() { + return array( + 'name' => t('Update tests, Complex'), + 'description' => t('Test the Update query builder, complex queries.'), + 'group' => t('Database'), + ); + } + + /** + * Test updates with OR conditionals. + */ + function testOrConditionUpdate() { + $update = db_update('test') + ->fields(array('job' => 'Musician')) + ->condition(db_or() + ->condition('name', 'John') + ->condition('name', 'Paul') + ); + $num_updated = $update->execute(); + $this->assertIdentical($num_updated, 2, t('Updated 2 records.')); + + $num_matches = db_query("SELECT count(*) FROM {test} WHERE job = :job", array(':job' => 'Musician'))->fetchField(); + $this->assertIdentical($num_matches, '2', t('Updated fields successfully.')); + } + + /** + * Test WHERE IN clauses. + */ + function testInConditionUpdate() { + $num_updated = db_update('test')->fields(array('job' => 'Musician')) + ->condition('name', array('John', 'Paul'), 'IN') + ->execute(); + $this->assertIdentical($num_updated, 2, t('Updated 2 records.')); + + $num_matches = db_query("SELECT count(*) FROM {test} WHERE job = :job", array(':job' => 'Musician'))->fetchField(); + $this->assertIdentical($num_matches, '2', t('Updated fields successfully.')); + } + + /** + * Test WHERE NOT IN clauses. + */ + function testNotInConditionUpdate() { + $num_updated = db_update('test')->fields(array('job' => 'Musician')) + ->condition('name', array('John', 'Paul', 'George'), 'NOT IN') + ->execute(); + $this->assertIdentical($num_updated, 1, t('Updated 1 record.')); + + $num_matches = db_query("SELECT count(*) FROM {test} WHERE job = :job", array(':job' => 'Musician'))->fetchField(); + $this->assertIdentical($num_matches, '1', t('Updated fields successfully.')); + } + + /** + * Test BETWEEN conditional clauses. + */ + function testBetweenConditionUpdate() { + try{ + $num_updated = db_update('test')->fields(array('job' => 'Musician')) + ->condition('age', array(25, 26), 'BETWEEN') + ->execute(); + $this->assertIdentical($num_updated, 2, t('Updated 2 records.')); + + $num_matches = db_query("SELECT count(*) FROM {test} WHERE job = :job", array(':job' => 'Musician'))->fetchField(); + $this->assertIdentical($num_matches, '2', t('Updated fields successfully.')); + } + catch (Exception $e) { + $this->assertTrue(FALSE, $e->getMessage()); + } + } + + /** + * Test LIKE conditionals. + */ + function testLikeConditionUpdate() { + $num_updated = db_update('test')->fields(array('job' => 'Musician')) + ->condition('name', '%ge%', 'LIKE') + ->execute(); + $this->assertIdentical($num_updated, 1, t('Updated 1 record.')); + + $num_matches = db_query("SELECT count(*) FROM {test} WHERE job = :job", array(':job' => 'Musician'))->fetchField(); + $this->assertIdentical($num_matches, '1', t('Updated fields successfully.')); + } + + /** + * Test update with expression values. + */ + function testUpdateExpression() { + try { + $before_age = db_query("SELECT age FROM {test} WHERE name = 'Ringo'")->fetchField(); + $GLOBALS['larry_test'] = 1; + $num_updated = db_update('test') + ->condition('name', 'Ringo') + ->fields(array('job' => 'Musician')) + ->expression('age', 'age + :age',array(':age' => 4)) + ->execute(); + $this->assertIdentical($num_updated, 1, t('Updated 1 record.')); + + $num_matches = db_query("SELECT count(*) FROM {test} WHERE job = :job", array(':job' => 'Musician'))->fetchField(); + $this->assertIdentical($num_matches, '1', t('Updated fields successfully.')); + + $person = db_query("SELECT * FROM {test} WHERE name = :name", array(':name' => 'Ringo'))->fetch(); + $this->assertEqual($person->name, 'Ringo', t('Name set correctly.')); + $this->assertEqual($person->age, $before_age + 4, t('Age set correctly.')); + $this->assertEqual($person->job, 'Musician', t('Job set correctly.')); + $GLOBALS['larry_test'] = 0; + } + catch (Exception $e) { + $this->assertTrue(FALSE, $e->getMessage()); + } + } +} + +/** + * Test update queries involving LOB values. + */ +class DatabaseUpdateLOBTestCase extends DatabaseTestCase { + + function getInfo() { + return array( + 'name' => t('Update tests, LOB'), + 'description' => t('Test the Update query builder with LOB fields.'), + 'group' => t('Database'), + ); + } + + /** + * Confirm that we can update a blob column. + */ + function testUpdateOneBlob() { + $data = "This is\000a test."; + $this->assertTrue(strlen($data) === 15, t('Test data contains a NULL.')); + $id = db_insert('test_one_blob')->fields(array('blob1' => $data))->execute(); + + $data .= $data; + db_update('test_one_blob')->condition('id', $id)->fields(array('blob1' => $data))->execute(); + + $res = db_query('SELECT * FROM {test_one_blob} WHERE id = %d', $id); + $r = db_fetch_array($res); + $this->assertTrue($r['blob1'] === $data, t('Can update a blob: id @id, @data.', array('@id' => $id, '@data' => serialize($r)))); + } + + /** + * Confirm that we can update two blob columns in the same table. + */ + function testUpdateMultipleBlob() { + $id = db_insert('test_two_blobs')->fields(array( + 'blob1' => 'This is', + 'blob2' => 'a test') + ) + ->execute(); + + db_update('test_two_blobs')->condition('id', $id)->fields(array('blob1' => 'and so', 'blob2' => 'is this'))->execute(); + + $res = db_query('SELECT * FROM {test_two_blobs} WHERE id = %d', $id); + $r = db_fetch_array($res); + $this->assertTrue($r['blob1'] === 'and so' && $r['blob2'] === 'is this', t('Can update multiple blobs per row.')); + } +} + +/** + * Delete tests. + * + * The DELETE tests are not as extensive, as all of the interesting code for + * DELETE queries is in the conditional which is identical to the UPDATE and + * SELECT conditional handling. + * + */ +class DatabaseDeleteTestCase extends DatabaseTestCase { + + function getInfo() { + return array( + 'name' => t('Delete tests'), + 'description' => t('Test the Delete query builder.'), + 'group' => t('Database'), + ); + } + + /** + * Confirm that we can delete a single record successfully. + */ + function testSimpleDelete() { + $num_records_before = db_query("SELECT COUNT(*) FROM {test}")->fetchField(); + + $num_deleted = db_delete('test')->condition('id', 1)->execute(); + $this->assertIdentical($num_deleted, 1, t('Deleted 1 record.')); + + $num_records_after = db_query("SELECT COUNT(*) FROM {test}")->fetchField(); + $this->assertEqual($num_records_before, $num_records_after + $num_deleted, t('Deletion adds up.')); + } +} + +/** + * Test the MERGE query builder. + */ +class DatabaseMergeTestCase extends DatabaseTestCase { + + function getInfo() { + return array( + 'name' => t('Merge tests'), + 'description' => t('Test the Merge query builder.'), + 'group' => t('Database'), + ); + } + + /** + * Confirm that we can merge-insert a record successfully. + */ + function testMergeInsert() { + try{ + $num_records_before = db_query("SELECT COUNT(*) FROM {test_people}")->fetchField(); + + db_merge('test_people') + ->key(array('job' => 'Presenter')) + ->fields(array( + 'age' => 31, + 'name' => 'Tiffany', + )) + ->execute(); + + $num_records_after = db_query("SELECT COUNT(*) FROM {test_people}")->fetchField(); + $this->assertEqual($num_records_before + 1, $num_records_after, t('Merge inserted properly.')); + + $person = db_query("SELECT * FROM {test_people} WHERE job = :job", array(':job' => 'Presenter'))->fetch(); + $this->assertEqual($person->name, 'Tiffany', t('Name set correctly.')); + $this->assertEqual($person->age, 31, t('Age set correctly.')); + $this->assertEqual($person->job, 'Presenter', t('Job set correctly.')); + } + catch(Exception $e) { + $this->assertTrue(FALSE, $e->getMessage()); + } + } + + /** + * Confirm that we can merge-update a record successfully. + */ + function testMergeUpdate() { + $num_records_before = db_query("SELECT COUNT(*) FROM {test_people}")->fetchField(); + + db_merge('test_people')->key(array('job' => 'Speaker'))->fields(array('age' => 31, 'name' => 'Tiffany'))->execute(); + + $num_records_after = db_query("SELECT COUNT(*) FROM {test_people}")->fetchField(); + $this->assertEqual($num_records_before, $num_records_after, t('Merge updated properly.')); + + $person = db_query("SELECT * FROM {test_people} WHERE job = :job", array(':job' => 'Speaker'))->fetch(); + $this->assertEqual($person->name, 'Tiffany', t('Name set correctly.')); + $this->assertEqual($person->age, 31, t('Age set correctly.')); + $this->assertEqual($person->job, 'Speaker', t('Job set correctly.')); + } + + /** + * Confirm that we can merge-update a record successfully, with exclusion. + */ + function testMergeUpdateExcept() { + $num_records_before = db_query("SELECT COUNT(*) FROM {test_people}")->fetchField(); + + db_merge('test_people')->key(array('job' => 'Speaker'))->fields(array('age' => 31, 'name' => 'Tiffany'))->updateExcept('age')->execute(); + + $num_records_after = db_query("SELECT COUNT(*) FROM {test_people}")->fetchField(); + $this->assertEqual($num_records_before, $num_records_after, t('Merge updated properly.')); + + $person = db_query("SELECT * FROM {test_people} WHERE job = :job", array(':job' => 'Speaker'))->fetch(); + $this->assertEqual($person->name, 'Tiffany', t('Name set correctly.')); + $this->assertEqual($person->age, 30, t('Age skipped correctly.')); + $this->assertEqual($person->job, 'Speaker', t('Job set correctly.')); + } + + /** + * Confirm that we can merge-update a record successfully, with alternate replacement. + */ + function testMergeUpdateExplicit() { + $num_records_before = db_query("SELECT COUNT(*) FROM {test_people}")->fetchField(); + + db_merge('test_people')->key(array('job' => 'Speaker'))->fields(array('age' => 31, 'name' => 'Tiffany'))->update(array('name' => 'Joe'))->execute(); + + $num_records_after = db_query("SELECT COUNT(*) FROM {test_people}")->fetchField(); + $this->assertEqual($num_records_before, $num_records_after, t('Merge updated properly.')); + + $person = db_query("SELECT * FROM {test_people} WHERE job = :job", array(':job' => 'Speaker'))->fetch(); + $this->assertEqual($person->name, 'Joe', t('Name set correctly.')); + $this->assertEqual($person->age, 30, t('Age skipped correctly.')); + $this->assertEqual($person->job, 'Speaker', t('Job set correctly.')); + } + + /** + * Confirm that we can merge-update a record successfully, with expressions. + */ + function testMergeUpdateExpression() { + $num_records_before = db_query("SELECT COUNT(*) FROM {test_people}")->fetchField(); + + $age_before = db_query("SELECT age FROM {test_people} WHERE job = 'Speaker'")->fetchField(); + + // This is a very contrived example, as I have no idea why you'd want to + // change age this way, but that's beside the point. + // Note that we are also double-setting age here, once as a literal and + // once as an expression. This test will only pass if the expression wins, + // which is what is supposed to happen. + db_merge('test_people') + ->key(array('job' => 'Speaker')) + ->fields(array('age' => 31, 'name' => 'Tiffany')) + ->expression('age', 'age + :age', array(':age' => 4)) + ->execute(); + + $num_records_after = db_query("SELECT COUNT(*) FROM {test_people}")->fetchField(); + $this->assertEqual($num_records_before, $num_records_after, t('Merge updated properly.')); + + $person = db_query("SELECT * FROM {test_people} WHERE job = :job", array(':job' => 'Speaker'))->fetch(); + $this->assertEqual($person->name, 'Tiffany', t('Name set correctly.')); + $this->assertEqual($person->age, $age_before + 4, t('Age updated correctly.')); + $this->assertEqual($person->job, 'Speaker', t('Job set correctly.')); + } +} + +/** + * Test the SELECT builder. + * + */ +class DatabaseSelectTestCase extends DatabaseTestCase { + + function getInfo() { + return array( + 'name' => t('Select tests'), + 'description' => t('Test the Select query builder.'), + 'group' => t('Database'), + ); + } + + /** + * Test rudimentary SELECT statements. + */ + function testSimpleSelect() { + try { + $query = db_select('test'); + $name_field = $query->addField('test', 'name'); + $age_field = $query->addField('test', 'age', 'age'); + $result = $query->execute(); + + $num_records = 0; + foreach ($result as $record) { + $num_records++; + } + + $this->assertEqual($num_records, 4, t('Returned the correct number of rows.')); + } + catch(Exception $e) { + $this->assertTrue(FALSE, $e->getMessage()); + } + } + + /** + * Test basic conditionals on SELECT statements. + */ + function testSimpleSelectConditional() { + $query = db_select('test'); + $name_field = $query->addField('test', 'name'); + $age_field = $query->addField('test', 'age', 'age'); + $query->condition('age', 27); + $result = $query->execute(); + + // Check that the aliases are being created the way we want. + $this->assertEqual($name_field, 'test_name', t('Name field alias is correct.')); + $this->assertEqual($age_field, 'age', t('Age field alias is correct.')); + + // Ensure that we got the right record. + $record = $result->fetch(); + $this->assertEqual($record->$name_field, 'George', t('Fetched name is correct.')); + $this->assertEqual($record->$age_field, 27, t('Fetched age is correct.')); + } + + /** + * Test SELECT statements with expressions. + */ + function testSimpleSelectExpression() { + $query = db_select('test'); + $name_field = $query->addField('test', 'name'); + $age_field = $query->addExpression("age*2", 'double_age'); + $query->condition('age', 27); + $result = $query->execute(); + + // Check that the aliases are being created the way we want. + $this->assertEqual($name_field, 'test_name', t('Name field alias is correct.')); + $this->assertEqual($age_field, 'double_age', t('Age field alias is correct.')); + + // Ensure that we got the right record. + $record = $result->fetch(); + $this->assertEqual($record->$name_field, 'George', t('Fetched name is correct.')); + $this->assertEqual($record->$age_field, 27*2, t('Fetched age expression is correct.')); + } +} + +/** + * Test select with order by clauses. + */ +class DatabaseSelectOrderedTestCase extends DatabaseTestCase { + + function getInfo() { + return array( + 'name' => t('Select tests, Ordered'), + 'description' => t('Test the Select query builder.'), + 'group' => t('Database'), + ); + } + + /** + * Test basic order by. + */ + function testSimpleSelectOrdered() { + try { + $query = db_select('test'); + $name_field = $query->addField('test', 'name'); + $age_field = $query->addField('test', 'age', 'age'); + $query->orderBy($age_field); + $result = $query->execute(); + + $num_records = 0; + $last_age = 0; + foreach ($result as $record) { + $num_records++; + $this->assertTrue($record->age >= $last_age, t('Results returned in correct order.')); + $last_age = $record->age; + } + + $this->assertEqual($num_records, 4, t('Returned the correct number of rows.')); + } + catch(Exception $e) { + $this->assertTrue(FALSE, $e->getMessage()); + } + } + + /** + * Test order by descending. + */ + function testSimpleSelectOrderedDesc() { + try { + $query = db_select('test'); + $name_field = $query->addField('test', 'name'); + $age_field = $query->addField('test', 'age', 'age'); + $query->orderBy($age_field, 'DESC'); + $result = $query->execute(); + + $num_records = 0; + $last_age = 100000000; + foreach ($result as $record) { + $num_records++; + $this->assertTrue($record->age <= $last_age, t('Results returned in correct order.')); + $last_age = $record->age; + } + + $this->assertEqual($num_records, 4, t('Returned the correct number of rows.')); + } + catch(Exception $e) { + $this->assertTrue(FALSE, $e->getMessage()); + } + } +} + +/** + * Test more complex select statements. + */ +class DatabaseSelectComplexTestCase extends DatabaseTestCase { + + function getInfo() { + return array( + 'name' => t('Select tests, Complex'), + 'description' => t('Test the Select query builder with more complex queries.'), + 'group' => t('Database'), + ); + } + + /** + * Test simple JOIN statements. + */ + function testDefaultJoin() { + try { + $query = db_select('test_task', 't'); + $people_alias = $query->join('test', 'p', 't.pid = p.id'); + $name_field = $query->addField($people_alias, 'name', 'name'); + $task_field = $query->addField('t', 'task', 'task'); + $priority_field = $query->addField('t', 'priority', 'priority'); + + $query->orderBy($priority_field); + $result = $query->execute(); + + $num_records = 0; + $last_priority = 0; + foreach ($result as $record) { + $num_records++; + $this->assertTrue($record->$priority_field >= $last_priority, t('Results returned in correct order.')); + $this->assertNotEqual($record->$name_field, 'Ringo', t('Taskless person not selected.')); + $last_priority = $record->$priority_field; + } + + $this->assertEqual($num_records, 7, t('Returned the correct number of rows.')); + } + catch(Exception $e) { + $this->assertTrue(FALSE, $e->getMessage()); + } + } + + /** + * Test LEFT OUTER joins. + */ + function testLeftOuterJoin() { + try { + $query = db_select('test', 'p'); + $people_alias = $query->leftJoin('test_task', 't', 't.pid = p.id'); + $name_field = $query->addField('p', 'name', 'name'); + $task_field = $query->addField($people_alias, 'task', 'task'); + $priority_field = $query->addField($people_alias, 'priority', 'priority'); + + $query->orderBy($name_field); + $result = $query->execute(); + + $num_records = 0; + $last_name = 0; + + foreach ($result as $record) { + $num_records++; + $this->assertTrue(strcmp($record->$name_field, $last_name) >= 0, t('Results returned in correct order.')); + $last_priority = $record->$name_field; + } + + $this->assertEqual($num_records, 8, t('Returned the correct number of rows.')); + } + catch(Exception $e) { + $this->assertTrue(FALSE, $e->getMessage()); + } + } + + /** + * Test GROUP BY clauses. + */ + function testGroupBy() { + try { + $query = db_select('test_task', 't'); + $count_field = $query->addExpression('COUNT(task)', 'num'); + $task_field = $query->addField('t', 'task'); + $query->orderBy($count_field); + $query->groupBy($task_field); + $result = $query->execute(); + + $num_records = 0; + $last_count = 0; + $records = array(); + foreach ($result as $record) { + $num_records++; + $this->assertTrue($record->$count_field >= $last_count, t('Results returned in correct order.')); + $last_count = $record->$count_field; + $records[$record->$task_field] = $record->$count_field; + } + + $correct_results = array( + 'eat' => 1, + 'sleep' => 2, + 'code' => 1, + 'found new band' => 1, + 'perform at superbowl' => 1, + ); + + foreach ($correct_results as $task => $count) { + $this->assertEqual($records[$task], $count, t("Correct number of '@task' records found.", array('@task' => $task))); + } + + $this->assertEqual($num_records, 6, t('Returned the correct number of total rows.')); + } + catch(Exception $e) { + $this->assertTrue(FALSE, $e->getMessage()); + } + } + + /** + * Test GROUP BY and HAVING clauses together. + */ + function testGroupByAndHaving() { + try { + $query = db_select('test_task', 't'); + $count_field = $query->addExpression('COUNT(task)', 'num'); + $task_field = $query->addField('t', 'task'); + $query->orderBy($count_field); + $query->groupBy($task_field); + $query->havingCondition('COUNT(task)', 2, '>='); + $result = $query->execute(); + + $num_records = 0; + $last_count = 0; + $records = array(); + foreach ($result as $record) { + $num_records++; + $this->assertTrue($record->$count_field >= 2, t('Record has the minimum count.')); + $this->assertTrue($record->$count_field >= $last_count, t('Results returned in correct order.')); + $last_count = $record->$count_field; + $records[$record->$task_field] = $record->$count_field; + } + + $correct_results = array( + 'sleep' => 2, + ); + + foreach ($correct_results as $task => $count) { + $this->assertEqual($records[$task], $count, t("Correct number of '@task' records found.", array('@task' => $task))); + } + + $this->assertEqual($num_records, 1, t('Returned the correct number of total rows.')); + } + catch(Exception $e) { + $this->assertTrue(FALSE, $e->getMessage()); + } + } + + /** + * Test range queries. The SQL clause varies with the database. + */ + function testRange() { + try { + $query = db_select('test'); + $name_field = $query->addField('test', 'name'); + $age_field = $query->addField('test', 'age', 'age'); + $query->range(0, 2); + $result = $query->execute(); + + $num_records = 0; + foreach ($result as $record) { + $num_records++; + } + + $this->assertEqual($num_records, 2, t('Returned the correct number of rows.')); + } + catch(Exception $e) { + $this->assertTrue(FALSE, $e->getMessage()); + } + } + + /** + * Test distinct queries. + */ + function testDistinct() { + try { + $query = db_select('test_task'); + $task_field = $query->addField('test_task', 'task'); + $query->distinct(); + $result = $query->execute(); + + $num_records = 0; + foreach ($result as $record) { + $num_records++; + } + + $this->assertEqual($num_records, 6, t('Returned the correct number of rows.')); + } + catch(Exception $e) { + $this->assertTrue(FALSE, $e->getMessage()); + } + } + + /** + * Test that we can generate a count query from a built query. + */ + function testCountQuery() { + try { + $query = db_select('test'); + $name_field = $query->addField('test', 'name'); + $age_field = $query->addField('test', 'age', 'age'); + $query->orderBy('name'); + + $count = $query->countQuery()->execute()->fetchField(); + + $this->assertEqual($count, 4, t('Counted the correct number of records.')); + + // Now make sure we didn't break the original query! We should still have + // all of the fields we asked for. + $record = $query->execute()->fetch(); + $this->assertEqual($record->$name_field, 'George', t('Correct data retrieved.')); + $this->assertEqual($record->$age_field, 27, t('Correct data retrieved.')); + } + catch(Exception $e) { + $this->assertTrue(FALSE, $e->getMessage()); + } + } +} + +/** + * Select tagging tests. + * + * Tags are a way to flag queries for alter hooks so they know + * what type of query it is, such as "node_access". + */ +class DatabaseTaggingTestCase extends DatabaseTestCase { + + function getInfo() { + return array( + 'name' => t('Query tagging tests'), + 'description' => t('Test the tagging capabilities of the Select builder.'), + 'group' => t('Database'), + ); + } + + /** + * Confirm that a query has a "tag" added to it. + */ + function testHasTag() { + try { + $query = db_select('test'); + $query->addField('test', 'name'); + $query->addField('test', 'age', 'age'); + + $query->addTag('test'); + + $this->assertTrue($query->hasTag('test'), t('hasTag() returned true.')); + $this->assertFalse($query->hasTag('other'), t('hasTag() returned false.')); + } + catch(Exception $e) { + $this->assertTrue(FALSE, $e->getMessage()); + } + } + + /** + * Test query tagging "has all of these tags" functionality. + */ + function testHasAllTags() { + try { + $query = db_select('test'); + $query->addField('test', 'name'); + $query->addField('test', 'age', 'age'); + + $query->addTag('test'); + $query->addTag('other'); + + $this->assertTrue($query->hasAllTags('test', 'other'), t('hasAllTags() returned true.')); + $this->assertFalse($query->hasAllTags('test', 'stuff'), t('hasAllTags() returned false.')); + } + catch(Exception $e) { + $this->assertTrue(FALSE, $e->getMessage()); + } + } + + /** + * Test query tagging "has at least one of these tags" functionality. + */ + function testHasAnyTag() { + try { + $query = db_select('test'); + $query->addField('test', 'name'); + $query->addField('test', 'age', 'age'); + + $query->addTag('test'); + + $this->assertTrue($query->hasAnyTag('test', 'other'), t('hasAnyTag() returned true.')); + $this->assertFalse($query->hasAnyTag('other', 'stuff'), t('hasAnyTag() returned false.')); + } + catch(Exception $e) { + $this->assertTrue(FALSE, $e->getMessage()); + } + } + + /** + * Test that we can attach meta data to a query object. + * + * This is how we pass additional context to alter hooks. + */ + function testMetaData() { + try { + $query = db_select('test'); + $query->addField('test', 'name'); + $query->addField('test', 'age', 'age'); + + $data = array( + 'a' => 'A', + 'b' => 'B', + ); + + $query->addMetaData('test', $data); + + $return = $query->getMetaData('test'); + $this->assertEqual($data, $return, t('Corect metadata returned.')); + + $return = $query->getMetaData('nothere'); + $this->assertNull($return, t('Non-existant key returned NULL.')); + } + catch(Exception $e) { + $this->assertTrue(FALSE, $e->getMessage()); + } + } +} + +/** + * Select alter tests. + * + * @see database_test_query_alter(). + */ +class DatabaseAlterTestCase extends DatabaseTestCase { + + function getInfo() { + return array( + 'name' => t('Query altering tests'), + 'description' => t('Test the hook_query_alter capabilities of the Select builder.'), + 'group' => t('Database'), + ); + } + + /** + * Test that we can do basic alters. + */ + function testSimpleAlter() { + try { + $query = db_select('test'); + $query->addField('test', 'name'); + $query->addField('test', 'age', 'age'); + $query->addTag('database_test_alter_add_range'); + + $result = $query->execute(); + + $num_records = 0; + foreach ($result as $record) { + $num_records++; + } + + $this->assertEqual($num_records, 2, t('Returned the correct number of rows.')); + } + catch(Exception $e) { + $this->assertTrue(FALSE, $e->getMessage()); + } + } + + /** + * Test that we can alter the joins on a query. + */ + function testAlterWithJoin() { + try { + $query = db_select('test_task'); + $tid_field = $query->addField('test_task', 'tid'); + $task_field = $query->addField('test_task', 'task'); + $query->orderBy($task_field); + $query->addTag('database_test_alter_add_join'); + + $result = $query->execute(); + + $records = $result->fetchAll(); + + $this->assertEqual(count($records), 2, t('Returned the correct number of rows.')); + + $this->assertEqual($records[0]->name, 'George', t('Correct data retrieved.')); + $this->assertEqual($records[0]->$tid_field, 4, t('Correct data retrieved.')); + $this->assertEqual($records[0]->$task_field, 'sing', t('Correct data retrieved.')); + $this->assertEqual($records[1]->name, 'George', t('Correct data retrieved.')); + $this->assertEqual($records[1]->$tid_field, 5, t('Correct data retrieved.')); + $this->assertEqual($records[1]->$task_field, 'sleep', t('Correct data retrieved.')); + } + catch(Exception $e) { + $this->assertTrue(FALSE, $e->getMessage()); + } + } + + /** + * Test that we can alter a query's conditionals. + */ + function testAlterChangeConditional() { + try { + $query = db_select('test_task'); + $tid_field = $query->addField('test_task', 'tid'); + $pid_field = $query->addField('test_task', 'pid'); + $task_field = $query->addField('test_task', 'task'); + $people_alias = $query->join('test', 'people', "test_task.pid = people.id"); + $name_field = $query->addField($people_alias, 'name', 'name'); + $query->condition('test_task.tid', '1'); + $query->orderBy($tid_field); + $query->addTag('database_test_alter_change_conditional'); + + $result = $query->execute(); + + $records = $result->fetchAll(); + + $this->assertEqual(count($records), 1, t('Returned the correct number of rows.')); + $this->assertEqual($records[0]->$name_field, 'John', t('Correct data retrieved.')); + $this->assertEqual($records[0]->$tid_field, 2, t('Correct data retrieved.')); + $this->assertEqual($records[0]->$pid_field, 1, t('Correct data retrieved.')); + $this->assertEqual($records[0]->$task_field, 'sleep', t('Correct data retrieved.')); + } + catch(Exception $e) { + $this->assertTrue(FALSE, $e->getMessage()); + } + } +} + +/** + * Select alter tests, part 2. + * + * @see database_test_query_alter(). + */ +class DatabaseAlter2TestCase extends DatabaseTestCase { + + function getInfo() { + return array( + 'name' => t('Query altering tests, part 2'), + 'description' => t('Test the hook_query_alter capabilities of the Select builder.'), + 'group' => t('Database'), + ); + } + + /** + * Test that we can alter the fields of a query. + */ + function testAlterChangeFields() { + try { + $query = db_select('test'); + $name_field = $query->addField('test', 'name'); + $age_field = $query->addField('test', 'age', 'age'); + $query->orderBy('name'); + $query->addTag('database_test_alter_change_fields'); + + $record = $query->execute()->fetch(); + $this->assertEqual($record->$name_field, 'George', t('Correct data retrieved.')); + $this->assertNull($record->$age_field, t('Age field not found, as intended.')); + } + catch(Exception $e) { + $this->assertTrue(FALSE, $e->getMessage()); + } + } + + /** + * Test that we can alter expressions in the query. + */ + function testAlterExpression() { + try { + $query = db_select('test'); + $name_field = $query->addField('test', 'name'); + $age_field = $query->addExpression("age*2", 'double_age'); + $query->condition('age', 27); + $query->addTag('database_test_alter_change_expressions'); + $result = $query->execute(); + + // Ensure that we got the right record. + $record = $result->fetch(); + + $this->assertEqual($record->$name_field, 'George', t('Fetched name is correct.')); + $this->assertEqual($record->$age_field, 27*3, t('Fetched age expression is correct.')); + } + catch(Exception $e) { + $this->assertTrue(FALSE, $e->getMessage()); + } + } + + /** + * Test that we can remove a range() value from a query. + */ + function testAlterRemoveRange() { + try { + $query = db_select('test'); + $query->addField('test', 'name'); + $query->addField('test', 'age', 'age'); + $query->range(0, 2); + $query->addTag('database_test_alter_remove_range'); + + $num_records = count($query->execute()->fetchAll()); + + $this->assertEqual($num_records, 4, t('Returned the correct number of rows.')); + } + catch(Exception $e) { + $this->assertTrue(FALSE, $e->getMessage()); + } + } +} + |