@È$pÖu‹Ê´-QqV ?V≥JÆÍqÛX8(lπï@zgÖ}Fe<ˇ‡Sñ“ÿ˜ê?6‡L∫Oß~µ –?ËeäÚ®YîÕ=Ü=¢DÁu*GvBk;)L¬N«î:flö∂≠ÇΩq„Ñm하Ë∂‚"û≥§:±≤i^ΩÑ!)Wıyŧô á„RÄ÷Òôc’≠—s™rı‚Pdêãh˘ßHVç5fifiÈF€çÌÛuçÖ/M=gëµ±ÿGû1coÔuñæ‘z®. õ∑7ÉÏÜÆ,°’H†ÍÉÌ∂7e º® íˆ⁄◊øNWK”ÂYµ‚ñé;µ¶gV-fl>µtË¥áßN2 ¯¶BaP-)eW.àôt^∏1›C∑Ö?L„&”5’4jvã–ªZ ÷+4% ´0l…»ú^°´© ûiπ∑é®óܱÒÿ‰ïˆÌ–dˆ◊Æ19rQ=Í|ı•rMæ¬;ò‰Y‰é9.”‹˝V«ã¯∏,+ë®j*¡·/';
+
+ $model =& new AppModel(array('name' => 'BinaryTest', 'ds' => 'test_suite'));
+ $model->save(compact('data'));
+
+ $result = $model->find('first');
+ $this->assertEqual($result['BinaryTest']['data'], $data);
+ }
+
+/**
+ * Tests the syntax of generated schema indexes
+ *
+ * @access public
+ * @return void
+ */
+ function testSchemaIndexSyntax() {
+ $schema = new CakeSchema();
+ $schema->tables = array('i18n' => array(
+ 'id' => array(
+ 'type' => 'integer', 'null' => false, 'default' => null,
+ 'length' => 10, 'key' => 'primary'
+ ),
+ 'locale' => array('type'=>'string', 'null' => false, 'length' => 6, 'key' => 'index'),
+ 'model' => array('type'=>'string', 'null' => false, 'key' => 'index'),
+ 'foreign_key' => array(
+ 'type'=>'integer', 'null' => false, 'length' => 10, 'key' => 'index'
+ ),
+ 'field' => array('type'=>'string', 'null' => false, 'key' => 'index'),
+ 'content' => array('type'=>'text', 'null' => true, 'default' => null),
+ 'indexes' => array(
+ 'PRIMARY' => array('column' => 'id', 'unique' => 1),
+ 'locale' => array('column' => 'locale', 'unique' => 0),
+ 'model' => array('column' => 'model', 'unique' => 0),
+ 'row_id' => array('column' => 'foreign_key', 'unique' => 0),
+ 'field' => array('column' => 'field', 'unique' => 0)
+ )
+ ));
+
+ $result = $this->db->createSchema($schema);
+ $this->assertNoPattern('/^CREATE INDEX(.+);,$/', $result);
+ }
+
+/**
+ * testCakeSchema method
+ *
+ * Test that schema generated postgresql queries are valid. ref #5696
+ * Check that the create statement for a schema generated table is the same as the original sql
+ *
+ * @return void
+ * @access public
+ */
+ function testCakeSchema() {
+ $db1 =& ConnectionManager::getDataSource('test_suite');
+ $db1->cacheSources = false;
+ $db1->reconnect(array('persistent' => false));
+ $db1->query('CREATE TABLE ' . $db1->fullTableName('datatype_tests') . ' (
+ id serial NOT NULL,
+ "varchar" character varying(40) NOT NULL,
+ "full_length" character varying NOT NULL,
+ "timestamp" timestamp without time zone,
+ date date,
+ CONSTRAINT test_suite_data_types_pkey PRIMARY KEY (id)
+ )');
+ $model = new Model(array('name' => 'DatatypeTest', 'ds' => 'test_suite'));
+ $schema = new CakeSchema(array('connection' => 'test_suite'));
+ $result = $schema->read(array(
+ 'connection' => 'test_suite',
+ ));
+ $schema->tables = array('datatype_tests' => $result['tables']['missing']['datatype_tests']);
+ $result = $db1->createSchema($schema, 'datatype_tests');
+
+ $this->assertNoPattern('/timestamp DEFAULT/', $result);
+ $this->assertPattern('/\"full_length\"\s*text\s.*,/', $result);
+ $this->assertPattern('/timestamp\s*,/', $result);
+
+ $db1->query('DROP TABLE ' . $db1->fullTableName('datatype_tests'));
+
+ $db1->query($result);
+ $result2 = $schema->read(array(
+ 'connection' => 'test_suite',
+ 'models' => array('DatatypeTest')
+ ));
+ $schema->tables = array('datatype_tests' => $result2['tables']['missing']['datatype_tests']);
+ $result2 = $db1->createSchema($schema, 'datatype_tests');
+ $this->assertEqual($result, $result2);
+
+ $db1->query('DROP TABLE ' . $db1->fullTableName('datatype_tests'));
+ }
+
+/**
+ * Test index generation from table info.
+ *
+ * @return void
+ */
+ function testIndexGeneration() {
+ $name = $this->db->fullTableName('index_test', false);
+ $this->db->query('CREATE TABLE ' . $name . ' ("id" serial NOT NULL PRIMARY KEY, "bool" integer, "small_char" varchar(50), "description" varchar(40) )');
+ $this->db->query('CREATE INDEX pointless_bool ON ' . $name . '("bool")');
+ $this->db->query('CREATE UNIQUE INDEX char_index ON ' . $name . '("small_char")');
+ $expected = array(
+ 'PRIMARY' => array('column' => 'id', 'unique' => 1),
+ 'pointless_bool' => array('column' => 'bool', 'unique' => 0),
+ 'char_index' => array('column' => 'small_char', 'unique' => 1),
+
+ );
+ $result = $this->db->index($name);
+ $this->assertEqual($expected, $result);
+
+ $this->db->query('DROP TABLE ' . $name);
+ $name = $this->db->fullTableName('index_test_2', false);
+ $this->db->query('CREATE TABLE ' . $name . ' ("id" serial NOT NULL PRIMARY KEY, "bool" integer, "small_char" varchar(50), "description" varchar(40) )');
+ $this->db->query('CREATE UNIQUE INDEX multi_col ON ' . $name . '("small_char", "bool")');
+ $expected = array(
+ 'PRIMARY' => array('column' => 'id', 'unique' => 1),
+ 'multi_col' => array('column' => array('small_char', 'bool'), 'unique' => 1),
+ );
+ $result = $this->db->index($name);
+ $this->assertEqual($expected, $result);
+ $this->db->query('DROP TABLE ' . $name);
+ }
+
+/**
+ * Test the alterSchema capabilities of postgres
+ *
+ * @access public
+ * @return void
+ */
+ function testAlterSchema() {
+ $Old =& new CakeSchema(array(
+ 'connection' => 'test_suite',
+ 'name' => 'AlterPosts',
+ 'alter_posts' => array(
+ 'id' => array('type' => 'integer', 'key' => 'primary'),
+ 'author_id' => array('type' => 'integer', 'null' => false),
+ 'title' => array('type' => 'string', 'null' => true),
+ 'body' => array('type' => 'text'),
+ 'published' => array('type' => 'string', 'length' => 1, 'default' => 'N'),
+ 'created' => array('type' => 'datetime'),
+ 'updated' => array('type' => 'datetime'),
+ )
+ ));
+ $this->db->query($this->db->createSchema($Old));
+
+ $New =& new CakeSchema(array(
+ 'connection' => 'test_suite',
+ 'name' => 'AlterPosts',
+ 'alter_posts' => array(
+ 'id' => array('type' => 'integer', 'key' => 'primary'),
+ 'author_id' => array('type' => 'integer', 'null' => true),
+ 'title' => array('type' => 'string', 'null' => false, 'default' => 'my title'),
+ 'body' => array('type' => 'string', 'length' => 500),
+ 'status' => array('type' => 'integer', 'length' => 3, 'default' => 1),
+ 'created' => array('type' => 'datetime'),
+ 'updated' => array('type' => 'datetime'),
+ )
+ ));
+ $this->db->query($this->db->alterSchema($New->compare($Old), 'alter_posts'));
+
+ $model = new CakeTestModel(array('table' => 'alter_posts', 'ds' => 'test_suite'));
+ $result = $model->schema();
+ $this->assertTrue(isset($result['status']));
+ $this->assertFalse(isset($result['published']));
+ $this->assertEqual($result['body']['type'], 'string');
+ $this->assertEqual($result['status']['default'], 1);
+ $this->assertEqual($result['author_id']['null'], true);
+ $this->assertEqual($result['title']['null'], false);
+
+ $this->db->query($this->db->dropSchema($New));
+ }
+
+/**
+ * Test the alter index capabilities of postgres
+ *
+ * @access public
+ * @return void
+ */
+ function testAlterIndexes() {
+ $this->db->cacheSources = false;
+
+ $schema1 =& new CakeSchema(array(
+ 'name' => 'AlterTest1',
+ 'connection' => 'test_suite',
+ 'altertest' => array(
+ 'id' => array('type' => 'integer', 'null' => false, 'default' => 0),
+ 'name' => array('type' => 'string', 'null' => false, 'length' => 50),
+ 'group1' => array('type' => 'integer', 'null' => true),
+ 'group2' => array('type' => 'integer', 'null' => true)
+ )
+ ));
+ $this->db->query($this->db->createSchema($schema1));
+
+ $schema2 =& new CakeSchema(array(
+ 'name' => 'AlterTest2',
+ 'connection' => 'test_suite',
+ 'altertest' => array(
+ 'id' => array('type' => 'integer', 'null' => false, 'default' => 0),
+ 'name' => array('type' => 'string', 'null' => false, 'length' => 50),
+ 'group1' => array('type' => 'integer', 'null' => true),
+ 'group2' => array('type' => 'integer', 'null' => true),
+ 'indexes' => array(
+ 'name_idx' => array('column' => 'name', 'unique' => 0),
+ 'group_idx' => array('column' => 'group1', 'unique' => 0),
+ 'compound_idx' => array('column' => array('group1', 'group2'), 'unique' => 0),
+ 'PRIMARY' => array('column' => 'id', 'unique' => 1)
+ )
+ )
+ ));
+ $this->db->query($this->db->alterSchema($schema2->compare($schema1)));
+
+ $indexes = $this->db->index('altertest');
+ $this->assertEqual($schema2->tables['altertest']['indexes'], $indexes);
+
+ // Change three indexes, delete one and add another one
+ $schema3 =& new CakeSchema(array(
+ 'name' => 'AlterTest3',
+ 'connection' => 'test_suite',
+ 'altertest' => array(
+ 'id' => array('type' => 'integer', 'null' => false, 'default' => 0),
+ 'name' => array('type' => 'string', 'null' => false, 'length' => 50),
+ 'group1' => array('type' => 'integer', 'null' => true),
+ 'group2' => array('type' => 'integer', 'null' => true),
+ 'indexes' => array(
+ 'name_idx' => array('column' => 'name', 'unique' => 1),
+ 'group_idx' => array('column' => 'group2', 'unique' => 0),
+ 'compound_idx' => array('column' => array('group2', 'group1'), 'unique' => 0),
+ 'another_idx' => array('column' => array('group1', 'name'), 'unique' => 0))
+ )));
+
+ $this->db->query($this->db->alterSchema($schema3->compare($schema2)));
+
+ $indexes = $this->db->index('altertest');
+ $this->assertEqual($schema3->tables['altertest']['indexes'], $indexes);
+
+ // Compare us to ourself.
+ $this->assertEqual($schema3->compare($schema3), array());
+
+ // Drop the indexes
+ $this->db->query($this->db->alterSchema($schema1->compare($schema3)));
+
+ $indexes = $this->db->index('altertest');
+ $this->assertEqual(array(), $indexes);
+
+ $this->db->query($this->db->dropSchema($schema1));
+ }
+
+/*
+ * Test it is possible to use virtual field with postgresql
+ *
+ * @access public
+ * @return void
+ */
+ function testVirtualFields() {
+ $this->loadFixtures('Article', 'Comment');
+ $Article = new Article;
+ $Article->virtualFields = array(
+ 'next_id' => 'Article.id + 1',
+ 'complex' => 'Article.title || Article.body',
+ 'functional' => 'COALESCE(User.user, Article.title)',
+ 'subquery' => 'SELECT count(*) FROM ' . $Article->Comment->table
+ );
+ $result = $Article->find('first');
+ $this->assertEqual($result['Article']['next_id'], 2);
+ $this->assertEqual($result['Article']['complex'], $result['Article']['title'] . $result['Article']['body']);
+ $this->assertEqual($result['Article']['functional'], $result['Article']['title']);
+ $this->assertEqual($result['Article']['subquery'], 6);
+ }
+
+/**
+ * Tests additional order options for postgres
+ *
+ * @access public
+ * @return void
+ */
+ function testOrderAdditionalParams() {
+ $result = $this->db->order(array('title' => 'DESC NULLS FIRST', 'body' => 'DESC'));
+ $expected = ' ORDER BY "title" DESC NULLS FIRST, "body" DESC';
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+* Test it is possible to do a SELECT COUNT(DISTINCT Model.field) query in postgres and it gets correctly quoted
+*/
+ function testQuoteDistinctInFunction() {
+ $this->loadFixtures('Article');
+ $Article = new Article;
+ $result = $this->db->fields($Article, null, array('COUNT(DISTINCT Article.id)'));
+ $expected = array('COUNT(DISTINCT "Article"."id")');
+ $this->assertEqual($result, $expected);
+
+ $result = $this->db->fields($Article, null, array('COUNT(DISTINCT id)'));
+ $expected = array('COUNT(DISTINCT "id")');
+ $this->assertEqual($result, $expected);
+
+ $result = $this->db->fields($Article, null, array('COUNT(DISTINCT FUNC(id))'));
+ $expected = array('COUNT(DISTINCT FUNC("id"))');
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * test that saveAll works even with conditions that lack a model name.
+ *
+ * @return void
+ */
+ function testUpdateAllWithNonQualifiedConditions() {
+ $this->loadFixtures('Article');
+ $Article =& new Article();
+ $result = $Article->updateAll(array('title' => "'Awesome'"), array('title' => 'Third Article'));
+ $this->assertTrue($result);
+
+ $result = $Article->find('count', array(
+ 'conditions' => array('Article.title' => 'Awesome')
+ ));
+ $this->assertEqual($result, 1, 'Article count is wrong or fixture has changed.');
+ }
+
+/**
+ * test alterSchema on two tables.
+ *
+ * @return void
+ */
+ function testAlteringTwoTables() {
+ $schema1 =& new CakeSchema(array(
+ 'name' => 'AlterTest1',
+ 'connection' => 'test_suite',
+ 'altertest' => array(
+ 'id' => array('type' => 'integer', 'null' => false, 'default' => 0),
+ 'name' => array('type' => 'string', 'null' => false, 'length' => 50),
+ ),
+ 'other_table' => array(
+ 'id' => array('type' => 'integer', 'null' => false, 'default' => 0),
+ 'name' => array('type' => 'string', 'null' => false, 'length' => 50),
+ )
+ ));
+ $schema2 =& new CakeSchema(array(
+ 'name' => 'AlterTest1',
+ 'connection' => 'test_suite',
+ 'altertest' => array(
+ 'id' => array('type' => 'integer', 'null' => false, 'default' => 0),
+ 'field_two' => array('type' => 'string', 'null' => false, 'length' => 50),
+ ),
+ 'other_table' => array(
+ 'id' => array('type' => 'integer', 'null' => false, 'default' => 0),
+ 'field_two' => array('type' => 'string', 'null' => false, 'length' => 50),
+ )
+ ));
+ $result = $this->db->alterSchema($schema2->compare($schema1));
+ $this->assertEqual(2, substr_count($result, 'field_two'), 'Too many fields');
+ $this->assertFalse(strpos(';ALTER', $result), 'Too many semi colons');
+ }
+}
diff --git a/code/ryzom/tools/server/www/webtt/cake/tests/cases/libs/model/datasources/dbo/dbo_sqlite.test.php b/code/ryzom/tools/server/www/webtt/cake/tests/cases/libs/model/datasources/dbo/dbo_sqlite.test.php
new file mode 100644
index 000000000..cd5886e0e
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/cake/tests/cases/libs/model/datasources/dbo/dbo_sqlite.test.php
@@ -0,0 +1,355 @@
+simulated[] = $sql;
+ return null;
+ }
+
+/**
+ * getLastQuery method
+ *
+ * @access public
+ * @return void
+ */
+ function getLastQuery() {
+ return $this->simulated[count($this->simulated) - 1];
+ }
+}
+
+/**
+ * DboSqliteTest class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model.datasources.dbo
+ */
+class DboSqliteTest extends CakeTestCase {
+
+/**
+ * Do not automatically load fixtures for each test, they will be loaded manually using CakeTestCase::loadFixtures
+ *
+ * @var boolean
+ * @access public
+ */
+ var $autoFixtures = false;
+
+/**
+ * Fixtures
+ *
+ * @var object
+ * @access public
+ */
+ var $fixtures = array('core.user');
+
+/**
+ * Actual DB connection used in testing
+ *
+ * @var DboSource
+ * @access public
+ */
+ var $db = null;
+
+/**
+ * Simulated DB connection used in testing
+ *
+ * @var DboSource
+ * @access public
+ */
+ var $db2 = null;
+
+/**
+ * Skip if cannot connect to SQLite
+ *
+ * @access public
+ */
+ function skip() {
+ $this->_initDb();
+ $this->skipUnless($this->db->config['driver'] == 'sqlite', '%s SQLite connection not available');
+ }
+
+/**
+ * Set up test suite database connection
+ *
+ * @access public
+ */
+ function startTest() {
+ $this->_initDb();
+ }
+
+/**
+ * Sets up a Dbo class instance for testing
+ *
+ * @access public
+ */
+ function setUp() {
+ Configure::write('Cache.disable', true);
+ $this->startTest();
+ $this->db =& ConnectionManager::getDataSource('test_suite');
+ $this->db2 = new DboSqliteTestDb($this->db->config, false);
+ }
+
+/**
+ * Sets up a Dbo class instance for testing
+ *
+ * @access public
+ */
+ function tearDown() {
+ Configure::write('Cache.disable', false);
+ unset($this->db2);
+ }
+
+/**
+ * Tests that SELECT queries from DboSqlite::listSources() are not cached
+ *
+ * @access public
+ */
+ function testTableListCacheDisabling() {
+ $this->assertFalse(in_array('foo_test', $this->db->listSources()));
+
+ $this->db->query('CREATE TABLE foo_test (test VARCHAR(255));');
+ $this->assertTrue(in_array('foo_test', $this->db->listSources()));
+
+ $this->db->query('DROP TABLE foo_test;');
+ $this->assertFalse(in_array('foo_test', $this->db->listSources()));
+ }
+
+/**
+ * test Index introspection.
+ *
+ * @access public
+ * @return void
+ */
+ function testIndex() {
+ $name = $this->db->fullTableName('with_a_key');
+ $this->db->query('CREATE TABLE ' . $name . ' ("id" int(11) PRIMARY KEY, "bool" int(1), "small_char" varchar(50), "description" varchar(40) );');
+ $this->db->query('CREATE INDEX pointless_bool ON ' . $name . '("bool")');
+ $this->db->query('CREATE UNIQUE INDEX char_index ON ' . $name . '("small_char")');
+ $expected = array(
+ 'PRIMARY' => array('column' => 'id', 'unique' => 1),
+ 'pointless_bool' => array('column' => 'bool', 'unique' => 0),
+ 'char_index' => array('column' => 'small_char', 'unique' => 1),
+
+ );
+ $result = $this->db->index($name);
+ $this->assertEqual($expected, $result);
+ $this->db->query('DROP TABLE ' . $name);
+
+ $this->db->query('CREATE TABLE ' . $name . ' ("id" int(11) PRIMARY KEY, "bool" int(1), "small_char" varchar(50), "description" varchar(40) );');
+ $this->db->query('CREATE UNIQUE INDEX multi_col ON ' . $name . '("small_char", "bool")');
+ $expected = array(
+ 'PRIMARY' => array('column' => 'id', 'unique' => 1),
+ 'multi_col' => array('column' => array('small_char', 'bool'), 'unique' => 1),
+ );
+ $result = $this->db->index($name);
+ $this->assertEqual($expected, $result);
+ $this->db->query('DROP TABLE ' . $name);
+ }
+
+/**
+ * Tests that cached table descriptions are saved under the sanitized key name
+ *
+ * @access public
+ */
+ function testCacheKeyName() {
+ Configure::write('Cache.disable', false);
+
+ $dbName = 'db' . rand() . '$(*%&).db';
+ $this->assertFalse(file_exists(TMP . $dbName));
+
+ $config = $this->db->config;
+ $db = new DboSqlite(array_merge($this->db->config, array('database' => TMP . $dbName)));
+ $this->assertTrue(file_exists(TMP . $dbName));
+
+ $db->execute("CREATE TABLE test_list (id VARCHAR(255));");
+
+ $db->cacheSources = true;
+ $this->assertEqual($db->listSources(), array('test_list'));
+ $db->cacheSources = false;
+
+ $fileName = '_' . preg_replace('/[^A-Za-z0-9_\-+]/', '_', TMP . $dbName) . '_list';
+
+ $result = Cache::read($fileName, '_cake_model_');
+ $this->assertEqual($result, array('test_list'));
+
+ Cache::delete($fileName, '_cake_model_');
+ Configure::write('Cache.disable', true);
+ }
+
+/**
+ * test building columns with SQLite
+ *
+ * @return void
+ */
+ function testBuildColumn() {
+ $data = array(
+ 'name' => 'int_field',
+ 'type' => 'integer',
+ 'null' => false,
+ );
+ $result = $this->db->buildColumn($data);
+ $expected = '"int_field" integer(11) NOT NULL';
+ $this->assertEqual($result, $expected);
+
+ $data = array(
+ 'name' => 'name',
+ 'type' => 'string',
+ 'length' => 20,
+ 'null' => false,
+ );
+ $result = $this->db->buildColumn($data);
+ $expected = '"name" varchar(20) NOT NULL';
+ $this->assertEqual($result, $expected);
+
+ $data = array(
+ 'name' => 'testName',
+ 'type' => 'string',
+ 'length' => 20,
+ 'default' => null,
+ 'null' => true,
+ 'collate' => 'NOCASE'
+ );
+ $result = $this->db->buildColumn($data);
+ $expected = '"testName" varchar(20) DEFAULT NULL COLLATE NOCASE';
+ $this->assertEqual($result, $expected);
+
+ $data = array(
+ 'name' => 'testName',
+ 'type' => 'string',
+ 'length' => 20,
+ 'default' => 'test-value',
+ 'null' => false,
+ );
+ $result = $this->db->buildColumn($data);
+ $expected = '"testName" varchar(20) DEFAULT \'test-value\' NOT NULL';
+ $this->assertEqual($result, $expected);
+
+ $data = array(
+ 'name' => 'testName',
+ 'type' => 'integer',
+ 'length' => 10,
+ 'default' => 10,
+ 'null' => false,
+ );
+ $result = $this->db->buildColumn($data);
+ $expected = '"testName" integer(10) DEFAULT \'10\' NOT NULL';
+ $this->assertEqual($result, $expected);
+
+ $data = array(
+ 'name' => 'testName',
+ 'type' => 'integer',
+ 'length' => 10,
+ 'default' => 10,
+ 'null' => false,
+ 'collate' => 'BADVALUE'
+ );
+ $result = $this->db->buildColumn($data);
+ $expected = '"testName" integer(10) DEFAULT \'10\' NOT NULL';
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * test describe() and normal results.
+ *
+ * @return void
+ */
+ function testDescribe() {
+ $Model =& new Model(array('name' => 'User', 'ds' => 'test_suite', 'table' => 'users'));
+ $result = $this->db->describe($Model);
+ $expected = array(
+ 'id' => array(
+ 'type' => 'integer',
+ 'key' => 'primary',
+ 'null' => false,
+ 'default' => null,
+ 'length' => 11
+ ),
+ 'user' => array(
+ 'type' => 'string',
+ 'length' => 255,
+ 'null' => false,
+ 'default' => null
+ ),
+ 'password' => array(
+ 'type' => 'string',
+ 'length' => 255,
+ 'null' => false,
+ 'default' => null
+ ),
+ 'created' => array(
+ 'type' => 'datetime',
+ 'null' => true,
+ 'default' => null,
+ 'length' => null,
+ ),
+ 'updated' => array(
+ 'type' => 'datetime',
+ 'null' => true,
+ 'default' => null,
+ 'length' => null,
+ )
+ );
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * test that describe does not corrupt UUID primary keys
+ *
+ * @return void
+ */
+ function testDescribeWithUuidPrimaryKey() {
+ $tableName = 'uuid_tests';
+ $this->db->query("CREATE TABLE {$tableName} (id VARCHAR(36) PRIMARY KEY, name VARCHAR, created DATETIME, modified DATETIME)");
+ $Model =& new Model(array('name' => 'UuidTest', 'ds' => 'test_suite', 'table' => 'uuid_tests'));
+ $result = $this->db->describe($Model);
+ $expected = array(
+ 'type' => 'string',
+ 'length' => 36,
+ 'null' => false,
+ 'default' => null,
+ 'key' => 'primary',
+ );
+ $this->assertEqual($result['id'], $expected);
+ $this->db->query('DROP TABLE ' . $tableName);
+ }
+}
diff --git a/code/ryzom/tools/server/www/webtt/cake/tests/cases/libs/model/datasources/dbo_source.test.php b/code/ryzom/tools/server/www/webtt/cake/tests/cases/libs/model/datasources/dbo_source.test.php
new file mode 100644
index 000000000..1e913ccef
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/cake/tests/cases/libs/model/datasources/dbo_source.test.php
@@ -0,0 +1,4616 @@
+
+ * Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
+ *
+ * Licensed under The Open Group Test Suite License
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
+ * @link http://book.cakephp.org/view/1196/Testing CakePHP(tm) Tests
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model.datasources
+ * @since CakePHP(tm) v 1.2.0.4206
+ * @license http://www.opensource.org/licenses/opengroup.php The Open Group Test Suite License
+ */
+if (!defined('CAKEPHP_UNIT_TEST_EXECUTION')) {
+ define('CAKEPHP_UNIT_TEST_EXECUTION', 1);
+}
+App::import('Model', array('Model', 'DataSource', 'DboSource', 'DboMysql', 'App'));
+require_once dirname(dirname(__FILE__)) . DS . 'models.php';
+
+/**
+ * TestModel class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model.datasources
+ */
+class TestModel extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'TestModel'
+ * @access public
+ */
+ var $name = 'TestModel';
+
+/**
+ * useTable property
+ *
+ * @var bool false
+ * @access public
+ */
+ var $useTable = false;
+
+/**
+ * schema property
+ *
+ * @var array
+ * @access protected
+ */
+ var $_schema = array(
+ 'id' => array('type' => 'integer', 'null' => '', 'default' => '', 'length' => '8'),
+ 'client_id' => array('type' => 'integer', 'null' => '', 'default' => '', 'length' => '11'),
+ 'name' => array('type' => 'string', 'null' => '', 'default' => '', 'length' => '255'),
+ 'login' => array('type' => 'string', 'null' => '', 'default' => '', 'length' => '255'),
+ 'passwd' => array('type' => 'string', 'null' => '1', 'default' => '', 'length' => '255'),
+ 'addr_1' => array('type' => 'string', 'null' => '1', 'default' => '', 'length' => '255'),
+ 'addr_2' => array('type' => 'string', 'null' => '1', 'default' => '', 'length' => '25'),
+ 'zip_code' => array('type' => 'string', 'null' => '1', 'default' => '', 'length' => '155'),
+ 'city' => array('type' => 'string', 'null' => '1', 'default' => '', 'length' => '155'),
+ 'country' => array('type' => 'string', 'null' => '1', 'default' => '', 'length' => '155'),
+ 'phone' => array('type' => 'string', 'null' => '1', 'default' => '', 'length' => '155'),
+ 'fax' => array('type' => 'string', 'null' => '1', 'default' => '', 'length' => '155'),
+ 'url' => array('type' => 'string', 'null' => '1', 'default' => '', 'length' => '255'),
+ 'email' => array('type' => 'string', 'null' => '1', 'default' => '', 'length' => '155'),
+ 'comments' => array('type' => 'text', 'null' => '1', 'default' => '', 'length' => '155'),
+ 'last_login' => array('type' => 'datetime', 'null' => '1', 'default' => '', 'length' => ''),
+ 'created' => array('type' => 'date', 'null' => '1', 'default' => '', 'length' => ''),
+ 'updated' => array('type' => 'datetime', 'null' => '1', 'default' => '', 'length' => null)
+ );
+
+/**
+ * find method
+ *
+ * @param mixed $conditions
+ * @param mixed $fields
+ * @param mixed $order
+ * @param mixed $recursive
+ * @access public
+ * @return void
+ */
+ function find($conditions = null, $fields = null, $order = null, $recursive = null) {
+ return array($conditions, $fields);
+ }
+
+/**
+ * findAll method
+ *
+ * @param mixed $conditions
+ * @param mixed $fields
+ * @param mixed $order
+ * @param mixed $recursive
+ * @access public
+ * @return void
+ */
+ function findAll($conditions = null, $fields = null, $order = null, $recursive = null) {
+ return $conditions;
+ }
+}
+
+/**
+ * TestModel2 class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model.datasources
+ */
+class TestModel2 extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'TestModel2'
+ * @access public
+ */
+ var $name = 'TestModel2';
+
+/**
+ * useTable property
+ *
+ * @var bool false
+ * @access public
+ */
+ var $useTable = false;
+}
+
+/**
+ * TestModel4 class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model.datasources
+ */
+class TestModel3 extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'TestModel3'
+ * @access public
+ */
+ var $name = 'TestModel3';
+
+/**
+ * useTable property
+ *
+ * @var bool false
+ * @access public
+ */
+ var $useTable = false;
+}
+
+/**
+ * TestModel4 class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model.datasources
+ */
+class TestModel4 extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'TestModel4'
+ * @access public
+ */
+ var $name = 'TestModel4';
+
+/**
+ * table property
+ *
+ * @var string 'test_model4'
+ * @access public
+ */
+ var $table = 'test_model4';
+
+/**
+ * useTable property
+ *
+ * @var bool false
+ * @access public
+ */
+ var $useTable = false;
+
+/**
+ * belongsTo property
+ *
+ * @var array
+ * @access public
+ */
+ var $belongsTo = array(
+ 'TestModel4Parent' => array(
+ 'className' => 'TestModel4',
+ 'foreignKey' => 'parent_id'
+ )
+ );
+
+/**
+ * hasOne property
+ *
+ * @var array
+ * @access public
+ */
+ var $hasOne = array(
+ 'TestModel5' => array(
+ 'className' => 'TestModel5',
+ 'foreignKey' => 'test_model4_id'
+ )
+ );
+
+/**
+ * hasAndBelongsToMany property
+ *
+ * @var array
+ * @access public
+ */
+ var $hasAndBelongsToMany = array('TestModel7' => array(
+ 'className' => 'TestModel7',
+ 'joinTable' => 'test_model4_test_model7',
+ 'foreignKey' => 'test_model4_id',
+ 'associationForeignKey' => 'test_model7_id',
+ 'with' => 'TestModel4TestModel7'
+ ));
+
+/**
+ * schema method
+ *
+ * @access public
+ * @return void
+ */
+ function schema() {
+ if (!isset($this->_schema)) {
+ $this->_schema = array(
+ 'id' => array('type' => 'integer', 'null' => '', 'default' => '', 'length' => '8'),
+ 'name' => array('type' => 'string', 'null' => '', 'default' => '', 'length' => '255'),
+ 'created' => array('type' => 'date', 'null' => '1', 'default' => '', 'length' => ''),
+ 'updated' => array('type' => 'datetime', 'null' => '1', 'default' => '', 'length' => null)
+ );
+ }
+ return $this->_schema;
+ }
+}
+
+/**
+ * TestModel4TestModel7 class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model.datasources
+ */
+class TestModel4TestModel7 extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'TestModel4TestModel7'
+ * @access public
+ */
+ var $name = 'TestModel4TestModel7';
+
+/**
+ * table property
+ *
+ * @var string 'test_model4_test_model7'
+ * @access public
+ */
+ var $table = 'test_model4_test_model7';
+
+/**
+ * useTable property
+ *
+ * @var bool false
+ * @access public
+ */
+ var $useTable = false;
+
+/**
+ * schema method
+ *
+ * @access public
+ * @return void
+ */
+ function schema() {
+ if (!isset($this->_schema)) {
+ $this->_schema = array(
+ 'test_model4_id' => array('type' => 'integer', 'null' => '', 'default' => '', 'length' => '8'),
+ 'test_model7_id' => array('type' => 'integer', 'null' => '', 'default' => '', 'length' => '8')
+ );
+ }
+ return $this->_schema;
+ }
+}
+
+/**
+ * TestModel5 class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model.datasources
+ */
+class TestModel5 extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'TestModel5'
+ * @access public
+ */
+ var $name = 'TestModel5';
+
+/**
+ * table property
+ *
+ * @var string 'test_model5'
+ * @access public
+ */
+ var $table = 'test_model5';
+
+/**
+ * useTable property
+ *
+ * @var bool false
+ * @access public
+ */
+ var $useTable = false;
+
+/**
+ * belongsTo property
+ *
+ * @var array
+ * @access public
+ */
+ var $belongsTo = array('TestModel4' => array(
+ 'className' => 'TestModel4',
+ 'foreignKey' => 'test_model4_id'
+ ));
+
+/**
+ * hasMany property
+ *
+ * @var array
+ * @access public
+ */
+ var $hasMany = array('TestModel6' => array(
+ 'className' => 'TestModel6',
+ 'foreignKey' => 'test_model5_id'
+ ));
+
+/**
+ * schema method
+ *
+ * @access public
+ * @return void
+ */
+ function schema() {
+ if (!isset($this->_schema)) {
+ $this->_schema = array(
+ 'id' => array('type' => 'integer', 'null' => '', 'default' => '', 'length' => '8'),
+ 'test_model4_id' => array('type' => 'integer', 'null' => '', 'default' => '', 'length' => '8'),
+ 'name' => array('type' => 'string', 'null' => '', 'default' => '', 'length' => '255'),
+ 'created' => array('type' => 'date', 'null' => '1', 'default' => '', 'length' => ''),
+ 'updated' => array('type' => 'datetime', 'null' => '1', 'default' => '', 'length' => null)
+ );
+ }
+ return $this->_schema;
+ }
+}
+
+/**
+ * TestModel6 class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model.datasources
+ */
+class TestModel6 extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'TestModel6'
+ * @access public
+ */
+ var $name = 'TestModel6';
+
+/**
+ * table property
+ *
+ * @var string 'test_model6'
+ * @access public
+ */
+ var $table = 'test_model6';
+
+/**
+ * useTable property
+ *
+ * @var bool false
+ * @access public
+ */
+ var $useTable = false;
+
+/**
+ * belongsTo property
+ *
+ * @var array
+ * @access public
+ */
+ var $belongsTo = array('TestModel5' => array(
+ 'className' => 'TestModel5',
+ 'foreignKey' => 'test_model5_id'
+ ));
+
+/**
+ * schema method
+ *
+ * @access public
+ * @return void
+ */
+ function schema() {
+ if (!isset($this->_schema)) {
+ $this->_schema = array(
+ 'id' => array('type' => 'integer', 'null' => '', 'default' => '', 'length' => '8'),
+ 'test_model5_id' => array('type' => 'integer', 'null' => '', 'default' => '', 'length' => '8'),
+ 'name' => array('type' => 'string', 'null' => '', 'default' => '', 'length' => '255'),
+ 'created' => array('type' => 'date', 'null' => '1', 'default' => '', 'length' => ''),
+ 'updated' => array('type' => 'datetime', 'null' => '1', 'default' => '', 'length' => null)
+ );
+ }
+ return $this->_schema;
+ }
+}
+
+/**
+ * TestModel7 class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model.datasources
+ */
+class TestModel7 extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'TestModel7'
+ * @access public
+ */
+ var $name = 'TestModel7';
+
+/**
+ * table property
+ *
+ * @var string 'test_model7'
+ * @access public
+ */
+ var $table = 'test_model7';
+
+/**
+ * useTable property
+ *
+ * @var bool false
+ * @access public
+ */
+ var $useTable = false;
+
+/**
+ * schema method
+ *
+ * @access public
+ * @return void
+ */
+ function schema() {
+ if (!isset($this->_schema)) {
+ $this->_schema = array(
+ 'id' => array('type' => 'integer', 'null' => '', 'default' => '', 'length' => '8'),
+ 'name' => array('type' => 'string', 'null' => '', 'default' => '', 'length' => '255'),
+ 'created' => array('type' => 'date', 'null' => '1', 'default' => '', 'length' => ''),
+ 'updated' => array('type' => 'datetime', 'null' => '1', 'default' => '', 'length' => null)
+ );
+ }
+ return $this->_schema;
+ }
+}
+
+/**
+ * TestModel8 class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model.datasources
+ */
+class TestModel8 extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'TestModel8'
+ * @access public
+ */
+ var $name = 'TestModel8';
+
+/**
+ * table property
+ *
+ * @var string 'test_model8'
+ * @access public
+ */
+ var $table = 'test_model8';
+
+/**
+ * useTable property
+ *
+ * @var bool false
+ * @access public
+ */
+ var $useTable = false;
+
+/**
+ * hasOne property
+ *
+ * @var array
+ * @access public
+ */
+ var $hasOne = array(
+ 'TestModel9' => array(
+ 'className' => 'TestModel9',
+ 'foreignKey' => 'test_model8_id',
+ 'conditions' => 'TestModel9.name != \'mariano\''
+ )
+ );
+
+/**
+ * schema method
+ *
+ * @access public
+ * @return void
+ */
+ function schema() {
+ if (!isset($this->_schema)) {
+ $this->_schema = array(
+ 'id' => array('type' => 'integer', 'null' => '', 'default' => '', 'length' => '8'),
+ 'test_model9_id' => array('type' => 'integer', 'null' => '', 'default' => '', 'length' => '8'),
+ 'name' => array('type' => 'string', 'null' => '', 'default' => '', 'length' => '255'),
+ 'created' => array('type' => 'date', 'null' => '1', 'default' => '', 'length' => ''),
+ 'updated' => array('type' => 'datetime', 'null' => '1', 'default' => '', 'length' => null)
+ );
+ }
+ return $this->_schema;
+ }
+}
+
+/**
+ * TestModel9 class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model.datasources
+ */
+class TestModel9 extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'TestModel9'
+ * @access public
+ */
+ var $name = 'TestModel9';
+
+/**
+ * table property
+ *
+ * @var string 'test_model9'
+ * @access public
+ */
+ var $table = 'test_model9';
+
+/**
+ * useTable property
+ *
+ * @var bool false
+ * @access public
+ */
+ var $useTable = false;
+
+/**
+ * belongsTo property
+ *
+ * @var array
+ * @access public
+ */
+ var $belongsTo = array('TestModel8' => array(
+ 'className' => 'TestModel8',
+ 'foreignKey' => 'test_model8_id',
+ 'conditions' => 'TestModel8.name != \'larry\''
+ ));
+
+/**
+ * schema method
+ *
+ * @access public
+ * @return void
+ */
+ function schema() {
+ if (!isset($this->_schema)) {
+ $this->_schema = array(
+ 'id' => array('type' => 'integer', 'null' => '', 'default' => '', 'length' => '8'),
+ 'test_model8_id' => array('type' => 'integer', 'null' => '', 'default' => '', 'length' => '11'),
+ 'name' => array('type' => 'string', 'null' => '', 'default' => '', 'length' => '255'),
+ 'created' => array('type' => 'date', 'null' => '1', 'default' => '', 'length' => ''),
+ 'updated' => array('type' => 'datetime', 'null' => '1', 'default' => '', 'length' => null)
+ );
+ }
+ return $this->_schema;
+ }
+}
+
+/**
+ * Level class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model.datasources
+ */
+class Level extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'Level'
+ * @access public
+ */
+ var $name = 'Level';
+
+/**
+ * table property
+ *
+ * @var string 'level'
+ * @access public
+ */
+ var $table = 'level';
+
+/**
+ * useTable property
+ *
+ * @var bool false
+ * @access public
+ */
+ var $useTable = false;
+
+/**
+ * hasMany property
+ *
+ * @var array
+ * @access public
+ */
+ var $hasMany = array(
+ 'Group'=> array(
+ 'className' => 'Group'
+ ),
+ 'User2' => array(
+ 'className' => 'User2'
+ )
+ );
+
+/**
+ * schema method
+ *
+ * @access public
+ * @return void
+ */
+ function schema() {
+ if (!isset($this->_schema)) {
+ $this->_schema = array(
+ 'id' => array('type' => 'integer', 'null' => false, 'default' => null, 'length' => '10'),
+ 'name' => array('type' => 'string', 'null' => true, 'default' => null, 'length' => '20'),
+ );
+ }
+ return $this->_schema;
+ }
+}
+
+/**
+ * Group class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model.datasources
+ */
+class Group extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'Group'
+ * @access public
+ */
+ var $name = 'Group';
+
+/**
+ * table property
+ *
+ * @var string 'group'
+ * @access public
+ */
+ var $table = 'group';
+
+/**
+ * useTable property
+ *
+ * @var bool false
+ * @access public
+ */
+ var $useTable = false;
+
+/**
+ * belongsTo property
+ *
+ * @var array
+ * @access public
+ */
+ var $belongsTo = array('Level');
+
+/**
+ * hasMany property
+ *
+ * @var array
+ * @access public
+ */
+ var $hasMany = array('Category2', 'User2');
+
+/**
+ * schema method
+ *
+ * @access public
+ * @return void
+ */
+ function schema() {
+ if (!isset($this->_schema)) {
+ $this->_schema = array(
+ 'id' => array('type' => 'integer', 'null' => false, 'default' => null, 'length' => '10'),
+ 'level_id' => array('type' => 'integer', 'null' => false, 'default' => null, 'length' => '10'),
+ 'name' => array('type' => 'string', 'null' => true, 'default' => null, 'length' => '20'),
+ );
+ }
+ return $this->_schema;
+ }
+
+}
+
+/**
+ * User2 class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model.datasources
+ */
+class User2 extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'User2'
+ * @access public
+ */
+ var $name = 'User2';
+
+/**
+ * table property
+ *
+ * @var string 'user'
+ * @access public
+ */
+ var $table = 'user';
+
+/**
+ * useTable property
+ *
+ * @var bool false
+ * @access public
+ */
+ var $useTable = false;
+
+/**
+ * belongsTo property
+ *
+ * @var array
+ * @access public
+ */
+ var $belongsTo = array(
+ 'Group' => array(
+ 'className' => 'Group'
+ ),
+ 'Level' => array(
+ 'className' => 'Level'
+ )
+ );
+
+/**
+ * hasMany property
+ *
+ * @var array
+ * @access public
+ */
+ var $hasMany = array(
+ 'Article2' => array(
+ 'className' => 'Article2'
+ ),
+ );
+
+/**
+ * schema method
+ *
+ * @access public
+ * @return void
+ */
+ function schema() {
+ if (!isset($this->_schema)) {
+ $this->_schema = array(
+ 'id' => array('type' => 'integer', 'null' => false, 'default' => null, 'length' => '10'),
+ 'group_id' => array('type' => 'integer', 'null' => false, 'default' => null, 'length' => '10'),
+ 'level_id' => array('type' => 'integer', 'null' => false, 'default' => null, 'length' => '10'),
+ 'name' => array('type' => 'string', 'null' => true, 'default' => null, 'length' => '20'),
+ );
+ }
+ return $this->_schema;
+ }
+}
+
+/**
+ * Category2 class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model.datasources
+ */
+class Category2 extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'Category2'
+ * @access public
+ */
+ var $name = 'Category2';
+
+/**
+ * table property
+ *
+ * @var string 'category'
+ * @access public
+ */
+ var $table = 'category';
+
+/**
+ * useTable property
+ *
+ * @var bool false
+ * @access public
+ */
+ var $useTable = false;
+
+/**
+ * belongsTo property
+ *
+ * @var array
+ * @access public
+ */
+ var $belongsTo = array(
+ 'Group' => array(
+ 'className' => 'Group',
+ 'foreignKey' => 'group_id'
+ ),
+ 'ParentCat' => array(
+ 'className' => 'Category2',
+ 'foreignKey' => 'parent_id'
+ )
+ );
+
+/**
+ * hasMany property
+ *
+ * @var array
+ * @access public
+ */
+ var $hasMany = array(
+ 'ChildCat' => array(
+ 'className' => 'Category2',
+ 'foreignKey' => 'parent_id'
+ ),
+ 'Article2' => array(
+ 'className' => 'Article2',
+ 'order'=>'Article2.published_date DESC',
+ 'foreignKey' => 'category_id',
+ 'limit'=>'3')
+ );
+
+/**
+ * schema method
+ *
+ * @access public
+ * @return void
+ */
+ function schema() {
+ if (!isset($this->_schema)) {
+ $this->_schema = array(
+ 'id' => array('type' => 'integer', 'null' => false, 'default' => '', 'length' => '10'),
+ 'group_id' => array('type' => 'integer', 'null' => false, 'default' => '', 'length' => '10'),
+ 'parent_id' => array('type' => 'integer', 'null' => false, 'default' => '', 'length' => '10'),
+ 'name' => array('type' => 'string', 'null' => false, 'default' => '', 'length' => '255'),
+ 'icon' => array('type' => 'string', 'null' => false, 'default' => '', 'length' => '255'),
+ 'description' => array('type' => 'text', 'null' => false, 'default' => '', 'length' => null),
+
+ );
+ }
+ return $this->_schema;
+ }
+}
+
+/**
+ * Article2 class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model.datasources
+ */
+class Article2 extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'Article2'
+ * @access public
+ */
+ var $name = 'Article2';
+
+/**
+ * table property
+ *
+ * @var string 'article'
+ * @access public
+ */
+ var $table = 'article';
+
+/**
+ * useTable property
+ *
+ * @var bool false
+ * @access public
+ */
+ var $useTable = false;
+
+/**
+ * belongsTo property
+ *
+ * @var array
+ * @access public
+ */
+ var $belongsTo = array(
+ 'Category2' => array('className' => 'Category2'),
+ 'User2' => array('className' => 'User2')
+ );
+
+/**
+ * schema method
+ *
+ * @access public
+ * @return void
+ */
+ function schema() {
+ if (!isset($this->_schema)) {
+ $this->_schema = array(
+ 'id' => array('type' => 'integer', 'null' => false, 'default' => '', 'length' => '10'),
+ 'category_id' => array('type' => 'integer', 'null' => false, 'default' => '0', 'length' => '10'),
+ 'user_id' => array('type' => 'integer', 'null' => false, 'default' => '0', 'length' => '10'),
+ 'rate_count' => array('type' => 'integer', 'null' => false, 'default' => '0', 'length' => '10'),
+ 'rate_sum' => array('type' => 'integer', 'null' => false, 'default' => '0', 'length' => '10'),
+ 'viewed' => array('type' => 'integer', 'null' => false, 'default' => '0', 'length' => '10'),
+ 'version' => array('type' => 'string', 'null' => true, 'default' => '', 'length' => '45'),
+ 'title' => array('type' => 'string', 'null' => false, 'default' => '', 'length' => '200'),
+ 'intro' => array('text' => 'string', 'null' => true, 'default' => '', 'length' => null),
+ 'comments' => array('type' => 'integer', 'null' => false, 'default' => '0', 'length' => '4'),
+ 'body' => array('text' => 'string', 'null' => true, 'default' => '', 'length' => null),
+ 'isdraft' => array('type' => 'boolean', 'null' => false, 'default' => '0', 'length' => '1'),
+ 'allow_comments' => array('type' => 'boolean', 'null' => false, 'default' => '1', 'length' => '1'),
+ 'moderate_comments' => array('type' => 'boolean', 'null' => false, 'default' => '1', 'length' => '1'),
+ 'published' => array('type' => 'boolean', 'null' => false, 'default' => '0', 'length' => '1'),
+ 'multipage' => array('type' => 'boolean', 'null' => false, 'default' => '0', 'length' => '1'),
+ 'published_date' => array('type' => 'datetime', 'null' => true, 'default' => '', 'length' => null),
+ 'created' => array('type' => 'datetime', 'null' => false, 'default' => '0000-00-00 00:00:00', 'length' => null),
+ 'modified' => array('type' => 'datetime', 'null' => false, 'default' => '0000-00-00 00:00:00', 'length' => null)
+ );
+ }
+ return $this->_schema;
+ }
+}
+
+/**
+ * CategoryFeatured2 class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model.datasources
+ */
+class CategoryFeatured2 extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'CategoryFeatured2'
+ * @access public
+ */
+ var $name = 'CategoryFeatured2';
+
+/**
+ * table property
+ *
+ * @var string 'category_featured'
+ * @access public
+ */
+ var $table = 'category_featured';
+
+/**
+ * useTable property
+ *
+ * @var bool false
+ * @access public
+ */
+ var $useTable = false;
+
+/**
+ * schema method
+ *
+ * @access public
+ * @return void
+ */
+ function schema() {
+ if (!isset($this->_schema)) {
+ $this->_schema = array(
+ 'id' => array('type' => 'integer', 'null' => false, 'default' => '', 'length' => '10'),
+ 'parent_id' => array('type' => 'integer', 'null' => false, 'default' => '', 'length' => '10'),
+ 'name' => array('type' => 'string', 'null' => false, 'default' => '', 'length' => '255'),
+ 'icon' => array('type' => 'string', 'null' => false, 'default' => '', 'length' => '255'),
+ 'description' => array('text' => 'string', 'null' => false, 'default' => '', 'length' => null)
+ );
+ }
+ return $this->_schema;
+ }
+}
+
+/**
+ * Featured2 class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model.datasources
+ */
+class Featured2 extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'Featured2'
+ * @access public
+ */
+ var $name = 'Featured2';
+
+/**
+ * table property
+ *
+ * @var string 'featured2'
+ * @access public
+ */
+ var $table = 'featured2';
+
+/**
+ * useTable property
+ *
+ * @var bool false
+ * @access public
+ */
+ var $useTable = false;
+
+/**
+ * belongsTo property
+ *
+ * @var array
+ * @access public
+ */
+ var $belongsTo = array(
+ 'CategoryFeatured2' => array(
+ 'className' => 'CategoryFeatured2'
+ )
+ );
+
+/**
+ * schema method
+ *
+ * @access public
+ * @return void
+ */
+ function schema() {
+ if (!isset($this->_schema)) {
+ $this->_schema = array(
+ 'id' => array('type' => 'integer', 'null' => false, 'default' => null, 'length' => '10'),
+ 'article_id' => array('type' => 'integer', 'null' => false, 'default' => '0', 'length' => '10'),
+ 'category_id' => array('type' => 'integer', 'null' => false, 'default' => '0', 'length' => '10'),
+ 'name' => array('type' => 'string', 'null' => true, 'default' => null, 'length' => '20')
+ );
+ }
+ return $this->_schema;
+ }
+}
+
+/**
+ * Comment2 class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model.datasources
+ */
+class Comment2 extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'Comment2'
+ * @access public
+ */
+ var $name = 'Comment2';
+
+/**
+ * table property
+ *
+ * @var string 'comment'
+ * @access public
+ */
+ var $table = 'comment';
+
+/**
+ * belongsTo property
+ *
+ * @var array
+ * @access public
+ */
+ var $belongsTo = array('ArticleFeatured2', 'User2');
+
+/**
+ * useTable property
+ *
+ * @var bool false
+ * @access public
+ */
+ var $useTable = false;
+
+/**
+ * schema method
+ *
+ * @access public
+ * @return void
+ */
+ function schema() {
+ if (!isset($this->_schema)) {
+ $this->_schema = array(
+ 'id' => array('type' => 'integer', 'null' => false, 'default' => null, 'length' => '10'),
+ 'article_featured_id' => array('type' => 'integer', 'null' => false, 'default' => '0', 'length' => '10'),
+ 'user_id' => array('type' => 'integer', 'null' => false, 'default' => '0', 'length' => '10'),
+ 'name' => array('type' => 'string', 'null' => true, 'default' => null, 'length' => '20')
+ );
+ }
+ return $this->_schema;
+ }
+}
+
+/**
+ * ArticleFeatured2 class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model.datasources
+ */
+class ArticleFeatured2 extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'ArticleFeatured2'
+ * @access public
+ */
+ var $name = 'ArticleFeatured2';
+
+/**
+ * table property
+ *
+ * @var string 'article_featured'
+ * @access public
+ */
+ var $table = 'article_featured';
+
+/**
+ * useTable property
+ *
+ * @var bool false
+ * @access public
+ */
+ var $useTable = false;
+
+/**
+ * belongsTo property
+ *
+ * @var array
+ * @access public
+ */
+ var $belongsTo = array(
+ 'CategoryFeatured2' => array('className' => 'CategoryFeatured2'),
+ 'User2' => array('className' => 'User2')
+ );
+
+/**
+ * hasOne property
+ *
+ * @var array
+ * @access public
+ */
+ var $hasOne = array(
+ 'Featured2' => array('className' => 'Featured2')
+ );
+
+/**
+ * hasMany property
+ *
+ * @var array
+ * @access public
+ */
+ var $hasMany = array(
+ 'Comment2' => array('className'=>'Comment2', 'dependent' => true)
+ );
+
+/**
+ * schema method
+ *
+ * @access public
+ * @return void
+ */
+ function schema() {
+ if (!isset($this->_schema)) {
+ $this->_schema = array(
+ 'id' => array('type' => 'integer', 'null' => false, 'default' => null, 'length' => '10'),
+ 'category_featured_id' => array('type' => 'integer', 'null' => false, 'default' => '0', 'length' => '10'),
+ 'user_id' => array('type' => 'integer', 'null' => false, 'default' => '0', 'length' => '10'),
+ 'title' => array('type' => 'string', 'null' => true, 'default' => null, 'length' => '20'),
+ 'body' => array('text' => 'string', 'null' => true, 'default' => '', 'length' => null),
+ 'published' => array('type' => 'boolean', 'null' => false, 'default' => '0', 'length' => '1'),
+ 'published_date' => array('type' => 'datetime', 'null' => true, 'default' => '', 'length' => null),
+ 'created' => array('type' => 'datetime', 'null' => false, 'default' => '0000-00-00 00:00:00', 'length' => null),
+ 'modified' => array('type' => 'datetime', 'null' => false, 'default' => '0000-00-00 00:00:00', 'length' => null)
+ );
+ }
+ return $this->_schema;
+ }
+}
+
+/**
+ * DboSourceTest class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model.datasources
+ */
+class DboSourceTest extends CakeTestCase {
+
+/**
+ * debug property
+ *
+ * @var mixed null
+ * @access public
+ */
+ var $debug = null;
+
+/**
+ * autoFixtures property
+ *
+ * @var bool false
+ * @access public
+ */
+ var $autoFixtures = false;
+
+/**
+ * fixtures property
+ *
+ * @var array
+ * @access public
+ */
+ var $fixtures = array(
+ 'core.apple', 'core.article', 'core.articles_tag', 'core.attachment', 'core.comment',
+ 'core.sample', 'core.tag', 'core.user', 'core.post', 'core.author', 'core.data_test'
+ );
+
+/**
+ * startTest method
+ *
+ * @access public
+ * @return void
+ */
+ function startTest() {
+ $this->__config = $this->db->config;
+
+ if (!class_exists('DboTest')) {
+ $db = ConnectionManager::getDataSource('test_suite');
+ $class = get_class($db);
+ eval("class DboTest extends $class {
+ var \$simulated = array();
+
+/**
+ * execute method
+ *
+ * @param \$sql
+ * @access protected
+ * @return void
+ */
+ function _execute(\$sql) {
+ \$this->simulated[] = \$sql;
+ return null;
+ }
+
+/**
+ * getLastQuery method
+ *
+ * @access public
+ * @return void
+ */
+ function getLastQuery() {
+ return \$this->simulated[count(\$this->simulated) - 1];
+ }
+ }");
+ }
+
+ $this->testDb =& new DboTest($this->__config);
+ $this->testDb->cacheSources = false;
+ $this->testDb->startQuote = '`';
+ $this->testDb->endQuote = '`';
+ Configure::write('debug', 1);
+ $this->debug = Configure::read('debug');
+ $this->Model =& new TestModel();
+ }
+
+/**
+ * endTest method
+ *
+ * @access public
+ * @return void
+ */
+ function endTest() {
+ unset($this->Model);
+ Configure::write('debug', $this->debug);
+ ClassRegistry::flush();
+ unset($this->debug);
+ }
+
+/**
+ * testFieldDoubleEscaping method
+ *
+ * @access public
+ * @return void
+ */
+ function testFieldDoubleEscaping() {
+ $config = array_merge($this->__config, array('driver' => 'test'));
+ $test =& ConnectionManager::create('quoteTest', $config);
+ $test->simulated = array();
+
+ $this->Model =& new Article2(array('alias' => 'Article', 'ds' => 'quoteTest'));
+ $this->Model->setDataSource('quoteTest');
+
+ $this->assertEqual($this->Model->escapeField(), '`Article`.`id`');
+ $result = $test->fields($this->Model, null, $this->Model->escapeField());
+ $this->assertEqual($result, array('`Article`.`id`'));
+
+ $result = $test->read($this->Model, array(
+ 'fields' => $this->Model->escapeField(),
+ 'conditions' => null,
+ 'recursive' => -1
+ ));
+ $this->assertEqual(trim($test->simulated[0]), 'SELECT `Article`.`id` FROM `' . $this->testDb->fullTableName('article', false) . '` AS `Article` WHERE 1 = 1');
+
+ $test->startQuote = '[';
+ $test->endQuote = ']';
+ $this->assertEqual($this->Model->escapeField(), '[Article].[id]');
+
+ $result = $test->fields($this->Model, null, $this->Model->escapeField());
+ $this->assertEqual($result, array('[Article].[id]'));
+
+ $result = $test->read($this->Model, array(
+ 'fields' => $this->Model->escapeField(),
+ 'conditions' => null,
+ 'recursive' => -1
+ ));
+ $this->assertEqual(trim($test->simulated[1]), 'SELECT [Article].[id] FROM [' . $this->testDb->fullTableName('article', false) . '] AS [Article] WHERE 1 = 1');
+
+ ClassRegistry::removeObject('Article');
+ }
+
+/**
+ * testGenerateAssociationQuerySelfJoin method
+ *
+ * @access public
+ * @return void
+ */
+ function testGenerateAssociationQuerySelfJoin() {
+ $this->startTime = microtime(true);
+ $this->Model =& new Article2();
+ $this->_buildRelatedModels($this->Model);
+ $this->_buildRelatedModels($this->Model->Category2);
+ $this->Model->Category2->ChildCat =& new Category2();
+ $this->Model->Category2->ParentCat =& new Category2();
+
+ $queryData = array();
+
+ foreach ($this->Model->Category2->__associations as $type) {
+ foreach ($this->Model->Category2->{$type} as $assoc => $assocData) {
+ $linkModel =& $this->Model->Category2->{$assoc};
+ $external = isset($assocData['external']);
+
+ if ($this->Model->Category2->alias == $linkModel->alias && $type != 'hasAndBelongsToMany' && $type != 'hasMany') {
+ $result = $this->testDb->generateAssociationQuery($this->Model->Category2, $linkModel, $type, $assoc, $assocData, $queryData, $external, $null);
+ $this->assertTrue($result);
+ } else {
+ if ($this->Model->Category2->useDbConfig == $linkModel->useDbConfig) {
+ $result = $this->testDb->generateAssociationQuery($this->Model->Category2, $linkModel, $type, $assoc, $assocData, $queryData, $external, $null);
+ $this->assertTrue($result);
+ }
+ }
+ }
+ }
+
+ $query = $this->testDb->generateAssociationQuery($this->Model->Category2, $null, null, null, null, $queryData, false, $null);
+ $this->assertPattern('/^SELECT\s+(.+)FROM(.+)`Category2`\.`group_id`\s+=\s+`Group`\.`id`\)\s+LEFT JOIN(.+)WHERE\s+1 = 1\s*$/', $query);
+
+ $this->Model =& new TestModel4();
+ $this->Model->schema();
+ $this->_buildRelatedModels($this->Model);
+
+ $binding = array('type' => 'belongsTo', 'model' => 'TestModel4Parent');
+ $queryData = array();
+ $resultSet = null;
+ $null = null;
+
+ $params = &$this->_prepareAssociationQuery($this->Model, $queryData, $binding);
+
+ $_queryData = $queryData;
+ $result = $this->testDb->generateAssociationQuery($this->Model, $params['linkModel'], $params['type'], $params['assoc'], $params['assocData'], $queryData, $params['external'], $resultSet);
+ $this->assertTrue($result);
+
+ $expected = array(
+ 'fields' => array(
+ '`TestModel4`.`id`',
+ '`TestModel4`.`name`',
+ '`TestModel4`.`created`',
+ '`TestModel4`.`updated`',
+ '`TestModel4Parent`.`id`',
+ '`TestModel4Parent`.`name`',
+ '`TestModel4Parent`.`created`',
+ '`TestModel4Parent`.`updated`'
+ ),
+ 'joins' => array(
+ array(
+ 'table' => '`test_model4`',
+ 'alias' => 'TestModel4Parent',
+ 'type' => 'LEFT',
+ 'conditions' => '`TestModel4`.`parent_id` = `TestModel4Parent`.`id`'
+ )
+ ),
+ 'limit' => array(),
+ 'offset' => array(),
+ 'conditions' => array(),
+ 'order' => array(),
+ 'group' => null
+ );
+ $this->assertEqual($queryData, $expected);
+
+ $result = $this->testDb->generateAssociationQuery($this->Model, $null, null, null, null, $queryData, false, $null);
+ $this->assertPattern('/^SELECT\s+`TestModel4`\.`id`, `TestModel4`\.`name`, `TestModel4`\.`created`, `TestModel4`\.`updated`, `TestModel4Parent`\.`id`, `TestModel4Parent`\.`name`, `TestModel4Parent`\.`created`, `TestModel4Parent`\.`updated`\s+/', $result);
+ $this->assertPattern('/FROM\s+`test_model4` AS `TestModel4`\s+LEFT JOIN\s+`test_model4` AS `TestModel4Parent`/', $result);
+ $this->assertPattern('/\s+ON\s+\(`TestModel4`.`parent_id` = `TestModel4Parent`.`id`\)\s+WHERE/', $result);
+ $this->assertPattern('/\s+WHERE\s+1 = 1\s+$/', $result);
+
+ $params['assocData']['type'] = 'INNER';
+ $this->Model->belongsTo['TestModel4Parent']['type'] = 'INNER';
+ $result = $this->testDb->generateAssociationQuery($this->Model, $params['linkModel'], $params['type'], $params['assoc'], $params['assocData'], $_queryData, $params['external'], $resultSet);
+ $this->assertTrue($result);
+ $this->assertEqual($_queryData['joins'][0]['type'], 'INNER');
+ }
+
+/**
+ * testGenerateInnerJoinAssociationQuery method
+ *
+ * @access public
+ * @return void
+ */
+ function testGenerateInnerJoinAssociationQuery() {
+ $this->Model =& new TestModel9();
+ $test =& ConnectionManager::create('test2', $this->__config);
+ $this->Model->setDataSource('test2');
+ $this->Model->TestModel8 =& new TestModel8();
+ $this->Model->TestModel8->setDataSource('test2');
+
+ $this->testDb->read($this->Model, array('recursive' => 1));
+ $result = $this->testDb->getLastQuery();
+ $this->assertPattern('/`TestModel9` LEFT JOIN `' . $this->testDb->fullTableName('test_model8', false) . '`/', $result);
+
+ $this->Model->belongsTo['TestModel8']['type'] = 'INNER';
+ $this->testDb->read($this->Model, array('recursive' => 1));
+ $result = $this->testDb->getLastQuery();
+ $this->assertPattern('/`TestModel9` INNER JOIN `' . $this->testDb->fullTableName('test_model8', false) . '`/', $result);
+
+ }
+
+/**
+ * testGenerateAssociationQuerySelfJoinWithConditionsInHasOneBinding method
+ *
+ * @access public
+ * @return void
+ */
+ function testGenerateAssociationQuerySelfJoinWithConditionsInHasOneBinding() {
+ $this->Model =& new TestModel8();
+ $this->Model->schema();
+ $this->_buildRelatedModels($this->Model);
+
+ $binding = array('type' => 'hasOne', 'model' => 'TestModel9');
+ $queryData = array();
+ $resultSet = null;
+ $null = null;
+
+ $params = &$this->_prepareAssociationQuery($this->Model, $queryData, $binding);
+ $_queryData = $queryData;
+ $result = $this->testDb->generateAssociationQuery($this->Model, $params['linkModel'], $params['type'], $params['assoc'], $params['assocData'], $queryData, $params['external'], $resultSet);
+ $this->assertTrue($result);
+
+ $result = $this->testDb->generateAssociationQuery($this->Model, $null, null, null, null, $queryData, false, $null);
+ $this->assertPattern('/^SELECT\s+`TestModel8`\.`id`, `TestModel8`\.`test_model9_id`, `TestModel8`\.`name`, `TestModel8`\.`created`, `TestModel8`\.`updated`, `TestModel9`\.`id`, `TestModel9`\.`test_model8_id`, `TestModel9`\.`name`, `TestModel9`\.`created`, `TestModel9`\.`updated`\s+/', $result);
+ $this->assertPattern('/FROM\s+`test_model8` AS `TestModel8`\s+LEFT JOIN\s+`test_model9` AS `TestModel9`/', $result);
+ $this->assertPattern('/\s+ON\s+\(`TestModel9`\.`name` != \'mariano\'\s+AND\s+`TestModel9`.`test_model8_id` = `TestModel8`.`id`\)\s+WHERE/', $result);
+ $this->assertPattern('/\s+WHERE\s+(?:\()?1\s+=\s+1(?:\))?\s*$/', $result);
+ }
+
+/**
+ * testGenerateAssociationQuerySelfJoinWithConditionsInBelongsToBinding method
+ *
+ * @access public
+ * @return void
+ */
+ function testGenerateAssociationQuerySelfJoinWithConditionsInBelongsToBinding() {
+ $this->Model =& new TestModel9();
+ $this->Model->schema();
+ $this->_buildRelatedModels($this->Model);
+
+ $binding = array('type' => 'belongsTo', 'model' => 'TestModel8');
+ $queryData = array();
+ $resultSet = null;
+ $null = null;
+
+ $params = &$this->_prepareAssociationQuery($this->Model, $queryData, $binding);
+ $result = $this->testDb->generateAssociationQuery($this->Model, $params['linkModel'], $params['type'], $params['assoc'], $params['assocData'], $queryData, $params['external'], $resultSet);
+ $this->assertTrue($result);
+
+ $result = $this->testDb->generateAssociationQuery($this->Model, $null, null, null, null, $queryData, false, $null);
+ $this->assertPattern('/^SELECT\s+`TestModel9`\.`id`, `TestModel9`\.`test_model8_id`, `TestModel9`\.`name`, `TestModel9`\.`created`, `TestModel9`\.`updated`, `TestModel8`\.`id`, `TestModel8`\.`test_model9_id`, `TestModel8`\.`name`, `TestModel8`\.`created`, `TestModel8`\.`updated`\s+/', $result);
+ $this->assertPattern('/FROM\s+`test_model9` AS `TestModel9`\s+LEFT JOIN\s+`test_model8` AS `TestModel8`/', $result);
+ $this->assertPattern('/\s+ON\s+\(`TestModel8`\.`name` != \'larry\'\s+AND\s+`TestModel9`.`test_model8_id` = `TestModel8`.`id`\)\s+WHERE/', $result);
+ $this->assertPattern('/\s+WHERE\s+(?:\()?1\s+=\s+1(?:\))?\s*$/', $result);
+ }
+
+/**
+ * testGenerateAssociationQuerySelfJoinWithConditions method
+ *
+ * @access public
+ * @return void
+ */
+ function testGenerateAssociationQuerySelfJoinWithConditions() {
+ $this->Model =& new TestModel4();
+ $this->Model->schema();
+ $this->_buildRelatedModels($this->Model);
+
+ $binding = array('type' => 'belongsTo', 'model' => 'TestModel4Parent');
+ $queryData = array('conditions' => array('TestModel4Parent.name !=' => 'mariano'));
+ $resultSet = null;
+ $null = null;
+
+ $params = &$this->_prepareAssociationQuery($this->Model, $queryData, $binding);
+
+ $result = $this->testDb->generateAssociationQuery($this->Model, $params['linkModel'], $params['type'], $params['assoc'], $params['assocData'], $queryData, $params['external'], $resultSet);
+ $this->assertTrue($result);
+
+ $result = $this->testDb->generateAssociationQuery($this->Model, $null, null, null, null, $queryData, false, $null);
+ $this->assertPattern('/^SELECT\s+`TestModel4`\.`id`, `TestModel4`\.`name`, `TestModel4`\.`created`, `TestModel4`\.`updated`, `TestModel4Parent`\.`id`, `TestModel4Parent`\.`name`, `TestModel4Parent`\.`created`, `TestModel4Parent`\.`updated`\s+/', $result);
+ $this->assertPattern('/FROM\s+`test_model4` AS `TestModel4`\s+LEFT JOIN\s+`test_model4` AS `TestModel4Parent`/', $result);
+ $this->assertPattern('/\s+ON\s+\(`TestModel4`.`parent_id` = `TestModel4Parent`.`id`\)\s+WHERE/', $result);
+ $this->assertPattern('/\s+WHERE\s+(?:\()?`TestModel4Parent`.`name`\s+!=\s+\'mariano\'(?:\))?\s*$/', $result);
+
+ $this->Featured2 =& new Featured2();
+ $this->Featured2->schema();
+
+ $this->Featured2->bindModel(array(
+ 'belongsTo' => array(
+ 'ArticleFeatured2' => array(
+ 'conditions' => 'ArticleFeatured2.published = \'Y\'',
+ 'fields' => 'id, title, user_id, published'
+ )
+ )
+ ));
+
+ $this->_buildRelatedModels($this->Featured2);
+
+ $binding = array('type' => 'belongsTo', 'model' => 'ArticleFeatured2');
+ $queryData = array('conditions' => array());
+ $resultSet = null;
+ $null = null;
+
+ $params = &$this->_prepareAssociationQuery($this->Featured2, $queryData, $binding);
+
+ $result = $this->testDb->generateAssociationQuery($this->Featured2, $params['linkModel'], $params['type'], $params['assoc'], $params['assocData'], $queryData, $params['external'], $resultSet);
+ $this->assertTrue($result);
+ $result = $this->testDb->generateAssociationQuery($this->Featured2, $null, null, null, null, $queryData, false, $null);
+
+ $this->assertPattern(
+ '/^SELECT\s+`Featured2`\.`id`, `Featured2`\.`article_id`, `Featured2`\.`category_id`, `Featured2`\.`name`,\s+'.
+ '`ArticleFeatured2`\.`id`, `ArticleFeatured2`\.`title`, `ArticleFeatured2`\.`user_id`, `ArticleFeatured2`\.`published`\s+' .
+ 'FROM\s+`featured2` AS `Featured2`\s+LEFT JOIN\s+`article_featured` AS `ArticleFeatured2`' .
+ '\s+ON\s+\(`ArticleFeatured2`.`published` = \'Y\'\s+AND\s+`Featured2`\.`article_featured2_id` = `ArticleFeatured2`\.`id`\)' .
+ '\s+WHERE\s+1\s+=\s+1\s*$/',
+ $result
+ );
+ }
+
+/**
+ * testGenerateAssociationQueryHasOne method
+ *
+ * @access public
+ * @return void
+ */
+ function testGenerateAssociationQueryHasOne() {
+ $this->Model =& new TestModel4();
+ $this->Model->schema();
+ $this->_buildRelatedModels($this->Model);
+
+ $binding = array('type' => 'hasOne', 'model' => 'TestModel5');
+
+ $queryData = array();
+ $resultSet = null;
+ $null = null;
+
+ $params = &$this->_prepareAssociationQuery($this->Model, $queryData, $binding);
+
+ $result = $this->testDb->generateAssociationQuery($this->Model, $params['linkModel'], $params['type'], $params['assoc'], $params['assocData'], $queryData, $params['external'], $resultSet);
+ $this->assertTrue($result);
+
+ $result = $this->testDb->buildJoinStatement($queryData['joins'][0]);
+ $expected = ' LEFT JOIN `test_model5` AS `TestModel5` ON (`TestModel5`.`test_model4_id` = `TestModel4`.`id`)';
+ $this->assertEqual(trim($result), trim($expected));
+
+ $result = $this->testDb->generateAssociationQuery($this->Model, $null, null, null, null, $queryData, false, $null);
+ $this->assertPattern('/^SELECT\s+`TestModel4`\.`id`, `TestModel4`\.`name`, `TestModel4`\.`created`, `TestModel4`\.`updated`, `TestModel5`\.`id`, `TestModel5`\.`test_model4_id`, `TestModel5`\.`name`, `TestModel5`\.`created`, `TestModel5`\.`updated`\s+/', $result);
+ $this->assertPattern('/\s+FROM\s+`test_model4` AS `TestModel4`\s+LEFT JOIN\s+/', $result);
+ $this->assertPattern('/`test_model5` AS `TestModel5`\s+ON\s+\(`TestModel5`.`test_model4_id` = `TestModel4`.`id`\)\s+WHERE/', $result);
+ $this->assertPattern('/\s+WHERE\s+(?:\()?\s*1 = 1\s*(?:\))?\s*$/', $result);
+ }
+
+/**
+ * testGenerateAssociationQueryHasOneWithConditions method
+ *
+ * @access public
+ * @return void
+ */
+ function testGenerateAssociationQueryHasOneWithConditions() {
+ $this->Model =& new TestModel4();
+ $this->Model->schema();
+ $this->_buildRelatedModels($this->Model);
+
+ $binding = array('type' => 'hasOne', 'model' => 'TestModel5');
+
+ $queryData = array('conditions' => array('TestModel5.name !=' => 'mariano'));
+ $resultSet = null;
+ $null = null;
+
+ $params = &$this->_prepareAssociationQuery($this->Model, $queryData, $binding);
+
+ $result = $this->testDb->generateAssociationQuery($this->Model, $params['linkModel'], $params['type'], $params['assoc'], $params['assocData'], $queryData, $params['external'], $resultSet);
+ $this->assertTrue($result);
+
+ $result = $this->testDb->generateAssociationQuery($this->Model, $null, null, null, null, $queryData, false, $null);
+
+ $this->assertPattern('/^SELECT\s+`TestModel4`\.`id`, `TestModel4`\.`name`, `TestModel4`\.`created`, `TestModel4`\.`updated`, `TestModel5`\.`id`, `TestModel5`\.`test_model4_id`, `TestModel5`\.`name`, `TestModel5`\.`created`, `TestModel5`\.`updated`\s+/', $result);
+ $this->assertPattern('/\s+FROM\s+`test_model4` AS `TestModel4`\s+LEFT JOIN\s+`test_model5` AS `TestModel5`/', $result);
+ $this->assertPattern('/\s+ON\s+\(`TestModel5`.`test_model4_id`\s+=\s+`TestModel4`.`id`\)\s+WHERE/', $result);
+ $this->assertPattern('/\s+WHERE\s+(?:\()?\s*`TestModel5`.`name`\s+!=\s+\'mariano\'\s*(?:\))?\s*$/', $result);
+ }
+
+/**
+ * testGenerateAssociationQueryBelongsTo method
+ *
+ * @access public
+ * @return void
+ */
+ function testGenerateAssociationQueryBelongsTo() {
+ $this->Model =& new TestModel5();
+ $this->Model->schema();
+ $this->_buildRelatedModels($this->Model);
+
+ $binding = array('type'=>'belongsTo', 'model'=>'TestModel4');
+ $queryData = array();
+ $resultSet = null;
+ $null = null;
+
+ $params = &$this->_prepareAssociationQuery($this->Model, $queryData, $binding);
+
+ $result = $this->testDb->generateAssociationQuery($this->Model, $params['linkModel'], $params['type'], $params['assoc'], $params['assocData'], $queryData, $params['external'], $resultSet);
+ $this->assertTrue($result);
+
+ $result = $this->testDb->buildJoinStatement($queryData['joins'][0]);
+ $expected = ' LEFT JOIN `test_model4` AS `TestModel4` ON (`TestModel5`.`test_model4_id` = `TestModel4`.`id`)';
+ $this->assertEqual(trim($result), trim($expected));
+
+ $result = $this->testDb->generateAssociationQuery($this->Model, $null, null, null, null, $queryData, false, $null);
+ $this->assertPattern('/^SELECT\s+`TestModel5`\.`id`, `TestModel5`\.`test_model4_id`, `TestModel5`\.`name`, `TestModel5`\.`created`, `TestModel5`\.`updated`, `TestModel4`\.`id`, `TestModel4`\.`name`, `TestModel4`\.`created`, `TestModel4`\.`updated`\s+/', $result);
+ $this->assertPattern('/\s+FROM\s+`test_model5` AS `TestModel5`\s+LEFT JOIN\s+`test_model4` AS `TestModel4`/', $result);
+ $this->assertPattern('/\s+ON\s+\(`TestModel5`.`test_model4_id` = `TestModel4`.`id`\)\s+WHERE\s+/', $result);
+ $this->assertPattern('/\s+WHERE\s+(?:\()?\s*1 = 1\s*(?:\))?\s*$/', $result);
+ }
+
+/**
+ * testGenerateAssociationQueryBelongsToWithConditions method
+ *
+ * @access public
+ * @return void
+ */
+ function testGenerateAssociationQueryBelongsToWithConditions() {
+ $this->Model =& new TestModel5();
+ $this->Model->schema();
+ $this->_buildRelatedModels($this->Model);
+
+ $binding = array('type' => 'belongsTo', 'model' => 'TestModel4');
+ $queryData = array('conditions' => array('TestModel5.name !=' => 'mariano'));
+ $resultSet = null;
+ $null = null;
+
+ $params = &$this->_prepareAssociationQuery($this->Model, $queryData, $binding);
+
+ $result = $this->testDb->generateAssociationQuery($this->Model, $params['linkModel'], $params['type'], $params['assoc'], $params['assocData'], $queryData, $params['external'], $resultSet);
+ $this->assertTrue($result);
+
+ $result = $this->testDb->buildJoinStatement($queryData['joins'][0]);
+ $expected = ' LEFT JOIN `test_model4` AS `TestModel4` ON (`TestModel5`.`test_model4_id` = `TestModel4`.`id`)';
+ $this->assertEqual(trim($result), trim($expected));
+
+ $result = $this->testDb->generateAssociationQuery($this->Model, $null, null, null, null, $queryData, false, $null);
+ $this->assertPattern('/^SELECT\s+`TestModel5`\.`id`, `TestModel5`\.`test_model4_id`, `TestModel5`\.`name`, `TestModel5`\.`created`, `TestModel5`\.`updated`, `TestModel4`\.`id`, `TestModel4`\.`name`, `TestModel4`\.`created`, `TestModel4`\.`updated`\s+/', $result);
+ $this->assertPattern('/\s+FROM\s+`test_model5` AS `TestModel5`\s+LEFT JOIN\s+`test_model4` AS `TestModel4`/', $result);
+ $this->assertPattern('/\s+ON\s+\(`TestModel5`.`test_model4_id` = `TestModel4`.`id`\)\s+WHERE\s+/', $result);
+ $this->assertPattern('/\s+WHERE\s+`TestModel5`.`name` != \'mariano\'\s*$/', $result);
+ }
+
+/**
+ * testGenerateAssociationQueryHasMany method
+ *
+ * @access public
+ * @return void
+ */
+ function testGenerateAssociationQueryHasMany() {
+ $this->Model =& new TestModel5();
+ $this->Model->schema();
+ $this->_buildRelatedModels($this->Model);
+
+ $binding = array('type' => 'hasMany', 'model' => 'TestModel6');
+ $queryData = array();
+ $resultSet = null;
+ $null = null;
+
+ $params = &$this->_prepareAssociationQuery($this->Model, $queryData, $binding);
+
+ $result = $this->testDb->generateAssociationQuery($this->Model, $params['linkModel'], $params['type'], $params['assoc'], $params['assocData'], $queryData, $params['external'], $resultSet);
+
+ $this->assertPattern('/^SELECT\s+`TestModel6`\.`id`, `TestModel6`\.`test_model5_id`, `TestModel6`\.`name`, `TestModel6`\.`created`, `TestModel6`\.`updated`\s+/', $result);
+ $this->assertPattern('/\s+FROM\s+`test_model6` AS `TestModel6`\s+WHERE/', $result);
+ $this->assertPattern('/\s+WHERE\s+`TestModel6`.`test_model5_id`\s+=\s+\({\$__cakeID__\$}\)/', $result);
+
+ $result = $this->testDb->generateAssociationQuery($this->Model, $null, null, null, null, $queryData, false, $null);
+ $this->assertPattern('/^SELECT\s+`TestModel5`\.`id`, `TestModel5`\.`test_model4_id`, `TestModel5`\.`name`, `TestModel5`\.`created`, `TestModel5`\.`updated`\s+/', $result);
+ $this->assertPattern('/\s+FROM\s+`test_model5` AS `TestModel5`\s+WHERE\s+/', $result);
+ $this->assertPattern('/\s+WHERE\s+(?:\()?\s*1 = 1\s*(?:\))?\s*$/', $result);
+ }
+
+/**
+ * testGenerateAssociationQueryHasManyWithLimit method
+ *
+ * @access public
+ * @return void
+ */
+ function testGenerateAssociationQueryHasManyWithLimit() {
+ $this->Model =& new TestModel5();
+ $this->Model->schema();
+ $this->_buildRelatedModels($this->Model);
+
+ $this->Model->hasMany['TestModel6']['limit'] = 2;
+
+ $binding = array('type' => 'hasMany', 'model' => 'TestModel6');
+ $queryData = array();
+ $resultSet = null;
+ $null = null;
+
+ $params = &$this->_prepareAssociationQuery($this->Model, $queryData, $binding);
+
+ $result = $this->testDb->generateAssociationQuery($this->Model, $params['linkModel'], $params['type'], $params['assoc'], $params['assocData'], $queryData, $params['external'], $resultSet);
+ $this->assertPattern(
+ '/^SELECT\s+' .
+ '`TestModel6`\.`id`, `TestModel6`\.`test_model5_id`, `TestModel6`\.`name`, `TestModel6`\.`created`, `TestModel6`\.`updated`\s+'.
+ 'FROM\s+`test_model6` AS `TestModel6`\s+WHERE\s+' .
+ '`TestModel6`.`test_model5_id`\s+=\s+\({\$__cakeID__\$}\)\s*'.
+ 'LIMIT \d*'.
+ '\s*$/', $result
+ );
+
+ $result = $this->testDb->generateAssociationQuery($this->Model, $null, null, null, null, $queryData, false, $null);
+ $this->assertPattern(
+ '/^SELECT\s+'.
+ '`TestModel5`\.`id`, `TestModel5`\.`test_model4_id`, `TestModel5`\.`name`, `TestModel5`\.`created`, `TestModel5`\.`updated`\s+'.
+ 'FROM\s+`test_model5` AS `TestModel5`\s+WHERE\s+'.
+ '(?:\()?\s*1 = 1\s*(?:\))?'.
+ '\s*$/', $result
+ );
+ }
+
+/**
+ * testGenerateAssociationQueryHasManyWithConditions method
+ *
+ * @access public
+ * @return void
+ */
+ function testGenerateAssociationQueryHasManyWithConditions() {
+ $this->Model =& new TestModel5();
+ $this->Model->schema();
+ $this->_buildRelatedModels($this->Model);
+
+ $binding = array('type' => 'hasMany', 'model' => 'TestModel6');
+ $queryData = array('conditions' => array('TestModel5.name !=' => 'mariano'));
+ $resultSet = null;
+ $null = null;
+
+ $params = &$this->_prepareAssociationQuery($this->Model, $queryData, $binding);
+
+ $result = $this->testDb->generateAssociationQuery($this->Model, $params['linkModel'], $params['type'], $params['assoc'], $params['assocData'], $queryData, $params['external'], $resultSet);
+ $this->assertPattern('/^SELECT\s+`TestModel6`\.`id`, `TestModel6`\.`test_model5_id`, `TestModel6`\.`name`, `TestModel6`\.`created`, `TestModel6`\.`updated`\s+/', $result);
+ $this->assertPattern('/\s+FROM\s+`test_model6` AS `TestModel6`\s+WHERE\s+/', $result);
+ $this->assertPattern('/WHERE\s+(?:\()?`TestModel6`\.`test_model5_id`\s+=\s+\({\$__cakeID__\$}\)(?:\))?/', $result);
+
+ $result = $this->testDb->generateAssociationQuery($this->Model, $null, null, null, null, $queryData, false, $null);
+ $this->assertPattern('/^SELECT\s+`TestModel5`\.`id`, `TestModel5`\.`test_model4_id`, `TestModel5`\.`name`, `TestModel5`\.`created`, `TestModel5`\.`updated`\s+/', $result);
+ $this->assertPattern('/\s+FROM\s+`test_model5` AS `TestModel5`\s+WHERE\s+/', $result);
+ $this->assertPattern('/\s+WHERE\s+(?:\()?`TestModel5`.`name`\s+!=\s+\'mariano\'(?:\))?\s*$/', $result);
+ }
+
+/**
+ * testGenerateAssociationQueryHasManyWithOffsetAndLimit method
+ *
+ * @access public
+ * @return void
+ */
+ function testGenerateAssociationQueryHasManyWithOffsetAndLimit() {
+ $this->Model =& new TestModel5();
+ $this->Model->schema();
+ $this->_buildRelatedModels($this->Model);
+
+ $__backup = $this->Model->hasMany['TestModel6'];
+
+ $this->Model->hasMany['TestModel6']['offset'] = 2;
+ $this->Model->hasMany['TestModel6']['limit'] = 5;
+
+ $binding = array('type' => 'hasMany', 'model' => 'TestModel6');
+ $queryData = array();
+ $resultSet = null;
+ $null = null;
+
+ $params = &$this->_prepareAssociationQuery($this->Model, $queryData, $binding);
+
+ $result = $this->testDb->generateAssociationQuery($this->Model, $params['linkModel'], $params['type'], $params['assoc'], $params['assocData'], $queryData, $params['external'], $resultSet);
+
+ $this->assertPattern('/^SELECT\s+`TestModel6`\.`id`, `TestModel6`\.`test_model5_id`, `TestModel6`\.`name`, `TestModel6`\.`created`, `TestModel6`\.`updated`\s+/', $result);
+ $this->assertPattern('/\s+FROM\s+`test_model6` AS `TestModel6`\s+WHERE\s+/', $result);
+ $this->assertPattern('/WHERE\s+(?:\()?`TestModel6`\.`test_model5_id`\s+=\s+\({\$__cakeID__\$}\)(?:\))?/', $result);
+ $this->assertPattern('/\s+LIMIT 2,\s*5\s*$/', $result);
+
+ $result = $this->testDb->generateAssociationQuery($this->Model, $null, null, null, null, $queryData, false, $null);
+ $this->assertPattern('/^SELECT\s+`TestModel5`\.`id`, `TestModel5`\.`test_model4_id`, `TestModel5`\.`name`, `TestModel5`\.`created`, `TestModel5`\.`updated`\s+/', $result);
+ $this->assertPattern('/\s+FROM\s+`test_model5` AS `TestModel5`\s+WHERE\s+/', $result);
+ $this->assertPattern('/\s+WHERE\s+(?:\()?1\s+=\s+1(?:\))?\s*$/', $result);
+
+ $this->Model->hasMany['TestModel6'] = $__backup;
+ }
+
+/**
+ * testGenerateAssociationQueryHasManyWithPageAndLimit method
+ *
+ * @access public
+ * @return void
+ */
+ function testGenerateAssociationQueryHasManyWithPageAndLimit() {
+ $this->Model =& new TestModel5();
+ $this->Model->schema();
+ $this->_buildRelatedModels($this->Model);
+
+ $__backup = $this->Model->hasMany['TestModel6'];
+
+ $this->Model->hasMany['TestModel6']['page'] = 2;
+ $this->Model->hasMany['TestModel6']['limit'] = 5;
+
+ $binding = array('type' => 'hasMany', 'model' => 'TestModel6');
+ $queryData = array();
+ $resultSet = null;
+ $null = null;
+
+ $params = &$this->_prepareAssociationQuery($this->Model, $queryData, $binding);
+
+ $result = $this->testDb->generateAssociationQuery($this->Model, $params['linkModel'], $params['type'], $params['assoc'], $params['assocData'], $queryData, $params['external'], $resultSet);
+ $this->assertPattern('/^SELECT\s+`TestModel6`\.`id`, `TestModel6`\.`test_model5_id`, `TestModel6`\.`name`, `TestModel6`\.`created`, `TestModel6`\.`updated`\s+/', $result);
+ $this->assertPattern('/\s+FROM\s+`test_model6` AS `TestModel6`\s+WHERE\s+/', $result);
+ $this->assertPattern('/WHERE\s+(?:\()?`TestModel6`\.`test_model5_id`\s+=\s+\({\$__cakeID__\$}\)(?:\))?/', $result);
+ $this->assertPattern('/\s+LIMIT 5,\s*5\s*$/', $result);
+
+ $result = $this->testDb->generateAssociationQuery($this->Model, $null, null, null, null, $queryData, false, $null);
+ $this->assertPattern('/^SELECT\s+`TestModel5`\.`id`, `TestModel5`\.`test_model4_id`, `TestModel5`\.`name`, `TestModel5`\.`created`, `TestModel5`\.`updated`\s+/', $result);
+ $this->assertPattern('/\s+FROM\s+`test_model5` AS `TestModel5`\s+WHERE\s+/', $result);
+ $this->assertPattern('/\s+WHERE\s+(?:\()?1\s+=\s+1(?:\))?\s*$/', $result);
+
+ $this->Model->hasMany['TestModel6'] = $__backup;
+ }
+
+/**
+ * testGenerateAssociationQueryHasManyWithFields method
+ *
+ * @access public
+ * @return void
+ */
+ function testGenerateAssociationQueryHasManyWithFields() {
+ $this->Model =& new TestModel5();
+ $this->Model->schema();
+ $this->_buildRelatedModels($this->Model);
+
+ $binding = array('type' => 'hasMany', 'model' => 'TestModel6');
+ $queryData = array('fields' => array('`TestModel5`.`name`'));
+ $resultSet = null;
+ $null = null;
+
+ $params = &$this->_prepareAssociationQuery($this->Model, $queryData, $binding);
+
+ $result = $this->testDb->generateAssociationQuery($this->Model, $params['linkModel'], $params['type'], $params['assoc'], $params['assocData'], $queryData, $params['external'], $resultSet);
+ $this->assertPattern('/^SELECT\s+`TestModel6`\.`id`, `TestModel6`\.`test_model5_id`, `TestModel6`\.`name`, `TestModel6`\.`created`, `TestModel6`\.`updated`\s+/', $result);
+ $this->assertPattern('/\s+FROM\s+`test_model6` AS `TestModel6`\s+WHERE\s+/', $result);
+ $this->assertPattern('/WHERE\s+(?:\()?`TestModel6`\.`test_model5_id`\s+=\s+\({\$__cakeID__\$}\)(?:\))?/', $result);
+
+ $result = $this->testDb->generateAssociationQuery($this->Model, $null, null, null, null, $queryData, false, $null);
+ $this->assertPattern('/^SELECT\s+`TestModel5`\.`name`, `TestModel5`\.`id`\s+/', $result);
+ $this->assertPattern('/\s+FROM\s+`test_model5` AS `TestModel5`\s+WHERE\s+/', $result);
+ $this->assertPattern('/\s+WHERE\s+(?:\()?1\s+=\s+1(?:\))?\s*$/', $result);
+
+ $binding = array('type' => 'hasMany', 'model' => 'TestModel6');
+ $queryData = array('fields' => array('`TestModel5`.`id`, `TestModel5`.`name`'));
+ $resultSet = null;
+ $null = null;
+
+ $params = &$this->_prepareAssociationQuery($this->Model, $queryData, $binding);
+
+ $result = $this->testDb->generateAssociationQuery($this->Model, $params['linkModel'], $params['type'], $params['assoc'], $params['assocData'], $queryData, $params['external'], $resultSet);
+ $this->assertPattern('/^SELECT\s+`TestModel6`\.`id`, `TestModel6`\.`test_model5_id`, `TestModel6`\.`name`, `TestModel6`\.`created`, `TestModel6`\.`updated`\s+/', $result);
+ $this->assertPattern('/\s+FROM\s+`test_model6` AS `TestModel6`\s+WHERE\s+/', $result);
+ $this->assertPattern('/WHERE\s+(?:\()?`TestModel6`\.`test_model5_id`\s+=\s+\({\$__cakeID__\$}\)(?:\))?/', $result);
+
+ $result = $this->testDb->generateAssociationQuery($this->Model, $null, null, null, null, $queryData, false, $null);
+ $this->assertPattern('/^SELECT\s+`TestModel5`\.`id`, `TestModel5`\.`name`\s+/', $result);
+ $this->assertPattern('/\s+FROM\s+`test_model5` AS `TestModel5`\s+WHERE\s+/', $result);
+ $this->assertPattern('/\s+WHERE\s+(?:\()?1\s+=\s+1(?:\))?\s*$/', $result);
+
+ $binding = array('type' => 'hasMany', 'model' => 'TestModel6');
+ $queryData = array('fields' => array('`TestModel5`.`name`', '`TestModel5`.`created`'));
+ $resultSet = null;
+ $null = null;
+
+ $params = &$this->_prepareAssociationQuery($this->Model, $queryData, $binding);
+
+ $result = $this->testDb->generateAssociationQuery($this->Model, $params['linkModel'], $params['type'], $params['assoc'], $params['assocData'], $queryData, $params['external'], $resultSet);
+ $this->assertPattern('/^SELECT\s+`TestModel6`\.`id`, `TestModel6`\.`test_model5_id`, `TestModel6`\.`name`, `TestModel6`\.`created`, `TestModel6`\.`updated`\s+/', $result);
+ $this->assertPattern('/\s+FROM\s+`test_model6` AS `TestModel6`\s+WHERE\s+/', $result);
+ $this->assertPattern('/WHERE\s+(?:\()?`TestModel6`\.`test_model5_id`\s+=\s+\({\$__cakeID__\$}\)(?:\))?/', $result);
+
+ $result = $this->testDb->generateAssociationQuery($this->Model, $null, null, null, null, $queryData, false, $null);
+ $this->assertPattern('/^SELECT\s+`TestModel5`\.`name`, `TestModel5`\.`created`, `TestModel5`\.`id`\s+/', $result);
+ $this->assertPattern('/\s+FROM\s+`test_model5` AS `TestModel5`\s+WHERE\s+/', $result);
+ $this->assertPattern('/\s+WHERE\s+(?:\()?1\s+=\s+1(?:\))?\s*$/', $result);
+
+ $this->Model->hasMany['TestModel6']['fields'] = array('name');
+
+ $binding = array('type' => 'hasMany', 'model' => 'TestModel6');
+ $queryData = array('fields' => array('`TestModel5`.`id`', '`TestModel5`.`name`'));
+ $resultSet = null;
+ $null = null;
+
+ $params = &$this->_prepareAssociationQuery($this->Model, $queryData, $binding);
+
+ $result = $this->testDb->generateAssociationQuery($this->Model, $params['linkModel'], $params['type'], $params['assoc'], $params['assocData'], $queryData, $params['external'], $resultSet);
+ $this->assertPattern('/^SELECT\s+`TestModel6`\.`name`, `TestModel6`\.`test_model5_id`\s+/', $result);
+ $this->assertPattern('/\s+FROM\s+`test_model6` AS `TestModel6`\s+WHERE\s+/', $result);
+ $this->assertPattern('/WHERE\s+(?:\()?`TestModel6`\.`test_model5_id`\s+=\s+\({\$__cakeID__\$}\)(?:\))?/', $result);
+
+ $result = $this->testDb->generateAssociationQuery($this->Model, $null, null, null, null, $queryData, false, $null);
+ $this->assertPattern('/^SELECT\s+`TestModel5`\.`id`, `TestModel5`\.`name`\s+/', $result);
+ $this->assertPattern('/\s+FROM\s+`test_model5` AS `TestModel5`\s+WHERE\s+/', $result);
+ $this->assertPattern('/\s+WHERE\s+(?:\()?1\s+=\s+1(?:\))?\s*$/', $result);
+
+ unset($this->Model->hasMany['TestModel6']['fields']);
+
+ $this->Model->hasMany['TestModel6']['fields'] = array('id', 'name');
+
+ $binding = array('type' => 'hasMany', 'model' => 'TestModel6');
+ $queryData = array('fields' => array('`TestModel5`.`id`', '`TestModel5`.`name`'));
+ $resultSet = null;
+ $null = null;
+
+ $params = &$this->_prepareAssociationQuery($this->Model, $queryData, $binding);
+
+ $result = $this->testDb->generateAssociationQuery($this->Model, $params['linkModel'], $params['type'], $params['assoc'], $params['assocData'], $queryData, $params['external'], $resultSet);
+ $this->assertPattern('/^SELECT\s+`TestModel6`\.`id`, `TestModel6`\.`name`, `TestModel6`\.`test_model5_id`\s+/', $result);
+ $this->assertPattern('/\s+FROM\s+`test_model6` AS `TestModel6`\s+WHERE\s+/', $result);
+ $this->assertPattern('/WHERE\s+(?:\()?`TestModel6`\.`test_model5_id`\s+=\s+\({\$__cakeID__\$}\)(?:\))?/', $result);
+
+ $result = $this->testDb->generateAssociationQuery($this->Model, $null, null, null, null, $queryData, false, $null);
+ $this->assertPattern('/^SELECT\s+`TestModel5`\.`id`, `TestModel5`\.`name`\s+/', $result);
+ $this->assertPattern('/\s+FROM\s+`test_model5` AS `TestModel5`\s+WHERE\s+/', $result);
+ $this->assertPattern('/\s+WHERE\s+(?:\()?1\s+=\s+1(?:\))?\s*$/', $result);
+
+ unset($this->Model->hasMany['TestModel6']['fields']);
+
+ $this->Model->hasMany['TestModel6']['fields'] = array('test_model5_id', 'name');
+
+ $binding = array('type' => 'hasMany', 'model' => 'TestModel6');
+ $queryData = array('fields' => array('`TestModel5`.`id`', '`TestModel5`.`name`'));
+ $resultSet = null;
+ $null = null;
+
+ $params = &$this->_prepareAssociationQuery($this->Model, $queryData, $binding);
+
+ $result = $this->testDb->generateAssociationQuery($this->Model, $params['linkModel'], $params['type'], $params['assoc'], $params['assocData'], $queryData, $params['external'], $resultSet);
+ $this->assertPattern('/^SELECT\s+`TestModel6`\.`test_model5_id`, `TestModel6`\.`name`\s+/', $result);
+ $this->assertPattern('/\s+FROM\s+`test_model6` AS `TestModel6`\s+WHERE\s+/', $result);
+ $this->assertPattern('/WHERE\s+(?:\()?`TestModel6`\.`test_model5_id`\s+=\s+\({\$__cakeID__\$}\)(?:\))?/', $result);
+
+ $result = $this->testDb->generateAssociationQuery($this->Model, $null, null, null, null, $queryData, false, $null);
+ $this->assertPattern('/^SELECT\s+`TestModel5`\.`id`, `TestModel5`\.`name`\s+/', $result);
+ $this->assertPattern('/\s+FROM\s+`test_model5` AS `TestModel5`\s+WHERE\s+/', $result);
+ $this->assertPattern('/\s+WHERE\s+(?:\()?1\s+=\s+1(?:\))?\s*$/', $result);
+
+ unset($this->Model->hasMany['TestModel6']['fields']);
+ }
+
+/**
+ * test generateAssociationQuery with a hasMany and an aggregate function.
+ *
+ * @return void
+ */
+ function testGenerateAssociationQueryHasManyAndAggregateFunction() {
+ $this->Model =& new TestModel5();
+ $this->Model->schema();
+ $this->_buildRelatedModels($this->Model);
+
+ $binding = array('type' => 'hasMany', 'model' => 'TestModel6');
+ $queryData = array('fields' => array('MIN(TestModel5.test_model4_id)'));
+ $resultSet = null;
+ $null = null;
+
+ $params = &$this->_prepareAssociationQuery($this->Model, $queryData, $binding);
+ $this->Model->recursive = 0;
+
+ $result = $this->testDb->generateAssociationQuery($this->Model, $null, $params['type'], $params['assoc'], $params['assocData'], $queryData, false, $resultSet);
+ $this->assertPattern('/^SELECT\s+MIN\(`TestModel5`\.`test_model4_id`\)\s+FROM/', $result);
+ }
+
+/**
+ * testGenerateAssociationQueryHasAndBelongsToMany method
+ *
+ * @access public
+ * @return void
+ */
+ function testGenerateAssociationQueryHasAndBelongsToMany() {
+ $this->Model =& new TestModel4();
+ $this->Model->schema();
+ $this->_buildRelatedModels($this->Model);
+
+ $binding = array('type' => 'hasAndBelongsToMany', 'model' => 'TestModel7');
+ $queryData = array();
+ $resultSet = null;
+ $null = null;
+
+ $params =& $this->_prepareAssociationQuery($this->Model, $queryData, $binding);
+
+ $result = $this->testDb->generateAssociationQuery($this->Model, $params['linkModel'], $params['type'], $params['assoc'], $params['assocData'], $queryData, $params['external'], $resultSet);
+ $this->assertPattern('/^SELECT\s+`TestModel7`\.`id`, `TestModel7`\.`name`, `TestModel7`\.`created`, `TestModel7`\.`updated`, `TestModel4TestModel7`\.`test_model4_id`, `TestModel4TestModel7`\.`test_model7_id`\s+/', $result);
+ $this->assertPattern('/\s+FROM\s+`test_model7` AS `TestModel7`\s+JOIN\s+`' . $this->testDb->fullTableName('test_model4_test_model7', false) . '`/', $result);
+ $this->assertPattern('/\s+ON\s+\(`TestModel4TestModel7`\.`test_model4_id`\s+=\s+{\$__cakeID__\$}\s+AND/', $result);
+ $this->assertPattern('/\s+AND\s+`TestModel4TestModel7`\.`test_model7_id`\s+=\s+`TestModel7`\.`id`\)/', $result);
+ $this->assertPattern('/WHERE\s+(?:\()?1 = 1(?:\))?\s*$/', $result);
+
+ $result = $this->testDb->generateAssociationQuery($this->Model, $null, null, null, null, $queryData, false, $null);
+ $this->assertPattern('/^SELECT\s+`TestModel4`\.`id`, `TestModel4`\.`name`, `TestModel4`\.`created`, `TestModel4`\.`updated`\s+/', $result);
+ $this->assertPattern('/\s+FROM\s+`test_model4` AS `TestModel4`\s+WHERE/', $result);
+ $this->assertPattern('/\s+WHERE\s+(?:\()?1 = 1(?:\))?\s*$/', $result);
+ }
+
+/**
+ * testGenerateAssociationQueryHasAndBelongsToManyWithConditions method
+ *
+ * @access public
+ * @return void
+ */
+ function testGenerateAssociationQueryHasAndBelongsToManyWithConditions() {
+ $this->Model =& new TestModel4();
+ $this->Model->schema();
+ $this->_buildRelatedModels($this->Model);
+
+ $binding = array('type'=>'hasAndBelongsToMany', 'model'=>'TestModel7');
+ $queryData = array('conditions' => array('TestModel4.name !=' => 'mariano'));
+ $resultSet = null;
+ $null = null;
+
+ $params =& $this->_prepareAssociationQuery($this->Model, $queryData, $binding);
+
+ $result = $this->testDb->generateAssociationQuery($this->Model, $params['linkModel'], $params['type'], $params['assoc'], $params['assocData'], $queryData, $params['external'], $resultSet);
+ $this->assertPattern('/^SELECT\s+`TestModel7`\.`id`, `TestModel7`\.`name`, `TestModel7`\.`created`, `TestModel7`\.`updated`, `TestModel4TestModel7`\.`test_model4_id`, `TestModel4TestModel7`\.`test_model7_id`\s+/', $result);
+ $this->assertPattern('/\s+FROM\s+`test_model7`\s+AS\s+`TestModel7`\s+JOIN\s+`test_model4_test_model7`\s+AS\s+`TestModel4TestModel7`/', $result);
+ $this->assertPattern('/\s+ON\s+\(`TestModel4TestModel7`\.`test_model4_id`\s+=\s+{\$__cakeID__\$}/', $result);
+ $this->assertPattern('/\s+AND\s+`TestModel4TestModel7`\.`test_model7_id`\s+=\s+`TestModel7`\.`id`\)\s+WHERE\s+/', $result);
+
+ $result = $this->testDb->generateAssociationQuery($this->Model, $null, null, null, null, $queryData, false, $null);
+ $this->assertPattern('/^SELECT\s+`TestModel4`\.`id`, `TestModel4`\.`name`, `TestModel4`\.`created`, `TestModel4`\.`updated`\s+/', $result);
+ $this->assertPattern('/\s+FROM\s+`test_model4` AS `TestModel4`\s+WHERE\s+(?:\()?`TestModel4`.`name`\s+!=\s+\'mariano\'(?:\))?\s*$/', $result);
+ }
+
+/**
+ * testGenerateAssociationQueryHasAndBelongsToManyWithOffsetAndLimit method
+ *
+ * @access public
+ * @return void
+ */
+ function testGenerateAssociationQueryHasAndBelongsToManyWithOffsetAndLimit() {
+ $this->Model =& new TestModel4();
+ $this->Model->schema();
+ $this->_buildRelatedModels($this->Model);
+
+ $__backup = $this->Model->hasAndBelongsToMany['TestModel7'];
+
+ $this->Model->hasAndBelongsToMany['TestModel7']['offset'] = 2;
+ $this->Model->hasAndBelongsToMany['TestModel7']['limit'] = 5;
+
+ $binding = array('type'=>'hasAndBelongsToMany', 'model'=>'TestModel7');
+ $queryData = array();
+ $resultSet = null;
+ $null = null;
+
+ $params = &$this->_prepareAssociationQuery($this->Model, $queryData, $binding);
+
+ $result = $this->testDb->generateAssociationQuery($this->Model, $params['linkModel'], $params['type'], $params['assoc'], $params['assocData'], $queryData, $params['external'], $resultSet);
+ $this->assertPattern('/^SELECT\s+`TestModel7`\.`id`, `TestModel7`\.`name`, `TestModel7`\.`created`, `TestModel7`\.`updated`, `TestModel4TestModel7`\.`test_model4_id`, `TestModel4TestModel7`\.`test_model7_id`\s+/', $result);
+ $this->assertPattern('/\s+FROM\s+`test_model7`\s+AS\s+`TestModel7`\s+JOIN\s+`test_model4_test_model7`\s+AS\s+`TestModel4TestModel7`/', $result);
+ $this->assertPattern('/\s+ON\s+\(`TestModel4TestModel7`\.`test_model4_id`\s+=\s+{\$__cakeID__\$}\s+/', $result);
+ $this->assertPattern('/\s+AND\s+`TestModel4TestModel7`\.`test_model7_id`\s+=\s+`TestModel7`\.`id`\)\s+WHERE\s+/', $result);
+ $this->assertPattern('/\s+(?:\()?1\s+=\s+1(?:\))?\s*\s+LIMIT 2,\s*5\s*$/', $result);
+
+ $result = $this->testDb->generateAssociationQuery($this->Model, $null, null, null, null, $queryData, false, $null);
+ $this->assertPattern('/^SELECT\s+`TestModel4`\.`id`, `TestModel4`\.`name`, `TestModel4`\.`created`, `TestModel4`\.`updated`\s+/', $result);
+ $this->assertPattern('/\s+FROM\s+`test_model4` AS `TestModel4`\s+WHERE\s+(?:\()?1\s+=\s+1(?:\))?\s*$/', $result);
+
+ $this->Model->hasAndBelongsToMany['TestModel7'] = $__backup;
+ }
+
+/**
+ * testGenerateAssociationQueryHasAndBelongsToManyWithPageAndLimit method
+ *
+ * @access public
+ * @return void
+ */
+ function testGenerateAssociationQueryHasAndBelongsToManyWithPageAndLimit() {
+ $this->Model =& new TestModel4();
+ $this->Model->schema();
+ $this->_buildRelatedModels($this->Model);
+
+ $__backup = $this->Model->hasAndBelongsToMany['TestModel7'];
+
+ $this->Model->hasAndBelongsToMany['TestModel7']['page'] = 2;
+ $this->Model->hasAndBelongsToMany['TestModel7']['limit'] = 5;
+
+ $binding = array('type'=>'hasAndBelongsToMany', 'model'=>'TestModel7');
+ $queryData = array();
+ $resultSet = null;
+ $null = null;
+
+ $params = &$this->_prepareAssociationQuery($this->Model, $queryData, $binding);
+
+ $result = $this->testDb->generateAssociationQuery($this->Model, $params['linkModel'], $params['type'], $params['assoc'], $params['assocData'], $queryData, $params['external'], $resultSet);
+ $this->assertPattern('/^SELECT\s+`TestModel7`\.`id`, `TestModel7`\.`name`, `TestModel7`\.`created`, `TestModel7`\.`updated`, `TestModel4TestModel7`\.`test_model4_id`, `TestModel4TestModel7`\.`test_model7_id`\s+/', $result);
+ $this->assertPattern('/\s+FROM\s+`test_model7`\s+AS\s+`TestModel7`\s+JOIN\s+`test_model4_test_model7`\s+AS\s+`TestModel4TestModel7`/', $result);
+ $this->assertPattern('/\s+ON\s+\(`TestModel4TestModel7`\.`test_model4_id`\s+=\s+{\$__cakeID__\$}/', $result);
+ $this->assertPattern('/\s+AND\s+`TestModel4TestModel7`\.`test_model7_id`\s+=\s+`TestModel7`\.`id`\)\s+WHERE\s+/', $result);
+ $this->assertPattern('/\s+(?:\()?1\s+=\s+1(?:\))?\s*\s+LIMIT 5,\s*5\s*$/', $result);
+
+ $result = $this->testDb->generateAssociationQuery($this->Model, $null, null, null, null, $queryData, false, $null);
+ $this->assertPattern('/^SELECT\s+`TestModel4`\.`id`, `TestModel4`\.`name`, `TestModel4`\.`created`, `TestModel4`\.`updated`\s+/', $result);
+ $this->assertPattern('/\s+FROM\s+`test_model4` AS `TestModel4`\s+WHERE\s+(?:\()?1\s+=\s+1(?:\))?\s*$/', $result);
+
+ $this->Model->hasAndBelongsToMany['TestModel7'] = $__backup;
+ }
+
+/**
+ * buildRelatedModels method
+ *
+ * @param mixed $model
+ * @access protected
+ * @return void
+ */
+ function _buildRelatedModels(&$model) {
+ foreach ($model->__associations as $type) {
+ foreach ($model->{$type} as $assoc => $assocData) {
+ if (is_string($assocData)) {
+ $className = $assocData;
+ } elseif (isset($assocData['className'])) {
+ $className = $assocData['className'];
+ }
+ $model->$className =& new $className();
+ $model->$className->schema();
+ }
+ }
+ }
+
+/**
+ * &_prepareAssociationQuery method
+ *
+ * @param mixed $model
+ * @param mixed $queryData
+ * @param mixed $binding
+ * @access public
+ * @return void
+ */
+ function &_prepareAssociationQuery(&$model, &$queryData, $binding) {
+ $type = $binding['type'];
+ $assoc = $binding['model'];
+ $assocData = $model->{$type}[$assoc];
+ $className = $assocData['className'];
+
+ $linkModel =& $model->{$className};
+ $external = isset($assocData['external']);
+ $queryData = $this->testDb->__scrubQueryData($queryData);
+
+ $result = array_merge(array('linkModel' => &$linkModel), compact('type', 'assoc', 'assocData', 'external'));
+ return $result;
+ }
+
+/**
+ * testSelectDistict method
+ *
+ * @access public
+ * @return void
+ */
+ function testSelectDistict() {
+ $result = $this->testDb->fields($this->Model, 'Vendor', "DISTINCT Vendor.id, Vendor.name");
+ $expected = array('DISTINCT `Vendor`.`id`', '`Vendor`.`name`');
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * test that booleans and null make logical condition strings.
+ *
+ * @return void
+ */
+ function testBooleanNullConditionsParsing() {
+ $result = $this->testDb->conditions(true);
+ $this->assertEqual($result, ' WHERE 1 = 1', 'true conditions failed %s');
+
+ $result = $this->testDb->conditions(false);
+ $this->assertEqual($result, ' WHERE 0 = 1', 'false conditions failed %s');
+
+ $result = $this->testDb->conditions(null);
+ $this->assertEqual($result, ' WHERE 1 = 1', 'null conditions failed %s');
+
+ $result = $this->testDb->conditions(array());
+ $this->assertEqual($result, ' WHERE 1 = 1', 'array() conditions failed %s');
+
+ $result = $this->testDb->conditions('');
+ $this->assertEqual($result, ' WHERE 1 = 1', '"" conditions failed %s');
+
+ $result = $this->testDb->conditions(' ', '" " conditions failed %s');
+ $this->assertEqual($result, ' WHERE 1 = 1');
+ }
+/**
+ * testStringConditionsParsing method
+ *
+ * @access public
+ * @return void
+ */
+ function testStringConditionsParsing() {
+ $result = $this->testDb->conditions("ProjectBid.project_id = Project.id");
+ $expected = " WHERE `ProjectBid`.`project_id` = `Project`.`id`";
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->conditions("Candy.name LIKE 'a' AND HardCandy.name LIKE 'c'");
+ $expected = " WHERE `Candy`.`name` LIKE 'a' AND `HardCandy`.`name` LIKE 'c'";
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->conditions("HardCandy.name LIKE 'a' AND Candy.name LIKE 'c'");
+ $expected = " WHERE `HardCandy`.`name` LIKE 'a' AND `Candy`.`name` LIKE 'c'";
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->conditions("Post.title = '1.1'");
+ $expected = " WHERE `Post`.`title` = '1.1'";
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->conditions("User.id != 0 AND User.user LIKE '%arr%'");
+ $expected = " WHERE `User`.`id` != 0 AND `User`.`user` LIKE '%arr%'";
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->conditions("SUM(Post.comments_count) > 500");
+ $expected = " WHERE SUM(`Post`.`comments_count`) > 500";
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->conditions("(Post.created < '" . date('Y-m-d H:i:s') . "') GROUP BY YEAR(Post.created), MONTH(Post.created)");
+ $expected = " WHERE (`Post`.`created` < '" . date('Y-m-d H:i:s') . "') GROUP BY YEAR(`Post`.`created`), MONTH(`Post`.`created`)";
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->conditions("score BETWEEN 90.1 AND 95.7");
+ $expected = " WHERE score BETWEEN 90.1 AND 95.7";
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->conditions(array('score' => array(2=>1, 2, 10)));
+ $expected = " WHERE score IN (1, 2, 10)";
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->conditions("Aro.rght = Aro.lft + 1.1");
+ $expected = " WHERE `Aro`.`rght` = `Aro`.`lft` + 1.1";
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->conditions("(Post.created < '" . date('Y-m-d H:i:s') . "') GROUP BY YEAR(Post.created), MONTH(Post.created)");
+ $expected = " WHERE (`Post`.`created` < '" . date('Y-m-d H:i:s') . "') GROUP BY YEAR(`Post`.`created`), MONTH(`Post`.`created`)";
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->conditions('Sportstaette.sportstaette LIKE "%ru%" AND Sportstaette.sportstaettenart_id = 2');
+ $expected = ' WHERE `Sportstaette`.`sportstaette` LIKE "%ru%" AND `Sportstaette`.`sportstaettenart_id` = 2';
+ $this->assertPattern('/\s*WHERE\s+`Sportstaette`\.`sportstaette`\s+LIKE\s+"%ru%"\s+AND\s+`Sports/', $result);
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->conditions('Sportstaette.sportstaettenart_id = 2 AND Sportstaette.sportstaette LIKE "%ru%"');
+ $expected = ' WHERE `Sportstaette`.`sportstaettenart_id` = 2 AND `Sportstaette`.`sportstaette` LIKE "%ru%"';
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->conditions('SUM(Post.comments_count) > 500 AND NOT Post.title IS NULL AND NOT Post.extended_title IS NULL');
+ $expected = ' WHERE SUM(`Post`.`comments_count`) > 500 AND NOT `Post`.`title` IS NULL AND NOT `Post`.`extended_title` IS NULL';
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->conditions('NOT Post.title IS NULL AND NOT Post.extended_title IS NULL AND SUM(Post.comments_count) > 500');
+ $expected = ' WHERE NOT `Post`.`title` IS NULL AND NOT `Post`.`extended_title` IS NULL AND SUM(`Post`.`comments_count`) > 500';
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->conditions('NOT Post.extended_title IS NULL AND NOT Post.title IS NULL AND Post.title != "" AND SPOON(SUM(Post.comments_count) + 1.1) > 500');
+ $expected = ' WHERE NOT `Post`.`extended_title` IS NULL AND NOT `Post`.`title` IS NULL AND `Post`.`title` != "" AND SPOON(SUM(`Post`.`comments_count`) + 1.1) > 500';
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->conditions('NOT Post.title_extended IS NULL AND NOT Post.title IS NULL AND Post.title_extended != Post.title');
+ $expected = ' WHERE NOT `Post`.`title_extended` IS NULL AND NOT `Post`.`title` IS NULL AND `Post`.`title_extended` != `Post`.`title`';
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->conditions("Comment.id = 'a'");
+ $expected = " WHERE `Comment`.`id` = 'a'";
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->conditions("lower(Article.title) LIKE 'a%'");
+ $expected = " WHERE lower(`Article`.`title`) LIKE 'a%'";
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->conditions('((MATCH(Video.title) AGAINST(\'My Search*\' IN BOOLEAN MODE) * 2) + (MATCH(Video.description) AGAINST(\'My Search*\' IN BOOLEAN MODE) * 0.4) + (MATCH(Video.tags) AGAINST(\'My Search*\' IN BOOLEAN MODE) * 1.5))');
+ $expected = ' WHERE ((MATCH(`Video`.`title`) AGAINST(\'My Search*\' IN BOOLEAN MODE) * 2) + (MATCH(`Video`.`description`) AGAINST(\'My Search*\' IN BOOLEAN MODE) * 0.4) + (MATCH(`Video`.`tags`) AGAINST(\'My Search*\' IN BOOLEAN MODE) * 1.5))';
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->conditions('DATEDIFF(NOW(),Article.published) < 1 && Article.live=1');
+ $expected = " WHERE DATEDIFF(NOW(),`Article`.`published`) < 1 && `Article`.`live`=1";
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->conditions('file = "index.html"');
+ $expected = ' WHERE file = "index.html"';
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->conditions("file = 'index.html'");
+ $expected = " WHERE file = 'index.html'";
+ $this->assertEqual($result, $expected);
+
+ $letter = $letter = 'd.a';
+ $conditions = array('Company.name like ' => $letter . '%');
+ $result = $this->testDb->conditions($conditions);
+ $expected = " WHERE `Company`.`name` like 'd.a%'";
+ $this->assertEqual($result, $expected);
+
+ $conditions = array('Artist.name' => 'JUDY and MARY');
+ $result = $this->testDb->conditions($conditions);
+ $expected = " WHERE `Artist`.`name` = 'JUDY and MARY'";
+ $this->assertEqual($result, $expected);
+
+ $conditions = array('Artist.name' => 'JUDY AND MARY');
+ $result = $this->testDb->conditions($conditions);
+ $expected = " WHERE `Artist`.`name` = 'JUDY AND MARY'";
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testQuotesInStringConditions method
+ *
+ * @access public
+ * @return void
+ */
+ function testQuotesInStringConditions() {
+ $result = $this->testDb->conditions('Member.email = \'mariano@cricava.com\'');
+ $expected = ' WHERE `Member`.`email` = \'mariano@cricava.com\'';
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->conditions('Member.email = "mariano@cricava.com"');
+ $expected = ' WHERE `Member`.`email` = "mariano@cricava.com"';
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->conditions('Member.email = \'mariano@cricava.com\' AND Member.user LIKE \'mariano.iglesias%\'');
+ $expected = ' WHERE `Member`.`email` = \'mariano@cricava.com\' AND `Member`.`user` LIKE \'mariano.iglesias%\'';
+ $this->assertEqual($result, $expected);
+
+
+ $result = $this->testDb->conditions('Member.email = "mariano@cricava.com" AND Member.user LIKE "mariano.iglesias%"');
+ $expected = ' WHERE `Member`.`email` = "mariano@cricava.com" AND `Member`.`user` LIKE "mariano.iglesias%"';
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testParenthesisInStringConditions method
+ *
+ * @access public
+ * @return void
+ */
+ function testParenthesisInStringConditions() {
+ $result = $this->testDb->conditions('Member.name = \'(lu\'');
+ $this->assertPattern('/^\s+WHERE\s+`Member`.`name`\s+=\s+\'\(lu\'$/', $result);
+
+ $result = $this->testDb->conditions('Member.name = \')lu\'');
+ $this->assertPattern('/^\s+WHERE\s+`Member`.`name`\s+=\s+\'\)lu\'$/', $result);
+
+ $result = $this->testDb->conditions('Member.name = \'va(lu\'');
+ $this->assertPattern('/^\s+WHERE\s+`Member`.`name`\s+=\s+\'va\(lu\'$/', $result);
+
+ $result = $this->testDb->conditions('Member.name = \'va)lu\'');
+ $this->assertPattern('/^\s+WHERE\s+`Member`.`name`\s+=\s+\'va\)lu\'$/', $result);
+
+ $result = $this->testDb->conditions('Member.name = \'va(lu)\'');
+ $this->assertPattern('/^\s+WHERE\s+`Member`.`name`\s+=\s+\'va\(lu\)\'$/', $result);
+
+ $result = $this->testDb->conditions('Member.name = \'va(lu)e\'');
+ $this->assertPattern('/^\s+WHERE\s+`Member`.`name`\s+=\s+\'va\(lu\)e\'$/', $result);
+
+ $result = $this->testDb->conditions('Member.name = \'(mariano)\'');
+ $this->assertPattern('/^\s+WHERE\s+`Member`.`name`\s+=\s+\'\(mariano\)\'$/', $result);
+
+ $result = $this->testDb->conditions('Member.name = \'(mariano)iglesias\'');
+ $this->assertPattern('/^\s+WHERE\s+`Member`.`name`\s+=\s+\'\(mariano\)iglesias\'$/', $result);
+
+ $result = $this->testDb->conditions('Member.name = \'(mariano) iglesias\'');
+ $this->assertPattern('/^\s+WHERE\s+`Member`.`name`\s+=\s+\'\(mariano\) iglesias\'$/', $result);
+
+ $result = $this->testDb->conditions('Member.name = \'(mariano word) iglesias\'');
+ $this->assertPattern('/^\s+WHERE\s+`Member`.`name`\s+=\s+\'\(mariano word\) iglesias\'$/', $result);
+
+ $result = $this->testDb->conditions('Member.name = \'(mariano.iglesias)\'');
+ $this->assertPattern('/^\s+WHERE\s+`Member`.`name`\s+=\s+\'\(mariano.iglesias\)\'$/', $result);
+
+ $result = $this->testDb->conditions('Member.name = \'Mariano Iglesias (mariano.iglesias)\'');
+ $this->assertPattern('/^\s+WHERE\s+`Member`.`name`\s+=\s+\'Mariano Iglesias \(mariano.iglesias\)\'$/', $result);
+
+ $result = $this->testDb->conditions('Member.name = \'Mariano Iglesias (mariano.iglesias) CakePHP\'');
+ $this->assertPattern('/^\s+WHERE\s+`Member`.`name`\s+=\s+\'Mariano Iglesias \(mariano.iglesias\) CakePHP\'$/', $result);
+
+ $result = $this->testDb->conditions('Member.name = \'(mariano.iglesias) CakePHP\'');
+ $this->assertPattern('/^\s+WHERE\s+`Member`.`name`\s+=\s+\'\(mariano.iglesias\) CakePHP\'$/', $result);
+ }
+
+/**
+ * testParenthesisInArrayConditions method
+ *
+ * @access public
+ * @return void
+ */
+ function testParenthesisInArrayConditions() {
+ $result = $this->testDb->conditions(array('Member.name' => '(lu'));
+ $this->assertPattern('/^\s+WHERE\s+`Member`.`name`\s+=\s+\'\(lu\'$/', $result);
+
+ $result = $this->testDb->conditions(array('Member.name' => ')lu'));
+ $this->assertPattern('/^\s+WHERE\s+`Member`.`name`\s+=\s+\'\)lu\'$/', $result);
+
+ $result = $this->testDb->conditions(array('Member.name' => 'va(lu'));
+ $this->assertPattern('/^\s+WHERE\s+`Member`.`name`\s+=\s+\'va\(lu\'$/', $result);
+
+ $result = $this->testDb->conditions(array('Member.name' => 'va)lu'));
+ $this->assertPattern('/^\s+WHERE\s+`Member`.`name`\s+=\s+\'va\)lu\'$/', $result);
+
+ $result = $this->testDb->conditions(array('Member.name' => 'va(lu)'));
+ $this->assertPattern('/^\s+WHERE\s+`Member`.`name`\s+=\s+\'va\(lu\)\'$/', $result);
+
+ $result = $this->testDb->conditions(array('Member.name' => 'va(lu)e'));
+ $this->assertPattern('/^\s+WHERE\s+`Member`.`name`\s+=\s+\'va\(lu\)e\'$/', $result);
+
+ $result = $this->testDb->conditions(array('Member.name' => '(mariano)'));
+ $this->assertPattern('/^\s+WHERE\s+`Member`.`name`\s+=\s+\'\(mariano\)\'$/', $result);
+
+ $result = $this->testDb->conditions(array('Member.name' => '(mariano)iglesias'));
+ $this->assertPattern('/^\s+WHERE\s+`Member`.`name`\s+=\s+\'\(mariano\)iglesias\'$/', $result);
+
+ $result = $this->testDb->conditions(array('Member.name' => '(mariano) iglesias'));
+ $this->assertPattern('/^\s+WHERE\s+`Member`.`name`\s+=\s+\'\(mariano\) iglesias\'$/', $result);
+
+ $result = $this->testDb->conditions(array('Member.name' => '(mariano word) iglesias'));
+ $this->assertPattern('/^\s+WHERE\s+`Member`.`name`\s+=\s+\'\(mariano word\) iglesias\'$/', $result);
+
+ $result = $this->testDb->conditions(array('Member.name' => '(mariano.iglesias)'));
+ $this->assertPattern('/^\s+WHERE\s+`Member`.`name`\s+=\s+\'\(mariano.iglesias\)\'$/', $result);
+
+ $result = $this->testDb->conditions(array('Member.name' => 'Mariano Iglesias (mariano.iglesias)'));
+ $this->assertPattern('/^\s+WHERE\s+`Member`.`name`\s+=\s+\'Mariano Iglesias \(mariano.iglesias\)\'$/', $result);
+
+ $result = $this->testDb->conditions(array('Member.name' => 'Mariano Iglesias (mariano.iglesias) CakePHP'));
+ $this->assertPattern('/^\s+WHERE\s+`Member`.`name`\s+=\s+\'Mariano Iglesias \(mariano.iglesias\) CakePHP\'$/', $result);
+
+ $result = $this->testDb->conditions(array('Member.name' => '(mariano.iglesias) CakePHP'));
+ $this->assertPattern('/^\s+WHERE\s+`Member`.`name`\s+=\s+\'\(mariano.iglesias\) CakePHP\'$/', $result);
+ }
+
+/**
+ * testArrayConditionsParsing method
+ *
+ * @access public
+ * @return void
+ */
+ function testArrayConditionsParsing() {
+ $result = $this->testDb->conditions(array('Stereo.type' => 'in dash speakers'));
+ $this->assertPattern("/^\s+WHERE\s+`Stereo`.`type`\s+=\s+'in dash speakers'/", $result);
+
+ $result = $this->testDb->conditions(array('Candy.name LIKE' => 'a', 'HardCandy.name LIKE' => 'c'));
+ $this->assertPattern("/^\s+WHERE\s+`Candy`.`name` LIKE\s+'a'\s+AND\s+`HardCandy`.`name`\s+LIKE\s+'c'/", $result);
+
+ $result = $this->testDb->conditions(array('HardCandy.name LIKE' => 'a', 'Candy.name LIKE' => 'c'));
+ $expected = " WHERE `HardCandy`.`name` LIKE 'a' AND `Candy`.`name` LIKE 'c'";
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->conditions(array('HardCandy.name LIKE' => 'a%', 'Candy.name LIKE' => '%c%'));
+ $expected = " WHERE `HardCandy`.`name` LIKE 'a%' AND `Candy`.`name` LIKE '%c%'";
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->conditions(array('HardCandy.name LIKE' => 'to be or%', 'Candy.name LIKE' => '%not to be%'));
+ $expected = " WHERE `HardCandy`.`name` LIKE 'to be or%' AND `Candy`.`name` LIKE '%not to be%'";
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->conditions(array('score BETWEEN ? AND ?' => array(90.1, 95.7)));
+ $expected = " WHERE `score` BETWEEN 90.100000 AND 95.700000";
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->conditions(array('Post.title' => 1.1));
+ $expected = " WHERE `Post`.`title` = 1.100000";
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->conditions(array('Post.title' => 1.1), true, true, new Post());
+ $expected = " WHERE `Post`.`title` = '1.1'";
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->conditions(array('SUM(Post.comments_count) >' => '500'));
+ $expected = " WHERE SUM(`Post`.`comments_count`) > '500'";
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->conditions(array('MAX(Post.rating) >' => '50'));
+ $expected = " WHERE MAX(`Post`.`rating`) > '50'";
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->conditions(array('title LIKE' => '%hello'));
+ $expected = " WHERE `title` LIKE '%hello'";
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->conditions(array('Post.name' => 'mad(g)ik'));
+ $expected = " WHERE `Post`.`name` = 'mad(g)ik'";
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->conditions(array('score' => array(1, 2, 10)));
+ $expected = " WHERE score IN (1, 2, 10)";
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->conditions(array('score' => array()));
+ $expected = " WHERE `score` IS NULL";
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->conditions(array('score !=' => array()));
+ $expected = " WHERE `score` IS NOT NULL";
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->conditions(array('score !=' => '20'));
+ $expected = " WHERE `score` != '20'";
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->conditions(array('score >' => '20'));
+ $expected = " WHERE `score` > '20'";
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->conditions(array('client_id >' => '20'), true, true, new TestModel());
+ $expected = " WHERE `client_id` > 20";
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->conditions(array('OR' => array(
+ array('User.user' => 'mariano'),
+ array('User.user' => 'nate')
+ )));
+
+ $expected = " WHERE ((`User`.`user` = 'mariano') OR (`User`.`user` = 'nate'))";
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->conditions(array('or' => array(
+ 'score BETWEEN ? AND ?' => array('4', '5'), 'rating >' => '20'
+ )));
+ $expected = " WHERE ((`score` BETWEEN '4' AND '5') OR (`rating` > '20'))";
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->conditions(array('or' => array(
+ 'score BETWEEN ? AND ?' => array('4', '5'), array('score >' => '20')
+ )));
+ $expected = " WHERE ((`score` BETWEEN '4' AND '5') OR (`score` > '20'))";
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->conditions(array('and' => array(
+ 'score BETWEEN ? AND ?' => array('4', '5'), array('score >' => '20')
+ )));
+ $expected = " WHERE ((`score` BETWEEN '4' AND '5') AND (`score` > '20'))";
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->conditions(array(
+ 'published' => 1, 'or' => array('score >' => '2', array('score >' => '20'))
+ ));
+ $expected = " WHERE `published` = 1 AND ((`score` > '2') OR (`score` > '20'))";
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->conditions(array(array('Project.removed' => false)));
+ $expected = " WHERE `Project`.`removed` = 0";
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->conditions(array(array('Project.removed' => true)));
+ $expected = " WHERE `Project`.`removed` = 1";
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->conditions(array(array('Project.removed' => null)));
+ $expected = " WHERE `Project`.`removed` IS NULL";
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->conditions(array(array('Project.removed !=' => null)));
+ $expected = " WHERE `Project`.`removed` IS NOT NULL";
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->conditions(array('(Usergroup.permissions) & 4' => 4));
+ $expected = " WHERE (`Usergroup`.`permissions`) & 4 = 4";
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->conditions(array('((Usergroup.permissions) & 4)' => 4));
+ $expected = " WHERE ((`Usergroup`.`permissions`) & 4) = 4";
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->conditions(array('Post.modified >=' => 'DATE_SUB(NOW(), INTERVAL 7 DAY)'));
+ $expected = " WHERE `Post`.`modified` >= 'DATE_SUB(NOW(), INTERVAL 7 DAY)'";
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->conditions(array('Post.modified >= DATE_SUB(NOW(), INTERVAL 7 DAY)'));
+ $expected = " WHERE `Post`.`modified` >= DATE_SUB(NOW(), INTERVAL 7 DAY)";
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->conditions(array(
+ 'NOT' => array('Course.id' => null, 'Course.vet' => 'N', 'level_of_education_id' => array(912,999)),
+ 'Enrollment.yearcompleted >' => '0')
+ );
+ $this->assertPattern('/^\s*WHERE\s+\(NOT\s+\(`Course`\.`id` IS NULL\)\s+AND NOT\s+\(`Course`\.`vet`\s+=\s+\'N\'\)\s+AND NOT\s+\(level_of_education_id IN \(912, 999\)\)\)\s+AND\s+`Enrollment`\.`yearcompleted`\s+>\s+\'0\'\s*$/', $result);
+
+ $result = $this->testDb->conditions(array('id <>' => '8'));
+ $this->assertPattern('/^\s*WHERE\s+`id`\s+<>\s+\'8\'\s*$/', $result);
+
+ $result = $this->testDb->conditions(array('TestModel.field =' => 'gribe$@()lu'));
+ $expected = " WHERE `TestModel`.`field` = 'gribe$@()lu'";
+ $this->assertEqual($result, $expected);
+
+ $conditions['NOT'] = array('Listing.expiration BETWEEN ? AND ?' => array("1", "100"));
+ $conditions[0]['OR'] = array(
+ "Listing.title LIKE" => "%term%",
+ "Listing.description LIKE" => "%term%"
+ );
+ $conditions[1]['OR'] = array(
+ "Listing.title LIKE" => "%term_2%",
+ "Listing.description LIKE" => "%term_2%"
+ );
+ $result = $this->testDb->conditions($conditions);
+ $expected = " WHERE NOT (`Listing`.`expiration` BETWEEN '1' AND '100') AND" .
+ " ((`Listing`.`title` LIKE '%term%') OR (`Listing`.`description` LIKE '%term%')) AND" .
+ " ((`Listing`.`title` LIKE '%term_2%') OR (`Listing`.`description` LIKE '%term_2%'))";
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->conditions(array('MD5(CONCAT(Reg.email,Reg.id))' => 'blah'));
+ $expected = " WHERE MD5(CONCAT(`Reg`.`email`,`Reg`.`id`)) = 'blah'";
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->conditions(array(
+ 'MD5(CONCAT(Reg.email,Reg.id))' => array('blah', 'blahblah')
+ ));
+ $expected = " WHERE MD5(CONCAT(`Reg`.`email`,`Reg`.`id`)) IN ('blah', 'blahblah')";
+ $this->assertEqual($result, $expected);
+
+ $conditions = array('id' => array(2, 5, 6, 9, 12, 45, 78, 43, 76));
+ $result = $this->testDb->conditions($conditions);
+ $expected = " WHERE id IN (2, 5, 6, 9, 12, 45, 78, 43, 76)";
+ $this->assertEqual($result, $expected);
+
+ $conditions = array('title' => 'user(s)');
+ $result = $this->testDb->conditions($conditions);
+ $expected = " WHERE `title` = 'user(s)'";
+ $this->assertEqual($result, $expected);
+
+ $conditions = array('title' => 'user(s) data');
+ $result = $this->testDb->conditions($conditions);
+ $expected = " WHERE `title` = 'user(s) data'";
+ $this->assertEqual($result, $expected);
+
+ $conditions = array('title' => 'user(s,arg) data');
+ $result = $this->testDb->conditions($conditions);
+ $expected = " WHERE `title` = 'user(s,arg) data'";
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->conditions(array("Book.book_name" => 'Java(TM)'));
+ $expected = " WHERE `Book`.`book_name` = 'Java(TM)'";
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->conditions(array("Book.book_name" => 'Java(TM) '));
+ $expected = " WHERE `Book`.`book_name` = 'Java(TM) '";
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->conditions(array("Book.id" => 0));
+ $expected = " WHERE `Book`.`id` = 0";
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->conditions(array("Book.id" => NULL));
+ $expected = " WHERE `Book`.`id` IS NULL";
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->conditions(array('Listing.beds >=' => 0));
+ $expected = " WHERE `Listing`.`beds` >= 0";
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->conditions(array(
+ 'ASCII(SUBSTRING(keyword, 1, 1)) BETWEEN ? AND ?' => array(65, 90)
+ ));
+ $expected = ' WHERE ASCII(SUBSTRING(keyword, 1, 1)) BETWEEN 65 AND 90';
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->conditions(array('or' => array(
+ '? BETWEEN Model.field1 AND Model.field2' => '2009-03-04'
+ )));
+ $expected = " WHERE '2009-03-04' BETWEEN Model.field1 AND Model.field2";
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testArrayConditionsParsingComplexKeys method
+ *
+ * @access public
+ * @return void
+ */
+ function testArrayConditionsParsingComplexKeys() {
+ $result = $this->testDb->conditions(array(
+ 'CAST(Book.created AS DATE)' => '2008-08-02'
+ ));
+ $expected = " WHERE CAST(`Book`.`created` AS DATE) = '2008-08-02'";
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->conditions(array(
+ 'CAST(Book.created AS DATE) <=' => '2008-08-02'
+ ));
+ $expected = " WHERE CAST(`Book`.`created` AS DATE) <= '2008-08-02'";
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->conditions(array(
+ '(Stats.clicks * 100) / Stats.views >' => 50
+ ));
+ $expected = " WHERE (`Stats`.`clicks` * 100) / `Stats`.`views` > 50";
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testMixedConditionsParsing method
+ *
+ * @access public
+ * @return void
+ */
+ function testMixedConditionsParsing() {
+ $conditions[] = 'User.first_name = \'Firstname\'';
+ $conditions[] = array('User.last_name' => 'Lastname');
+ $result = $this->testDb->conditions($conditions);
+ $expected = " WHERE `User`.`first_name` = 'Firstname' AND `User`.`last_name` = 'Lastname'";
+ $this->assertEqual($result, $expected);
+
+ $conditions = array(
+ 'Thread.project_id' => 5,
+ 'Thread.buyer_id' => 14,
+ '1=1 GROUP BY Thread.project_id'
+ );
+ $result = $this->testDb->conditions($conditions);
+ $this->assertPattern('/^\s*WHERE\s+`Thread`.`project_id`\s*=\s*5\s+AND\s+`Thread`.`buyer_id`\s*=\s*14\s+AND\s+1\s*=\s*1\s+GROUP BY `Thread`.`project_id`$/', $result);
+ }
+
+/**
+ * testConditionsOptionalArguments method
+ *
+ * @access public
+ * @return void
+ */
+ function testConditionsOptionalArguments() {
+ $result = $this->testDb->conditions( array('Member.name' => 'Mariano'), true, false);
+ $this->assertPattern('/^\s*`Member`.`name`\s*=\s*\'Mariano\'\s*$/', $result);
+
+ $result = $this->testDb->conditions( array(), true, false);
+ $this->assertPattern('/^\s*1\s*=\s*1\s*$/', $result);
+ }
+
+/**
+ * testConditionsWithModel
+ *
+ * @access public
+ * @return void
+ */
+ function testConditionsWithModel() {
+ $this->Model =& new Article2();
+
+ $result = $this->testDb->conditions(array('Article2.viewed >=' => 0), true, true, $this->Model);
+ $expected = " WHERE `Article2`.`viewed` >= 0";
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->conditions(array('Article2.viewed >=' => '0'), true, true, $this->Model);
+ $expected = " WHERE `Article2`.`viewed` >= 0";
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->conditions(array('Article2.viewed >=' => '1'), true, true, $this->Model);
+ $expected = " WHERE `Article2`.`viewed` >= 1";
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->conditions(array('Article2.rate_sum BETWEEN ? AND ?' => array(0, 10)), true, true, $this->Model);
+ $expected = " WHERE `Article2`.`rate_sum` BETWEEN 0 AND 10";
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->conditions(array('Article2.rate_sum BETWEEN ? AND ?' => array('0', '10')), true, true, $this->Model);
+ $expected = " WHERE `Article2`.`rate_sum` BETWEEN 0 AND 10";
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->conditions(array('Article2.rate_sum BETWEEN ? AND ?' => array('1', '10')), true, true, $this->Model);
+ $expected = " WHERE `Article2`.`rate_sum` BETWEEN 1 AND 10";
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testFieldParsing method
+ *
+ * @access public
+ * @return void
+ */
+ function testFieldParsing() {
+ $result = $this->testDb->fields($this->Model, 'Vendor', "Vendor.id, COUNT(Model.vendor_id) AS `Vendor`.`count`");
+ $expected = array('`Vendor`.`id`', 'COUNT(`Model`.`vendor_id`) AS `Vendor`.`count`');
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->fields($this->Model, 'Vendor', "`Vendor`.`id`, COUNT(`Model`.`vendor_id`) AS `Vendor`.`count`");
+ $expected = array('`Vendor`.`id`', 'COUNT(`Model`.`vendor_id`) AS `Vendor`.`count`');
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->fields($this->Model, 'Post', "CONCAT(REPEAT(' ', COUNT(Parent.name) - 1), Node.name) AS name, Node.created");
+ $expected = array("CONCAT(REPEAT(' ', COUNT(`Parent`.`name`) - 1), Node.name) AS name", "`Node`.`created`");
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->fields($this->Model, null, 'round( (3.55441 * fooField), 3 ) AS test');
+ $this->assertEqual($result, array('round( (3.55441 * fooField), 3 ) AS test'));
+
+ $result = $this->testDb->fields($this->Model, null, 'ROUND(`Rating`.`rate_total` / `Rating`.`rate_count`,2) AS rating');
+ $this->assertEqual($result, array('ROUND(`Rating`.`rate_total` / `Rating`.`rate_count`,2) AS rating'));
+
+ $result = $this->testDb->fields($this->Model, null, 'ROUND(Rating.rate_total / Rating.rate_count,2) AS rating');
+ $this->assertEqual($result, array('ROUND(Rating.rate_total / Rating.rate_count,2) AS rating'));
+
+ $result = $this->testDb->fields($this->Model, 'Post', "Node.created, CONCAT(REPEAT(' ', COUNT(Parent.name) - 1), Node.name) AS name");
+ $expected = array("`Node`.`created`", "CONCAT(REPEAT(' ', COUNT(`Parent`.`name`) - 1), Node.name) AS name");
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->fields($this->Model, 'Post', "2.2,COUNT(*), SUM(Something.else) as sum, Node.created, CONCAT(REPEAT(' ', COUNT(Parent.name) - 1), Node.name) AS name,Post.title,Post.1,1.1");
+ $expected = array(
+ '2.2', 'COUNT(*)', 'SUM(`Something`.`else`) as sum', '`Node`.`created`',
+ "CONCAT(REPEAT(' ', COUNT(`Parent`.`name`) - 1), Node.name) AS name", '`Post`.`title`', '`Post`.`1`', '1.1'
+ );
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->fields($this->Model, null, "(`Provider`.`star_total` / `Provider`.`total_ratings`) as `rating`");
+ $expected = array("(`Provider`.`star_total` / `Provider`.`total_ratings`) as `rating`");
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->fields($this->Model, 'Post');
+ $expected = array(
+ '`Post`.`id`', '`Post`.`client_id`', '`Post`.`name`', '`Post`.`login`',
+ '`Post`.`passwd`', '`Post`.`addr_1`', '`Post`.`addr_2`', '`Post`.`zip_code`',
+ '`Post`.`city`', '`Post`.`country`', '`Post`.`phone`', '`Post`.`fax`',
+ '`Post`.`url`', '`Post`.`email`', '`Post`.`comments`', '`Post`.`last_login`',
+ '`Post`.`created`', '`Post`.`updated`'
+ );
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->fields($this->Model, 'Other');
+ $expected = array(
+ '`Other`.`id`', '`Other`.`client_id`', '`Other`.`name`', '`Other`.`login`',
+ '`Other`.`passwd`', '`Other`.`addr_1`', '`Other`.`addr_2`', '`Other`.`zip_code`',
+ '`Other`.`city`', '`Other`.`country`', '`Other`.`phone`', '`Other`.`fax`',
+ '`Other`.`url`', '`Other`.`email`', '`Other`.`comments`', '`Other`.`last_login`',
+ '`Other`.`created`', '`Other`.`updated`'
+ );
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->fields($this->Model, null, array(), false);
+ $expected = array('id', 'client_id', 'name', 'login', 'passwd', 'addr_1', 'addr_2', 'zip_code', 'city', 'country', 'phone', 'fax', 'url', 'email', 'comments', 'last_login', 'created', 'updated');
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->fields($this->Model, null, 'COUNT(*)');
+ $expected = array('COUNT(*)');
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->fields($this->Model, null, 'SUM(Thread.unread_buyer) AS ' . $this->testDb->name('sum_unread_buyer'));
+ $expected = array('SUM(`Thread`.`unread_buyer`) AS `sum_unread_buyer`');
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->fields($this->Model, null, 'name, count(*)');
+ $expected = array('`TestModel`.`name`', 'count(*)');
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->fields($this->Model, null, 'count(*), name');
+ $expected = array('count(*)', '`TestModel`.`name`');
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->fields(
+ $this->Model, null, 'field1, field2, field3, count(*), name'
+ );
+ $expected = array(
+ '`TestModel`.`field1`', '`TestModel`.`field2`',
+ '`TestModel`.`field3`', 'count(*)', '`TestModel`.`name`'
+ );
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->fields($this->Model, null, array('dayofyear(now())'));
+ $expected = array('dayofyear(now())');
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->fields($this->Model, null, array('MAX(Model.field) As Max'));
+ $expected = array('MAX(`Model`.`field`) As Max');
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->fields($this->Model, null, array('Model.field AS AnotherName'));
+ $expected = array('`Model`.`field` AS `AnotherName`');
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->fields($this->Model, null, array('field AS AnotherName'));
+ $expected = array('`field` AS `AnotherName`');
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->fields($this->Model, null, array(
+ 'TestModel.field AS AnotherName'
+ ));
+ $expected = array('`TestModel`.`field` AS `AnotherName`');
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->fields($this->Model, 'Foo', array(
+ 'id', 'title', '(user_count + discussion_count + post_count) AS score'
+ ));
+ $expected = array(
+ '`Foo`.`id`',
+ '`Foo`.`title`',
+ '(user_count + discussion_count + post_count) AS score'
+ );
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * test that fields() will accept objects made from DboSource::expression
+ *
+ * @return void
+ */
+ function testFieldsWithExpression() {
+ $expression = $this->testDb->expression("CASE Sample.id WHEN 1 THEN 'Id One' ELSE 'Other Id' END AS case_col");
+ $result = $this->testDb->fields($this->Model, null, array("id", $expression));
+ $expected = array(
+ '`TestModel`.`id`',
+ "CASE Sample.id WHEN 1 THEN 'Id One' ELSE 'Other Id' END AS case_col"
+ );
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * test that order() will accept objects made from DboSource::expression
+ *
+ * @return void
+ */
+ function testOrderWithExpression() {
+ $expression = $this->testDb->expression("CASE Sample.id WHEN 1 THEN 'Id One' ELSE 'Other Id' END AS case_col");
+ $result = $this->testDb->order($expression);
+ $expected = " ORDER BY CASE Sample.id WHEN 1 THEN 'Id One' ELSE 'Other Id' END AS case_col";
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testMergeAssociations method
+ *
+ * @access public
+ * @return void
+ */
+ function testMergeAssociations() {
+ $data = array('Article2' => array(
+ 'id' => '1', 'user_id' => '1', 'title' => 'First Article',
+ 'body' => 'First Article Body', 'published' => 'Y',
+ 'created' => '2007-03-18 10:39:23', 'updated' => '2007-03-18 10:41:31'
+ ));
+ $merge = array('Topic' => array(array(
+ 'id' => '1', 'topic' => 'Topic', 'created' => '2007-03-17 01:16:23',
+ 'updated' => '2007-03-17 01:18:31'
+ )));
+ $expected = array(
+ 'Article2' => array(
+ 'id' => '1', 'user_id' => '1', 'title' => 'First Article',
+ 'body' => 'First Article Body', 'published' => 'Y',
+ 'created' => '2007-03-18 10:39:23', 'updated' => '2007-03-18 10:41:31'
+ ),
+ 'Topic' => array(
+ 'id' => '1', 'topic' => 'Topic', 'created' => '2007-03-17 01:16:23',
+ 'updated' => '2007-03-17 01:18:31'
+ )
+ );
+ $this->testDb->__mergeAssociation($data, $merge, 'Topic', 'hasOne');
+ $this->assertEqual($data, $expected);
+
+ $data = array('Article2' => array(
+ 'id' => '1', 'user_id' => '1', 'title' => 'First Article',
+ 'body' => 'First Article Body', 'published' => 'Y',
+ 'created' => '2007-03-18 10:39:23', 'updated' => '2007-03-18 10:41:31'
+ ));
+ $merge = array('User2' => array(array(
+ 'id' => '1', 'user' => 'mariano', 'password' => '5f4dcc3b5aa765d61d8327deb882cf99',
+ 'created' => '2007-03-17 01:16:23', 'updated' => '2007-03-17 01:18:31'
+ )));
+
+ $expected = array(
+ 'Article2' => array(
+ 'id' => '1', 'user_id' => '1', 'title' => 'First Article',
+ 'body' => 'First Article Body', 'published' => 'Y',
+ 'created' => '2007-03-18 10:39:23', 'updated' => '2007-03-18 10:41:31'
+ ),
+ 'User2' => array(
+ 'id' => '1', 'user' => 'mariano', 'password' => '5f4dcc3b5aa765d61d8327deb882cf99', 'created' => '2007-03-17 01:16:23', 'updated' => '2007-03-17 01:18:31'
+ )
+ );
+ $this->testDb->__mergeAssociation($data, $merge, 'User2', 'belongsTo');
+ $this->assertEqual($data, $expected);
+
+ $data = array(
+ 'Article2' => array(
+ 'id' => '1', 'user_id' => '1', 'title' => 'First Article', 'body' => 'First Article Body', 'published' => 'Y', 'created' => '2007-03-18 10:39:23', 'updated' => '2007-03-18 10:41:31'
+ )
+ );
+ $merge = array(array('Comment' => false));
+ $expected = array(
+ 'Article2' => array(
+ 'id' => '1', 'user_id' => '1', 'title' => 'First Article', 'body' => 'First Article Body', 'published' => 'Y', 'created' => '2007-03-18 10:39:23', 'updated' => '2007-03-18 10:41:31'
+ ),
+ 'Comment' => array()
+ );
+ $this->testDb->__mergeAssociation($data, $merge, 'Comment', 'hasMany');
+ $this->assertEqual($data, $expected);
+
+ $data = array(
+ 'Article' => array(
+ 'id' => '1', 'user_id' => '1', 'title' => 'First Article', 'body' => 'First Article Body', 'published' => 'Y', 'created' => '2007-03-18 10:39:23', 'updated' => '2007-03-18 10:41:31'
+ )
+ );
+ $merge = array(
+ array(
+ 'Comment' => array(
+ 'id' => '1', 'comment' => 'Comment 1', 'created' => '2007-03-17 01:16:23', 'updated' => '2007-03-17 01:18:31'
+ )
+ ),
+ array(
+ 'Comment' => array(
+ 'id' => '2', 'comment' => 'Comment 2', 'created' => '2007-03-17 01:16:23', 'updated' => '2007-03-17 01:18:31'
+ )
+ )
+ );
+ $expected = array(
+ 'Article' => array(
+ 'id' => '1', 'user_id' => '1', 'title' => 'First Article', 'body' => 'First Article Body', 'published' => 'Y', 'created' => '2007-03-18 10:39:23', 'updated' => '2007-03-18 10:41:31'
+ ),
+ 'Comment' => array(
+ array(
+ 'id' => '1', 'comment' => 'Comment 1', 'created' => '2007-03-17 01:16:23', 'updated' => '2007-03-17 01:18:31'
+ ),
+ array(
+ 'id' => '2', 'comment' => 'Comment 2', 'created' => '2007-03-17 01:16:23', 'updated' => '2007-03-17 01:18:31'
+ )
+ )
+ );
+ $this->testDb->__mergeAssociation($data, $merge, 'Comment', 'hasMany');
+ $this->assertEqual($data, $expected);
+
+ $data = array(
+ 'Article' => array(
+ 'id' => '1', 'user_id' => '1', 'title' => 'First Article', 'body' => 'First Article Body', 'published' => 'Y', 'created' => '2007-03-18 10:39:23', 'updated' => '2007-03-18 10:41:31'
+ )
+ );
+ $merge = array(
+ array(
+ 'Comment' => array(
+ 'id' => '1', 'comment' => 'Comment 1', 'created' => '2007-03-17 01:16:23', 'updated' => '2007-03-17 01:18:31'
+ ),
+ 'User2' => array(
+ 'id' => '1', 'user' => 'mariano', 'password' => '5f4dcc3b5aa765d61d8327deb882cf99', 'created' => '2007-03-17 01:16:23', 'updated' => '2007-03-17 01:18:31'
+ )
+ ),
+ array(
+ 'Comment' => array(
+ 'id' => '2', 'comment' => 'Comment 2', 'created' => '2007-03-17 01:16:23', 'updated' => '2007-03-17 01:18:31'
+ ),
+ 'User2' => array(
+ 'id' => '1', 'user' => 'mariano', 'password' => '5f4dcc3b5aa765d61d8327deb882cf99', 'created' => '2007-03-17 01:16:23', 'updated' => '2007-03-17 01:18:31'
+ )
+ )
+ );
+ $expected = array(
+ 'Article' => array(
+ 'id' => '1', 'user_id' => '1', 'title' => 'First Article', 'body' => 'First Article Body', 'published' => 'Y', 'created' => '2007-03-18 10:39:23', 'updated' => '2007-03-18 10:41:31'
+ ),
+ 'Comment' => array(
+ array(
+ 'id' => '1', 'comment' => 'Comment 1', 'created' => '2007-03-17 01:16:23', 'updated' => '2007-03-17 01:18:31',
+ 'User2' => array(
+ 'id' => '1', 'user' => 'mariano', 'password' => '5f4dcc3b5aa765d61d8327deb882cf99', 'created' => '2007-03-17 01:16:23', 'updated' => '2007-03-17 01:18:31'
+ )
+ ),
+ array(
+ 'id' => '2', 'comment' => 'Comment 2', 'created' => '2007-03-17 01:16:23', 'updated' => '2007-03-17 01:18:31',
+ 'User2' => array(
+ 'id' => '1', 'user' => 'mariano', 'password' => '5f4dcc3b5aa765d61d8327deb882cf99', 'created' => '2007-03-17 01:16:23', 'updated' => '2007-03-17 01:18:31'
+ )
+ )
+ )
+ );
+ $this->testDb->__mergeAssociation($data, $merge, 'Comment', 'hasMany');
+ $this->assertEqual($data, $expected);
+
+ $data = array(
+ 'Article' => array(
+ 'id' => '1', 'user_id' => '1', 'title' => 'First Article', 'body' => 'First Article Body', 'published' => 'Y', 'created' => '2007-03-18 10:39:23', 'updated' => '2007-03-18 10:41:31'
+ )
+ );
+ $merge = array(
+ array(
+ 'Comment' => array(
+ 'id' => '1', 'comment' => 'Comment 1', 'created' => '2007-03-17 01:16:23', 'updated' => '2007-03-17 01:18:31'
+ ),
+ 'User2' => array(
+ 'id' => '1', 'user' => 'mariano', 'password' => '5f4dcc3b5aa765d61d8327deb882cf99', 'created' => '2007-03-17 01:16:23', 'updated' => '2007-03-17 01:18:31'
+ ),
+ 'Tag' => array(
+ array('id' => 1, 'tag' => 'Tag 1'),
+ array('id' => 2, 'tag' => 'Tag 2')
+ )
+ ),
+ array(
+ 'Comment' => array(
+ 'id' => '2', 'comment' => 'Comment 2', 'created' => '2007-03-17 01:16:23', 'updated' => '2007-03-17 01:18:31'
+ ),
+ 'User2' => array(
+ 'id' => '1', 'user' => 'mariano', 'password' => '5f4dcc3b5aa765d61d8327deb882cf99', 'created' => '2007-03-17 01:16:23', 'updated' => '2007-03-17 01:18:31'
+ ),
+ 'Tag' => array()
+ )
+ );
+ $expected = array(
+ 'Article' => array(
+ 'id' => '1', 'user_id' => '1', 'title' => 'First Article', 'body' => 'First Article Body', 'published' => 'Y', 'created' => '2007-03-18 10:39:23', 'updated' => '2007-03-18 10:41:31'
+ ),
+ 'Comment' => array(
+ array(
+ 'id' => '1', 'comment' => 'Comment 1', 'created' => '2007-03-17 01:16:23', 'updated' => '2007-03-17 01:18:31',
+ 'User2' => array(
+ 'id' => '1', 'user' => 'mariano', 'password' => '5f4dcc3b5aa765d61d8327deb882cf99', 'created' => '2007-03-17 01:16:23', 'updated' => '2007-03-17 01:18:31'
+ ),
+ 'Tag' => array(
+ array('id' => 1, 'tag' => 'Tag 1'),
+ array('id' => 2, 'tag' => 'Tag 2')
+ )
+ ),
+ array(
+ 'id' => '2', 'comment' => 'Comment 2', 'created' => '2007-03-17 01:16:23', 'updated' => '2007-03-17 01:18:31',
+ 'User2' => array(
+ 'id' => '1', 'user' => 'mariano', 'password' => '5f4dcc3b5aa765d61d8327deb882cf99', 'created' => '2007-03-17 01:16:23', 'updated' => '2007-03-17 01:18:31'
+ ),
+ 'Tag' => array()
+ )
+ )
+ );
+ $this->testDb->__mergeAssociation($data, $merge, 'Comment', 'hasMany');
+ $this->assertEqual($data, $expected);
+
+ $data = array(
+ 'Article' => array(
+ 'id' => '1', 'user_id' => '1', 'title' => 'First Article', 'body' => 'First Article Body', 'published' => 'Y', 'created' => '2007-03-18 10:39:23', 'updated' => '2007-03-18 10:41:31'
+ )
+ );
+ $merge = array(
+ array(
+ 'Tag' => array(
+ 'id' => '1', 'tag' => 'Tag 1', 'created' => '2007-03-17 01:16:23', 'updated' => '2007-03-17 01:18:31'
+ )
+ ),
+ array(
+ 'Tag' => array(
+ 'id' => '2', 'tag' => 'Tag 2', 'created' => '2007-03-17 01:16:23', 'updated' => '2007-03-17 01:18:31'
+ )
+ ),
+ array(
+ 'Tag' => array(
+ 'id' => '3', 'tag' => 'Tag 3', 'created' => '2007-03-17 01:16:23', 'updated' => '2007-03-17 01:18:31'
+ )
+ )
+ );
+ $expected = array(
+ 'Article' => array(
+ 'id' => '1', 'user_id' => '1', 'title' => 'First Article', 'body' => 'First Article Body', 'published' => 'Y', 'created' => '2007-03-18 10:39:23', 'updated' => '2007-03-18 10:41:31'
+ ),
+ 'Tag' => array(
+ array(
+ 'id' => '1', 'tag' => 'Tag 1', 'created' => '2007-03-17 01:16:23', 'updated' => '2007-03-17 01:18:31'
+ ),
+ array(
+ 'id' => '2', 'tag' => 'Tag 2', 'created' => '2007-03-17 01:16:23', 'updated' => '2007-03-17 01:18:31'
+ ),
+ array(
+ 'id' => '3', 'tag' => 'Tag 3', 'created' => '2007-03-17 01:16:23', 'updated' => '2007-03-17 01:18:31'
+ )
+ )
+ );
+ $this->testDb->__mergeAssociation($data, $merge, 'Tag', 'hasAndBelongsToMany');
+ $this->assertEqual($data, $expected);
+
+ $data = array(
+ 'Article' => array(
+ 'id' => '1', 'user_id' => '1', 'title' => 'First Article', 'body' => 'First Article Body', 'published' => 'Y', 'created' => '2007-03-18 10:39:23', 'updated' => '2007-03-18 10:41:31'
+ )
+ );
+ $merge = array(
+ array(
+ 'Tag' => array(
+ 'id' => '1', 'tag' => 'Tag 1', 'created' => '2007-03-17 01:16:23', 'updated' => '2007-03-17 01:18:31'
+ )
+ ),
+ array(
+ 'Tag' => array(
+ 'id' => '2', 'tag' => 'Tag 2', 'created' => '2007-03-17 01:16:23', 'updated' => '2007-03-17 01:18:31'
+ )
+ ),
+ array(
+ 'Tag' => array(
+ 'id' => '3', 'tag' => 'Tag 3', 'created' => '2007-03-17 01:16:23', 'updated' => '2007-03-17 01:18:31'
+ )
+ )
+ );
+ $expected = array(
+ 'Article' => array(
+ 'id' => '1', 'user_id' => '1', 'title' => 'First Article', 'body' => 'First Article Body', 'published' => 'Y', 'created' => '2007-03-18 10:39:23', 'updated' => '2007-03-18 10:41:31'
+ ),
+ 'Tag' => array('id' => '1', 'tag' => 'Tag 1', 'created' => '2007-03-17 01:16:23', 'updated' => '2007-03-17 01:18:31')
+ );
+ $this->testDb->__mergeAssociation($data, $merge, 'Tag', 'hasOne');
+ $this->assertEqual($data, $expected);
+ }
+
+/**
+ * testRenderStatement method
+ *
+ * @access public
+ * @return void
+ */
+ function testRenderStatement() {
+ $result = $this->testDb->renderStatement('select', array(
+ 'fields' => 'id', 'table' => 'table', 'conditions' => 'WHERE 1=1',
+ 'alias' => '', 'joins' => '', 'order' => '', 'limit' => '', 'group' => ''
+ ));
+ $this->assertPattern('/^\s*SELECT\s+id\s+FROM\s+table\s+WHERE\s+1=1\s*$/', $result);
+
+ $result = $this->testDb->renderStatement('update', array('fields' => 'value=2', 'table' => 'table', 'conditions' => 'WHERE 1=1', 'alias' => ''));
+ $this->assertPattern('/^\s*UPDATE\s+table\s+SET\s+value=2\s+WHERE\s+1=1\s*$/', $result);
+
+ $result = $this->testDb->renderStatement('update', array('fields' => 'value=2', 'table' => 'table', 'conditions' => 'WHERE 1=1', 'alias' => 'alias', 'joins' => ''));
+ $this->assertPattern('/^\s*UPDATE\s+table\s+AS\s+alias\s+SET\s+value=2\s+WHERE\s+1=1\s*$/', $result);
+
+ $result = $this->testDb->renderStatement('delete', array('fields' => 'value=2', 'table' => 'table', 'conditions' => 'WHERE 1=1', 'alias' => ''));
+ $this->assertPattern('/^\s*DELETE\s+FROM\s+table\s+WHERE\s+1=1\s*$/', $result);
+
+ $result = $this->testDb->renderStatement('delete', array('fields' => 'value=2', 'table' => 'table', 'conditions' => 'WHERE 1=1', 'alias' => 'alias', 'joins' => ''));
+ $this->assertPattern('/^\s*DELETE\s+alias\s+FROM\s+table\s+AS\s+alias\s+WHERE\s+1=1\s*$/', $result);
+ }
+
+/**
+ * testStatements method
+ *
+ * @access public
+ * @return void
+ */
+ function testStatements() {
+ $Article =& ClassRegistry::init('Article');
+
+ $result = $this->testDb->update($Article, array('field1'), array('value1'));
+ $this->assertFalse($result);
+ $result = $this->testDb->getLastQuery();
+ $this->assertPattern('/^\s*UPDATE\s+' . $this->testDb->fullTableName('articles') . '\s+SET\s+`field1`\s*=\s*\'value1\'\s+WHERE\s+1 = 1\s*$/', $result);
+
+ $result = $this->testDb->update($Article, array('field1'), array('2'), '2=2');
+ $this->assertFalse($result);
+ $result = $this->testDb->getLastQuery();
+ $this->assertPattern('/^\s*UPDATE\s+' . $this->testDb->fullTableName('articles') . ' AS `Article`\s+LEFT JOIN\s+' . $this->testDb->fullTableName('users') . ' AS `User` ON \(`Article`.`user_id` = `User`.`id`\)\s+SET\s+`Article`\.`field1`\s*=\s*2\s+WHERE\s+2\s*=\s*2\s*$/', $result);
+
+ $result = $this->testDb->delete($Article);
+ $this->assertTrue($result);
+ $result = $this->testDb->getLastQuery();
+ $this->assertPattern('/^\s*DELETE\s+FROM\s+' . $this->testDb->fullTableName('articles') . '\s+WHERE\s+1 = 1\s*$/', $result);
+
+ $result = $this->testDb->delete($Article, true);
+ $this->assertTrue($result);
+ $result = $this->testDb->getLastQuery();
+ $this->assertPattern('/^\s*DELETE\s+`Article`\s+FROM\s+' . $this->testDb->fullTableName('articles') . '\s+AS `Article`\s+LEFT JOIN\s+' . $this->testDb->fullTableName('users') . ' AS `User` ON \(`Article`.`user_id` = `User`.`id`\)\s+WHERE\s+1\s*=\s*1\s*$/', $result);
+
+ $result = $this->testDb->delete($Article, '2=2');
+ $this->assertTrue($result);
+ $result = $this->testDb->getLastQuery();
+ $this->assertPattern('/^\s*DELETE\s+`Article`\s+FROM\s+' . $this->testDb->fullTableName('articles') . '\s+AS `Article`\s+LEFT JOIN\s+' . $this->testDb->fullTableName('users') . ' AS `User` ON \(`Article`.`user_id` = `User`.`id`\)\s+WHERE\s+2\s*=\s*2\s*$/', $result);
+
+ $result = $this->testDb->hasAny($Article, '1=2');
+ $this->assertFalse($result);
+
+ $result = $this->testDb->insertMulti('articles', array('field'), array('(1)', '(2)'));
+ $this->assertFalse($result);
+ $result = $this->testDb->getLastQuery();
+ $this->assertPattern('/^\s*INSERT INTO\s+' . $this->testDb->fullTableName('articles') . '\s+\(`field`\)\s+VALUES\s+\(1\),\s*\(2\)\s*$/', $result);
+ }
+
+/**
+ * testSchema method
+ *
+ * @access public
+ * @return void
+ */
+ function testSchema() {
+ $Schema =& new CakeSchema();
+ $Schema->tables = array('table' => array(), 'anotherTable' => array());
+
+ $this->expectError();
+ $result = $this->testDb->dropSchema(null);
+ $this->assertTrue($result === null);
+
+ $result = $this->testDb->dropSchema($Schema, 'non_existing');
+ $this->assertTrue(empty($result));
+
+ $result = $this->testDb->dropSchema($Schema, 'table');
+ $this->assertPattern('/^\s*DROP TABLE IF EXISTS\s+' . $this->testDb->fullTableName('table') . ';\s*$/s', $result);
+ }
+
+/**
+ * testMagicMethodQuerying method
+ *
+ * @access public
+ * @return void
+ */
+ function testMagicMethodQuerying() {
+ $result = $this->testDb->query('findByFieldName', array('value'), $this->Model);
+ $expected = array('first', array(
+ 'conditions' => array('TestModel.field_name' => 'value'),
+ 'fields' => null, 'order' => null, 'recursive' => null
+ ));
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->query('findByFindBy', array('value'), $this->Model);
+ $expected = array('first', array(
+ 'conditions' => array('TestModel.find_by' => 'value'),
+ 'fields' => null, 'order' => null, 'recursive' => null
+ ));
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->query('findAllByFieldName', array('value'), $this->Model);
+ $expected = array('all', array(
+ 'conditions' => array('TestModel.field_name' => 'value'),
+ 'fields' => null, 'order' => null, 'limit' => null,
+ 'page' => null, 'recursive' => null
+ ));
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->query('findAllById', array('a'), $this->Model);
+ $expected = array('all', array(
+ 'conditions' => array('TestModel.id' => 'a'),
+ 'fields' => null, 'order' => null, 'limit' => null,
+ 'page' => null, 'recursive' => null
+ ));
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->query('findByFieldName', array(array('value1', 'value2', 'value3')), $this->Model);
+ $expected = array('first', array(
+ 'conditions' => array('TestModel.field_name' => array('value1', 'value2', 'value3')),
+ 'fields' => null, 'order' => null, 'recursive' => null
+ ));
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->query('findByFieldName', array(null), $this->Model);
+ $expected = array('first', array(
+ 'conditions' => array('TestModel.field_name' => null),
+ 'fields' => null, 'order' => null, 'recursive' => null
+ ));
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->query('findByFieldName', array('= a'), $this->Model);
+ $expected = array('first', array(
+ 'conditions' => array('TestModel.field_name' => '= a'),
+ 'fields' => null, 'order' => null, 'recursive' => null
+ ));
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->query('findByFieldName', array(), $this->Model);
+ $expected = false;
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->query('directCall', array(), $this->Model);
+ $this->assertFalse($result);
+
+ $result = $this->testDb->query('directCall', true, $this->Model);
+ $this->assertFalse($result);
+
+ $result = $this->testDb->query('directCall', false, $this->Model);
+ $this->assertFalse($result);
+ }
+
+/**
+ * testOrderParsing method
+ *
+ * @access public
+ * @return void
+ */
+ function testOrderParsing() {
+ $result = $this->testDb->order("ADDTIME(Event.time_begin, '-06:00:00') ASC");
+ $expected = " ORDER BY ADDTIME(`Event`.`time_begin`, '-06:00:00') ASC";
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->order("title, id");
+ $this->assertPattern('/^\s*ORDER BY\s+`title`\s+ASC,\s+`id`\s+ASC\s*$/', $result);
+
+ $result = $this->testDb->order("title desc, id desc");
+ $this->assertPattern('/^\s*ORDER BY\s+`title`\s+desc,\s+`id`\s+desc\s*$/', $result);
+
+ $result = $this->testDb->order(array("title desc, id desc"));
+ $this->assertPattern('/^\s*ORDER BY\s+`title`\s+desc,\s+`id`\s+desc\s*$/', $result);
+
+ $result = $this->testDb->order(array("title", "id"));
+ $this->assertPattern('/^\s*ORDER BY\s+`title`\s+ASC,\s+`id`\s+ASC\s*$/', $result);
+
+ $result = $this->testDb->order(array(array('title'), array('id')));
+ $this->assertPattern('/^\s*ORDER BY\s+`title`\s+ASC,\s+`id`\s+ASC\s*$/', $result);
+
+ $result = $this->testDb->order(array("Post.title" => 'asc', "Post.id" => 'desc'));
+ $this->assertPattern('/^\s*ORDER BY\s+`Post`.`title`\s+asc,\s+`Post`.`id`\s+desc\s*$/', $result);
+
+ $result = $this->testDb->order(array(array("Post.title" => 'asc', "Post.id" => 'desc')));
+ $this->assertPattern('/^\s*ORDER BY\s+`Post`.`title`\s+asc,\s+`Post`.`id`\s+desc\s*$/', $result);
+
+ $result = $this->testDb->order(array("title"));
+ $this->assertPattern('/^\s*ORDER BY\s+`title`\s+ASC\s*$/', $result);
+
+ $result = $this->testDb->order(array(array("title")));
+ $this->assertPattern('/^\s*ORDER BY\s+`title`\s+ASC\s*$/', $result);
+
+ $result = $this->testDb->order("Dealer.id = 7 desc, Dealer.id = 3 desc, Dealer.title asc");
+ $expected = " ORDER BY `Dealer`.`id` = 7 desc, `Dealer`.`id` = 3 desc, `Dealer`.`title` asc";
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->order(array("Page.name" => "='test' DESC"));
+ $this->assertPattern("/^\s*ORDER BY\s+`Page`\.`name`\s*='test'\s+DESC\s*$/", $result);
+
+ $result = $this->testDb->order("Page.name = 'view' DESC");
+ $this->assertPattern("/^\s*ORDER BY\s+`Page`\.`name`\s*=\s*'view'\s+DESC\s*$/", $result);
+
+ $result = $this->testDb->order("(Post.views)");
+ $this->assertPattern("/^\s*ORDER BY\s+\(`Post`\.`views`\)\s+ASC\s*$/", $result);
+
+ $result = $this->testDb->order("(Post.views)*Post.views");
+ $this->assertPattern("/^\s*ORDER BY\s+\(`Post`\.`views`\)\*`Post`\.`views`\s+ASC\s*$/", $result);
+
+ $result = $this->testDb->order("(Post.views) * Post.views");
+ $this->assertPattern("/^\s*ORDER BY\s+\(`Post`\.`views`\) \* `Post`\.`views`\s+ASC\s*$/", $result);
+
+ $result = $this->testDb->order("(Model.field1 + Model.field2) * Model.field3");
+ $this->assertPattern("/^\s*ORDER BY\s+\(`Model`\.`field1` \+ `Model`\.`field2`\) \* `Model`\.`field3`\s+ASC\s*$/", $result);
+
+ $result = $this->testDb->order("Model.name+0 ASC");
+ $this->assertPattern("/^\s*ORDER BY\s+`Model`\.`name`\+0\s+ASC\s*$/", $result);
+
+ $result = $this->testDb->order("Anuncio.destaque & 2 DESC");
+ $expected = ' ORDER BY `Anuncio`.`destaque` & 2 DESC';
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->order("3963.191 * id");
+ $expected = ' ORDER BY 3963.191 * id ASC';
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->order(array('Property.sale_price IS NULL'));
+ $expected = ' ORDER BY `Property`.`sale_price` IS NULL ASC';
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->order(array('Export.column-name' => 'ASC'));
+ $expected = ' ORDER BY `Export`.`column-name` ASC';
+ $this->assertEqual($result, $expected, 'Columns with -s are not working with order()');
+ }
+
+/**
+ * testComplexSortExpression method
+ *
+ * @return void
+ * @access public
+ */
+ function testComplexSortExpression() {
+ $result = $this->testDb->order(array('(Model.field > 100) DESC', 'Model.field ASC'));
+ $this->assertPattern("/^\s*ORDER BY\s+\(`Model`\.`field`\s+>\s+100\)\s+DESC,\s+`Model`\.`field`\s+ASC\s*$/", $result);
+ }
+
+/**
+ * testCalculations method
+ *
+ * @access public
+ * @return void
+ */
+ function testCalculations() {
+ $result = $this->testDb->calculate($this->Model, 'count');
+ $this->assertEqual($result, 'COUNT(*) AS `count`');
+
+ $result = $this->testDb->calculate($this->Model, 'count', array('id'));
+ $this->assertEqual($result, 'COUNT(`id`) AS `count`');
+
+ $result = $this->testDb->calculate(
+ $this->Model,
+ 'count',
+ array($this->testDb->expression('DISTINCT id'))
+ );
+ $this->assertEqual($result, 'COUNT(DISTINCT id) AS `count`');
+
+ $result = $this->testDb->calculate($this->Model, 'count', array('id', 'id_count'));
+ $this->assertEqual($result, 'COUNT(`id`) AS `id_count`');
+
+ $result = $this->testDb->calculate($this->Model, 'count', array('Model.id', 'id_count'));
+ $this->assertEqual($result, 'COUNT(`Model`.`id`) AS `id_count`');
+
+ $result = $this->testDb->calculate($this->Model, 'max', array('id'));
+ $this->assertEqual($result, 'MAX(`id`) AS `id`');
+
+ $result = $this->testDb->calculate($this->Model, 'max', array('Model.id', 'id'));
+ $this->assertEqual($result, 'MAX(`Model`.`id`) AS `id`');
+
+ $result = $this->testDb->calculate($this->Model, 'max', array('`Model`.`id`', 'id'));
+ $this->assertEqual($result, 'MAX(`Model`.`id`) AS `id`');
+
+ $result = $this->testDb->calculate($this->Model, 'min', array('`Model`.`id`', 'id'));
+ $this->assertEqual($result, 'MIN(`Model`.`id`) AS `id`');
+
+ $result = $this->testDb->calculate($this->Model, 'min', 'left');
+ $this->assertEqual($result, 'MIN(`left`) AS `left`');
+ }
+
+/**
+ * testLength method
+ *
+ * @access public
+ * @return void
+ */
+ function testLength() {
+ $result = $this->testDb->length('varchar(255)');
+ $expected = 255;
+ $this->assertIdentical($result, $expected);
+
+ $result = $this->testDb->length('int(11)');
+ $expected = 11;
+ $this->assertIdentical($result, $expected);
+
+ $result = $this->testDb->length('float(5,3)');
+ $expected = '5,3';
+ $this->assertIdentical($result, $expected);
+
+ $result = $this->testDb->length('decimal(5,2)');
+ $expected = '5,2';
+ $this->assertIdentical($result, $expected);
+
+ $result = $this->testDb->length("enum('test','me','now')");
+ $expected = 4;
+ $this->assertIdentical($result, $expected);
+
+ $result = $this->testDb->length("set('a','b','cd')");
+ $expected = 2;
+ $this->assertIdentical($result, $expected);
+
+ $this->expectError();
+ $result = $this->testDb->length(false);
+ $this->assertTrue($result === null);
+
+ $result = $this->testDb->length('datetime');
+ $expected = null;
+ $this->assertIdentical($result, $expected);
+
+ $result = $this->testDb->length('text');
+ $expected = null;
+ $this->assertIdentical($result, $expected);
+ }
+
+/**
+ * testBuildIndex method
+ *
+ * @access public
+ * @return void
+ */
+ function testBuildIndex() {
+ $data = array(
+ 'PRIMARY' => array('column' => 'id')
+ );
+ $result = $this->testDb->buildIndex($data);
+ $expected = array('PRIMARY KEY (`id`)');
+ $this->assertIdentical($result, $expected);
+
+ $data = array(
+ 'MyIndex' => array('column' => 'id', 'unique' => true)
+ );
+ $result = $this->testDb->buildIndex($data);
+ $expected = array('UNIQUE KEY `MyIndex` (`id`)');
+ $this->assertEqual($result, $expected);
+
+ $data = array(
+ 'MyIndex' => array('column' => array('id', 'name'), 'unique' => true)
+ );
+ $result = $this->testDb->buildIndex($data);
+ $expected = array('UNIQUE KEY `MyIndex` (`id`, `name`)');
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testBuildColumn method
+ *
+ * @access public
+ * @return void
+ */
+ function testBuildColumn() {
+ $this->expectError();
+ $data = array(
+ 'name' => 'testName',
+ 'type' => 'varchar(255)',
+ 'default',
+ 'null' => true,
+ 'key'
+ );
+ $this->testDb->buildColumn($data);
+
+ $data = array(
+ 'name' => 'testName',
+ 'type' => 'string',
+ 'length' => 255,
+ 'default',
+ 'null' => true,
+ 'key'
+ );
+ $result = $this->testDb->buildColumn($data);
+ $expected = '`testName` varchar(255) DEFAULT NULL';
+ $this->assertEqual($result, $expected);
+
+ $data = array(
+ 'name' => 'int_field',
+ 'type' => 'integer',
+ 'default' => '',
+ 'null' => false,
+ );
+ $restore = $this->testDb->columns;
+
+ $this->testDb->columns = array('integer' => array('name' => 'int', 'limit' => '11', 'formatter' => 'intval'), );
+ $result = $this->testDb->buildColumn($data);
+ $expected = '`int_field` int(11) NOT NULL';
+ $this->assertEqual($result, $expected);
+
+ $this->testDb->fieldParameters['param'] = array(
+ 'value' => 'COLLATE',
+ 'quote' => false,
+ 'join' => ' ',
+ 'column' => 'Collate',
+ 'position' => 'beforeDefault',
+ 'options' => array('GOOD', 'OK')
+ );
+ $data = array(
+ 'name' => 'int_field',
+ 'type' => 'integer',
+ 'default' => '',
+ 'null' => false,
+ 'param' => 'BAD'
+ );
+ $result = $this->testDb->buildColumn($data);
+ $expected = '`int_field` int(11) NOT NULL';
+ $this->assertEqual($result, $expected);
+
+ $data = array(
+ 'name' => 'int_field',
+ 'type' => 'integer',
+ 'default' => '',
+ 'null' => false,
+ 'param' => 'GOOD'
+ );
+ $result = $this->testDb->buildColumn($data);
+ $expected = '`int_field` int(11) COLLATE GOOD NOT NULL';
+ $this->assertEqual($result, $expected);
+
+ $this->testDb->columns = $restore;
+
+ $data = array(
+ 'name' => 'created',
+ 'type' => 'timestamp',
+ 'default' => 'current_timestamp',
+ 'null' => false,
+ );
+ $result = $this->db->buildColumn($data);
+ $expected = '`created` timestamp DEFAULT CURRENT_TIMESTAMP NOT NULL';
+ $this->assertEqual($result, $expected);
+
+ $data = array(
+ 'name' => 'created',
+ 'type' => 'timestamp',
+ 'default' => 'CURRENT_TIMESTAMP',
+ 'null' => true,
+ );
+ $result = $this->db->buildColumn($data);
+ $expected = '`created` timestamp DEFAULT CURRENT_TIMESTAMP';
+ $this->assertEqual($result, $expected);
+
+ $data = array(
+ 'name' => 'modified',
+ 'type' => 'timestamp',
+ 'null' => true,
+ );
+ $result = $this->db->buildColumn($data);
+ $expected = '`modified` timestamp NULL';
+ $this->assertEqual($result, $expected);
+
+ $data = array(
+ 'name' => 'modified',
+ 'type' => 'timestamp',
+ 'default' => null,
+ 'null' => true,
+ );
+ $result = $this->db->buildColumn($data);
+ $expected = '`modified` timestamp NULL';
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * test hasAny()
+ *
+ * @return void
+ */
+ function testHasAny() {
+ $this->testDb->hasAny($this->Model, array());
+ $expected = 'SELECT COUNT(`TestModel`.`id`) AS count FROM `test_models` AS `TestModel` WHERE 1 = 1';
+ $this->assertEqual(end($this->testDb->simulated), $expected);
+
+ $this->testDb->hasAny($this->Model, array('TestModel.name' => 'harry'));
+ $expected = "SELECT COUNT(`TestModel`.`id`) AS count FROM `test_models` AS `TestModel` WHERE `TestModel`.`name` = 'harry'";
+ $this->assertEqual(end($this->testDb->simulated), $expected);
+ }
+
+/**
+ * testIntrospectType method
+ *
+ * @access public
+ * @return void
+ */
+ function testIntrospectType() {
+ $this->assertEqual($this->testDb->introspectType(0), 'integer');
+ $this->assertEqual($this->testDb->introspectType(2), 'integer');
+ $this->assertEqual($this->testDb->introspectType('2'), 'string');
+ $this->assertEqual($this->testDb->introspectType('2.2'), 'string');
+ $this->assertEqual($this->testDb->introspectType(2.2), 'float');
+ $this->assertEqual($this->testDb->introspectType('stringme'), 'string');
+ $this->assertEqual($this->testDb->introspectType('0stringme'), 'string');
+
+ $data = array(2.2);
+ $this->assertEqual($this->testDb->introspectType($data), 'float');
+
+ $data = array('2.2');
+ $this->assertEqual($this->testDb->introspectType($data), 'float');
+
+ $data = array(2);
+ $this->assertEqual($this->testDb->introspectType($data), 'integer');
+
+ $data = array('2');
+ $this->assertEqual($this->testDb->introspectType($data), 'integer');
+
+ $data = array('string');
+ $this->assertEqual($this->testDb->introspectType($data), 'string');
+
+ $data = array(2.2, '2.2');
+ $this->assertEqual($this->testDb->introspectType($data), 'float');
+
+ $data = array(2, '2');
+ $this->assertEqual($this->testDb->introspectType($data), 'integer');
+
+ $data = array('string one', 'string two');
+ $this->assertEqual($this->testDb->introspectType($data), 'string');
+
+ $data = array('2.2', 3);
+ $this->assertEqual($this->testDb->introspectType($data), 'integer');
+
+ $data = array('2.2', '0stringme');
+ $this->assertEqual($this->testDb->introspectType($data), 'string');
+
+ $data = array(2.2, 3);
+ $this->assertEqual($this->testDb->introspectType($data), 'integer');
+
+ $data = array(2.2, '0stringme');
+ $this->assertEqual($this->testDb->introspectType($data), 'string');
+
+ $data = array(2, 'stringme');
+ $this->assertEqual($this->testDb->introspectType($data), 'string');
+
+ $data = array(2, '2.2', 'stringgme');
+ $this->assertEqual($this->testDb->introspectType($data), 'string');
+
+ $data = array(2, '2.2');
+ $this->assertEqual($this->testDb->introspectType($data), 'integer');
+
+ $data = array(2, 2.2);
+ $this->assertEqual($this->testDb->introspectType($data), 'integer');
+
+
+ // NULL
+ $result = $this->testDb->value(null, 'boolean');
+ $this->assertEqual($result, 'NULL');
+
+ // EMPTY STRING
+ $result = $this->testDb->value('', 'boolean');
+ $this->assertEqual($result, "NULL");
+
+
+ // BOOLEAN
+ $result = $this->testDb->value('true', 'boolean');
+ $this->assertEqual($result, 1);
+
+ $result = $this->testDb->value('false', 'boolean');
+ $this->assertEqual($result, 1);
+
+ $result = $this->testDb->value(true, 'boolean');
+ $this->assertEqual($result, 1);
+
+ $result = $this->testDb->value(false, 'boolean');
+ $this->assertEqual($result, 0);
+
+ $result = $this->testDb->value(1, 'boolean');
+ $this->assertEqual($result, 1);
+
+ $result = $this->testDb->value(0, 'boolean');
+ $this->assertEqual($result, 0);
+
+ $result = $this->testDb->value('abc', 'boolean');
+ $this->assertEqual($result, 1);
+
+ $result = $this->testDb->value(1.234, 'boolean');
+ $this->assertEqual($result, 1);
+
+ $result = $this->testDb->value('1.234e05', 'boolean');
+ $this->assertEqual($result, 1);
+
+ // NUMBERS
+ $result = $this->testDb->value(123, 'integer');
+ $this->assertEqual($result, 123);
+
+ $result = $this->testDb->value('123', 'integer');
+ $this->assertEqual($result, '123');
+
+ $result = $this->testDb->value('0123', 'integer');
+ $this->assertEqual($result, "'0123'");
+
+ $result = $this->testDb->value('0x123ABC', 'integer');
+ $this->assertEqual($result, "'0x123ABC'");
+
+ $result = $this->testDb->value('0x123', 'integer');
+ $this->assertEqual($result, "'0x123'");
+
+ $result = $this->testDb->value(1.234, 'float');
+ $this->assertEqual($result, 1.234);
+
+ $result = $this->testDb->value('1.234', 'float');
+ $this->assertEqual($result, '1.234');
+
+ $result = $this->testDb->value(' 1.234 ', 'float');
+ $this->assertEqual($result, "' 1.234 '");
+
+ $result = $this->testDb->value('1.234e05', 'float');
+ $this->assertEqual($result, "'1.234e05'");
+
+ $result = $this->testDb->value('1.234e+5', 'float');
+ $this->assertEqual($result, "'1.234e+5'");
+
+ $result = $this->testDb->value('1,234', 'float');
+ $this->assertEqual($result, "'1,234'");
+
+ $result = $this->testDb->value('FFF', 'integer');
+ $this->assertEqual($result, "'FFF'");
+
+ $result = $this->testDb->value('abc', 'integer');
+ $this->assertEqual($result, "'abc'");
+
+ // STRINGS
+ $result = $this->testDb->value('123', 'string');
+ $this->assertEqual($result, "'123'");
+
+ $result = $this->testDb->value(123, 'string');
+ $this->assertEqual($result, "'123'");
+
+ $result = $this->testDb->value(1.234, 'string');
+ $this->assertEqual($result, "'1.234'");
+
+ $result = $this->testDb->value('abc', 'string');
+ $this->assertEqual($result, "'abc'");
+
+ $result = $this->testDb->value(' abc ', 'string');
+ $this->assertEqual($result, "' abc '");
+
+ $result = $this->testDb->value('a bc', 'string');
+ $this->assertEqual($result, "'a bc'");
+ }
+
+/**
+ * testValue method
+ *
+ * @access public
+ * @return void
+ */
+ function testValue() {
+ $result = $this->testDb->value('{$__cakeForeignKey__$}');
+ $this->assertEqual($result, '{$__cakeForeignKey__$}');
+
+ $result = $this->testDb->value(array('first', 2, 'third'));
+ $expected = array('\'first\'', 2, '\'third\'');
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testReconnect method
+ *
+ * @access public
+ * @return void
+ */
+ function testReconnect() {
+ $this->testDb->reconnect(array('prefix' => 'foo'));
+ $this->assertTrue($this->testDb->connected);
+ $this->assertEqual($this->testDb->config['prefix'], 'foo');
+ }
+
+/**
+ * testRealQueries method
+ *
+ * @access public
+ * @return void
+ */
+ function testRealQueries() {
+ $this->loadFixtures('Apple', 'Article', 'User', 'Comment', 'Tag');
+
+ $Apple =& ClassRegistry::init('Apple');
+ $Article =& ClassRegistry::init('Article');
+
+ $result = $this->db->rawQuery('SELECT color, name FROM ' . $this->db->fullTableName('apples'));
+ $this->assertTrue(!empty($result));
+
+ $result = $this->db->fetchRow($result);
+ $expected = array($this->db->fullTableName('apples', false) => array(
+ 'color' => 'Red 1',
+ 'name' => 'Red Apple 1'
+ ));
+ $this->assertEqual($result, $expected);
+
+ $result = $this->db->fetchAll('SELECT name FROM ' . $this->testDb->fullTableName('apples') . ' ORDER BY id');
+ $expected = array(
+ array($this->db->fullTableName('apples', false) => array('name' => 'Red Apple 1')),
+ array($this->db->fullTableName('apples', false) => array('name' => 'Bright Red Apple')),
+ array($this->db->fullTableName('apples', false) => array('name' => 'green blue')),
+ array($this->db->fullTableName('apples', false) => array('name' => 'Test Name')),
+ array($this->db->fullTableName('apples', false) => array('name' => 'Blue Green')),
+ array($this->db->fullTableName('apples', false) => array('name' => 'My new apple')),
+ array($this->db->fullTableName('apples', false) => array('name' => 'Some odd color'))
+ );
+ $this->assertEqual($result, $expected);
+
+ $result = $this->db->field($this->testDb->fullTableName('apples', false), 'SELECT color, name FROM ' . $this->testDb->fullTableName('apples') . ' ORDER BY id');
+ $expected = array(
+ 'color' => 'Red 1',
+ 'name' => 'Red Apple 1'
+ );
+ $this->assertEqual($result, $expected);
+
+ $Apple->unbindModel(array(), false);
+ $result = $this->db->read($Apple, array(
+ 'fields' => array($Apple->escapeField('name')),
+ 'conditions' => null,
+ 'recursive' => -1
+ ));
+ $expected = array(
+ array('Apple' => array('name' => 'Red Apple 1')),
+ array('Apple' => array('name' => 'Bright Red Apple')),
+ array('Apple' => array('name' => 'green blue')),
+ array('Apple' => array('name' => 'Test Name')),
+ array('Apple' => array('name' => 'Blue Green')),
+ array('Apple' => array('name' => 'My new apple')),
+ array('Apple' => array('name' => 'Some odd color'))
+ );
+ $this->assertEqual($result, $expected);
+
+ $result = $this->db->read($Article, array(
+ 'fields' => array('id', 'user_id', 'title'),
+ 'conditions' => null,
+ 'recursive' => 1
+ ));
+
+ $this->assertTrue(Set::matches('/Article[id=1]', $result));
+ $this->assertTrue(Set::matches('/Comment[id=1]', $result));
+ $this->assertTrue(Set::matches('/Comment[id=2]', $result));
+ $this->assertFalse(Set::matches('/Comment[id=10]', $result));
+ }
+
+/**
+ * testName method
+ *
+ * @access public
+ * @return void
+ */
+ function testName() {
+ $result = $this->testDb->name('name');
+ $expected = '`name`';
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->name(array('name', 'Model.*'));
+ $expected = array('`name`', '`Model`.*');
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->name('MTD()');
+ $expected = 'MTD()';
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->name('(sm)');
+ $expected = '(sm)';
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->name('name AS x');
+ $expected = '`name` AS `x`';
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->name('Model.name AS x');
+ $expected = '`Model`.`name` AS `x`';
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->name('Function(Something.foo)');
+ $expected = 'Function(`Something`.`foo`)';
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->name('Function(SubFunction(Something.foo))');
+ $expected = 'Function(SubFunction(`Something`.`foo`))';
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->name('Function(Something.foo) AS x');
+ $expected = 'Function(`Something`.`foo`) AS `x`';
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->name('name-with-minus');
+ $expected = '`name-with-minus`';
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->name(array('my-name', 'Foo-Model.*'));
+ $expected = array('`my-name`', '`Foo-Model`.*');
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->name(array('Team.P%', 'Team.G/G'));
+ $expected = array('`Team`.`P%`', '`Team`.`G/G`');
+ $this->assertEqual($result, $expected);
+
+ $result = $this->testDb->name('Model.name as y');
+ $expected = '`Model`.`name` AS `y`';
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * test that cacheMethod works as exepected
+ *
+ * @return void
+ */
+ function testCacheMethod() {
+ $this->testDb->cacheMethods = true;
+ $result = $this->testDb->cacheMethod('name', 'some-key', 'stuff');
+ $this->assertEqual($result, 'stuff');
+
+ $result = $this->testDb->cacheMethod('name', 'some-key');
+ $this->assertEqual($result, 'stuff');
+
+ $result = $this->testDb->cacheMethod('conditions', 'some-key');
+ $this->assertNull($result);
+
+ $result = $this->testDb->cacheMethod('name', 'other-key');
+ $this->assertNull($result);
+
+ $this->testDb->cacheMethods = false;
+ $result = $this->testDb->cacheMethod('name', 'some-key', 'stuff');
+ $this->assertEqual($result, 'stuff');
+
+ $result = $this->testDb->cacheMethod('name', 'some-key');
+ $this->assertNull($result);
+ }
+
+/**
+ * testLog method
+ *
+ * @access public
+ * @return void
+ */
+ function testLog() {
+ $this->testDb->logQuery('Query 1');
+ $this->testDb->logQuery('Query 2');
+
+ $log = $this->testDb->getLog(false, false);
+ $result = Set::extract($log['log'], '/query');
+ $expected = array('Query 1', 'Query 2');
+ $this->assertEqual($result, $expected);
+
+ $oldError = $this->testDb->error;
+ $this->testDb->error = true;
+ $result = $this->testDb->logQuery('Error 1');
+ $this->assertFalse($result);
+ $this->testDb->error = $oldError;
+
+ $log = $this->testDb->getLog(false, false);
+ $result = Set::combine($log['log'], '/query', '/error');
+ $expected = array('Query 1' => false, 'Query 2' => false, 'Error 1' => true);
+ $this->assertEqual($result, $expected);
+
+ Configure::write('debug', 2);
+ ob_start();
+ $this->testDb->showLog();
+ $contents = ob_get_clean();
+
+ $this->assertPattern('/Query 1/s', $contents);
+ $this->assertPattern('/Query 2/s', $contents);
+ $this->assertPattern('/Error 1/s', $contents);
+
+ ob_start();
+ $this->testDb->showLog(true);
+ $contents = ob_get_clean();
+
+ $this->assertPattern('/Query 1/s', $contents);
+ $this->assertPattern('/Query 2/s', $contents);
+ $this->assertPattern('/Error 1/s', $contents);
+
+ $oldError = $this->testDb->error;
+ $oldDebug = Configure::read('debug');
+ Configure::write('debug', 2);
+
+ $this->testDb->error = true;
+ $this->expectError();
+ ob_start();
+ $this->testDb->showQuery('Error 2');
+ $contents = ob_get_clean();
+
+ $this->assertPattern('/Error 2/s', $contents);
+
+ $this->testDb->error = $oldError;
+ Configure::write('debug', $oldDebug);
+ }
+
+/**
+ * test getting the query log as an array.
+ *
+ * @return void
+ */
+ function testGetLog() {
+ $this->testDb->logQuery('Query 1');
+ $this->testDb->logQuery('Query 2');
+
+ $oldError = $this->testDb->error;
+ $this->testDb->error = true;
+ $result = $this->testDb->logQuery('Error 1');
+ $this->assertFalse($result);
+ $this->testDb->error = $oldError;
+
+ $log = $this->testDb->getLog();
+ $expected = array('query' => 'Query 1', 'error' => '', 'affected' => '', 'numRows' => '', 'took' => '');
+ $this->assertEqual($log['log'][0], $expected);
+ $expected = array('query' => 'Query 2', 'error' => '', 'affected' => '', 'numRows' => '', 'took' => '');
+ $this->assertEqual($log['log'][1], $expected);
+ $expected = array('query' => 'Error 1', 'error' => true, 'affected' => '', 'numRows' => '', 'took' => '');
+ $this->assertEqual($log['log'][2], $expected);
+ }
+
+/**
+ * test that execute runs queries.
+ *
+ * @return void
+ */
+ function testExecute() {
+ $query = 'SELECT * FROM ' . $this->testDb->fullTableName('articles') . ' WHERE 1 = 1';
+
+ $this->db->_result = null;
+ $this->db->took = null;
+ $this->db->affected = null;
+ $result = $this->db->execute($query, array('stats' => false));
+ $this->assertNotNull($result, 'No query performed! %s');
+ $this->assertNull($this->db->took, 'Stats were set %s');
+ $this->assertNull($this->db->affected, 'Stats were set %s');
+
+ $result = $this->db->execute($query);
+ $this->assertNotNull($result, 'No query performed! %s');
+ $this->assertNotNull($this->db->took, 'Stats were not set %s');
+ $this->assertNotNull($this->db->affected, 'Stats were not set %s');
+ }
+
+/**
+ * test that query() returns boolean values from operations like CREATE TABLE
+ *
+ * @return void
+ */
+ function testFetchAllBooleanReturns() {
+ $name = $this->db->fullTableName('test_query');
+ $query = "CREATE TABLE {$name} (name varchar(10));";
+ $result = $this->db->query($query);
+ $this->assertTrue($result, 'Query did not return a boolean. %s');
+
+ $query = "DROP TABLE {$name};";
+ $result = $this->db->fetchAll($query);
+ $this->assertTrue($result, 'Query did not return a boolean. %s');
+ }
+
+/**
+ * test ShowQuery generation of regular and error messages
+ *
+ * @return void
+ */
+ function testShowQuery() {
+ $this->testDb->error = false;
+ ob_start();
+ $this->testDb->showQuery('Some Query');
+ $contents = ob_get_clean();
+ $this->assertPattern('/Some Query/s', $contents);
+ $this->assertPattern('/Aff:/s', $contents);
+ $this->assertPattern('/Num:/s', $contents);
+ $this->assertPattern('/Took:/s', $contents);
+
+ $this->expectError();
+ $this->testDb->error = true;
+ ob_start();
+ $this->testDb->showQuery('Another Query');
+ $contents = ob_get_clean();
+ $this->assertPattern('/Another Query/s', $contents);
+ $this->assertNoPattern('/Aff:/s', $contents);
+ $this->assertNoPattern('/Num:/s', $contents);
+ $this->assertNoPattern('/Took:/s', $contents);
+ }
+
+/**
+ * test fields generating usable virtual fields to use in query
+ *
+ * @return void
+ */
+ function testVirtualFields() {
+ $this->loadFixtures('Article');
+
+ $Article =& ClassRegistry::init('Article');
+ $Article->virtualFields = array(
+ 'this_moment' => 'NOW()',
+ 'two' => '1 + 1',
+ 'comment_count' => 'SELECT COUNT(*) FROM ' . $this->db->fullTableName('comments') .
+ ' WHERE Article.id = ' . $this->db->fullTableName('comments') . '.article_id'
+ );
+ $result = $this->db->fields($Article);
+ $expected = array(
+ '`Article`.`id`',
+ '`Article`.`user_id`',
+ '`Article`.`title`',
+ '`Article`.`body`',
+ '`Article`.`published`',
+ '`Article`.`created`',
+ '`Article`.`updated`',
+ '(NOW()) AS `Article__this_moment`',
+ '(1 + 1) AS `Article__two`',
+ '(SELECT COUNT(*) FROM comments WHERE `Article`.`id` = `comments`.`article_id`) AS `Article__comment_count`'
+ );
+ $this->assertEqual($expected, $result);
+
+ $result = $this->db->fields($Article, null, array('this_moment', 'title'));
+ $expected = array(
+ '`Article`.`title`',
+ '(NOW()) AS `Article__this_moment`',
+ );
+ $this->assertEqual($expected, $result);
+
+ $result = $this->db->fields($Article, null, array('Article.title', 'Article.this_moment'));
+ $expected = array(
+ '`Article`.`title`',
+ '(NOW()) AS `Article__this_moment`',
+ );
+ $this->assertEqual($expected, $result);
+
+ $result = $this->db->fields($Article, null, array('Article.this_moment', 'Article.title'));
+ $expected = array(
+ '`Article`.`title`',
+ '(NOW()) AS `Article__this_moment`',
+ );
+ $this->assertEqual($expected, $result);
+
+ $result = $this->db->fields($Article, null, array('Article.*'));
+ $expected = array(
+ '`Article`.*',
+ '(NOW()) AS `Article__this_moment`',
+ '(1 + 1) AS `Article__two`',
+ '(SELECT COUNT(*) FROM comments WHERE `Article`.`id` = `comments`.`article_id`) AS `Article__comment_count`'
+ );
+ $this->assertEqual($expected, $result);
+
+ $result = $this->db->fields($Article, null, array('*'));
+ $expected = array(
+ '*',
+ '(NOW()) AS `Article__this_moment`',
+ '(1 + 1) AS `Article__two`',
+ '(SELECT COUNT(*) FROM comments WHERE `Article`.`id` = `comments`.`article_id`) AS `Article__comment_count`'
+ );
+ $this->assertEqual($expected, $result);
+ }
+
+/**
+ * test conditions to generate query conditions for virtual fields
+ *
+ * @return void
+ */
+ function testVirtualFieldsInConditions() {
+ $Article =& ClassRegistry::init('Article');
+ $Article->virtualFields = array(
+ 'this_moment' => 'NOW()',
+ 'two' => '1 + 1',
+ 'comment_count' => 'SELECT COUNT(*) FROM ' . $this->db->fullTableName('comments') .
+ ' WHERE Article.id = ' . $this->db->fullTableName('comments') . '.article_id'
+ );
+ $conditions = array('two' => 2);
+ $result = $this->db->conditions($conditions, true, false, $Article);
+ $expected = '(1 + 1) = 2';
+ $this->assertEqual($expected, $result);
+
+ $conditions = array('this_moment BETWEEN ? AND ?' => array(1,2));
+ $expected = 'NOW() BETWEEN 1 AND 2';
+ $result = $this->db->conditions($conditions, true, false, $Article);
+ $this->assertEqual($expected, $result);
+
+ $conditions = array('comment_count >' => 5);
+ $expected = '(SELECT COUNT(*) FROM comments WHERE `Article`.`id` = `comments`.`article_id`) > 5';
+ $result = $this->db->conditions($conditions, true, false, $Article);
+ $this->assertEqual($expected, $result);
+
+ $conditions = array('NOT' => array('two' => 2));
+ $result = $this->db->conditions($conditions, true, false, $Article);
+ $expected = 'NOT ((1 + 1) = 2)';
+ $this->assertEqual($expected, $result);
+ }
+
+/**
+ * test that virtualFields with complex functions and aliases work.
+ *
+ * @return void
+ */
+ function testConditionsWithComplexVirtualFields() {
+ $Article =& ClassRegistry::init('Article');
+ $Article->virtualFields = array(
+ 'distance' => 'ACOS(SIN(20 * PI() / 180)
+ * SIN(Article.latitude * PI() / 180)
+ + COS(20 * PI() / 180)
+ * COS(Article.latitude * PI() / 180)
+ * COS((50 - Article.longitude) * PI() / 180)
+ ) * 180 / PI() * 60 * 1.1515 * 1.609344'
+ );
+ $conditions = array('distance >=' => 20);
+ $result = $this->db->conditions($conditions, true, true, $Article);
+
+ $this->assertPattern('/\) >= 20/', $result);
+ $this->assertPattern('/[`\'"]Article[`\'"].[`\'"]latitude[`\'"]/', $result);
+ $this->assertPattern('/[`\'"]Article[`\'"].[`\'"]longitude[`\'"]/', $result);
+ }
+
+/**
+ * test order to generate query order clause for virtual fields
+ *
+ * @return void
+ */
+ function testVirtualFieldsInOrder() {
+ $Article =& ClassRegistry::init('Article');
+ $Article->virtualFields = array(
+ 'this_moment' => 'NOW()',
+ 'two' => '1 + 1',
+ );
+ $order = array('two', 'this_moment');
+ $result = $this->db->order($order, 'ASC', $Article);
+ $expected = ' ORDER BY (1 + 1) ASC, (NOW()) ASC';
+ $this->assertEqual($expected, $result);
+
+ $order = array('Article.two', 'Article.this_moment');
+ $result = $this->db->order($order, 'ASC', $Article);
+ $expected = ' ORDER BY (1 + 1) ASC, (NOW()) ASC';
+ $this->assertEqual($expected, $result);
+ }
+
+/**
+ * test calculate to generate claculate statements on virtual fields
+ *
+ * @return void
+ */
+ function testVirtualFieldsInCalculate() {
+ $Article =& ClassRegistry::init('Article');
+ $Article->virtualFields = array(
+ 'this_moment' => 'NOW()',
+ 'two' => '1 + 1',
+ 'comment_count' => 'SELECT COUNT(*) FROM ' . $this->db->fullTableName('comments') .
+ ' WHERE Article.id = ' . $this->db->fullTableName('comments'). '.article_id'
+ );
+
+ $result = $this->db->calculate($Article, 'count', array('this_moment'));
+ $expected = 'COUNT(NOW()) AS `count`';
+ $this->assertEqual($expected, $result);
+
+ $result = $this->db->calculate($Article, 'max', array('comment_count'));
+ $expected = 'MAX(SELECT COUNT(*) FROM comments WHERE `Article`.`id` = `comments`.`article_id`) AS `comment_count`';
+ $this->assertEqual($expected, $result);
+ }
+
+/**
+ * test a full example of using virtual fields
+ *
+ * @return void
+ */
+ function testVirtualFieldsFetch() {
+ $this->loadFixtures('Article', 'Comment');
+
+ $Article =& ClassRegistry::init('Article');
+ $Article->virtualFields = array(
+ 'comment_count' => 'SELECT COUNT(*) FROM ' . $this->db->fullTableName('comments') .
+ ' WHERE Article.id = ' . $this->db->fullTableName('comments') . '.article_id'
+ );
+
+ $conditions = array('comment_count >' => 2);
+ $query = 'SELECT ' . join(',',$this->db->fields($Article, null, array('id', 'comment_count'))) .
+ ' FROM ' . $this->db->fullTableName($Article) . ' Article ' . $this->db->conditions($conditions, true, true, $Article);
+ $result = $this->db->fetchAll($query);
+ $expected = array(array(
+ 'Article' => array('id' => 1, 'comment_count' => 4)
+ ));
+ $this->assertEqual($expected, $result);
+ }
+
+/**
+ * test reading complex virtualFields with subqueries.
+ *
+ * @return void
+ */
+ function testVirtualFieldsComplexRead() {
+ $this->loadFixtures('DataTest', 'Article', 'Comment');
+
+ $Article =& ClassRegistry::init('Article');
+ $commentTable = $this->db->fullTableName('comments');
+ $Article =& ClassRegistry::init('Article');
+ $Article->virtualFields = array(
+ 'comment_count' => 'SELECT COUNT(*) FROM ' . $commentTable .
+ ' AS Comment WHERE Article.id = Comment.article_id'
+ );
+ $result = $Article->find('all');
+ $this->assertTrue(count($result) > 0);
+ $this->assertTrue($result[0]['Article']['comment_count'] > 0);
+
+ $DataTest =& ClassRegistry::init('DataTest');
+ $DataTest->virtualFields = array(
+ 'complicated' => 'ACOS(SIN(20 * PI() / 180)
+ * SIN(DataTest.float * PI() / 180)
+ + COS(20 * PI() / 180)
+ * COS(DataTest.count * PI() / 180)
+ * COS((50 - DataTest.float) * PI() / 180)
+ ) * 180 / PI() * 60 * 1.1515 * 1.609344'
+ );
+ $result = $DataTest->find('all');
+ $this->assertTrue(count($result) > 0);
+ $this->assertTrue($result[0]['DataTest']['complicated'] > 0);
+ }
+
+/**
+ * test that virtualFields with complex functions and aliases work.
+ *
+ * @return void
+ */
+ function testFieldsWithComplexVirtualFields() {
+ $Article =& new Article();
+ $Article->virtualFields = array(
+ 'distance' => 'ACOS(SIN(20 * PI() / 180)
+ * SIN(Article.latitude * PI() / 180)
+ + COS(20 * PI() / 180)
+ * COS(Article.latitude * PI() / 180)
+ * COS((50 - Article.longitude) * PI() / 180)
+ ) * 180 / PI() * 60 * 1.1515 * 1.609344'
+ );
+
+ $fields = array('id', 'distance');
+ $result = $this->db->fields($Article, null, $fields);
+ $qs = $this->db->startQuote;
+ $qe = $this->db->endQuote;
+
+ $this->assertEqual($result[0], "{$qs}Article{$qe}.{$qs}id{$qe}");
+ $this->assertPattern('/Article__distance/', $result[1]);
+ $this->assertPattern('/[`\'"]Article[`\'"].[`\'"]latitude[`\'"]/', $result[1]);
+ $this->assertPattern('/[`\'"]Article[`\'"].[`\'"]longitude[`\'"]/', $result[1]);
+ }
+
+/**
+ * test reading virtual fields containing newlines when recursive > 0
+ *
+ * @return void
+ */
+ function testReadVirtualFieldsWithNewLines() {
+ $Article =& new Article();
+ $Article->recursive = 1;
+ $Article->virtualFields = array(
+ 'test' => '
+ User.id + User.id
+ '
+ );
+ $result = $this->db->fields($Article, null, array());
+ $result = $this->db->fields($Article, $Article->alias, $result);
+ $this->assertPattern('/[`\"]User[`\"]\.[`\"]id[`\"] \+ [`\"]User[`\"]\.[`\"]id[`\"]/', $result[7]);
+ }
+
+/**
+ * test group to generate GROUP BY statements on virtual fields
+ *
+ * @return void
+ */
+ function testVirtualFieldsInGroup() {
+ $Article =& ClassRegistry::init('Article');
+ $Article->virtualFields = array(
+ 'this_year' => 'YEAR(Article.created)'
+ );
+
+ $result = $this->db->group('this_year',$Article);
+ $expected = " GROUP BY (YEAR(`Article`.`created`))";
+ $this->assertEqual($expected, $result);
+ }
+
+/**
+ * Test that group works without a model
+ *
+ * @return void
+ */
+ function testGroupNoModel() {
+ $result = $this->db->group('created');
+ $this->assertEqual(' GROUP BY created', $result);
+ }
+
+/**
+ * test the permutations of fullTableName()
+ *
+ * @return void
+ */
+ function testFullTablePermutations() {
+ $Article =& ClassRegistry::init('Article');
+ $result = $this->testDb->fullTableName($Article, false);
+ $this->assertEqual($result, 'articles');
+
+ $Article->tablePrefix = 'tbl_';
+ $result = $this->testDb->fullTableName($Article, false);
+ $this->assertEqual($result, 'tbl_articles');
+
+ $Article->useTable = $Article->table = 'with spaces';
+ $Article->tablePrefix = '';
+ $result = $this->testDb->fullTableName($Article);
+ $this->assertEqual($result, '`with spaces`');
+ }
+
+/**
+ * test that read() only calls queryAssociation on db objects when the method is defined.
+ *
+ * @return void
+ */
+ function testReadOnlyCallingQueryAssociationWhenDefined() {
+ ConnectionManager::create('test_no_queryAssociation', array(
+ 'datasource' => 'data'
+ ));
+ $Article =& ClassRegistry::init('Article');
+ $Article->Comment->useDbConfig = 'test_no_queryAssociation';
+ $result = $Article->find('all');
+ $this->assertTrue(is_array($result));
+ }
+
+/**
+ * test that fields() is using methodCache()
+ *
+ * @return void
+ */
+ function testFieldsUsingMethodCache() {
+ $this->testDb->cacheMethods = false;
+ $this->assertTrue(empty($this->testDb->methodCache['fields']), 'Cache not empty');
+
+ $Article =& ClassRegistry::init('Article');
+ $this->testDb->fields($Article, null, array('title', 'body', 'published'));
+ $this->assertTrue(empty($this->testDb->methodCache['fields']), 'Cache not empty');
+ }
+}
diff --git a/code/ryzom/tools/server/www/webtt/cake/tests/cases/libs/model/db_acl.test.php b/code/ryzom/tools/server/www/webtt/cake/tests/cases/libs/model/db_acl.test.php
new file mode 100644
index 000000000..b970d2332
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/cake/tests/cases/libs/model/db_acl.test.php
@@ -0,0 +1,397 @@
+
+ * Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
+ *
+ * Licensed under The Open Group Test Suite License
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
+ * @link http://book.cakephp.org/view/1196/Testing CakePHP(tm) Tests
+ * @package cake
+ * @subpackage cake.tests.cases.libs.controller.components.dbacl.models
+ * @since CakePHP(tm) v 1.2.0.4206
+ * @license http://www.opensource.org/licenses/opengroup.php The Open Group Test Suite License
+ */
+if (!defined('CAKEPHP_UNIT_TEST_EXECUTION')) {
+ define('CAKEPHP_UNIT_TEST_EXECUTION', 1);
+}
+App::import('Component', 'Acl');
+App::import('Core', 'db_acl');
+
+/**
+ * DB ACL wrapper test class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.controller.components
+ */
+class DbAclNodeTestBase extends AclNode {
+
+/**
+ * useDbConfig property
+ *
+ * @var string 'test_suite'
+ * @access public
+ */
+ var $useDbConfig = 'test_suite';
+
+/**
+ * cacheSources property
+ *
+ * @var bool false
+ * @access public
+ */
+ var $cacheSources = false;
+}
+
+/**
+ * Aro Test Wrapper
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.controller.components
+ */
+class DbAroTest extends DbAclNodeTestBase {
+
+/**
+ * name property
+ *
+ * @var string 'DbAroTest'
+ * @access public
+ */
+ var $name = 'DbAroTest';
+
+/**
+ * useTable property
+ *
+ * @var string 'aros'
+ * @access public
+ */
+ var $useTable = 'aros';
+
+/**
+ * hasAndBelongsToMany property
+ *
+ * @var array
+ * @access public
+ */
+ var $hasAndBelongsToMany = array('DbAcoTest' => array('with' => 'DbPermissionTest'));
+}
+
+/**
+ * Aco Test Wrapper
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.controller.components
+ */
+class DbAcoTest extends DbAclNodeTestBase {
+
+/**
+ * name property
+ *
+ * @var string 'DbAcoTest'
+ * @access public
+ */
+ var $name = 'DbAcoTest';
+
+/**
+ * useTable property
+ *
+ * @var string 'acos'
+ * @access public
+ */
+ var $useTable = 'acos';
+
+/**
+ * hasAndBelongsToMany property
+ *
+ * @var array
+ * @access public
+ */
+ var $hasAndBelongsToMany = array('DbAroTest' => array('with' => 'DbPermissionTest'));
+}
+
+/**
+ * Permission Test Wrapper
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.controller.components
+ */
+class DbPermissionTest extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'DbPermissionTest'
+ * @access public
+ */
+ var $name = 'DbPermissionTest';
+
+/**
+ * useTable property
+ *
+ * @var string 'aros_acos'
+ * @access public
+ */
+ var $useTable = 'aros_acos';
+
+/**
+ * cacheQueries property
+ *
+ * @var bool false
+ * @access public
+ */
+ var $cacheQueries = false;
+
+/**
+ * belongsTo property
+ *
+ * @var array
+ * @access public
+ */
+ var $belongsTo = array('DbAroTest' => array('foreignKey' => 'aro_id'), 'DbAcoTest' => array('foreignKey' => 'aco_id'));
+}
+
+/**
+ * DboActionTest class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.controller.components
+ */
+class DbAcoActionTest extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'DbAcoActionTest'
+ * @access public
+ */
+ var $name = 'DbAcoActionTest';
+
+/**
+ * useTable property
+ *
+ * @var string 'aco_actions'
+ * @access public
+ */
+ var $useTable = 'aco_actions';
+
+/**
+ * belongsTo property
+ *
+ * @var array
+ * @access public
+ */
+ var $belongsTo = array('DbAcoTest' => array('foreignKey' => 'aco_id'));
+}
+
+/**
+ * DbAroUserTest class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.controller.components
+ */
+class DbAroUserTest extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'AuthUser'
+ * @access public
+ */
+ var $name = 'AuthUser';
+
+/**
+ * useTable property
+ *
+ * @var string 'auth_users'
+ * @access public
+ */
+ var $useTable = 'auth_users';
+
+/**
+ * bindNode method
+ *
+ * @param mixed $ref
+ * @access public
+ * @return void
+ */
+ function bindNode($ref = null) {
+ if (Configure::read('DbAclbindMode') == 'string') {
+ return 'ROOT/admins/Gandalf';
+ } elseif (Configure::read('DbAclbindMode') == 'array') {
+ return array('DbAroTest' => array('DbAroTest.model' => 'AuthUser', 'DbAroTest.foreign_key' => 2));
+ }
+ }
+}
+
+/**
+ * DbAclTest class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.controller.components
+ */
+class DbAclTest extends DbAcl {
+
+/**
+ * construct method
+ *
+ * @access private
+ * @return void
+ */
+ function __construct() {
+ $this->Aro =& new DbAroTest();
+ $this->Aro->Permission =& new DbPermissionTest();
+ $this->Aco =& new DbAcoTest();
+ $this->Aro->Permission =& new DbPermissionTest();
+ }
+}
+
+/**
+ * AclNodeTest class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.controller.components.dbacl.models
+ */
+class AclNodeTest extends CakeTestCase {
+
+/**
+ * fixtures property
+ *
+ * @var array
+ * @access public
+ */
+ var $fixtures = array('core.aro', 'core.aco', 'core.aros_aco', 'core.aco_action', 'core.auth_user');
+
+/**
+ * setUp method
+ *
+ * @access public
+ * @return void
+ */
+ function setUp() {
+ Configure::write('Acl.classname', 'DbAclTest');
+ Configure::write('Acl.database', 'test_suite');
+ }
+
+/**
+ * testNode method
+ *
+ * @access public
+ * @return void
+ */
+ function testNode() {
+ $Aco =& new DbAcoTest();
+ $result = Set::extract($Aco->node('Controller1'), '{n}.DbAcoTest.id');
+ $expected = array(2, 1);
+ $this->assertEqual($result, $expected);
+
+ $result = Set::extract($Aco->node('Controller1/action1'), '{n}.DbAcoTest.id');
+ $expected = array(3, 2, 1);
+ $this->assertEqual($result, $expected);
+
+ $result = Set::extract($Aco->node('Controller2/action1'), '{n}.DbAcoTest.id');
+ $expected = array(7, 6, 1);
+ $this->assertEqual($result, $expected);
+
+ $result = Set::extract($Aco->node('Controller1/action2'), '{n}.DbAcoTest.id');
+ $expected = array(5, 2, 1);
+ $this->assertEqual($result, $expected);
+
+ $result = Set::extract($Aco->node('Controller1/action1/record1'), '{n}.DbAcoTest.id');
+ $expected = array(4, 3, 2, 1);
+ $this->assertEqual($result, $expected);
+
+ $result = Set::extract($Aco->node('Controller2/action1/record1'), '{n}.DbAcoTest.id');
+ $expected = array(8, 7, 6, 1);
+ $this->assertEqual($result, $expected);
+
+ $result = Set::extract($Aco->node('Controller2/action3'), '{n}.DbAcoTest.id');
+ $this->assertFalse($result);
+
+ $result = Set::extract($Aco->node('Controller2/action3/record5'), '{n}.DbAcoTest.id');
+ $this->assertFalse($result);
+
+ $result = $Aco->node('');
+ $this->assertEqual($result, null);
+ }
+
+/**
+ * test that node() doesn't dig deeper than it should.
+ *
+ * @return void
+ */
+ function testNodeWithDuplicatePathSegments() {
+ $Aco =& new DbAcoTest();
+ $nodes = $Aco->node('ROOT/Users');
+ $this->assertEqual($nodes[0]['DbAcoTest']['parent_id'], 1, 'Parent id does not point at ROOT. %s');
+ }
+
+/**
+ * testNodeArrayFind method
+ *
+ * @access public
+ * @return void
+ */
+ function testNodeArrayFind() {
+ $Aro = new DbAroTest();
+ Configure::write('DbAclbindMode', 'string');
+ $result = Set::extract($Aro->node(array('DbAroUserTest' => array('id' => '1', 'foreign_key' => '1'))), '{n}.DbAroTest.id');
+ $expected = array(3, 2, 1);
+ $this->assertEqual($result, $expected);
+
+ Configure::write('DbAclbindMode', 'array');
+ $result = Set::extract($Aro->node(array('DbAroUserTest' => array('id' => 4, 'foreign_key' => 2))), '{n}.DbAroTest.id');
+ $expected = array(4);
+ $this->assertEqual($result, $expected);
+ }
+ /**
+ * testNodeObjectFind method
+ *
+ * @access public
+ * @return void
+ */
+ function testNodeObjectFind() {
+ $Aro = new DbAroTest();
+ $Model = new DbAroUserTest();
+ $Model->id = 1;
+ $result = Set::extract($Aro->node($Model), '{n}.DbAroTest.id');
+ $expected = array(3, 2, 1);
+ $this->assertEqual($result, $expected);
+
+ $Model->id = 2;
+ $result = Set::extract($Aro->node($Model), '{n}.DbAroTest.id');
+ $expected = array(4, 2, 1);
+ $this->assertEqual($result, $expected);
+
+ }
+
+/**
+ * testNodeAliasParenting method
+ *
+ * @access public
+ * @return void
+ */
+ function testNodeAliasParenting() {
+ $Aco = new DbAcoTest();
+ $db =& ConnectionManager::getDataSource('test_suite');
+ $db->truncate($Aco);
+ $db->_queriesLog = array();
+
+ $Aco->create(array('model' => null, 'foreign_key' => null, 'parent_id' => null, 'alias' => 'Application'));
+ $Aco->save();
+
+ $Aco->create(array('model' => null, 'foreign_key' => null, 'parent_id' => $Aco->id, 'alias' => 'Pages'));
+ $Aco->save();
+
+ $result = $Aco->find('all');
+ $expected = array(
+ array('DbAcoTest' => array('id' => '1', 'parent_id' => null, 'model' => null, 'foreign_key' => null, 'alias' => 'Application', 'lft' => '1', 'rght' => '4'), 'DbAroTest' => array()),
+ array('DbAcoTest' => array('id' => '2', 'parent_id' => '1', 'model' => null, 'foreign_key' => null, 'alias' => 'Pages', 'lft' => '2', 'rght' => '3', ), 'DbAroTest' => array())
+ );
+ $this->assertEqual($result, $expected);
+ }
+}
diff --git a/code/ryzom/tools/server/www/webtt/cake/tests/cases/libs/model/model.test.php b/code/ryzom/tools/server/www/webtt/cake/tests/cases/libs/model/model.test.php
new file mode 100644
index 000000000..14d57f9ab
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/cake/tests/cases/libs/model/model.test.php
@@ -0,0 +1,103 @@
+
+ * Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
+ *
+ * Licensed under The Open Group Test Suite License
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
+ * @link http://book.cakephp.org/view/1196/Testing CakePHP(tm) Tests
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ * @since CakePHP(tm) v 1.2.0.4206
+ * @license http://www.opensource.org/licenses/opengroup.php The Open Group Test Suite License
+ */
+App::import('Core', array('AppModel', 'Model'));
+require_once dirname(__FILE__) . DS . 'models.php';
+
+SimpleTest::ignore('BaseModelTest');
+
+/**
+ * ModelBaseTest
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class BaseModelTest extends CakeTestCase {
+
+/**
+ * autoFixtures property
+ *
+ * @var bool false
+ * @access public
+ */
+ var $autoFixtures = false;
+
+/**
+ * fixtures property
+ *
+ * @var array
+ * @access public
+ */
+ var $fixtures = array(
+ 'core.category', 'core.category_thread', 'core.user', 'core.my_category', 'core.my_product',
+ 'core.my_user', 'core.my_categories_my_users', 'core.my_categories_my_products',
+ 'core.article', 'core.featured', 'core.article_featureds_tags', 'core.article_featured',
+ 'core.articles', 'core.numeric_article', 'core.tag', 'core.articles_tag', 'core.comment',
+ 'core.attachment', 'core.apple', 'core.sample', 'core.another_article', 'core.item',
+ 'core.advertisement', 'core.home', 'core.post', 'core.author', 'core.bid', 'core.portfolio',
+ 'core.product', 'core.project', 'core.thread', 'core.message', 'core.items_portfolio',
+ 'core.syfile', 'core.image', 'core.device_type', 'core.device_type_category',
+ 'core.feature_set', 'core.exterior_type_category', 'core.document', 'core.device',
+ 'core.document_directory', 'core.primary_model', 'core.secondary_model', 'core.something',
+ 'core.something_else', 'core.join_thing', 'core.join_a', 'core.join_b', 'core.join_c',
+ 'core.join_a_b', 'core.join_a_c', 'core.uuid', 'core.data_test', 'core.posts_tag',
+ 'core.the_paper_monkies', 'core.person', 'core.underscore_field', 'core.node',
+ 'core.dependency', 'core.story', 'core.stories_tag', 'core.cd', 'core.book', 'core.basket',
+ 'core.overall_favorite', 'core.account', 'core.content', 'core.content_account',
+ 'core.film_file', 'core.test_plugin_article', 'core.test_plugin_comment', 'core.uuiditem',
+ 'core.counter_cache_user', 'core.counter_cache_post',
+ 'core.counter_cache_user_nonstandard_primary_key',
+ 'core.counter_cache_post_nonstandard_primary_key', 'core.uuidportfolio',
+ 'core.uuiditems_uuidportfolio', 'core.uuiditems_uuidportfolio_numericid', 'core.fruit',
+ 'core.fruits_uuid_tag', 'core.uuid_tag', 'core.product_update_all', 'core.group_update_all'
+ );
+
+/**
+ * start method
+ *
+ * @access public
+ * @return void
+ */
+ function start() {
+ parent::start();
+ $this->debug = Configure::read('debug');
+ Configure::write('debug', 2);
+ }
+
+/**
+ * end method
+ *
+ * @access public
+ * @return void
+ */
+ function end() {
+ parent::end();
+ Configure::write('debug', $this->debug);
+ }
+
+/**
+ * endTest method
+ *
+ * @access public
+ * @return void
+ */
+ function endTest() {
+ ClassRegistry::flush();
+ }
+}
diff --git a/code/ryzom/tools/server/www/webtt/cake/tests/cases/libs/model/model_behavior.test.php b/code/ryzom/tools/server/www/webtt/cake/tests/cases/libs/model/model_behavior.test.php
new file mode 100644
index 000000000..ee139877b
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/cake/tests/cases/libs/model/model_behavior.test.php
@@ -0,0 +1,1138 @@
+ 'testMethod', '/look for\s+(.+)/' => 'speakEnglish');
+
+/**
+ * setup method
+ *
+ * @param mixed $model
+ * @param array $config
+ * @access public
+ * @return void
+ */
+ function setup(&$model, $config = array()) {
+ parent::setup($model, $config);
+ if (isset($config['mangle'])) {
+ $config['mangle'] .= ' mangled';
+ }
+ $this->settings[$model->alias] = array_merge(array('beforeFind' => 'on', 'afterFind' => 'off'), $config);
+ }
+
+/**
+ * beforeFind method
+ *
+ * @param mixed $model
+ * @param mixed $query
+ * @access public
+ * @return void
+ */
+ function beforeFind(&$model, $query) {
+ $settings = $this->settings[$model->alias];
+ if (!isset($settings['beforeFind']) || $settings['beforeFind'] == 'off') {
+ return parent::beforeFind($model, $query);
+ }
+ switch ($settings['beforeFind']) {
+ case 'on':
+ return false;
+ break;
+ case 'test':
+ return null;
+ break;
+ case 'modify':
+ $query['fields'] = array($model->alias . '.id', $model->alias . '.name', $model->alias . '.mytime');
+ $query['recursive'] = -1;
+ return $query;
+ break;
+ }
+ }
+
+/**
+ * afterFind method
+ *
+ * @param mixed $model
+ * @param mixed $results
+ * @param mixed $primary
+ * @access public
+ * @return void
+ */
+ function afterFind(&$model, $results, $primary) {
+ $settings = $this->settings[$model->alias];
+ if (!isset($settings['afterFind']) || $settings['afterFind'] == 'off') {
+ return parent::afterFind($model, $results, $primary);
+ }
+ switch ($settings['afterFind']) {
+ case 'on':
+ return array();
+ break;
+ case 'test':
+ return true;
+ break;
+ case 'test2':
+ return null;
+ break;
+ case 'modify':
+ return Set::extract($results, "{n}.{$model->alias}");
+ break;
+ }
+ }
+
+/**
+ * beforeSave method
+ *
+ * @param mixed $model
+ * @access public
+ * @return void
+ */
+ function beforeSave(&$model) {
+ $settings = $this->settings[$model->alias];
+ if (!isset($settings['beforeSave']) || $settings['beforeSave'] == 'off') {
+ return parent::beforeSave($model);
+ }
+ switch ($settings['beforeSave']) {
+ case 'on':
+ return false;
+ break;
+ case 'test':
+ return null;
+ break;
+ case 'modify':
+ $model->data[$model->alias]['name'] .= ' modified before';
+ return true;
+ break;
+ }
+ }
+
+/**
+ * afterSave method
+ *
+ * @param mixed $model
+ * @param mixed $created
+ * @access public
+ * @return void
+ */
+ function afterSave(&$model, $created) {
+ $settings = $this->settings[$model->alias];
+ if (!isset($settings['afterSave']) || $settings['afterSave'] == 'off') {
+ return parent::afterSave($model, $created);
+ }
+ $string = 'modified after';
+ if ($created) {
+ $string .= ' on create';
+ }
+ switch ($settings['afterSave']) {
+ case 'on':
+ $model->data[$model->alias]['aftersave'] = $string;
+ break;
+ case 'test':
+ unset($model->data[$model->alias]['name']);
+ break;
+ case 'test2':
+ return false;
+ break;
+ case 'modify':
+ $model->data[$model->alias]['name'] .= ' ' . $string;
+ break;
+ }
+ }
+
+/**
+ * beforeValidate method
+ *
+ * @param mixed $model
+ * @access public
+ * @return void
+ */
+ function beforeValidate(&$model) {
+ $settings = $this->settings[$model->alias];
+ if (!isset($settings['validate']) || $settings['validate'] == 'off') {
+ return parent::beforeValidate($model);
+ }
+ switch ($settings['validate']) {
+ case 'on':
+ $model->invalidate('name');
+ return true;
+ break;
+ case 'test':
+ return null;
+ break;
+ case 'whitelist':
+ $this->_addToWhitelist($model, array('name'));
+ return true;
+ break;
+ case 'stop':
+ $model->invalidate('name');
+ return false;
+ break;
+ }
+ }
+
+/**
+ * beforeDelete method
+ *
+ * @param mixed $model
+ * @param bool $cascade
+ * @access public
+ * @return void
+ */
+ function beforeDelete(&$model, $cascade = true) {
+ $settings =& $this->settings[$model->alias];
+ if (!isset($settings['beforeDelete']) || $settings['beforeDelete'] == 'off') {
+ return parent::beforeDelete($model, $cascade);
+ }
+ switch ($settings['beforeDelete']) {
+ case 'on':
+ return false;
+ break;
+ case 'test':
+ return null;
+ break;
+ case 'test2':
+ echo 'beforeDelete success';
+ if ($cascade) {
+ echo ' (cascading) ';
+ }
+ break;
+ }
+ }
+
+/**
+ * afterDelete method
+ *
+ * @param mixed $model
+ * @access public
+ * @return void
+ */
+ function afterDelete(&$model) {
+ $settings =& $this->settings[$model->alias];
+ if (!isset($settings['afterDelete']) || $settings['afterDelete'] == 'off') {
+ return parent::afterDelete($model);
+ }
+ switch ($settings['afterDelete']) {
+ case 'on':
+ echo 'afterDelete success';
+ break;
+ }
+ }
+
+/**
+ * onError method
+ *
+ * @param mixed $model
+ * @access public
+ * @return void
+ */
+ function onError(&$model) {
+ $settings = $this->settings[$model->alias];
+ if (!isset($settings['onError']) || $settings['onError'] == 'off') {
+ return parent::onError($model, $cascade);
+ }
+ echo "onError trigger success";
+ }
+/**
+ * beforeTest method
+ *
+ * @param mixed $model
+ * @access public
+ * @return void
+ */
+ function beforeTest(&$model) {
+ $model->beforeTestResult[] = strtolower(get_class($this));
+ return strtolower(get_class($this));
+ }
+
+/**
+ * testMethod method
+ *
+ * @param mixed $model
+ * @param bool $param
+ * @access public
+ * @return void
+ */
+ function testMethod(&$model, $param = true) {
+ if ($param === true) {
+ return 'working';
+ }
+ }
+
+/**
+ * testData method
+ *
+ * @param mixed $model
+ * @access public
+ * @return void
+ */
+ function testData(&$model) {
+ if (!isset($model->data['Apple']['field'])) {
+ return false;
+ }
+ $model->data['Apple']['field_2'] = true;
+ return true;
+ }
+
+/**
+ * validateField method
+ *
+ * @param mixed $model
+ * @param mixed $field
+ * @access public
+ * @return void
+ */
+ function validateField(&$model, $field) {
+ return current($field) === 'Orange';
+ }
+
+/**
+ * speakEnglish method
+ *
+ * @param mixed $model
+ * @param mixed $method
+ * @param mixed $query
+ * @access public
+ * @return void
+ */
+ function speakEnglish(&$model, $method, $query) {
+ $method = preg_replace('/look for\s+/', 'Item.name = \'', $method);
+ $query = preg_replace('/^in\s+/', 'Location.name = \'', $query);
+ return $method . '\' AND ' . $query . '\'';
+ }
+}
+
+/**
+ * Test2Behavior class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class Test2Behavior extends TestBehavior{
+}
+
+/**
+ * Test3Behavior class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class Test3Behavior extends TestBehavior{
+}
+
+/**
+ * Test4Behavior class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class Test4Behavior extends ModelBehavior{
+ function setup(&$model, $config = null) {
+ $model->bindModel(
+ array('hasMany' => array('Comment'))
+ );
+ }
+}
+
+/**
+ * Test5Behavior class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class Test5Behavior extends ModelBehavior{
+ function setup(&$model, $config = null) {
+ $model->bindModel(
+ array('belongsTo' => array('User'))
+ );
+ }
+}
+
+/**
+ * Test6Behavior class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class Test6Behavior extends ModelBehavior{
+ function setup(&$model, $config = null) {
+ $model->bindModel(
+ array('hasAndBelongsToMany' => array('Tag'))
+ );
+ }
+}
+
+/**
+ * Test7Behavior class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class Test7Behavior extends ModelBehavior{
+ function setup(&$model, $config = null) {
+ $model->bindModel(
+ array('hasOne' => array('Attachment'))
+ );
+ }
+}
+
+/**
+ * BehaviorTest class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class BehaviorTest extends CakeTestCase {
+
+/**
+ * fixtures property
+ *
+ * @var array
+ * @access public
+ */
+ var $fixtures = array(
+ 'core.apple', 'core.sample', 'core.article', 'core.user', 'core.comment',
+ 'core.attachment', 'core.tag', 'core.articles_tag'
+ );
+
+/**
+ * tearDown method
+ *
+ * @access public
+ * @return void
+ */
+ function endTest() {
+ ClassRegistry::flush();
+ }
+
+/**
+ * testBehaviorBinding method
+ *
+ * @access public
+ * @return void
+ */
+ function testBehaviorBinding() {
+ $Apple = new Apple();
+ $this->assertIdentical($Apple->Behaviors->attached(), array());
+
+ $Apple->Behaviors->attach('Test', array('key' => 'value'));
+ $this->assertIdentical($Apple->Behaviors->attached(), array('Test'));
+ $this->assertEqual(strtolower(get_class($Apple->Behaviors->Test)), 'testbehavior');
+ $expected = array('beforeFind' => 'on', 'afterFind' => 'off', 'key' => 'value');
+ $this->assertEqual($Apple->Behaviors->Test->settings['Apple'], $expected);
+ $this->assertEqual(array_keys($Apple->Behaviors->Test->settings), array('Apple'));
+
+ $this->assertIdentical($Apple->Sample->Behaviors->attached(), array());
+ $Apple->Sample->Behaviors->attach('Test', array('key2' => 'value2'));
+ $this->assertIdentical($Apple->Sample->Behaviors->attached(), array('Test'));
+ $this->assertEqual($Apple->Sample->Behaviors->Test->settings['Sample'], array('beforeFind' => 'on', 'afterFind' => 'off', 'key2' => 'value2'));
+
+ $this->assertEqual(array_keys($Apple->Behaviors->Test->settings), array('Apple', 'Sample'));
+ $this->assertIdentical(
+ $Apple->Sample->Behaviors->Test->settings,
+ $Apple->Behaviors->Test->settings
+ );
+ $this->assertNotIdentical($Apple->Behaviors->Test->settings['Apple'], $Apple->Sample->Behaviors->Test->settings['Sample']);
+
+ $Apple->Behaviors->attach('Test', array('key2' => 'value2', 'key3' => 'value3', 'beforeFind' => 'off'));
+ $Apple->Sample->Behaviors->attach('Test', array('key' => 'value', 'key3' => 'value3', 'beforeFind' => 'off'));
+ $this->assertEqual($Apple->Behaviors->Test->settings['Apple'], array('beforeFind' => 'off', 'afterFind' => 'off', 'key' => 'value', 'key2' => 'value2', 'key3' => 'value3'));
+ $this->assertEqual($Apple->Behaviors->Test->settings['Apple'], $Apple->Sample->Behaviors->Test->settings['Sample']);
+
+ $this->assertFalse(isset($Apple->Child->Behaviors->Test));
+ $Apple->Child->Behaviors->attach('Test', array('key' => 'value', 'key2' => 'value2', 'key3' => 'value3', 'beforeFind' => 'off'));
+ $this->assertEqual($Apple->Child->Behaviors->Test->settings['Child'], $Apple->Sample->Behaviors->Test->settings['Sample']);
+
+ $this->assertFalse(isset($Apple->Parent->Behaviors->Test));
+ $Apple->Parent->Behaviors->attach('Test', array('key' => 'value', 'key2' => 'value2', 'key3' => 'value3', 'beforeFind' => 'off'));
+ $this->assertEqual($Apple->Parent->Behaviors->Test->settings['Parent'], $Apple->Sample->Behaviors->Test->settings['Sample']);
+
+ $Apple->Parent->Behaviors->attach('Test', array('key' => 'value', 'key2' => 'value', 'key3' => 'value', 'beforeFind' => 'off'));
+ $this->assertNotEqual($Apple->Parent->Behaviors->Test->settings['Parent'], $Apple->Sample->Behaviors->Test->settings['Sample']);
+
+ $Apple->Behaviors->attach('Plugin.Test', array('key' => 'new value'));
+ $expected = array(
+ 'beforeFind' => 'off', 'afterFind' => 'off', 'key' => 'new value',
+ 'key2' => 'value2', 'key3' => 'value3'
+ );
+ $this->assertEqual($Apple->Behaviors->Test->settings['Apple'], $expected);
+
+ $current = $Apple->Behaviors->Test->settings['Apple'];
+ $expected = array_merge($current, array('mangle' => 'trigger mangled'));
+ $Apple->Behaviors->attach('Test', array('mangle' => 'trigger'));
+ $this->assertEqual($Apple->Behaviors->Test->settings['Apple'], $expected);
+
+ $Apple->Behaviors->attach('Test');
+ $expected = array_merge($current, array('mangle' => 'trigger mangled mangled'));
+
+ $this->assertEqual($Apple->Behaviors->Test->settings['Apple'], $expected);
+ $Apple->Behaviors->attach('Test', array('mangle' => 'trigger'));
+ $expected = array_merge($current, array('mangle' => 'trigger mangled'));
+ $this->assertEqual($Apple->Behaviors->Test->settings['Apple'], $expected);
+ }
+
+/**
+ * test that attach()/detach() works with plugin.banana
+ *
+ * @return void
+ */
+ function testDetachWithPluginNames() {
+ $Apple = new Apple();
+ $Apple->Behaviors->attach('Plugin.Test');
+ $this->assertTrue(isset($Apple->Behaviors->Test), 'Missing behavior');
+ $this->assertEqual($Apple->Behaviors->attached(), array('Test'));
+
+ $Apple->Behaviors->detach('Plugin.Test');
+ $this->assertEqual($Apple->Behaviors->attached(), array());
+
+ $Apple->Behaviors->attach('Plugin.Test');
+ $this->assertTrue(isset($Apple->Behaviors->Test), 'Missing behavior');
+ $this->assertEqual($Apple->Behaviors->attached(), array('Test'));
+
+ $Apple->Behaviors->detach('Test');
+ $this->assertEqual($Apple->Behaviors->attached(), array());
+ }
+
+/**
+ * test that attaching a non existant Behavior triggers a cake error.
+ *
+ * @return void
+ */
+ function testInvalidBehaviorCausingCakeError() {
+ $Apple =& new Apple();
+ $Apple->Behaviors =& new MockModelBehaviorCollection();
+ $Apple->Behaviors->expectOnce('cakeError');
+ $Apple->Behaviors->expectAt(0, 'cakeError', array('missingBehaviorFile', '*'));
+ $this->assertFalse($Apple->Behaviors->attach('NoSuchBehavior'));
+ }
+
+/**
+ * testBehaviorToggling method
+ *
+ * @access public
+ * @return void
+ */
+ function testBehaviorToggling() {
+ $Apple = new Apple();
+ $this->assertIdentical($Apple->Behaviors->enabled(), array());
+
+ $Apple->Behaviors->init('Apple', array('Test' => array('key' => 'value')));
+ $this->assertIdentical($Apple->Behaviors->enabled(), array('Test'));
+
+ $Apple->Behaviors->disable('Test');
+ $this->assertIdentical($Apple->Behaviors->attached(), array('Test'));
+ $this->assertIdentical($Apple->Behaviors->enabled(), array());
+
+ $Apple->Sample->Behaviors->attach('Test');
+ $this->assertIdentical($Apple->Sample->Behaviors->enabled('Test'), true);
+ $this->assertIdentical($Apple->Behaviors->enabled(), array());
+
+ $Apple->Behaviors->enable('Test');
+ $this->assertIdentical($Apple->Behaviors->attached('Test'), true);
+ $this->assertIdentical($Apple->Behaviors->enabled(), array('Test'));
+
+ $Apple->Behaviors->disable('Test');
+ $this->assertIdentical($Apple->Behaviors->enabled(), array());
+ $Apple->Behaviors->attach('Test', array('enabled' => true));
+ $this->assertIdentical($Apple->Behaviors->enabled(), array('Test'));
+ $Apple->Behaviors->attach('Test', array('enabled' => false));
+ $this->assertIdentical($Apple->Behaviors->enabled(), array());
+ $Apple->Behaviors->detach('Test');
+ $this->assertIdentical($Apple->Behaviors->enabled(), array());
+ }
+
+/**
+ * testBehaviorFindCallbacks method
+ *
+ * @access public
+ * @return void
+ */
+ function testBehaviorFindCallbacks() {
+ $Apple = new Apple();
+ $expected = $Apple->find('all');
+
+ $Apple->Behaviors->attach('Test');
+ $this->assertIdentical($Apple->find('all'), null);
+
+ $Apple->Behaviors->attach('Test', array('beforeFind' => 'off'));
+ $this->assertIdentical($Apple->find('all'), $expected);
+
+ $Apple->Behaviors->attach('Test', array('beforeFind' => 'test'));
+ $this->assertIdentical($Apple->find('all'), $expected);
+
+ $Apple->Behaviors->attach('Test', array('beforeFind' => 'modify'));
+ $expected2 = array(
+ array('Apple' => array('id' => '1', 'name' => 'Red Apple 1', 'mytime' => '22:57:17')),
+ array('Apple' => array('id' => '2', 'name' => 'Bright Red Apple', 'mytime' => '22:57:17')),
+ array('Apple' => array('id' => '3', 'name' => 'green blue', 'mytime' => '22:57:17'))
+ );
+ $result = $Apple->find('all', array('conditions' => array('Apple.id <' => '4')));
+ $this->assertEqual($result, $expected2);
+
+ $Apple->Behaviors->disable('Test');
+ $result = $Apple->find('all');
+ $this->assertEqual($result, $expected);
+
+ $Apple->Behaviors->attach('Test', array('beforeFind' => 'off', 'afterFind' => 'on'));
+ $this->assertIdentical($Apple->find('all'), array());
+
+ $Apple->Behaviors->attach('Test', array('afterFind' => 'off'));
+ $this->assertEqual($Apple->find('all'), $expected);
+
+ $Apple->Behaviors->attach('Test', array('afterFind' => 'test'));
+ $this->assertEqual($Apple->find('all'), $expected);
+
+ $Apple->Behaviors->attach('Test', array('afterFind' => 'test2'));
+ $this->assertEqual($Apple->find('all'), $expected);
+
+ $Apple->Behaviors->attach('Test', array('afterFind' => 'modify'));
+ $expected = array(
+ array('id' => '1', 'apple_id' => '2', 'color' => 'Red 1', 'name' => 'Red Apple 1', 'created' => '2006-11-22 10:38:58', 'date' => '1951-01-04', 'modified' => '2006-12-01 13:31:26', 'mytime' => '22:57:17'),
+ array('id' => '2', 'apple_id' => '1', 'color' => 'Bright Red 1', 'name' => 'Bright Red Apple', 'created' => '2006-11-22 10:43:13', 'date' => '2014-01-01', 'modified' => '2006-11-30 18:38:10', 'mytime' => '22:57:17'),
+ array('id' => '3', 'apple_id' => '2', 'color' => 'blue green', 'name' => 'green blue', 'created' => '2006-12-25 05:13:36', 'date' => '2006-12-25', 'modified' => '2006-12-25 05:23:24', 'mytime' => '22:57:17'),
+ array('id' => '4', 'apple_id' => '2', 'color' => 'Blue Green', 'name' => 'Test Name', 'created' => '2006-12-25 05:23:36', 'date' => '2006-12-25', 'modified' => '2006-12-25 05:23:36', 'mytime' => '22:57:17'),
+ array('id' => '5', 'apple_id' => '5', 'color' => 'Green', 'name' => 'Blue Green', 'created' => '2006-12-25 05:24:06', 'date' => '2006-12-25', 'modified' => '2006-12-25 05:29:16', 'mytime' => '22:57:17'),
+ array('id' => '6', 'apple_id' => '4', 'color' => 'My new appleOrange', 'name' => 'My new apple', 'created' => '2006-12-25 05:29:39', 'date' => '2006-12-25', 'modified' => '2006-12-25 05:29:39', 'mytime' => '22:57:17'),
+ array('id' => '7', 'apple_id' => '6', 'color' => 'Some wierd color', 'name' => 'Some odd color', 'created' => '2006-12-25 05:34:21', 'date' => '2006-12-25', 'modified' => '2006-12-25 05:34:21', 'mytime' => '22:57:17')
+ );
+ $this->assertEqual($Apple->find('all'), $expected);
+ }
+
+/**
+ * testBehaviorHasManyFindCallbacks method
+ *
+ * @access public
+ * @return void
+ */
+ function testBehaviorHasManyFindCallbacks() {
+ $Apple = new Apple();
+ $Apple->unbindModel(array('hasOne' => array('Sample'), 'belongsTo' => array('Parent')), false);
+ $expected = $Apple->find('all');
+
+ $Apple->unbindModel(array('hasMany' => array('Child')));
+ $wellBehaved = $Apple->find('all');
+ $Apple->Child->Behaviors->attach('Test', array('afterFind' => 'modify'));
+ $Apple->unbindModel(array('hasMany' => array('Child')));
+ $this->assertIdentical($Apple->find('all'), $wellBehaved);
+
+ $Apple->Child->Behaviors->attach('Test', array('before' => 'off'));
+ $this->assertIdentical($Apple->find('all'), $expected);
+
+ $Apple->Child->Behaviors->attach('Test', array('before' => 'test'));
+ $this->assertIdentical($Apple->find('all'), $expected);
+
+ $expected2 = array(
+ array(
+ 'Apple' => array('id' => 1),
+ 'Child' => array(
+ array('id' => 2,'name' => 'Bright Red Apple', 'mytime' => '22:57:17'))),
+ array(
+ 'Apple' => array('id' => 2),
+ 'Child' => array(
+ array('id' => 1, 'name' => 'Red Apple 1', 'mytime' => '22:57:17'),
+ array('id' => 3, 'name' => 'green blue', 'mytime' => '22:57:17'),
+ array('id' => 4, 'name' => 'Test Name', 'mytime' => '22:57:17'))),
+ array(
+ 'Apple' => array('id' => 3),
+ 'Child' => array())
+ );
+
+ $Apple->Child->Behaviors->attach('Test', array('before' => 'modify'));
+ $result = $Apple->find('all', array('fields' => array('Apple.id'), 'conditions' => array('Apple.id <' => '4')));
+ //$this->assertEqual($result, $expected2);
+
+ $Apple->Child->Behaviors->disable('Test');
+ $result = $Apple->find('all');
+ $this->assertEqual($result, $expected);
+
+ $Apple->Child->Behaviors->attach('Test', array('before' => 'off', 'after' => 'on'));
+ //$this->assertIdentical($Apple->find('all'), array());
+
+ $Apple->Child->Behaviors->attach('Test', array('after' => 'off'));
+ $this->assertEqual($Apple->find('all'), $expected);
+
+ $Apple->Child->Behaviors->attach('Test', array('after' => 'test'));
+ $this->assertEqual($Apple->find('all'), $expected);
+
+ $Apple->Child->Behaviors->attach('Test', array('after' => 'test2'));
+ $this->assertEqual($Apple->find('all'), $expected);
+
+ $Apple->Child->Behaviors->attach('Test', array('after' => 'modify'));
+ $expected = array(
+ array('id' => '1', 'apple_id' => '2', 'color' => 'Red 1', 'name' => 'Red Apple 1', 'created' => '2006-11-22 10:38:58', 'date' => '1951-01-04', 'modified' => '2006-12-01 13:31:26', 'mytime' => '22:57:17'),
+ array('id' => '2', 'apple_id' => '1', 'color' => 'Bright Red 1', 'name' => 'Bright Red Apple', 'created' => '2006-11-22 10:43:13', 'date' => '2014-01-01', 'modified' => '2006-11-30 18:38:10', 'mytime' => '22:57:17'),
+ array('id' => '3', 'apple_id' => '2', 'color' => 'blue green', 'name' => 'green blue', 'created' => '2006-12-25 05:13:36', 'date' => '2006-12-25', 'modified' => '2006-12-25 05:23:24', 'mytime' => '22:57:17'),
+ array('id' => '4', 'apple_id' => '2', 'color' => 'Blue Green', 'name' => 'Test Name', 'created' => '2006-12-25 05:23:36', 'date' => '2006-12-25', 'modified' => '2006-12-25 05:23:36', 'mytime' => '22:57:17'),
+ array('id' => '5', 'apple_id' => '5', 'color' => 'Green', 'name' => 'Blue Green', 'created' => '2006-12-25 05:24:06', 'date' => '2006-12-25', 'modified' => '2006-12-25 05:29:16', 'mytime' => '22:57:17'),
+ array('id' => '6', 'apple_id' => '4', 'color' => 'My new appleOrange', 'name' => 'My new apple', 'created' => '2006-12-25 05:29:39', 'date' => '2006-12-25', 'modified' => '2006-12-25 05:29:39', 'mytime' => '22:57:17'),
+ array('id' => '7', 'apple_id' => '6', 'color' => 'Some wierd color', 'name' => 'Some odd color', 'created' => '2006-12-25 05:34:21', 'date' => '2006-12-25', 'modified' => '2006-12-25 05:34:21', 'mytime' => '22:57:17')
+ );
+ //$this->assertEqual($Apple->find('all'), $expected);
+
+ }
+ /**
+ * testBehaviorHasOneFindCallbacks method
+ *
+ * @access public
+ * @return void
+ */
+ function testBehaviorHasOneFindCallbacks() {
+ $Apple = new Apple();
+ $Apple->unbindModel(array('hasMany' => array('Child'), 'belongsTo' => array('Parent')), false);
+ $expected = $Apple->find('all');
+
+ $Apple->unbindModel(array('hasOne' => array('Sample')));
+ $wellBehaved = $Apple->find('all');
+ $Apple->Sample->Behaviors->attach('Test');
+ $Apple->unbindModel(array('hasOne' => array('Sample')));
+ $this->assertIdentical($Apple->find('all'), $wellBehaved);
+
+ $Apple->Sample->Behaviors->attach('Test', array('before' => 'off'));
+ $this->assertIdentical($Apple->find('all'), $expected);
+
+ $Apple->Sample->Behaviors->attach('Test', array('before' => 'test'));
+ $this->assertIdentical($Apple->find('all'), $expected);
+
+ $Apple->Sample->Behaviors->attach('Test', array('before' => 'modify'));
+ $expected2 = array(
+ array(
+ 'Apple' => array('id' => 1),
+ 'Child' => array(
+ array('id' => 2,'name' => 'Bright Red Apple', 'mytime' => '22:57:17'))),
+ array(
+ 'Apple' => array('id' => 2),
+ 'Child' => array(
+ array('id' => 1, 'name' => 'Red Apple 1', 'mytime' => '22:57:17'),
+ array('id' => 3, 'name' => 'green blue', 'mytime' => '22:57:17'),
+ array('id' => 4, 'name' => 'Test Name', 'mytime' => '22:57:17'))),
+ array(
+ 'Apple' => array('id' => 3),
+ 'Child' => array())
+ );
+ $result = $Apple->find('all', array('fields' => array('Apple.id'), 'conditions' => array('Apple.id <' => '4')));
+ //$this->assertEqual($result, $expected2);
+
+ $Apple->Sample->Behaviors->disable('Test');
+ $result = $Apple->find('all');
+ $this->assertEqual($result, $expected);
+
+ $Apple->Sample->Behaviors->attach('Test', array('before' => 'off', 'after' => 'on'));
+ //$this->assertIdentical($Apple->find('all'), array());
+
+ $Apple->Sample->Behaviors->attach('Test', array('after' => 'off'));
+ $this->assertEqual($Apple->find('all'), $expected);
+
+ $Apple->Sample->Behaviors->attach('Test', array('after' => 'test'));
+ $this->assertEqual($Apple->find('all'), $expected);
+
+ $Apple->Sample->Behaviors->attach('Test', array('after' => 'test2'));
+ $this->assertEqual($Apple->find('all'), $expected);
+
+ $Apple->Sample->Behaviors->attach('Test', array('after' => 'modify'));
+ $expected = array(
+ array('id' => '1', 'apple_id' => '2', 'color' => 'Red 1', 'name' => 'Red Apple 1', 'created' => '2006-11-22 10:38:58', 'date' => '1951-01-04', 'modified' => '2006-12-01 13:31:26', 'mytime' => '22:57:17'),
+ array('id' => '2', 'apple_id' => '1', 'color' => 'Bright Red 1', 'name' => 'Bright Red Apple', 'created' => '2006-11-22 10:43:13', 'date' => '2014-01-01', 'modified' => '2006-11-30 18:38:10', 'mytime' => '22:57:17'),
+ array('id' => '3', 'apple_id' => '2', 'color' => 'blue green', 'name' => 'green blue', 'created' => '2006-12-25 05:13:36', 'date' => '2006-12-25', 'modified' => '2006-12-25 05:23:24', 'mytime' => '22:57:17'),
+ array('id' => '4', 'apple_id' => '2', 'color' => 'Blue Green', 'name' => 'Test Name', 'created' => '2006-12-25 05:23:36', 'date' => '2006-12-25', 'modified' => '2006-12-25 05:23:36', 'mytime' => '22:57:17'),
+ array('id' => '5', 'apple_id' => '5', 'color' => 'Green', 'name' => 'Blue Green', 'created' => '2006-12-25 05:24:06', 'date' => '2006-12-25', 'modified' => '2006-12-25 05:29:16', 'mytime' => '22:57:17'),
+ array('id' => '6', 'apple_id' => '4', 'color' => 'My new appleOrange', 'name' => 'My new apple', 'created' => '2006-12-25 05:29:39', 'date' => '2006-12-25', 'modified' => '2006-12-25 05:29:39', 'mytime' => '22:57:17'),
+ array('id' => '7', 'apple_id' => '6', 'color' => 'Some wierd color', 'name' => 'Some odd color', 'created' => '2006-12-25 05:34:21', 'date' => '2006-12-25', 'modified' => '2006-12-25 05:34:21', 'mytime' => '22:57:17')
+ );
+ //$this->assertEqual($Apple->find('all'), $expected);
+ }
+ /**
+ * testBehaviorBelongsToFindCallbacks method
+ *
+ * @access public
+ * @return void
+ */
+ function testBehaviorBelongsToFindCallbacks() {
+ $Apple = new Apple();
+ $Apple->unbindModel(array('hasMany' => array('Child'), 'hasOne' => array('Sample')), false);
+ $expected = $Apple->find('all');
+
+ $Apple->unbindModel(array('belongsTo' => array('Parent')));
+ $wellBehaved = $Apple->find('all');
+ $Apple->Parent->Behaviors->attach('Test');
+ $Apple->unbindModel(array('belongsTo' => array('Parent')));
+ $this->assertIdentical($Apple->find('all'), $wellBehaved);
+
+ $Apple->Parent->Behaviors->attach('Test', array('before' => 'off'));
+ $this->assertIdentical($Apple->find('all'), $expected);
+
+ $Apple->Parent->Behaviors->attach('Test', array('before' => 'test'));
+ $this->assertIdentical($Apple->find('all'), $expected);
+
+ $Apple->Parent->Behaviors->attach('Test', array('before' => 'modify'));
+ $expected2 = array(
+ array(
+ 'Apple' => array('id' => 1),
+ 'Parent' => array('id' => 2,'name' => 'Bright Red Apple', 'mytime' => '22:57:17')),
+ array(
+ 'Apple' => array('id' => 2),
+ 'Parent' => array('id' => 1, 'name' => 'Red Apple 1', 'mytime' => '22:57:17')),
+ array(
+ 'Apple' => array('id' => 3),
+ 'Parent' => array('id' => 2,'name' => 'Bright Red Apple', 'mytime' => '22:57:17'))
+ );
+ $result = $Apple->find('all', array(
+ 'fields' => array('Apple.id', 'Parent.id', 'Parent.name', 'Parent.mytime'),
+ 'conditions' => array('Apple.id <' => '4')
+ ));
+ $this->assertEqual($result, $expected2);
+
+ $Apple->Parent->Behaviors->disable('Test');
+ $result = $Apple->find('all');
+ $this->assertEqual($result, $expected);
+
+ $Apple->Parent->Behaviors->attach('Test', array('after' => 'off'));
+ $this->assertEqual($Apple->find('all'), $expected);
+
+ $Apple->Parent->Behaviors->attach('Test', array('after' => 'test'));
+ $this->assertEqual($Apple->find('all'), $expected);
+
+ $Apple->Parent->Behaviors->attach('Test', array('after' => 'test2'));
+ $this->assertEqual($Apple->find('all'), $expected);
+
+ $Apple->Parent->Behaviors->attach('Test', array('after' => 'modify'));
+ $expected = array(
+ array('id' => '1', 'apple_id' => '2', 'color' => 'Red 1', 'name' => 'Red Apple 1', 'created' => '2006-11-22 10:38:58', 'date' => '1951-01-04', 'modified' => '2006-12-01 13:31:26', 'mytime' => '22:57:17'),
+ array('id' => '2', 'apple_id' => '1', 'color' => 'Bright Red 1', 'name' => 'Bright Red Apple', 'created' => '2006-11-22 10:43:13', 'date' => '2014-01-01', 'modified' => '2006-11-30 18:38:10', 'mytime' => '22:57:17'),
+ array('id' => '3', 'apple_id' => '2', 'color' => 'blue green', 'name' => 'green blue', 'created' => '2006-12-25 05:13:36', 'date' => '2006-12-25', 'modified' => '2006-12-25 05:23:24', 'mytime' => '22:57:17'),
+ array('id' => '4', 'apple_id' => '2', 'color' => 'Blue Green', 'name' => 'Test Name', 'created' => '2006-12-25 05:23:36', 'date' => '2006-12-25', 'modified' => '2006-12-25 05:23:36', 'mytime' => '22:57:17'),
+ array('id' => '5', 'apple_id' => '5', 'color' => 'Green', 'name' => 'Blue Green', 'created' => '2006-12-25 05:24:06', 'date' => '2006-12-25', 'modified' => '2006-12-25 05:29:16', 'mytime' => '22:57:17'),
+ array('id' => '6', 'apple_id' => '4', 'color' => 'My new appleOrange', 'name' => 'My new apple', 'created' => '2006-12-25 05:29:39', 'date' => '2006-12-25', 'modified' => '2006-12-25 05:29:39', 'mytime' => '22:57:17'),
+ array('id' => '7', 'apple_id' => '6', 'color' => 'Some wierd color', 'name' => 'Some odd color', 'created' => '2006-12-25 05:34:21', 'date' => '2006-12-25', 'modified' => '2006-12-25 05:34:21', 'mytime' => '22:57:17')
+ );
+ //$this->assertEqual($Apple->find('all'), $expected);
+ }
+
+/**
+ * testBehaviorSaveCallbacks method
+ *
+ * @access public
+ * @return void
+ */
+ function testBehaviorSaveCallbacks() {
+ $Sample = new Sample();
+ $record = array('Sample' => array('apple_id' => 6, 'name' => 'sample99'));
+
+ $Sample->Behaviors->attach('Test', array('beforeSave' => 'on'));
+ $Sample->create();
+ $this->assertIdentical($Sample->save($record), false);
+
+ $Sample->Behaviors->attach('Test', array('beforeSave' => 'off'));
+ $Sample->create();
+ $this->assertIdentical($Sample->save($record), $record);
+
+ $Sample->Behaviors->attach('Test', array('beforeSave' => 'test'));
+ $Sample->create();
+ $this->assertIdentical($Sample->save($record), $record);
+
+ $Sample->Behaviors->attach('Test', array('beforeSave' => 'modify'));
+ $expected = Set::insert($record, 'Sample.name', 'sample99 modified before');
+ $Sample->create();
+ $this->assertIdentical($Sample->save($record), $expected);
+
+ $Sample->Behaviors->disable('Test');
+ $this->assertIdentical($Sample->save($record), $record);
+
+ $Sample->Behaviors->attach('Test', array('beforeSave' => 'off', 'afterSave' => 'on'));
+ $expected = Set::merge($record, array('Sample' => array('aftersave' => 'modified after on create')));
+ $Sample->create();
+ $this->assertIdentical($Sample->save($record), $expected);
+
+ $Sample->Behaviors->attach('Test', array('beforeSave' => 'modify', 'afterSave' => 'modify'));
+ $expected = Set::merge($record, array('Sample' => array('name' => 'sample99 modified before modified after on create')));
+ $Sample->create();
+ $this->assertIdentical($Sample->save($record), $expected);
+
+ $Sample->Behaviors->attach('Test', array('beforeSave' => 'off', 'afterSave' => 'test'));
+ $Sample->create();
+ $this->assertIdentical($Sample->save($record), $record);
+
+ $Sample->Behaviors->attach('Test', array('afterSave' => 'test2'));
+ $Sample->create();
+ $this->assertIdentical($Sample->save($record), $record);
+
+ $Sample->Behaviors->attach('Test', array('beforeFind' => 'off', 'afterFind' => 'off'));
+ $Sample->recursive = -1;
+ $record2 = $Sample->read(null, 1);
+
+ $Sample->Behaviors->attach('Test', array('afterSave' => 'on'));
+ $expected = Set::merge($record2, array('Sample' => array('aftersave' => 'modified after')));
+ $Sample->create();
+ $this->assertIdentical($Sample->save($record2), $expected);
+
+ $Sample->Behaviors->attach('Test', array('afterSave' => 'modify'));
+ $expected = Set::merge($record2, array('Sample' => array('name' => 'sample1 modified after')));
+ $Sample->create();
+ $this->assertIdentical($Sample->save($record2), $expected);
+ }
+
+/**
+ * testBehaviorDeleteCallbacks method
+ *
+ * @access public
+ * @return void
+ */
+ function testBehaviorDeleteCallbacks() {
+ $Apple = new Apple();
+
+ $Apple->Behaviors->attach('Test', array('beforeFind' => 'off', 'beforeDelete' => 'off'));
+ $this->assertIdentical($Apple->delete(6), true);
+
+ $Apple->Behaviors->attach('Test', array('beforeDelete' => 'on'));
+ $this->assertIdentical($Apple->delete(4), false);
+
+ $Apple->Behaviors->attach('Test', array('beforeDelete' => 'test2'));
+ if (ob_start()) {
+ $results = $Apple->delete(4);
+ $this->assertIdentical(trim(ob_get_clean()), 'beforeDelete success (cascading)');
+ $this->assertIdentical($results, true);
+ }
+ if (ob_start()) {
+ $results = $Apple->delete(3, false);
+ $this->assertIdentical(trim(ob_get_clean()), 'beforeDelete success');
+ $this->assertIdentical($results, true);
+ }
+
+ $Apple->Behaviors->attach('Test', array('beforeDelete' => 'off', 'afterDelete' => 'on'));
+ if (ob_start()) {
+ $results = $Apple->delete(2, false);
+ $this->assertIdentical(trim(ob_get_clean()), 'afterDelete success');
+ $this->assertIdentical($results, true);
+ }
+ }
+ /**
+ * testBehaviorOnErrorCallback method
+ *
+ * @access public
+ * @return void
+ */
+ function testBehaviorOnErrorCallback() {
+ $Apple = new Apple();
+
+ $Apple->Behaviors->attach('Test', array('beforeFind' => 'off', 'onError' => 'on'));
+ if (ob_start()) {
+ $Apple->Behaviors->Test->onError($Apple);
+ $this->assertIdentical(trim(ob_get_clean()), 'onError trigger success');
+ }
+
+ if (ob_start()) {
+ $Apple->delete(99);
+ //$this->assertIdentical(trim(ob_get_clean()), 'onError trigger success');
+ }
+ }
+ /**
+ * testBehaviorValidateCallback method
+ *
+ * @access public
+ * @return void
+ */
+ function testBehaviorValidateCallback() {
+ $Apple = new Apple();
+
+ $Apple->Behaviors->attach('Test');
+ $this->assertIdentical($Apple->validates(), true);
+
+ $Apple->Behaviors->attach('Test', array('validate' => 'on'));
+ $this->assertIdentical($Apple->validates(), false);
+ $this->assertIdentical($Apple->validationErrors, array('name' => true));
+
+ $Apple->Behaviors->attach('Test', array('validate' => 'stop'));
+ $this->assertIdentical($Apple->validates(), false);
+ $this->assertIdentical($Apple->validationErrors, array('name' => true));
+
+ $Apple->Behaviors->attach('Test', array('validate' => 'whitelist'));
+ $Apple->validates();
+ $this->assertIdentical($Apple->whitelist, array());
+
+ $Apple->whitelist = array('unknown');
+ $Apple->validates();
+ $this->assertIdentical($Apple->whitelist, array('unknown', 'name'));
+ }
+
+/**
+ * testBehaviorValidateMethods method
+ *
+ * @access public
+ * @return void
+ */
+ function testBehaviorValidateMethods() {
+ $Apple = new Apple();
+ $Apple->Behaviors->attach('Test');
+ $Apple->validate['color'] = 'validateField';
+
+ $result = $Apple->save(array('name' => 'Genetically Modified Apple', 'color' => 'Orange'));
+ $this->assertEqual(array_keys($result['Apple']), array('name', 'color', 'modified', 'created'));
+
+ $Apple->create();
+ $result = $Apple->save(array('name' => 'Regular Apple', 'color' => 'Red'));
+ $this->assertFalse($result);
+ }
+
+/**
+ * testBehaviorMethodDispatching method
+ *
+ * @access public
+ * @return void
+ */
+ function testBehaviorMethodDispatching() {
+ $Apple = new Apple();
+ $Apple->Behaviors->attach('Test');
+
+ $expected = 'working';
+ $this->assertEqual($Apple->testMethod(), $expected);
+ $this->assertEqual($Apple->Behaviors->dispatchMethod($Apple, 'testMethod'), $expected);
+
+ $result = $Apple->Behaviors->dispatchMethod($Apple, 'wtf');
+ $this->assertEqual($result, array('unhandled'));
+
+ $result = $Apple->{'look for the remote'}('in the couch');
+ $expected = "Item.name = 'the remote' AND Location.name = 'the couch'";
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testBehaviorMethodDispatchingWithData method
+ *
+ * @access public
+ * @return void
+ */
+ function testBehaviorMethodDispatchingWithData() {
+ $Apple = new Apple();
+ $Apple->Behaviors->attach('Test');
+
+ $Apple->set('field', 'value');
+ $this->assertTrue($Apple->testData());
+ $this->assertTrue($Apple->data['Apple']['field_2']);
+
+ $this->assertTrue($Apple->testData('one', 'two', 'three', 'four', 'five', 'six'));
+ }
+
+/**
+ * testBehaviorTrigger method
+ *
+ * @access public
+ * @return void
+ */
+ function testBehaviorTrigger() {
+ $Apple =& new Apple();
+ $Apple->Behaviors->attach('Test');
+ $Apple->Behaviors->attach('Test2');
+ $Apple->Behaviors->attach('Test3');
+
+ $Apple->beforeTestResult = array();
+ $Apple->Behaviors->trigger($Apple, 'beforeTest');
+ $expected = array('testbehavior', 'test2behavior', 'test3behavior');
+ $this->assertIdentical($Apple->beforeTestResult, $expected);
+
+ $Apple->beforeTestResult = array();
+ $Apple->Behaviors->trigger($Apple, 'beforeTest', array(), array('break' => true, 'breakOn' => 'test2behavior'));
+ $expected = array('testbehavior', 'test2behavior');
+ $this->assertIdentical($Apple->beforeTestResult, $expected);
+
+ $Apple->beforeTestResult = array();
+ $Apple->Behaviors->trigger($Apple, 'beforeTest', array(), array('break' => true, 'breakOn' => array('test2behavior', 'test3behavior')));
+ $expected = array('testbehavior', 'test2behavior');
+ $this->assertIdentical($Apple->beforeTestResult, $expected);
+ }
+
+/**
+ * undocumented function
+ *
+ * @return void
+ * @access public
+ */
+ function testBindModelCallsInBehaviors() {
+ $this->loadFixtures('Article', 'Comment');
+
+ // hasMany
+ $Article = new Article();
+ $Article->unbindModel(array('hasMany' => array('Comment')));
+ $result = $Article->find('first');
+ $this->assertFalse(array_key_exists('Comment', $result));
+
+ $Article->Behaviors->attach('Test4');
+ $result = $Article->find('first');
+ $this->assertTrue(array_key_exists('Comment', $result));
+
+ // belongsTo
+ $Article->unbindModel(array('belongsTo' => array('User')));
+ $result = $Article->find('first');
+ $this->assertFalse(array_key_exists('User', $result));
+
+ $Article->Behaviors->attach('Test5');
+ $result = $Article->find('first');
+ $this->assertTrue(array_key_exists('User', $result));
+
+ // hasAndBelongsToMany
+ $Article->unbindModel(array('hasAndBelongsToMany' => array('Tag')));
+ $result = $Article->find('first');
+ $this->assertFalse(array_key_exists('Tag', $result));
+
+ $Article->Behaviors->attach('Test6');
+ $result = $Article->find('first');
+ $this->assertTrue(array_key_exists('Comment', $result));
+
+ // hasOne
+ $Comment = new Comment();
+ $Comment->unbindModel(array('hasOne' => array('Attachment')));
+ $result = $Comment->find('first');
+ $this->assertFalse(array_key_exists('Attachment', $result));
+
+ $Comment->Behaviors->attach('Test7');
+ $result = $Comment->find('first');
+ $this->assertTrue(array_key_exists('Attachment', $result));
+ }
+
+/**
+ * Test attach and detaching
+ *
+ * @access public
+ * @return void
+ */
+ function testBehaviorAttachAndDetach() {
+ $Sample =& new Sample();
+ $Sample->actsAs = array('Test3' => array('bar'), 'Test2' => array('foo', 'bar'));
+ $Sample->Behaviors->init($Sample->alias, $Sample->actsAs);
+ $Sample->Behaviors->attach('Test2');
+ $Sample->Behaviors->detach('Test3');
+
+ $Sample->Behaviors->trigger($Sample, 'beforeTest');
+ }
+}
diff --git a/code/ryzom/tools/server/www/webtt/cake/tests/cases/libs/model/model_delete.test.php b/code/ryzom/tools/server/www/webtt/cake/tests/cases/libs/model/model_delete.test.php
new file mode 100644
index 000000000..668a61317
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/cake/tests/cases/libs/model/model_delete.test.php
@@ -0,0 +1,754 @@
+
+ * Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
+ *
+ * Licensed under The Open Group Test Suite License
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
+ * @link http://book.cakephp.org/view/1196/Testing CakePHP(tm) Tests
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ * @since CakePHP(tm) v 1.2.0.4206
+ * @license http://www.opensource.org/licenses/opengroup.php The Open Group Test Suite License
+ */
+require_once dirname(__FILE__) . DS . 'model.test.php';
+
+/**
+ * ModelDeleteTest
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model.operations
+ */
+class ModelDeleteTest extends BaseModelTest {
+
+/**
+ * testDeleteHabtmReferenceWithConditions method
+ *
+ * @access public
+ * @return void
+ */
+ function testDeleteHabtmReferenceWithConditions() {
+ $this->loadFixtures('Portfolio', 'Item', 'ItemsPortfolio');
+
+ $Portfolio =& new Portfolio();
+ $Portfolio->hasAndBelongsToMany['Item']['conditions'] = array('ItemsPortfolio.item_id >' => 1);
+
+ $result = $Portfolio->find('first', array(
+ 'conditions' => array('Portfolio.id' => 1)
+ ));
+ $expected = array(
+ array(
+ 'id' => 3,
+ 'syfile_id' => 3,
+ 'published' => 0,
+ 'name' => 'Item 3',
+ 'ItemsPortfolio' => array(
+ 'id' => 3,
+ 'item_id' => 3,
+ 'portfolio_id' => 1
+ )),
+ array(
+ 'id' => 4,
+ 'syfile_id' => 4,
+ 'published' => 0,
+ 'name' => 'Item 4',
+ 'ItemsPortfolio' => array(
+ 'id' => 4,
+ 'item_id' => 4,
+ 'portfolio_id' => 1
+ )),
+ array(
+ 'id' => 5,
+ 'syfile_id' => 5,
+ 'published' => 0,
+ 'name' => 'Item 5',
+ 'ItemsPortfolio' => array(
+ 'id' => 5,
+ 'item_id' => 5,
+ 'portfolio_id' => 1
+ )));
+ $this->assertEqual($result['Item'], $expected);
+
+ $result = $Portfolio->ItemsPortfolio->find('all', array(
+ 'conditions' => array('ItemsPortfolio.portfolio_id' => 1)
+ ));
+ $expected = array(
+ array(
+ 'ItemsPortfolio' => array(
+ 'id' => 1,
+ 'item_id' => 1,
+ 'portfolio_id' => 1
+ )),
+ array(
+ 'ItemsPortfolio' => array(
+ 'id' => 3,
+ 'item_id' => 3,
+ 'portfolio_id' => 1
+ )),
+ array(
+ 'ItemsPortfolio' => array(
+ 'id' => 4,
+ 'item_id' => 4,
+ 'portfolio_id' => 1
+ )),
+ array(
+ 'ItemsPortfolio' => array(
+ 'id' => 5,
+ 'item_id' => 5,
+ 'portfolio_id' => 1
+ )));
+ $this->assertEqual($result, $expected);
+
+ $Portfolio->delete(1);
+
+ $result = $Portfolio->find('first', array(
+ 'conditions' => array('Portfolio.id' => 1)
+ ));
+ $this->assertFalse($result);
+
+ $result = $Portfolio->ItemsPortfolio->find('all', array(
+ 'conditions' => array('ItemsPortfolio.portfolio_id' => 1)
+ ));
+ $this->assertFalse($result);
+ }
+
+/**
+ * testDeleteArticleBLinks method
+ *
+ * @access public
+ * @return void
+ */
+ function testDeleteArticleBLinks() {
+ $this->loadFixtures('Article', 'ArticlesTag', 'Tag');
+ $TestModel =& new ArticleB();
+
+ $result = $TestModel->ArticlesTag->find('all');
+ $expected = array(
+ array('ArticlesTag' => array('article_id' => '1', 'tag_id' => '1')),
+ array('ArticlesTag' => array('article_id' => '1', 'tag_id' => '2')),
+ array('ArticlesTag' => array('article_id' => '2', 'tag_id' => '1')),
+ array('ArticlesTag' => array('article_id' => '2', 'tag_id' => '3'))
+ );
+ $this->assertEqual($result, $expected);
+
+ $TestModel->delete(1);
+ $result = $TestModel->ArticlesTag->find('all');
+
+ $expected = array(
+ array('ArticlesTag' => array('article_id' => '2', 'tag_id' => '1')),
+ array('ArticlesTag' => array('article_id' => '2', 'tag_id' => '3'))
+ );
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testDeleteDependentWithConditions method
+ *
+ * @access public
+ * @return void
+ */
+ function testDeleteDependentWithConditions() {
+ $this->loadFixtures('Cd','Book','OverallFavorite');
+
+ $Cd =& new Cd();
+ $Book =& new Book();
+ $OverallFavorite =& new OverallFavorite();
+
+ $Cd->delete(1);
+
+ $result = $OverallFavorite->find('all', array(
+ 'fields' => array('model_type', 'model_id', 'priority')
+ ));
+ $expected = array(
+ array(
+ 'OverallFavorite' => array(
+ 'model_type' => 'Book',
+ 'model_id' => 1,
+ 'priority' => 2
+ )));
+
+ $this->assertTrue(is_array($result));
+ $this->assertEqual($result, $expected);
+
+ $Book->delete(1);
+
+ $result = $OverallFavorite->find('all', array(
+ 'fields' => array('model_type', 'model_id', 'priority')
+ ));
+ $expected = array();
+
+ $this->assertTrue(is_array($result));
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testDel method
+ *
+ * @access public
+ * @return void
+ */
+ function testDelete() {
+ $this->loadFixtures('Article');
+ $TestModel =& new Article();
+
+ $result = $TestModel->delete(2);
+ $this->assertTrue($result);
+
+ $result = $TestModel->read(null, 2);
+ $this->assertFalse($result);
+
+ $TestModel->recursive = -1;
+ $result = $TestModel->find('all', array(
+ 'fields' => array('id', 'title')
+ ));
+ $expected = array(
+ array('Article' => array(
+ 'id' => 1,
+ 'title' => 'First Article'
+ )),
+ array('Article' => array(
+ 'id' => 3,
+ 'title' => 'Third Article'
+ )));
+ $this->assertEqual($result, $expected);
+
+ $result = $TestModel->delete(3);
+ $this->assertTrue($result);
+
+ $result = $TestModel->read(null, 3);
+ $this->assertFalse($result);
+
+ $TestModel->recursive = -1;
+ $result = $TestModel->find('all', array(
+ 'fields' => array('id', 'title')
+ ));
+ $expected = array(
+ array('Article' => array(
+ 'id' => 1,
+ 'title' => 'First Article'
+ )));
+
+ $this->assertEqual($result, $expected);
+
+ // make sure deleting a non-existent record doesn't break save()
+ // ticket #6293
+ $this->loadFixtures('Uuid');
+ $Uuid =& new Uuid();
+ $data = array(
+ 'B607DAB9-88A2-46CF-B57C-842CA9E3B3B3',
+ '52C8865C-10EE-4302-AE6C-6E7D8E12E2C8',
+ '8208C7FE-E89C-47C5-B378-DED6C271F9B8');
+ foreach ($data as $id) {
+ $Uuid->save(array('id' => $id));
+ }
+ $Uuid->delete('52C8865C-10EE-4302-AE6C-6E7D8E12E2C8');
+ $Uuid->delete('52C8865C-10EE-4302-AE6C-6E7D8E12E2C8');
+ foreach ($data as $id) {
+ $Uuid->save(array('id' => $id));
+ }
+ $result = $Uuid->find('all', array(
+ 'conditions' => array('id' => $data),
+ 'fields' => array('id'),
+ 'order' => 'id'));
+ $expected = array(
+ array('Uuid' => array(
+ 'id' => '52C8865C-10EE-4302-AE6C-6E7D8E12E2C8')),
+ array('Uuid' => array(
+ 'id' => '8208C7FE-E89C-47C5-B378-DED6C271F9B8')),
+ array('Uuid' => array(
+ 'id' => 'B607DAB9-88A2-46CF-B57C-842CA9E3B3B3')));
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * test that delete() updates the correct records counterCache() records.
+ *
+ * @return void
+ */
+ function testDeleteUpdatingCounterCacheCorrectly() {
+ $this->loadFixtures('CounterCacheUser', 'CounterCachePost');
+ $User =& new CounterCacheUser();
+
+ $User->Post->delete(3);
+ $result = $User->read(null, 301);
+ $this->assertEqual($result['User']['post_count'], 0);
+
+ $result = $User->read(null, 66);
+ $this->assertEqual($result['User']['post_count'], 2);
+ }
+
+/**
+ * testDeleteAll method
+ *
+ * @access public
+ * @return void
+ */
+ function testDeleteAll() {
+ $this->loadFixtures('Article');
+ $TestModel =& new Article();
+
+ $data = array('Article' => array(
+ 'user_id' => 2,
+ 'id' => 4,
+ 'title' => 'Fourth Article',
+ 'published' => 'N'
+ ));
+ $result = $TestModel->set($data) && $TestModel->save();
+ $this->assertTrue($result);
+
+ $data = array('Article' => array(
+ 'user_id' => 2,
+ 'id' => 5,
+ 'title' => 'Fifth Article',
+ 'published' => 'Y'
+ ));
+ $result = $TestModel->set($data) && $TestModel->save();
+ $this->assertTrue($result);
+
+ $data = array('Article' => array(
+ 'user_id' => 1,
+ 'id' => 6,
+ 'title' => 'Sixth Article',
+ 'published' => 'N'
+ ));
+ $result = $TestModel->set($data) && $TestModel->save();
+ $this->assertTrue($result);
+
+ $TestModel->recursive = -1;
+ $result = $TestModel->find('all', array(
+ 'fields' => array('id', 'user_id', 'title', 'published')
+ ));
+
+ $expected = array(
+ array('Article' => array(
+ 'id' => 1,
+ 'user_id' => 1,
+ 'title' => 'First Article',
+ 'published' => 'Y'
+ )),
+ array('Article' => array(
+ 'id' => 2,
+ 'user_id' => 3,
+ 'title' => 'Second Article',
+ 'published' => 'Y'
+ )),
+ array('Article' => array(
+ 'id' => 3,
+ 'user_id' => 1,
+ 'title' => 'Third Article',
+ 'published' => 'Y')),
+ array('Article' => array(
+ 'id' => 4,
+ 'user_id' => 2,
+ 'title' => 'Fourth Article',
+ 'published' => 'N'
+ )),
+ array('Article' => array(
+ 'id' => 5,
+ 'user_id' => 2,
+ 'title' => 'Fifth Article',
+ 'published' => 'Y'
+ )),
+ array('Article' => array(
+ 'id' => 6,
+ 'user_id' => 1,
+ 'title' => 'Sixth Article',
+ 'published' => 'N'
+ )));
+
+ $this->assertEqual($result, $expected);
+
+ $result = $TestModel->deleteAll(array('Article.published' => 'N'));
+ $this->assertTrue($result);
+
+ $TestModel->recursive = -1;
+ $result = $TestModel->find('all', array(
+ 'fields' => array('id', 'user_id', 'title', 'published')
+ ));
+ $expected = array(
+ array('Article' => array(
+ 'id' => 1,
+ 'user_id' => 1,
+ 'title' => 'First Article',
+ 'published' => 'Y'
+ )),
+ array('Article' => array(
+ 'id' => 2,
+ 'user_id' => 3,
+ 'title' => 'Second Article',
+ 'published' => 'Y'
+ )),
+ array('Article' => array(
+ 'id' => 3,
+ 'user_id' => 1,
+ 'title' => 'Third Article',
+ 'published' => 'Y'
+ )),
+ array('Article' => array(
+ 'id' => 5,
+ 'user_id' => 2,
+ 'title' => 'Fifth Article',
+ 'published' => 'Y'
+ )));
+ $this->assertEqual($result, $expected);
+
+ $data = array('Article.user_id' => array(2, 3));
+ $result = $TestModel->deleteAll($data, true, true);
+ $this->assertTrue($result);
+
+ $TestModel->recursive = -1;
+ $result = $TestModel->find('all', array(
+ 'fields' => array('id', 'user_id', 'title', 'published')
+ ));
+ $expected = array(
+ array('Article' => array(
+ 'id' => 1,
+ 'user_id' => 1,
+ 'title' => 'First Article',
+ 'published' => 'Y'
+ )),
+ array('Article' => array(
+ 'id' => 3,
+ 'user_id' => 1,
+ 'title' => 'Third Article',
+ 'published' => 'Y'
+ )));
+ $this->assertEqual($result, $expected);
+
+ $result = $TestModel->deleteAll(array('Article.user_id' => 999));
+ $this->assertTrue($result, 'deleteAll returned false when all no records matched conditions. %s');
+
+ $this->expectError();
+ ob_start();
+ $result = $TestModel->deleteAll(array('Article.non_existent_field' => 999));
+ ob_get_clean();
+ $this->assertFalse($result, 'deleteAll returned true when find query generated sql error. %s');
+ }
+
+/**
+ * testRecursiveDel method
+ *
+ * @access public
+ * @return void
+ */
+ function testRecursiveDel() {
+ $this->loadFixtures('Article', 'Comment', 'Attachment');
+ $TestModel =& new Article();
+
+ $result = $TestModel->delete(2);
+ $this->assertTrue($result);
+
+ $TestModel->recursive = 2;
+ $result = $TestModel->read(null, 2);
+ $this->assertFalse($result);
+
+ $result = $TestModel->Comment->read(null, 5);
+ $this->assertFalse($result);
+
+ $result = $TestModel->Comment->read(null, 6);
+ $this->assertFalse($result);
+
+ $result = $TestModel->Comment->Attachment->read(null, 1);
+ $this->assertFalse($result);
+
+ $result = $TestModel->find('count');
+ $this->assertEqual($result, 2);
+
+ $result = $TestModel->Comment->find('count');
+ $this->assertEqual($result, 4);
+
+ $result = $TestModel->Comment->Attachment->find('count');
+ $this->assertEqual($result, 0);
+ }
+
+/**
+ * testDependentExclusiveDelete method
+ *
+ * @access public
+ * @return void
+ */
+ function testDependentExclusiveDelete() {
+ $this->loadFixtures('Article', 'Comment');
+ $TestModel =& new Article10();
+
+ $result = $TestModel->find('all');
+ $this->assertEqual(count($result[0]['Comment']), 4);
+ $this->assertEqual(count($result[1]['Comment']), 2);
+ $this->assertEqual($TestModel->Comment->find('count'), 6);
+
+ $TestModel->delete(1);
+ $this->assertEqual($TestModel->Comment->find('count'), 2);
+ }
+
+/**
+ * testDeleteLinks method
+ *
+ * @access public
+ * @return void
+ */
+ function testDeleteLinks() {
+ $this->loadFixtures('Article', 'ArticlesTag', 'Tag');
+ $TestModel =& new Article();
+
+ $result = $TestModel->ArticlesTag->find('all');
+ $expected = array(
+ array('ArticlesTag' => array(
+ 'article_id' => '1',
+ 'tag_id' => '1'
+ )),
+ array('ArticlesTag' => array(
+ 'article_id' => '1',
+ 'tag_id' => '2'
+ )),
+ array('ArticlesTag' => array(
+ 'article_id' => '2',
+ 'tag_id' => '1'
+ )),
+ array('ArticlesTag' => array(
+ 'article_id' => '2',
+ 'tag_id' => '3'
+ )));
+ $this->assertEqual($result, $expected);
+
+ $TestModel->delete(1);
+ $result = $TestModel->ArticlesTag->find('all');
+
+ $expected = array(
+ array('ArticlesTag' => array(
+ 'article_id' => '2',
+ 'tag_id' => '1'
+ )),
+ array('ArticlesTag' => array(
+ 'article_id' => '2',
+ 'tag_id' => '3'
+ )));
+ $this->assertEqual($result, $expected);
+
+ $result = $TestModel->deleteAll(array('Article.user_id' => 999));
+ $this->assertTrue($result, 'deleteAll returned false when all no records matched conditions. %s');
+ }
+
+/**
+ * test deleteLinks with Multiple habtm associations
+ *
+ * @return void
+ */
+ function testDeleteLinksWithMultipleHabtmAssociations() {
+ $this->loadFixtures('JoinA', 'JoinB', 'JoinC', 'JoinAB', 'JoinAC');
+ $JoinA =& new JoinA();
+
+ //create two new join records to expose the issue.
+ $JoinA->JoinAsJoinC->create(array(
+ 'join_a_id' => 1,
+ 'join_c_id' => 2,
+ ));
+ $JoinA->JoinAsJoinC->save();
+ $JoinA->JoinAsJoinB->create(array(
+ 'join_a_id' => 1,
+ 'join_b_id' => 2,
+ ));
+ $JoinA->JoinAsJoinB->save();
+
+ $result = $JoinA->delete(1);
+ $this->assertTrue($result, 'Delete failed %s');
+
+ $joinedBs = $JoinA->JoinAsJoinB->find('count', array(
+ 'conditions' => array('JoinAsJoinB.join_a_id' => 1)
+ ));
+ $this->assertEqual($joinedBs, 0, 'JoinA/JoinB link records left over. %s');
+
+ $joinedBs = $JoinA->JoinAsJoinC->find('count', array(
+ 'conditions' => array('JoinAsJoinC.join_a_id' => 1)
+ ));
+ $this->assertEqual($joinedBs, 0, 'JoinA/JoinC link records left over. %s');
+ }
+
+/**
+ * testHabtmDeleteLinksWhenNoPrimaryKeyInJoinTable method
+ *
+ * @access public
+ * @return void
+ */
+ function testHabtmDeleteLinksWhenNoPrimaryKeyInJoinTable() {
+
+ $this->loadFixtures('Apple', 'Device', 'ThePaperMonkies');
+ $ThePaper =& new ThePaper();
+ $ThePaper->id = 1;
+ $ThePaper->save(array('Monkey' => array(2, 3)));
+
+ $result = $ThePaper->findById(1);
+ $expected = array(
+ array(
+ 'id' => '2',
+ 'device_type_id' => '1',
+ 'name' => 'Device 2',
+ 'typ' => '1'
+ ),
+ array(
+ 'id' => '3',
+ 'device_type_id' => '1',
+ 'name' => 'Device 3',
+ 'typ' => '2'
+ ));
+ $this->assertEqual($result['Monkey'], $expected);
+
+ $ThePaper =& new ThePaper();
+ $ThePaper->id = 2;
+ $ThePaper->save(array('Monkey' => array(2, 3)));
+
+ $result = $ThePaper->findById(2);
+ $expected = array(
+ array(
+ 'id' => '2',
+ 'device_type_id' => '1',
+ 'name' => 'Device 2',
+ 'typ' => '1'
+ ),
+ array(
+ 'id' => '3',
+ 'device_type_id' => '1',
+ 'name' => 'Device 3',
+ 'typ' => '2'
+ ));
+ $this->assertEqual($result['Monkey'], $expected);
+
+ $ThePaper->delete(1);
+ $result = $ThePaper->findById(2);
+ $expected = array(
+ array(
+ 'id' => '2',
+ 'device_type_id' => '1',
+ 'name' => 'Device 2',
+ 'typ' => '1'
+ ),
+ array(
+ 'id' => '3',
+ 'device_type_id' => '1',
+ 'name' => 'Device 3',
+ 'typ' => '2'
+ ));
+ $this->assertEqual($result['Monkey'], $expected);
+ }
+
+/**
+ * test that beforeDelete returning false can abort deletion.
+ *
+ * @return void
+ */
+ function testBeforeDeleteDeleteAbortion() {
+ $this->loadFixtures('Post');
+ $Model =& new CallbackPostTestModel();
+ $Model->beforeDeleteReturn = false;
+
+ $result = $Model->delete(1);
+ $this->assertFalse($result);
+
+ $exists = $Model->findById(1);
+ $this->assertTrue(is_array($exists));
+ }
+
+/**
+ * test for a habtm deletion error that occurs in postgres but should not.
+ * And should not occur in any dbo.
+ *
+ * @return void
+ */
+ function testDeleteHabtmPostgresFailure() {
+ $this->loadFixtures('Article', 'Tag', 'ArticlesTag');
+
+ $Article =& ClassRegistry::init('Article');
+ $Article->hasAndBelongsToMany['Tag']['unique'] = true;
+
+ $Tag =& ClassRegistry::init('Tag');
+ $Tag->bindModel(array('hasAndBelongsToMany' => array(
+ 'Article' => array(
+ 'className' => 'Article',
+ 'unique' => true
+ )
+ )), true);
+
+ // Article 1 should have Tag.1 and Tag.2
+ $before = $Article->find("all", array(
+ "conditions" => array("Article.id" => 1),
+ ));
+ $this->assertEqual(count($before[0]['Tag']), 2, 'Tag count for Article.id = 1 is incorrect, should be 2 %s');
+
+ // From now on, Tag #1 is only associated with Post #1
+ $submitted_data = array(
+ "Tag" => array("id" => 1, 'tag' => 'tag1'),
+ "Article" => array(
+ "Article" => array(1)
+ )
+ );
+ $Tag->save($submitted_data);
+
+ // One more submission (The other way around) to make sure the reverse save looks good.
+ $submitted_data = array(
+ "Article" => array("id" => 2, 'title' => 'second article'),
+ "Tag" => array(
+ "Tag" => array(2, 3)
+ )
+ );
+ // ERROR:
+ // Postgresql: DELETE FROM "articles_tags" WHERE tag_id IN ('1', '3')
+ // MySQL: DELETE `ArticlesTag` FROM `articles_tags` AS `ArticlesTag` WHERE `ArticlesTag`.`article_id` = 2 AND `ArticlesTag`.`tag_id` IN (1, 3)
+ $Article->save($submitted_data);
+
+ // Want to make sure Article #1 has Tag #1 and Tag #2 still.
+ $after = $Article->find("all", array(
+ "conditions" => array("Article.id" => 1),
+ ));
+
+ // Removing Article #2 from Tag #1 is all that should have happened.
+ $this->assertEqual(count($before[0]["Tag"]), count($after[0]["Tag"]));
+ }
+
+/**
+ * test that deleting records inside the beforeDelete doesn't truncate the table.
+ *
+ * @return void
+ */
+ function testBeforeDeleteWipingTable() {
+ $this->loadFixtures('Comment');
+
+ $Comment =& new BeforeDeleteComment();
+ // Delete 3 records.
+ $Comment->delete(4);
+ $result = $Comment->find('count');
+
+ $this->assertTrue($result > 1, 'Comments are all gone.');
+ $Comment->create(array(
+ 'article_id' => 1,
+ 'user_id' => 2,
+ 'comment' => 'new record',
+ 'published' => 'Y'
+ ));
+ $Comment->save();
+
+ $Comment->delete(5);
+ $result = $Comment->find('count');
+
+ $this->assertTrue($result > 1, 'Comments are all gone.');
+ }
+
+/**
+ * test that deleting the same record from the beforeDelete and the delete doesn't truncate the table.
+ *
+ * @return void
+ */
+ function testBeforeDeleteWipingTableWithDuplicateDelete() {
+ $this->loadFixtures('Comment');
+
+ $Comment =& new BeforeDeleteComment();
+ $Comment->delete(1);
+
+ $result = $Comment->find('count');
+ $this->assertTrue($result > 1, 'Comments are all gone.');
+ }
+}
diff --git a/code/ryzom/tools/server/www/webtt/cake/tests/cases/libs/model/model_integration.test.php b/code/ryzom/tools/server/www/webtt/cake/tests/cases/libs/model/model_integration.test.php
new file mode 100644
index 000000000..3d951e434
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/cake/tests/cases/libs/model/model_integration.test.php
@@ -0,0 +1,1930 @@
+
+ * Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
+ *
+ * Licensed under The Open Group Test Suite License
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
+ * @link http://book.cakephp.org/view/1196/Testing CakePHP(tm) Tests
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ * @since CakePHP(tm) v 1.2.0.4206
+ * @license http://www.opensource.org/licenses/opengroup.php The Open Group Test Suite License
+ */
+require_once dirname(__FILE__) . DS . 'model.test.php';
+App::import('Core', 'DboSource');
+
+/**
+ * DboMock class
+ * A Dbo Source driver to mock a connection and a identity name() method
+ */
+class DboMock extends DboSource {
+
+/**
+* Returns the $field without modifications
+*/
+ function name($field) {
+ return $field;
+ }
+/**
+* Returns true to fake a database connection
+*/
+ function connect() {
+ return true;
+ }
+}
+
+/**
+ * ModelIntegrationTest
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model.operations
+ */
+class ModelIntegrationTest extends BaseModelTest {
+
+/**
+ * testPkInHAbtmLinkModelArticleB
+ *
+ * @access public
+ * @return void
+ */
+ function testPkInHabtmLinkModelArticleB() {
+ $this->loadFixtures('Article', 'Tag');
+ $TestModel2 =& new ArticleB();
+ $this->assertEqual($TestModel2->ArticlesTag->primaryKey, 'article_id');
+ }
+
+/**
+ * Tests that $cacheSources can only be disabled in the db using model settings, not enabled
+ *
+ * @access public
+ * @return void
+ */
+ function testCacheSourcesDisabling() {
+ $this->db->cacheSources = true;
+ $TestModel = new JoinA();
+ $TestModel->cacheSources = false;
+ $TestModel->setSource('join_as');
+ $this->assertFalse($this->db->cacheSources);
+
+ $this->db->cacheSources = false;
+ $TestModel = new JoinA();
+ $TestModel->cacheSources = true;
+ $TestModel->setSource('join_as');
+ $this->assertFalse($this->db->cacheSources);
+ }
+
+/**
+ * testPkInHabtmLinkModel method
+ *
+ * @access public
+ * @return void
+ */
+ function testPkInHabtmLinkModel() {
+ //Test Nonconformant Models
+ $this->loadFixtures('Content', 'ContentAccount', 'Account');
+ $TestModel =& new Content();
+ $this->assertEqual($TestModel->ContentAccount->primaryKey, 'iContentAccountsId');
+
+ //test conformant models with no PK in the join table
+ $this->loadFixtures('Article', 'Tag');
+ $TestModel2 =& new Article();
+ $this->assertEqual($TestModel2->ArticlesTag->primaryKey, 'article_id');
+
+ //test conformant models with PK in join table
+ $this->loadFixtures('Item', 'Portfolio', 'ItemsPortfolio');
+ $TestModel3 =& new Portfolio();
+ $this->assertEqual($TestModel3->ItemsPortfolio->primaryKey, 'id');
+
+ //test conformant models with PK in join table - join table contains extra field
+ $this->loadFixtures('JoinA', 'JoinB', 'JoinAB');
+ $TestModel4 =& new JoinA();
+ $this->assertEqual($TestModel4->JoinAsJoinB->primaryKey, 'id');
+
+ }
+
+/**
+ * testDynamicBehaviorAttachment method
+ *
+ * @access public
+ * @return void
+ */
+ function testDynamicBehaviorAttachment() {
+ $this->loadFixtures('Apple');
+ $TestModel =& new Apple();
+ $this->assertEqual($TestModel->Behaviors->attached(), array());
+
+ $TestModel->Behaviors->attach('Tree', array('left' => 'left_field', 'right' => 'right_field'));
+ $this->assertTrue(is_object($TestModel->Behaviors->Tree));
+ $this->assertEqual($TestModel->Behaviors->attached(), array('Tree'));
+
+ $expected = array(
+ 'parent' => 'parent_id',
+ 'left' => 'left_field',
+ 'right' => 'right_field',
+ 'scope' => '1 = 1',
+ 'type' => 'nested',
+ '__parentChange' => false,
+ 'recursive' => -1
+ );
+
+ $this->assertEqual($TestModel->Behaviors->Tree->settings['Apple'], $expected);
+
+ $expected['enabled'] = false;
+ $TestModel->Behaviors->attach('Tree', array('enabled' => false));
+ $this->assertEqual($TestModel->Behaviors->Tree->settings['Apple'], $expected);
+ $this->assertEqual($TestModel->Behaviors->attached(), array('Tree'));
+
+ $TestModel->Behaviors->detach('Tree');
+ $this->assertEqual($TestModel->Behaviors->attached(), array());
+ $this->assertFalse(isset($TestModel->Behaviors->Tree));
+ }
+
+/**
+ * Tests cross database joins. Requires $test and $test2 to both be set in DATABASE_CONFIG
+ * NOTE: When testing on MySQL, you must set 'persistent' => false on *both* database connections,
+ * or one connection will step on the other.
+ */
+ function testCrossDatabaseJoins() {
+ $config = new DATABASE_CONFIG();
+
+ $skip = $this->skipIf(
+ !isset($config->test) || !isset($config->test2),
+ '%s Primary and secondary test databases not configured, skipping cross-database '
+ .'join tests.'
+ .' To run these tests, you must define $test and $test2 in your database configuration.'
+ );
+
+ if ($skip) {
+ return;
+ }
+
+ $this->loadFixtures('Article', 'Tag', 'ArticlesTag', 'User', 'Comment');
+ $TestModel =& new Article();
+
+ $expected = array(
+ array(
+ 'Article' => array(
+ 'id' => '1',
+ 'user_id' => '1',
+ 'title' => 'First Article',
+ 'body' => 'First Article Body',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:39:23',
+ 'updated' => '2007-03-18 10:41:31'
+ ),
+ 'User' => array(
+ 'id' => '1',
+ 'user' => 'mariano',
+ 'password' => '5f4dcc3b5aa765d61d8327deb882cf99',
+ 'created' => '2007-03-17 01:16:23',
+ 'updated' => '2007-03-17 01:18:31'
+ ),
+ 'Comment' => array(
+ array(
+ 'id' => '1',
+ 'article_id' => '1',
+ 'user_id' => '2',
+ 'comment' => 'First Comment for First Article',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:45:23',
+ 'updated' => '2007-03-18 10:47:31'
+ ),
+ array(
+ 'id' => '2',
+ 'article_id' => '1',
+ 'user_id' => '4',
+ 'comment' => 'Second Comment for First Article',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:47:23',
+ 'updated' => '2007-03-18 10:49:31'
+ ),
+ array(
+ 'id' => '3',
+ 'article_id' => '1',
+ 'user_id' => '1',
+ 'comment' => 'Third Comment for First Article',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:49:23',
+ 'updated' => '2007-03-18 10:51:31'
+ ),
+ array(
+ 'id' => '4',
+ 'article_id' => '1',
+ 'user_id' => '1',
+ 'comment' => 'Fourth Comment for First Article',
+ 'published' => 'N',
+ 'created' => '2007-03-18 10:51:23',
+ 'updated' => '2007-03-18 10:53:31'
+ )),
+ 'Tag' => array(
+ array(
+ 'id' => '1',
+ 'tag' => 'tag1',
+ 'created' => '2007-03-18 12:22:23',
+ 'updated' => '2007-03-18 12:24:31'
+ ),
+ array(
+ 'id' => '2',
+ 'tag' => 'tag2',
+ 'created' => '2007-03-18 12:24:23',
+ 'updated' => '2007-03-18 12:26:31'
+ ))),
+ array(
+ 'Article' => array(
+ 'id' => '2',
+ 'user_id' => '3',
+ 'title' => 'Second Article',
+ 'body' => 'Second Article Body',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:41:23',
+ 'updated' => '2007-03-18 10:43:31'
+ ),
+ 'User' => array(
+ 'id' => '3',
+ 'user' => 'larry',
+ 'password' => '5f4dcc3b5aa765d61d8327deb882cf99',
+ 'created' => '2007-03-17 01:20:23',
+ 'updated' => '2007-03-17 01:22:31'
+ ),
+ 'Comment' => array(
+ array(
+ 'id' => '5',
+ 'article_id' => '2',
+ 'user_id' => '1',
+ 'comment' => 'First Comment for Second Article',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:53:23',
+ 'updated' => '2007-03-18 10:55:31'
+ ),
+ array(
+ 'id' => '6',
+ 'article_id' => '2',
+ 'user_id' => '2',
+ 'comment' => 'Second Comment for Second Article',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:55:23',
+ 'updated' => '2007-03-18 10:57:31'
+ )),
+ 'Tag' => array(
+ array(
+ 'id' => '1',
+ 'tag' => 'tag1',
+ 'created' => '2007-03-18 12:22:23',
+ 'updated' => '2007-03-18 12:24:31'
+ ),
+ array(
+ 'id' => '3',
+ 'tag' => 'tag3',
+ 'created' => '2007-03-18 12:26:23',
+ 'updated' => '2007-03-18 12:28:31'
+ ))),
+ array(
+ 'Article' => array(
+ 'id' => '3',
+ 'user_id' => '1',
+ 'title' => 'Third Article',
+ 'body' => 'Third Article Body',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:43:23',
+ 'updated' => '2007-03-18 10:45:31'
+ ),
+ 'User' => array(
+ 'id' => '1',
+ 'user' => 'mariano',
+ 'password' => '5f4dcc3b5aa765d61d8327deb882cf99',
+ 'created' => '2007-03-17 01:16:23',
+ 'updated' => '2007-03-17 01:18:31'
+ ),
+ 'Comment' => array(),
+ 'Tag' => array()
+ ));
+ $this->assertEqual($TestModel->find('all'), $expected);
+
+ $db2 =& ConnectionManager::getDataSource('test2');
+
+ foreach (array('User', 'Comment') as $class) {
+ $this->_fixtures[$this->_fixtureClassMap[$class]]->create($db2);
+ $this->_fixtures[$this->_fixtureClassMap[$class]]->insert($db2);
+ $this->db->truncate(Inflector::pluralize(Inflector::underscore($class)));
+ }
+
+ $this->assertEqual($TestModel->User->find('all'), array());
+ $this->assertEqual($TestModel->Comment->find('all'), array());
+ $this->assertEqual($TestModel->find('count'), 3);
+
+ $TestModel->User->setDataSource('test2');
+ $TestModel->Comment->setDataSource('test2');
+
+ foreach ($expected as $key => $value) {
+ unset($value['Comment'], $value['Tag']);
+ $expected[$key] = $value;
+ }
+
+ $TestModel->recursive = 0;
+ $result = $TestModel->find('all');
+ $this->assertEqual($result, $expected);
+
+ foreach ($expected as $key => $value) {
+ unset($value['Comment'], $value['Tag']);
+ $expected[$key] = $value;
+ }
+
+ $TestModel->recursive = 0;
+ $result = $TestModel->find('all');
+ $this->assertEqual($result, $expected);
+
+ $result = Set::extract($TestModel->User->find('all'), '{n}.User.id');
+ $this->assertEqual($result, array('1', '2', '3', '4'));
+ $this->assertEqual($TestModel->find('all'), $expected);
+
+ $TestModel->Comment->unbindModel(array('hasOne' => array('Attachment')));
+ $expected = array(
+ array(
+ 'Comment' => array(
+ 'id' => '1',
+ 'article_id' => '1',
+ 'user_id' => '2',
+ 'comment' => 'First Comment for First Article',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:45:23',
+ 'updated' => '2007-03-18 10:47:31'
+ ),
+ 'User' => array(
+ 'id' => '2',
+ 'user' => 'nate',
+ 'password' => '5f4dcc3b5aa765d61d8327deb882cf99',
+ 'created' => '2007-03-17 01:18:23',
+ 'updated' => '2007-03-17 01:20:31'
+ ),
+ 'Article' => array(
+ 'id' => '1',
+ 'user_id' => '1',
+ 'title' => 'First Article',
+ 'body' => 'First Article Body',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:39:23',
+ 'updated' => '2007-03-18 10:41:31'
+ )),
+ array(
+ 'Comment' => array(
+ 'id' => '2',
+ 'article_id' => '1',
+ 'user_id' => '4',
+ 'comment' => 'Second Comment for First Article',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:47:23',
+ 'updated' => '2007-03-18 10:49:31'
+ ),
+ 'User' => array(
+ 'id' => '4',
+ 'user' => 'garrett',
+ 'password' => '5f4dcc3b5aa765d61d8327deb882cf99',
+ 'created' => '2007-03-17 01:22:23',
+ 'updated' => '2007-03-17 01:24:31'
+ ),
+ 'Article' => array(
+ 'id' => '1',
+ 'user_id' => '1',
+ 'title' => 'First Article',
+ 'body' => 'First Article Body',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:39:23',
+ 'updated' => '2007-03-18 10:41:31'
+ )),
+ array(
+ 'Comment' => array(
+ 'id' => '3',
+ 'article_id' => '1',
+ 'user_id' => '1',
+ 'comment' => 'Third Comment for First Article',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:49:23',
+ 'updated' => '2007-03-18 10:51:31'
+ ),
+ 'User' => array(
+ 'id' => '1',
+ 'user' => 'mariano',
+ 'password' => '5f4dcc3b5aa765d61d8327deb882cf99',
+ 'created' => '2007-03-17 01:16:23',
+ 'updated' => '2007-03-17 01:18:31'
+ ),
+ 'Article' => array(
+ 'id' => '1',
+ 'user_id' => '1',
+ 'title' => 'First Article',
+ 'body' => 'First Article Body',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:39:23',
+ 'updated' => '2007-03-18 10:41:31'
+ )),
+ array(
+ 'Comment' => array(
+ 'id' => '4',
+ 'article_id' => '1',
+ 'user_id' => '1',
+ 'comment' => 'Fourth Comment for First Article',
+ 'published' => 'N',
+ 'created' => '2007-03-18 10:51:23',
+ 'updated' => '2007-03-18 10:53:31'
+ ),
+ 'User' => array(
+ 'id' => '1',
+ 'user' => 'mariano',
+ 'password' => '5f4dcc3b5aa765d61d8327deb882cf99',
+ 'created' => '2007-03-17 01:16:23',
+ 'updated' => '2007-03-17 01:18:31'
+ ),
+ 'Article' => array(
+ 'id' => '1',
+ 'user_id' => '1',
+ 'title' => 'First Article',
+ 'body' => 'First Article Body',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:39:23',
+ 'updated' => '2007-03-18 10:41:31'
+ )),
+ array(
+ 'Comment' => array(
+ 'id' => '5',
+ 'article_id' => '2',
+ 'user_id' => '1',
+ 'comment' => 'First Comment for Second Article',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:53:23',
+ 'updated' => '2007-03-18 10:55:31'
+ ),
+ 'User' => array(
+ 'id' => '1',
+ 'user' => 'mariano',
+ 'password' => '5f4dcc3b5aa765d61d8327deb882cf99',
+ 'created' => '2007-03-17 01:16:23',
+ 'updated' => '2007-03-17 01:18:31'
+ ),
+ 'Article' => array(
+ 'id' => '2',
+ 'user_id' => '3',
+ 'title' => 'Second Article',
+ 'body' => 'Second Article Body',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:41:23',
+ 'updated' => '2007-03-18 10:43:31'
+ )),
+ array(
+ 'Comment' => array(
+ 'id' => '6',
+ 'article_id' => '2',
+ 'user_id' => '2',
+ 'comment' => 'Second Comment for Second Article',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:55:23',
+ 'updated' => '2007-03-18 10:57:31'
+ ),
+ 'User' => array(
+ 'id' => '2',
+ 'user' => 'nate',
+ 'password' => '5f4dcc3b5aa765d61d8327deb882cf99',
+ 'created' => '2007-03-17 01:18:23',
+ 'updated' => '2007-03-17 01:20:31'
+ ),
+ 'Article' => array(
+ 'id' => '2',
+ 'user_id' => '3',
+ 'title' => 'Second Article',
+ 'body' => 'Second Article Body',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:41:23',
+ 'updated' => '2007-03-18 10:43:31'
+ )));
+ $this->assertEqual($TestModel->Comment->find('all'), $expected);
+
+ foreach (array('User', 'Comment') as $class) {
+ $this->_fixtures[$this->_fixtureClassMap[$class]]->drop($db2);
+ }
+ }
+
+/**
+ * testDisplayField method
+ *
+ * @access public
+ * @return void
+ */
+ function testDisplayField() {
+ $this->loadFixtures('Post', 'Comment', 'Person');
+ $Post = new Post();
+ $Comment = new Comment();
+ $Person = new Person();
+
+ $this->assertEqual($Post->displayField, 'title');
+ $this->assertEqual($Person->displayField, 'name');
+ $this->assertEqual($Comment->displayField, 'id');
+ }
+
+/**
+ * testSchema method
+ *
+ * @access public
+ * @return void
+ */
+ function testSchema() {
+ $Post = new Post();
+
+ $result = $Post->schema();
+ $columns = array('id', 'author_id', 'title', 'body', 'published', 'created', 'updated');
+ $this->assertEqual(array_keys($result), $columns);
+
+ $types = array('integer', 'integer', 'string', 'text', 'string', 'datetime', 'datetime');
+ $this->assertEqual(Set::extract(array_values($result), '{n}.type'), $types);
+
+ $result = $Post->schema('body');
+ $this->assertEqual($result['type'], 'text');
+ $this->assertNull($Post->schema('foo'));
+
+ $this->assertEqual($Post->getColumnTypes(), array_combine($columns, $types));
+ }
+
+/**
+ * test deconstruct() with time fields.
+ *
+ * @return void
+ */
+ function testDeconstructFieldsTime() {
+ $this->loadFixtures('Apple');
+ $TestModel =& new Apple();
+
+ $data = array();
+ $data['Apple']['mytime']['hour'] = '';
+ $data['Apple']['mytime']['min'] = '';
+ $data['Apple']['mytime']['sec'] = '';
+
+ $TestModel->data = null;
+ $TestModel->set($data);
+ $expected = array('Apple'=> array('mytime'=> ''));
+ $this->assertEqual($TestModel->data, $expected);
+
+ $data = array();
+ $data['Apple']['mytime']['hour'] = '';
+ $data['Apple']['mytime']['min'] = '';
+ $data['Apple']['mytime']['meridan'] = '';
+
+ $TestModel->data = null;
+ $TestModel->set($data);
+ $expected = array('Apple'=> array('mytime'=> ''));
+ $this->assertEqual($TestModel->data, $expected, 'Empty values are not returning properly. %s');
+
+ $data = array();
+ $data['Apple']['mytime']['hour'] = '12';
+ $data['Apple']['mytime']['min'] = '0';
+ $data['Apple']['mytime']['meridian'] = 'am';
+
+ $TestModel->data = null;
+ $TestModel->set($data);
+ $expected = array('Apple'=> array('mytime'=> '00:00:00'));
+ $this->assertEqual($TestModel->data, $expected, 'Midnight is not returning proper values. %s');
+
+ $data = array();
+ $data['Apple']['mytime']['hour'] = '00';
+ $data['Apple']['mytime']['min'] = '00';
+
+ $TestModel->data = null;
+ $TestModel->set($data);
+ $expected = array('Apple'=> array('mytime'=> '00:00:00'));
+ $this->assertEqual($TestModel->data, $expected, 'Midnight is not returning proper values. %s');
+
+ $data = array();
+ $data['Apple']['mytime']['hour'] = '03';
+ $data['Apple']['mytime']['min'] = '04';
+ $data['Apple']['mytime']['sec'] = '04';
+
+ $TestModel->data = null;
+ $TestModel->set($data);
+ $expected = array('Apple'=> array('mytime'=> '03:04:04'));
+ $this->assertEqual($TestModel->data, $expected);
+
+ $data = array();
+ $data['Apple']['mytime']['hour'] = '3';
+ $data['Apple']['mytime']['min'] = '4';
+ $data['Apple']['mytime']['sec'] = '4';
+
+ $TestModel->data = null;
+ $TestModel->set($data);
+ $expected = array('Apple' => array('mytime'=> '03:04:04'));
+ $this->assertEqual($TestModel->data, $expected);
+
+ $data = array();
+ $data['Apple']['mytime']['hour'] = '03';
+ $data['Apple']['mytime']['min'] = '4';
+ $data['Apple']['mytime']['sec'] = '4';
+
+ $TestModel->data = null;
+ $TestModel->set($data);
+ $expected = array('Apple'=> array('mytime'=> '03:04:04'));
+ $this->assertEqual($TestModel->data, $expected);
+
+ $db = ConnectionManager::getDataSource('test_suite');
+ $data = array();
+ $data['Apple']['mytime'] = $db->expression('NOW()');
+ $TestModel->data = null;
+ $TestModel->set($data);
+ $this->assertEqual($TestModel->data, $data);
+ }
+
+/**
+ * testDeconstructFields with datetime, timestamp, and date fields
+ *
+ * @access public
+ * @return void
+ */
+ function testDeconstructFieldsDateTime() {
+ $this->loadFixtures('Apple');
+ $TestModel =& new Apple();
+
+ //test null/empty values first
+ $data['Apple']['created']['year'] = '';
+ $data['Apple']['created']['month'] = '';
+ $data['Apple']['created']['day'] = '';
+ $data['Apple']['created']['hour'] = '';
+ $data['Apple']['created']['min'] = '';
+ $data['Apple']['created']['sec'] = '';
+
+ $TestModel->data = null;
+ $TestModel->set($data);
+ $expected = array('Apple'=> array('created'=> ''));
+ $this->assertEqual($TestModel->data, $expected);
+
+ $data = array();
+ $data['Apple']['date']['year'] = '';
+ $data['Apple']['date']['month'] = '';
+ $data['Apple']['date']['day'] = '';
+
+ $TestModel->data = null;
+ $TestModel->set($data);
+ $expected = array('Apple'=> array('date'=> ''));
+ $this->assertEqual($TestModel->data, $expected);
+
+ $data = array();
+ $data['Apple']['created']['year'] = '2007';
+ $data['Apple']['created']['month'] = '08';
+ $data['Apple']['created']['day'] = '20';
+ $data['Apple']['created']['hour'] = '';
+ $data['Apple']['created']['min'] = '';
+ $data['Apple']['created']['sec'] = '';
+
+ $TestModel->data = null;
+ $TestModel->set($data);
+ $expected = array('Apple'=> array('created'=> '2007-08-20 00:00:00'));
+ $this->assertEqual($TestModel->data, $expected);
+
+ $data = array();
+ $data['Apple']['created']['year'] = '2007';
+ $data['Apple']['created']['month'] = '08';
+ $data['Apple']['created']['day'] = '20';
+ $data['Apple']['created']['hour'] = '10';
+ $data['Apple']['created']['min'] = '12';
+ $data['Apple']['created']['sec'] = '';
+
+ $TestModel->data = null;
+ $TestModel->set($data);
+ $expected = array('Apple'=> array('created'=> '2007-08-20 10:12:00'));
+ $this->assertEqual($TestModel->data, $expected);
+
+ $data = array();
+ $data['Apple']['created']['year'] = '2007';
+ $data['Apple']['created']['month'] = '';
+ $data['Apple']['created']['day'] = '12';
+ $data['Apple']['created']['hour'] = '20';
+ $data['Apple']['created']['min'] = '';
+ $data['Apple']['created']['sec'] = '';
+
+ $TestModel->data = null;
+ $TestModel->set($data);
+ $expected = array('Apple'=> array('created'=> ''));
+ $this->assertEqual($TestModel->data, $expected);
+
+ $data = array();
+ $data['Apple']['created']['hour'] = '20';
+ $data['Apple']['created']['min'] = '33';
+
+ $TestModel->data = null;
+ $TestModel->set($data);
+ $expected = array('Apple'=> array('created'=> ''));
+ $this->assertEqual($TestModel->data, $expected);
+
+ $data = array();
+ $data['Apple']['created']['hour'] = '20';
+ $data['Apple']['created']['min'] = '33';
+ $data['Apple']['created']['sec'] = '33';
+
+ $TestModel->data = null;
+ $TestModel->set($data);
+ $expected = array('Apple'=> array('created'=> ''));
+ $this->assertEqual($TestModel->data, $expected);
+
+ $data = array();
+ $data['Apple']['created']['hour'] = '13';
+ $data['Apple']['created']['min'] = '00';
+ $data['Apple']['date']['year'] = '2006';
+ $data['Apple']['date']['month'] = '12';
+ $data['Apple']['date']['day'] = '25';
+
+ $TestModel->data = null;
+ $TestModel->set($data);
+ $expected = array(
+ 'Apple'=> array(
+ 'created'=> '',
+ 'date'=> '2006-12-25'
+ ));
+ $this->assertEqual($TestModel->data, $expected);
+
+ $data = array();
+ $data['Apple']['created']['year'] = '2007';
+ $data['Apple']['created']['month'] = '08';
+ $data['Apple']['created']['day'] = '20';
+ $data['Apple']['created']['hour'] = '10';
+ $data['Apple']['created']['min'] = '12';
+ $data['Apple']['created']['sec'] = '09';
+ $data['Apple']['date']['year'] = '2006';
+ $data['Apple']['date']['month'] = '12';
+ $data['Apple']['date']['day'] = '25';
+
+ $TestModel->data = null;
+ $TestModel->set($data);
+ $expected = array(
+ 'Apple'=> array(
+ 'created'=> '2007-08-20 10:12:09',
+ 'date'=> '2006-12-25'
+ ));
+ $this->assertEqual($TestModel->data, $expected);
+
+ $data = array();
+ $data['Apple']['created']['year'] = '--';
+ $data['Apple']['created']['month'] = '--';
+ $data['Apple']['created']['day'] = '--';
+ $data['Apple']['created']['hour'] = '--';
+ $data['Apple']['created']['min'] = '--';
+ $data['Apple']['created']['sec'] = '--';
+ $data['Apple']['date']['year'] = '--';
+ $data['Apple']['date']['month'] = '--';
+ $data['Apple']['date']['day'] = '--';
+
+ $TestModel->data = null;
+ $TestModel->set($data);
+ $expected = array('Apple'=> array('created'=> '', 'date'=> ''));
+ $this->assertEqual($TestModel->data, $expected);
+
+ $data = array();
+ $data['Apple']['created']['year'] = '2007';
+ $data['Apple']['created']['month'] = '--';
+ $data['Apple']['created']['day'] = '20';
+ $data['Apple']['created']['hour'] = '10';
+ $data['Apple']['created']['min'] = '12';
+ $data['Apple']['created']['sec'] = '09';
+ $data['Apple']['date']['year'] = '2006';
+ $data['Apple']['date']['month'] = '12';
+ $data['Apple']['date']['day'] = '25';
+
+ $TestModel->data = null;
+ $TestModel->set($data);
+ $expected = array('Apple'=> array('created'=> '', 'date'=> '2006-12-25'));
+ $this->assertEqual($TestModel->data, $expected);
+
+ $data = array();
+ $data['Apple']['date']['year'] = '2006';
+ $data['Apple']['date']['month'] = '12';
+ $data['Apple']['date']['day'] = '25';
+
+ $TestModel->data = null;
+ $TestModel->set($data);
+ $expected = array('Apple'=> array('date'=> '2006-12-25'));
+ $this->assertEqual($TestModel->data, $expected);
+
+ $db = ConnectionManager::getDataSource('test_suite');
+ $data = array();
+ $data['Apple']['modified'] = $db->expression('NOW()');
+ $TestModel->data = null;
+ $TestModel->set($data);
+ $this->assertEqual($TestModel->data, $data);
+ }
+
+/**
+ * testTablePrefixSwitching method
+ *
+ * @access public
+ * @return void
+ */
+ function testTablePrefixSwitching() {
+ ConnectionManager::create('database1',
+ array_merge($this->db->config, array('prefix' => 'aaa_')
+ ));
+ ConnectionManager::create('database2',
+ array_merge($this->db->config, array('prefix' => 'bbb_')
+ ));
+
+ $db1 = ConnectionManager::getDataSource('database1');
+ $db2 = ConnectionManager::getDataSource('database2');
+
+ $TestModel = new Apple();
+ $TestModel->setDataSource('database1');
+ $this->assertEqual($this->db->fullTableName($TestModel, false), 'aaa_apples');
+ $this->assertEqual($db1->fullTableName($TestModel, false), 'aaa_apples');
+ $this->assertEqual($db2->fullTableName($TestModel, false), 'aaa_apples');
+
+ $TestModel->setDataSource('database2');
+ $this->assertEqual($this->db->fullTableName($TestModel, false), 'bbb_apples');
+ $this->assertEqual($db1->fullTableName($TestModel, false), 'bbb_apples');
+ $this->assertEqual($db2->fullTableName($TestModel, false), 'bbb_apples');
+
+ $TestModel = new Apple();
+ $TestModel->tablePrefix = 'custom_';
+ $this->assertEqual($this->db->fullTableName($TestModel, false), 'custom_apples');
+ $TestModel->setDataSource('database1');
+ $this->assertEqual($this->db->fullTableName($TestModel, false), 'custom_apples');
+ $this->assertEqual($db1->fullTableName($TestModel, false), 'custom_apples');
+
+ $TestModel = new Apple();
+ $TestModel->setDataSource('database1');
+ $this->assertEqual($this->db->fullTableName($TestModel, false), 'aaa_apples');
+ $TestModel->tablePrefix = '';
+ $TestModel->setDataSource('database2');
+ $this->assertEqual($db2->fullTableName($TestModel, false), 'apples');
+ $this->assertEqual($db1->fullTableName($TestModel, false), 'apples');
+
+ $TestModel->tablePrefix = null;
+ $TestModel->setDataSource('database1');
+ $this->assertEqual($db2->fullTableName($TestModel, false), 'aaa_apples');
+ $this->assertEqual($db1->fullTableName($TestModel, false), 'aaa_apples');
+
+ $TestModel->tablePrefix = false;
+ $TestModel->setDataSource('database2');
+ $this->assertEqual($db2->fullTableName($TestModel, false), 'apples');
+ $this->assertEqual($db1->fullTableName($TestModel, false), 'apples');
+ }
+
+/**
+ * Tests validation parameter order in custom validation methods
+ *
+ * @access public
+ * @return void
+ */
+ function testInvalidAssociation() {
+ $TestModel =& new ValidationTest1();
+ $this->assertNull($TestModel->getAssociated('Foo'));
+ }
+
+/**
+ * testLoadModelSecondIteration method
+ *
+ * @access public
+ * @return void
+ */
+ function testLoadModelSecondIteration() {
+ $model = new ModelA();
+ $this->assertIsA($model,'ModelA');
+
+ $this->assertIsA($model->ModelB, 'ModelB');
+ $this->assertIsA($model->ModelB->ModelD, 'ModelD');
+
+ $this->assertIsA($model->ModelC, 'ModelC');
+ $this->assertIsA($model->ModelC->ModelD, 'ModelD');
+ }
+
+/**
+ * ensure that exists() does not persist between method calls reset on create
+ *
+ * @return void
+ */
+ function testResetOfExistsOnCreate() {
+ $this->loadFixtures('Article');
+ $Article =& new Article();
+ $Article->id = 1;
+ $Article->saveField('title', 'Reset me');
+ $Article->delete();
+ $Article->id = 1;
+ $this->assertFalse($Article->exists());
+
+ $Article->create();
+ $this->assertFalse($Article->exists());
+ $Article->id = 2;
+ $Article->saveField('title', 'Staying alive');
+ $result = $Article->read(null, 2);
+ $this->assertEqual($result['Article']['title'], 'Staying alive');
+ }
+
+/**
+ * testUseTableFalseExistsCheck method
+ *
+ * @return void
+ */
+ function testUseTableFalseExistsCheck() {
+ $this->loadFixtures('Article');
+ $Article =& new Article();
+ $Article->id = 1337;
+ $result = $Article->exists();
+ $this->assertFalse($result);
+
+ $Article->useTable = false;
+ $Article->id = null;
+ $result = $Article->exists();
+ $this->assertFalse($result);
+
+ // An article with primary key of '1' has been loaded by the fixtures.
+ $Article->useTable = false;
+ $Article->id = 1;
+ $result = $Article->exists();
+ $this->assertTrue($result);
+ }
+
+/**
+ * testPluginAssociations method
+ *
+ * @access public
+ * @return void
+ */
+ function testPluginAssociations() {
+ $this->loadFixtures('TestPluginArticle', 'User', 'TestPluginComment');
+ $TestModel =& new TestPluginArticle();
+
+ $result = $TestModel->find('all');
+ $expected = array(
+ array(
+ 'TestPluginArticle' => array(
+ 'id' => 1,
+ 'user_id' => 1,
+ 'title' => 'First Plugin Article',
+ 'body' => 'First Plugin Article Body',
+ 'published' => 'Y',
+ 'created' => '2008-09-24 10:39:23',
+ 'updated' => '2008-09-24 10:41:31'
+ ),
+ 'User' => array(
+ 'id' => 1,
+ 'user' => 'mariano',
+ 'password' => '5f4dcc3b5aa765d61d8327deb882cf99',
+ 'created' => '2007-03-17 01:16:23',
+ 'updated' => '2007-03-17 01:18:31'
+ ),
+ 'TestPluginComment' => array(
+ array(
+ 'id' => 1,
+ 'article_id' => 1,
+ 'user_id' => 2,
+ 'comment' => 'First Comment for First Plugin Article',
+ 'published' => 'Y',
+ 'created' => '2008-09-24 10:45:23',
+ 'updated' => '2008-09-24 10:47:31'
+ ),
+ array(
+ 'id' => 2,
+ 'article_id' => 1,
+ 'user_id' => 4,
+ 'comment' => 'Second Comment for First Plugin Article',
+ 'published' => 'Y',
+ 'created' => '2008-09-24 10:47:23',
+ 'updated' => '2008-09-24 10:49:31'
+ ),
+ array(
+ 'id' => 3,
+ 'article_id' => 1,
+ 'user_id' => 1,
+ 'comment' => 'Third Comment for First Plugin Article',
+ 'published' => 'Y',
+ 'created' => '2008-09-24 10:49:23',
+ 'updated' => '2008-09-24 10:51:31'
+ ),
+ array(
+ 'id' => 4,
+ 'article_id' => 1,
+ 'user_id' => 1,
+ 'comment' => 'Fourth Comment for First Plugin Article',
+ 'published' => 'N',
+ 'created' => '2008-09-24 10:51:23',
+ 'updated' => '2008-09-24 10:53:31'
+ ))),
+ array(
+ 'TestPluginArticle' => array(
+ 'id' => 2,
+ 'user_id' => 3,
+ 'title' => 'Second Plugin Article',
+ 'body' => 'Second Plugin Article Body',
+ 'published' => 'Y',
+ 'created' => '2008-09-24 10:41:23',
+ 'updated' => '2008-09-24 10:43:31'
+ ),
+ 'User' => array(
+ 'id' => 3,
+ 'user' => 'larry',
+ 'password' => '5f4dcc3b5aa765d61d8327deb882cf99',
+ 'created' => '2007-03-17 01:20:23',
+ 'updated' => '2007-03-17 01:22:31'
+ ),
+ 'TestPluginComment' => array(
+ array(
+ 'id' => 5,
+ 'article_id' => 2,
+ 'user_id' => 1,
+ 'comment' => 'First Comment for Second Plugin Article',
+ 'published' => 'Y',
+ 'created' => '2008-09-24 10:53:23',
+ 'updated' => '2008-09-24 10:55:31'
+ ),
+ array(
+ 'id' => 6,
+ 'article_id' => 2,
+ 'user_id' => 2,
+ 'comment' => 'Second Comment for Second Plugin Article',
+ 'published' => 'Y',
+ 'created' => '2008-09-24 10:55:23',
+ 'updated' => '2008-09-24 10:57:31'
+ ))),
+ array(
+ 'TestPluginArticle' => array(
+ 'id' => 3,
+ 'user_id' => 1,
+ 'title' => 'Third Plugin Article',
+ 'body' => 'Third Plugin Article Body',
+ 'published' => 'Y',
+ 'created' => '2008-09-24 10:43:23',
+ 'updated' => '2008-09-24 10:45:31'
+ ),
+ 'User' => array(
+ 'id' => 1,
+ 'user' => 'mariano',
+ 'password' => '5f4dcc3b5aa765d61d8327deb882cf99',
+ 'created' => '2007-03-17 01:16:23',
+ 'updated' => '2007-03-17 01:18:31'
+ ),
+ 'TestPluginComment' => array()
+ ));
+
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * Tests getAssociated method
+ *
+ * @access public
+ * @return void
+ */
+ function testGetAssociated() {
+ $this->loadFixtures('Article');
+ $Article = ClassRegistry::init('Article');
+
+ $assocTypes = array('hasMany', 'hasOne', 'belongsTo', 'hasAndBelongsToMany');
+ foreach ($assocTypes as $type) {
+ $this->assertEqual($Article->getAssociated($type), array_keys($Article->{$type}));
+ }
+
+ $Article->bindModel(array('hasMany' => array('Category')));
+ $this->assertEqual($Article->getAssociated('hasMany'), array('Comment', 'Category'));
+
+ $results = $Article->getAssociated();
+ $this->assertEqual(sort(array_keys($results)), array('Category', 'Comment', 'Tag'));
+
+ $Article->unbindModel(array('hasAndBelongsToMany' => array('Tag')));
+ $this->assertEqual($Article->getAssociated('hasAndBelongsToMany'), array());
+
+ $result = $Article->getAssociated('Category');
+ $expected = array(
+ 'className' => 'Category',
+ 'foreignKey' => 'article_id',
+ 'conditions' => '',
+ 'fields' => '',
+ 'order' => '',
+ 'limit' => '',
+ 'offset' => '',
+ 'dependent' => '',
+ 'exclusive' => '',
+ 'finderQuery' => '',
+ 'counterQuery' => '',
+ 'association' => 'hasMany',
+ );
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testAutoConstructAssociations method
+ *
+ * @access public
+ * @return void
+ */
+ function testAutoConstructAssociations() {
+ $this->loadFixtures('User', 'ArticleFeatured');
+ $TestModel =& new AssociationTest1();
+
+ $result = $TestModel->hasAndBelongsToMany;
+ $expected = array('AssociationTest2' => array(
+ 'unique' => false,
+ 'joinTable' => 'join_as_join_bs',
+ 'foreignKey' => false,
+ 'className' => 'AssociationTest2',
+ 'with' => 'JoinAsJoinB',
+ 'associationForeignKey' => 'join_b_id',
+ 'conditions' => '', 'fields' => '', 'order' => '', 'limit' => '', 'offset' => '',
+ 'finderQuery' => '', 'deleteQuery' => '', 'insertQuery' => ''
+ ));
+ $this->assertEqual($result, $expected);
+
+ // Tests related to ticket https://trac.cakephp.org/ticket/5594
+ $TestModel =& new ArticleFeatured();
+ $TestFakeModel =& new ArticleFeatured(array('table' => false));
+
+ $expected = array(
+ 'User' => array(
+ 'className' => 'User', 'foreignKey' => 'user_id',
+ 'conditions' => '', 'fields' => '', 'order' => '', 'counterCache' => ''
+ ),
+ 'Category' => array(
+ 'className' => 'Category', 'foreignKey' => 'category_id',
+ 'conditions' => '', 'fields' => '', 'order' => '', 'counterCache' => ''
+ )
+ );
+ $this->assertIdentical($TestModel->belongsTo, $expected);
+ $this->assertIdentical($TestFakeModel->belongsTo, $expected);
+
+ $this->assertEqual($TestModel->User->name, 'User');
+ $this->assertEqual($TestFakeModel->User->name, 'User');
+ $this->assertEqual($TestModel->Category->name, 'Category');
+ $this->assertEqual($TestFakeModel->Category->name, 'Category');
+
+ $expected = array(
+ 'Featured' => array(
+ 'className' => 'Featured',
+ 'foreignKey' => 'article_featured_id',
+ 'conditions' => '',
+ 'fields' => '',
+ 'order' => '',
+ 'dependent' => ''
+ ));
+
+ $this->assertIdentical($TestModel->hasOne, $expected);
+ $this->assertIdentical($TestFakeModel->hasOne, $expected);
+
+ $this->assertEqual($TestModel->Featured->name, 'Featured');
+ $this->assertEqual($TestFakeModel->Featured->name, 'Featured');
+
+ $expected = array(
+ 'Comment' => array(
+ 'className' => 'Comment',
+ 'dependent' => true,
+ 'foreignKey' => 'article_featured_id',
+ 'conditions' => '',
+ 'fields' => '',
+ 'order' => '',
+ 'limit' => '',
+ 'offset' => '',
+ 'exclusive' => '',
+ 'finderQuery' => '',
+ 'counterQuery' => ''
+ ));
+
+ $this->assertIdentical($TestModel->hasMany, $expected);
+ $this->assertIdentical($TestFakeModel->hasMany, $expected);
+
+ $this->assertEqual($TestModel->Comment->name, 'Comment');
+ $this->assertEqual($TestFakeModel->Comment->name, 'Comment');
+
+ $expected = array(
+ 'Tag' => array(
+ 'className' => 'Tag',
+ 'joinTable' => 'article_featureds_tags',
+ 'with' => 'ArticleFeaturedsTag',
+ 'foreignKey' => 'article_featured_id',
+ 'associationForeignKey' => 'tag_id',
+ 'conditions' => '',
+ 'fields' => '',
+ 'order' => '',
+ 'limit' => '',
+ 'offset' => '',
+ 'unique' => true,
+ 'finderQuery' => '',
+ 'deleteQuery' => '',
+ 'insertQuery' => ''
+ ));
+
+ $this->assertIdentical($TestModel->hasAndBelongsToMany, $expected);
+ $this->assertIdentical($TestFakeModel->hasAndBelongsToMany, $expected);
+
+ $this->assertEqual($TestModel->Tag->name, 'Tag');
+ $this->assertEqual($TestFakeModel->Tag->name, 'Tag');
+ }
+
+/**
+ * test Model::__construct
+ *
+ * ensure that $actsAS and $_findMethods are merged.
+ *
+ * @return void
+ */
+ function testConstruct() {
+ $this->loadFixtures('Post', 'Comment');
+
+ $TestModel =& ClassRegistry::init('MergeVarPluginPost');
+ $this->assertEqual($TestModel->actsAs, array('Containable', 'Tree'));
+ $this->assertTrue(isset($TestModel->Behaviors->Containable));
+ $this->assertTrue(isset($TestModel->Behaviors->Tree));
+
+ $TestModel =& ClassRegistry::init('MergeVarPluginComment');
+ $expected = array('Containable', 'Containable' => array('some_settings'));
+ $this->assertEqual($TestModel->actsAs, $expected);
+ $this->assertTrue(isset($TestModel->Behaviors->Containable));
+ }
+
+/**
+ * test Model::__construct
+ *
+ * ensure that $actsAS and $_findMethods are merged.
+ *
+ * @return void
+ */
+ function testConstructWithAlternateDataSource() {
+ $TestModel =& ClassRegistry::init(array(
+ 'class' => 'DoesntMatter', 'ds' => 'test_suite', 'table' => false
+ ));
+ $this->assertEqual('test_suite', $TestModel->useDbConfig);
+
+ //deprecated but test it anyway
+ $NewVoid =& new TheVoid(null, false, 'other');
+ $this->assertEqual('other', $NewVoid->useDbConfig);
+ }
+
+/**
+ * testColumnTypeFetching method
+ *
+ * @access public
+ * @return void
+ */
+ function testColumnTypeFetching() {
+ $model =& new Test();
+ $this->assertEqual($model->getColumnType('id'), 'integer');
+ $this->assertEqual($model->getColumnType('notes'), 'text');
+ $this->assertEqual($model->getColumnType('updated'), 'datetime');
+ $this->assertEqual($model->getColumnType('unknown'), null);
+
+ $model =& new Article();
+ $this->assertEqual($model->getColumnType('User.created'), 'datetime');
+ $this->assertEqual($model->getColumnType('Tag.id'), 'integer');
+ $this->assertEqual($model->getColumnType('Article.id'), 'integer');
+ }
+
+/**
+ * testHabtmUniqueKey method
+ *
+ * @access public
+ * @return void
+ */
+ function testHabtmUniqueKey() {
+ $model =& new Item();
+ $this->assertFalse($model->hasAndBelongsToMany['Portfolio']['unique']);
+ }
+
+/**
+ * testIdentity method
+ *
+ * @access public
+ * @return void
+ */
+ function testIdentity() {
+ $TestModel =& new Test();
+ $result = $TestModel->alias;
+ $expected = 'Test';
+ $this->assertEqual($result, $expected);
+
+ $TestModel =& new TestAlias();
+ $result = $TestModel->alias;
+ $expected = 'TestAlias';
+ $this->assertEqual($result, $expected);
+
+ $TestModel =& new Test(array('alias' => 'AnotherTest'));
+ $result = $TestModel->alias;
+ $expected = 'AnotherTest';
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testWithAssociation method
+ *
+ * @access public
+ * @return void
+ */
+ function testWithAssociation() {
+ $this->loadFixtures('Something', 'SomethingElse', 'JoinThing');
+ $TestModel =& new Something();
+ $result = $TestModel->SomethingElse->find('all');
+
+ $expected = array(
+ array(
+ 'SomethingElse' => array(
+ 'id' => '1',
+ 'title' => 'First Post',
+ 'body' => 'First Post Body',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:39:23',
+ 'updated' => '2007-03-18 10:41:31'
+ ),
+ 'Something' => array(
+ array(
+ 'id' => '3',
+ 'title' => 'Third Post',
+ 'body' => 'Third Post Body',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:43:23',
+ 'updated' => '2007-03-18 10:45:31',
+ 'JoinThing' => array(
+ 'id' => '3',
+ 'something_id' => '3',
+ 'something_else_id' => '1',
+ 'doomed' => '1',
+ 'created' => '2007-03-18 10:43:23',
+ 'updated' => '2007-03-18 10:45:31'
+ )))),
+ array(
+ 'SomethingElse' => array(
+ 'id' => '2',
+ 'title' => 'Second Post',
+ 'body' => 'Second Post Body',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:41:23',
+ 'updated' => '2007-03-18 10:43:31'
+ ),
+ 'Something' => array(
+ array(
+ 'id' => '1',
+ 'title' => 'First Post',
+ 'body' => 'First Post Body',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:39:23',
+ 'updated' => '2007-03-18 10:41:31',
+ 'JoinThing' => array(
+ 'id' => '1',
+ 'something_id' => '1',
+ 'something_else_id' => '2',
+ 'doomed' => '1',
+ 'created' => '2007-03-18 10:39:23',
+ 'updated' => '2007-03-18 10:41:31'
+ )))),
+ array(
+ 'SomethingElse' => array(
+ 'id' => '3',
+ 'title' => 'Third Post',
+ 'body' => 'Third Post Body',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:43:23',
+ 'updated' => '2007-03-18 10:45:31'
+ ),
+ 'Something' => array(
+ array(
+ 'id' => '2',
+ 'title' => 'Second Post',
+ 'body' => 'Second Post Body',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:41:23',
+ 'updated' => '2007-03-18 10:43:31',
+ 'JoinThing' => array(
+ 'id' => '2',
+ 'something_id' => '2',
+ 'something_else_id' => '3',
+ 'doomed' => '0',
+ 'created' => '2007-03-18 10:41:23',
+ 'updated' => '2007-03-18 10:43:31'
+ )))));
+ $this->assertEqual($result, $expected);
+
+ $result = $TestModel->find('all');
+ $expected = array(
+ array(
+ 'Something' => array(
+ 'id' => '1',
+ 'title' => 'First Post',
+ 'body' => 'First Post Body',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:39:23',
+ 'updated' => '2007-03-18 10:41:31'
+ ),
+ 'SomethingElse' => array(
+ array(
+ 'id' => '2',
+ 'title' => 'Second Post',
+ 'body' => 'Second Post Body',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:41:23',
+ 'updated' => '2007-03-18 10:43:31',
+ 'JoinThing' => array(
+ 'doomed' => '1',
+ 'something_id' => '1',
+ 'something_else_id' => '2'
+ )))),
+ array(
+ 'Something' => array(
+ 'id' => '2',
+ 'title' => 'Second Post',
+ 'body' => 'Second Post Body',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:41:23',
+ 'updated' => '2007-03-18 10:43:31'
+ ),
+ 'SomethingElse' => array(
+ array(
+ 'id' => '3',
+ 'title' => 'Third Post',
+ 'body' => 'Third Post Body',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:43:23',
+ 'updated' => '2007-03-18 10:45:31',
+ 'JoinThing' => array(
+ 'doomed' => '0',
+ 'something_id' => '2',
+ 'something_else_id' => '3'
+ )))),
+ array(
+ 'Something' => array(
+ 'id' => '3',
+ 'title' => 'Third Post',
+ 'body' => 'Third Post Body',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:43:23',
+ 'updated' => '2007-03-18 10:45:31'
+ ),
+ 'SomethingElse' => array(
+ array(
+ 'id' => '1',
+ 'title' => 'First Post',
+ 'body' => 'First Post Body',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:39:23',
+ 'updated' => '2007-03-18 10:41:31',
+ 'JoinThing' => array(
+ 'doomed' => '1',
+ 'something_id' => '3',
+ 'something_else_id' => '1'
+ )))));
+ $this->assertEqual($result, $expected);
+
+ $result = $TestModel->findById(1);
+ $expected = array(
+ 'Something' => array(
+ 'id' => '1',
+ 'title' => 'First Post',
+ 'body' => 'First Post Body',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:39:23',
+ 'updated' => '2007-03-18 10:41:31'
+ ),
+ 'SomethingElse' => array(
+ array(
+ 'id' => '2',
+ 'title' => 'Second Post',
+ 'body' => 'Second Post Body',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:41:23',
+ 'updated' => '2007-03-18 10:43:31',
+ 'JoinThing' => array(
+ 'doomed' => '1',
+ 'something_id' => '1',
+ 'something_else_id' => '2'
+ ))));
+ $this->assertEqual($result, $expected);
+
+ $expected = $TestModel->findById(1);
+ $TestModel->set($expected);
+ $TestModel->save();
+ $result = $TestModel->findById(1);
+ $this->assertEqual($result, $expected);
+
+ $TestModel->hasAndBelongsToMany['SomethingElse']['unique'] = false;
+ $TestModel->create(array(
+ 'Something' => array('id' => 1),
+ 'SomethingElse' => array(3, array(
+ 'something_else_id' => 1,
+ 'doomed' => '1'
+ ))));
+
+ $ts = date('Y-m-d H:i:s');
+ $TestModel->save();
+
+ $TestModel->hasAndBelongsToMany['SomethingElse']['order'] = 'SomethingElse.id ASC';
+ $result = $TestModel->findById(1);
+ $expected = array(
+ 'Something' => array(
+ 'id' => '1',
+ 'title' => 'First Post',
+ 'body' => 'First Post Body',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:39:23',
+ 'updated' => $ts),
+ 'SomethingElse' => array(
+ array(
+ 'id' => '1',
+ 'title' => 'First Post',
+ 'body' => 'First Post Body',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:39:23',
+ 'updated' => '2007-03-18 10:41:31',
+ 'JoinThing' => array(
+ 'doomed' => '1',
+ 'something_id' => '1',
+ 'something_else_id' => '1'
+ )),
+ array(
+ 'id' => '2',
+ 'title' => 'Second Post',
+ 'body' => 'Second Post Body',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:41:23',
+ 'updated' => '2007-03-18 10:43:31',
+ 'JoinThing' => array(
+ 'doomed' => '1',
+ 'something_id' => '1',
+ 'something_else_id' => '2'
+ )),
+ array(
+ 'id' => '3',
+ 'title' => 'Third Post',
+ 'body' => 'Third Post Body',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:43:23',
+ 'updated' => '2007-03-18 10:45:31',
+ 'JoinThing' => array(
+ 'doomed' => '0',
+ 'something_id' => '1',
+ 'something_else_id' => '3'
+ ))));
+
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testFindSelfAssociations method
+ *
+ * @access public
+ * @return void
+ */
+ function testFindSelfAssociations() {
+ $this->loadFixtures('Person');
+
+ $TestModel =& new Person();
+ $TestModel->recursive = 2;
+ $result = $TestModel->read(null, 1);
+ $expected = array(
+ 'Person' => array(
+ 'id' => 1,
+ 'name' => 'person',
+ 'mother_id' => 2,
+ 'father_id' => 3
+ ),
+ 'Mother' => array(
+ 'id' => 2,
+ 'name' => 'mother',
+ 'mother_id' => 4,
+ 'father_id' => 5,
+ 'Mother' => array(
+ 'id' => 4,
+ 'name' => 'mother - grand mother',
+ 'mother_id' => 0,
+ 'father_id' => 0
+ ),
+ 'Father' => array(
+ 'id' => 5,
+ 'name' => 'mother - grand father',
+ 'mother_id' => 0,
+ 'father_id' => 0
+ )),
+ 'Father' => array(
+ 'id' => 3,
+ 'name' => 'father',
+ 'mother_id' => 6,
+ 'father_id' => 7,
+ 'Father' => array(
+ 'id' => 7,
+ 'name' => 'father - grand father',
+ 'mother_id' => 0,
+ 'father_id' => 0
+ ),
+ 'Mother' => array(
+ 'id' => 6,
+ 'name' => 'father - grand mother',
+ 'mother_id' => 0,
+ 'father_id' => 0
+ )));
+
+ $this->assertEqual($result, $expected);
+
+ $TestModel->recursive = 3;
+ $result = $TestModel->read(null, 1);
+ $expected = array(
+ 'Person' => array(
+ 'id' => 1,
+ 'name' => 'person',
+ 'mother_id' => 2,
+ 'father_id' => 3
+ ),
+ 'Mother' => array(
+ 'id' => 2,
+ 'name' => 'mother',
+ 'mother_id' => 4,
+ 'father_id' => 5,
+ 'Mother' => array(
+ 'id' => 4,
+ 'name' => 'mother - grand mother',
+ 'mother_id' => 0,
+ 'father_id' => 0,
+ 'Mother' => array(),
+ 'Father' => array()),
+ 'Father' => array(
+ 'id' => 5,
+ 'name' => 'mother - grand father',
+ 'mother_id' => 0,
+ 'father_id' => 0,
+ 'Father' => array(),
+ 'Mother' => array()
+ )),
+ 'Father' => array(
+ 'id' => 3,
+ 'name' => 'father',
+ 'mother_id' => 6,
+ 'father_id' => 7,
+ 'Father' => array(
+ 'id' => 7,
+ 'name' => 'father - grand father',
+ 'mother_id' => 0,
+ 'father_id' => 0,
+ 'Father' => array(),
+ 'Mother' => array()
+ ),
+ 'Mother' => array(
+ 'id' => 6,
+ 'name' => 'father - grand mother',
+ 'mother_id' => 0,
+ 'father_id' => 0,
+ 'Mother' => array(),
+ 'Father' => array()
+ )));
+
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testDynamicAssociations method
+ *
+ * @access public
+ * @return void
+ */
+ function testDynamicAssociations() {
+ $this->loadFixtures('Article', 'Comment');
+ $TestModel =& new Article();
+
+ $TestModel->belongsTo = $TestModel->hasAndBelongsToMany = $TestModel->hasOne = array();
+ $TestModel->hasMany['Comment'] = array_merge($TestModel->hasMany['Comment'], array(
+ 'foreignKey' => false,
+ 'conditions' => array('Comment.user_id =' => '2')
+ ));
+ $result = $TestModel->find('all');
+ $expected = array(
+ array(
+ 'Article' => array(
+ 'id' => '1',
+ 'user_id' => '1',
+ 'title' => 'First Article',
+ 'body' => 'First Article Body',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:39:23',
+ 'updated' => '2007-03-18 10:41:31'
+ ),
+ 'Comment' => array(
+ array(
+ 'id' => '1',
+ 'article_id' => '1',
+ 'user_id' => '2',
+ 'comment' => 'First Comment for First Article',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:45:23',
+ 'updated' => '2007-03-18 10:47:31'
+ ),
+ array(
+ 'id' => '6',
+ 'article_id' => '2',
+ 'user_id' => '2',
+ 'comment' => 'Second Comment for Second Article',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:55:23',
+ 'updated' => '2007-03-18 10:57:31'
+ ))),
+ array(
+ 'Article' => array(
+ 'id' => '2',
+ 'user_id' => '3',
+ 'title' => 'Second Article',
+ 'body' => 'Second Article Body',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:41:23',
+ 'updated' => '2007-03-18 10:43:31'
+ ),
+ 'Comment' => array(
+ array(
+ 'id' => '1',
+ 'article_id' => '1',
+ 'user_id' => '2',
+ 'comment' => 'First Comment for First Article',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:45:23',
+ 'updated' => '2007-03-18 10:47:31'
+ ),
+ array(
+ 'id' => '6',
+ 'article_id' => '2',
+ 'user_id' => '2',
+ 'comment' => 'Second Comment for Second Article',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:55:23',
+ 'updated' => '2007-03-18 10:57:31'
+ ))),
+ array(
+ 'Article' => array(
+ 'id' => '3',
+ 'user_id' => '1',
+ 'title' => 'Third Article',
+ 'body' => 'Third Article Body',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:43:23',
+ 'updated' => '2007-03-18 10:45:31'
+ ),
+ 'Comment' => array(
+ array(
+ 'id' => '1',
+ 'article_id' => '1',
+ 'user_id' => '2',
+ 'comment' => 'First Comment for First Article',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:45:23',
+ 'updated' => '2007-03-18 10:47:31'
+ ),
+ array(
+ 'id' => '6',
+ 'article_id' => '2',
+ 'user_id' => '2',
+ 'comment' => 'Second Comment for Second Article',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:55:23',
+ 'updated' => '2007-03-18 10:57:31'
+ ))));
+
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testCreation method
+ *
+ * @access public
+ * @return void
+ */
+ function testCreation() {
+ $this->loadFixtures('Article');
+ $TestModel =& new Test();
+ $result = $TestModel->create();
+ $expected = array('Test' => array('notes' => 'write some notes here'));
+ $this->assertEqual($result, $expected);
+ $TestModel =& new User();
+ $result = $TestModel->schema();
+
+ if (isset($this->db->columns['primary_key']['length'])) {
+ $intLength = $this->db->columns['primary_key']['length'];
+ } elseif (isset($this->db->columns['integer']['length'])) {
+ $intLength = $this->db->columns['integer']['length'];
+ } else {
+ $intLength = 11;
+ }
+ foreach (array('collate', 'charset') as $type) {
+ unset($result['user'][$type]);
+ unset($result['password'][$type]);
+ }
+
+ $expected = array(
+ 'id' => array(
+ 'type' => 'integer',
+ 'null' => false,
+ 'default' => null,
+ 'length' => $intLength,
+ 'key' => 'primary'
+ ),
+ 'user' => array(
+ 'type' => 'string',
+ 'null' => false,
+ 'default' => '',
+ 'length' => 255
+ ),
+ 'password' => array(
+ 'type' => 'string',
+ 'null' => false,
+ 'default' => '',
+ 'length' => 255
+ ),
+ 'created' => array(
+ 'type' => 'datetime',
+ 'null' => true,
+ 'default' => null,
+ 'length' => null
+ ),
+ 'updated'=> array(
+ 'type' => 'datetime',
+ 'null' => true,
+ 'default' => null,
+ 'length' => null
+ ));
+
+ $this->assertEqual($result, $expected);
+
+ $TestModel =& new Article();
+ $result = $TestModel->create();
+ $expected = array('Article' => array('published' => 'N'));
+ $this->assertEqual($result, $expected);
+
+ $FeaturedModel =& new Featured();
+ $data = array(
+ 'article_featured_id' => 1,
+ 'category_id' => 1,
+ 'published_date' => array(
+ 'year' => 2008,
+ 'month' => 06,
+ 'day' => 11
+ ),
+ 'end_date' => array(
+ 'year' => 2008,
+ 'month' => 06,
+ 'day' => 20
+ ));
+
+ $expected = array(
+ 'Featured' => array(
+ 'article_featured_id' => 1,
+ 'category_id' => 1,
+ 'published_date' => '2008-6-11 00:00:00',
+ 'end_date' => '2008-6-20 00:00:00'
+ ));
+
+ $this->assertEqual($FeaturedModel->create($data), $expected);
+
+ $data = array(
+ 'published_date' => array(
+ 'year' => 2008,
+ 'month' => 06,
+ 'day' => 11
+ ),
+ 'end_date' => array(
+ 'year' => 2008,
+ 'month' => 06,
+ 'day' => 20
+ ),
+ 'article_featured_id' => 1,
+ 'category_id' => 1
+ );
+
+ $expected = array(
+ 'Featured' => array(
+ 'published_date' => '2008-6-11 00:00:00',
+ 'end_date' => '2008-6-20 00:00:00',
+ 'article_featured_id' => 1,
+ 'category_id' => 1
+ ));
+
+ $this->assertEqual($FeaturedModel->create($data), $expected);
+ }
+
+/**
+ * testEscapeField to prove it escapes the field well even when it has part of the alias on it
+ * @see ttp://cakephp.lighthouseapp.com/projects/42648-cakephp-1x/tickets/473-escapefield-doesnt-consistently-prepend-modelname
+ *
+ * @access public
+ * @return void
+ */
+ function testEscapeField() {
+ $TestModel =& new Test();
+ $db =& $TestModel->getDataSource();
+
+ $result = $TestModel->escapeField('test_field');
+ $expected = $db->name('Test.test_field');
+ $this->assertEqual($result, $expected);
+
+ $result = $TestModel->escapeField('TestField');
+ $expected = $db->name('Test.TestField');
+ $this->assertEqual($result, $expected);
+
+ $result = $TestModel->escapeField('DomainHandle', 'Domain');
+ $expected = $db->name('Domain.DomainHandle');
+ $this->assertEqual($result, $expected);
+
+ ConnectionManager::create('mock', array('driver' => 'mock'));
+ $TestModel->setDataSource('mock');
+ $db =& $TestModel->getDataSource();
+
+ $result = $TestModel->escapeField('DomainHandle', 'Domain');
+ $expected = $db->name('Domain.DomainHandle');
+ $this->assertEqual($result, $expected);
+ }
+}
diff --git a/code/ryzom/tools/server/www/webtt/cake/tests/cases/libs/model/model_read.test.php b/code/ryzom/tools/server/www/webtt/cake/tests/cases/libs/model/model_read.test.php
new file mode 100755
index 000000000..d59af8988
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/cake/tests/cases/libs/model/model_read.test.php
@@ -0,0 +1,7456 @@
+
+ * Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
+ *
+ * Licensed under The Open Group Test Suite License
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
+ * @link http://book.cakephp.org/view/1196/Testing CakePHP(tm) Tests
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ * @since CakePHP(tm) v 1.2.0.4206
+ * @license http://www.opensource.org/licenses/opengroup.php The Open Group Test Suite License
+ */
+require_once dirname(__FILE__) . DS . 'model.test.php';
+/**
+ * ModelReadTest
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model.operations
+ */
+class ModelReadTest extends BaseModelTest {
+
+/**
+ * testFetchingNonUniqueFKJoinTableRecords()
+ *
+ * Tests if the results are properly returned in the case there are non-unique FK's
+ * in the join table but another fields value is different. For example:
+ * something_id | something_else_id | doomed = 1
+ * something_id | something_else_id | doomed = 0
+ * Should return both records and not just one.
+ *
+ * @access public
+ * @return void
+ */
+ function testFetchingNonUniqueFKJoinTableRecords() {
+ $this->loadFixtures('Something', 'SomethingElse', 'JoinThing');
+ $Something = new Something();
+
+ $joinThingData = array(
+ 'JoinThing' => array(
+ 'something_id' => 1,
+ 'something_else_id' => 2,
+ 'doomed' => '0',
+ 'created' => '2007-03-18 10:39:23',
+ 'updated' => '2007-03-18 10:41:31'
+ )
+ );
+
+ $Something->JoinThing->create($joinThingData);
+ $Something->JoinThing->save();
+
+ $result = $Something->JoinThing->find('all', array('conditions' => array('something_else_id' => 2)));
+ $this->assertEqual($result[0]['JoinThing']['doomed'], true);
+ $this->assertEqual($result[1]['JoinThing']['doomed'], false);
+
+ $result = $Something->find('first');
+ $this->assertEqual(count($result['SomethingElse']), 2);
+
+ $doomed = Set::extract('/JoinThing/doomed', $result['SomethingElse']);
+ $this->assertTrue(in_array(true, $doomed));
+ $this->assertTrue(in_array(false, $doomed));
+ }
+
+/**
+ * testGroupBy method
+ *
+ * These tests will never pass with Postgres or Oracle as all fields in a select must be
+ * part of an aggregate function or in the GROUP BY statement.
+ *
+ * @access public
+ * @return void
+ */
+ function testGroupBy() {
+ $db = ConnectionManager::getDataSource('test_suite');
+ $isStrictGroupBy = in_array($db->config['driver'], array('postgres', 'oracle'));
+ $message = '%s Postgres and Oracle have strict GROUP BY and are incompatible with this test.';
+
+ if ($this->skipIf($isStrictGroupBy, $message )) {
+ return;
+ }
+
+ $this->loadFixtures('Project', 'Product', 'Thread', 'Message', 'Bid');
+ $Thread =& new Thread();
+ $Product =& new Product();
+
+ $result = $Thread->find('all', array(
+ 'group' => 'Thread.project_id',
+ 'order' => 'Thread.id ASC'
+ ));
+
+ $expected = array(
+ array(
+ 'Thread' => array(
+ 'id' => 1,
+ 'project_id' => 1,
+ 'name' => 'Project 1, Thread 1'
+ ),
+ 'Project' => array(
+ 'id' => 1,
+ 'name' => 'Project 1'
+ ),
+ 'Message' => array(
+ array(
+ 'id' => 1,
+ 'thread_id' => 1,
+ 'name' => 'Thread 1, Message 1'
+ ))),
+ array(
+ 'Thread' => array(
+ 'id' => 3,
+ 'project_id' => 2,
+ 'name' => 'Project 2, Thread 1'
+ ),
+ 'Project' => array(
+ 'id' => 2,
+ 'name' => 'Project 2'
+ ),
+ 'Message' => array(
+ array(
+ 'id' => 3,
+ 'thread_id' => 3,
+ 'name' => 'Thread 3, Message 1'
+ ))));
+ $this->assertEqual($result, $expected);
+
+ $rows = $Thread->find('all', array(
+ 'group' => 'Thread.project_id',
+ 'fields' => array('Thread.project_id', 'COUNT(*) AS total')
+ ));
+ $result = array();
+ foreach($rows as $row) {
+ $result[$row['Thread']['project_id']] = $row[0]['total'];
+ }
+ $expected = array(
+ 1 => 2,
+ 2 => 1
+ );
+ $this->assertEqual($result, $expected);
+
+ $rows = $Thread->find('all', array(
+ 'group' => 'Thread.project_id',
+ 'fields' => array('Thread.project_id', 'COUNT(*) AS total'),
+ 'order'=> 'Thread.project_id'
+ ));
+ $result = array();
+ foreach($rows as $row) {
+ $result[$row['Thread']['project_id']] = $row[0]['total'];
+ }
+ $expected = array(
+ 1 => 2,
+ 2 => 1
+ );
+ $this->assertEqual($result, $expected);
+
+ $result = $Thread->find('all', array(
+ 'conditions' => array('Thread.project_id' => 1),
+ 'group' => 'Thread.project_id'
+ ));
+ $expected = array(
+ array(
+ 'Thread' => array(
+ 'id' => 1,
+ 'project_id' => 1,
+ 'name' => 'Project 1, Thread 1'
+ ),
+ 'Project' => array(
+ 'id' => 1,
+ 'name' => 'Project 1'
+ ),
+ 'Message' => array(
+ array(
+ 'id' => 1,
+ 'thread_id' => 1,
+ 'name' => 'Thread 1, Message 1'
+ ))));
+ $this->assertEqual($result, $expected);
+
+ $result = $Thread->find('all', array(
+ 'conditions' => array('Thread.project_id' => 1),
+ 'group' => 'Thread.project_id, Project.id'
+ ));
+ $this->assertEqual($result, $expected);
+
+ $result = $Thread->find('all', array(
+ 'conditions' => array('Thread.project_id' => 1),
+ 'group' => 'project_id'
+ ));
+ $this->assertEqual($result, $expected);
+
+ $result = $Thread->find('all', array(
+ 'conditions' => array('Thread.project_id' => 1),
+ 'group' => array('project_id')
+ ));
+ $this->assertEqual($result, $expected);
+
+ $result = $Thread->find('all', array(
+ 'conditions' => array('Thread.project_id' => 1),
+ 'group' => array('project_id', 'Project.id')
+ ));
+ $this->assertEqual($result, $expected);
+
+ $result = $Thread->find('all', array(
+ 'conditions' => array('Thread.project_id' => 1),
+ 'group' => array('Thread.project_id', 'Project.id')
+ ));
+ $this->assertEqual($result, $expected);
+
+ $expected = array(
+ array('Product' => array('type' => 'Clothing'), array('price' => 32)),
+ array('Product' => array('type' => 'Food'), array('price' => 9)),
+ array('Product' => array('type' => 'Music'), array( 'price' => 4)),
+ array('Product' => array('type' => 'Toy'), array('price' => 3))
+ );
+ $result = $Product->find('all',array(
+ 'fields'=>array('Product.type', 'MIN(Product.price) as price'),
+ 'group'=> 'Product.type',
+ 'order' => 'Product.type ASC'
+ ));
+ $this->assertEqual($result, $expected);
+
+ $result = $Product->find('all', array(
+ 'fields'=>array('Product.type', 'MIN(Product.price) as price'),
+ 'group'=> array('Product.type'),
+ 'order' => 'Product.type ASC'));
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testOldQuery method
+ *
+ * @access public
+ * @return void
+ */
+ function testOldQuery() {
+ $this->loadFixtures('Article');
+ $Article =& new Article();
+
+ $query = 'SELECT title FROM ';
+ $query .= $this->db->fullTableName('articles');
+ $query .= ' WHERE ' . $this->db->fullTableName('articles') . '.id IN (1,2)';
+
+ $results = $Article->query($query);
+ $this->assertTrue(is_array($results));
+ $this->assertEqual(count($results), 2);
+
+ $query = 'SELECT title, body FROM ';
+ $query .= $this->db->fullTableName('articles');
+ $query .= ' WHERE ' . $this->db->fullTableName('articles') . '.id = 1';
+
+ $results = $Article->query($query, false);
+ $this->assertTrue(!isset($this->db->_queryCache[$query]));
+ $this->assertTrue(is_array($results));
+
+ $query = 'SELECT title, id FROM ';
+ $query .= $this->db->fullTableName('articles');
+ $query .= ' WHERE ' . $this->db->fullTableName('articles');
+ $query .= '.published = ' . $this->db->value('Y');
+
+ $results = $Article->query($query, true);
+ $this->assertTrue(isset($this->db->_queryCache[$query]));
+ $this->assertTrue(is_array($results));
+ }
+
+/**
+ * testPreparedQuery method
+ *
+ * @access public
+ * @return void
+ */
+ function testPreparedQuery() {
+ $this->loadFixtures('Article');
+ $Article =& new Article();
+ $this->db->_queryCache = array();
+
+ $finalQuery = 'SELECT title, published FROM ';
+ $finalQuery .= $this->db->fullTableName('articles');
+ $finalQuery .= ' WHERE ' . $this->db->fullTableName('articles');
+ $finalQuery .= '.id = ' . $this->db->value(1);
+ $finalQuery .= ' AND ' . $this->db->fullTableName('articles');
+ $finalQuery .= '.published = ' . $this->db->value('Y');
+
+ $query = 'SELECT title, published FROM ';
+ $query .= $this->db->fullTableName('articles');
+ $query .= ' WHERE ' . $this->db->fullTableName('articles');
+ $query .= '.id = ? AND ' . $this->db->fullTableName('articles') . '.published = ?';
+
+ $params = array(1, 'Y');
+ $result = $Article->query($query, $params);
+ $expected = array(
+ '0' => array(
+ $this->db->fullTableName('articles', false) => array(
+ 'title' => 'First Article', 'published' => 'Y')
+ ));
+
+ if (isset($result[0][0])) {
+ $expected[0][0] = $expected[0][$this->db->fullTableName('articles', false)];
+ unset($expected[0][$this->db->fullTableName('articles', false)]);
+ }
+
+ $this->assertEqual($result, $expected);
+ $this->assertTrue(isset($this->db->_queryCache[$finalQuery]));
+
+ $finalQuery = 'SELECT id, created FROM ';
+ $finalQuery .= $this->db->fullTableName('articles');
+ $finalQuery .= ' WHERE ' . $this->db->fullTableName('articles');
+ $finalQuery .= '.title = ' . $this->db->value('First Article');
+
+ $query = 'SELECT id, created FROM ';
+ $query .= $this->db->fullTableName('articles');
+ $query .= ' WHERE ' . $this->db->fullTableName('articles') . '.title = ?';
+
+ $params = array('First Article');
+ $result = $Article->query($query, $params, false);
+ $this->assertTrue(is_array($result));
+ $this->assertTrue(
+ isset($result[0][$this->db->fullTableName('articles', false)])
+ || isset($result[0][0])
+ );
+ $this->assertFalse(isset($this->db->_queryCache[$finalQuery]));
+
+ $query = 'SELECT title FROM ';
+ $query .= $this->db->fullTableName('articles');
+ $query .= ' WHERE ' . $this->db->fullTableName('articles') . '.title LIKE ?';
+
+ $params = array('%First%');
+ $result = $Article->query($query, $params);
+ $this->assertTrue(is_array($result));
+ $this->assertTrue(
+ isset($result[0][$this->db->fullTableName('articles', false)]['title'])
+ || isset($result[0][0]['title'])
+ );
+
+ //related to ticket #5035
+ $query = 'SELECT title FROM ';
+ $query .= $this->db->fullTableName('articles') . ' WHERE title = ? AND published = ?';
+ $params = array('First? Article', 'Y');
+ $Article->query($query, $params);
+
+ $expected = 'SELECT title FROM ';
+ $expected .= $this->db->fullTableName('articles');
+ $expected .= " WHERE title = 'First? Article' AND published = 'Y'";
+ $this->assertTrue(isset($this->db->_queryCache[$expected]));
+
+ }
+
+/**
+ * testParameterMismatch method
+ *
+ * @access public
+ * @return void
+ */
+ function testParameterMismatch() {
+ $this->loadFixtures('Article');
+ $Article =& new Article();
+
+ $query = 'SELECT * FROM ' . $this->db->fullTableName('articles');
+ $query .= ' WHERE ' . $this->db->fullTableName('articles');
+ $query .= '.published = ? AND ' . $this->db->fullTableName('articles') . '.user_id = ?';
+ $params = array('Y');
+ $this->expectError();
+
+ ob_start();
+ $result = $Article->query($query, $params);
+ ob_end_clean();
+ $this->assertEqual($result, null);
+ }
+
+/**
+ * testVeryStrangeUseCase method
+ *
+ * @access public
+ * @return void
+ */
+ function testVeryStrangeUseCase() {
+ $message = "%s skipping SELECT * FROM ? WHERE ? = ? AND ? = ?; prepared query.";
+ $message .= " MSSQL is incompatible with this test.";
+
+ if ($this->skipIf($this->db->config['driver'] == 'mssql', $message)) {
+ return;
+ }
+
+ $this->loadFixtures('Article');
+ $Article =& new Article();
+
+ $query = 'SELECT * FROM ? WHERE ? = ? AND ? = ?';
+ $param = array(
+ $this->db->fullTableName('articles'),
+ $this->db->fullTableName('articles') . '.user_id', '3',
+ $this->db->fullTableName('articles') . '.published', 'Y'
+ );
+ $this->expectError();
+
+ ob_start();
+ $result = $Article->query($query, $param);
+ ob_end_clean();
+ }
+
+/**
+ * testRecursiveUnbind method
+ *
+ * @access public
+ * @return void
+ */
+ function testRecursiveUnbind() {
+ $this->loadFixtures('Apple', 'Sample');
+ $TestModel =& new Apple();
+ $TestModel->recursive = 2;
+
+ $result = $TestModel->find('all');
+ $expected = array(
+ array(
+ 'Apple' => array (
+ 'id' => 1,
+ 'apple_id' => 2,
+ 'color' => 'Red 1',
+ 'name' => 'Red Apple 1',
+ 'created' => '2006-11-22 10:38:58',
+ 'date' => '1951-01-04',
+ 'modified' => '2006-12-01 13:31:26',
+ 'mytime' => '22:57:17'
+ ),
+ 'Parent' => array(
+ 'id' => 2,
+ 'apple_id' => 1,
+ 'color' => 'Bright Red 1',
+ 'name' => 'Bright Red Apple',
+ 'created' => '2006-11-22 10:43:13',
+ 'date' => '2014-01-01',
+ 'modified' => '2006-11-30 18:38:10',
+ 'mytime' => '22:57:17',
+ 'Parent' => array(
+ 'id' => 1,
+ 'apple_id' => 2,
+ 'color' => 'Red 1',
+ 'name' => 'Red Apple 1',
+ 'created' => '2006-11-22 10:38:58',
+ 'date' => '1951-01-04',
+ 'modified' => '2006-12-01 13:31:26',
+ 'mytime' => '22:57:17'
+ ),
+ 'Sample' => array(
+ 'id' => 2,
+ 'apple_id' => 2,
+ 'name' => 'sample2'
+ ),
+ 'Child' => array(
+ array(
+ 'id' => 1,
+ 'apple_id' => 2,
+ 'color' => 'Red 1',
+ 'name' => 'Red Apple 1',
+ 'created' => '2006-11-22 10:38:58',
+ 'date' => '1951-01-04',
+ 'modified' => '2006-12-01 13:31:26',
+ 'mytime' => '22:57:17'
+ ),
+ array(
+ 'id' => 3,
+ 'apple_id' => 2,
+ 'color' => 'blue green',
+ 'name' => 'green blue',
+ 'created' => '2006-12-25 05:13:36',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:23:24',
+ 'mytime' => '22:57:17'
+ ),
+ array(
+ 'id' => 4,
+ 'apple_id' => 2,
+ 'color' => 'Blue Green',
+ 'name' => 'Test Name',
+ 'created' => '2006-12-25 05:23:36',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:23:36',
+ 'mytime' => '22:57:17'
+ ))),
+ 'Sample' => array(
+ 'id' =>'',
+ 'apple_id' => '',
+ 'name' => ''
+ ),
+ 'Child' => array(
+ array(
+ 'id' => 2,
+ 'apple_id' => 1,
+ 'color' => 'Bright Red 1',
+ 'name' => 'Bright Red Apple',
+ 'created' => '2006-11-22 10:43:13',
+ 'date' => '2014-01-01',
+ 'modified' => '2006-11-30 18:38:10',
+ 'mytime' => '22:57:17',
+ 'Parent' => array(
+ 'id' => 1,
+ 'apple_id' => 2,
+ 'color' => 'Red 1',
+ 'name' => 'Red Apple 1',
+ 'created' => '2006-11-22 10:38:58',
+ 'date' => '1951-01-04',
+ 'modified' => '2006-12-01 13:31:26',
+ 'mytime' => '22:57:17'
+ ),
+ 'Sample' => array(
+ 'id' => 2,
+ 'apple_id' => 2,
+ 'name' => 'sample2'
+ ),
+ 'Child' => array(
+ array(
+ 'id' => 1,
+ 'apple_id' => 2,
+ 'color' => 'Red 1',
+ 'name' => 'Red Apple 1',
+ 'created' => '2006-11-22 10:38:58',
+ 'date' => '1951-01-04',
+ 'modified' => '2006-12-01 13:31:26',
+ 'mytime' => '22:57:17'
+ ),
+ array(
+ 'id' => 3,
+ 'apple_id' => 2,
+ 'color' => 'blue green',
+ 'name' => 'green blue',
+ 'created' => '2006-12-25 05:13:36',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:23:24',
+ 'mytime' => '22:57:17'
+ ),
+ array(
+ 'id' => 4,
+ 'apple_id' => 2,
+ 'color' => 'Blue Green',
+ 'name' => 'Test Name',
+ 'created' => '2006-12-25 05:23:36',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:23:36',
+ 'mytime' => '22:57:17'
+ ))))),
+ array(
+ 'Apple' => array(
+ 'id' => 2,
+ 'apple_id' => 1,
+ 'color' => 'Bright Red 1',
+ 'name' => 'Bright Red Apple',
+ 'created' => '2006-11-22 10:43:13',
+ 'date' => '2014-01-01',
+ 'modified' => '2006-11-30 18:38:10',
+ 'mytime' => '22:57:17'
+ ),
+ 'Parent' => array(
+ 'id' => 1,
+ 'apple_id' => 2,
+ 'color' => 'Red 1',
+ 'name' => 'Red Apple 1',
+ 'created' => '2006-11-22 10:38:58',
+ 'date' => '1951-01-04',
+ 'modified' => '2006-12-01 13:31:26',
+ 'mytime' => '22:57:17',
+ 'Parent' => array(
+ 'id' => 2,
+ 'apple_id' => 1,
+ 'color' => 'Bright Red 1',
+ 'name' => 'Bright Red Apple',
+ 'created' => '2006-11-22 10:43:13',
+ 'date' => '2014-01-01',
+ 'modified' => '2006-11-30 18:38:10',
+ 'mytime' => '22:57:17'
+ ),
+ 'Sample' => array(),
+ 'Child' => array(
+ array(
+ 'id' => 2,
+ 'apple_id' => 1,
+ 'color' => 'Bright Red 1',
+ 'name' => 'Bright Red Apple',
+ 'created' => '2006-11-22 10:43:13',
+ 'date' => '2014-01-01',
+ 'modified' => '2006-11-30 18:38:10',
+ 'mytime' => '22:57:17'
+ ))),
+ 'Sample' => array(
+ 'id' => 2,
+ 'apple_id' => 2,
+ 'name' => 'sample2',
+ 'Apple' => array(
+ 'id' => 2,
+ 'apple_id' => 1,
+ 'color' => 'Bright Red 1',
+ 'name' => 'Bright Red Apple',
+ 'created' => '2006-11-22 10:43:13',
+ 'date' => '2014-01-01',
+ 'modified' => '2006-11-30 18:38:10',
+ 'mytime' => '22:57:17'
+ )),
+ 'Child' => array(
+ array(
+ 'id' => 1,
+ 'apple_id' => 2,
+ 'color' => 'Red 1',
+ 'name' => 'Red Apple 1',
+ 'created' => '2006-11-22 10:38:58',
+ 'date' => '1951-01-04',
+ 'modified' => '2006-12-01 13:31:26',
+ 'mytime' => '22:57:17',
+ 'Parent' => array(
+ 'id' => 2,
+ 'apple_id' => 1,
+ 'color' => 'Bright Red 1',
+ 'name' => 'Bright Red Apple',
+ 'created' => '2006-11-22 10:43:13',
+ 'date' => '2014-01-01',
+ 'modified' => '2006-11-30 18:38:10',
+ 'mytime' => '22:57:17'
+ ),
+ 'Sample' => array(),
+ 'Child' => array(
+ array(
+ 'id' => 2,
+ 'apple_id' => 1,
+ 'color' => 'Bright Red 1',
+ 'name' => 'Bright Red Apple',
+ 'created' => '2006-11-22 10:43:13',
+ 'date' => '2014-01-01',
+ 'modified' => '2006-11-30 18:38:10',
+ 'mytime' => '22:57:17'
+ ))),
+ array(
+ 'id' => 3,
+ 'apple_id' => 2,
+ 'color' => 'blue green',
+ 'name' => 'green blue',
+ 'created' => '2006-12-25 05:13:36',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:23:24',
+ 'mytime' => '22:57:17',
+ 'Parent' => array(
+ 'id' => 2,
+ 'apple_id' => 1,
+ 'color' => 'Bright Red 1',
+ 'name' => 'Bright Red Apple',
+ 'created' => '2006-11-22 10:43:13',
+ 'date' => '2014-01-01',
+ 'modified' => '2006-11-30 18:38:10',
+ 'mytime' => '22:57:17'
+ ),
+ 'Sample' => array(
+ 'id' => 1,
+ 'apple_id' => 3,
+ 'name' => 'sample1'
+ )),
+ array(
+ 'id' => 4,
+ 'apple_id' => 2,
+ 'color' => 'Blue Green',
+ 'name' => 'Test Name',
+ 'created' => '2006-12-25 05:23:36',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:23:36',
+ 'mytime' => '22:57:17',
+ 'Parent' => array(
+ 'id' => 2,
+ 'apple_id' => 1,
+ 'color' => 'Bright Red 1',
+ 'name' => 'Bright Red Apple',
+ 'created' => '2006-11-22 10:43:13',
+ 'date' => '2014-01-01',
+ 'modified' => '2006-11-30 18:38:10',
+ 'mytime' => '22:57:17'
+ ),
+ 'Sample' => array(
+ 'id' => 3,
+ 'apple_id' => 4,
+ 'name' => 'sample3'
+ ),
+ 'Child' => array(
+ array(
+ 'id' => 6,
+ 'apple_id' => 4,
+ 'color' => 'My new appleOrange',
+ 'name' => 'My new apple',
+ 'created' => '2006-12-25 05:29:39',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:29:39',
+ 'mytime' => '22:57:17'
+ ))))),
+ array(
+ 'Apple' => array(
+ 'id' => 3,
+ 'apple_id' => 2,
+ 'color' => 'blue green',
+ 'name' => 'green blue',
+ 'created' => '2006-12-25 05:13:36',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:23:24',
+ 'mytime' => '22:57:17'
+ ),
+ 'Parent' => array(
+ 'id' => 2,
+ 'apple_id' => 1,
+ 'color' => 'Bright Red 1',
+ 'name' => 'Bright Red Apple',
+ 'created' => '2006-11-22 10:43:13',
+ 'date' => '2014-01-01',
+ 'modified' => '2006-11-30 18:38:10',
+ 'mytime' => '22:57:17',
+ 'Parent' => array(
+ 'id' => 1,
+ 'apple_id' => 2,
+ 'color' => 'Red 1',
+ 'name' => 'Red Apple 1',
+ 'created' => '2006-11-22 10:38:58',
+ 'date' => '1951-01-04',
+ 'modified' => '2006-12-01 13:31:26',
+ 'mytime' => '22:57:17'
+ ),
+ 'Sample' => array(
+ 'id' => 2,
+ 'apple_id' => 2,
+ 'name' => 'sample2'
+ ),
+ 'Child' => array(
+ array(
+ 'id' => 1,
+ 'apple_id' => 2,
+ 'color' => 'Red 1',
+ 'name' => 'Red Apple 1',
+ 'created' => '2006-11-22 10:38:58',
+ 'date' => '1951-01-04',
+ 'modified' => '2006-12-01 13:31:26',
+ 'mytime' => '22:57:17'
+ ),
+ array(
+ 'id' => 3,
+ 'apple_id' => 2,
+ 'color' => 'blue green',
+ 'name' => 'green blue',
+ 'created' => '2006-12-25 05:13:36',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:23:24',
+ 'mytime' => '22:57:17'
+ ),
+ array(
+ 'id' => 4,
+ 'apple_id' => 2,
+ 'color' => 'Blue Green',
+ 'name' => 'Test Name',
+ 'created' => '2006-12-25 05:23:36',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:23:36',
+ 'mytime' => '22:57:17'
+ ))),
+ 'Sample' => array(
+ 'id' => 1,
+ 'apple_id' => 3,
+ 'name' => 'sample1',
+ 'Apple' => array(
+ 'id' => 3,
+ 'apple_id' => 2,
+ 'color' => 'blue green',
+ 'name' => 'green blue',
+ 'created' => '2006-12-25 05:13:36',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:23:24',
+ 'mytime' => '22:57:17'
+ )),
+ 'Child' => array()
+ ),
+ array(
+ 'Apple' => array(
+ 'id' => 4,
+ 'apple_id' => 2,
+ 'color' => 'Blue Green',
+ 'name' => 'Test Name',
+ 'created' => '2006-12-25 05:23:36',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:23:36',
+ 'mytime' => '22:57:17'
+ ),
+ 'Parent' => array(
+ 'id' => 2,
+ 'apple_id' => 1,
+ 'color' => 'Bright Red 1',
+ 'name' => 'Bright Red Apple',
+ 'created' => '2006-11-22 10:43:13',
+ 'date' => '2014-01-01',
+ 'modified' => '2006-11-30 18:38:10',
+ 'mytime' => '22:57:17',
+ 'Parent' => array(
+ 'id' => 1,
+ 'apple_id' => 2,
+ 'color' => 'Red 1',
+ 'name' => 'Red Apple 1',
+ 'created' => '2006-11-22 10:38:58',
+ 'date' => '1951-01-04',
+ 'modified' => '2006-12-01 13:31:26', 'mytime' => '22:57:17'),
+ 'Sample' => array('id' => 2, 'apple_id' => 2, 'name' => 'sample2'),
+ 'Child' => array(
+ array(
+ 'id' => 1,
+ 'apple_id' => 2,
+ 'color' => 'Red 1',
+ 'name' => 'Red Apple 1',
+ 'created' => '2006-11-22 10:38:58',
+ 'date' => '1951-01-04',
+ 'modified' => '2006-12-01 13:31:26',
+ 'mytime' => '22:57:17'
+ ),
+ array(
+ 'id' => 3,
+ 'apple_id' => 2,
+ 'color' => 'blue green',
+ 'name' => 'green blue',
+ 'created' => '2006-12-25 05:13:36',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:23:24',
+ 'mytime' => '22:57:17'
+ ),
+ array(
+ 'id' => 4,
+ 'apple_id' => 2,
+ 'color' => 'Blue Green',
+ 'name' => 'Test Name',
+ 'created' => '2006-12-25 05:23:36',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:23:36',
+ 'mytime' => '22:57:17'
+ ))),
+ 'Sample' => array(
+ 'id' => 3,
+ 'apple_id' => 4,
+ 'name' => 'sample3',
+ 'Apple' => array(
+ 'id' => 4,
+ 'apple_id' => 2,
+ 'color' => 'Blue Green',
+ 'name' => 'Test Name',
+ 'created' => '2006-12-25 05:23:36',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:23:36',
+ 'mytime' => '22:57:17'
+ )),
+ 'Child' => array(
+ array(
+ 'id' => 6,
+ 'apple_id' => 4,
+ 'color' => 'My new appleOrange',
+ 'name' => 'My new apple',
+ 'created' => '2006-12-25 05:29:39',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:29:39',
+ 'mytime' => '22:57:17',
+ 'Parent' => array(
+ 'id' => 4,
+ 'apple_id' => 2,
+ 'color' => 'Blue Green',
+ 'name' => 'Test Name',
+ 'created' => '2006-12-25 05:23:36',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:23:36',
+ 'mytime' => '22:57:17'
+ ),
+ 'Sample' => array(),
+ 'Child' => array(
+ array(
+ 'id' => 7,
+ 'apple_id' => 6,
+ 'color' => 'Some wierd color',
+ 'name' => 'Some odd color',
+ 'created' => '2006-12-25 05:34:21',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:34:21',
+ 'mytime' => '22:57:17'
+ ))))),
+ array(
+ 'Apple' => array(
+ 'id' => 5,
+ 'apple_id' => 5,
+ 'color' => 'Green',
+ 'name' => 'Blue Green',
+ 'created' => '2006-12-25 05:24:06',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:29:16',
+ 'mytime' => '22:57:17'
+ ),
+ 'Parent' => array(
+ 'id' => 5,
+ 'apple_id' => 5,
+ 'color' => 'Green',
+ 'name' => 'Blue Green',
+ 'created' => '2006-12-25 05:24:06',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:29:16',
+ 'mytime' => '22:57:17',
+ 'Parent' => array(
+ 'id' => 5,
+ 'apple_id' => 5,
+ 'color' => 'Green',
+ 'name' => 'Blue Green',
+ 'created' => '2006-12-25 05:24:06',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:29:16',
+ 'mytime' => '22:57:17'
+ ),
+ 'Sample' => array(
+ 'id' => 4,
+ 'apple_id' => 5,
+ 'name' => 'sample4'
+ ),
+ 'Child' => array(
+ array(
+ 'id' => 5,
+ 'apple_id' => 5,
+ 'color' => 'Green',
+ 'name' => 'Blue Green',
+ 'created' => '2006-12-25 05:24:06',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:29:16',
+ 'mytime' => '22:57:17'
+ ))),
+ 'Sample' => array(
+ 'id' => 4,
+ 'apple_id' => 5,
+ 'name' => 'sample4',
+ 'Apple' => array(
+ 'id' => 5,
+ 'apple_id' => 5,
+ 'color' => 'Green',
+ 'name' => 'Blue Green',
+ 'created' => '2006-12-25 05:24:06',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:29:16',
+ 'mytime' => '22:57:17'
+ )),
+ 'Child' => array(
+ array(
+ 'id' => 5,
+ 'apple_id' => 5,
+ 'color' => 'Green',
+ 'name' => 'Blue Green',
+ 'created' => '2006-12-25 05:24:06',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:29:16',
+ 'mytime' => '22:57:17',
+ 'Parent' => array(
+ 'id' => 5,
+ 'apple_id' => 5,
+ 'color' => 'Green',
+ 'name' => 'Blue Green',
+ 'created' => '2006-12-25 05:24:06',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:29:16',
+ 'mytime' => '22:57:17'
+ ),
+ 'Sample' => array(
+ 'id' => 4,
+ 'apple_id' => 5,
+ 'name' => 'sample4'
+ ),
+ 'Child' => array(
+ array(
+ 'id' => 5,
+ 'apple_id' => 5,
+ 'color' => 'Green',
+ 'name' => 'Blue Green',
+ 'created' => '2006-12-25 05:24:06',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:29:16',
+ 'mytime' => '22:57:17'
+ ))))),
+ array(
+ 'Apple' => array(
+ 'id' => 6,
+ 'apple_id' => 4,
+ 'color' => 'My new appleOrange',
+ 'name' => 'My new apple',
+ 'created' => '2006-12-25 05:29:39',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:29:39',
+ 'mytime' => '22:57:17'
+ ),
+ 'Parent' => array(
+ 'id' => 4,
+ 'apple_id' => 2,
+ 'color' => 'Blue Green',
+ 'name' => 'Test Name',
+ 'created' => '2006-12-25 05:23:36',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:23:36',
+ 'mytime' => '22:57:17',
+ 'Parent' => array(
+ 'id' => 2,
+ 'apple_id' => 1,
+ 'color' => 'Bright Red 1',
+ 'name' => 'Bright Red Apple',
+ 'created' => '2006-11-22 10:43:13',
+ 'date' => '2014-01-01',
+ 'modified' => '2006-11-30 18:38:10',
+ 'mytime' => '22:57:17'
+ ),
+ 'Sample' => array(
+ 'id' => 3,
+ 'apple_id' => 4,
+ 'name' => 'sample3'
+ ),
+ 'Child' => array(
+ array(
+ 'id' => 6,
+ 'apple_id' => 4,
+ 'color' => 'My new appleOrange',
+ 'name' => 'My new apple',
+ 'created' => '2006-12-25 05:29:39',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:29:39',
+ 'mytime' => '22:57:17'
+ ))),
+ 'Sample' => array(
+ 'id' => '',
+ 'apple_id' => '',
+ 'name' => ''
+ ),
+ 'Child' => array(
+ array(
+ 'id' => 7,
+ 'apple_id' => 6,
+ 'color' => 'Some wierd color',
+ 'name' => 'Some odd color',
+ 'created' => '2006-12-25 05:34:21',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:34:21',
+ 'mytime' => '22:57:17',
+ 'Parent' => array(
+ 'id' => 6,
+ 'apple_id' => 4,
+ 'color' => 'My new appleOrange',
+ 'name' => 'My new apple',
+ 'created' => '2006-12-25 05:29:39',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:29:39',
+ 'mytime' => '22:57:17'
+ ),
+ 'Sample' => array()
+ ))),
+ array(
+ 'Apple' => array(
+ 'id' => 7,
+ 'apple_id' => 6,
+ 'color' =>
+ 'Some wierd color',
+ 'name' => 'Some odd color',
+ 'created' => '2006-12-25 05:34:21',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:34:21',
+ 'mytime' => '22:57:17'
+ ),
+ 'Parent' => array(
+ 'id' => 6,
+ 'apple_id' => 4,
+ 'color' => 'My new appleOrange',
+ 'name' => 'My new apple',
+ 'created' => '2006-12-25 05:29:39',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:29:39',
+ 'mytime' => '22:57:17',
+ 'Parent' => array(
+ 'id' => 4,
+ 'apple_id' => 2,
+ 'color' => 'Blue Green',
+ 'name' => 'Test Name',
+ 'created' => '2006-12-25 05:23:36',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:23:36',
+ 'mytime' => '22:57:17'
+ ),
+ 'Sample' => array(),
+ 'Child' => array(
+ array(
+ 'id' => 7,
+ 'apple_id' => 6,
+ 'color' => 'Some wierd color',
+ 'name' => 'Some odd color',
+ 'created' => '2006-12-25 05:34:21',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:34:21',
+ 'mytime' => '22:57:17'
+ ))),
+ 'Sample' => array(
+ 'id' => '',
+ 'apple_id' => '',
+ 'name' => ''
+ ),
+ 'Child' => array()));
+ $this->assertEqual($result, $expected);
+
+ $result = $TestModel->Parent->unbindModel(array('hasOne' => array('Sample')));
+ $this->assertTrue($result);
+
+ $result = $TestModel->find('all');
+ $expected = array(
+ array(
+ 'Apple' => array(
+ 'id' => 1,
+ 'apple_id' => 2,
+ 'color' => 'Red 1',
+ 'name' => 'Red Apple 1',
+ 'created' => '2006-11-22 10:38:58',
+ 'date' => '1951-01-04',
+ 'modified' => '2006-12-01 13:31:26',
+ 'mytime' => '22:57:17'),
+ 'Parent' => array(
+ 'id' => 2,
+ 'apple_id' => 1,
+ 'color' => 'Bright Red 1',
+ 'name' => 'Bright Red Apple',
+ 'created' => '2006-11-22 10:43:13',
+ 'date' => '2014-01-01',
+ 'modified' => '2006-11-30 18:38:10',
+ 'mytime' => '22:57:17',
+ 'Parent' => array(
+ 'id' => 1,
+ 'apple_id' => 2,
+ 'color' => 'Red 1',
+ 'name' => 'Red Apple 1',
+ 'created' => '2006-11-22 10:38:58',
+ 'date' => '1951-01-04',
+ 'modified' => '2006-12-01 13:31:26',
+ 'mytime' => '22:57:17'
+ ),
+ 'Child' => array(
+ array(
+ 'id' => 1,
+ 'apple_id' => 2,
+ 'color' => 'Red 1',
+ 'name' => 'Red Apple 1',
+ 'created' => '2006-11-22 10:38:58',
+ 'date' => '1951-01-04',
+ 'modified' => '2006-12-01 13:31:26',
+ 'mytime' => '22:57:17'
+ ),
+ array(
+ 'id' => 3,
+ 'apple_id' => 2,
+ 'color' => 'blue green',
+ 'name' => 'green blue',
+ 'created' => '2006-12-25 05:13:36',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:23:24',
+ 'mytime' => '22:57:17'
+ ),
+ array(
+ 'id' => 4,
+ 'apple_id' => 2,
+ 'color' => 'Blue Green',
+ 'name' => 'Test Name',
+ 'created' => '2006-12-25 05:23:36',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:23:36',
+ 'mytime' => '22:57:17'
+ ))),
+ 'Sample' => array(
+ 'id' =>'',
+ 'apple_id' => '',
+ 'name' => ''
+ ),
+ 'Child' => array(
+ array(
+ 'id' => 2,
+ 'apple_id' => 1,
+ 'color' => 'Bright Red 1',
+ 'name' => 'Bright Red Apple',
+ 'created' => '2006-11-22 10:43:13',
+ 'date' => '2014-01-01',
+ 'modified' => '2006-11-30 18:38:10',
+ 'mytime' => '22:57:17',
+ 'Parent' => array(
+ 'id' => 1,
+ 'apple_id' => 2,
+ 'color' => 'Red 1',
+ 'name' => 'Red Apple 1',
+ 'created' => '2006-11-22 10:38:58',
+ 'date' => '1951-01-04',
+ 'modified' => '2006-12-01 13:31:26',
+ 'mytime' => '22:57:17'
+ ),
+ 'Sample' => array(
+ 'id' => 2,
+ 'apple_id' => 2,
+ 'name' => 'sample2'
+ ),
+ 'Child' => array(
+ array(
+ 'id' => 1,
+ 'apple_id' => 2,
+ 'color' => 'Red 1',
+ 'name' => 'Red Apple 1',
+ 'created' => '2006-11-22 10:38:58',
+ 'date' => '1951-01-04',
+ 'modified' => '2006-12-01 13:31:26',
+ 'mytime' => '22:57:17'
+ ),
+ array(
+ 'id' => 3,
+ 'apple_id' => 2,
+ 'color' => 'blue green',
+ 'name' => 'green blue',
+ 'created' => '2006-12-25 05:13:36',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:23:24',
+ 'mytime' => '22:57:17'
+ ),
+ array(
+ 'id' => 4,
+ 'apple_id' => 2,
+ 'color' => 'Blue Green',
+ 'name' => 'Test Name',
+ 'created' => '2006-12-25 05:23:36',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:23:36',
+ 'mytime' => '22:57:17'
+ ))))),
+ array(
+ 'Apple' => array(
+ 'id' => 2,
+ 'apple_id' => 1,
+ 'color' => 'Bright Red 1',
+ 'name' => 'Bright Red Apple',
+ 'created' => '2006-11-22 10:43:13',
+ 'date' => '2014-01-01',
+ 'modified' => '2006-11-30 18:38:10',
+ 'mytime' => '22:57:17'
+ ),
+ 'Parent' => array(
+ 'id' => 1,
+ 'apple_id' => 2,
+ 'color' => 'Red 1',
+ 'name' => 'Red Apple 1',
+ 'created' => '2006-11-22 10:38:58',
+ 'date' => '1951-01-04',
+ 'modified' => '2006-12-01 13:31:26',
+ 'mytime' => '22:57:17',
+ 'Parent' => array(
+ 'id' => 2,
+ 'apple_id' => 1,
+ 'color' => 'Bright Red 1',
+ 'name' => 'Bright Red Apple',
+ 'created' => '2006-11-22 10:43:13',
+ 'date' => '2014-01-01',
+ 'modified' => '2006-11-30 18:38:10',
+ 'mytime' => '22:57:17'
+ ),
+ 'Child' => array(
+ array(
+ 'id' => 2,
+ 'apple_id' => 1,
+ 'color' => 'Bright Red 1',
+ 'name' => 'Bright Red Apple',
+ 'created' => '2006-11-22 10:43:13',
+ 'date' => '2014-01-01',
+ 'modified' => '2006-11-30 18:38:10',
+ 'mytime' => '22:57:17'
+ ))),
+ 'Sample' => array(
+ 'id' => 2,
+ 'apple_id' => 2,
+ 'name' => 'sample2',
+ 'Apple' => array(
+ 'id' => 2,
+ 'apple_id' => 1,
+ 'color' => 'Bright Red 1',
+ 'name' => 'Bright Red Apple',
+ 'created' => '2006-11-22 10:43:13',
+ 'date' => '2014-01-01',
+ 'modified' => '2006-11-30 18:38:10',
+ 'mytime' => '22:57:17'
+ )),
+ 'Child' => array(
+ array(
+ 'id' => 1,
+ 'apple_id' => 2,
+ 'color' => 'Red 1',
+ 'name' => 'Red Apple 1',
+ 'created' => '2006-11-22 10:38:58',
+ 'date' => '1951-01-04',
+ 'modified' => '2006-12-01 13:31:26',
+ 'mytime' => '22:57:17',
+ 'Parent' => array(
+ 'id' => 2,
+ 'apple_id' => 1,
+ 'color' => 'Bright Red 1',
+ 'name' => 'Bright Red Apple',
+ 'created' => '2006-11-22 10:43:13',
+ 'date' => '2014-01-01',
+ 'modified' => '2006-11-30 18:38:10',
+ 'mytime' => '22:57:17'
+ ),
+ 'Sample' => array(),
+ 'Child' => array(
+ array(
+ 'id' => 2,
+ 'apple_id' => 1,
+ 'color' => 'Bright Red 1',
+ 'name' => 'Bright Red Apple',
+ 'created' => '2006-11-22 10:43:13',
+ 'date' => '2014-01-01', 'modified' =>
+ '2006-11-30 18:38:10',
+ 'mytime' => '22:57:17'
+ ))),
+ array(
+ 'id' => 3,
+ 'apple_id' => 2,
+ 'color' => 'blue green',
+ 'name' => 'green blue',
+ 'created' => '2006-12-25 05:13:36',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:23:24',
+ 'mytime' => '22:57:17',
+ 'Parent' => array(
+ 'id' => 2,
+ 'apple_id' => 1,
+ 'color' => 'Bright Red 1',
+ 'name' => 'Bright Red Apple',
+ 'created' => '2006-11-22 10:43:13',
+ 'date' => '2014-01-01',
+ 'modified' => '2006-11-30 18:38:10',
+ 'mytime' => '22:57:17'
+ ),
+ 'Sample' => array(
+ 'id' => 1,
+ 'apple_id' => 3,
+ 'name' => 'sample1'
+ )),
+ array(
+ 'id' => 4,
+ 'apple_id' => 2,
+ 'color' => 'Blue Green',
+ 'name' => 'Test Name',
+ 'created' => '2006-12-25 05:23:36',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:23:36',
+ 'mytime' => '22:57:17',
+ 'Parent' => array(
+ 'id' => 2,
+ 'apple_id' => 1,
+ 'color' => 'Bright Red 1',
+ 'name' => 'Bright Red Apple',
+ 'created' => '2006-11-22 10:43:13',
+ 'date' => '2014-01-01',
+ 'modified' => '2006-11-30 18:38:10',
+ 'mytime' => '22:57:17'
+ ),
+ 'Sample' => array(
+ 'id' => 3,
+ 'apple_id' => 4,
+ 'name' => 'sample3'
+ ),
+ 'Child' => array(
+ array(
+ 'id' => 6,
+ 'apple_id' => 4,
+ 'color' => 'My new appleOrange',
+ 'name' => 'My new apple',
+ 'created' => '2006-12-25 05:29:39',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:29:39',
+ 'mytime' => '22:57:17'
+ ))))),
+ array(
+ 'Apple' => array(
+ 'id' => 3,
+ 'apple_id' => 2,
+ 'color' => 'blue green',
+ 'name' => 'green blue',
+ 'created' => '2006-12-25 05:13:36',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:23:24',
+ 'mytime' => '22:57:17'
+ ),
+ 'Parent' => array(
+ 'id' => 2,
+ 'apple_id' => 1,
+ 'color' => 'Bright Red 1',
+ 'name' => 'Bright Red Apple',
+ 'created' => '2006-11-22 10:43:13',
+ 'date' => '2014-01-01',
+ 'modified' => '2006-11-30 18:38:10',
+ 'mytime' => '22:57:17',
+ 'Parent' => array(
+ 'id' => 1,
+ 'apple_id' => 2,
+ 'color' => 'Red 1',
+ 'name' => 'Red Apple 1',
+ 'created' => '2006-11-22 10:38:58',
+ 'date' => '1951-01-04',
+ 'modified' => '2006-12-01 13:31:26',
+ 'mytime' => '22:57:17'
+ ),
+ 'Child' => array(
+ array(
+ 'id' => 1,
+ 'apple_id' => 2,
+ 'color' => 'Red 1',
+ 'name' => 'Red Apple 1',
+ 'created' => '2006-11-22 10:38:58',
+ 'date' => '1951-01-04',
+ 'modified' => '2006-12-01 13:31:26',
+ 'mytime' => '22:57:17'
+ ),
+ array(
+ 'id' => 3,
+ 'apple_id' => 2,
+ 'color' => 'blue green',
+ 'name' => 'green blue',
+ 'created' => '2006-12-25 05:13:36',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:23:24',
+ 'mytime' => '22:57:17'
+ ),
+ array(
+ 'id' => 4,
+ 'apple_id' => 2,
+ 'color' => 'Blue Green',
+ 'name' => 'Test Name',
+ 'created' => '2006-12-25 05:23:36',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:23:36',
+ 'mytime' => '22:57:17'
+ ))),
+ 'Sample' => array(
+ 'id' => 1,
+ 'apple_id' => 3,
+ 'name' => 'sample1',
+ 'Apple' => array(
+ 'id' => 3,
+ 'apple_id' => 2,
+ 'color' => 'blue green',
+ 'name' => 'green blue',
+ 'created' => '2006-12-25 05:13:36',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:23:24',
+ 'mytime' => '22:57:17'
+ )),
+ 'Child' => array()
+ ),
+ array(
+ 'Apple' => array(
+ 'id' => 4,
+ 'apple_id' => 2,
+ 'color' => 'Blue Green',
+ 'name' => 'Test Name',
+ 'created' => '2006-12-25 05:23:36',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:23:36',
+ 'mytime' => '22:57:17'
+ ),
+ 'Parent' => array(
+ 'id' => 2,
+ 'apple_id' => 1,
+ 'color' => 'Bright Red 1',
+ 'name' => 'Bright Red Apple',
+ 'created' => '2006-11-22 10:43:13',
+ 'date' => '2014-01-01',
+ 'modified' => '2006-11-30 18:38:10',
+ 'mytime' => '22:57:17',
+ 'Parent' => array(
+ 'id' => 1,
+ 'apple_id' => 2,
+ 'color' => 'Red 1',
+ 'name' => 'Red Apple 1',
+ 'created' => '2006-11-22 10:38:58',
+ 'date' => '1951-01-04',
+ 'modified' => '2006-12-01 13:31:26',
+ 'mytime' => '22:57:17'
+ ),
+ 'Child' => array(
+ array(
+ 'id' => 1,
+ 'apple_id' => 2,
+ 'color' => 'Red 1',
+ 'name' => 'Red Apple 1',
+ 'created' => '2006-11-22 10:38:58',
+ 'date' => '1951-01-04',
+ 'modified' => '2006-12-01 13:31:26',
+ 'mytime' => '22:57:17'
+ ),
+ array(
+ 'id' => 3,
+ 'apple_id' => 2,
+ 'color' => 'blue green',
+ 'name' => 'green blue',
+ 'created' => '2006-12-25 05:13:36',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:23:24',
+ 'mytime' => '22:57:17'
+ ),
+ array(
+ 'id' => 4,
+ 'apple_id' => 2,
+ 'color' => 'Blue Green',
+ 'name' => 'Test Name',
+ 'created' => '2006-12-25 05:23:36',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:23:36',
+ 'mytime' => '22:57:17'
+ ))),
+ 'Sample' => array(
+ 'id' => 3,
+ 'apple_id' => 4,
+ 'name' => 'sample3',
+ 'Apple' => array(
+ 'id' => 4,
+ 'apple_id' => 2,
+ 'color' => 'Blue Green',
+ 'name' => 'Test Name',
+ 'created' => '2006-12-25 05:23:36',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:23:36',
+ 'mytime' => '22:57:17'
+ )),
+ 'Child' => array(
+ array(
+ 'id' => 6,
+ 'apple_id' => 4,
+ 'color' => 'My new appleOrange',
+ 'name' => 'My new apple',
+ 'created' => '2006-12-25 05:29:39',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:29:39',
+ 'mytime' => '22:57:17',
+ 'Parent' => array(
+ 'id' => 4,
+ 'apple_id' => 2,
+ 'color' => 'Blue Green',
+ 'name' => 'Test Name',
+ 'created' => '2006-12-25 05:23:36',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:23:36',
+ 'mytime' => '22:57:17'
+ ),
+ 'Sample' => array(),
+ 'Child' => array(
+ array(
+ 'id' => 7,
+ 'apple_id' => 6,
+ 'color' => 'Some wierd color',
+ 'name' => 'Some odd color',
+ 'created' => '2006-12-25 05:34:21',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:34:21',
+ 'mytime' => '22:57:17'
+ ))))),
+ array(
+ 'Apple' => array(
+ 'id' => 5,
+ 'apple_id' => 5,
+ 'color' => 'Green',
+ 'name' => 'Blue Green',
+ 'created' => '2006-12-25 05:24:06',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:29:16',
+ 'mytime' => '22:57:17'
+ ),
+ 'Parent' => array(
+ 'id' => 5,
+ 'apple_id' => 5,
+ 'color' => 'Green',
+ 'name' => 'Blue Green',
+ 'created' => '2006-12-25 05:24:06',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:29:16',
+ 'mytime' => '22:57:17',
+ 'Parent' => array(
+ 'id' => 5,
+ 'apple_id' => 5,
+ 'color' => 'Green',
+ 'name' => 'Blue Green',
+ 'created' => '2006-12-25 05:24:06',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:29:16',
+ 'mytime' => '22:57:17'
+ ),
+ 'Child' => array(
+ array(
+ 'id' => 5,
+ 'apple_id' => 5,
+ 'color' => 'Green',
+ 'name' => 'Blue Green',
+ 'created' => '2006-12-25 05:24:06',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:29:16',
+ 'mytime' => '22:57:17'
+ ))),
+ 'Sample' => array(
+ 'id' => 4,
+ 'apple_id' => 5,
+ 'name' => 'sample4',
+ 'Apple' => array(
+ 'id' => 5,
+ 'apple_id' => 5,
+ 'color' => 'Green',
+ 'name' => 'Blue Green',
+ 'created' => '2006-12-25 05:24:06',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:29:16',
+ 'mytime' => '22:57:17'
+ )),
+ 'Child' => array(
+ array(
+ 'id' => 5,
+ 'apple_id' => 5,
+ 'color' => 'Green',
+ 'name' => 'Blue Green',
+ 'created' => '2006-12-25 05:24:06',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:29:16',
+ 'mytime' => '22:57:17',
+ 'Parent' => array(
+ 'id' => 5,
+ 'apple_id' => 5,
+ 'color' => 'Green',
+ 'name' => 'Blue Green',
+ 'created' => '2006-12-25 05:24:06',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:29:16',
+ 'mytime' => '22:57:17'
+ ),
+ 'Sample' => array(
+ 'id' => 4,
+ 'apple_id' => 5,
+ 'name' => 'sample4'
+ ),
+ 'Child' => array(
+ array(
+ 'id' => 5,
+ 'apple_id' => 5,
+ 'color' => 'Green',
+ 'name' => 'Blue Green',
+ 'created' => '2006-12-25 05:24:06',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:29:16',
+ 'mytime' => '22:57:17'
+ ))))),
+ array(
+ 'Apple' => array(
+ 'id' => 6,
+ 'apple_id' => 4,
+ 'color' => 'My new appleOrange',
+ 'name' => 'My new apple',
+ 'created' => '2006-12-25 05:29:39',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:29:39',
+ 'mytime' => '22:57:17'
+ ),
+ 'Parent' => array(
+ 'id' => 4,
+ 'apple_id' => 2,
+ 'color' => 'Blue Green',
+ 'name' => 'Test Name',
+ 'created' => '2006-12-25 05:23:36',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:23:36',
+ 'mytime' => '22:57:17',
+ 'Parent' => array(
+ 'id' => 2,
+ 'apple_id' => 1,
+ 'color' => 'Bright Red 1',
+ 'name' => 'Bright Red Apple',
+ 'created' => '2006-11-22 10:43:13',
+ 'date' => '2014-01-01',
+ 'modified' => '2006-11-30 18:38:10',
+ 'mytime' => '22:57:17'
+ ),
+ 'Child' => array(
+ array(
+ 'id' => 6,
+ 'apple_id' => 4,
+ 'color' => 'My new appleOrange',
+ 'name' => 'My new apple',
+ 'created' => '2006-12-25 05:29:39',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:29:39',
+ 'mytime' => '22:57:17'
+ ))),
+ 'Sample' => array(
+ 'id' => '',
+ 'apple_id' => '',
+ 'name' => ''
+ ),
+ 'Child' => array(
+ array(
+ 'id' => 7,
+ 'apple_id' => 6,
+ 'color' => 'Some wierd color',
+ 'name' => 'Some odd color',
+ 'created' => '2006-12-25 05:34:21',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:34:21',
+ 'mytime' => '22:57:17',
+ 'Parent' => array(
+ 'id' => 6,
+ 'apple_id' => 4,
+ 'color' => 'My new appleOrange',
+ 'name' => 'My new apple',
+ 'created' => '2006-12-25 05:29:39',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:29:39',
+ 'mytime' => '22:57:17'
+ ),
+ 'Sample' => array()
+ ))),
+ array(
+ 'Apple' => array(
+ 'id' => 7,
+ 'apple_id' => 6,
+ 'color' => 'Some wierd color',
+ 'name' => 'Some odd color',
+ 'created' => '2006-12-25 05:34:21',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:34:21',
+ 'mytime' => '22:57:17'
+ ),
+ 'Parent' => array(
+ 'id' => 6,
+ 'apple_id' => 4,
+ 'color' => 'My new appleOrange',
+ 'name' => 'My new apple',
+ 'created' => '2006-12-25 05:29:39',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:29:39',
+ 'mytime' => '22:57:17',
+ 'Parent' => array(
+ 'id' => 4,
+ 'apple_id' => 2,
+ 'color' => 'Blue Green',
+ 'name' => 'Test Name',
+ 'created' => '2006-12-25 05:23:36',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:23:36',
+ 'mytime' => '22:57:17'
+ ),
+ 'Child' => array(
+ array(
+ 'id' => 7,
+ 'apple_id' => 6,
+ 'color' => 'Some wierd color',
+ 'name' => 'Some odd color',
+ 'created' => '2006-12-25 05:34:21',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:34:21',
+ 'mytime' => '22:57:17'
+ ))),
+ 'Sample' => array(
+ 'id' => '',
+ 'apple_id' => '',
+ 'name' => ''
+ ),
+ 'Child' => array()
+ ));
+
+ $this->assertEqual($result, $expected);
+
+ $result = $TestModel->Parent->unbindModel(array('hasOne' => array('Sample')));
+ $this->assertTrue($result);
+
+ $result = $TestModel->unbindModel(array('hasMany' => array('Child')));
+ $this->assertTrue($result);
+
+ $result = $TestModel->find('all');
+ $expected = array(
+ array(
+ 'Apple' => array (
+ 'id' => 1,
+ 'apple_id' => 2,
+ 'color' => 'Red 1',
+ 'name' => 'Red Apple 1',
+ 'created' => '2006-11-22 10:38:58',
+ 'date' => '1951-01-04',
+ 'modified' => '2006-12-01 13:31:26',
+ 'mytime' => '22:57:17'
+ ),
+ 'Parent' => array(
+ 'id' => 2,
+ 'apple_id' => 1,
+ 'color' => 'Bright Red 1',
+ 'name' => 'Bright Red Apple',
+ 'created' => '2006-11-22 10:43:13',
+ 'date' => '2014-01-01',
+ 'modified' => '2006-11-30 18:38:10',
+ 'mytime' => '22:57:17',
+ 'Parent' => array(
+ 'id' => 1,
+ 'apple_id' => 2,
+ 'color' => 'Red 1',
+ 'name' => 'Red Apple 1',
+ 'created' => '2006-11-22 10:38:58',
+ 'date' => '1951-01-04',
+ 'modified' => '2006-12-01 13:31:26',
+ 'mytime' => '22:57:17'
+ ),
+ 'Child' => array(
+ array(
+ 'id' => 1,
+ 'apple_id' => 2,
+ 'color' => 'Red 1',
+ 'name' => 'Red Apple 1',
+ 'created' => '2006-11-22 10:38:58',
+ 'date' => '1951-01-04',
+ 'modified' => '2006-12-01 13:31:26',
+ 'mytime' => '22:57:17'
+ ),
+ array(
+ 'id' => 3,
+ 'apple_id' => 2,
+ 'color' => 'blue green',
+ 'name' => 'green blue',
+ 'created' => '2006-12-25 05:13:36',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:23:24',
+ 'mytime' => '22:57:17'
+ ),
+ array(
+ 'id' => 4,
+ 'apple_id' => 2,
+ 'color' => 'Blue Green',
+ 'name' => 'Test Name',
+ 'created' => '2006-12-25 05:23:36',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:23:36',
+ 'mytime' => '22:57:17'
+ ))),
+ 'Sample' => array(
+ 'id' =>'',
+ 'apple_id' => '',
+ 'name' => ''
+ )),
+ array(
+ 'Apple' => array(
+ 'id' => 2,
+ 'apple_id' => 1,
+ 'color' => 'Bright Red 1',
+ 'name' => 'Bright Red Apple',
+ 'created' => '2006-11-22 10:43:13',
+ 'date' => '2014-01-01',
+ 'modified' => '2006-11-30 18:38:10',
+ 'mytime' => '22:57:17'
+ ),
+ 'Parent' => array(
+ 'id' => 1,
+ 'apple_id' => 2,
+ 'color' => 'Red 1',
+ 'name' => 'Red Apple 1',
+ 'created' => '2006-11-22 10:38:58',
+ 'date' => '1951-01-04',
+ 'modified' => '2006-12-01 13:31:26',
+ 'mytime' => '22:57:17',
+ 'Parent' => array(
+ 'id' => 2,
+ 'apple_id' => 1,
+ 'color' => 'Bright Red 1',
+ 'name' => 'Bright Red Apple',
+ 'created' => '2006-11-22 10:43:13',
+ 'date' => '2014-01-01',
+ 'modified' => '2006-11-30 18:38:10',
+ 'mytime' => '22:57:17'
+ ),
+ 'Child' => array(
+ array(
+ 'id' => 2,
+ 'apple_id' => 1,
+ 'color' => 'Bright Red 1',
+ 'name' => 'Bright Red Apple',
+ 'created' => '2006-11-22 10:43:13',
+ 'date' => '2014-01-01',
+ 'modified' => '2006-11-30 18:38:10',
+ 'mytime' => '22:57:17'
+ ))),
+ 'Sample' => array(
+ 'id' => 2,
+ 'apple_id' => 2,
+ 'name' => 'sample2',
+ 'Apple' => array(
+ 'id' => 2,
+ 'apple_id' => 1,
+ 'color' => 'Bright Red 1',
+ 'name' => 'Bright Red Apple',
+ 'created' => '2006-11-22 10:43:13',
+ 'date' => '2014-01-01',
+ 'modified' => '2006-11-30 18:38:10',
+ 'mytime' => '22:57:17'
+ ))),
+ array(
+ 'Apple' => array(
+ 'id' => 3,
+ 'apple_id' => 2,
+ 'color' => 'blue green',
+ 'name' => 'green blue',
+ 'created' => '2006-12-25 05:13:36',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:23:24',
+ 'mytime' => '22:57:17'
+ ),
+ 'Parent' => array(
+ 'id' => 2,
+ 'apple_id' => 1,
+ 'color' => 'Bright Red 1',
+ 'name' => 'Bright Red Apple',
+ 'created' => '2006-11-22 10:43:13',
+ 'date' => '2014-01-01',
+ 'modified' => '2006-11-30 18:38:10',
+ 'mytime' => '22:57:17',
+ 'Parent' => array(
+ 'id' => 1,
+ 'apple_id' => 2,
+ 'color' => 'Red 1',
+ 'name' => 'Red Apple 1',
+ 'created' => '2006-11-22 10:38:58',
+ 'date' => '1951-01-04',
+ 'modified' => '2006-12-01 13:31:26',
+ 'mytime' => '22:57:17'
+ ),
+ 'Child' => array(
+ array(
+ 'id' => 1,
+ 'apple_id' => 2,
+ 'color' => 'Red 1',
+ 'name' => 'Red Apple 1',
+ 'created' => '2006-11-22 10:38:58',
+ 'date' => '1951-01-04',
+ 'modified' => '2006-12-01 13:31:26',
+ 'mytime' => '22:57:17'
+ ),
+ array(
+ 'id' => 3,
+ 'apple_id' => 2,
+ 'color' => 'blue green',
+ 'name' => 'green blue',
+ 'created' => '2006-12-25 05:13:36',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:23:24',
+ 'mytime' => '22:57:17'
+ ),
+ array(
+ 'id' => 4,
+ 'apple_id' => 2,
+ 'color' => 'Blue Green',
+ 'name' => 'Test Name',
+ 'created' => '2006-12-25 05:23:36',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:23:36',
+ 'mytime' => '22:57:17'
+ ))),
+ 'Sample' => array(
+ 'id' => 1,
+ 'apple_id' => 3,
+ 'name' => 'sample1',
+ 'Apple' => array(
+ 'id' => 3,
+ 'apple_id' => 2,
+ 'color' => 'blue green',
+ 'name' => 'green blue',
+ 'created' => '2006-12-25 05:13:36',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:23:24',
+ 'mytime' => '22:57:17'
+ ))),
+ array(
+ 'Apple' => array(
+ 'id' => 4,
+ 'apple_id' => 2,
+ 'color' => 'Blue Green',
+ 'name' => 'Test Name',
+ 'created' => '2006-12-25 05:23:36',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:23:36',
+ 'mytime' => '22:57:17'
+ ),
+ 'Parent' => array(
+ 'id' => 2,
+ 'apple_id' => 1,
+ 'color' => 'Bright Red 1',
+ 'name' => 'Bright Red Apple',
+ 'created' => '2006-11-22 10:43:13',
+ 'date' => '2014-01-01',
+ 'modified' => '2006-11-30 18:38:10',
+ 'mytime' => '22:57:17',
+ 'Parent' => array(
+ 'id' => 1,
+ 'apple_id' => 2,
+ 'color' => 'Red 1',
+ 'name' => 'Red Apple 1',
+ 'created' => '2006-11-22 10:38:58',
+ 'date' => '1951-01-04',
+ 'modified' => '2006-12-01 13:31:26',
+ 'mytime' => '22:57:17'
+ ),
+ 'Child' => array(
+ array(
+ 'id' => 1,
+ 'apple_id' => 2,
+ 'color' => 'Red 1',
+ 'name' => 'Red Apple 1',
+ 'created' => '2006-11-22 10:38:58',
+ 'date' => '1951-01-04',
+ 'modified' => '2006-12-01 13:31:26',
+ 'mytime' => '22:57:17'
+ ),
+ array(
+ 'id' => 3,
+ 'apple_id' => 2,
+ 'color' => 'blue green',
+ 'name' => 'green blue',
+ 'created' => '2006-12-25 05:13:36',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:23:24',
+ 'mytime' => '22:57:17'
+ ),
+ array(
+ 'id' => 4,
+ 'apple_id' => 2,
+ 'color' => 'Blue Green',
+ 'name' => 'Test Name',
+ 'created' => '2006-12-25 05:23:36',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:23:36',
+ 'mytime' => '22:57:17'
+ ))),
+ 'Sample' => array(
+ 'id' => 3,
+ 'apple_id' => 4,
+ 'name' => 'sample3',
+ 'Apple' => array(
+ 'id' => 4,
+ 'apple_id' => 2,
+ 'color' => 'Blue Green',
+ 'name' => 'Test Name',
+ 'created' => '2006-12-25 05:23:36',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:23:36',
+ 'mytime' => '22:57:17'
+ ))),
+ array(
+ 'Apple' => array(
+ 'id' => 5,
+ 'apple_id' => 5,
+ 'color' => 'Green',
+ 'name' => 'Blue Green',
+ 'created' => '2006-12-25 05:24:06',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:29:16',
+ 'mytime' => '22:57:17'
+ ),
+ 'Parent' => array(
+ 'id' => 5,
+ 'apple_id' => 5,
+ 'color' => 'Green',
+ 'name' => 'Blue Green',
+ 'created' => '2006-12-25 05:24:06',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:29:16',
+ 'mytime' => '22:57:17',
+ 'Parent' => array(
+ 'id' => 5,
+ 'apple_id' => 5,
+ 'color' => 'Green',
+ 'name' => 'Blue Green',
+ 'created' => '2006-12-25 05:24:06',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:29:16',
+ 'mytime' => '22:57:17'
+ ),
+ 'Child' => array(
+ array(
+ 'id' => 5,
+ 'apple_id' => 5,
+ 'color' => 'Green',
+ 'name' => 'Blue Green',
+ 'created' => '2006-12-25 05:24:06',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:29:16',
+ 'mytime' => '22:57:17'
+ ))),
+ 'Sample' => array(
+ 'id' => 4,
+ 'apple_id' => 5,
+ 'name' => 'sample4',
+ 'Apple' => array(
+ 'id' => 5,
+ 'apple_id' => 5,
+ 'color' => 'Green',
+ 'name' => 'Blue Green',
+ 'created' => '2006-12-25 05:24:06',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:29:16',
+ 'mytime' => '22:57:17'
+ ))),
+ array(
+ 'Apple' => array(
+ 'id' => 6,
+ 'apple_id' => 4,
+ 'color' => 'My new appleOrange',
+ 'name' => 'My new apple',
+ 'created' => '2006-12-25 05:29:39',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:29:39',
+ 'mytime' => '22:57:17'
+ ),
+ 'Parent' => array(
+ 'id' => 4,
+ 'apple_id' => 2,
+ 'color' => 'Blue Green',
+ 'name' => 'Test Name',
+ 'created' => '2006-12-25 05:23:36',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:23:36',
+ 'mytime' => '22:57:17',
+ 'Parent' => array(
+ 'id' => 2,
+ 'apple_id' => 1,
+ 'color' => 'Bright Red 1',
+ 'name' => 'Bright Red Apple',
+ 'created' => '2006-11-22 10:43:13',
+ 'date' => '2014-01-01',
+ 'modified' => '2006-11-30 18:38:10',
+ 'mytime' => '22:57:17'
+ ),
+ 'Child' => array(
+ array(
+ 'id' => 6,
+ 'apple_id' => 4,
+ 'color' => 'My new appleOrange',
+ 'name' => 'My new apple',
+ 'created' => '2006-12-25 05:29:39',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:29:39',
+ 'mytime' => '22:57:17'
+ ))),
+ 'Sample' => array(
+ 'id' => '',
+ 'apple_id' => '',
+ 'name' => ''
+ )),
+ array(
+ 'Apple' => array(
+ 'id' => 7,
+ 'apple_id' => 6,
+ 'color' => 'Some wierd color',
+ 'name' => 'Some odd color',
+ 'created' => '2006-12-25 05:34:21',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:34:21',
+ 'mytime' => '22:57:17'
+ ),
+ 'Parent' => array(
+ 'id' => 6,
+ 'apple_id' => 4,
+ 'color' => 'My new appleOrange',
+ 'name' => 'My new apple',
+ 'created' => '2006-12-25 05:29:39',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:29:39',
+ 'mytime' => '22:57:17',
+ 'Parent' => array(
+ 'id' => 4,
+ 'apple_id' => 2,
+ 'color' => 'Blue Green',
+ 'name' => 'Test Name',
+ 'created' => '2006-12-25 05:23:36',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:23:36',
+ 'mytime' => '22:57:17'
+ ),
+ 'Child' => array(
+ array(
+ 'id' => 7,
+ 'apple_id' => 6,
+ 'color' => 'Some wierd color',
+ 'name' => 'Some odd color',
+ 'created' => '2006-12-25 05:34:21',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:34:21',
+ 'mytime' => '22:57:17'
+ ))),
+ 'Sample' => array(
+ 'id' => '',
+ 'apple_id' => '',
+ 'name' => ''
+ )));
+
+ $this->assertEqual($result, $expected);
+
+ $result = $TestModel->unbindModel(array('hasMany' => array('Child')));
+ $this->assertTrue($result);
+
+ $result = $TestModel->Sample->unbindModel(array('belongsTo' => array('Apple')));
+ $this->assertTrue($result);
+
+ $result = $TestModel->find('all');
+ $expected = array(
+ array(
+ 'Apple' => array(
+ 'id' => 1,
+ 'apple_id' => 2,
+ 'color' => 'Red 1',
+ 'name' => 'Red Apple 1',
+ 'created' => '2006-11-22 10:38:58',
+ 'date' => '1951-01-04',
+ 'modified' => '2006-12-01 13:31:26',
+ 'mytime' => '22:57:17'
+ ),
+ 'Parent' => array(
+ 'id' => 2,
+ 'apple_id' => 1,
+ 'color' => 'Bright Red 1',
+ 'name' => 'Bright Red Apple',
+ 'created' => '2006-11-22 10:43:13',
+ 'date' => '2014-01-01',
+ 'modified' => '2006-11-30 18:38:10',
+ 'mytime' => '22:57:17',
+ 'Parent' => array(
+ 'id' => 1,
+ 'apple_id' => 2,
+ 'color' => 'Red 1',
+ 'name' => 'Red Apple 1',
+ 'created' => '2006-11-22 10:38:58',
+ 'date' => '1951-01-04',
+ 'modified' => '2006-12-01 13:31:26',
+ 'mytime' => '22:57:17'
+ ),
+ 'Sample' => array(
+ 'id' => 2,
+ 'apple_id' => 2,
+ 'name' => 'sample2'
+ ),
+ 'Child' => array(
+ array(
+ 'id' => 1,
+ 'apple_id' => 2,
+ 'color' => 'Red 1',
+ 'name' => 'Red Apple 1',
+ 'created' => '2006-11-22 10:38:58',
+ 'date' => '1951-01-04',
+ 'modified' => '2006-12-01 13:31:26',
+ 'mytime' => '22:57:17'
+ ),
+ array(
+ 'id' => 3,
+ 'apple_id' => 2,
+ 'color' => 'blue green',
+ 'name' => 'green blue',
+ 'created' => '2006-12-25 05:13:36',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:23:24',
+ 'mytime' => '22:57:17'
+ ),
+ array(
+ 'id' => 4,
+ 'apple_id' => 2,
+ 'color' => 'Blue Green',
+ 'name' => 'Test Name',
+ 'created' => '2006-12-25 05:23:36',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:23:36',
+ 'mytime' => '22:57:17'
+ ))),
+ 'Sample' => array(
+ 'id' =>'',
+ 'apple_id' => '',
+ 'name' => ''
+ )),
+ array(
+ 'Apple' => array(
+ 'id' => 2,
+ 'apple_id' => 1,
+ 'color' => 'Bright Red 1',
+ 'name' => 'Bright Red Apple',
+ 'created' => '2006-11-22 10:43:13',
+ 'date' => '2014-01-01',
+ 'modified' => '2006-11-30 18:38:10',
+ 'mytime' => '22:57:17'
+ ),
+ 'Parent' => array(
+ 'id' => 1,
+ 'apple_id' => 2,
+ 'color' => 'Red 1',
+ 'name' => 'Red Apple 1',
+ 'created' => '2006-11-22 10:38:58',
+ 'date' => '1951-01-04',
+ 'modified' => '2006-12-01 13:31:26',
+ 'mytime' => '22:57:17',
+ 'Parent' => array(
+ 'id' => 2,
+ 'apple_id' => 1,
+ 'color' => 'Bright Red 1',
+ 'name' => 'Bright Red Apple',
+ 'created' => '2006-11-22 10:43:13',
+ 'date' => '2014-01-01',
+ 'modified' => '2006-11-30 18:38:10',
+ 'mytime' => '22:57:17'
+ ),
+ 'Sample' => array(),
+ 'Child' => array(
+ array(
+ 'id' => 2,
+ 'apple_id' => 1,
+ 'color' => 'Bright Red 1',
+ 'name' => 'Bright Red Apple',
+ 'created' => '2006-11-22 10:43:13',
+ 'date' => '2014-01-01',
+ 'modified' => '2006-11-30 18:38:10',
+ 'mytime' => '22:57:17'
+ ))),
+ 'Sample' => array(
+ 'id' => 2,
+ 'apple_id' => 2,
+ 'name' => 'sample2'
+ )),
+ array(
+ 'Apple' => array(
+ 'id' => 3,
+ 'apple_id' => 2,
+ 'color' => 'blue green',
+ 'name' => 'green blue',
+ 'created' => '2006-12-25 05:13:36',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:23:24',
+ 'mytime' => '22:57:17'
+ ),
+ 'Parent' => array(
+ 'id' => 2,
+ 'apple_id' => 1,
+ 'color' => 'Bright Red 1',
+ 'name' => 'Bright Red Apple',
+ 'created' => '2006-11-22 10:43:13',
+ 'date' => '2014-01-01',
+ 'modified' => '2006-11-30 18:38:10',
+ 'mytime' => '22:57:17',
+ 'Parent' => array(
+ 'id' => 1,
+ 'apple_id' => 2,
+ 'color' => 'Red 1',
+ 'name' => 'Red Apple 1',
+ 'created' => '2006-11-22 10:38:58',
+ 'date' => '1951-01-04',
+ 'modified' => '2006-12-01 13:31:26',
+ 'mytime' => '22:57:17'
+ ),
+ 'Sample' => array(
+ 'id' => 2,
+ 'apple_id' => 2,
+ 'name' => 'sample2'
+ ),
+ 'Child' => array(
+ array(
+ 'id' => 1,
+ 'apple_id' => 2,
+ 'color' => 'Red 1',
+ 'name' => 'Red Apple 1',
+ 'created' => '2006-11-22 10:38:58',
+ 'date' => '1951-01-04',
+ 'modified' => '2006-12-01 13:31:26',
+ 'mytime' => '22:57:17'
+ ),
+ array(
+ 'id' => 3,
+ 'apple_id' => 2,
+ 'color' => 'blue green',
+ 'name' => 'green blue',
+ 'created' => '2006-12-25 05:13:36',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:23:24',
+ 'mytime' => '22:57:17'
+ ),
+ array(
+ 'id' => 4,
+ 'apple_id' => 2,
+ 'color' => 'Blue Green',
+ 'name' => 'Test Name',
+ 'created' => '2006-12-25 05:23:36',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:23:36',
+ 'mytime' => '22:57:17'
+ ))),
+ 'Sample' => array(
+ 'id' => 1,
+ 'apple_id' => 3,
+ 'name' => 'sample1'
+ )),
+ array(
+ 'Apple' => array(
+ 'id' => 4,
+ 'apple_id' => 2,
+ 'color' => 'Blue Green',
+ 'name' => 'Test Name',
+ 'created' => '2006-12-25 05:23:36',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:23:36',
+ 'mytime' => '22:57:17'
+ ),
+ 'Parent' => array(
+ 'id' => 2,
+ 'apple_id' => 1,
+ 'color' => 'Bright Red 1',
+ 'name' => 'Bright Red Apple',
+ 'created' => '2006-11-22 10:43:13',
+ 'date' => '2014-01-01',
+ 'modified' => '2006-11-30 18:38:10',
+ 'mytime' => '22:57:17',
+ 'Parent' => array(
+ 'id' => 1,
+ 'apple_id' => 2,
+ 'color' => 'Red 1',
+ 'name' => 'Red Apple 1',
+ 'created' => '2006-11-22 10:38:58',
+ 'date' => '1951-01-04',
+ 'modified' => '2006-12-01 13:31:26',
+ 'mytime' => '22:57:17'
+ ),
+ 'Sample' => array(
+ 'id' => 2,
+ 'apple_id' => 2,
+ 'name' => 'sample2'
+ ),
+ 'Child' => array(
+ array(
+ 'id' => 1,
+ 'apple_id' => 2,
+ 'color' => 'Red 1',
+ 'name' => 'Red Apple 1',
+ 'created' => '2006-11-22 10:38:58',
+ 'date' => '1951-01-04',
+ 'modified' => '2006-12-01 13:31:26',
+ 'mytime' => '22:57:17'
+ ),
+ array(
+ 'id' => 3,
+ 'apple_id' => 2,
+ 'color' => 'blue green',
+ 'name' => 'green blue',
+ 'created' => '2006-12-25 05:13:36',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:23:24',
+ 'mytime' => '22:57:17'
+ ),
+ array(
+ 'id' => 4,
+ 'apple_id' => 2,
+ 'color' => 'Blue Green',
+ 'name' => 'Test Name',
+ 'created' => '2006-12-25 05:23:36',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:23:36',
+ 'mytime' => '22:57:17'
+ ))),
+ 'Sample' => array(
+ 'id' => 3,
+ 'apple_id' => 4,
+ 'name' => 'sample3'
+ )),
+ array(
+ 'Apple' => array(
+ 'id' => 5,
+ 'apple_id' => 5,
+ 'color' => 'Green',
+ 'name' => 'Blue Green',
+ 'created' => '2006-12-25 05:24:06',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:29:16',
+ 'mytime' => '22:57:17'
+ ),
+ 'Parent' => array(
+ 'id' => 5,
+ 'apple_id' => 5,
+ 'color' => 'Green',
+ 'name' => 'Blue Green',
+ 'created' => '2006-12-25 05:24:06',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:29:16',
+ 'mytime' => '22:57:17',
+ 'Parent' => array(
+ 'id' => 5,
+ 'apple_id' => 5,
+ 'color' => 'Green',
+ 'name' => 'Blue Green',
+ 'created' => '2006-12-25 05:24:06',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:29:16',
+ 'mytime' => '22:57:17'
+ ),
+ 'Sample' => array(
+ 'id' => 4,
+ 'apple_id' => 5,
+ 'name' => 'sample4'
+ ),
+ 'Child' => array(
+ array(
+ 'id' => 5,
+ 'apple_id' => 5,
+ 'color' => 'Green',
+ 'name' => 'Blue Green',
+ 'created' => '2006-12-25 05:24:06',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:29:16',
+ 'mytime' => '22:57:17'
+ ))),
+ 'Sample' => array(
+ 'id' => 4,
+ 'apple_id' => 5,
+ 'name' => 'sample4'
+ )),
+ array(
+ 'Apple' => array(
+ 'id' => 6,
+ 'apple_id' => 4,
+ 'color' => 'My new appleOrange',
+ 'name' => 'My new apple',
+ 'created' => '2006-12-25 05:29:39',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:29:39',
+ 'mytime' => '22:57:17'
+ ),
+ 'Parent' => array(
+ 'id' => 4,
+ 'apple_id' => 2,
+ 'color' => 'Blue Green',
+ 'name' => 'Test Name',
+ 'created' => '2006-12-25 05:23:36',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:23:36',
+ 'mytime' => '22:57:17',
+ 'Parent' => array(
+ 'id' => 2,
+ 'apple_id' => 1,
+ 'color' => 'Bright Red 1',
+ 'name' => 'Bright Red Apple',
+ 'created' => '2006-11-22 10:43:13',
+ 'date' => '2014-01-01',
+ 'modified' => '2006-11-30 18:38:10',
+ 'mytime' => '22:57:17'
+ ),
+ 'Sample' => array(
+ 'id' => 3,
+ 'apple_id' => 4,
+ 'name' => 'sample3'
+ ),
+ 'Child' => array(
+ array(
+ 'id' => 6,
+ 'apple_id' => 4,
+ 'color' => 'My new appleOrange',
+ 'name' => 'My new apple',
+ 'created' => '2006-12-25 05:29:39',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:29:39',
+ 'mytime' => '22:57:17'
+ ))),
+ 'Sample' => array(
+ 'id' => '',
+ 'apple_id' => '',
+ 'name' => ''
+ )),
+ array(
+ 'Apple' => array(
+ 'id' => 7,
+ 'apple_id' => 6,
+ 'color' => 'Some wierd color',
+ 'name' => 'Some odd color',
+ 'created' => '2006-12-25 05:34:21',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:34:21',
+ 'mytime' => '22:57:17'
+ ),
+ 'Parent' => array(
+ 'id' => 6,
+ 'apple_id' => 4,
+ 'color' => 'My new appleOrange',
+ 'name' => 'My new apple',
+ 'created' => '2006-12-25 05:29:39',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:29:39',
+ 'mytime' => '22:57:17',
+ 'Parent' => array(
+ 'id' => 4,
+ 'apple_id' => 2,
+ 'color' => 'Blue Green',
+ 'name' => 'Test Name',
+ 'created' => '2006-12-25 05:23:36',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:23:36',
+ 'mytime' => '22:57:17'
+ ),
+ 'Sample' => array(),
+ 'Child' => array(
+ array(
+ 'id' => 7,
+ 'apple_id' => 6,
+ 'color' => 'Some wierd color',
+ 'name' => 'Some odd color',
+ 'created' => '2006-12-25 05:34:21',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:34:21',
+ 'mytime' => '22:57:17'
+ ))),
+ 'Sample' => array(
+ 'id' => '',
+ 'apple_id' => '',
+ 'name' => ''
+ )));
+ $this->assertEqual($result, $expected);
+
+ $result = $TestModel->Parent->unbindModel(array('belongsTo' => array('Parent')));
+ $this->assertTrue($result);
+
+ $result = $TestModel->unbindModel(array('hasMany' => array('Child')));
+ $this->assertTrue($result);
+
+ $result = $TestModel->find('all');
+ $expected = array(
+ array(
+ 'Apple' => array(
+ 'id' => 1,
+ 'apple_id' => 2,
+ 'color' => 'Red 1',
+ 'name' => 'Red Apple 1',
+ 'created' => '2006-11-22 10:38:58',
+ 'date' => '1951-01-04',
+ 'modified' => '2006-12-01 13:31:26',
+ 'mytime' => '22:57:17'
+ ),
+ 'Parent' => array(
+ 'id' => 2,
+ 'apple_id' => 1,
+ 'color' => 'Bright Red 1',
+ 'name' => 'Bright Red Apple',
+ 'created' => '2006-11-22 10:43:13',
+ 'date' => '2014-01-01',
+ 'modified' => '2006-11-30 18:38:10',
+ 'mytime' => '22:57:17',
+ 'Sample' => array(
+ 'id' => 2,
+ 'apple_id' => 2,
+ 'name' => 'sample2'
+ ),
+ 'Child' => array(
+ array(
+ 'id' => 1,
+ 'apple_id' => 2,
+ 'color' => 'Red 1',
+ 'name' => 'Red Apple 1',
+ 'created' => '2006-11-22 10:38:58',
+ 'date' => '1951-01-04',
+ 'modified' => '2006-12-01 13:31:26',
+ 'mytime' => '22:57:17'
+ ),
+ array(
+ 'id' => 3,
+ 'apple_id' => 2,
+ 'color' => 'blue green',
+ 'name' => 'green blue',
+ 'created' => '2006-12-25 05:13:36',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:23:24',
+ 'mytime' => '22:57:17'
+ ),
+ array(
+ 'id' => 4,
+ 'apple_id' => 2,
+ 'color' => 'Blue Green',
+ 'name' => 'Test Name',
+ 'created' => '2006-12-25 05:23:36',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:23:36',
+ 'mytime' => '22:57:17'
+ ))),
+ 'Sample' => array(
+ 'id' =>'',
+ 'apple_id' => '',
+ 'name' => ''
+ )),
+ array(
+ 'Apple' => array(
+ 'id' => 2,
+ 'apple_id' => 1,
+ 'color' => 'Bright Red 1',
+ 'name' => 'Bright Red Apple',
+ 'created' => '2006-11-22 10:43:13',
+ 'date' => '2014-01-01',
+ 'modified' => '2006-11-30 18:38:10',
+ 'mytime' => '22:57:17'
+ ),
+ 'Parent' => array(
+ 'id' => 1,
+ 'apple_id' => 2,
+ 'color' => 'Red 1',
+ 'name' => 'Red Apple 1',
+ 'created' => '2006-11-22 10:38:58',
+ 'date' => '1951-01-04',
+ 'modified' => '2006-12-01 13:31:26',
+ 'mytime' => '22:57:17',
+ 'Sample' => array(),
+ 'Child' => array(
+ array(
+ 'id' => 2,
+ 'apple_id' => 1,
+ 'color' => 'Bright Red 1',
+ 'name' => 'Bright Red Apple',
+ 'created' => '2006-11-22 10:43:13',
+ 'date' => '2014-01-01',
+ 'modified' => '2006-11-30 18:38:10',
+ 'mytime' => '22:57:17'
+ ))),
+ 'Sample' => array(
+ 'id' => 2,
+ 'apple_id' => 2,
+ 'name' => 'sample2',
+ 'Apple' => array(
+ 'id' => 2,
+ 'apple_id' => 1,
+ 'color' => 'Bright Red 1',
+ 'name' => 'Bright Red Apple',
+ 'created' => '2006-11-22 10:43:13',
+ 'date' => '2014-01-01',
+ 'modified' => '2006-11-30 18:38:10',
+ 'mytime' => '22:57:17'
+ ))),
+ array(
+ 'Apple' => array(
+ 'id' => 3,
+ 'apple_id' => 2,
+ 'color' => 'blue green',
+ 'name' => 'green blue',
+ 'created' => '2006-12-25 05:13:36',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:23:24',
+ 'mytime' => '22:57:17'
+ ),
+ 'Parent' => array(
+ 'id' => 2,
+ 'apple_id' => 1,
+ 'color' => 'Bright Red 1',
+ 'name' => 'Bright Red Apple',
+ 'created' => '2006-11-22 10:43:13',
+ 'date' => '2014-01-01',
+ 'modified' => '2006-11-30 18:38:10',
+ 'mytime' => '22:57:17',
+ 'Sample' => array(
+ 'id' => 2,
+ 'apple_id' => 2,
+ 'name' => 'sample2'
+ ),
+ 'Child' => array(
+ array(
+ 'id' => 1,
+ 'apple_id' => 2,
+ 'color' => 'Red 1',
+ 'name' => 'Red Apple 1',
+ 'created' => '2006-11-22 10:38:58',
+ 'date' => '1951-01-04',
+ 'modified' => '2006-12-01 13:31:26',
+ 'mytime' => '22:57:17'
+ ),
+ array(
+ 'id' => 3,
+ 'apple_id' => 2,
+ 'color' => 'blue green',
+ 'name' => 'green blue',
+ 'created' => '2006-12-25 05:13:36',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:23:24',
+ 'mytime' => '22:57:17'
+ ),
+ array(
+ 'id' => 4,
+ 'apple_id' => 2,
+ 'color' => 'Blue Green',
+ 'name' => 'Test Name',
+ 'created' => '2006-12-25 05:23:36',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:23:36',
+ 'mytime' => '22:57:17'
+ ))),
+ 'Sample' => array(
+ 'id' => 1,
+ 'apple_id' => 3,
+ 'name' => 'sample1',
+ 'Apple' => array(
+ 'id' => 3,
+ 'apple_id' => 2,
+ 'color' => 'blue green',
+ 'name' => 'green blue',
+ 'created' => '2006-12-25 05:13:36',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:23:24',
+ 'mytime' => '22:57:17'
+ ))),
+ array(
+ 'Apple' => array(
+ 'id' => 4,
+ 'apple_id' => 2,
+ 'color' => 'Blue Green',
+ 'name' => 'Test Name',
+ 'created' => '2006-12-25 05:23:36',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:23:36',
+ 'mytime' => '22:57:17'
+ ),
+ 'Parent' => array(
+ 'id' => 2,
+ 'apple_id' => 1,
+ 'color' => 'Bright Red 1',
+ 'name' => 'Bright Red Apple',
+ 'created' => '2006-11-22 10:43:13',
+ 'date' => '2014-01-01',
+ 'modified' => '2006-11-30 18:38:10',
+ 'mytime' => '22:57:17',
+ 'Sample' => array(
+ 'id' => 2,
+ 'apple_id' => 2,
+ 'name' => 'sample2'
+ ),
+ 'Child' => array(
+ array(
+ 'id' => 1,
+ 'apple_id' => 2,
+ 'color' => 'Red 1',
+ 'name' => 'Red Apple 1',
+ 'created' => '2006-11-22 10:38:58',
+ 'date' => '1951-01-04',
+ 'modified' => '2006-12-01 13:31:26',
+ 'mytime' => '22:57:17'
+ ),
+ array(
+ 'id' => 3,
+ 'apple_id' => 2,
+ 'color' => 'blue green',
+ 'name' => 'green blue',
+ 'created' => '2006-12-25 05:13:36',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:23:24',
+ 'mytime' => '22:57:17'
+ ),
+ array(
+ 'id' => 4,
+ 'apple_id' => 2,
+ 'color' => 'Blue Green',
+ 'name' => 'Test Name',
+ 'created' => '2006-12-25 05:23:36',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:23:36',
+ 'mytime' => '22:57:17'
+ ))),
+ 'Sample' => array(
+ 'id' => 3,
+ 'apple_id' => 4,
+ 'name' => 'sample3',
+ 'Apple' => array(
+ 'id' => 4,
+ 'apple_id' => 2,
+ 'color' => 'Blue Green',
+ 'name' => 'Test Name',
+ 'created' => '2006-12-25 05:23:36',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:23:36',
+ 'mytime' => '22:57:17'
+ ))),
+ array(
+ 'Apple' => array(
+ 'id' => 5,
+ 'apple_id' => 5,
+ 'color' => 'Green',
+ 'name' => 'Blue Green',
+ 'created' => '2006-12-25 05:24:06',
+ 'date' => '2006-12-25',
+ 'modified' =>
+ '2006-12-25 05:29:16',
+ 'mytime' => '22:57:17'
+ ),
+ 'Parent' => array(
+ 'id' => 5,
+ 'apple_id' => 5,
+ 'color' => 'Green',
+ 'name' => 'Blue Green',
+ 'created' => '2006-12-25 05:24:06',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:29:16',
+ 'mytime' => '22:57:17',
+ 'Sample' => array(
+ 'id' => 4,
+ 'apple_id' => 5,
+ 'name' => 'sample4'
+ ),
+ 'Child' => array(
+ array(
+ 'id' => 5,
+ 'apple_id' => 5,
+ 'color' => 'Green',
+ 'name' => 'Blue Green',
+ 'created' => '2006-12-25 05:24:06',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:29:16',
+ 'mytime' => '22:57:17'
+ ))),
+ 'Sample' => array(
+ 'id' => 4,
+ 'apple_id' => 5,
+ 'name' => 'sample4',
+ 'Apple' => array(
+ 'id' => 5,
+ 'apple_id' => 5,
+ 'color' => 'Green',
+ 'name' => 'Blue Green',
+ 'created' => '2006-12-25 05:24:06',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:29:16',
+ 'mytime' => '22:57:17'
+ ))),
+ array(
+ 'Apple' => array(
+ 'id' => 6,
+ 'apple_id' => 4,
+ 'color' => 'My new appleOrange',
+ 'name' => 'My new apple',
+ 'created' => '2006-12-25 05:29:39',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:29:39',
+ 'mytime' => '22:57:17'),
+ 'Parent' => array(
+ 'id' => 4,
+ 'apple_id' => 2,
+ 'color' => 'Blue Green',
+ 'name' => 'Test Name',
+ 'created' => '2006-12-25 05:23:36',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:23:36',
+ 'mytime' => '22:57:17',
+ 'Sample' => array(
+ 'id' => 3,
+ 'apple_id' => 4,
+ 'name' => 'sample3'
+ ),
+ 'Child' => array(
+ array(
+ 'id' => 6,
+ 'apple_id' => 4,
+ 'color' => 'My new appleOrange',
+ 'name' => 'My new apple',
+ 'created' => '2006-12-25 05:29:39',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:29:39',
+ 'mytime' => '22:57:17'
+ ))),
+ 'Sample' => array(
+ 'id' => '',
+ 'apple_id' => '',
+ 'name' => ''
+ )),
+ array(
+ 'Apple' => array(
+ 'id' => 7,
+ 'apple_id' => 6,
+ 'color' => 'Some wierd color',
+ 'name' => 'Some odd color',
+ 'created' => '2006-12-25 05:34:21',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:34:21',
+ 'mytime' => '22:57:17'
+ ),
+ 'Parent' => array(
+ 'id' => 6,
+ 'apple_id' => 4,
+ 'color' => 'My new appleOrange',
+ 'name' => 'My new apple',
+ 'created' => '2006-12-25 05:29:39',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:29:39',
+ 'mytime' => '22:57:17',
+ 'Sample' => array(),
+ 'Child' => array(
+ array(
+ 'id' => 7,
+ 'apple_id' => 6,
+ 'color' => 'Some wierd color',
+ 'name' => 'Some odd color',
+ 'created' => '2006-12-25 05:34:21',
+ 'date' => '2006-12-25', 'modified' =>
+ '2006-12-25 05:34:21',
+ 'mytime' => '22:57:17'
+ ))),
+ 'Sample' => array(
+ 'id' => '',
+ 'apple_id' => '',
+ 'name' => ''
+ )));
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testSelfAssociationAfterFind method
+ *
+ * @access public
+ * @return void
+ */
+ function testSelfAssociationAfterFind() {
+ $this->loadFixtures('Apple');
+ $afterFindModel = new NodeAfterFind();
+ $afterFindModel->recursive = 3;
+ $afterFindData = $afterFindModel->find('all');
+
+ $duplicateModel = new NodeAfterFind();
+ $duplicateModel->recursive = 3;
+ $duplicateModelData = $duplicateModel->find('all');
+
+ $noAfterFindModel = new NodeNoAfterFind();
+ $noAfterFindModel->recursive = 3;
+ $noAfterFindData = $noAfterFindModel->find('all');
+
+ $this->assertFalse($afterFindModel == $noAfterFindModel);
+ // Limitation of PHP 4 and PHP 5 > 5.1.6 when comparing recursive objects
+ if (PHP_VERSION === '5.1.6') {
+ $this->assertFalse($afterFindModel != $duplicateModel);
+ }
+ $this->assertEqual($afterFindData, $noAfterFindData);
+ }
+
+/**
+ * testFindAllThreaded method
+ *
+ * @access public
+ * @return void
+ */
+ function testFindAllThreaded() {
+ $this->loadFixtures('Category');
+ $TestModel =& new Category();
+
+ $result = $TestModel->find('threaded');
+ $expected = array(
+ array(
+ 'Category' => array(
+ 'id' => '1',
+ 'parent_id' => '0',
+ 'name' => 'Category 1',
+ 'created' => '2007-03-18 15:30:23',
+ 'updated' => '2007-03-18 15:32:31'
+ ),
+ 'children' => array(
+ array(
+ 'Category' => array(
+ 'id' => '2',
+ 'parent_id' => '1',
+ 'name' => 'Category 1.1',
+ 'created' => '2007-03-18 15:30:23',
+ 'updated' => '2007-03-18 15:32:31'
+ ),
+ 'children' => array(
+ array('Category' => array(
+ 'id' => '7',
+ 'parent_id' => '2',
+ 'name' => 'Category 1.1.1',
+ 'created' => '2007-03-18 15:30:23',
+ 'updated' => '2007-03-18 15:32:31'),
+ 'children' => array()),
+ array('Category' => array(
+ 'id' => '8',
+ 'parent_id' => '2',
+ 'name' => 'Category 1.1.2',
+ 'created' => '2007-03-18 15:30:23',
+ 'updated' => '2007-03-18 15:32:31'),
+ 'children' => array()))
+ ),
+ array(
+ 'Category' => array(
+ 'id' => '3',
+ 'parent_id' => '1',
+ 'name' => 'Category 1.2',
+ 'created' => '2007-03-18 15:30:23',
+ 'updated' => '2007-03-18 15:32:31'
+ ),
+ 'children' => array()
+ )
+ )
+ ),
+ array(
+ 'Category' => array(
+ 'id' => '4',
+ 'parent_id' => '0',
+ 'name' => 'Category 2',
+ 'created' => '2007-03-18 15:30:23',
+ 'updated' => '2007-03-18 15:32:31'
+ ),
+ 'children' => array()
+ ),
+ array(
+ 'Category' => array(
+ 'id' => '5',
+ 'parent_id' => '0',
+ 'name' => 'Category 3',
+ 'created' => '2007-03-18 15:30:23',
+ 'updated' => '2007-03-18 15:32:31'
+ ),
+ 'children' => array(
+ array(
+ 'Category' => array(
+ 'id' => '6',
+ 'parent_id' => '5',
+ 'name' => 'Category 3.1',
+ 'created' => '2007-03-18 15:30:23',
+ 'updated' => '2007-03-18 15:32:31'
+ ),
+ 'children' => array()
+ )
+ )
+ )
+ );
+ $this->assertEqual($result, $expected);
+
+ $result = $TestModel->find('threaded', array(
+ 'conditions' => array('Category.name LIKE' => 'Category 1%')
+ ));
+
+ $expected = array(
+ array(
+ 'Category' => array(
+ 'id' => '1',
+ 'parent_id' => '0',
+ 'name' => 'Category 1',
+ 'created' => '2007-03-18 15:30:23',
+ 'updated' => '2007-03-18 15:32:31'
+ ),
+ 'children' => array(
+ array(
+ 'Category' => array(
+ 'id' => '2',
+ 'parent_id' => '1',
+ 'name' => 'Category 1.1',
+ 'created' => '2007-03-18 15:30:23',
+ 'updated' => '2007-03-18 15:32:31'
+ ),
+ 'children' => array(
+ array('Category' => array(
+ 'id' => '7',
+ 'parent_id' => '2',
+ 'name' => 'Category 1.1.1',
+ 'created' => '2007-03-18 15:30:23',
+ 'updated' => '2007-03-18 15:32:31'),
+ 'children' => array()),
+ array('Category' => array(
+ 'id' => '8',
+ 'parent_id' => '2',
+ 'name' => 'Category 1.1.2',
+ 'created' => '2007-03-18 15:30:23',
+ 'updated' => '2007-03-18 15:32:31'),
+ 'children' => array()))
+ ),
+ array(
+ 'Category' => array(
+ 'id' => '3',
+ 'parent_id' => '1',
+ 'name' => 'Category 1.2',
+ 'created' => '2007-03-18 15:30:23',
+ 'updated' => '2007-03-18 15:32:31'
+ ),
+ 'children' => array()
+ )
+ )
+ )
+ );
+ $this->assertEqual($result, $expected);
+
+ $result = $TestModel->find('threaded', array(
+ 'fields' => 'id, parent_id, name'
+ ));
+
+ $expected = array(
+ array(
+ 'Category' => array(
+ 'id' => '1',
+ 'parent_id' => '0',
+ 'name' => 'Category 1'
+ ),
+ 'children' => array(
+ array(
+ 'Category' => array(
+ 'id' => '2',
+ 'parent_id' => '1',
+ 'name' => 'Category 1.1'
+ ),
+ 'children' => array(
+ array('Category' => array(
+ 'id' => '7',
+ 'parent_id' => '2',
+ 'name' => 'Category 1.1.1'),
+ 'children' => array()),
+ array('Category' => array(
+ 'id' => '8',
+ 'parent_id' => '2',
+ 'name' => 'Category 1.1.2'),
+ 'children' => array()))
+ ),
+ array(
+ 'Category' => array(
+ 'id' => '3',
+ 'parent_id' => '1',
+ 'name' => 'Category 1.2'
+ ),
+ 'children' => array()
+ )
+ )
+ ),
+ array(
+ 'Category' => array(
+ 'id' => '4',
+ 'parent_id' => '0',
+ 'name' => 'Category 2'
+ ),
+ 'children' => array()
+ ),
+ array(
+ 'Category' => array(
+ 'id' => '5',
+ 'parent_id' => '0',
+ 'name' => 'Category 3'
+ ),
+ 'children' => array(
+ array(
+ 'Category' => array(
+ 'id' => '6',
+ 'parent_id' => '5',
+ 'name' => 'Category 3.1'
+ ),
+ 'children' => array()
+ )
+ )
+ )
+ );
+ $this->assertEqual($result, $expected);
+
+ $result = $TestModel->find('threaded', array('order' => 'id DESC'));
+
+ $expected = array(
+ array(
+ 'Category' => array(
+ 'id' => 5,
+ 'parent_id' => 0,
+ 'name' => 'Category 3',
+ 'created' => '2007-03-18 15:30:23',
+ 'updated' => '2007-03-18 15:32:31'
+ ),
+ 'children' => array(
+ array(
+ 'Category' => array(
+ 'id' => 6,
+ 'parent_id' => 5,
+ 'name' => 'Category 3.1',
+ 'created' => '2007-03-18 15:30:23',
+ 'updated' => '2007-03-18 15:32:31'
+ ),
+ 'children' => array()
+ )
+ )
+ ),
+ array(
+ 'Category' => array(
+ 'id' => 4,
+ 'parent_id' => 0,
+ 'name' => 'Category 2',
+ 'created' => '2007-03-18 15:30:23',
+ 'updated' => '2007-03-18 15:32:31'
+ ),
+ 'children' => array()
+ ),
+ array(
+ 'Category' => array(
+ 'id' => 1,
+ 'parent_id' => 0,
+ 'name' => 'Category 1',
+ 'created' => '2007-03-18 15:30:23',
+ 'updated' => '2007-03-18 15:32:31'
+ ),
+ 'children' => array(
+ array(
+ 'Category' => array(
+ 'id' => 3,
+ 'parent_id' => 1,
+ 'name' => 'Category 1.2',
+ 'created' => '2007-03-18 15:30:23',
+ 'updated' => '2007-03-18 15:32:31'
+ ),
+ 'children' => array()
+ ),
+ array(
+ 'Category' => array(
+ 'id' => 2,
+ 'parent_id' => 1,
+ 'name' => 'Category 1.1',
+ 'created' => '2007-03-18 15:30:23',
+ 'updated' => '2007-03-18 15:32:31'
+ ),
+ 'children' => array(
+ array('Category' => array(
+ 'id' => '8',
+ 'parent_id' => '2',
+ 'name' => 'Category 1.1.2',
+ 'created' => '2007-03-18 15:30:23',
+ 'updated' => '2007-03-18 15:32:31'),
+ 'children' => array()),
+ array('Category' => array(
+ 'id' => '7',
+ 'parent_id' => '2',
+ 'name' => 'Category 1.1.1',
+ 'created' => '2007-03-18 15:30:23',
+ 'updated' => '2007-03-18 15:32:31'),
+ 'children' => array()))
+ )
+ )
+ )
+ );
+ $this->assertEqual($result, $expected);
+
+ $result = $TestModel->find('threaded', array(
+ 'conditions' => array('Category.name LIKE' => 'Category 3%')
+ ));
+ $expected = array(
+ array(
+ 'Category' => array(
+ 'id' => '5',
+ 'parent_id' => '0',
+ 'name' => 'Category 3',
+ 'created' => '2007-03-18 15:30:23',
+ 'updated' => '2007-03-18 15:32:31'
+ ),
+ 'children' => array(
+ array(
+ 'Category' => array(
+ 'id' => '6',
+ 'parent_id' => '5',
+ 'name' => 'Category 3.1',
+ 'created' => '2007-03-18 15:30:23',
+ 'updated' => '2007-03-18 15:32:31'
+ ),
+ 'children' => array()
+ )
+ )
+ )
+ );
+ $this->assertEqual($result, $expected);
+
+ $result = $TestModel->find('threaded', array(
+ 'conditions' => array('Category.name LIKE' => 'Category 1.1%')
+ ));
+ $expected = array(
+ array('Category' =>
+ array(
+ 'id' => '2',
+ 'parent_id' => '1',
+ 'name' => 'Category 1.1',
+ 'created' => '2007-03-18 15:30:23',
+ 'updated' => '2007-03-18 15:32:31'),
+ 'children' => array(
+ array('Category' => array(
+ 'id' => '7',
+ 'parent_id' => '2',
+ 'name' => 'Category 1.1.1',
+ 'created' => '2007-03-18 15:30:23',
+ 'updated' => '2007-03-18 15:32:31'),
+ 'children' => array()),
+ array('Category' => array(
+ 'id' => '8',
+ 'parent_id' => '2',
+ 'name' => 'Category 1.1.2',
+ 'created' => '2007-03-18 15:30:23',
+ 'updated' => '2007-03-18 15:32:31'),
+ 'children' => array()))));
+ $this->assertEqual($result, $expected);
+
+ $result = $TestModel->find('threaded', array(
+ 'fields' => 'id, parent_id, name',
+ 'conditions' => array('Category.id !=' => 2)
+ ));
+ $expected = array(
+ array(
+ 'Category' => array(
+ 'id' => '1',
+ 'parent_id' => '0',
+ 'name' => 'Category 1'
+ ),
+ 'children' => array(
+ array(
+ 'Category' => array(
+ 'id' => '3',
+ 'parent_id' => '1',
+ 'name' => 'Category 1.2'
+ ),
+ 'children' => array()
+ )
+ )
+ ),
+ array(
+ 'Category' => array(
+ 'id' => '4',
+ 'parent_id' => '0',
+ 'name' => 'Category 2'
+ ),
+ 'children' => array()
+ ),
+ array(
+ 'Category' => array(
+ 'id' => '5',
+ 'parent_id' => '0',
+ 'name' => 'Category 3'
+ ),
+ 'children' => array(
+ array(
+ 'Category' => array(
+ 'id' => '6',
+ 'parent_id' => '5',
+ 'name' => 'Category 3.1'
+ ),
+ 'children' => array()
+ )
+ )
+ )
+ );
+ $this->assertEqual($result, $expected);
+
+ $result = $TestModel->find('all', array(
+ 'fields' => 'id, name, parent_id',
+ 'conditions' => array('Category.id !=' => 1)
+ ));
+ $expected = array (
+ array ('Category' => array(
+ 'id' => '2',
+ 'name' => 'Category 1.1',
+ 'parent_id' => '1'
+ )),
+ array ('Category' => array(
+ 'id' => '3',
+ 'name' => 'Category 1.2',
+ 'parent_id' => '1'
+ )),
+ array ('Category' => array(
+ 'id' => '4',
+ 'name' => 'Category 2',
+ 'parent_id' => '0'
+ )),
+ array ('Category' => array(
+ 'id' => '5',
+ 'name' => 'Category 3',
+ 'parent_id' => '0'
+ )),
+ array ('Category' => array(
+ 'id' => '6',
+ 'name' => 'Category 3.1',
+ 'parent_id' => '5'
+ )),
+ array ('Category' => array(
+ 'id' => '7',
+ 'name' => 'Category 1.1.1',
+ 'parent_id' => '2'
+ )),
+ array ('Category' => array(
+ 'id' => '8',
+ 'name' => 'Category 1.1.2',
+ 'parent_id' => '2'
+ )));
+ $this->assertEqual($result, $expected);
+
+ $result = $TestModel->find('threaded', array(
+ 'fields' => 'id, parent_id, name',
+ 'conditions' => array('Category.id !=' => 1)
+ ));
+ $expected = array(
+ array(
+ 'Category' => array(
+ 'id' => '2',
+ 'parent_id' => '1',
+ 'name' => 'Category 1.1'
+ ),
+ 'children' => array(
+ array('Category' => array(
+ 'id' => '7',
+ 'parent_id' => '2',
+ 'name' => 'Category 1.1.1'),
+ 'children' => array()),
+ array('Category' => array(
+ 'id' => '8',
+ 'parent_id' => '2',
+ 'name' => 'Category 1.1.2'),
+ 'children' => array()))
+ ),
+ array(
+ 'Category' => array(
+ 'id' => '3',
+ 'parent_id' => '1',
+ 'name' => 'Category 1.2'
+ ),
+ 'children' => array()
+ )
+ );
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * test find('neighbors')
+ *
+ * @return void
+ * @access public
+ */
+ function testFindNeighbors() {
+ $this->loadFixtures('User', 'Article');
+ $TestModel =& new Article();
+
+ $TestModel->id = 1;
+ $result = $TestModel->find('neighbors', array('fields' => array('id')));
+ $expected = array(
+ 'prev' => null,
+ 'next' => array(
+ 'Article' => array('id' => 2)
+ ));
+ $this->assertEqual($result, $expected);
+
+ $TestModel->id = 2;
+ $result = $TestModel->find('neighbors', array(
+ 'fields' => array('id')
+ ));
+
+ $expected = array(
+ 'prev' => array(
+ 'Article' => array(
+ 'id' => 1
+ )),
+ 'next' => array(
+ 'Article' => array(
+ 'id' => 3
+ )));
+ $this->assertEqual($result, $expected);
+
+ $TestModel->id = 3;
+ $result = $TestModel->find('neighbors', array('fields' => array('id')));
+ $expected = array(
+ 'prev' => array(
+ 'Article' => array(
+ 'id' => 2
+ )),
+ 'next' => null
+ );
+ $this->assertEqual($result, $expected);
+
+ $TestModel->id = 1;
+ $result = $TestModel->find('neighbors', array('recursive' => -1));
+ $expected = array(
+ 'prev' => null,
+ 'next' => array(
+ 'Article' => array(
+ 'id' => 2,
+ 'user_id' => 3,
+ 'title' => 'Second Article',
+ 'body' => 'Second Article Body',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:41:23',
+ 'updated' => '2007-03-18 10:43:31'
+ )
+ )
+ );
+ $this->assertEqual($result, $expected);
+
+ $TestModel->id = 2;
+ $result = $TestModel->find('neighbors', array('recursive' => -1));
+ $expected = array(
+ 'prev' => array(
+ 'Article' => array(
+ 'id' => 1,
+ 'user_id' => 1,
+ 'title' => 'First Article',
+ 'body' => 'First Article Body',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:39:23',
+ 'updated' => '2007-03-18 10:41:31'
+ )
+ ),
+ 'next' => array(
+ 'Article' => array(
+ 'id' => 3,
+ 'user_id' => 1,
+ 'title' => 'Third Article',
+ 'body' => 'Third Article Body',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:43:23',
+ 'updated' => '2007-03-18 10:45:31'
+ )
+ )
+ );
+ $this->assertEqual($result, $expected);
+
+ $TestModel->id = 3;
+ $result = $TestModel->find('neighbors', array('recursive' => -1));
+ $expected = array(
+ 'prev' => array(
+ 'Article' => array(
+ 'id' => 2,
+ 'user_id' => 3,
+ 'title' => 'Second Article',
+ 'body' => 'Second Article Body',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:41:23',
+ 'updated' => '2007-03-18 10:43:31'
+ )
+ ),
+ 'next' => null
+ );
+ $this->assertEqual($result, $expected);
+
+ $TestModel->recursive = 0;
+ $TestModel->id = 1;
+ $one = $TestModel->read();
+ $TestModel->id = 2;
+ $two = $TestModel->read();
+ $TestModel->id = 3;
+ $three = $TestModel->read();
+
+ $TestModel->id = 1;
+ $result = $TestModel->find('neighbors');
+ $expected = array('prev' => null, 'next' => $two);
+ $this->assertEqual($result, $expected);
+
+ $TestModel->id = 2;
+ $result = $TestModel->find('neighbors');
+ $expected = array('prev' => $one, 'next' => $three);
+ $this->assertEqual($result, $expected);
+
+ $TestModel->id = 3;
+ $result = $TestModel->find('neighbors');
+ $expected = array('prev' => $two, 'next' => null);
+ $this->assertEqual($result, $expected);
+
+ $TestModel->recursive = 2;
+ $TestModel->id = 1;
+ $one = $TestModel->read();
+ $TestModel->id = 2;
+ $two = $TestModel->read();
+ $TestModel->id = 3;
+ $three = $TestModel->read();
+
+ $TestModel->id = 1;
+ $result = $TestModel->find('neighbors', array('recursive' => 2));
+ $expected = array('prev' => null, 'next' => $two);
+ $this->assertEqual($result, $expected);
+
+ $TestModel->id = 2;
+ $result = $TestModel->find('neighbors', array('recursive' => 2));
+ $expected = array('prev' => $one, 'next' => $three);
+ $this->assertEqual($result, $expected);
+
+ $TestModel->id = 3;
+ $result = $TestModel->find('neighbors', array('recursive' => 2));
+ $expected = array('prev' => $two, 'next' => null);
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testFindCombinedRelations method
+ *
+ * @access public
+ * @return void
+ */
+ function testFindCombinedRelations() {
+ $this->loadFixtures('Apple', 'Sample');
+ $TestModel =& new Apple();
+
+ $result = $TestModel->find('all');
+
+ $expected = array(
+ array(
+ 'Apple' => array(
+ 'id' => '1',
+ 'apple_id' => '2',
+ 'color' => 'Red 1',
+ 'name' => 'Red Apple 1',
+ 'created' => '2006-11-22 10:38:58',
+ 'date' => '1951-01-04',
+ 'modified' => '2006-12-01 13:31:26',
+ 'mytime' => '22:57:17'
+ ),
+ 'Parent' => array(
+ 'id' => '2',
+ 'apple_id' => '1',
+ 'color' => 'Bright Red 1',
+ 'name' => 'Bright Red Apple',
+ 'created' => '2006-11-22 10:43:13',
+ 'date' => '2014-01-01',
+ 'modified' => '2006-11-30 18:38:10',
+ 'mytime' => '22:57:17'
+ ),
+ 'Sample' => array(
+ 'id' => null,
+ 'apple_id' => null,
+ 'name' => null
+ ),
+ 'Child' => array(
+ array(
+ 'id' => '2',
+ 'apple_id' => '1',
+ 'color' => 'Bright Red 1',
+ 'name' => 'Bright Red Apple',
+ 'created' => '2006-11-22 10:43:13',
+ 'date' => '2014-01-01',
+ 'modified' => '2006-11-30 18:38:10',
+ 'mytime' => '22:57:17'
+ ))),
+ array(
+ 'Apple' => array(
+ 'id' => '2',
+ 'apple_id' => '1',
+ 'color' => 'Bright Red 1',
+ 'name' => 'Bright Red Apple',
+ 'created' => '2006-11-22 10:43:13',
+ 'date' => '2014-01-01',
+ 'modified' => '2006-11-30 18:38:10',
+ 'mytime' => '22:57:17'
+ ),
+ 'Parent' => array(
+ 'id' => '1',
+ 'apple_id' => '2',
+ 'color' => 'Red 1',
+ 'name' => 'Red Apple 1',
+ 'created' => '2006-11-22 10:38:58',
+ 'date' => '1951-01-04',
+ 'modified' => '2006-12-01 13:31:26',
+ 'mytime' => '22:57:17'
+ ),
+ 'Sample' => array(
+ 'id' => '2',
+ 'apple_id' => '2',
+ 'name' => 'sample2'
+ ),
+ 'Child' => array(
+ array(
+ 'id' => '1',
+ 'apple_id' => '2',
+ 'color' => 'Red 1',
+ 'name' => 'Red Apple 1',
+ 'created' => '2006-11-22 10:38:58',
+ 'date' => '1951-01-04',
+ 'modified' => '2006-12-01 13:31:26',
+ 'mytime' => '22:57:17'
+ ),
+ array(
+ 'id' => '3',
+ 'apple_id' => '2',
+ 'color' => 'blue green',
+ 'name' => 'green blue',
+ 'created' => '2006-12-25 05:13:36',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:23:24',
+ 'mytime' => '22:57:17'
+ ),
+ array(
+ 'id' => '4',
+ 'apple_id' => '2',
+ 'color' => 'Blue Green',
+ 'name' => 'Test Name',
+ 'created' => '2006-12-25 05:23:36',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:23:36',
+ 'mytime' => '22:57:17'
+ ))),
+ array(
+ 'Apple' => array(
+ 'id' => '3',
+ 'apple_id' => '2',
+ 'color' => 'blue green',
+ 'name' => 'green blue',
+ 'created' => '2006-12-25 05:13:36',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:23:24',
+ 'mytime' => '22:57:17'
+ ),
+ 'Parent' => array(
+ 'id' => '2',
+ 'apple_id' => '1',
+ 'color' => 'Bright Red 1',
+ 'name' => 'Bright Red Apple',
+ 'created' => '2006-11-22 10:43:13',
+ 'date' => '2014-01-01',
+ 'modified' => '2006-11-30 18:38:10',
+ 'mytime' => '22:57:17'
+ ),
+ 'Sample' => array(
+ 'id' => '1',
+ 'apple_id' => '3',
+ 'name' => 'sample1'
+ ),
+ 'Child' => array()
+ ),
+ array(
+ 'Apple' => array(
+ 'id' => '4',
+ 'apple_id' => '2',
+ 'color' => 'Blue Green',
+ 'name' => 'Test Name',
+ 'created' => '2006-12-25 05:23:36',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:23:36',
+ 'mytime' => '22:57:17'
+ ),
+ 'Parent' => array(
+ 'id' => '2',
+ 'apple_id' => '1',
+ 'color' => 'Bright Red 1',
+ 'name' => 'Bright Red Apple',
+ 'created' => '2006-11-22 10:43:13',
+ 'date' => '2014-01-01',
+ 'modified' => '2006-11-30 18:38:10',
+ 'mytime' => '22:57:17'
+ ),
+ 'Sample' => array(
+ 'id' => '3',
+ 'apple_id' => '4',
+ 'name' => 'sample3'
+ ),
+ 'Child' => array(
+ array(
+ 'id' => '6',
+ 'apple_id' => '4',
+ 'color' => 'My new appleOrange',
+ 'name' => 'My new apple',
+ 'created' => '2006-12-25 05:29:39',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:29:39',
+ 'mytime' => '22:57:17'
+ ))),
+ array(
+ 'Apple' => array(
+ 'id' => '5',
+ 'apple_id' => '5',
+ 'color' => 'Green',
+ 'name' => 'Blue Green',
+ 'created' => '2006-12-25 05:24:06',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:29:16',
+ 'mytime' => '22:57:17'
+ ),
+ 'Parent' => array(
+ 'id' => '5',
+ 'apple_id' => '5',
+ 'color' => 'Green',
+ 'name' => 'Blue Green',
+ 'created' => '2006-12-25 05:24:06',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:29:16',
+ 'mytime' => '22:57:17'
+ ),
+ 'Sample' => array(
+ 'id' => '4',
+ 'apple_id' => '5',
+ 'name' => 'sample4'
+ ),
+ 'Child' => array(
+ array(
+ 'id' => '5',
+ 'apple_id' => '5',
+ 'color' => 'Green',
+ 'name' => 'Blue Green',
+ 'created' => '2006-12-25 05:24:06',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:29:16',
+ 'mytime' => '22:57:17'
+ ))),
+ array(
+ 'Apple' => array(
+ 'id' => '6',
+ 'apple_id' => '4',
+ 'color' => 'My new appleOrange',
+ 'name' => 'My new apple',
+ 'created' => '2006-12-25 05:29:39',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:29:39',
+ 'mytime' => '22:57:17'
+ ),
+ 'Parent' => array(
+ 'id' => '4',
+ 'apple_id' => '2',
+ 'color' => 'Blue Green',
+ 'name' => 'Test Name',
+ 'created' => '2006-12-25 05:23:36',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:23:36',
+ 'mytime' => '22:57:17'
+ ),
+ 'Sample' => array(
+ 'id' => null,
+ 'apple_id' => null,
+ 'name' => null
+ ),
+ 'Child' => array(
+ array(
+ 'id' => '7',
+ 'apple_id' => '6',
+ 'color' => 'Some wierd color',
+ 'name' => 'Some odd color',
+ 'created' => '2006-12-25 05:34:21',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:34:21',
+ 'mytime' => '22:57:17'
+ ))),
+ array(
+ 'Apple' => array(
+ 'id' => '7',
+ 'apple_id' => '6',
+ 'color' => 'Some wierd color',
+ 'name' => 'Some odd color',
+ 'created' => '2006-12-25 05:34:21',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:34:21',
+ 'mytime' => '22:57:17'
+ ),
+ 'Parent' => array(
+ 'id' => '6',
+ 'apple_id' => '4',
+ 'color' => 'My new appleOrange',
+ 'name' => 'My new apple',
+ 'created' => '2006-12-25 05:29:39',
+ 'date' => '2006-12-25',
+ 'modified' => '2006-12-25 05:29:39',
+ 'mytime' => '22:57:17'
+ ),
+ 'Sample' => array(
+ 'id' => null,
+ 'apple_id' => null,
+ 'name' => null
+ ),
+ 'Child' => array()
+ ));
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testSaveEmpty method
+ *
+ * @access public
+ * @return void
+ */
+ function testSaveEmpty() {
+ $this->loadFixtures('Thread');
+ $TestModel =& new Thread();
+ $data = array();
+ $expected = $TestModel->save($data);
+ $this->assertFalse($expected);
+ }
+
+/**
+ * testFindAllWithConditionInChildQuery
+ *
+ * @todo external conditions like this are going to need to be revisited at some point
+ * @access public
+ * @return void
+ */
+ function testFindAllWithConditionInChildQuery() {
+ $this->loadFixtures('Basket', 'FilmFile');
+
+ $TestModel =& new Basket();
+ $recursive = 3;
+ $result = $TestModel->find('all', compact('conditions', 'recursive'));
+
+ $expected = array(
+ array(
+ 'Basket' => array(
+ 'id' => 1,
+ 'type' => 'nonfile',
+ 'name' => 'basket1',
+ 'object_id' => 1,
+ 'user_id' => 1,
+ ),
+ 'FilmFile' => array(
+ 'id' => '',
+ 'name' => '',
+ )
+ ),
+ array(
+ 'Basket' => array(
+ 'id' => 2,
+ 'type' => 'file',
+ 'name' => 'basket2',
+ 'object_id' => 2,
+ 'user_id' => 1,
+ ),
+ 'FilmFile' => array(
+ 'id' => 2,
+ 'name' => 'two',
+ )
+ ),
+ );
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testFindAllWithConditionsHavingMixedDataTypes method
+ *
+ * @access public
+ * @return void
+ */
+ function testFindAllWithConditionsHavingMixedDataTypes() {
+ $this->loadFixtures('Article');
+ $TestModel =& new Article();
+ $expected = array(
+ array(
+ 'Article' => array(
+ 'id' => 1,
+ 'user_id' => 1,
+ 'title' => 'First Article',
+ 'body' => 'First Article Body',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:39:23',
+ 'updated' => '2007-03-18 10:41:31'
+ )
+ ),
+ array(
+ 'Article' => array(
+ 'id' => 2,
+ 'user_id' => 3,
+ 'title' => 'Second Article',
+ 'body' => 'Second Article Body',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:41:23',
+ 'updated' => '2007-03-18 10:43:31'
+ )
+ )
+ );
+ $conditions = array('id' => array('1', 2));
+ $recursive = -1;
+ $order = 'Article.id ASC';
+ $result = $TestModel->find('all', compact('conditions', 'recursive', 'order'));
+ $this->assertEqual($result, $expected);
+
+ if ($this->skipIf($this->db->config['driver'] == 'postgres', 'The rest of testFindAllWithConditionsHavingMixedDataTypes test is not compatible with Postgres')) {
+ return;
+ }
+ $conditions = array('id' => array('1', 2, '3.0'));
+ $order = 'Article.id ASC';
+ $result = $TestModel->find('all', compact('recursive', 'conditions', 'order'));
+ $expected = array(
+ array(
+ 'Article' => array(
+ 'id' => 1,
+ 'user_id' => 1,
+ 'title' => 'First Article',
+ 'body' => 'First Article Body',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:39:23',
+ 'updated' => '2007-03-18 10:41:31'
+ )
+ ),
+ array(
+ 'Article' => array(
+ 'id' => 2,
+ 'user_id' => 3,
+ 'title' => 'Second Article',
+ 'body' => 'Second Article Body',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:41:23',
+ 'updated' => '2007-03-18 10:43:31'
+ )
+ ),
+ array(
+ 'Article' => array(
+ 'id' => 3,
+ 'user_id' => 1,
+ 'title' => 'Third Article',
+ 'body' => 'Third Article Body',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:43:23',
+ 'updated' => '2007-03-18 10:45:31'
+ )
+ )
+ );
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testBindUnbind method
+ *
+ * @access public
+ * @return void
+ */
+ function testBindUnbind() {
+ $this->loadFixtures('User', 'Comment', 'FeatureSet');
+ $TestModel =& new User();
+
+ $result = $TestModel->hasMany;
+ $expected = array();
+ $this->assertEqual($result, $expected);
+
+ $result = $TestModel->bindModel(array('hasMany' => array('Comment')));
+ $this->assertTrue($result);
+
+ $result = $TestModel->find('all', array(
+ 'fields' => 'User.id, User.user'
+ ));
+ $expected = array(
+ array(
+ 'User' => array(
+ 'id' => '1',
+ 'user' => 'mariano'
+ ),
+ 'Comment' => array(
+ array(
+ 'id' => '3',
+ 'article_id' => '1',
+ 'user_id' => '1',
+ 'comment' => 'Third Comment for First Article',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:49:23',
+ 'updated' => '2007-03-18 10:51:31'
+ ),
+ array(
+ 'id' => '4',
+ 'article_id' => '1',
+ 'user_id' => '1',
+ 'comment' => 'Fourth Comment for First Article',
+ 'published' => 'N',
+ 'created' => '2007-03-18 10:51:23',
+ 'updated' => '2007-03-18 10:53:31'
+ ),
+ array(
+ 'id' => '5',
+ 'article_id' => '2',
+ 'user_id' => '1',
+ 'comment' => 'First Comment for Second Article',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:53:23',
+ 'updated' => '2007-03-18 10:55:31'
+ ))),
+ array(
+ 'User' => array(
+ 'id' => '2',
+ 'user' => 'nate'
+ ),
+ 'Comment' => array(
+ array(
+ 'id' => '1',
+ 'article_id' => '1',
+ 'user_id' => '2',
+ 'comment' => 'First Comment for First Article',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:45:23',
+ 'updated' => '2007-03-18 10:47:31'
+ ),
+ array(
+ 'id' => '6',
+ 'article_id' => '2',
+ 'user_id' => '2',
+ 'comment' => 'Second Comment for Second Article',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:55:23',
+ 'updated' => '2007-03-18 10:57:31'
+ ))),
+ array(
+ 'User' => array(
+ 'id' => '3',
+ 'user' => 'larry'
+ ),
+ 'Comment' => array()
+ ),
+ array(
+ 'User' => array(
+ 'id' => '4',
+ 'user' => 'garrett'
+ ),
+ 'Comment' => array(
+ array(
+ 'id' => '2',
+ 'article_id' => '1',
+ 'user_id' => '4',
+ 'comment' => 'Second Comment for First Article',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:47:23',
+ 'updated' => '2007-03-18 10:49:31'
+ ))));
+
+ $this->assertEqual($result, $expected);
+
+ $TestModel->resetAssociations();
+ $result = $TestModel->hasMany;
+ $this->assertEqual($result, array());
+
+ $result = $TestModel->bindModel(array('hasMany' => array('Comment')), false);
+ $this->assertTrue($result);
+
+ $result = $TestModel->find('all', array(
+ 'fields' => 'User.id, User.user'
+ ));
+
+ $expected = array(
+ array(
+ 'User' => array(
+ 'id' => '1',
+ 'user' => 'mariano'
+ ),
+ 'Comment' => array(
+ array(
+ 'id' => '3',
+ 'article_id' => '1',
+ 'user_id' => '1',
+ 'comment' => 'Third Comment for First Article',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:49:23',
+ 'updated' => '2007-03-18 10:51:31'
+ ),
+ array(
+ 'id' => '4',
+ 'article_id' => '1',
+ 'user_id' => '1',
+ 'comment' => 'Fourth Comment for First Article',
+ 'published' => 'N',
+ 'created' => '2007-03-18 10:51:23',
+ 'updated' => '2007-03-18 10:53:31'
+ ),
+ array(
+ 'id' => '5',
+ 'article_id' => '2',
+ 'user_id' => '1',
+ 'comment' => 'First Comment for Second Article',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:53:23',
+ 'updated' => '2007-03-18 10:55:31'
+ ))),
+ array(
+ 'User' => array(
+ 'id' => '2',
+ 'user' => 'nate'
+ ),
+ 'Comment' => array(
+ array(
+ 'id' => '1',
+ 'article_id' => '1',
+ 'user_id' => '2',
+ 'comment' => 'First Comment for First Article',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:45:23',
+ 'updated' => '2007-03-18 10:47:31'
+ ),
+ array(
+ 'id' => '6',
+ 'article_id' => '2',
+ 'user_id' => '2',
+ 'comment' => 'Second Comment for Second Article',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:55:23',
+ 'updated' => '2007-03-18 10:57:31'
+ ))),
+ array(
+ 'User' => array(
+ 'id' => '3',
+ 'user' => 'larry'
+ ),
+ 'Comment' => array()
+ ),
+ array(
+ 'User' => array(
+ 'id' => '4',
+ 'user' => 'garrett'
+ ),
+ 'Comment' => array(
+ array(
+ 'id' => '2',
+ 'article_id' => '1',
+ 'user_id' => '4',
+ 'comment' => 'Second Comment for First Article',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:47:23',
+ 'updated' => '2007-03-18 10:49:31'
+ ))));
+
+ $this->assertEqual($result, $expected);
+
+ $result = $TestModel->hasMany;
+ $expected = array(
+ 'Comment' => array(
+ 'className' => 'Comment',
+ 'foreignKey' => 'user_id',
+ 'conditions' => null,
+ 'fields' => null,
+ 'order' => null,
+ 'limit' => null,
+ 'offset' => null,
+ 'dependent' => null,
+ 'exclusive' => null,
+ 'finderQuery' => null,
+ 'counterQuery' => null
+ ));
+ $this->assertEqual($result, $expected);
+
+ $result = $TestModel->unbindModel(array('hasMany' => array('Comment')));
+ $this->assertTrue($result);
+
+ $result = $TestModel->hasMany;
+ $expected = array();
+ $this->assertEqual($result, $expected);
+
+ $result = $TestModel->find('all', array(
+ 'fields' => 'User.id, User.user'
+ ));
+ $expected = array(
+ array('User' => array('id' => '1', 'user' => 'mariano')),
+ array('User' => array('id' => '2', 'user' => 'nate')),
+ array('User' => array('id' => '3', 'user' => 'larry')),
+ array('User' => array('id' => '4', 'user' => 'garrett')));
+ $this->assertEqual($result, $expected);
+
+ $result = $TestModel->find('all', array(
+ 'fields' => 'User.id, User.user'
+ ));
+ $expected = array(
+ array(
+ 'User' => array(
+ 'id' => '1',
+ 'user' => 'mariano'
+ ),
+ 'Comment' => array(
+ array(
+ 'id' => '3',
+ 'article_id' => '1',
+ 'user_id' => '1',
+ 'comment' => 'Third Comment for First Article',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:49:23',
+ 'updated' => '2007-03-18 10:51:31'
+ ),
+ array(
+ 'id' => '4',
+ 'article_id' => '1',
+ 'user_id' => '1',
+ 'comment' => 'Fourth Comment for First Article',
+ 'published' => 'N',
+ 'created' => '2007-03-18 10:51:23',
+ 'updated' => '2007-03-18 10:53:31'
+ ),
+ array(
+ 'id' => '5',
+ 'article_id' => '2',
+ 'user_id' => '1',
+ 'comment' => 'First Comment for Second Article',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:53:23',
+ 'updated' => '2007-03-18 10:55:31'
+ ))),
+ array(
+ 'User' => array(
+ 'id' => '2',
+ 'user' => 'nate'
+ ),
+ 'Comment' => array(
+ array(
+ 'id' => '1',
+ 'article_id' => '1',
+ 'user_id' => '2',
+ 'comment' => 'First Comment for First Article',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:45:23',
+ 'updated' => '2007-03-18 10:47:31'
+ ),
+ array(
+ 'id' => '6',
+ 'article_id' => '2',
+ 'user_id' => '2',
+ 'comment' => 'Second Comment for Second Article',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:55:23',
+ 'updated' => '2007-03-18 10:57:31'
+ ))),
+ array(
+ 'User' => array(
+ 'id' => '3',
+ 'user' => 'larry'
+ ),
+ 'Comment' => array()
+ ),
+ array(
+ 'User' => array(
+ 'id' => '4',
+ 'user' => 'garrett'
+ ),
+ 'Comment' => array(
+ array(
+ 'id' => '2',
+ 'article_id' => '1',
+ 'user_id' => '4',
+ 'comment' =>
+ 'Second Comment for First Article',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:47:23',
+ 'updated' => '2007-03-18 10:49:31'
+ ))));
+ $this->assertEqual($result, $expected);
+
+ $result = $TestModel->unbindModel(array('hasMany' => array('Comment')), false);
+ $this->assertTrue($result);
+
+ $result = $TestModel->find('all', array('fields' => 'User.id, User.user'));
+ $expected = array(
+ array('User' => array('id' => '1', 'user' => 'mariano')),
+ array('User' => array('id' => '2', 'user' => 'nate')),
+ array('User' => array('id' => '3', 'user' => 'larry')),
+ array('User' => array('id' => '4', 'user' => 'garrett')));
+ $this->assertEqual($result, $expected);
+
+ $result = $TestModel->hasMany;
+ $expected = array();
+ $this->assertEqual($result, $expected);
+
+ $result = $TestModel->bindModel(array('hasMany' => array(
+ 'Comment' => array('className' => 'Comment', 'conditions' => 'Comment.published = \'Y\'')
+ )));
+ $this->assertTrue($result);
+
+ $result = $TestModel->find('all', array('fields' => 'User.id, User.user'));
+ $expected = array(
+ array(
+ 'User' => array(
+ 'id' => '1',
+ 'user' => 'mariano'
+ ),
+ 'Comment' => array(
+ array(
+ 'id' => '3',
+ 'article_id' => '1',
+ 'user_id' => '1',
+ 'comment' => 'Third Comment for First Article',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:49:23',
+ 'updated' => '2007-03-18 10:51:31'
+ ),
+ array(
+ 'id' => '5',
+ 'article_id' => '2',
+ 'user_id' => '1',
+ 'comment' => 'First Comment for Second Article',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:53:23',
+ 'updated' => '2007-03-18 10:55:31'
+ ))),
+ array(
+ 'User' => array(
+ 'id' => '2',
+ 'user' => 'nate'
+ ),
+ 'Comment' => array(
+ array(
+ 'id' => '1',
+ 'article_id' => '1',
+ 'user_id' => '2',
+ 'comment' => 'First Comment for First Article',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:45:23',
+ 'updated' => '2007-03-18 10:47:31'
+ ),
+ array(
+ 'id' => '6',
+ 'article_id' => '2',
+ 'user_id' => '2',
+ 'comment' => 'Second Comment for Second Article',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:55:23',
+ 'updated' => '2007-03-18 10:57:31'
+ ))),
+ array(
+ 'User' => array(
+ 'id' => '3',
+ 'user' => 'larry'
+ ),
+ 'Comment' => array()
+ ),
+ array(
+ 'User' => array(
+ 'id' => '4',
+ 'user' => 'garrett'
+ ),
+ 'Comment' => array(
+ array(
+ 'id' => '2',
+ 'article_id' => '1',
+ 'user_id' => '4',
+ 'comment' => 'Second Comment for First Article',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:47:23',
+ 'updated' => '2007-03-18 10:49:31'
+ ))));
+
+ $this->assertEqual($result, $expected);
+
+ $TestModel2 =& new DeviceType();
+
+ $expected = array(
+ 'className' => 'FeatureSet',
+ 'foreignKey' => 'feature_set_id',
+ 'conditions' => '',
+ 'fields' => '',
+ 'order' => '',
+ 'counterCache' => ''
+ );
+ $this->assertEqual($TestModel2->belongsTo['FeatureSet'], $expected);
+
+ $TestModel2->bindModel(array(
+ 'belongsTo' => array(
+ 'FeatureSet' => array(
+ 'className' => 'FeatureSet',
+ 'conditions' => array('active' => true)
+ )
+ )
+ ));
+ $expected['conditions'] = array('active' => true);
+ $this->assertEqual($TestModel2->belongsTo['FeatureSet'], $expected);
+
+ $TestModel2->bindModel(array(
+ 'belongsTo' => array(
+ 'FeatureSet' => array(
+ 'className' => 'FeatureSet',
+ 'foreignKey' => false,
+ 'conditions' => array('Feature.name' => 'DeviceType.name')
+ )
+ )
+ ));
+ $expected['conditions'] = array('Feature.name' => 'DeviceType.name');
+ $expected['foreignKey'] = false;
+ $this->assertEqual($TestModel2->belongsTo['FeatureSet'], $expected);
+
+ $TestModel2->bindModel(array(
+ 'hasMany' => array(
+ 'NewFeatureSet' => array(
+ 'className' => 'FeatureSet',
+ 'conditions' => array('active' => true)
+ )
+ )
+ ));
+
+ $expected = array(
+ 'className' => 'FeatureSet',
+ 'conditions' => array('active' => true),
+ 'foreignKey' => 'device_type_id',
+ 'fields' => '',
+ 'order' => '',
+ 'limit' => '',
+ 'offset' => '',
+ 'dependent' => '',
+ 'exclusive' => '',
+ 'finderQuery' => '',
+ 'counterQuery' => ''
+ );
+ $this->assertEqual($TestModel2->hasMany['NewFeatureSet'], $expected);
+ $this->assertTrue(is_object($TestModel2->NewFeatureSet));
+ }
+
+/**
+ * testBindMultipleTimes method
+ *
+ * @access public
+ * @return void
+ */
+ function testBindMultipleTimes() {
+ $this->loadFixtures('User', 'Comment', 'Article');
+ $TestModel =& new User();
+
+ $result = $TestModel->hasMany;
+ $expected = array();
+ $this->assertEqual($result, $expected);
+
+ $result = $TestModel->bindModel(array(
+ 'hasMany' => array(
+ 'Items' => array('className' => 'Comment')
+ )));
+ $this->assertTrue($result);
+
+ $result = $TestModel->find('all', array(
+ 'fields' => 'User.id, User.user'
+ ));
+ $expected = array(
+ array(
+ 'User' => array(
+ 'id' => '1',
+ 'user' => 'mariano'
+ ),
+ 'Items' => array(
+ array(
+ 'id' => '3',
+ 'article_id' => '1',
+ 'user_id' => '1',
+ 'comment' => 'Third Comment for First Article',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:49:23',
+ 'updated' => '2007-03-18 10:51:31'
+ ),
+ array(
+ 'id' => '4',
+ 'article_id' => '1',
+ 'user_id' => '1',
+ 'comment' => 'Fourth Comment for First Article',
+ 'published' => 'N',
+ 'created' => '2007-03-18 10:51:23',
+ 'updated' => '2007-03-18 10:53:31'
+ ),
+ array(
+ 'id' => '5',
+ 'article_id' => '2',
+ 'user_id' => '1',
+ 'comment' => 'First Comment for Second Article',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:53:23',
+ 'updated' => '2007-03-18 10:55:31'
+ ))),
+ array(
+ 'User' => array(
+ 'id' => '2',
+ 'user' => 'nate'
+ ),
+ 'Items' => array(
+ array(
+ 'id' => '1',
+ 'article_id' => '1',
+ 'user_id' => '2',
+ 'comment' => 'First Comment for First Article',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:45:23',
+ 'updated' => '2007-03-18 10:47:31'
+ ),
+ array(
+ 'id' => '6',
+ 'article_id' => '2',
+ 'user_id' => '2',
+ 'comment' => 'Second Comment for Second Article',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:55:23',
+ 'updated' => '2007-03-18 10:57:31'
+ ))),
+ array(
+ 'User' => array(
+ 'id' => '3',
+ 'user' => 'larry'
+ ),
+ 'Items' => array()
+ ),
+ array(
+ 'User' => array(
+ 'id' => '4', 'user' => 'garrett'),
+ 'Items' => array(
+ array(
+ 'id' => '2',
+ 'article_id' => '1',
+ 'user_id' => '4',
+ 'comment' => 'Second Comment for First Article',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:47:23',
+ 'updated' => '2007-03-18 10:49:31'
+ ))));
+ $this->assertEqual($result, $expected);
+
+ $result = $TestModel->bindModel(array(
+ 'hasMany' => array(
+ 'Items' => array('className' => 'Article')
+ )));
+ $this->assertTrue($result);
+
+ $result = $TestModel->find('all', array(
+ 'fields' => 'User.id, User.user'
+ ));
+ $expected = array(
+ array(
+ 'User' => array(
+ 'id' => '1',
+ 'user' => 'mariano'
+ ),
+ 'Items' => array(
+ array(
+ 'id' => 1,
+ 'user_id' => 1,
+ 'title' => 'First Article',
+ 'body' => 'First Article Body',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:39:23',
+ 'updated' => '2007-03-18 10:41:31'
+ ),
+ array(
+ 'id' => 3,
+ 'user_id' => 1,
+ 'title' => 'Third Article',
+ 'body' => 'Third Article Body',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:43:23',
+ 'updated' => '2007-03-18 10:45:31'
+ ))),
+ array(
+ 'User' => array(
+ 'id' => '2',
+ 'user' => 'nate'
+ ),
+ 'Items' => array()
+ ),
+ array(
+ 'User' => array(
+ 'id' => '3',
+ 'user' => 'larry'
+ ),
+ 'Items' => array(
+ array(
+ 'id' => 2,
+ 'user_id' => 3,
+ 'title' => 'Second Article',
+ 'body' => 'Second Article Body',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:41:23',
+ 'updated' => '2007-03-18 10:43:31'
+ ))),
+ array(
+ 'User' => array(
+ 'id' => '4',
+ 'user' => 'garrett'
+ ),
+ 'Items' => array()
+ ));
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * test that multiple reset = true calls to bindModel() result in the original associations.
+ *
+ * @return void
+ */
+ function testBindModelMultipleTimesResetCorrectly() {
+ $this->loadFixtures('User', 'Comment', 'Article');
+ $TestModel =& new User();
+
+ $TestModel->bindModel(array('hasMany' => array('Comment')));
+ $TestModel->bindModel(array('hasMany' => array('Comment')));
+ $TestModel->resetAssociations();
+
+ $this->assertFalse(isset($TestModel->hasMany['Comment']), 'Association left behind');
+ }
+
+/**
+ * testBindMultipleTimes method with different reset settings
+ *
+ * @access public
+ * @return void
+ */
+ function testBindMultipleTimesWithDifferentResetSettings() {
+ $this->loadFixtures('User', 'Comment', 'Article');
+ $TestModel =& new User();
+
+ $result = $TestModel->hasMany;
+ $expected = array();
+ $this->assertEqual($result, $expected);
+
+ $result = $TestModel->bindModel(array(
+ 'hasMany' => array('Comment')
+ ));
+ $this->assertTrue($result);
+ $result = $TestModel->bindModel(
+ array('hasMany' => array('Article')),
+ false
+ );
+ $this->assertTrue($result);
+
+ $result = array_keys($TestModel->hasMany);
+ $expected = array('Comment', 'Article');
+ $this->assertEqual($result, $expected);
+
+ $TestModel->resetAssociations();
+
+ $result = array_keys($TestModel->hasMany);
+ $expected = array('Article');
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * test that bindModel behaves with Custom primary Key associations
+ *
+ * @return void
+ */
+ function bindWithCustomPrimaryKey() {
+ $this->loadFixtures('Story', 'StoriesTag', 'Tag');
+ $Model =& ClassRegistry::init('StoriesTag');
+ $Model->bindModel(array(
+ 'belongsTo' => array(
+ 'Tag' => array(
+ 'className' => 'Tag',
+ 'foreignKey' => 'story'
+ ))));
+
+ $result = $Model->find('all');
+ $this->assertFalse(empty($result));
+ }
+
+/**
+ * test that calling unbindModel() with reset == true multiple times
+ * leaves associations in the correct state.
+ *
+ * @return void
+ */
+ function testUnbindMultipleTimesResetCorrectly() {
+ $this->loadFixtures('User', 'Comment', 'Article');
+ $TestModel =& new Article10();
+
+ $TestModel->unbindModel(array('hasMany' => array('Comment')));
+ $TestModel->unbindModel(array('hasMany' => array('Comment')));
+ $TestModel->resetAssociations();
+
+ $this->assertTrue(isset($TestModel->hasMany['Comment']), 'Association permanently removed');
+ }
+
+/**
+ * testBindMultipleTimes method with different reset settings
+ *
+ * @access public
+ * @return void
+ */
+ function testUnBindMultipleTimesWithDifferentResetSettings() {
+ $this->loadFixtures('User', 'Comment', 'Article');
+ $TestModel =& new Comment();
+
+ $result = array_keys($TestModel->belongsTo);
+ $expected = array('Article', 'User');
+ $this->assertEqual($result, $expected);
+
+ $result = $TestModel->unbindModel(array(
+ 'belongsTo' => array('User')
+ ));
+ $this->assertTrue($result);
+ $result = $TestModel->unbindModel(
+ array('belongsTo' => array('Article')),
+ false
+ );
+ $this->assertTrue($result);
+
+ $result = array_keys($TestModel->belongsTo);
+ $expected = array();
+ $this->assertEqual($result, $expected);
+
+ $TestModel->resetAssociations();
+
+ $result = array_keys($TestModel->belongsTo);
+ $expected = array('User');
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testAssociationAfterFind method
+ *
+ * @access public
+ * @return void
+ */
+ function testAssociationAfterFind() {
+ $this->loadFixtures('Post', 'Author', 'Comment');
+ $TestModel =& new Post();
+ $result = $TestModel->find('all');
+ $expected = array(
+ array(
+ 'Post' => array(
+ 'id' => '1',
+ 'author_id' => '1',
+ 'title' => 'First Post',
+ 'body' => 'First Post Body',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:39:23',
+ 'updated' => '2007-03-18 10:41:31'
+ ),
+ 'Author' => array(
+ 'id' => '1',
+ 'user' => 'mariano',
+ 'password' => '5f4dcc3b5aa765d61d8327deb882cf99',
+ 'created' => '2007-03-17 01:16:23',
+ 'updated' => '2007-03-17 01:18:31',
+ 'test' => 'working'
+ )),
+ array(
+ 'Post' => array(
+ 'id' => '2',
+ 'author_id' => '3',
+ 'title' => 'Second Post',
+ 'body' => 'Second Post Body',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:41:23',
+ 'updated' => '2007-03-18 10:43:31'
+ ),
+ 'Author' => array(
+ 'id' => '3',
+ 'user' => 'larry',
+ 'password' => '5f4dcc3b5aa765d61d8327deb882cf99',
+ 'created' => '2007-03-17 01:20:23',
+ 'updated' => '2007-03-17 01:22:31',
+ 'test' => 'working'
+ )),
+ array(
+ 'Post' => array(
+ 'id' => '3',
+ 'author_id' => '1',
+ 'title' => 'Third Post',
+ 'body' => 'Third Post Body',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:43:23',
+ 'updated' => '2007-03-18 10:45:31'
+ ),
+ 'Author' => array(
+ 'id' => '1',
+ 'user' => 'mariano',
+ 'password' => '5f4dcc3b5aa765d61d8327deb882cf99',
+ 'created' => '2007-03-17 01:16:23',
+ 'updated' => '2007-03-17 01:18:31',
+ 'test' => 'working'
+ )));
+ $this->assertEqual($result, $expected);
+ unset($TestModel);
+
+ $Author =& new Author();
+ $Author->Post->bindModel(array(
+ 'hasMany' => array(
+ 'Comment' => array(
+ 'className' => 'ModifiedComment',
+ 'foreignKey' => 'article_id',
+ )
+ )));
+ $result = $Author->find('all', array(
+ 'conditions' => array('Author.id' => 1),
+ 'recursive' => 2
+ ));
+ $expected = array(
+ 'id' => 1,
+ 'article_id' => 1,
+ 'user_id' => 2,
+ 'comment' => 'First Comment for First Article',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:45:23',
+ 'updated' => '2007-03-18 10:47:31',
+ 'callback' => 'Fire'
+ );
+ $this->assertEqual($result[0]['Post'][0]['Comment'][0], $expected);
+ }
+
+/**
+ * Tests that callbacks can be properly disabled
+ *
+ * @access public
+ * @return void
+ */
+ function testCallbackDisabling() {
+ $this->loadFixtures('Author');
+ $TestModel = new ModifiedAuthor();
+
+ $result = Set::extract($TestModel->find('all'), '/Author/user');
+ $expected = array('mariano (CakePHP)', 'nate (CakePHP)', 'larry (CakePHP)', 'garrett (CakePHP)');
+ $this->assertEqual($result, $expected);
+
+ $result = Set::extract($TestModel->find('all', array('callbacks' => 'after')), '/Author/user');
+ $expected = array('mariano (CakePHP)', 'nate (CakePHP)', 'larry (CakePHP)', 'garrett (CakePHP)');
+ $this->assertEqual($result, $expected);
+
+ $result = Set::extract($TestModel->find('all', array('callbacks' => 'before')), '/Author/user');
+ $expected = array('mariano', 'nate', 'larry', 'garrett');
+ $this->assertEqual($result, $expected);
+
+ $result = Set::extract($TestModel->find('all', array('callbacks' => false)), '/Author/user');
+ $expected = array('mariano', 'nate', 'larry', 'garrett');
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * Tests that the database configuration assigned to the model can be changed using
+ * (before|after)Find callbacks
+ *
+ * @access public
+ * @return void
+ */
+ function testCallbackSourceChange() {
+ $this->loadFixtures('Post');
+ $TestModel = new Post();
+ $this->assertEqual(3, count($TestModel->find('all')));
+
+ $this->expectError(new PatternExpectation('/Non-existent data source foo/i'));
+ $this->assertFalse($TestModel->find('all', array('connection' => 'foo')));
+ }
+
+/**
+ * testMultipleBelongsToWithSameClass method
+ *
+ * @access public
+ * @return void
+ */
+ function testMultipleBelongsToWithSameClass() {
+ $this->loadFixtures(
+ 'DeviceType',
+ 'DeviceTypeCategory',
+ 'FeatureSet',
+ 'ExteriorTypeCategory',
+ 'Document',
+ 'Device',
+ 'DocumentDirectory'
+ );
+
+ $DeviceType =& new DeviceType();
+
+ $DeviceType->recursive = 2;
+ $result = $DeviceType->read(null, 1);
+
+ $expected = array(
+ 'DeviceType' => array(
+ 'id' => 1,
+ 'device_type_category_id' => 1,
+ 'feature_set_id' => 1,
+ 'exterior_type_category_id' => 1,
+ 'image_id' => 1,
+ 'extra1_id' => 1,
+ 'extra2_id' => 1,
+ 'name' => 'DeviceType 1',
+ 'order' => 0
+ ),
+ 'Image' => array(
+ 'id' => 1,
+ 'document_directory_id' => 1,
+ 'name' => 'Document 1',
+ 'DocumentDirectory' => array(
+ 'id' => 1,
+ 'name' => 'DocumentDirectory 1'
+ )),
+ 'Extra1' => array(
+ 'id' => 1,
+ 'document_directory_id' => 1,
+ 'name' => 'Document 1',
+ 'DocumentDirectory' => array(
+ 'id' => 1,
+ 'name' => 'DocumentDirectory 1'
+ )),
+ 'Extra2' => array(
+ 'id' => 1,
+ 'document_directory_id' => 1,
+ 'name' => 'Document 1',
+ 'DocumentDirectory' => array(
+ 'id' => 1,
+ 'name' => 'DocumentDirectory 1'
+ )),
+ 'DeviceTypeCategory' => array(
+ 'id' => 1,
+ 'name' => 'DeviceTypeCategory 1'
+ ),
+ 'FeatureSet' => array(
+ 'id' => 1,
+ 'name' => 'FeatureSet 1'
+ ),
+ 'ExteriorTypeCategory' => array(
+ 'id' => 1,
+ 'image_id' => 1,
+ 'name' => 'ExteriorTypeCategory 1',
+ 'Image' => array(
+ 'id' => 1,
+ 'device_type_id' => 1,
+ 'name' => 'Device 1',
+ 'typ' => 1
+ )),
+ 'Device' => array(
+ array(
+ 'id' => 1,
+ 'device_type_id' => 1,
+ 'name' => 'Device 1',
+ 'typ' => 1
+ ),
+ array(
+ 'id' => 2,
+ 'device_type_id' => 1,
+ 'name' => 'Device 2',
+ 'typ' => 1
+ ),
+ array(
+ 'id' => 3,
+ 'device_type_id' => 1,
+ 'name' => 'Device 3',
+ 'typ' => 2
+ )));
+
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testHabtmRecursiveBelongsTo method
+ *
+ * @access public
+ * @return void
+ */
+ function testHabtmRecursiveBelongsTo() {
+ $this->loadFixtures('Portfolio', 'Item', 'ItemsPortfolio', 'Syfile', 'Image');
+ $Portfolio =& new Portfolio();
+
+ $result = $Portfolio->find(array('id' => 2), null, null, 3);
+ $expected = array(
+ 'Portfolio' => array(
+ 'id' => 2,
+ 'seller_id' => 1,
+ 'name' => 'Portfolio 2'
+ ),
+ 'Item' => array(
+ array(
+ 'id' => 2,
+ 'syfile_id' => 2,
+ 'published' => 0,
+ 'name' => 'Item 2',
+ 'ItemsPortfolio' => array(
+ 'id' => 2,
+ 'item_id' => 2,
+ 'portfolio_id' => 2
+ ),
+ 'Syfile' => array(
+ 'id' => 2,
+ 'image_id' => 2,
+ 'name' => 'Syfile 2',
+ 'item_count' => null,
+ 'Image' => array(
+ 'id' => 2,
+ 'name' => 'Image 2'
+ )
+ )),
+ array(
+ 'id' => 6,
+ 'syfile_id' => 6,
+ 'published' => 0,
+ 'name' => 'Item 6',
+ 'ItemsPortfolio' => array(
+ 'id' => 6,
+ 'item_id' => 6,
+ 'portfolio_id' => 2
+ ),
+ 'Syfile' => array(
+ 'id' => 6,
+ 'image_id' => null,
+ 'name' => 'Syfile 6',
+ 'item_count' => null,
+ 'Image' => array()
+ ))));
+
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testHabtmFinderQuery method
+ *
+ * @access public
+ * @return void
+ */
+ function testHabtmFinderQuery() {
+ $this->loadFixtures('Article', 'Tag', 'ArticlesTag');
+ $Article =& new Article();
+
+ $sql = $this->db->buildStatement(
+ array(
+ 'fields' => $this->db->fields($Article->Tag, null, array(
+ 'Tag.id', 'Tag.tag', 'ArticlesTag.article_id', 'ArticlesTag.tag_id'
+ )),
+ 'table' => $this->db->fullTableName('tags'),
+ 'alias' => 'Tag',
+ 'limit' => null,
+ 'offset' => null,
+ 'group' => null,
+ 'joins' => array(array(
+ 'alias' => 'ArticlesTag',
+ 'table' => $this->db->fullTableName('articles_tags'),
+ 'conditions' => array(
+ array("ArticlesTag.article_id" => '{$__cakeID__$}'),
+ array("ArticlesTag.tag_id" => $this->db->identifier('Tag.id'))
+ )
+ )),
+ 'conditions' => array(),
+ 'order' => null
+ ),
+ $Article
+ );
+
+ $Article->hasAndBelongsToMany['Tag']['finderQuery'] = $sql;
+ $result = $Article->find('first');
+ $expected = array(
+ array(
+ 'id' => '1',
+ 'tag' => 'tag1'
+ ),
+ array(
+ 'id' => '2',
+ 'tag' => 'tag2'
+ ));
+
+ $this->assertEqual($result['Tag'], $expected);
+ }
+
+/**
+ * testHabtmLimitOptimization method
+ *
+ * @access public
+ * @return void
+ */
+ function testHabtmLimitOptimization() {
+ $this->loadFixtures('Article', 'User', 'Comment', 'Tag', 'ArticlesTag');
+ $TestModel =& new Article();
+
+ $TestModel->hasAndBelongsToMany['Tag']['limit'] = 2;
+ $result = $TestModel->read(null, 2);
+ $expected = array(
+ 'Article' => array(
+ 'id' => '2',
+ 'user_id' => '3',
+ 'title' => 'Second Article',
+ 'body' => 'Second Article Body',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:41:23',
+ 'updated' => '2007-03-18 10:43:31'
+ ),
+ 'User' => array(
+ 'id' => '3',
+ 'user' => 'larry',
+ 'password' => '5f4dcc3b5aa765d61d8327deb882cf99',
+ 'created' => '2007-03-17 01:20:23',
+ 'updated' => '2007-03-17 01:22:31'
+ ),
+ 'Comment' => array(
+ array(
+ 'id' => '5',
+ 'article_id' => '2',
+ 'user_id' => '1',
+ 'comment' => 'First Comment for Second Article',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:53:23',
+ 'updated' => '2007-03-18 10:55:31'
+ ),
+ array(
+ 'id' => '6',
+ 'article_id' => '2',
+ 'user_id' => '2',
+ 'comment' => 'Second Comment for Second Article',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:55:23',
+ 'updated' => '2007-03-18 10:57:31'
+ )),
+ 'Tag' => array(
+ array(
+ 'id' => '1',
+ 'tag' => 'tag1',
+ 'created' => '2007-03-18 12:22:23',
+ 'updated' => '2007-03-18 12:24:31'
+ ),
+ array(
+ 'id' => '3',
+ 'tag' => 'tag3',
+ 'created' => '2007-03-18 12:26:23',
+ 'updated' => '2007-03-18 12:28:31'
+ )));
+
+ $this->assertEqual($result, $expected);
+
+ $TestModel->hasAndBelongsToMany['Tag']['limit'] = 1;
+ $result = $TestModel->read(null, 2);
+ unset($expected['Tag'][1]);
+
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testHasManyLimitOptimization method
+ *
+ * @access public
+ * @return void
+ */
+ function testHasManyLimitOptimization() {
+ $this->loadFixtures('Project', 'Thread', 'Message', 'Bid');
+ $Project =& new Project();
+ $Project->recursive = 3;
+
+ $result = $Project->find('all');
+ $expected = array(
+ array(
+ 'Project' => array(
+ 'id' => 1,
+ 'name' => 'Project 1'
+ ),
+ 'Thread' => array(
+ array(
+ 'id' => 1,
+ 'project_id' => 1,
+ 'name' => 'Project 1, Thread 1',
+ 'Project' => array(
+ 'id' => 1,
+ 'name' => 'Project 1',
+ 'Thread' => array(
+ array(
+ 'id' => 1,
+ 'project_id' => 1,
+ 'name' => 'Project 1, Thread 1'
+ ),
+ array(
+ 'id' => 2,
+ 'project_id' => 1,
+ 'name' => 'Project 1, Thread 2'
+ ))),
+ 'Message' => array(
+ array(
+ 'id' => 1,
+ 'thread_id' => 1,
+ 'name' => 'Thread 1, Message 1',
+ 'Bid' => array(
+ 'id' => 1,
+ 'message_id' => 1,
+ 'name' => 'Bid 1.1'
+ )))),
+ array(
+ 'id' => 2,
+ 'project_id' => 1,
+ 'name' => 'Project 1, Thread 2',
+ 'Project' => array(
+ 'id' => 1,
+ 'name' => 'Project 1',
+ 'Thread' => array(
+ array(
+ 'id' => 1,
+ 'project_id' => 1,
+ 'name' => 'Project 1, Thread 1'
+ ),
+ array(
+ 'id' => 2,
+ 'project_id' => 1,
+ 'name' => 'Project 1, Thread 2'
+ ))),
+ 'Message' => array(
+ array(
+ 'id' => 2,
+ 'thread_id' => 2,
+ 'name' => 'Thread 2, Message 1',
+ 'Bid' => array(
+ 'id' => 4,
+ 'message_id' => 2,
+ 'name' => 'Bid 2.1'
+ )))))),
+ array(
+ 'Project' => array(
+ 'id' => 2,
+ 'name' => 'Project 2'
+ ),
+ 'Thread' => array(
+ array(
+ 'id' => 3,
+ 'project_id' => 2,
+ 'name' => 'Project 2, Thread 1',
+ 'Project' => array(
+ 'id' => 2,
+ 'name' => 'Project 2',
+ 'Thread' => array(
+ array(
+ 'id' => 3,
+ 'project_id' => 2,
+ 'name' => 'Project 2, Thread 1'
+ ))),
+ 'Message' => array(
+ array(
+ 'id' => 3,
+ 'thread_id' => 3,
+ 'name' => 'Thread 3, Message 1',
+ 'Bid' => array(
+ 'id' => 3,
+ 'message_id' => 3,
+ 'name' => 'Bid 3.1'
+ )))))),
+ array(
+ 'Project' => array(
+ 'id' => 3,
+ 'name' => 'Project 3'
+ ),
+ 'Thread' => array()
+ ));
+
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testFindAllRecursiveSelfJoin method
+ *
+ * @access public
+ * @return void
+ */
+ function testFindAllRecursiveSelfJoin() {
+ $this->loadFixtures('Home', 'AnotherArticle', 'Advertisement');
+ $TestModel =& new Home();
+ $TestModel->recursive = 2;
+
+ $result = $TestModel->find('all');
+ $expected = array(
+ array(
+ 'Home' => array(
+ 'id' => '1',
+ 'another_article_id' => '1',
+ 'advertisement_id' => '1',
+ 'title' => 'First Home',
+ 'created' => '2007-03-18 10:39:23',
+ 'updated' => '2007-03-18 10:41:31'
+ ),
+ 'AnotherArticle' => array(
+ 'id' => '1',
+ 'title' => 'First Article',
+ 'created' => '2007-03-18 10:39:23',
+ 'updated' => '2007-03-18 10:41:31',
+ 'Home' => array(
+ array(
+ 'id' => '1',
+ 'another_article_id' => '1',
+ 'advertisement_id' => '1',
+ 'title' => 'First Home',
+ 'created' => '2007-03-18 10:39:23',
+ 'updated' => '2007-03-18 10:41:31'
+ ))),
+ 'Advertisement' => array(
+ 'id' => '1',
+ 'title' => 'First Ad',
+ 'created' => '2007-03-18 10:39:23',
+ 'updated' => '2007-03-18 10:41:31',
+ 'Home' => array(
+ array(
+ 'id' => '1',
+ 'another_article_id' => '1',
+ 'advertisement_id' => '1',
+ 'title' => 'First Home',
+ 'created' => '2007-03-18 10:39:23',
+ 'updated' => '2007-03-18 10:41:31'
+ ),
+ array(
+ 'id' => '2',
+ 'another_article_id' => '3',
+ 'advertisement_id' => '1',
+ 'title' => 'Second Home',
+ 'created' => '2007-03-18 10:41:23',
+ 'updated' => '2007-03-18 10:43:31'
+ )))),
+ array(
+ 'Home' => array(
+ 'id' => '2',
+ 'another_article_id' => '3',
+ 'advertisement_id' => '1',
+ 'title' => 'Second Home',
+ 'created' => '2007-03-18 10:41:23',
+ 'updated' => '2007-03-18 10:43:31'
+ ),
+ 'AnotherArticle' => array(
+ 'id' => '3',
+ 'title' => 'Third Article',
+ 'created' => '2007-03-18 10:43:23',
+ 'updated' => '2007-03-18 10:45:31',
+ 'Home' => array(
+ array(
+ 'id' => '2',
+ 'another_article_id' => '3',
+ 'advertisement_id' => '1',
+ 'title' => 'Second Home',
+ 'created' => '2007-03-18 10:41:23',
+ 'updated' => '2007-03-18 10:43:31'
+ ))),
+ 'Advertisement' => array(
+ 'id' => '1',
+ 'title' => 'First Ad',
+ 'created' => '2007-03-18 10:39:23',
+ 'updated' => '2007-03-18 10:41:31',
+ 'Home' => array(
+ array(
+ 'id' => '1',
+ 'another_article_id' => '1',
+ 'advertisement_id' => '1',
+ 'title' => 'First Home',
+ 'created' => '2007-03-18 10:39:23',
+ 'updated' => '2007-03-18 10:41:31'
+ ),
+ array(
+ 'id' => '2',
+ 'another_article_id' => '3',
+ 'advertisement_id' => '1',
+ 'title' => 'Second Home',
+ 'created' => '2007-03-18 10:41:23',
+ 'updated' => '2007-03-18 10:43:31'
+ )))));
+
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testFindAllRecursiveWithHabtm method
+ *
+ * @return void
+ * @access public
+ */
+ function testFindAllRecursiveWithHabtm() {
+ $this->loadFixtures(
+ 'MyCategoriesMyUsers',
+ 'MyCategoriesMyProducts',
+ 'MyCategory',
+ 'MyUser',
+ 'MyProduct'
+ );
+
+ $MyUser =& new MyUser();
+ $MyUser->recursive = 2;
+
+ $result = $MyUser->find('all');
+ $expected = array(
+ array(
+ 'MyUser' => array('id' => '1', 'firstname' => 'userA'),
+ 'MyCategory' => array(
+ array(
+ 'id' => '1',
+ 'name' => 'A',
+ 'MyProduct' => array(
+ array(
+ 'id' => '1',
+ 'name' => 'book'
+ ))),
+ array(
+ 'id' => '3',
+ 'name' => 'C',
+ 'MyProduct' => array(
+ array(
+ 'id' => '2',
+ 'name' => 'computer'
+ ))))),
+ array(
+ 'MyUser' => array(
+ 'id' => '2',
+ 'firstname' => 'userB'
+ ),
+ 'MyCategory' => array(
+ array(
+ 'id' => '1',
+ 'name' => 'A',
+ 'MyProduct' => array(
+ array(
+ 'id' => '1',
+ 'name' => 'book'
+ ))),
+ array(
+ 'id' => '2',
+ 'name' => 'B',
+ 'MyProduct' => array(
+ array(
+ 'id' => '1',
+ 'name' => 'book'
+ ),
+ array(
+ 'id' => '2',
+ 'name' => 'computer'
+ ))))));
+
+ $this->assertIdentical($result, $expected);
+ }
+
+/**
+ * testReadFakeThread method
+ *
+ * @access public
+ * @return void
+ */
+ function testReadFakeThread() {
+ $this->loadFixtures('CategoryThread');
+ $TestModel =& new CategoryThread();
+
+ $fullDebug = $this->db->fullDebug;
+ $this->db->fullDebug = true;
+ $TestModel->recursive = 6;
+ $TestModel->id = 7;
+ $result = $TestModel->read();
+ $expected = array(
+ 'CategoryThread' => array(
+ 'id' => 7,
+ 'parent_id' => 6,
+ 'name' => 'Category 2.1',
+ 'created' => '2007-03-18 15:30:23',
+ 'updated' => '2007-03-18 15:32:31'
+ ),
+ 'ParentCategory' => array(
+ 'id' => 6,
+ 'parent_id' => 5,
+ 'name' => 'Category 2',
+ 'created' => '2007-03-18 15:30:23',
+ 'updated' => '2007-03-18 15:32:31',
+ 'ParentCategory' => array(
+ 'id' => 5,
+ 'parent_id' => 4,
+ 'name' => 'Category 1.1.1.1',
+ 'created' => '2007-03-18 15:30:23',
+ 'updated' => '2007-03-18 15:32:31',
+ 'ParentCategory' => array(
+ 'id' => 4,
+ 'parent_id' => 3,
+ 'name' => 'Category 1.1.2',
+ 'created' => '2007-03-18 15:30:23',
+ 'updated' => '2007-03-18 15:32:31',
+ 'ParentCategory' => array(
+ 'id' => 3,
+ 'parent_id' => 2,
+ 'name' => 'Category 1.1.1',
+ 'created' => '2007-03-18 15:30:23',
+ 'updated' => '2007-03-18 15:32:31',
+ 'ParentCategory' => array(
+ 'id' => 2,
+ 'parent_id' => 1,
+ 'name' => 'Category 1.1',
+ 'created' => '2007-03-18 15:30:23',
+ 'updated' => '2007-03-18 15:32:31',
+ 'ParentCategory' => array(
+ 'id' => 1,
+ 'parent_id' => 0,
+ 'name' => 'Category 1',
+ 'created' => '2007-03-18 15:30:23',
+ 'updated' => '2007-03-18 15:32:31'
+ )))))));
+
+ $this->db->fullDebug = $fullDebug;
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testFindFakeThread method
+ *
+ * @access public
+ * @return void
+ */
+ function testFindFakeThread() {
+ $this->loadFixtures('CategoryThread');
+ $TestModel =& new CategoryThread();
+
+ $fullDebug = $this->db->fullDebug;
+ $this->db->fullDebug = true;
+ $TestModel->recursive = 6;
+ $result = $TestModel->find(array('CategoryThread.id' => 7));
+
+ $expected = array(
+ 'CategoryThread' => array(
+ 'id' => 7,
+ 'parent_id' => 6,
+ 'name' => 'Category 2.1',
+ 'created' => '2007-03-18 15:30:23',
+ 'updated' => '2007-03-18 15:32:31'
+ ),
+ 'ParentCategory' => array(
+ 'id' => 6,
+ 'parent_id' => 5,
+ 'name' => 'Category 2',
+ 'created' => '2007-03-18 15:30:23',
+ 'updated' => '2007-03-18 15:32:31',
+ 'ParentCategory' => array(
+ 'id' => 5,
+ 'parent_id' => 4,
+ 'name' => 'Category 1.1.1.1',
+ 'created' => '2007-03-18 15:30:23',
+ 'updated' => '2007-03-18 15:32:31',
+ 'ParentCategory' => array(
+ 'id' => 4,
+ 'parent_id' => 3,
+ 'name' => 'Category 1.1.2',
+ 'created' => '2007-03-18 15:30:23',
+ 'updated' => '2007-03-18 15:32:31',
+ 'ParentCategory' => array(
+ 'id' => 3,
+ 'parent_id' => 2,
+ 'name' => 'Category 1.1.1',
+ 'created' => '2007-03-18 15:30:23',
+ 'updated' => '2007-03-18 15:32:31',
+ 'ParentCategory' => array(
+ 'id' => 2,
+ 'parent_id' => 1,
+ 'name' => 'Category 1.1',
+ 'created' => '2007-03-18 15:30:23',
+ 'updated' => '2007-03-18 15:32:31',
+ 'ParentCategory' => array(
+ 'id' => 1,
+ 'parent_id' => 0,
+ 'name' => 'Category 1',
+ 'created' => '2007-03-18 15:30:23',
+ 'updated' => '2007-03-18 15:32:31'
+ )))))));
+
+ $this->db->fullDebug = $fullDebug;
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testFindAllFakeThread method
+ *
+ * @access public
+ * @return void
+ */
+ function testFindAllFakeThread() {
+ $this->loadFixtures('CategoryThread');
+ $TestModel =& new CategoryThread();
+
+ $fullDebug = $this->db->fullDebug;
+ $this->db->fullDebug = true;
+ $TestModel->recursive = 6;
+ $result = $TestModel->find('all', null, null, 'CategoryThread.id ASC');
+ $expected = array(
+ array(
+ 'CategoryThread' => array(
+ 'id' => 1,
+ 'parent_id' => 0,
+ 'name' => 'Category 1',
+ 'created' => '2007-03-18 15:30:23',
+ 'updated' => '2007-03-18 15:32:31'
+ ),
+ 'ParentCategory' => array(
+ 'id' => null,
+ 'parent_id' => null,
+ 'name' => null,
+ 'created' => null,
+ 'updated' => null,
+ 'ParentCategory' => array()
+ )),
+ array(
+ 'CategoryThread' => array(
+ 'id' => 2,
+ 'parent_id' => 1,
+ 'name' => 'Category 1.1',
+ 'created' => '2007-03-18 15:30:23',
+ 'updated' => '2007-03-18 15:32:31'
+ ),
+ 'ParentCategory' => array(
+ 'id' => 1,
+ 'parent_id' => 0,
+ 'name' => 'Category 1',
+ 'created' => '2007-03-18 15:30:23',
+ 'updated' => '2007-03-18 15:32:31',
+ 'ParentCategory' => array()
+ )),
+ array(
+ 'CategoryThread' => array(
+ 'id' => 3,
+ 'parent_id' => 2,
+ 'name' => 'Category 1.1.1',
+ 'created' => '2007-03-18 15:30:23',
+ 'updated' => '2007-03-18 15:32:31'
+ ),
+ 'ParentCategory' => array(
+ 'id' => 2,
+ 'parent_id' => 1,
+ 'name' => 'Category 1.1',
+ 'created' => '2007-03-18 15:30:23',
+ 'updated' => '2007-03-18 15:32:31',
+ 'ParentCategory' => array(
+ 'id' => 1,
+ 'parent_id' => 0,
+ 'name' => 'Category 1',
+ 'created' => '2007-03-18 15:30:23',
+ 'updated' => '2007-03-18 15:32:31',
+ 'ParentCategory' => array()
+ ))),
+ array(
+ 'CategoryThread' => array(
+ 'id' => 4,
+ 'parent_id' => 3,
+ 'name' => 'Category 1.1.2',
+ 'created' => '2007-03-18 15:30:23',
+ 'updated' => '2007-03-18 15:32:31'
+ ),
+ 'ParentCategory' => array(
+ 'id' => 3,
+ 'parent_id' => 2,
+ 'name' => 'Category 1.1.1',
+ 'created' => '2007-03-18 15:30:23',
+ 'updated' => '2007-03-18 15:32:31',
+ 'ParentCategory' => array(
+ 'id' => 2,
+ 'parent_id' => 1,
+ 'name' => 'Category 1.1',
+ 'created' => '2007-03-18 15:30:23',
+ 'updated' => '2007-03-18 15:32:31',
+ 'ParentCategory' => array(
+ 'id' => 1,
+ 'parent_id' => 0,
+ 'name' => 'Category 1',
+ 'created' => '2007-03-18 15:30:23',
+ 'updated' => '2007-03-18 15:32:31',
+ 'ParentCategory' => array()
+ )))),
+ array(
+ 'CategoryThread' => array(
+ 'id' => 5,
+ 'parent_id' => 4,
+ 'name' => 'Category 1.1.1.1',
+ 'created' => '2007-03-18 15:30:23',
+ 'updated' => '2007-03-18 15:32:31'
+ ),
+ 'ParentCategory' => array(
+ 'id' => 4,
+ 'parent_id' => 3,
+ 'name' => 'Category 1.1.2',
+ 'created' => '2007-03-18 15:30:23',
+ 'updated' => '2007-03-18 15:32:31',
+ 'ParentCategory' => array(
+ 'id' => 3,
+ 'parent_id' => 2,
+ 'name' => 'Category 1.1.1',
+ 'created' => '2007-03-18 15:30:23',
+ 'updated' => '2007-03-18 15:32:31',
+ 'ParentCategory' => array(
+ 'id' => 2,
+ 'parent_id' => 1,
+ 'name' => 'Category 1.1',
+ 'created' => '2007-03-18 15:30:23',
+ 'updated' => '2007-03-18 15:32:31',
+ 'ParentCategory' => array(
+ 'id' => 1,
+ 'parent_id' => 0,
+ 'name' => 'Category 1',
+ 'created' => '2007-03-18 15:30:23',
+ 'updated' => '2007-03-18 15:32:31',
+ 'ParentCategory' => array()
+ ))))),
+ array(
+ 'CategoryThread' => array(
+ 'id' => 6,
+ 'parent_id' => 5,
+ 'name' => 'Category 2',
+ 'created' => '2007-03-18 15:30:23',
+ 'updated' => '2007-03-18 15:32:31'
+ ),
+ 'ParentCategory' => array(
+ 'id' => 5,
+ 'parent_id' => 4,
+ 'name' => 'Category 1.1.1.1',
+ 'created' => '2007-03-18 15:30:23',
+ 'updated' => '2007-03-18 15:32:31',
+ 'ParentCategory' => array(
+ 'id' => 4,
+ 'parent_id' => 3,
+ 'name' => 'Category 1.1.2',
+ 'created' => '2007-03-18 15:30:23',
+ 'updated' => '2007-03-18 15:32:31',
+ 'ParentCategory' => array(
+ 'id' => 3,
+ 'parent_id' => 2,
+ 'name' => 'Category 1.1.1',
+ 'created' => '2007-03-18 15:30:23',
+ 'updated' => '2007-03-18 15:32:31',
+ 'ParentCategory' => array(
+ 'id' => 2,
+ 'parent_id' => 1,
+ 'name' => 'Category 1.1',
+ 'created' => '2007-03-18 15:30:23',
+ 'updated' => '2007-03-18 15:32:31',
+ 'ParentCategory' => array(
+ 'id' => 1,
+ 'parent_id' => 0,
+ 'name' => 'Category 1',
+ 'created' => '2007-03-18 15:30:23',
+ 'updated' => '2007-03-18 15:32:31',
+ 'ParentCategory' => array()
+ )))))),
+ array(
+ 'CategoryThread' => array(
+ 'id' => 7,
+ 'parent_id' => 6,
+ 'name' => 'Category 2.1',
+ 'created' => '2007-03-18 15:30:23',
+ 'updated' => '2007-03-18 15:32:31'
+ ),
+ 'ParentCategory' => array(
+ 'id' => 6,
+ 'parent_id' => 5,
+ 'name' => 'Category 2',
+ 'created' => '2007-03-18 15:30:23',
+ 'updated' => '2007-03-18 15:32:31',
+ 'ParentCategory' => array(
+ 'id' => 5,
+ 'parent_id' => 4,
+ 'name' => 'Category 1.1.1.1',
+ 'created' => '2007-03-18 15:30:23',
+ 'updated' => '2007-03-18 15:32:31',
+ 'ParentCategory' => array(
+ 'id' => 4,
+ 'parent_id' => 3,
+ 'name' => 'Category 1.1.2',
+ 'created' => '2007-03-18 15:30:23',
+ 'updated' => '2007-03-18 15:32:31',
+ 'ParentCategory' => array(
+ 'id' => 3,
+ 'parent_id' => 2,
+ 'name' => 'Category 1.1.1',
+ 'created' => '2007-03-18 15:30:23',
+ 'updated' => '2007-03-18 15:32:31',
+ 'ParentCategory' => array(
+ 'id' => 2,
+ 'parent_id' => 1,
+ 'name' => 'Category 1.1',
+ 'created' => '2007-03-18 15:30:23',
+ 'updated' => '2007-03-18 15:32:31',
+ 'ParentCategory' => array(
+ 'id' => 1,
+ 'parent_id' => 0,
+ 'name' => 'Category 1',
+ 'created' => '2007-03-18 15:30:23',
+ 'updated' => '2007-03-18 15:32:31'
+ ))))))));
+
+ $this->db->fullDebug = $fullDebug;
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testConditionalNumerics method
+ *
+ * @access public
+ * @return void
+ */
+ function testConditionalNumerics() {
+ $this->loadFixtures('NumericArticle');
+ $NumericArticle =& new NumericArticle();
+ $data = array('title' => '12345abcde');
+ $result = $NumericArticle->find($data);
+ $this->assertTrue(!empty($result));
+
+ $data = array('title' => '12345');
+ $result = $NumericArticle->find($data);
+ $this->assertTrue(empty($result));
+ }
+
+/**
+ * test find('all') method
+ *
+ * @access public
+ * @return void
+ */
+ function testFindAll() {
+ $this->loadFixtures('User');
+ $TestModel =& new User();
+ $TestModel->cacheQueries = false;
+
+ $result = $TestModel->find('all');
+ $expected = array(
+ array(
+ 'User' => array(
+ 'id' => '1',
+ 'user' => 'mariano',
+ 'password' => '5f4dcc3b5aa765d61d8327deb882cf99',
+ 'created' => '2007-03-17 01:16:23',
+ 'updated' => '2007-03-17 01:18:31'
+ )),
+ array(
+ 'User' => array(
+ 'id' => '2',
+ 'user' => 'nate',
+ 'password' => '5f4dcc3b5aa765d61d8327deb882cf99',
+ 'created' => '2007-03-17 01:18:23',
+ 'updated' => '2007-03-17 01:20:31'
+ )),
+ array(
+ 'User' => array(
+ 'id' => '3',
+ 'user' => 'larry',
+ 'password' => '5f4dcc3b5aa765d61d8327deb882cf99',
+ 'created' => '2007-03-17 01:20:23',
+ 'updated' => '2007-03-17 01:22:31'
+ )),
+ array(
+ 'User' => array(
+ 'id' => '4',
+ 'user' => 'garrett',
+ 'password' => '5f4dcc3b5aa765d61d8327deb882cf99',
+ 'created' => '2007-03-17 01:22:23',
+ 'updated' => '2007-03-17 01:24:31'
+ )));
+ $this->assertEqual($result, $expected);
+
+ $result = $TestModel->find('all', array('conditions' => 'User.id > 2'));
+ $expected = array(
+ array(
+ 'User' => array(
+ 'id' => '3',
+ 'user' => 'larry',
+ 'password' => '5f4dcc3b5aa765d61d8327deb882cf99',
+ 'created' => '2007-03-17 01:20:23',
+ 'updated' => '2007-03-17 01:22:31'
+ )),
+ array(
+ 'User' => array(
+ 'id' => '4',
+ 'user' => 'garrett',
+ 'password' => '5f4dcc3b5aa765d61d8327deb882cf99',
+ 'created' => '2007-03-17 01:22:23',
+ 'updated' => '2007-03-17 01:24:31'
+ )));
+ $this->assertEqual($result, $expected);
+
+ $result = $TestModel->find('all', array(
+ 'conditions' => array('User.id !=' => '0', 'User.user LIKE' => '%arr%')
+ ));
+ $expected = array(
+ array(
+ 'User' => array(
+ 'id' => '3',
+ 'user' => 'larry',
+ 'password' => '5f4dcc3b5aa765d61d8327deb882cf99',
+ 'created' => '2007-03-17 01:20:23',
+ 'updated' => '2007-03-17 01:22:31'
+ )),
+ array(
+ 'User' => array(
+ 'id' => '4',
+ 'user' => 'garrett',
+ 'password' => '5f4dcc3b5aa765d61d8327deb882cf99',
+ 'created' => '2007-03-17 01:22:23',
+ 'updated' => '2007-03-17 01:24:31'
+ )));
+ $this->assertEqual($result, $expected);
+
+ $result = $TestModel->find('all', array('conditions' => array('User.id' => '0')));
+ $expected = array();
+ $this->assertEqual($result, $expected);
+
+ $result = $TestModel->find('all', array(
+ 'conditions' => array('or' => array('User.id' => '0', 'User.user LIKE' => '%a%')
+ )));
+
+ $expected = array(
+ array(
+ 'User' => array(
+ 'id' => '1',
+ 'user' => 'mariano',
+ 'password' => '5f4dcc3b5aa765d61d8327deb882cf99',
+ 'created' => '2007-03-17 01:16:23',
+ 'updated' => '2007-03-17 01:18:31'
+ )),
+ array(
+ 'User' => array(
+ 'id' => '2',
+ 'user' => 'nate',
+ 'password' => '5f4dcc3b5aa765d61d8327deb882cf99',
+ 'created' => '2007-03-17 01:18:23',
+ 'updated' => '2007-03-17 01:20:31'
+ )),
+ array(
+ 'User' => array(
+ 'id' => '3',
+ 'user' => 'larry',
+ 'password' => '5f4dcc3b5aa765d61d8327deb882cf99',
+ 'created' => '2007-03-17 01:20:23',
+ 'updated' => '2007-03-17 01:22:31'
+ )),
+ array(
+ 'User' => array(
+ 'id' => '4',
+ 'user' => 'garrett',
+ 'password' => '5f4dcc3b5aa765d61d8327deb882cf99',
+ 'created' => '2007-03-17 01:22:23',
+ 'updated' => '2007-03-17 01:24:31'
+ )));
+ $this->assertEqual($result, $expected);
+
+ $result = $TestModel->find('all', array('fields' => 'User.id, User.user'));
+ $expected = array(
+ array('User' => array('id' => '1', 'user' => 'mariano')),
+ array('User' => array('id' => '2', 'user' => 'nate')),
+ array('User' => array('id' => '3', 'user' => 'larry')),
+ array('User' => array('id' => '4', 'user' => 'garrett')));
+ $this->assertEqual($result, $expected);
+
+ $result = $TestModel->find('all', array('fields' => 'User.user', 'order' => 'User.user ASC'));
+ $expected = array(
+ array('User' => array('user' => 'garrett')),
+ array('User' => array('user' => 'larry')),
+ array('User' => array('user' => 'mariano')),
+ array('User' => array('user' => 'nate')));
+ $this->assertEqual($result, $expected);
+
+ $result = $TestModel->find('all', array('fields' => 'User.user', 'order' => 'User.user DESC'));
+ $expected = array(
+ array('User' => array('user' => 'nate')),
+ array('User' => array('user' => 'mariano')),
+ array('User' => array('user' => 'larry')),
+ array('User' => array('user' => 'garrett')));
+ $this->assertEqual($result, $expected);
+
+ $result = $TestModel->find('all', array('limit' => 3, 'page' => 1));
+
+ $expected = array(
+ array(
+ 'User' => array(
+ 'id' => '1',
+ 'user' => 'mariano',
+ 'password' => '5f4dcc3b5aa765d61d8327deb882cf99',
+ 'created' => '2007-03-17 01:16:23',
+ 'updated' => '2007-03-17 01:18:31'
+ )),
+ array(
+ 'User' => array(
+ 'id' => '2',
+ 'user' => 'nate',
+ 'password' => '5f4dcc3b5aa765d61d8327deb882cf99',
+ 'created' => '2007-03-17 01:18:23',
+ 'updated' => '2007-03-17 01:20:31'
+ )),
+ array(
+ 'User' => array(
+ 'id' => '3',
+ 'user' => 'larry',
+ 'password' => '5f4dcc3b5aa765d61d8327deb882cf99',
+ 'created' => '2007-03-17 01:20:23',
+ 'updated' => '2007-03-17 01:22:31'
+ )));
+ $this->assertEqual($result, $expected);
+
+ $ids = array(4 => 1, 5 => 3);
+ $result = $TestModel->find('all', array(
+ 'conditions' => array('User.id' => $ids),
+ 'order' => 'User.id'
+ ));
+ $expected = array(
+ array(
+ 'User' => array(
+ 'id' => '1',
+ 'user' => 'mariano',
+ 'password' => '5f4dcc3b5aa765d61d8327deb882cf99',
+ 'created' => '2007-03-17 01:16:23',
+ 'updated' => '2007-03-17 01:18:31'
+ )),
+ array(
+ 'User' => array(
+ 'id' => '3',
+ 'user' => 'larry',
+ 'password' => '5f4dcc3b5aa765d61d8327deb882cf99',
+ 'created' => '2007-03-17 01:20:23',
+ 'updated' => '2007-03-17 01:22:31'
+ )));
+ $this->assertEqual($result, $expected);
+
+ // These tests are expected to fail on SQL Server since the LIMIT/OFFSET
+ // hack can't handle small record counts.
+ if ($this->db->config['driver'] != 'mssql') {
+ $result = $TestModel->find('all', array('limit' => 3, 'page' => 2));
+ $expected = array(
+ array(
+ 'User' => array(
+ 'id' => '4',
+ 'user' => 'garrett',
+ 'password' => '5f4dcc3b5aa765d61d8327deb882cf99',
+ 'created' => '2007-03-17 01:22:23',
+ 'updated' => '2007-03-17 01:24:31'
+ )));
+ $this->assertEqual($result, $expected);
+
+ $result = $TestModel->find('all', array('limit' => 3, 'page' => 3));
+ $expected = array();
+ $this->assertEqual($result, $expected);
+ }
+ }
+
+/**
+ * test find('list') method
+ *
+ * @access public
+ * @return void
+ */
+ function testGenerateFindList() {
+ $this->loadFixtures('Article', 'Apple', 'Post', 'Author', 'User');
+
+ $TestModel =& new Article();
+ $TestModel->displayField = 'title';
+
+ $result = $TestModel->find('list', array(
+ 'order' => 'Article.title ASC'
+ ));
+
+ $expected = array(
+ 1 => 'First Article',
+ 2 => 'Second Article',
+ 3 => 'Third Article'
+ );
+ $this->assertEqual($result, $expected);
+
+ $db =& ConnectionManager::getDataSource('test_suite');
+ if ($db->config['driver'] == 'mysql') {
+ $result = $TestModel->find('list', array(
+ 'order' => array('FIELD(Article.id, 3, 2) ASC', 'Article.title ASC')
+ ));
+ $expected = array(
+ 1 => 'First Article',
+ 3 => 'Third Article',
+ 2 => 'Second Article'
+ );
+ $this->assertEqual($result, $expected);
+ }
+
+ $result = Set::combine(
+ $TestModel->find('all', array(
+ 'order' => 'Article.title ASC',
+ 'fields' => array('id', 'title')
+ )),
+ '{n}.Article.id', '{n}.Article.title'
+ );
+ $expected = array(
+ 1 => 'First Article',
+ 2 => 'Second Article',
+ 3 => 'Third Article'
+ );
+ $this->assertEqual($result, $expected);
+
+ $result = Set::combine(
+ $TestModel->find('all', array(
+ 'order' => 'Article.title ASC'
+ )),
+ '{n}.Article.id', '{n}.Article'
+ );
+ $expected = array(
+ 1 => array(
+ 'id' => 1,
+ 'user_id' => 1,
+ 'title' => 'First Article',
+ 'body' => 'First Article Body',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:39:23',
+ 'updated' => '2007-03-18 10:41:31'
+ ),
+ 2 => array(
+ 'id' => 2,
+ 'user_id' => 3,
+ 'title' => 'Second Article',
+ 'body' => 'Second Article Body',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:41:23',
+ 'updated' => '2007-03-18 10:43:31'
+ ),
+ 3 => array(
+ 'id' => 3,
+ 'user_id' => 1,
+ 'title' => 'Third Article',
+ 'body' => 'Third Article Body',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:43:23',
+ 'updated' => '2007-03-18 10:45:31'
+ ));
+
+ $this->assertEqual($result, $expected);
+
+ $result = Set::combine(
+ $TestModel->find('all', array(
+ 'order' => 'Article.title ASC'
+ )),
+ '{n}.Article.id', '{n}.Article', '{n}.Article.user_id'
+ );
+ $expected = array(
+ 1 => array(
+ 1 => array(
+ 'id' => 1,
+ 'user_id' => 1,
+ 'title' => 'First Article',
+ 'body' => 'First Article Body',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:39:23',
+ 'updated' => '2007-03-18 10:41:31'
+ ),
+ 3 => array(
+ 'id' => 3,
+ 'user_id' => 1,
+ 'title' => 'Third Article',
+ 'body' => 'Third Article Body',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:43:23',
+ 'updated' => '2007-03-18 10:45:31'
+ )),
+ 3 => array(
+ 2 => array(
+ 'id' => 2,
+ 'user_id' => 3,
+ 'title' => 'Second Article',
+ 'body' => 'Second Article Body',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:41:23',
+ 'updated' => '2007-03-18 10:43:31'
+ )));
+
+ $this->assertEqual($result, $expected);
+
+ $result = Set::combine(
+ $TestModel->find('all', array(
+ 'order' => 'Article.title ASC',
+ 'fields' => array('id', 'title', 'user_id')
+ )),
+ '{n}.Article.id', '{n}.Article.title', '{n}.Article.user_id'
+ );
+
+ $expected = array(
+ 1 => array(
+ 1 => 'First Article',
+ 3 => 'Third Article'
+ ),
+ 3 => array(
+ 2 => 'Second Article'
+ ));
+ $this->assertEqual($result, $expected);
+
+ $TestModel =& new Apple();
+ $expected = array(
+ 1 => 'Red Apple 1',
+ 2 => 'Bright Red Apple',
+ 3 => 'green blue',
+ 4 => 'Test Name',
+ 5 => 'Blue Green',
+ 6 => 'My new apple',
+ 7 => 'Some odd color'
+ );
+
+ $this->assertEqual($TestModel->find('list'), $expected);
+ $this->assertEqual($TestModel->Parent->find('list'), $expected);
+
+ $TestModel =& new Post();
+ $result = $TestModel->find('list', array(
+ 'fields' => 'Post.title'
+ ));
+ $expected = array(
+ 1 => 'First Post',
+ 2 => 'Second Post',
+ 3 => 'Third Post'
+ );
+ $this->assertEqual($result, $expected);
+
+ $result = $TestModel->find('list', array(
+ 'fields' => 'title'
+ ));
+ $expected = array(
+ 1 => 'First Post',
+ 2 => 'Second Post',
+ 3 => 'Third Post'
+ );
+ $this->assertEqual($result, $expected);
+
+ $result = $TestModel->find('list', array(
+ 'fields' => array('title', 'id')
+ ));
+ $expected = array(
+ 'First Post' => '1',
+ 'Second Post' => '2',
+ 'Third Post' => '3'
+ );
+ $this->assertEqual($result, $expected);
+
+ $result = $TestModel->find('list', array(
+ 'fields' => array('title', 'id', 'created')
+ ));
+ $expected = array(
+ '2007-03-18 10:39:23' => array(
+ 'First Post' => '1'
+ ),
+ '2007-03-18 10:41:23' => array(
+ 'Second Post' => '2'
+ ),
+ '2007-03-18 10:43:23' => array(
+ 'Third Post' => '3'
+ ),
+ );
+ $this->assertEqual($result, $expected);
+
+ $result = $TestModel->find('list', array(
+ 'fields' => array('Post.body')
+ ));
+ $expected = array(
+ 1 => 'First Post Body',
+ 2 => 'Second Post Body',
+ 3 => 'Third Post Body'
+ );
+ $this->assertEqual($result, $expected);
+
+ $result = $TestModel->find('list', array(
+ 'fields' => array('Post.title', 'Post.body')
+ ));
+ $expected = array(
+ 'First Post' => 'First Post Body',
+ 'Second Post' => 'Second Post Body',
+ 'Third Post' => 'Third Post Body'
+ );
+ $this->assertEqual($result, $expected);
+
+ $result = $TestModel->find('list', array(
+ 'fields' => array('Post.id', 'Post.title', 'Author.user'),
+ 'recursive' => 1
+ ));
+ $expected = array(
+ 'mariano' => array(
+ 1 => 'First Post',
+ 3 => 'Third Post'
+ ),
+ 'larry' => array(
+ 2 => 'Second Post'
+ ));
+ $this->assertEqual($result, $expected);
+
+ $TestModel =& new User();
+ $result = $TestModel->find('list', array(
+ 'fields' => array('User.user', 'User.password')
+ ));
+ $expected = array(
+ 'mariano' => '5f4dcc3b5aa765d61d8327deb882cf99',
+ 'nate' => '5f4dcc3b5aa765d61d8327deb882cf99',
+ 'larry' => '5f4dcc3b5aa765d61d8327deb882cf99',
+ 'garrett' => '5f4dcc3b5aa765d61d8327deb882cf99'
+ );
+ $this->assertEqual($result, $expected);
+
+ $TestModel =& new ModifiedAuthor();
+ $result = $TestModel->find('list', array(
+ 'fields' => array('Author.id', 'Author.user')
+ ));
+ $expected = array(
+ 1 => 'mariano (CakePHP)',
+ 2 => 'nate (CakePHP)',
+ 3 => 'larry (CakePHP)',
+ 4 => 'garrett (CakePHP)'
+ );
+ $this->assertEqual($result, $expected);
+
+ $TestModel =& new Article();
+ $TestModel->displayField = 'title';
+ $result = $TestModel->find('list', array(
+ 'conditions' => array('User.user' => 'mariano'),
+ 'recursive' => 0
+ ));
+ $expected = array(
+ 1 => 'First Article',
+ 3 => 'Third Article'
+ );
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testFindField method
+ *
+ * @access public
+ * @return void
+ */
+ function testFindField() {
+ $this->loadFixtures('User');
+ $TestModel =& new User();
+
+ $TestModel->id = 1;
+ $result = $TestModel->field('user');
+ $this->assertEqual($result, 'mariano');
+
+ $result = $TestModel->field('User.user');
+ $this->assertEqual($result, 'mariano');
+
+ $TestModel->id = false;
+ $result = $TestModel->field('user', array(
+ 'user' => 'mariano'
+ ));
+ $this->assertEqual($result, 'mariano');
+
+ $result = $TestModel->field('COUNT(*) AS count', true);
+ $this->assertEqual($result, 4);
+
+ $result = $TestModel->field('COUNT(*)', true);
+ $this->assertEqual($result, 4);
+ }
+
+/**
+ * testFindUnique method
+ *
+ * @access public
+ * @return void
+ */
+ function testFindUnique() {
+ $this->loadFixtures('User');
+ $TestModel =& new User();
+
+ $this->assertFalse($TestModel->isUnique(array(
+ 'user' => 'nate'
+ )));
+ $TestModel->id = 2;
+ $this->assertTrue($TestModel->isUnique(array(
+ 'user' => 'nate'
+ )));
+ $this->assertFalse($TestModel->isUnique(array(
+ 'user' => 'nate',
+ 'password' => '5f4dcc3b5aa765d61d8327deb882cf99'
+ )));
+ }
+
+/**
+ * test find('count') method
+ *
+ * @access public
+ * @return void
+ */
+ function testFindCount() {
+ $this->loadFixtures('User', 'Project');
+
+ $TestModel =& new User();
+ $result = $TestModel->find('count');
+ $this->assertEqual($result, 4);
+
+ $fullDebug = $this->db->fullDebug;
+ $this->db->fullDebug = true;
+ $TestModel->order = 'User.id';
+ $this->db->_queriesLog = array();
+ $result = $TestModel->find('count');
+ $this->assertEqual($result, 4);
+
+ $this->assertTrue(isset($this->db->_queriesLog[0]['query']));
+ $this->assertNoPattern('/ORDER\s+BY/', $this->db->_queriesLog[0]['query']);
+ }
+
+/**
+ * Test that find('first') does not use the id set to the object.
+ *
+ * @return void
+ */
+ function testFindFirstNoIdUsed() {
+ $this->loadFixtures('Project');
+
+ $Project =& new Project();
+ $Project->id = 3;
+ $result = $Project->find('first');
+
+ $this->assertEqual($result['Project']['name'], 'Project 1', 'Wrong record retrieved');
+ }
+
+/**
+ * test find with COUNT(DISTINCT field)
+ *
+ * @return void
+ */
+ function testFindCountDistinct() {
+ $skip = $this->skipIf(
+ $this->db->config['driver'] == 'sqlite',
+ 'SELECT COUNT(DISTINCT field) is not compatible with SQLite'
+ );
+ if ($skip) {
+ return;
+ }
+ $this->loadFixtures('Project');
+ $TestModel =& new Project();
+ $TestModel->create(array('name' => 'project')) && $TestModel->save();
+ $TestModel->create(array('name' => 'project')) && $TestModel->save();
+ $TestModel->create(array('name' => 'project')) && $TestModel->save();
+
+ $result = $TestModel->find('count', array('fields' => 'DISTINCT name'));
+ $this->assertEqual($result, 4);
+ }
+
+/**
+ * Test find(count) with Db::expression
+ *
+ * @access public
+ * @return void
+ */
+ function testFindCountWithDbExpressions() {
+ if ($this->skipIf($this->db->config['driver'] == 'postgres', '%s testFindCountWithExpressions is not compatible with Postgres')) {
+ return;
+ }
+ $this->loadFixtures('Project');
+ $db = ConnectionManager::getDataSource('test_suite');
+ $TestModel =& new Project();
+
+ $result = $TestModel->find('count', array('conditions' => array(
+ $db->expression('Project.name = \'Project 3\'')
+ )));
+ $this->assertEqual($result, 1);
+
+ $result = $TestModel->find('count', array('conditions' => array(
+ 'Project.name' => $db->expression('\'Project 3\'')
+ )));
+ $this->assertEqual($result, 1);
+ }
+
+/**
+ * testFindMagic method
+ *
+ * @access public
+ * @return void
+ */
+ function testFindMagic() {
+ $this->loadFixtures('User');
+ $TestModel =& new User();
+
+ $result = $TestModel->findByUser('mariano');
+ $expected = array(
+ 'User' => array(
+ 'id' => '1',
+ 'user' => 'mariano',
+ 'password' => '5f4dcc3b5aa765d61d8327deb882cf99',
+ 'created' => '2007-03-17 01:16:23',
+ 'updated' => '2007-03-17 01:18:31'
+ ));
+ $this->assertEqual($result, $expected);
+
+ $result = $TestModel->findByPassword('5f4dcc3b5aa765d61d8327deb882cf99');
+ $expected = array('User' => array(
+ 'id' => '1',
+ 'user' => 'mariano',
+ 'password' => '5f4dcc3b5aa765d61d8327deb882cf99',
+ 'created' => '2007-03-17 01:16:23',
+ 'updated' => '2007-03-17 01:18:31'
+ ));
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testRead method
+ *
+ * @access public
+ * @return void
+ */
+ function testRead() {
+ $this->loadFixtures('User', 'Article');
+ $TestModel =& new User();
+
+ $result = $TestModel->read();
+ $this->assertFalse($result);
+
+ $TestModel->id = 2;
+ $result = $TestModel->read();
+ $expected = array(
+ 'User' => array(
+ 'id' => '2',
+ 'user' => 'nate',
+ 'password' => '5f4dcc3b5aa765d61d8327deb882cf99',
+ 'created' => '2007-03-17 01:18:23',
+ 'updated' => '2007-03-17 01:20:31'
+ ));
+ $this->assertEqual($result, $expected);
+
+ $result = $TestModel->read(null, 2);
+ $expected = array(
+ 'User' => array(
+ 'id' => '2',
+ 'user' => 'nate',
+ 'password' => '5f4dcc3b5aa765d61d8327deb882cf99',
+ 'created' => '2007-03-17 01:18:23',
+ 'updated' => '2007-03-17 01:20:31'
+ ));
+ $this->assertEqual($result, $expected);
+
+ $TestModel->id = 2;
+ $result = $TestModel->read(array('id', 'user'));
+ $expected = array('User' => array('id' => '2', 'user' => 'nate'));
+ $this->assertEqual($result, $expected);
+
+ $result = $TestModel->read('id, user', 2);
+ $expected = array(
+ 'User' => array(
+ 'id' => '2',
+ 'user' => 'nate'
+ ));
+ $this->assertEqual($result, $expected);
+
+ $result = $TestModel->bindModel(array('hasMany' => array('Article')));
+ $this->assertTrue($result);
+
+ $TestModel->id = 1;
+ $result = $TestModel->read('id, user');
+ $expected = array(
+ 'User' => array(
+ 'id' => '1',
+ 'user' => 'mariano'
+ ),
+ 'Article' => array(
+ array(
+ 'id' => '1',
+ 'user_id' => '1',
+ 'title' => 'First Article',
+ 'body' => 'First Article Body',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:39:23',
+ 'updated' => '2007-03-18 10:41:31'
+ ),
+ array(
+ 'id' => '3',
+ 'user_id' => '1',
+ 'title' => 'Third Article',
+ 'body' => 'Third Article Body',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:43:23',
+ 'updated' => '2007-03-18 10:45:31'
+ )));
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testRecursiveRead method
+ *
+ * @access public
+ * @return void
+ */
+ function testRecursiveRead() {
+ $this->loadFixtures(
+ 'User',
+ 'Article',
+ 'Comment',
+ 'Tag',
+ 'ArticlesTag',
+ 'Featured',
+ 'ArticleFeatured'
+ );
+ $TestModel =& new User();
+
+ $result = $TestModel->bindModel(array('hasMany' => array('Article')), false);
+ $this->assertTrue($result);
+
+ $TestModel->recursive = 0;
+ $result = $TestModel->read('id, user', 1);
+ $expected = array(
+ 'User' => array('id' => '1', 'user' => 'mariano'),
+ );
+ $this->assertEqual($result, $expected);
+
+ $TestModel->recursive = 1;
+ $result = $TestModel->read('id, user', 1);
+ $expected = array(
+ 'User' => array(
+ 'id' => '1',
+ 'user' => 'mariano'
+ ),
+ 'Article' => array(
+ array(
+ 'id' => '1',
+ 'user_id' => '1',
+ 'title' => 'First Article',
+ 'body' => 'First Article Body',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:39:23',
+ 'updated' => '2007-03-18 10:41:31'
+ ),
+ array(
+ 'id' => '3',
+ 'user_id' => '1',
+ 'title' => 'Third Article',
+ 'body' => 'Third Article Body',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:43:23',
+ 'updated' => '2007-03-18 10:45:31'
+ )));
+ $this->assertEqual($result, $expected);
+
+ $TestModel->recursive = 2;
+ $result = $TestModel->read('id, user', 3);
+ $expected = array(
+ 'User' => array(
+ 'id' => '3',
+ 'user' => 'larry'
+ ),
+ 'Article' => array(
+ array(
+ 'id' => '2',
+ 'user_id' => '3',
+ 'title' => 'Second Article',
+ 'body' => 'Second Article Body',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:41:23',
+ 'updated' => '2007-03-18 10:43:31',
+ 'User' => array(
+ 'id' => '3',
+ 'user' => 'larry',
+ 'password' => '5f4dcc3b5aa765d61d8327deb882cf99',
+ 'created' => '2007-03-17 01:20:23',
+ 'updated' => '2007-03-17 01:22:31'
+ ),
+ 'Comment' => array(
+ array(
+ 'id' => '5',
+ 'article_id' => '2',
+ 'user_id' => '1',
+ 'comment' => 'First Comment for Second Article',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:53:23',
+ 'updated' => '2007-03-18 10:55:31'
+ ),
+ array(
+ 'id' => '6',
+ 'article_id' => '2',
+ 'user_id' => '2',
+ 'comment' => 'Second Comment for Second Article',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:55:23',
+ 'updated' => '2007-03-18 10:57:31'
+ )),
+ 'Tag' => array(
+ array(
+ 'id' => '1',
+ 'tag' => 'tag1',
+ 'created' => '2007-03-18 12:22:23',
+ 'updated' => '2007-03-18 12:24:31'
+ ),
+ array(
+ 'id' => '3',
+ 'tag' => 'tag3',
+ 'created' => '2007-03-18 12:26:23',
+ 'updated' => '2007-03-18 12:28:31'
+ )))));
+ $this->assertEqual($result, $expected);
+ }
+
+ function testRecursiveFindAll() {
+ $this->db->truncate(new Featured());
+
+ $this->loadFixtures(
+ 'User',
+ 'Article',
+ 'Comment',
+ 'Tag',
+ 'ArticlesTag',
+ 'Attachment',
+ 'ArticleFeatured',
+ 'Featured',
+ 'Category'
+ );
+ $TestModel =& new Article();
+
+ $result = $TestModel->find('all', array('conditions' => array('Article.user_id' => 1)));
+ $expected = array(
+ array(
+ 'Article' => array(
+ 'id' => '1',
+ 'user_id' => '1',
+ 'title' => 'First Article',
+ 'body' => 'First Article Body',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:39:23',
+ 'updated' => '2007-03-18 10:41:31'
+ ),
+ 'User' => array(
+ 'id' => '1',
+ 'user' => 'mariano',
+ 'password' => '5f4dcc3b5aa765d61d8327deb882cf99',
+ 'created' => '2007-03-17 01:16:23',
+ 'updated' => '2007-03-17 01:18:31'
+ ),
+ 'Comment' => array(
+ array(
+ 'id' => '1',
+ 'article_id' => '1',
+ 'user_id' => '2',
+ 'comment' => 'First Comment for First Article',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:45:23',
+ 'updated' => '2007-03-18 10:47:31'
+ ),
+ array(
+ 'id' => '2',
+ 'article_id' => '1',
+ 'user_id' => '4',
+ 'comment' => 'Second Comment for First Article',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:47:23',
+ 'updated' => '2007-03-18 10:49:31'
+ ),
+ array(
+ 'id' => '3',
+ 'article_id' => '1',
+ 'user_id' => '1',
+ 'comment' => 'Third Comment for First Article',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:49:23',
+ 'updated' => '2007-03-18 10:51:31'
+ ),
+ array(
+ 'id' => '4',
+ 'article_id' => '1',
+ 'user_id' => '1',
+ 'comment' => 'Fourth Comment for First Article',
+ 'published' => 'N',
+ 'created' => '2007-03-18 10:51:23',
+ 'updated' => '2007-03-18 10:53:31'
+ )
+ ),
+ 'Tag' => array(
+ array(
+ 'id' => '1',
+ 'tag' => 'tag1',
+ 'created' => '2007-03-18 12:22:23',
+ 'updated' => '2007-03-18 12:24:31'
+ ),
+ array(
+ 'id' => '2',
+ 'tag' => 'tag2',
+ 'created' => '2007-03-18 12:24:23',
+ 'updated' => '2007-03-18 12:26:31'
+ ))),
+ array(
+ 'Article' => array(
+ 'id' => '3',
+ 'user_id' => '1',
+ 'title' => 'Third Article',
+ 'body' => 'Third Article Body',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:43:23',
+ 'updated' => '2007-03-18 10:45:31'
+ ),
+ 'User' => array(
+ 'id' => '1',
+ 'user' => 'mariano',
+ 'password' => '5f4dcc3b5aa765d61d8327deb882cf99',
+ 'created' => '2007-03-17 01:16:23',
+ 'updated' => '2007-03-17 01:18:31'
+ ),
+ 'Comment' => array(),
+ 'Tag' => array()
+ )
+ );
+ $this->assertEqual($result, $expected);
+
+ $result = $TestModel->find('all', array(
+ 'conditions' => array('Article.user_id' => 3),
+ 'limit' => 1,
+ 'recursive' => 2
+ ));
+
+ $expected = array(
+ array(
+ 'Article' => array(
+ 'id' => '2',
+ 'user_id' => '3',
+ 'title' => 'Second Article',
+ 'body' => 'Second Article Body',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:41:23',
+ 'updated' => '2007-03-18 10:43:31'
+ ),
+ 'User' => array(
+ 'id' => '3',
+ 'user' => 'larry',
+ 'password' => '5f4dcc3b5aa765d61d8327deb882cf99',
+ 'created' => '2007-03-17 01:20:23',
+ 'updated' => '2007-03-17 01:22:31'
+ ),
+ 'Comment' => array(
+ array(
+ 'id' => '5',
+ 'article_id' => '2',
+ 'user_id' => '1',
+ 'comment' => 'First Comment for Second Article',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:53:23',
+ 'updated' => '2007-03-18 10:55:31',
+ 'Article' => array(
+ 'id' => '2',
+ 'user_id' => '3',
+ 'title' => 'Second Article',
+ 'body' => 'Second Article Body',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:41:23',
+ 'updated' => '2007-03-18 10:43:31'
+ ),
+ 'User' => array(
+ 'id' => '1',
+ 'user' => 'mariano',
+ 'password' => '5f4dcc3b5aa765d61d8327deb882cf99',
+ 'created' => '2007-03-17 01:16:23',
+ 'updated' => '2007-03-17 01:18:31'
+ ),
+ 'Attachment' => array(
+ 'id' => '1',
+ 'comment_id' => 5,
+ 'attachment' => 'attachment.zip',
+ 'created' => '2007-03-18 10:51:23',
+ 'updated' => '2007-03-18 10:53:31'
+ )
+ ),
+ array(
+ 'id' => '6',
+ 'article_id' => '2',
+ 'user_id' => '2',
+ 'comment' => 'Second Comment for Second Article',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:55:23',
+ 'updated' => '2007-03-18 10:57:31',
+ 'Article' => array(
+ 'id' => '2',
+ 'user_id' => '3',
+ 'title' => 'Second Article',
+ 'body' => 'Second Article Body',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:41:23',
+ 'updated' => '2007-03-18 10:43:31'
+ ),
+ 'User' => array(
+ 'id' => '2',
+ 'user' => 'nate',
+ 'password' => '5f4dcc3b5aa765d61d8327deb882cf99',
+ 'created' => '2007-03-17 01:18:23',
+ 'updated' => '2007-03-17 01:20:31'
+ ),
+ 'Attachment' => false
+ )
+ ),
+ 'Tag' => array(
+ array(
+ 'id' => '1',
+ 'tag' => 'tag1',
+ 'created' => '2007-03-18 12:22:23',
+ 'updated' => '2007-03-18 12:24:31'
+ ),
+ array(
+ 'id' => '3',
+ 'tag' => 'tag3',
+ 'created' => '2007-03-18 12:26:23',
+ 'updated' => '2007-03-18 12:28:31'
+ ))));
+
+ $this->assertEqual($result, $expected);
+
+ $Featured = new Featured();
+
+ $Featured->recursive = 2;
+ $Featured->bindModel(array(
+ 'belongsTo' => array(
+ 'ArticleFeatured' => array(
+ 'conditions' => "ArticleFeatured.published = 'Y'",
+ 'fields' => 'id, title, user_id, published'
+ )
+ )
+ ));
+
+ $Featured->ArticleFeatured->unbindModel(array(
+ 'hasMany' => array('Attachment', 'Comment'),
+ 'hasAndBelongsToMany' => array('Tag'))
+ );
+
+ $orderBy = 'ArticleFeatured.id ASC';
+ $result = $Featured->find('all', array(
+ 'order' => $orderBy, 'limit' => 3
+ ));
+
+ $expected = array(
+ array(
+ 'Featured' => array(
+ 'id' => '1',
+ 'article_featured_id' => '1',
+ 'category_id' => '1',
+ 'published_date' => '2007-03-31 10:39:23',
+ 'end_date' => '2007-05-15 10:39:23',
+ 'created' => '2007-03-18 10:39:23',
+ 'updated' => '2007-03-18 10:41:31'
+ ),
+ 'ArticleFeatured' => array(
+ 'id' => '1',
+ 'title' => 'First Article',
+ 'user_id' => '1',
+ 'published' => 'Y',
+ 'User' => array(
+ 'id' => '1',
+ 'user' => 'mariano',
+ 'password' => '5f4dcc3b5aa765d61d8327deb882cf99',
+ 'created' => '2007-03-17 01:16:23',
+ 'updated' => '2007-03-17 01:18:31'
+ ),
+ 'Category' => array(),
+ 'Featured' => array(
+ 'id' => '1',
+ 'article_featured_id' => '1',
+ 'category_id' => '1',
+ 'published_date' => '2007-03-31 10:39:23',
+ 'end_date' => '2007-05-15 10:39:23',
+ 'created' => '2007-03-18 10:39:23',
+ 'updated' => '2007-03-18 10:41:31'
+ )),
+ 'Category' => array(
+ 'id' => '1',
+ 'parent_id' => '0',
+ 'name' => 'Category 1',
+ 'created' => '2007-03-18 15:30:23',
+ 'updated' => '2007-03-18 15:32:31'
+ )),
+ array(
+ 'Featured' => array(
+ 'id' => '2',
+ 'article_featured_id' => '2',
+ 'category_id' => '1',
+ 'published_date' => '2007-03-31 10:39:23',
+ 'end_date' => '2007-05-15 10:39:23',
+ 'created' => '2007-03-18 10:39:23',
+ 'updated' => '2007-03-18 10:41:31'
+ ),
+ 'ArticleFeatured' => array(
+ 'id' => '2',
+ 'title' => 'Second Article',
+ 'user_id' => '3',
+ 'published' => 'Y',
+ 'User' => array(
+ 'id' => '3',
+ 'user' => 'larry',
+ 'password' => '5f4dcc3b5aa765d61d8327deb882cf99',
+ 'created' => '2007-03-17 01:20:23',
+ 'updated' => '2007-03-17 01:22:31'
+ ),
+ 'Category' => array(),
+ 'Featured' => array(
+ 'id' => '2',
+ 'article_featured_id' => '2',
+ 'category_id' => '1',
+ 'published_date' => '2007-03-31 10:39:23',
+ 'end_date' => '2007-05-15 10:39:23',
+ 'created' => '2007-03-18 10:39:23',
+ 'updated' => '2007-03-18 10:41:31'
+ )),
+ 'Category' => array(
+ 'id' => '1',
+ 'parent_id' => '0',
+ 'name' => 'Category 1',
+ 'created' => '2007-03-18 15:30:23',
+ 'updated' => '2007-03-18 15:32:31'
+ )));
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testRecursiveFindAllWithLimit method
+ *
+ * @access public
+ * @return void
+ */
+ function testRecursiveFindAllWithLimit() {
+ $this->loadFixtures('Article', 'User', 'Tag', 'ArticlesTag', 'Comment', 'Attachment');
+ $TestModel =& new Article();
+
+ $TestModel->hasMany['Comment']['limit'] = 2;
+
+ $result = $TestModel->find('all', array(
+ 'conditions' => array('Article.user_id' => 1)
+ ));
+ $expected = array(
+ array(
+ 'Article' => array(
+ 'id' => '1',
+ 'user_id' => '1',
+ 'title' => 'First Article',
+ 'body' => 'First Article Body',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:39:23',
+ 'updated' => '2007-03-18 10:41:31'
+ ),
+ 'User' => array(
+ 'id' => '1',
+ 'user' => 'mariano',
+ 'password' => '5f4dcc3b5aa765d61d8327deb882cf99',
+ 'created' => '2007-03-17 01:16:23',
+ 'updated' => '2007-03-17 01:18:31'
+ ),
+ 'Comment' => array(
+ array(
+ 'id' => '1',
+ 'article_id' => '1',
+ 'user_id' => '2',
+ 'comment' => 'First Comment for First Article',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:45:23',
+ 'updated' => '2007-03-18 10:47:31'
+ ),
+ array(
+ 'id' => '2',
+ 'article_id' => '1',
+ 'user_id' => '4',
+ 'comment' => 'Second Comment for First Article',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:47:23',
+ 'updated' => '2007-03-18 10:49:31'
+ ),
+ ),
+ 'Tag' => array(
+ array(
+ 'id' => '1',
+ 'tag' => 'tag1',
+ 'created' => '2007-03-18 12:22:23',
+ 'updated' => '2007-03-18 12:24:31'
+ ),
+ array(
+ 'id' => '2',
+ 'tag' => 'tag2',
+ 'created' => '2007-03-18 12:24:23',
+ 'updated' => '2007-03-18 12:26:31'
+ ))),
+ array(
+ 'Article' => array(
+ 'id' => '3',
+ 'user_id' => '1',
+ 'title' => 'Third Article',
+ 'body' => 'Third Article Body',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:43:23',
+ 'updated' => '2007-03-18 10:45:31'
+ ),
+ 'User' => array(
+ 'id' => '1',
+ 'user' => 'mariano',
+ 'password' => '5f4dcc3b5aa765d61d8327deb882cf99',
+ 'created' => '2007-03-17 01:16:23',
+ 'updated' => '2007-03-17 01:18:31'
+ ),
+ 'Comment' => array(),
+ 'Tag' => array()
+ )
+ );
+ $this->assertEqual($result, $expected);
+
+ $TestModel->hasMany['Comment']['limit'] = 1;
+
+ $result = $TestModel->find('all', array(
+ 'conditions' => array('Article.user_id' => 3),
+ 'limit' => 1,
+ 'recursive' => 2
+ ));
+ $expected = array(
+ array(
+ 'Article' => array(
+ 'id' => '2',
+ 'user_id' => '3',
+ 'title' => 'Second Article',
+ 'body' => 'Second Article Body',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:41:23',
+ 'updated' => '2007-03-18 10:43:31'
+ ),
+ 'User' => array(
+ 'id' => '3',
+ 'user' => 'larry',
+ 'password' => '5f4dcc3b5aa765d61d8327deb882cf99',
+ 'created' => '2007-03-17 01:20:23',
+ 'updated' => '2007-03-17 01:22:31'
+ ),
+ 'Comment' => array(
+ array(
+ 'id' => '5',
+ 'article_id' => '2',
+ 'user_id' => '1',
+ 'comment' => 'First Comment for Second Article',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:53:23',
+ 'updated' => '2007-03-18 10:55:31',
+ 'Article' => array(
+ 'id' => '2',
+ 'user_id' => '3',
+ 'title' => 'Second Article',
+ 'body' => 'Second Article Body',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:41:23',
+ 'updated' => '2007-03-18 10:43:31'
+ ),
+ 'User' => array(
+ 'id' => '1',
+ 'user' => 'mariano',
+ 'password' => '5f4dcc3b5aa765d61d8327deb882cf99',
+ 'created' => '2007-03-17 01:16:23',
+ 'updated' => '2007-03-17 01:18:31'
+ ),
+ 'Attachment' => array(
+ 'id' => '1',
+ 'comment_id' => 5,
+ 'attachment' => 'attachment.zip',
+ 'created' => '2007-03-18 10:51:23',
+ 'updated' => '2007-03-18 10:53:31'
+ )
+ )
+ ),
+ 'Tag' => array(
+ array(
+ 'id' => '1',
+ 'tag' => 'tag1',
+ 'created' => '2007-03-18 12:22:23',
+ 'updated' => '2007-03-18 12:24:31'
+ ),
+ array(
+ 'id' => '3',
+ 'tag' => 'tag3',
+ 'created' => '2007-03-18 12:26:23',
+ 'updated' => '2007-03-18 12:28:31'
+ )
+ )
+ )
+ );
+ $this->assertEqual($result, $expected);
+ }
+/**
+ * Testing availability of $this->findQueryType in Model callbacks
+ *
+ * @return void
+ */
+ function testFindQueryTypeInCallbacks() {
+ $this->loadFixtures('Comment');
+ $Comment =& new AgainModifiedComment();
+ $comments = $Comment->find('all');
+ $this->assertEqual($comments[0]['Comment']['querytype'], 'all');
+ $comments = $Comment->find('first');
+ $this->assertEqual($comments['Comment']['querytype'], 'first');
+ }
+
+/**
+ * testVirtualFields()
+ *
+ * Test correct fetching of virtual fields
+ * currently is not possible to do Relation.virtualField
+ *
+ * @access public
+ * @return void
+ */
+ function testVirtualFields() {
+ $this->loadFixtures('Post', 'Author');
+ $Post =& ClassRegistry::init('Post');
+ $Post->virtualFields = array('two' => "1 + 1");
+ $result = $Post->find('first');
+ $this->assertEqual($result['Post']['two'], 2);
+
+ $Post->Author->virtualFields = array('false' => '1 = 2');
+ $result = $Post->find('first');
+ $this->assertEqual($result['Post']['two'], 2);
+ $this->assertEqual($result['Author']['false'], false);
+
+ $result = $Post->find('first',array('fields' => array('author_id')));
+ $this->assertFalse(isset($result['Post']['two']));
+ $this->assertFalse(isset($result['Author']['false']));
+
+ $result = $Post->find('first',array('fields' => array('author_id', 'two')));
+ $this->assertEqual($result['Post']['two'], 2);
+ $this->assertFalse(isset($result['Author']['false']));
+
+ $result = $Post->find('first',array('fields' => array('two')));
+ $this->assertEqual($result['Post']['two'], 2);
+
+ $Post->id = 1;
+ $result = $Post->field('two');
+ $this->assertEqual($result, 2);
+
+ $result = $Post->find('first',array(
+ 'conditions' => array('two' => 2),
+ 'limit' => 1
+ ));
+ $this->assertEqual($result['Post']['two'], 2);
+
+ $result = $Post->find('first',array(
+ 'conditions' => array('two <' => 3),
+ 'limit' => 1
+ ));
+ $this->assertEqual($result['Post']['two'], 2);
+
+ $result = $Post->find('first',array(
+ 'conditions' => array('NOT' => array('two >' => 3)),
+ 'limit' => 1
+ ));
+ $this->assertEqual($result['Post']['two'], 2);
+
+ $dbo =& $Post->getDataSource();
+ $Post->virtualFields = array('other_field' => 'Post.id + 1');
+ $result = $Post->find('first', array(
+ 'conditions' => array('other_field' => 3),
+ 'limit' => 1
+ ));
+ $this->assertEqual($result['Post']['id'], 2);
+
+ $Post->virtualFields = array('other_field' => 'Post.id + 1');
+ $result = $Post->find('all', array(
+ 'fields' => array($dbo->calculate($Post, 'max', array('other_field')))
+ ));
+ $this->assertEqual($result[0][0]['other_field'], 4);
+
+ ClassRegistry::flush();
+ $Writing =& ClassRegistry::init(array('class' => 'Post', 'alias' => 'Writing'), 'Model');
+ $Writing->virtualFields = array('two' => "1 + 1");
+ $result = $Writing->find('first');
+ $this->assertEqual($result['Writing']['two'], 2);
+
+ $Post->create();
+ $Post->virtualFields = array('other_field' => 'COUNT(Post.id) + 1');
+ $result = $Post->field('other_field');
+ $this->assertEqual($result, 4);
+
+ if ($this->skipIf($this->db->config['driver'] == 'postgres', 'The rest of virtualFieds test is not compatible with Postgres')) {
+ return;
+ }
+ ClassRegistry::flush();
+ $Post =& ClassRegistry::init('Post');
+
+ $Post->create();
+ $Post->virtualFields = array(
+ 'year' => 'YEAR(Post.created)',
+ 'unique_test_field' => 'COUNT(Post.id)'
+ );
+
+ $expectation = array(
+ 'Post' => array(
+ 'year' => 2007,
+ 'unique_test_field' => 3
+ )
+ );
+
+ $result = $Post->find('first', array(
+ 'fields' => array_keys($Post->virtualFields),
+ 'group' => array('year')
+ ));
+
+ $this->assertEqual($result, $expectation);
+
+
+ $Author =& ClassRegistry::init('Author');
+ $Author->virtualFields = array(
+ 'full_name' => 'CONCAT(Author.user, " ", Author.id)'
+ );
+
+ $result = $Author->find('first', array(
+ 'conditions' => array('Author.user' => 'mariano'),
+ 'fields' => array('Author.password', 'Author.full_name'),
+ 'recursive' => -1
+ ));
+ $this->assertTrue(isset($result['Author']['full_name']));
+
+ $result = $Author->find('first', array(
+ 'conditions' => array('Author.user' => 'mariano'),
+ 'fields' => array('Author.full_name', 'Author.password'),
+ 'recursive' => -1
+ ));
+ $this->assertTrue(isset($result['Author']['full_name']));
+ }
+
+/**
+ * test that virtual fields work when they don't contain functions.
+ *
+ * @return void
+ */
+ function testVirtualFieldAsAString() {
+ $this->loadFixtures('Post', 'Author');
+ $Post =& new Post();
+ $Post->virtualFields = array(
+ 'writer' => 'Author.user'
+ );
+ $result = $Post->find('first');
+ $this->assertTrue(isset($result['Post']['writer']), 'virtual field not fetched %s');
+ }
+
+/**
+ * test that isVirtualField will accept both aliased and non aliased fieldnames
+ *
+ * @return void
+ */
+ function testIsVirtualField() {
+ $this->loadFixtures('Post');
+ $Post =& ClassRegistry::init('Post');
+ $Post->virtualFields = array('other_field' => 'COUNT(Post.id) + 1');
+
+ $this->assertTrue($Post->isVirtualField('other_field'));
+ $this->assertTrue($Post->isVirtualField('Post.other_field'));
+ $this->assertFalse($Post->isVirtualField('id'));
+ $this->assertFalse($Post->isVirtualField('Post.id'));
+ $this->assertFalse($Post->isVirtualField(array()));
+ }
+
+/**
+ * test that getting virtual fields works with and without model alias attached
+ *
+ * @return void
+ */
+ function testGetVirtualField() {
+ $this->loadFixtures('Post');
+ $Post =& ClassRegistry::init('Post');
+ $Post->virtualFields = array('other_field' => 'COUNT(Post.id) + 1');
+
+ $this->assertEqual($Post->getVirtualField('other_field'), $Post->virtualFields['other_field']);
+ $this->assertEqual($Post->getVirtualField('Post.other_field'), $Post->virtualFields['other_field']);
+ }
+}
diff --git a/code/ryzom/tools/server/www/webtt/cake/tests/cases/libs/model/model_validation.test.php b/code/ryzom/tools/server/www/webtt/cake/tests/cases/libs/model/model_validation.test.php
new file mode 100644
index 000000000..d0b3fb648
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/cake/tests/cases/libs/model/model_validation.test.php
@@ -0,0 +1,673 @@
+
+ * Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
+ *
+ * Licensed under The Open Group Test Suite License
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
+ * @link http://book.cakephp.org/view/1196/Testing CakePHP(tm) Tests
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ * @since CakePHP(tm) v 1.2.0.4206
+ * @license http://www.opensource.org/licenses/opengroup.php The Open Group Test Suite License
+ */
+require_once dirname(__FILE__) . DS . 'model.test.php';
+
+/**
+ * ModelValidationTest
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model.operations
+ */
+class ModelValidationTest extends BaseModelTest {
+
+/**
+ * Tests validation parameter order in custom validation methods
+ *
+ * @access public
+ * @return void
+ */
+ function testValidationParams() {
+ $TestModel =& new ValidationTest1();
+ $TestModel->validate['title'] = array(
+ 'rule' => 'customValidatorWithParams',
+ 'required' => true
+ );
+ $TestModel->create(array('title' => 'foo'));
+ $TestModel->invalidFields();
+
+ $expected = array(
+ 'data' => array(
+ 'title' => 'foo'
+ ),
+ 'validator' => array(
+ 'rule' => 'customValidatorWithParams',
+ 'on' => null,
+ 'last' => false,
+ 'allowEmpty' => false,
+ 'required' => true
+ ),
+ 'or' => true,
+ 'ignore_on_same' => 'id'
+ );
+ $this->assertEqual($TestModel->validatorParams, $expected);
+
+ $TestModel->validate['title'] = array(
+ 'rule' => 'customValidatorWithMessage',
+ 'required' => true
+ );
+ $expected = array(
+ 'title' => 'This field will *never* validate! Muhahaha!'
+ );
+
+ $this->assertEqual($TestModel->invalidFields(), $expected);
+
+ $TestModel->validate['title'] = array(
+ 'rule' => array('customValidatorWithSixParams', 'one', 'two', null, 'four'),
+ 'required' => true
+ );
+ $TestModel->create(array('title' => 'foo'));
+ $TestModel->invalidFields();
+ $expected = array(
+ 'data' => array(
+ 'title' => 'foo'
+ ),
+ 'one' => 'one',
+ 'two' => 'two',
+ 'three' => null,
+ 'four' => 'four',
+ 'five' => array(
+ 'rule' => array(1 => 'one', 2 => 'two', 3 => null, 4 => 'four'),
+ 'on' => null,
+ 'last' => false,
+ 'allowEmpty' => false,
+ 'required' => true
+ ),
+ 'six' => 6
+ );
+ $this->assertEqual($TestModel->validatorParams, $expected);
+
+ $TestModel->validate['title'] = array(
+ 'rule' => array('customValidatorWithSixParams', 'one', array('two'), null, 'four', array('five' => 5)),
+ 'required' => true
+ );
+ $TestModel->create(array('title' => 'foo'));
+ $TestModel->invalidFields();
+ $expected = array(
+ 'data' => array(
+ 'title' => 'foo'
+ ),
+ 'one' => 'one',
+ 'two' => array('two'),
+ 'three' => null,
+ 'four' => 'four',
+ 'five' => array('five' => 5),
+ 'six' => array(
+ 'rule' => array(1 => 'one', 2 => array('two'), 3 => null, 4 => 'four', 5 => array('five' => 5)),
+ 'on' => null,
+ 'last' => false,
+ 'allowEmpty' => false,
+ 'required' => true
+ )
+ );
+ $this->assertEqual($TestModel->validatorParams, $expected);
+ }
+
+/**
+ * Tests validation parameter fieldList in invalidFields
+ *
+ * @access public
+ * @return void
+ */
+ function testInvalidFieldsWithFieldListParams() {
+ $TestModel =& new ValidationTest1();
+ $TestModel->validate = $validate = array(
+ 'title' => array(
+ 'rule' => 'alphaNumeric',
+ 'required' => true
+ ),
+ 'name' => array(
+ 'rule' => 'alphaNumeric',
+ 'required' => true
+ ));
+ $TestModel->set(array('title' => '$$', 'name' => '##'));
+ $TestModel->invalidFields(array('fieldList' => array('title')));
+ $expected = array(
+ 'title' => 'This field cannot be left blank'
+ );
+ $this->assertEqual($TestModel->validationErrors, $expected);
+ $TestModel->validationErrors = array();
+
+ $TestModel->invalidFields(array('fieldList' => array('name')));
+ $expected = array(
+ 'name' => 'This field cannot be left blank'
+ );
+ $this->assertEqual($TestModel->validationErrors, $expected);
+ $TestModel->validationErrors = array();
+
+ $TestModel->invalidFields(array('fieldList' => array('name', 'title')));
+ $expected = array(
+ 'name' => 'This field cannot be left blank',
+ 'title' => 'This field cannot be left blank'
+ );
+ $this->assertEqual($TestModel->validationErrors, $expected);
+ $TestModel->validationErrors = array();
+
+ $TestModel->whitelist = array('name');
+ $TestModel->invalidFields();
+ $expected = array('name' => 'This field cannot be left blank');
+ $this->assertEqual($TestModel->validationErrors, $expected);
+
+ $this->assertEqual($TestModel->validate, $validate);
+ }
+
+/**
+ * Test that invalidFields() integrates well with save(). And that fieldList can be an empty type.
+ *
+ * @return void
+ */
+ function testInvalidFieldsWhitelist() {
+ $TestModel =& new ValidationTest1();
+ $TestModel->validate = array(
+ 'title' => array(
+ 'rule' => 'alphaNumeric',
+ 'required' => true
+ ),
+ 'name' => array(
+ 'rule' => 'alphaNumeric',
+ 'required' => true
+ ));
+
+ $TestModel->whitelist = array('name');
+ $TestModel->save(array('name' => '#$$#', 'title' => '$$$$'));
+
+ $expected = array('name' => 'This field cannot be left blank');
+ $this->assertEqual($TestModel->validationErrors, $expected);
+ }
+
+/**
+ * testValidates method
+ *
+ * @access public
+ * @return void
+ */
+ function testValidates() {
+ $TestModel =& new TestValidate();
+
+ $TestModel->validate = array(
+ 'user_id' => 'numeric',
+ 'title' => array('allowEmpty' => false, 'rule' => 'notEmpty'),
+ 'body' => 'notEmpty'
+ );
+
+ $data = array('TestValidate' => array(
+ 'user_id' => '1',
+ 'title' => '',
+ 'body' => 'body'
+ ));
+ $result = $TestModel->create($data);
+ $this->assertTrue($result);
+ $result = $TestModel->validates();
+ $this->assertFalse($result);
+
+ $data = array('TestValidate' => array(
+ 'user_id' => '1',
+ 'title' => 'title',
+ 'body' => 'body'
+ ));
+ $result = $TestModel->create($data) && $TestModel->validates();
+ $this->assertTrue($result);
+
+ $data = array('TestValidate' => array(
+ 'user_id' => '1',
+ 'title' => '0',
+ 'body' => 'body'
+ ));
+ $result = $TestModel->create($data);
+ $this->assertTrue($result);
+ $result = $TestModel->validates();
+ $this->assertTrue($result);
+
+ $data = array('TestValidate' => array(
+ 'user_id' => '1',
+ 'title' => 0,
+ 'body' => 'body'
+ ));
+ $result = $TestModel->create($data);
+ $this->assertTrue($result);
+ $result = $TestModel->validates();
+ $this->assertTrue($result);
+
+ $TestModel->validate['modified'] = array('allowEmpty' => true, 'rule' => 'date');
+
+ $data = array('TestValidate' => array(
+ 'user_id' => '1',
+ 'title' => 0,
+ 'body' => 'body',
+ 'modified' => ''
+ ));
+ $result = $TestModel->create($data);
+ $this->assertTrue($result);
+ $result = $TestModel->validates();
+ $this->assertTrue($result);
+
+ $data = array('TestValidate' => array(
+ 'user_id' => '1',
+ 'title' => 0,
+ 'body' => 'body',
+ 'modified' => '2007-05-01'
+ ));
+ $result = $TestModel->create($data);
+ $this->assertTrue($result);
+ $result = $TestModel->validates();
+ $this->assertTrue($result);
+
+ $data = array('TestValidate' => array(
+ 'user_id' => '1',
+ 'title' => 0,
+ 'body' => 'body',
+ 'modified' => 'invalid-date-here'
+ ));
+ $result = $TestModel->create($data);
+ $this->assertTrue($result);
+ $result = $TestModel->validates();
+ $this->assertFalse($result);
+
+ $data = array('TestValidate' => array(
+ 'user_id' => '1',
+ 'title' => 0,
+ 'body' => 'body',
+ 'modified' => 0
+ ));
+ $result = $TestModel->create($data);
+ $this->assertTrue($result);
+ $result = $TestModel->validates();
+ $this->assertFalse($result);
+
+ $data = array('TestValidate' => array(
+ 'user_id' => '1',
+ 'title' => 0,
+ 'body' => 'body',
+ 'modified' => '0'
+ ));
+ $result = $TestModel->create($data);
+ $this->assertTrue($result);
+ $result = $TestModel->validates();
+ $this->assertFalse($result);
+
+ $TestModel->validate['modified'] = array('allowEmpty' => false, 'rule' => 'date');
+
+ $data = array('TestValidate' => array('modified' => null));
+ $result = $TestModel->create($data);
+ $this->assertTrue($result);
+ $result = $TestModel->validates();
+ $this->assertFalse($result);
+
+ $data = array('TestValidate' => array('modified' => false));
+ $result = $TestModel->create($data);
+ $this->assertTrue($result);
+ $result = $TestModel->validates();
+ $this->assertFalse($result);
+
+ $data = array('TestValidate' => array('modified' => ''));
+ $result = $TestModel->create($data);
+ $this->assertTrue($result);
+ $result = $TestModel->validates();
+ $this->assertFalse($result);
+
+ $data = array('TestValidate' => array(
+ 'modified' => '2007-05-01'
+ ));
+ $result = $TestModel->create($data);
+ $this->assertTrue($result);
+ $result = $TestModel->validates();
+ $this->assertTrue($result);
+
+ $TestModel->validate['slug'] = array('allowEmpty' => false, 'rule' => array('maxLength', 45));
+
+ $data = array('TestValidate' => array(
+ 'user_id' => '1',
+ 'title' => 0,
+ 'body' => 'body',
+ 'slug' => ''
+ ));
+ $result = $TestModel->create($data);
+ $this->assertTrue($result);
+ $result = $TestModel->validates();
+ $this->assertFalse($result);
+
+ $data = array('TestValidate' => array(
+ 'user_id' => '1',
+ 'title' => 0,
+ 'body' => 'body',
+ 'slug' => 'slug-right-here'
+ ));
+ $result = $TestModel->create($data);
+ $this->assertTrue($result);
+ $result = $TestModel->validates();
+ $this->assertTrue($result);
+
+ $data = array('TestValidate' => array(
+ 'user_id' => '1',
+ 'title' => 0,
+ 'body' => 'body',
+ 'slug' => 'abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz'
+ ));
+ $result = $TestModel->create($data);
+ $this->assertTrue($result);
+ $result = $TestModel->validates();
+ $this->assertFalse($result);
+
+ $TestModel->validate = array(
+ 'number' => array(
+ 'rule' => 'validateNumber',
+ 'min' => 3,
+ 'max' => 5
+ ),
+ 'title' => array(
+ 'allowEmpty' => false,
+ 'rule' => 'notEmpty'
+ ));
+
+ $data = array('TestValidate' => array(
+ 'title' => 'title',
+ 'number' => '0'
+ ));
+ $result = $TestModel->create($data);
+ $this->assertTrue($result);
+ $result = $TestModel->validates();
+ $this->assertFalse($result);
+
+ $data = array('TestValidate' => array(
+ 'title' => 'title',
+ 'number' => 0
+ ));
+ $result = $TestModel->create($data);
+ $this->assertTrue($result);
+ $result = $TestModel->validates();
+ $this->assertFalse($result);
+
+ $data = array('TestValidate' => array(
+ 'title' => 'title',
+ 'number' => '3'
+ ));
+ $result = $TestModel->create($data);
+ $this->assertTrue($result);
+ $result = $TestModel->validates();
+ $this->assertTrue($result);
+
+ $data = array('TestValidate' => array(
+ 'title' => 'title',
+ 'number' => 3
+ ));
+ $result = $TestModel->create($data);
+ $this->assertTrue($result);
+ $result = $TestModel->validates();
+ $this->assertTrue($result);
+
+ $TestModel->validate = array(
+ 'number' => array(
+ 'rule' => 'validateNumber',
+ 'min' => 5,
+ 'max' => 10
+ ),
+ 'title' => array(
+ 'allowEmpty' => false,
+ 'rule' => 'notEmpty'
+ ));
+
+ $data = array('TestValidate' => array(
+ 'title' => 'title',
+ 'number' => '3'
+ ));
+ $result = $TestModel->create($data);
+ $this->assertTrue($result);
+ $result = $TestModel->validates();
+ $this->assertFalse($result);
+
+ $data = array('TestValidate' => array(
+ 'title' => 'title',
+ 'number' => 3
+ ));
+ $result = $TestModel->create($data);
+ $this->assertTrue($result);
+ $result = $TestModel->validates();
+ $this->assertFalse($result);
+
+ $TestModel->validate = array(
+ 'title' => array(
+ 'allowEmpty' => false,
+ 'rule' => 'validateTitle'
+ ));
+
+ $data = array('TestValidate' => array('title' => ''));
+ $result = $TestModel->create($data);
+ $this->assertTrue($result);
+ $result = $TestModel->validates();
+ $this->assertFalse($result);
+
+ $data = array('TestValidate' => array('title' => 'new title'));
+ $result = $TestModel->create($data);
+ $this->assertTrue($result);
+ $result = $TestModel->validates();
+ $this->assertFalse($result);
+
+ $data = array('TestValidate' => array('title' => 'title-new'));
+ $result = $TestModel->create($data);
+ $this->assertTrue($result);
+ $result = $TestModel->validates();
+ $this->assertTrue($result);
+
+ $TestModel->validate = array('title' => array(
+ 'allowEmpty' => true,
+ 'rule' => 'validateTitle'
+ ));
+ $data = array('TestValidate' => array('title' => ''));
+ $result = $TestModel->create($data);
+ $this->assertTrue($result);
+ $result = $TestModel->validates();
+ $this->assertTrue($result);
+
+ $TestModel->validate = array(
+ 'title' => array(
+ 'length' => array(
+ 'allowEmpty' => true,
+ 'rule' => array('maxLength', 10)
+ )));
+ $data = array('TestValidate' => array('title' => ''));
+ $result = $TestModel->create($data);
+ $this->assertTrue($result);
+ $result = $TestModel->validates();
+ $this->assertTrue($result);
+
+ $TestModel->validate = array(
+ 'title' => array(
+ 'rule' => array('userDefined', 'Article', 'titleDuplicate')
+ ));
+ $data = array('TestValidate' => array('title' => 'My Article Title'));
+ $result = $TestModel->create($data);
+ $this->assertTrue($result);
+ $result = $TestModel->validates();
+ $this->assertFalse($result);
+
+ $data = array('TestValidate' => array(
+ 'title' => 'My Article With a Different Title'
+ ));
+ $result = $TestModel->create($data);
+ $this->assertTrue($result);
+ $result = $TestModel->validates();
+ $this->assertTrue($result);
+
+ $TestModel->validate = array(
+ 'title' => array(
+ 'tooShort' => array('rule' => array('minLength', 50)),
+ 'onlyLetters' => array('rule' => '/^[a-z]+$/i')
+ ),
+ );
+ $data = array('TestValidate' => array(
+ 'title' => 'I am a short string'
+ ));
+ $TestModel->create($data);
+ $result = $TestModel->validates();
+ $this->assertFalse($result);
+ $result = $TestModel->validationErrors;
+ $expected = array(
+ 'title' => 'onlyLetters'
+ );
+ $this->assertEqual($result, $expected);
+
+ $TestModel->validate = array(
+ 'title' => array(
+ 'tooShort' => array(
+ 'rule' => array('minLength', 50),
+ 'last' => true
+ ),
+ 'onlyLetters' => array('rule' => '/^[a-z]+$/i')
+ ),
+ );
+ $data = array('TestValidate' => array(
+ 'title' => 'I am a short string'
+ ));
+ $TestModel->create($data);
+ $result = $TestModel->validates();
+ $this->assertFalse($result);
+ $result = $TestModel->validationErrors;
+ $expected = array(
+ 'title' => 'tooShort'
+ );
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * test that validates() checks all the 'with' associations as well for validation
+ * as this can cause partial/wrong data insertion.
+ *
+ * @return void
+ */
+ function testValidatesWithAssociations() {
+ $data = array(
+ 'Something' => array(
+ 'id' => 5,
+ 'title' => 'Extra Fields',
+ 'body' => 'Extra Fields Body',
+ 'published' => '1'
+ ),
+ 'SomethingElse' => array(
+ array('something_else_id' => 1, 'doomed' => '')
+ )
+ );
+
+ $Something =& new Something();
+ $JoinThing =& $Something->JoinThing;
+
+ $JoinThing->validate = array('doomed' => array('rule' => 'notEmpty'));
+
+ $expectedError = array('doomed' => 'This field cannot be left blank');
+
+ $Something->create();
+ $result = $Something->save($data);
+ $this->assertFalse($result, 'Save occured even when with models failed. %s');
+ $this->assertEqual($JoinThing->validationErrors, $expectedError);
+ $count = $Something->find('count', array('conditions' => array('Something.id' => $data['Something']['id'])));
+ $this->assertIdentical($count, 0);
+
+ $data = array(
+ 'Something' => array(
+ 'id' => 5,
+ 'title' => 'Extra Fields',
+ 'body' => 'Extra Fields Body',
+ 'published' => '1'
+ ),
+ 'SomethingElse' => array(
+ array('something_else_id' => 1, 'doomed' => 1),
+ array('something_else_id' => 1, 'doomed' => '')
+ )
+ );
+ $Something->create();
+ $result = $Something->save($data);
+ $this->assertFalse($result, 'Save occured even when with models failed. %s');
+
+ $joinRecords = $JoinThing->find('count', array(
+ 'conditions' => array('JoinThing.something_id' => $data['Something']['id'])
+ ));
+ $this->assertEqual($joinRecords, 0, 'Records were saved on the join table. %s');
+ }
+
+/**
+ * test that saveAll and with models with validation interact well
+ *
+ * @return void
+ */
+ function testValidatesWithModelsAndSaveAll() {
+ $data = array(
+ 'Something' => array(
+ 'id' => 5,
+ 'title' => 'Extra Fields',
+ 'body' => 'Extra Fields Body',
+ 'published' => '1'
+ ),
+ 'SomethingElse' => array(
+ array('something_else_id' => 1, 'doomed' => '')
+ )
+ );
+ $Something =& new Something();
+ $JoinThing =& $Something->JoinThing;
+
+ $JoinThing->validate = array('doomed' => array('rule' => 'notEmpty'));
+ $expectedError = array('doomed' => 'This field cannot be left blank');
+
+ $Something->create();
+ $result = $Something->saveAll($data, array('validate' => 'only'));
+ $this->assertFalse($result);
+ $this->assertEqual($JoinThing->validationErrors, $expectedError);
+
+ $Something->create();
+ $result = $Something->saveAll($data, array('validate' => 'first'));
+ $this->assertFalse($result);
+ $this->assertEqual($JoinThing->validationErrors, $expectedError);
+
+ $count = $Something->find('count', array('conditions' => array('Something.id' => $data['Something']['id'])));
+ $this->assertIdentical($count, 0);
+
+ $joinRecords = $JoinThing->find('count', array(
+ 'conditions' => array('JoinThing.something_id' => $data['Something']['id'])
+ ));
+ $this->assertEqual($joinRecords, 0, 'Records were saved on the join table. %s');
+ }
+
+/**
+ * Test that missing validation methods trigger errors in development mode.
+ * Helps to make developement easier.
+ *
+ * @return void
+ */
+ function testMissingValidationErrorTriggering() {
+ $restore = Configure::read('debug');
+ Configure::write('debug', 2);
+
+ $TestModel =& new ValidationTest1();
+ $TestModel->create(array('title' => 'foo'));
+ $TestModel->validate = array(
+ 'title' => array(
+ 'rule' => array('thisOneBringsThePain'),
+ 'required' => true
+ )
+ );
+ $this->expectError(new PatternExpectation('/thisOneBringsThePain for title/i'));
+ $TestModel->invalidFields(array('fieldList' => array('title')));
+
+ Configure::write('debug', 0);
+ $this->assertNoErrors();
+ $TestModel->invalidFields(array('fieldList' => array('title')));
+ Configure::write('debug', $restore);
+ }
+
+}
diff --git a/code/ryzom/tools/server/www/webtt/cake/tests/cases/libs/model/model_write.test.php b/code/ryzom/tools/server/www/webtt/cake/tests/cases/libs/model/model_write.test.php
new file mode 100644
index 000000000..d88bffeaa
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/cake/tests/cases/libs/model/model_write.test.php
@@ -0,0 +1,4048 @@
+
+ * Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
+ *
+ * Licensed under The Open Group Test Suite License
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
+ * @link http://book.cakephp.org/view/1196/Testing CakePHP(tm) Tests
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ * @since CakePHP(tm) v 1.2.0.4206
+ * @license http://www.opensource.org/licenses/opengroup.php The Open Group Test Suite License
+ */
+require_once dirname(__FILE__) . DS . 'model.test.php';
+/**
+ * ModelWriteTest
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model.operations
+ */
+class ModelWriteTest extends BaseModelTest {
+
+/**
+ * testInsertAnotherHabtmRecordWithSameForeignKey method
+ *
+ * @access public
+ * @return void
+ */
+ function testInsertAnotherHabtmRecordWithSameForeignKey() {
+ $this->loadFixtures('JoinA', 'JoinB', 'JoinAB');
+ $TestModel = new JoinA();
+
+ $result = $TestModel->JoinAsJoinB->findById(1);
+ $expected = array(
+ 'JoinAsJoinB' => array(
+ 'id' => 1,
+ 'join_a_id' => 1,
+ 'join_b_id' => 2,
+ 'other' => 'Data for Join A 1 Join B 2',
+ 'created' => '2008-01-03 10:56:33',
+ 'updated' => '2008-01-03 10:56:33'
+ ));
+ $this->assertEqual($result, $expected);
+
+ $TestModel->JoinAsJoinB->create();
+ $result = $TestModel->JoinAsJoinB->save(array(
+ 'join_a_id' => 1,
+ 'join_b_id' => 1,
+ 'other' => 'Data for Join A 1 Join B 1',
+ 'created' => '2008-01-03 10:56:44',
+ 'updated' => '2008-01-03 10:56:44'
+ ));
+ $this->assertTrue($result);
+ $lastInsertId = $TestModel->JoinAsJoinB->getLastInsertID();
+ $this->assertTrue($lastInsertId != null);
+
+ $result = $TestModel->JoinAsJoinB->findById(1);
+ $expected = array(
+ 'JoinAsJoinB' => array(
+ 'id' => 1,
+ 'join_a_id' => 1,
+ 'join_b_id' => 2,
+ 'other' => 'Data for Join A 1 Join B 2',
+ 'created' => '2008-01-03 10:56:33',
+ 'updated' => '2008-01-03 10:56:33'
+ ));
+ $this->assertEqual($result, $expected);
+
+ $updatedValue = 'UPDATED Data for Join A 1 Join B 2';
+ $TestModel->JoinAsJoinB->id = 1;
+ $result = $TestModel->JoinAsJoinB->saveField('other', $updatedValue, false);
+ $this->assertTrue($result);
+
+ $result = $TestModel->JoinAsJoinB->findById(1);
+ $this->assertEqual($result['JoinAsJoinB']['other'], $updatedValue);
+ }
+
+/**
+ * testSaveDateAsFirstEntry method
+ *
+ * @access public
+ * @return void
+ */
+ function testSaveDateAsFirstEntry() {
+ $this->loadFixtures('Article');
+
+ $Article =& new Article();
+
+ $data = array(
+ 'Article' => array(
+ 'created' => array(
+ 'day' => '1',
+ 'month' => '1',
+ 'year' => '2008'
+ ),
+ 'title' => 'Test Title',
+ 'user_id' => 1
+ ));
+ $Article->create();
+ $this->assertTrue($Article->save($data));
+
+ $testResult = $Article->find(array('Article.title' => 'Test Title'));
+
+ $this->assertEqual($testResult['Article']['title'], $data['Article']['title']);
+ $this->assertEqual($testResult['Article']['created'], '2008-01-01 00:00:00');
+
+ }
+
+/**
+ * testUnderscoreFieldSave method
+ *
+ * @access public
+ * @return void
+ */
+ function testUnderscoreFieldSave() {
+ $this->loadFixtures('UnderscoreField');
+ $UnderscoreField =& new UnderscoreField();
+
+ $currentCount = $UnderscoreField->find('count');
+ $this->assertEqual($currentCount, 3);
+ $data = array('UnderscoreField' => array(
+ 'user_id' => '1',
+ 'my_model_has_a_field' => 'Content here',
+ 'body' => 'Body',
+ 'published' => 'Y',
+ 'another_field' => 4
+ ));
+ $ret = $UnderscoreField->save($data);
+ $this->assertTrue($ret);
+
+ $currentCount = $UnderscoreField->find('count');
+ $this->assertEqual($currentCount, 4);
+ }
+
+/**
+ * testAutoSaveUuid method
+ *
+ * @access public
+ * @return void
+ */
+ function testAutoSaveUuid() {
+ // SQLite does not support non-integer primary keys
+ $this->skipIf($this->db->config['driver'] == 'sqlite');
+
+ $this->loadFixtures('Uuid');
+ $TestModel =& new Uuid();
+
+ $TestModel->save(array('title' => 'Test record'));
+ $result = $TestModel->findByTitle('Test record');
+ $this->assertEqual(
+ array_keys($result['Uuid']),
+ array('id', 'title', 'count', 'created', 'updated')
+ );
+ $this->assertEqual(strlen($result['Uuid']['id']), 36);
+ }
+
+/**
+ * Ensure that if the id key is null but present the save doesn't fail (with an
+ * x sql error: "Column id specified twice")
+ *
+ * @return void
+ * @access public
+ */
+ function testSaveUuidNull() {
+ // SQLite does not support non-integer primary keys
+ $this->skipIf($this->db->config['driver'] == 'sqlite');
+
+ $this->loadFixtures('Uuid');
+ $TestModel =& new Uuid();
+
+ $TestModel->save(array('title' => 'Test record', 'id' => null));
+ $result = $TestModel->findByTitle('Test record');
+ $this->assertEqual(
+ array_keys($result['Uuid']),
+ array('id', 'title', 'count', 'created', 'updated')
+ );
+ $this->assertEqual(strlen($result['Uuid']['id']), 36);
+ }
+
+/**
+ * testZeroDefaultFieldValue method
+ *
+ * @access public
+ * @return void
+ */
+ function testZeroDefaultFieldValue() {
+ $this->skipIf(
+ $this->db->config['driver'] == 'sqlite',
+ '%s SQLite uses loose typing, this operation is unsupported'
+ );
+ $this->loadFixtures('DataTest');
+ $TestModel =& new DataTest();
+
+ $TestModel->create(array());
+ $TestModel->save();
+ $result = $TestModel->findById($TestModel->id);
+ $this->assertIdentical($result['DataTest']['count'], '0');
+ $this->assertIdentical($result['DataTest']['float'], '0');
+ }
+
+/**
+ * testNonNumericHabtmJoinKey method
+ *
+ * @access public
+ * @return void
+ */
+ function testNonNumericHabtmJoinKey() {
+ $this->loadFixtures('Post', 'Tag', 'PostsTag');
+ $Post =& new Post();
+ $Post->bindModel(array(
+ 'hasAndBelongsToMany' => array('Tag')
+ ));
+ $Post->Tag->primaryKey = 'tag';
+
+ $result = $Post->find('all');
+ $expected = array(
+ array(
+ 'Post' => array(
+ 'id' => '1',
+ 'author_id' => '1',
+ 'title' => 'First Post',
+ 'body' => 'First Post Body',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:39:23',
+ 'updated' => '2007-03-18 10:41:31'
+ ),
+ 'Author' => array(
+ 'id' => null,
+ 'user' => null,
+ 'password' => null,
+ 'created' => null,
+ 'updated' => null,
+ 'test' => 'working'
+ ),
+ 'Tag' => array(
+ array(
+ 'id' => '1',
+ 'tag' => 'tag1',
+ 'created' => '2007-03-18 12:22:23',
+ 'updated' => '2007-03-18 12:24:31'
+ ),
+ array(
+ 'id' => '2',
+ 'tag' => 'tag2',
+ 'created' => '2007-03-18 12:24:23',
+ 'updated' => '2007-03-18 12:26:31'
+ ))),
+ array(
+ 'Post' => array(
+ 'id' => '2',
+ 'author_id' => '3',
+ 'title' => 'Second Post',
+ 'body' => 'Second Post Body',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:41:23',
+ 'updated' => '2007-03-18 10:43:31'
+ ),
+ 'Author' => array(
+ 'id' => null,
+ 'user' => null,
+ 'password' => null,
+ 'created' => null,
+ 'updated' => null,
+ 'test' => 'working'
+ ),
+ 'Tag' => array(
+ array(
+ 'id' => '1',
+ 'tag' => 'tag1',
+ 'created' => '2007-03-18 12:22:23',
+ 'updated' => '2007-03-18 12:24:31'
+ ),
+ array(
+ 'id' => '3',
+ 'tag' => 'tag3',
+ 'created' => '2007-03-18 12:26:23',
+ 'updated' => '2007-03-18 12:28:31'
+ ))),
+ array(
+ 'Post' => array(
+ 'id' => '3',
+ 'author_id' => '1',
+ 'title' => 'Third Post',
+ 'body' => 'Third Post Body',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:43:23',
+ 'updated' => '2007-03-18 10:45:31'
+ ),
+ 'Author' => array(
+ 'id' => null,
+ 'user' => null,
+ 'password' => null,
+ 'created' => null,
+ 'updated' => null,
+ 'test' => 'working'
+ ),
+ 'Tag' => array()
+ ));
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * Tests validation parameter order in custom validation methods
+ *
+ * @access public
+ * @return void
+ */
+ function testAllowSimulatedFields() {
+ $TestModel =& new ValidationTest1();
+
+ $TestModel->create(array(
+ 'title' => 'foo',
+ 'bar' => 'baz'
+ ));
+ $expected = array(
+ 'ValidationTest1' => array(
+ 'title' => 'foo',
+ 'bar' => 'baz'
+ ));
+ $this->assertEqual($TestModel->data, $expected);
+ }
+
+/**
+ * test that Caches are getting cleared on save().
+ * ensure that both inflections of controller names are getting cleared
+ * as url for controller could be either overallFavorites/index or overall_favorites/index
+ *
+ * @return void
+ */
+ function testCacheClearOnSave() {
+ $_back = array(
+ 'check' => Configure::read('Cache.check'),
+ 'disable' => Configure::read('Cache.disable'),
+ );
+ Configure::write('Cache.check', true);
+ Configure::write('Cache.disable', false);
+
+ $this->loadFixtures('OverallFavorite');
+ $OverallFavorite =& new OverallFavorite();
+
+ touch(CACHE . 'views' . DS . 'some_dir_overallfavorites_index.php');
+ touch(CACHE . 'views' . DS . 'some_dir_overall_favorites_index.php');
+
+ $data = array(
+ 'OverallFavorite' => array(
+ 'id' => 22,
+ 'model_type' => '8-track',
+ 'model_id' => '3',
+ 'priority' => '1'
+ )
+ );
+ $OverallFavorite->create($data);
+ $OverallFavorite->save();
+
+ $this->assertFalse(file_exists(CACHE . 'views' . DS . 'some_dir_overallfavorites_index.php'));
+ $this->assertFalse(file_exists(CACHE . 'views' . DS . 'some_dir_overall_favorites_index.php'));
+
+ Configure::write('Cache.check', $_back['check']);
+ Configure::write('Cache.disable', $_back['disable']);
+ }
+
+/**
+ * testSaveWithCounterCache method
+ *
+ * @access public
+ * @return void
+ */
+ function testSaveWithCounterCache() {
+ $this->loadFixtures('Syfile', 'Item');
+ $TestModel =& new Syfile();
+ $TestModel2 =& new Item();
+
+ $result = $TestModel->findById(1);
+ $this->assertIdentical($result['Syfile']['item_count'], null);
+
+ $TestModel2->save(array(
+ 'name' => 'Item 7',
+ 'syfile_id' => 1,
+ 'published' => false
+ ));
+
+ $result = $TestModel->findById(1);
+ $this->assertIdentical($result['Syfile']['item_count'], '2');
+
+ $TestModel2->delete(1);
+ $result = $TestModel->findById(1);
+ $this->assertIdentical($result['Syfile']['item_count'], '1');
+
+ $TestModel2->id = 2;
+ $TestModel2->saveField('syfile_id', 1);
+
+ $result = $TestModel->findById(1);
+ $this->assertIdentical($result['Syfile']['item_count'], '2');
+
+ $result = $TestModel->findById(2);
+ $this->assertIdentical($result['Syfile']['item_count'], '0');
+ }
+
+/**
+ * Tests that counter caches are updated when records are added
+ *
+ * @access public
+ * @return void
+ */
+ function testCounterCacheIncrease() {
+ $this->loadFixtures('CounterCacheUser', 'CounterCachePost');
+ $User = new CounterCacheUser();
+ $Post = new CounterCachePost();
+ $data = array('Post' => array(
+ 'id' => 22,
+ 'title' => 'New Post',
+ 'user_id' => 66
+ ));
+
+ $Post->save($data);
+ $user = $User->find('first', array(
+ 'conditions' => array('id' => 66),
+ 'recursive' => -1
+ ));
+
+ $result = $user[$User->alias]['post_count'];
+ $expected = 3;
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * Tests that counter caches are updated when records are deleted
+ *
+ * @access public
+ * @return void
+ */
+ function testCounterCacheDecrease() {
+ $this->loadFixtures('CounterCacheUser', 'CounterCachePost');
+ $User = new CounterCacheUser();
+ $Post = new CounterCachePost();
+
+ $Post->delete(2);
+ $user = $User->find('first', array(
+ 'conditions' => array('id' => 66),
+ 'recursive' => -1
+ ));
+
+ $result = $user[$User->alias]['post_count'];
+ $expected = 1;
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * Tests that counter caches are updated when foreign keys of counted records change
+ *
+ * @access public
+ * @return void
+ */
+ function testCounterCacheUpdated() {
+ $this->loadFixtures('CounterCacheUser', 'CounterCachePost');
+ $User = new CounterCacheUser();
+ $Post = new CounterCachePost();
+
+ $data = $Post->find('first', array(
+ 'conditions' => array('id' => 1),
+ 'recursive' => -1
+ ));
+ $data[$Post->alias]['user_id'] = 301;
+ $Post->save($data);
+
+ $users = $User->find('all',array('order' => 'User.id'));
+ $this->assertEqual($users[0]['User']['post_count'], 1);
+ $this->assertEqual($users[1]['User']['post_count'], 2);
+ }
+
+/**
+ * Test counter cache with models that use a non-standard (i.e. not using 'id')
+ * as their primary key.
+ *
+ * @access public
+ * @return void
+ */
+ function testCounterCacheWithNonstandardPrimaryKey() {
+ $this->loadFixtures(
+ 'CounterCacheUserNonstandardPrimaryKey',
+ 'CounterCachePostNonstandardPrimaryKey'
+ );
+
+ $User = new CounterCacheUserNonstandardPrimaryKey();
+ $Post = new CounterCachePostNonstandardPrimaryKey();
+
+ $data = $Post->find('first', array(
+ 'conditions' => array('pid' => 1),
+ 'recursive' => -1
+ ));
+ $data[$Post->alias]['uid'] = 301;
+ $Post->save($data);
+
+ $users = $User->find('all',array('order' => 'User.uid'));
+ $this->assertEqual($users[0]['User']['post_count'], 1);
+ $this->assertEqual($users[1]['User']['post_count'], 2);
+ }
+
+/**
+ * test Counter Cache With Self Joining table
+ *
+ * @return void
+ * @access public
+ */
+ function testCounterCacheWithSelfJoin() {
+ $skip = $this->skipIf(
+ ($this->db->config['driver'] == 'sqlite'),
+ 'SQLite 2.x does not support ALTER TABLE ADD COLUMN'
+ );
+ if ($skip) {
+ return;
+ }
+
+ $this->loadFixtures('CategoryThread');
+ $this->db->query('ALTER TABLE '. $this->db->fullTableName('category_threads') . " ADD COLUMN child_count INTEGER");
+ $Category =& new CategoryThread();
+ $result = $Category->updateAll(array('CategoryThread.name' => "'updated'"), array('CategoryThread.parent_id' => 5));
+ $this->assertTrue($result);
+
+ $Category =& new CategoryThread();
+ $Category->belongsTo['ParentCategory']['counterCache'] = 'child_count';
+ $Category->updateCounterCache(array('parent_id' => 5));
+ $result = Set::extract($Category->find('all', array('conditions' => array('CategoryThread.id' => 5))), '{n}.CategoryThread.child_count');
+ $expected = array_fill(0, 1, 1);
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testSaveWithCounterCacheScope method
+ *
+ * @access public
+ * @return void
+ */
+ function testSaveWithCounterCacheScope() {
+ $this->loadFixtures('Syfile', 'Item');
+ $TestModel =& new Syfile();
+ $TestModel2 =& new Item();
+ $TestModel2->belongsTo['Syfile']['counterCache'] = true;
+ $TestModel2->belongsTo['Syfile']['counterScope'] = array('published' => true);
+
+ $result = $TestModel->findById(1);
+ $this->assertIdentical($result['Syfile']['item_count'], null);
+
+ $TestModel2->save(array(
+ 'name' => 'Item 7',
+ 'syfile_id' => 1,
+ 'published'=> true
+ ));
+
+ $result = $TestModel->findById(1);
+ $this->assertIdentical($result['Syfile']['item_count'], '1');
+
+ $TestModel2->id = 1;
+ $TestModel2->saveField('published', true);
+ $result = $TestModel->findById(1);
+ $this->assertIdentical($result['Syfile']['item_count'], '2');
+
+ $TestModel2->save(array(
+ 'id' => 1,
+ 'syfile_id' => 1,
+ 'published'=> false
+ ));
+
+ $result = $TestModel->findById(1);
+ $this->assertIdentical($result['Syfile']['item_count'], '1');
+ }
+
+/**
+ * test that beforeValidate returning false can abort saves.
+ *
+ * @return void
+ */
+ function testBeforeValidateSaveAbortion() {
+ $Model =& new CallbackPostTestModel();
+ $Model->beforeValidateReturn = false;
+
+ $data = array(
+ 'title' => 'new article',
+ 'body' => 'this is some text.'
+ );
+ $Model->create();
+ $result = $Model->save($data);
+ $this->assertFalse($result);
+ }
+/**
+ * test that beforeSave returning false can abort saves.
+ *
+ * @return void
+ */
+ function testBeforeSaveSaveAbortion() {
+ $Model =& new CallbackPostTestModel();
+ $Model->beforeSaveReturn = false;
+
+ $data = array(
+ 'title' => 'new article',
+ 'body' => 'this is some text.'
+ );
+ $Model->create();
+ $result = $Model->save($data);
+ $this->assertFalse($result);
+ }
+
+/**
+ * testSaveField method
+ *
+ * @access public
+ * @return void
+ */
+ function testSaveField() {
+ $this->loadFixtures('Article');
+ $TestModel =& new Article();
+
+ $TestModel->id = 1;
+ $result = $TestModel->saveField('title', 'New First Article');
+ $this->assertTrue($result);
+
+ $TestModel->recursive = -1;
+ $result = $TestModel->read(array('id', 'user_id', 'title', 'body'), 1);
+ $expected = array('Article' => array(
+ 'id' => '1',
+ 'user_id' => '1',
+ 'title' => 'New First Article',
+ 'body' => 'First Article Body'
+ ));
+ $this->assertEqual($result, $expected);
+
+ $TestModel->id = 1;
+ $result = $TestModel->saveField('title', '');
+ $this->assertTrue($result);
+
+ $TestModel->recursive = -1;
+ $result = $TestModel->read(array('id', 'user_id', 'title', 'body'), 1);
+ $expected = array('Article' => array(
+ 'id' => '1',
+ 'user_id' => '1',
+ 'title' => '',
+ 'body' => 'First Article Body'
+ ));
+ $result['Article']['title'] = trim($result['Article']['title']);
+ $this->assertEqual($result, $expected);
+
+ $TestModel->id = 1;
+ $TestModel->set('body', 'Messed up data');
+ $this->assertTrue($TestModel->saveField('title', 'First Article'));
+ $result = $TestModel->read(array('id', 'user_id', 'title', 'body'), 1);
+ $expected = array('Article' => array(
+ 'id' => '1',
+ 'user_id' => '1',
+ 'title' => 'First Article',
+ 'body' => 'First Article Body'
+ ));
+ $this->assertEqual($result, $expected);
+
+ $TestModel->recursive = -1;
+ $result = $TestModel->read(array('id', 'user_id', 'title', 'body'), 1);
+
+ $TestModel->id = 1;
+ $result = $TestModel->saveField('title', '', true);
+ $this->assertFalse($result);
+
+ $this->loadFixtures('Node', 'Dependency');
+ $Node =& new Node();
+ $Node->set('id', 1);
+ $result = $Node->read();
+ $this->assertEqual(Set::extract('/ParentNode/name', $result), array('Second'));
+
+ $Node->saveField('state', 10);
+ $result = $Node->read();
+ $this->assertEqual(Set::extract('/ParentNode/name', $result), array('Second'));
+ }
+
+/**
+ * testSaveWithCreate method
+ *
+ * @access public
+ * @return void
+ */
+ function testSaveWithCreate() {
+ $this->loadFixtures(
+ 'User',
+ 'Article',
+ 'User',
+ 'Comment',
+ 'Tag',
+ 'ArticlesTag',
+ 'Attachment'
+ );
+ $TestModel =& new User();
+
+ $data = array('User' => array(
+ 'user' => 'user',
+ 'password' => ''
+ ));
+ $result = $TestModel->save($data);
+ $this->assertFalse($result);
+ $this->assertTrue(!empty($TestModel->validationErrors));
+
+ $TestModel =& new Article();
+
+ $data = array('Article' => array(
+ 'user_id' => '',
+ 'title' => '',
+ 'body' => ''
+ ));
+ $result = $TestModel->create($data) && $TestModel->save();
+ $this->assertFalse($result);
+ $this->assertTrue(!empty($TestModel->validationErrors));
+
+ $data = array('Article' => array(
+ 'id' => 1,
+ 'user_id' => '1',
+ 'title' => 'New First Article',
+ 'body' => ''
+ ));
+ $result = $TestModel->create($data) && $TestModel->save();
+ $this->assertFalse($result);
+
+ $data = array('Article' => array(
+ 'id' => 1,
+ 'title' => 'New First Article'
+ ));
+ $result = $TestModel->create() && $TestModel->save($data, false);
+ $this->assertTrue($result);
+
+ $TestModel->recursive = -1;
+ $result = $TestModel->read(array('id', 'user_id', 'title', 'body', 'published'), 1);
+ $expected = array('Article' => array(
+ 'id' => '1',
+ 'user_id' => '1',
+ 'title' => 'New First Article',
+ 'body' => 'First Article Body',
+ 'published' => 'N'
+ ));
+ $this->assertEqual($result, $expected);
+
+ $data = array('Article' => array(
+ 'id' => 1,
+ 'user_id' => '2',
+ 'title' => 'First Article',
+ 'body' => 'New First Article Body',
+ 'published' => 'Y'
+ ));
+ $result = $TestModel->create() && $TestModel->save($data, true, array('id', 'title', 'published'));
+ $this->assertTrue($result);
+
+ $TestModel->recursive = -1;
+ $result = $TestModel->read(array('id', 'user_id', 'title', 'body', 'published'), 1);
+ $expected = array('Article' => array(
+ 'id' => '1',
+ 'user_id' => '1',
+ 'title' => 'First Article',
+ 'body' => 'First Article Body',
+ 'published' => 'Y'
+ ));
+ $this->assertEqual($result, $expected);
+
+ $data = array(
+ 'Article' => array(
+ 'user_id' => '2',
+ 'title' => 'New Article',
+ 'body' => 'New Article Body',
+ 'created' => '2007-03-18 14:55:23',
+ 'updated' => '2007-03-18 14:57:31'
+ ),
+ 'Tag' => array('Tag' => array(1, 3))
+ );
+ $TestModel->create();
+ $result = $TestModel->create() && $TestModel->save($data);
+ $this->assertTrue($result);
+
+ $TestModel->recursive = 2;
+ $result = $TestModel->read(null, 4);
+ $expected = array(
+ 'Article' => array(
+ 'id' => '4',
+ 'user_id' => '2',
+ 'title' => 'New Article',
+ 'body' => 'New Article Body',
+ 'published' => 'N',
+ 'created' => '2007-03-18 14:55:23',
+ 'updated' => '2007-03-18 14:57:31'
+ ),
+ 'User' => array(
+ 'id' => '2',
+ 'user' => 'nate',
+ 'password' => '5f4dcc3b5aa765d61d8327deb882cf99',
+ 'created' => '2007-03-17 01:18:23',
+ 'updated' => '2007-03-17 01:20:31'
+ ),
+ 'Comment' => array(),
+ 'Tag' => array(
+ array(
+ 'id' => '1',
+ 'tag' => 'tag1',
+ 'created' => '2007-03-18 12:22:23',
+ 'updated' => '2007-03-18 12:24:31'
+ ),
+ array(
+ 'id' => '3',
+ 'tag' => 'tag3',
+ 'created' => '2007-03-18 12:26:23',
+ 'updated' => '2007-03-18 12:28:31'
+ )));
+ $this->assertEqual($result, $expected);
+
+ $data = array('Comment' => array(
+ 'article_id' => '4',
+ 'user_id' => '1',
+ 'comment' => 'Comment New Article',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 14:57:23',
+ 'updated' => '2007-03-18 14:59:31'
+ ));
+ $result = $TestModel->Comment->create() && $TestModel->Comment->save($data);
+ $this->assertTrue($result);
+
+ $data = array('Attachment' => array(
+ 'comment_id' => '7',
+ 'attachment' => 'newattachment.zip',
+ 'created' => '2007-03-18 15:02:23',
+ 'updated' => '2007-03-18 15:04:31'
+ ));
+ $result = $TestModel->Comment->Attachment->save($data);
+ $this->assertTrue($result);
+
+ $TestModel->recursive = 2;
+ $result = $TestModel->read(null, 4);
+ $expected = array(
+ 'Article' => array(
+ 'id' => '4',
+ 'user_id' => '2',
+ 'title' => 'New Article',
+ 'body' => 'New Article Body',
+ 'published' => 'N',
+ 'created' => '2007-03-18 14:55:23',
+ 'updated' => '2007-03-18 14:57:31'
+ ),
+ 'User' => array(
+ 'id' => '2',
+ 'user' => 'nate',
+ 'password' => '5f4dcc3b5aa765d61d8327deb882cf99',
+ 'created' => '2007-03-17 01:18:23',
+ 'updated' => '2007-03-17 01:20:31'
+ ),
+ 'Comment' => array(
+ array(
+ 'id' => '7',
+ 'article_id' => '4',
+ 'user_id' => '1',
+ 'comment' => 'Comment New Article',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 14:57:23',
+ 'updated' => '2007-03-18 14:59:31',
+ 'Article' => array(
+ 'id' => '4',
+ 'user_id' => '2',
+ 'title' => 'New Article',
+ 'body' => 'New Article Body',
+ 'published' => 'N',
+ 'created' => '2007-03-18 14:55:23',
+ 'updated' => '2007-03-18 14:57:31'
+ ),
+ 'User' => array(
+ 'id' => '1',
+ 'user' => 'mariano',
+ 'password' => '5f4dcc3b5aa765d61d8327deb882cf99',
+ 'created' => '2007-03-17 01:16:23',
+ 'updated' => '2007-03-17 01:18:31'
+ ),
+ 'Attachment' => array(
+ 'id' => '2',
+ 'comment_id' => '7',
+ 'attachment' => 'newattachment.zip',
+ 'created' => '2007-03-18 15:02:23',
+ 'updated' => '2007-03-18 15:04:31'
+ ))),
+ 'Tag' => array(
+ array(
+ 'id' => '1',
+ 'tag' => 'tag1',
+ 'created' => '2007-03-18 12:22:23',
+ 'updated' => '2007-03-18 12:24:31'
+ ),
+ array(
+ 'id' => '3',
+ 'tag' => 'tag3',
+ 'created' => '2007-03-18 12:26:23',
+ 'updated' => '2007-03-18 12:28:31'
+ )));
+
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * test that a null Id doesn't cause errors
+ *
+ * @return void
+ */
+ function testSaveWithNullId() {
+ $this->loadFixtures('User');
+ $User =& new User();
+ $User->read(null, 1);
+ $User->data['User']['id'] = null;
+ $this->assertTrue($User->save(array('password' => 'test')));
+ $this->assertTrue($User->id > 0);
+
+ $result = $User->read(null, 2);
+ $User->data['User']['id'] = null;
+ $this->assertTrue($User->save(array('password' => 'test')));
+ $this->assertTrue($User->id > 0);
+
+ $User->data['User'] = array('password' => 'something');
+ $this->assertTrue($User->save());
+ $result = $User->read();
+ $this->assertEqual($User->data['User']['password'], 'something');
+ }
+
+/**
+ * testSaveWithSet method
+ *
+ * @access public
+ * @return void
+ */
+ function testSaveWithSet() {
+ $this->loadFixtures('Article');
+ $TestModel =& new Article();
+
+ // Create record we will be updating later
+
+ $data = array('Article' => array(
+ 'user_id' => '1',
+ 'title' => 'Fourth Article',
+ 'body' => 'Fourth Article Body',
+ 'published' => 'Y'
+ ));
+ $result = $TestModel->create() && $TestModel->save($data);
+ $this->assertTrue($result);
+
+ // Check record we created
+
+ $TestModel->recursive = -1;
+ $result = $TestModel->read(array('id', 'user_id', 'title', 'body', 'published'), 4);
+ $expected = array('Article' => array(
+ 'id' => '4',
+ 'user_id' => '1',
+ 'title' => 'Fourth Article',
+ 'body' => 'Fourth Article Body',
+ 'published' => 'Y'
+ ));
+ $this->assertEqual($result, $expected);
+
+ // Create new record just to overlap Model->id on previously created record
+
+ $data = array('Article' => array(
+ 'user_id' => '4',
+ 'title' => 'Fifth Article',
+ 'body' => 'Fifth Article Body',
+ 'published' => 'Y'
+ ));
+ $result = $TestModel->create() && $TestModel->save($data);
+ $this->assertTrue($result);
+
+ $TestModel->recursive = -1;
+ $result = $TestModel->read(array('id', 'user_id', 'title', 'body', 'published'), 5);
+ $expected = array('Article' => array(
+ 'id' => '5',
+ 'user_id' => '4',
+ 'title' => 'Fifth Article',
+ 'body' => 'Fifth Article Body',
+ 'published' => 'Y'
+ ));
+ $this->assertEqual($result, $expected);
+
+ // Go back and edit the first article we created, starting by checking it's still there
+
+ $TestModel->recursive = -1;
+ $result = $TestModel->read(array('id', 'user_id', 'title', 'body', 'published'), 4);
+ $expected = array('Article' => array(
+ 'id' => '4',
+ 'user_id' => '1',
+ 'title' => 'Fourth Article',
+ 'body' => 'Fourth Article Body',
+ 'published' => 'Y'
+ ));
+ $this->assertEqual($result, $expected);
+
+ // And now do the update with set()
+
+ $data = array('Article' => array(
+ 'id' => '4',
+ 'title' => 'Fourth Article - New Title',
+ 'published' => 'N'
+ ));
+ $result = $TestModel->set($data) && $TestModel->save();
+ $this->assertTrue($result);
+
+ $TestModel->recursive = -1;
+ $result = $TestModel->read(array('id', 'user_id', 'title', 'body', 'published'), 4);
+ $expected = array('Article' => array(
+ 'id' => '4',
+ 'user_id' => '1',
+ 'title' => 'Fourth Article - New Title',
+ 'body' => 'Fourth Article Body',
+ 'published' => 'N'
+ ));
+ $this->assertEqual($result, $expected);
+
+ $TestModel->recursive = -1;
+ $result = $TestModel->read(array('id', 'user_id', 'title', 'body', 'published'), 5);
+ $expected = array('Article' => array(
+ 'id' => '5',
+ 'user_id' => '4',
+ 'title' => 'Fifth Article',
+ 'body' => 'Fifth Article Body',
+ 'published' => 'Y'
+ ));
+ $this->assertEqual($result, $expected);
+
+ $data = array('Article' => array('id' => '5', 'title' => 'Fifth Article - New Title 5'));
+ $result = ($TestModel->set($data) && $TestModel->save());
+ $this->assertTrue($result);
+
+ $TestModel->recursive = -1;
+ $result = $TestModel->read(array('id', 'user_id', 'title', 'body', 'published'), 5);
+ $expected = array('Article' => array(
+ 'id' => '5',
+ 'user_id' => '4',
+ 'title' => 'Fifth Article - New Title 5',
+ 'body' => 'Fifth Article Body',
+ 'published' => 'Y'
+ ));
+ $this->assertEqual($result, $expected);
+
+ $TestModel->recursive = -1;
+ $result = $TestModel->find('all', array('fields' => array('id', 'title')));
+ $expected = array(
+ array('Article' => array('id' => 1, 'title' => 'First Article' )),
+ array('Article' => array('id' => 2, 'title' => 'Second Article' )),
+ array('Article' => array('id' => 3, 'title' => 'Third Article' )),
+ array('Article' => array('id' => 4, 'title' => 'Fourth Article - New Title' )),
+ array('Article' => array('id' => 5, 'title' => 'Fifth Article - New Title 5' ))
+ );
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testSaveWithNonExistentFields method
+ *
+ * @access public
+ * @return void
+ */
+ function testSaveWithNonExistentFields() {
+ $this->loadFixtures('Article');
+ $TestModel =& new Article();
+ $TestModel->recursive = -1;
+
+ $data = array(
+ 'non_existent' => 'This field does not exist',
+ 'user_id' => '1',
+ 'title' => 'Fourth Article - New Title',
+ 'body' => 'Fourth Article Body',
+ 'published' => 'N'
+ );
+ $result = $TestModel->create() && $TestModel->save($data);
+ $this->assertTrue($result);
+
+ $expected = array('Article' => array(
+ 'id' => '4',
+ 'user_id' => '1',
+ 'title' => 'Fourth Article - New Title',
+ 'body' => 'Fourth Article Body',
+ 'published' => 'N'
+ ));
+ $result = $TestModel->read(array('id', 'user_id', 'title', 'body', 'published'), 4);
+ $this->assertEqual($result, $expected);
+
+ $data = array(
+ 'user_id' => '1',
+ 'non_existent' => 'This field does not exist',
+ 'title' => 'Fiveth Article - New Title',
+ 'body' => 'Fiveth Article Body',
+ 'published' => 'N'
+ );
+ $result = $TestModel->create() && $TestModel->save($data);
+ $this->assertTrue($result);
+
+ $expected = array('Article' => array(
+ 'id' => '5',
+ 'user_id' => '1',
+ 'title' => 'Fiveth Article - New Title',
+ 'body' => 'Fiveth Article Body',
+ 'published' => 'N'
+ ));
+ $result = $TestModel->read(array('id', 'user_id', 'title', 'body', 'published'), 5);
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testSaveFromXml method
+ *
+ * @access public
+ * @return void
+ */
+ function testSaveFromXml() {
+ $this->loadFixtures('Article');
+ App::import('Core', 'Xml');
+
+ $Article = new Article();
+ $Article->save(new Xml(' '));
+ $this->assertTrue($Article->save(new Xml(' ')));
+
+ $results = $Article->find(array('Article.title' => 'test xml'));
+ $this->assertTrue($results);
+ }
+
+/**
+ * testSaveHabtm method
+ *
+ * @access public
+ * @return void
+ */
+ function testSaveHabtm() {
+ $this->loadFixtures('Article', 'User', 'Comment', 'Tag', 'ArticlesTag');
+ $TestModel =& new Article();
+
+ $result = $TestModel->findById(2);
+ $expected = array(
+ 'Article' => array(
+ 'id' => '2',
+ 'user_id' => '3',
+ 'title' => 'Second Article',
+ 'body' => 'Second Article Body',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:41:23',
+ 'updated' => '2007-03-18 10:43:31'
+ ),
+ 'User' => array(
+ 'id' => '3',
+ 'user' => 'larry',
+ 'password' => '5f4dcc3b5aa765d61d8327deb882cf99',
+ 'created' => '2007-03-17 01:20:23',
+ 'updated' => '2007-03-17 01:22:31'
+ ),
+ 'Comment' => array(
+ array(
+ 'id' => '5',
+ 'article_id' => '2',
+ 'user_id' => '1',
+ 'comment' => 'First Comment for Second Article',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:53:23',
+ 'updated' => '2007-03-18 10:55:31'
+ ),
+ array(
+ 'id' => '6',
+ 'article_id' => '2',
+ 'user_id' => '2',
+ 'comment' => 'Second Comment for Second Article',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:55:23',
+ 'updated' => '2007-03-18 10:57:31'
+ )),
+ 'Tag' => array(
+ array(
+ 'id' => '1',
+ 'tag' => 'tag1',
+ 'created' => '2007-03-18 12:22:23',
+ 'updated' => '2007-03-18 12:24:31'
+ ),
+ array(
+ 'id' => '3',
+ 'tag' => 'tag3',
+ 'created' => '2007-03-18 12:26:23',
+ 'updated' => '2007-03-18 12:28:31'
+ )
+ )
+ );
+ $this->assertEqual($result, $expected);
+
+ $data = array(
+ 'Article' => array(
+ 'id' => '2',
+ 'title' => 'New Second Article'
+ ),
+ 'Tag' => array('Tag' => array(1, 2))
+ );
+
+ $this->assertTrue($TestModel->set($data));
+ $this->assertTrue($TestModel->save());
+
+ $TestModel->unbindModel(array('belongsTo' => array('User'), 'hasMany' => array('Comment')));
+ $result = $TestModel->find(array('Article.id' => 2), array('id', 'user_id', 'title', 'body'));
+ $expected = array(
+ 'Article' => array(
+ 'id' => '2',
+ 'user_id' => '3',
+ 'title' => 'New Second Article',
+ 'body' => 'Second Article Body'
+ ),
+ 'Tag' => array(
+ array(
+ 'id' => '1',
+ 'tag' => 'tag1',
+ 'created' => '2007-03-18 12:22:23',
+ 'updated' => '2007-03-18 12:24:31'
+ ),
+ array(
+ 'id' => '2',
+ 'tag' => 'tag2',
+ 'created' => '2007-03-18 12:24:23',
+ 'updated' => '2007-03-18 12:26:31'
+ )));
+ $this->assertEqual($result, $expected);
+
+ $data = array('Article' => array('id' => '2'), 'Tag' => array('Tag' => array(2, 3)));
+ $result = $TestModel->set($data);
+ $this->assertTrue($result);
+
+ $result = $TestModel->save();
+ $this->assertTrue($result);
+
+ $TestModel->unbindModel(array(
+ 'belongsTo' => array('User'),
+ 'hasMany' => array('Comment')
+ ));
+ $result = $TestModel->find(array('Article.id'=>2), array('id', 'user_id', 'title', 'body'));
+ $expected = array(
+ 'Article' => array(
+ 'id' => '2',
+ 'user_id' => '3',
+ 'title' => 'New Second Article',
+ 'body' => 'Second Article Body'
+ ),
+ 'Tag' => array(
+ array(
+ 'id' => '2',
+ 'tag' => 'tag2',
+ 'created' => '2007-03-18 12:24:23',
+ 'updated' => '2007-03-18 12:26:31'
+ ),
+ array(
+ 'id' => '3',
+ 'tag' => 'tag3',
+ 'created' => '2007-03-18 12:26:23',
+ 'updated' => '2007-03-18 12:28:31'
+ )));
+ $this->assertEqual($result, $expected);
+
+ $data = array('Tag' => array('Tag' => array(1, 2, 3)));
+
+ $result = $TestModel->set($data);
+ $this->assertTrue($result);
+
+ $result = $TestModel->save();
+ $this->assertTrue($result);
+
+ $TestModel->unbindModel(array(
+ 'belongsTo' => array('User'),
+ 'hasMany' => array('Comment')
+ ));
+ $result = $TestModel->find(array('Article.id' => 2), array('id', 'user_id', 'title', 'body'));
+ $expected = array(
+ 'Article' => array(
+ 'id' => '2',
+ 'user_id' => '3',
+ 'title' => 'New Second Article',
+ 'body' => 'Second Article Body'
+ ),
+ 'Tag' => array(
+ array(
+ 'id' => '1',
+ 'tag' => 'tag1',
+ 'created' => '2007-03-18 12:22:23',
+ 'updated' => '2007-03-18 12:24:31'
+ ),
+ array(
+ 'id' => '2',
+ 'tag' => 'tag2',
+ 'created' => '2007-03-18 12:24:23',
+ 'updated' => '2007-03-18 12:26:31'
+ ),
+ array(
+ 'id' => '3',
+ 'tag' => 'tag3',
+ 'created' => '2007-03-18 12:26:23',
+ 'updated' => '2007-03-18 12:28:31'
+ )));
+ $this->assertEqual($result, $expected);
+
+ $data = array('Tag' => array('Tag' => array()));
+ $result = $TestModel->set($data);
+ $this->assertTrue($result);
+
+ $result = $TestModel->save();
+ $this->assertTrue($result);
+
+ $data = array('Tag' => array('Tag' => ''));
+ $result = $TestModel->set($data);
+ $this->assertTrue($result);
+
+ $result = $TestModel->save();
+ $this->assertTrue($result);
+
+ $TestModel->unbindModel(array(
+ 'belongsTo' => array('User'),
+ 'hasMany' => array('Comment')
+ ));
+ $result = $TestModel->find(array('Article.id'=>2), array('id', 'user_id', 'title', 'body'));
+ $expected = array(
+ 'Article' => array(
+ 'id' => '2',
+ 'user_id' => '3',
+ 'title' => 'New Second Article',
+ 'body' => 'Second Article Body'
+ ),
+ 'Tag' => array()
+ );
+ $this->assertEqual($result, $expected);
+
+ $data = array('Tag' => array('Tag' => array(2, 3)));
+ $result = $TestModel->set($data);
+ $this->assertTrue($result);
+
+ $result = $TestModel->save();
+ $this->assertTrue($result);
+
+ $TestModel->unbindModel(array(
+ 'belongsTo' => array('User'),
+ 'hasMany' => array('Comment')
+ ));
+ $result = $TestModel->find(array('Article.id'=>2), array('id', 'user_id', 'title', 'body'));
+ $expected = array(
+ 'Article' => array(
+ 'id' => '2',
+ 'user_id' => '3',
+ 'title' => 'New Second Article',
+ 'body' => 'Second Article Body'
+ ),
+ 'Tag' => array(
+ array(
+ 'id' => '2',
+ 'tag' => 'tag2',
+ 'created' => '2007-03-18 12:24:23',
+ 'updated' => '2007-03-18 12:26:31'
+ ),
+ array(
+ 'id' => '3',
+ 'tag' => 'tag3',
+ 'created' => '2007-03-18 12:26:23',
+ 'updated' => '2007-03-18 12:28:31'
+ )));
+ $this->assertEqual($result, $expected);
+
+ $data = array(
+ 'Tag' => array(
+ 'Tag' => array(1, 2)
+ ),
+ 'Article' => array(
+ 'id' => '2',
+ 'title' => 'New Second Article'
+ ));
+ $this->assertTrue($TestModel->set($data));
+ $this->assertTrue($TestModel->save());
+
+ $TestModel->unbindModel(array(
+ 'belongsTo' => array('User'),
+ 'hasMany' => array('Comment')
+ ));
+ $result = $TestModel->find(array('Article.id'=>2), array('id', 'user_id', 'title', 'body'));
+ $expected = array(
+ 'Article' => array(
+ 'id' => '2',
+ 'user_id' => '3',
+ 'title' => 'New Second Article',
+ 'body' => 'Second Article Body'
+ ),
+ 'Tag' => array(
+ array(
+ 'id' => '1',
+ 'tag' => 'tag1',
+ 'created' => '2007-03-18 12:22:23',
+ 'updated' => '2007-03-18 12:24:31'
+ ),
+ array(
+ 'id' => '2',
+ 'tag' => 'tag2',
+ 'created' => '2007-03-18 12:24:23',
+ 'updated' => '2007-03-18 12:26:31'
+ )));
+ $this->assertEqual($result, $expected);
+
+ $data = array(
+ 'Tag' => array(
+ 'Tag' => array(1, 2)
+ ),
+ 'Article' => array(
+ 'id' => '2',
+ 'title' => 'New Second Article Title'
+ ));
+ $result = $TestModel->set($data);
+ $this->assertTrue($result);
+ $this->assertTrue($TestModel->save());
+
+ $TestModel->unbindModel(array(
+ 'belongsTo' => array('User'),
+ 'hasMany' => array('Comment')
+ ));
+ $result = $TestModel->find(array('Article.id'=>2), array('id', 'user_id', 'title', 'body'));
+ $expected = array(
+ 'Article' => array(
+ 'id' => '2',
+ 'user_id' => '3',
+ 'title' => 'New Second Article Title',
+ 'body' => 'Second Article Body'
+ ),
+ 'Tag' => array(
+ array(
+ 'id' => '1',
+ 'tag' => 'tag1',
+ 'created' => '2007-03-18 12:22:23',
+ 'updated' => '2007-03-18 12:24:31'
+ ),
+ array(
+ 'id' => '2',
+ 'tag' => 'tag2',
+ 'created' => '2007-03-18 12:24:23',
+ 'updated' => '2007-03-18 12:26:31'
+ )
+ )
+ );
+ $this->assertEqual($result, $expected);
+
+ $data = array(
+ 'Tag' => array(
+ 'Tag' => array(2, 3)
+ ),
+ 'Article' => array(
+ 'id' => '2',
+ 'title' => 'Changed Second Article'
+ ));
+ $this->assertTrue($TestModel->set($data));
+ $this->assertTrue($TestModel->save());
+
+ $TestModel->unbindModel(array(
+ 'belongsTo' => array('User'),
+ 'hasMany' => array('Comment')
+ ));
+ $result = $TestModel->find(array('Article.id'=>2), array('id', 'user_id', 'title', 'body'));
+ $expected = array(
+ 'Article' => array(
+ 'id' => '2',
+ 'user_id' => '3',
+ 'title' => 'Changed Second Article',
+ 'body' => 'Second Article Body'
+ ),
+ 'Tag' => array(
+ array(
+ 'id' => '2',
+ 'tag' => 'tag2',
+ 'created' => '2007-03-18 12:24:23',
+ 'updated' => '2007-03-18 12:26:31'
+ ),
+ array(
+ 'id' => '3',
+ 'tag' => 'tag3',
+ 'created' => '2007-03-18 12:26:23',
+ 'updated' => '2007-03-18 12:28:31'
+ )
+ )
+ );
+ $this->assertEqual($result, $expected);
+
+ $data = array(
+ 'Tag' => array(
+ 'Tag' => array(1, 3)
+ ),
+ 'Article' => array('id' => '2'),
+ );
+
+ $result = $TestModel->set($data);
+ $this->assertTrue($result);
+
+ $result = $TestModel->save();
+ $this->assertTrue($result);
+
+ $TestModel->unbindModel(array(
+ 'belongsTo' => array('User'),
+ 'hasMany' => array('Comment')
+ ));
+ $result = $TestModel->find(array('Article.id'=>2), array('id', 'user_id', 'title', 'body'));
+ $expected = array(
+ 'Article' => array(
+ 'id' => '2',
+ 'user_id' => '3',
+ 'title' => 'Changed Second Article',
+ 'body' => 'Second Article Body'
+ ),
+ 'Tag' => array(
+ array(
+ 'id' => '1',
+ 'tag' => 'tag1',
+ 'created' => '2007-03-18 12:22:23',
+ 'updated' => '2007-03-18 12:24:31'
+ ),
+ array(
+ 'id' => '3',
+ 'tag' => 'tag3',
+ 'created' => '2007-03-18 12:26:23',
+ 'updated' => '2007-03-18 12:28:31'
+ )));
+ $this->assertEqual($result, $expected);
+
+ $data = array(
+ 'Article' => array(
+ 'id' => 10,
+ 'user_id' => '2',
+ 'title' => 'New Article With Tags and fieldList',
+ 'body' => 'New Article Body with Tags and fieldList',
+ 'created' => '2007-03-18 14:55:23',
+ 'updated' => '2007-03-18 14:57:31'
+ ),
+ 'Tag' => array(
+ 'Tag' => array(1, 2, 3)
+ ));
+ $result = $TestModel->create()
+ && $TestModel->save($data, true, array('user_id', 'title', 'published'));
+ $this->assertTrue($result);
+
+ $TestModel->unbindModel(array('belongsTo' => array('User'), 'hasMany' => array('Comment')));
+ $result = $TestModel->read();
+ $expected = array(
+ 'Article' => array(
+ 'id' => 4,
+ 'user_id' => 2,
+ 'title' => 'New Article With Tags and fieldList',
+ 'body' => '',
+ 'published' => 'N',
+ 'created' => '',
+ 'updated' => ''
+ ),
+ 'Tag' => array(
+ 0 => array(
+ 'id' => 1,
+ 'tag' => 'tag1',
+ 'created' => '2007-03-18 12:22:23',
+ 'updated' => '2007-03-18 12:24:31'
+ ),
+ 1 => array(
+ 'id' => 2,
+ 'tag' => 'tag2',
+ 'created' => '2007-03-18 12:24:23',
+ 'updated' => '2007-03-18 12:26:31'
+ ),
+ 2 => array(
+ 'id' => 3,
+ 'tag' => 'tag3',
+ 'created' => '2007-03-18 12:26:23',
+ 'updated' => '2007-03-18 12:28:31'
+ )));
+ $this->assertEqual($result, $expected);
+
+
+ $this->loadFixtures('JoinA', 'JoinC', 'JoinAC', 'JoinB', 'JoinAB');
+ $TestModel = new JoinA();
+ $TestModel->hasBelongsToMany['JoinC']['unique'] = true;
+ $data = array(
+ 'JoinA' => array(
+ 'id' => 1,
+ 'name' => 'Join A 1',
+ 'body' => 'Join A 1 Body',
+ ),
+ 'JoinC' => array(
+ 'JoinC' => array(
+ array('join_c_id' => 2, 'other' => 'new record'),
+ array('join_c_id' => 3, 'other' => 'new record')
+ )
+ )
+ );
+ $TestModel->save($data);
+ $result = $TestModel->read(null, 1);
+ $expected = array(4, 5);
+ $this->assertEqual(Set::extract('/JoinC/JoinAsJoinC/id', $result), $expected);
+ $expected = array('new record', 'new record');
+ $this->assertEqual(Set::extract('/JoinC/JoinAsJoinC/other', $result), $expected);
+ }
+
+/**
+ * testSaveHabtmCustomKeys method
+ *
+ * @access public
+ * @return void
+ */
+ function testSaveHabtmCustomKeys() {
+ $this->loadFixtures('Story', 'StoriesTag', 'Tag');
+ $Story =& new Story();
+
+ $data = array(
+ 'Story' => array('story' => '1'),
+ 'Tag' => array(
+ 'Tag' => array(2, 3)
+ ));
+ $result = $Story->set($data);
+ $this->assertTrue($result);
+
+ $result = $Story->save();
+ $this->assertTrue($result);
+
+ $result = $Story->find('all', array('order' => array('Story.story')));
+ $expected = array(
+ array(
+ 'Story' => array(
+ 'story' => 1,
+ 'title' => 'First Story'
+ ),
+ 'Tag' => array(
+ array(
+ 'id' => 2,
+ 'tag' => 'tag2',
+ 'created' => '2007-03-18 12:24:23',
+ 'updated' => '2007-03-18 12:26:31'
+ ),
+ array(
+ 'id' => 3,
+ 'tag' => 'tag3',
+ 'created' => '2007-03-18 12:26:23',
+ 'updated' => '2007-03-18 12:28:31'
+ ))),
+ array(
+ 'Story' => array(
+ 'story' => 2,
+ 'title' => 'Second Story'
+ ),
+ 'Tag' => array()
+ ));
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * test that saving habtm records respects conditions set in the 'conditions' key
+ * for the association.
+ *
+ * @return void
+ */
+ function testHabtmSaveWithConditionsInAssociation() {
+ $this->loadFixtures('JoinThing', 'Something', 'SomethingElse');
+ $Something =& new Something();
+ $Something->unbindModel(array('hasAndBelongsToMany' => array('SomethingElse')), false);
+
+ $Something->bindModel(array(
+ 'hasAndBelongsToMany' => array(
+ 'DoomedSomethingElse' => array(
+ 'className' => 'SomethingElse',
+ 'joinTable' => 'join_things',
+ 'conditions' => 'JoinThing.doomed = true',
+ 'unique' => true
+ ),
+ 'NotDoomedSomethingElse' => array(
+ 'className' => 'SomethingElse',
+ 'joinTable' => 'join_things',
+ 'conditions' => array('JoinThing.doomed' => 0),
+ 'unique' => true
+ )
+ )
+ ), false);
+ $result = $Something->read(null, 1);
+ $this->assertTrue(empty($result['NotDoomedSomethingElse']));
+ $this->assertEqual(count($result['DoomedSomethingElse']), 1);
+
+ $data = array(
+ 'Something' => array('id' => 1),
+ 'NotDoomedSomethingElse' => array(
+ 'NotDoomedSomethingElse' => array(
+ array('something_else_id' => 2, 'doomed' => 0),
+ array('something_else_id' => 3, 'doomed' => 0)
+ )
+ )
+ );
+ $Something->create($data);
+ $result = $Something->save();
+ $this->assertTrue($result);
+
+ $result = $Something->read(null, 1);
+ $this->assertEqual(count($result['NotDoomedSomethingElse']), 2);
+ $this->assertEqual(count($result['DoomedSomethingElse']), 1);
+ }
+/**
+ * testHabtmSaveKeyResolution method
+ *
+ * @access public
+ * @return void
+ */
+ function testHabtmSaveKeyResolution() {
+ $this->loadFixtures('Apple', 'Device', 'ThePaperMonkies');
+ $ThePaper =& new ThePaper();
+
+ $ThePaper->id = 1;
+ $ThePaper->save(array('Monkey' => array(2, 3)));
+
+ $result = $ThePaper->findById(1);
+ $expected = array(
+ array(
+ 'id' => '2',
+ 'device_type_id' => '1',
+ 'name' => 'Device 2',
+ 'typ' => '1'
+ ),
+ array(
+ 'id' => '3',
+ 'device_type_id' => '1',
+ 'name' => 'Device 3',
+ 'typ' => '2'
+ ));
+ $this->assertEqual($result['Monkey'], $expected);
+
+ $ThePaper->id = 2;
+ $ThePaper->save(array('Monkey' => array(1, 2, 3)));
+
+ $result = $ThePaper->findById(2);
+ $expected = array(
+ array(
+ 'id' => '1',
+ 'device_type_id' => '1',
+ 'name' => 'Device 1',
+ 'typ' => '1'
+ ),
+ array(
+ 'id' => '2',
+ 'device_type_id' => '1',
+ 'name' => 'Device 2',
+ 'typ' => '1'
+ ),
+ array(
+ 'id' => '3',
+ 'device_type_id' => '1',
+ 'name' => 'Device 3',
+ 'typ' => '2'
+ ));
+ $this->assertEqual($result['Monkey'], $expected);
+
+ $ThePaper->id = 2;
+ $ThePaper->save(array('Monkey' => array(1, 3)));
+
+ $result = $ThePaper->findById(2);
+ $expected = array(
+ array(
+ 'id' => '1',
+ 'device_type_id' => '1',
+ 'name' => 'Device 1',
+ 'typ' => '1'
+ ),
+ array(
+ 'id' => '3',
+ 'device_type_id' => '1',
+ 'name' => 'Device 3',
+ 'typ' => '2'
+ ));
+ $this->assertEqual($result['Monkey'], $expected);
+
+ $result = $ThePaper->findById(1);
+ $expected = array(
+ array(
+ 'id' => '2',
+ 'device_type_id' => '1',
+ 'name' => 'Device 2',
+ 'typ' => '1'
+ ),
+ array(
+ 'id' => '3',
+ 'device_type_id' => '1',
+ 'name' => 'Device 3',
+ 'typ' => '2'
+ ));
+ $this->assertEqual($result['Monkey'], $expected);
+ }
+
+/**
+ * testCreationOfEmptyRecord method
+ *
+ * @access public
+ * @return void
+ */
+ function testCreationOfEmptyRecord() {
+ $this->loadFixtures('Author');
+ $TestModel =& new Author();
+ $this->assertEqual($TestModel->find('count'), 4);
+
+ $TestModel->deleteAll(true, false, false);
+ $this->assertEqual($TestModel->find('count'), 0);
+
+ $result = $TestModel->save();
+ $this->assertTrue(isset($result['Author']['created']));
+ $this->assertTrue(isset($result['Author']['updated']));
+ $this->assertEqual($TestModel->find('count'), 1);
+ }
+
+/**
+ * testCreateWithPKFiltering method
+ *
+ * @access public
+ * @return void
+ */
+ function testCreateWithPKFiltering() {
+ $TestModel =& new Article();
+ $data = array(
+ 'id' => 5,
+ 'user_id' => 2,
+ 'title' => 'My article',
+ 'body' => 'Some text'
+ );
+
+ $result = $TestModel->create($data);
+ $expected = array(
+ 'Article' => array(
+ 'published' => 'N',
+ 'id' => 5,
+ 'user_id' => 2,
+ 'title' => 'My article',
+ 'body' => 'Some text'
+ ));
+
+ $this->assertEqual($result, $expected);
+ $this->assertEqual($TestModel->id, 5);
+
+ $result = $TestModel->create($data, true);
+ $expected = array(
+ 'Article' => array(
+ 'published' => 'N',
+ 'id' => false,
+ 'user_id' => 2,
+ 'title' => 'My article',
+ 'body' => 'Some text'
+ ));
+
+ $this->assertEqual($result, $expected);
+ $this->assertFalse($TestModel->id);
+
+ $result = $TestModel->create(array('Article' => $data), true);
+ $expected = array(
+ 'Article' => array(
+ 'published' => 'N',
+ 'id' => false,
+ 'user_id' => 2,
+ 'title' => 'My article',
+ 'body' => 'Some text'
+ ));
+
+ $this->assertEqual($result, $expected);
+ $this->assertFalse($TestModel->id);
+
+ $data = array(
+ 'id' => 6,
+ 'user_id' => 2,
+ 'title' => 'My article',
+ 'body' => 'Some text',
+ 'created' => '1970-01-01 00:00:00',
+ 'updated' => '1970-01-01 12:00:00',
+ 'modified' => '1970-01-01 12:00:00'
+ );
+
+ $result = $TestModel->create($data);
+ $expected = array(
+ 'Article' => array(
+ 'published' => 'N',
+ 'id' => 6,
+ 'user_id' => 2,
+ 'title' => 'My article',
+ 'body' => 'Some text',
+ 'created' => '1970-01-01 00:00:00',
+ 'updated' => '1970-01-01 12:00:00',
+ 'modified' => '1970-01-01 12:00:00'
+ ));
+ $this->assertEqual($result, $expected);
+ $this->assertEqual($TestModel->id, 6);
+
+ $result = $TestModel->create(array(
+ 'Article' => array_diff_key($data, array(
+ 'created' => true,
+ 'updated' => true,
+ 'modified' => true
+ ))), true);
+ $expected = array(
+ 'Article' => array(
+ 'published' => 'N',
+ 'id' => false,
+ 'user_id' => 2,
+ 'title' => 'My article',
+ 'body' => 'Some text'
+ ));
+ $this->assertEqual($result, $expected);
+ $this->assertFalse($TestModel->id);
+ }
+
+/**
+ * testCreationWithMultipleData method
+ *
+ * @access public
+ * @return void
+ */
+ function testCreationWithMultipleData() {
+ $this->loadFixtures('Article', 'Comment');
+ $Article =& new Article();
+ $Comment =& new Comment();
+
+ $articles = $Article->find('all', array(
+ 'fields' => array('id','title'),
+ 'recursive' => -1
+ ));
+
+ $comments = $Comment->find('all', array(
+ 'fields' => array('id','article_id','user_id','comment','published'), 'recursive' => -1));
+
+ $this->assertEqual($articles, array(
+ array('Article' => array(
+ 'id' => 1,
+ 'title' => 'First Article'
+ )),
+ array('Article' => array(
+ 'id' => 2,
+ 'title' => 'Second Article'
+ )),
+ array('Article' => array(
+ 'id' => 3,
+ 'title' => 'Third Article'
+ ))));
+
+ $this->assertEqual($comments, array(
+ array('Comment' => array(
+ 'id' => 1,
+ 'article_id' => 1,
+ 'user_id' => 2,
+ 'comment' => 'First Comment for First Article',
+ 'published' => 'Y'
+ )),
+ array('Comment' => array(
+ 'id' => 2,
+ 'article_id' => 1,
+ 'user_id' => 4,
+ 'comment' => 'Second Comment for First Article',
+ 'published' => 'Y'
+ )),
+ array('Comment' => array(
+ 'id' => 3,
+ 'article_id' => 1,
+ 'user_id' => 1,
+ 'comment' => 'Third Comment for First Article',
+ 'published' => 'Y'
+ )),
+ array('Comment' => array(
+ 'id' => 4,
+ 'article_id' => 1,
+ 'user_id' => 1,
+ 'comment' => 'Fourth Comment for First Article',
+ 'published' => 'N'
+ )),
+ array('Comment' => array(
+ 'id' => 5,
+ 'article_id' => 2,
+ 'user_id' => 1,
+ 'comment' => 'First Comment for Second Article',
+ 'published' => 'Y'
+ )),
+ array('Comment' => array(
+ 'id' => 6,
+ 'article_id' => 2,
+ 'user_id' => 2,
+ 'comment' => 'Second Comment for Second Article',
+ 'published' => 'Y'
+ ))));
+
+ $data = array(
+ 'Comment' => array(
+ 'article_id' => 2,
+ 'user_id' => 4,
+ 'comment' => 'Brand New Comment',
+ 'published' => 'N'
+ ),
+ 'Article' => array(
+ 'id' => 2,
+ 'title' => 'Second Article Modified'
+ ));
+
+ $result = $Comment->create($data);
+
+ $this->assertTrue($result);
+ $result = $Comment->save();
+ $this->assertTrue($result);
+
+ $articles = $Article->find('all', array(
+ 'fields' => array('id','title'),
+ 'recursive' => -1
+ ));
+
+ $comments = $Comment->find('all', array(
+ 'fields' => array('id','article_id','user_id','comment','published'),
+ 'recursive' => -1
+ ));
+
+ $this->assertEqual($articles, array(
+ array('Article' => array(
+ 'id' => 1,
+ 'title' => 'First Article'
+ )),
+ array('Article' => array(
+ 'id' => 2,
+ 'title' => 'Second Article'
+ )),
+ array('Article' => array(
+ 'id' => 3,
+ 'title' => 'Third Article'
+ ))));
+
+ $this->assertEqual($comments, array(
+ array('Comment' => array(
+ 'id' => 1,
+ 'article_id' => 1,
+ 'user_id' => 2,
+ 'comment' => 'First Comment for First Article',
+ 'published' => 'Y'
+ )),
+ array('Comment' => array(
+ 'id' => 2,
+ 'article_id' => 1,
+ 'user_id' => 4,
+ 'comment' => 'Second Comment for First Article',
+ 'published' => 'Y'
+ )),
+ array('Comment' => array(
+ 'id' => 3,
+ 'article_id' => 1,
+ 'user_id' => 1,
+ 'comment' => 'Third Comment for First Article',
+ 'published' => 'Y'
+ )),
+ array('Comment' => array(
+ 'id' => 4,
+ 'article_id' => 1,
+ 'user_id' => 1,
+ 'comment' => 'Fourth Comment for First Article',
+ 'published' => 'N'
+ )),
+ array('Comment' => array(
+ 'id' => 5,
+ 'article_id' => 2,
+ 'user_id' => 1,
+ 'comment' => 'First Comment for Second Article',
+ 'published' => 'Y'
+ )),
+ array('Comment' => array(
+ 'id' => 6,
+ 'article_id' => 2,
+ 'user_id' => 2, 'comment' =>
+ 'Second Comment for Second Article',
+ 'published' => 'Y'
+ )),
+ array('Comment' => array(
+ 'id' => 7,
+ 'article_id' => 2,
+ 'user_id' => 4,
+ 'comment' => 'Brand New Comment',
+ 'published' => 'N'
+ ))));
+
+ }
+
+/**
+ * testCreationWithMultipleDataSameModel method
+ *
+ * @access public
+ * @return void
+ */
+ function testCreationWithMultipleDataSameModel() {
+ $this->loadFixtures('Article');
+ $Article =& new Article();
+ $SecondaryArticle =& new Article();
+
+ $result = $Article->field('title', array('id' => 1));
+ $this->assertEqual($result, 'First Article');
+
+ $data = array(
+ 'Article' => array(
+ 'user_id' => 2,
+ 'title' => 'Brand New Article',
+ 'body' => 'Brand New Article Body',
+ 'published' => 'Y'
+ ),
+ 'SecondaryArticle' => array(
+ 'id' => 1
+ ));
+
+ $Article->create();
+ $result = $Article->save($data);
+ $this->assertTrue($result);
+
+ $result = $Article->getInsertID();
+ $this->assertTrue(!empty($result));
+
+ $result = $Article->field('title', array('id' => 1));
+ $this->assertEqual($result, 'First Article');
+
+ $articles = $Article->find('all', array(
+ 'fields' => array('id','title'),
+ 'recursive' => -1
+ ));
+
+ $this->assertEqual($articles, array(
+ array('Article' => array(
+ 'id' => 1,
+ 'title' => 'First Article'
+ )),
+ array('Article' => array(
+ 'id' => 2,
+ 'title' => 'Second Article'
+ )),
+ array('Article' => array(
+ 'id' => 3,
+ 'title' => 'Third Article'
+ )),
+ array('Article' => array(
+ 'id' => 4,
+ 'title' => 'Brand New Article'
+ ))));
+ }
+
+/**
+ * testCreationWithMultipleDataSameModelManualInstances method
+ *
+ * @access public
+ * @return void
+ */
+ function testCreationWithMultipleDataSameModelManualInstances() {
+ $this->loadFixtures('PrimaryModel');
+ $Primary =& new PrimaryModel();
+ $Secondary =& new PrimaryModel();
+
+ $result = $Primary->field('primary_name', array('id' => 1));
+ $this->assertEqual($result, 'Primary Name Existing');
+
+ $data = array(
+ 'PrimaryModel' => array(
+ 'primary_name' => 'Primary Name New'
+ ),
+ 'SecondaryModel' => array(
+ 'id' => array(1)
+ ));
+
+ $Primary->create();
+ $result = $Primary->save($data);
+ $this->assertTrue($result);
+
+ $result = $Primary->field('primary_name', array('id' => 1));
+ $this->assertEqual($result, 'Primary Name Existing');
+
+ $result = $Primary->getInsertID();
+ $this->assertTrue(!empty($result));
+
+ $result = $Primary->field('primary_name', array('id' => $result));
+ $this->assertEqual($result, 'Primary Name New');
+
+ $result = $Primary->find('count');
+ $this->assertEqual($result, 2);
+ }
+
+/**
+ * testRecordExists method
+ *
+ * @access public
+ * @return void
+ */
+ function testRecordExists() {
+ $this->loadFixtures('User');
+ $TestModel =& new User();
+
+ $this->assertFalse($TestModel->exists());
+ $TestModel->read(null, 1);
+ $this->assertTrue($TestModel->exists());
+ $TestModel->create();
+ $this->assertFalse($TestModel->exists());
+ $TestModel->id = 4;
+ $this->assertTrue($TestModel->exists());
+
+ $TestModel =& new TheVoid();
+ $this->assertFalse($TestModel->exists());
+
+ $TestModel->id = 5;
+ $this->expectError();
+ ob_start();
+ $this->assertFalse($TestModel->exists());
+ $output = ob_get_clean();
+ }
+
+/**
+ * testUpdateExisting method
+ *
+ * @access public
+ * @return void
+ */
+ function testUpdateExisting() {
+ $this->loadFixtures('User', 'Article', 'Comment');
+ $TestModel =& new User();
+ $TestModel->create();
+
+ $TestModel->save(array(
+ 'User' => array(
+ 'user' => 'some user',
+ 'password' => 'some password'
+ )));
+ $this->assertTrue(is_int($TestModel->id) || (intval($TestModel->id) === 5));
+ $id = $TestModel->id;
+
+ $TestModel->save(array(
+ 'User' => array(
+ 'user' => 'updated user'
+ )));
+ $this->assertEqual($TestModel->id, $id);
+
+ $result = $TestModel->findById($id);
+ $this->assertEqual($result['User']['user'], 'updated user');
+ $this->assertEqual($result['User']['password'], 'some password');
+
+ $Article =& new Article();
+ $Comment =& new Comment();
+ $data = array(
+ 'Comment' => array(
+ 'id' => 1,
+ 'comment' => 'First Comment for First Article'
+ ),
+ 'Article' => array(
+ 'id' => 2,
+ 'title' => 'Second Article'
+ ));
+
+ $result = $Article->save($data);
+ $this->assertTrue($result);
+
+ $result = $Comment->save($data);
+ $this->assertTrue($result);
+ }
+
+/**
+ * test updating records and saving blank values.
+ *
+ * @return void
+ */
+ function testUpdateSavingBlankValues() {
+ $this->loadFixtures('Article');
+ $Article =& new Article();
+ $Article->validate = array();
+ $Article->create();
+ $result = $Article->save(array(
+ 'id' => 1,
+ 'title' => '',
+ 'body' => ''
+ ));
+ $this->assertTrue($result);
+ $result = $Article->find('first', array('conditions' => array('Article.id' => 1)));
+ $this->assertEqual('', $result['Article']['title'], 'Title is not blank');
+ $this->assertEqual('', $result['Article']['body'], 'Body is not blank');
+ }
+
+/**
+ * testUpdateMultiple method
+ *
+ * @access public
+ * @return void
+ */
+ function testUpdateMultiple() {
+ $this->loadFixtures('Comment', 'Article', 'User', 'CategoryThread');
+ $TestModel =& new Comment();
+ $result = Set::extract($TestModel->find('all'), '{n}.Comment.user_id');
+ $expected = array('2', '4', '1', '1', '1', '2');
+ $this->assertEqual($result, $expected);
+
+ $TestModel->updateAll(array('Comment.user_id' => 5), array('Comment.user_id' => 2));
+ $result = Set::combine($TestModel->find('all'), '{n}.Comment.id', '{n}.Comment.user_id');
+ $expected = array(1 => 5, 2 => 4, 3 => 1, 4 => 1, 5 => 1, 6 => 5);
+ $this->assertEqual($result, $expected);
+
+ $result = $TestModel->updateAll(
+ array('Comment.comment' => "'Updated today'"),
+ array('Comment.user_id' => 5)
+ );
+ $this->assertTrue($result);
+ $result = Set::extract(
+ $TestModel->find('all', array(
+ 'conditions' => array(
+ 'Comment.user_id' => 5
+ ))),
+ '{n}.Comment.comment'
+ );
+ $expected = array_fill(0, 2, 'Updated today');
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testHabtmUuidWithUuidId method
+ *
+ * @access public
+ * @return void
+ */
+ function testHabtmUuidWithUuidId() {
+ $this->loadFixtures('Uuidportfolio', 'Uuiditem', 'UuiditemsUuidportfolio');
+ $TestModel =& new Uuidportfolio();
+
+ $data = array('Uuidportfolio' => array('name' => 'Portfolio 3'));
+ $data['Uuiditem']['Uuiditem'] = array('483798c8-c7cc-430e-8cf9-4fcc40cf8569');
+ $TestModel->create($data);
+ $TestModel->save();
+ $id = $TestModel->id;
+ $result = $TestModel->read(null, $id);
+ $this->assertEqual(1, count($result['Uuiditem']));
+ $this->assertEqual(strlen($result['Uuiditem'][0]['UuiditemsUuidportfolio']['id']), 36);
+ }
+
+/**
+ * test HABTM saving when join table has no primary key and only 2 columns.
+ *
+ * @return void
+ */
+ function testHabtmSavingWithNoPrimaryKeyUuidJoinTable() {
+ $this->loadFixtures('UuidTag', 'Fruit', 'FruitsUuidTag');
+ $Fruit =& new Fruit();
+ $data = array(
+ 'Fruit' => array(
+ 'color' => 'Red',
+ 'shape' => 'Heart-shaped',
+ 'taste' => 'sweet',
+ 'name' => 'Strawberry',
+ ),
+ 'UuidTag' => array(
+ 'UuidTag' => array(
+ '481fc6d0-b920-43e0-e50f-6d1740cf8569'
+ )
+ )
+ );
+ $this->assertTrue($Fruit->save($data));
+ }
+
+/**
+ * test HABTM saving when join table has no primary key and only 2 columns, no with model is used.
+ *
+ * @return void
+ */
+ function testHabtmSavingWithNoPrimaryKeyUuidJoinTableNoWith() {
+ $this->loadFixtures('UuidTag', 'Fruit', 'FruitsUuidTag');
+ $Fruit =& new FruitNoWith();
+ $data = array(
+ 'Fruit' => array(
+ 'color' => 'Red',
+ 'shape' => 'Heart-shaped',
+ 'taste' => 'sweet',
+ 'name' => 'Strawberry',
+ ),
+ 'UuidTag' => array(
+ 'UuidTag' => array(
+ '481fc6d0-b920-43e0-e50f-6d1740cf8569'
+ )
+ )
+ );
+ $this->assertTrue($Fruit->save($data));
+ }
+
+/**
+ * testHabtmUuidWithNumericId method
+ *
+ * @access public
+ * @return void
+ */
+ function testHabtmUuidWithNumericId() {
+ $this->loadFixtures('Uuidportfolio', 'Uuiditem', 'UuiditemsUuidportfolioNumericid');
+ $TestModel =& new Uuiditem();
+
+ $data = array('Uuiditem' => array('name' => 'Item 7', 'published' => 0));
+ $data['Uuidportfolio']['Uuidportfolio'] = array('480af662-eb8c-47d3-886b-230540cf8569');
+ $TestModel->create($data);
+ $TestModel->save();
+ $id = $TestModel->id;
+ $result = $TestModel->read(null, $id);
+ $this->assertEqual(1, count($result['Uuidportfolio']));
+ }
+
+/**
+ * testSaveMultipleHabtm method
+ *
+ * @access public
+ * @return void
+ */
+ function testSaveMultipleHabtm() {
+ $this->loadFixtures('JoinA', 'JoinB', 'JoinC', 'JoinAB', 'JoinAC');
+ $TestModel = new JoinA();
+ $result = $TestModel->findById(1);
+
+ $expected = array(
+ 'JoinA' => array(
+ 'id' => 1,
+ 'name' => 'Join A 1',
+ 'body' => 'Join A 1 Body',
+ 'created' => '2008-01-03 10:54:23',
+ 'updated' => '2008-01-03 10:54:23'
+ ),
+ 'JoinB' => array(
+ 0 => array(
+ 'id' => 2,
+ 'name' => 'Join B 2',
+ 'created' => '2008-01-03 10:55:02',
+ 'updated' => '2008-01-03 10:55:02',
+ 'JoinAsJoinB' => array(
+ 'id' => 1,
+ 'join_a_id' => 1,
+ 'join_b_id' => 2,
+ 'other' => 'Data for Join A 1 Join B 2',
+ 'created' => '2008-01-03 10:56:33',
+ 'updated' => '2008-01-03 10:56:33'
+ ))),
+ 'JoinC' => array(
+ 0 => array(
+ 'id' => 2,
+ 'name' => 'Join C 2',
+ 'created' => '2008-01-03 10:56:12',
+ 'updated' => '2008-01-03 10:56:12',
+ 'JoinAsJoinC' => array(
+ 'id' => 1,
+ 'join_a_id' => 1,
+ 'join_c_id' => 2,
+ 'other' => 'Data for Join A 1 Join C 2',
+ 'created' => '2008-01-03 10:57:22',
+ 'updated' => '2008-01-03 10:57:22'
+ ))));
+
+ $this->assertEqual($result, $expected);
+
+ $ts = date('Y-m-d H:i:s');
+ $TestModel->id = 1;
+ $data = array(
+ 'JoinA' => array(
+ 'id' => '1',
+ 'name' => 'New name for Join A 1',
+ 'updated' => $ts
+ ),
+ 'JoinB' => array(
+ array(
+ 'id' => 1,
+ 'join_b_id' => 2,
+ 'other' => 'New data for Join A 1 Join B 2',
+ 'created' => $ts,
+ 'updated' => $ts
+ )),
+ 'JoinC' => array(
+ array(
+ 'id' => 1,
+ 'join_c_id' => 2,
+ 'other' => 'New data for Join A 1 Join C 2',
+ 'created' => $ts,
+ 'updated' => $ts
+ )));
+
+ $TestModel->set($data);
+ $TestModel->save();
+
+ $result = $TestModel->findById(1);
+ $expected = array(
+ 'JoinA' => array(
+ 'id' => 1,
+ 'name' => 'New name for Join A 1',
+ 'body' => 'Join A 1 Body',
+ 'created' => '2008-01-03 10:54:23',
+ 'updated' => $ts
+ ),
+ 'JoinB' => array(
+ 0 => array(
+ 'id' => 2,
+ 'name' => 'Join B 2',
+ 'created' => '2008-01-03 10:55:02',
+ 'updated' => '2008-01-03 10:55:02',
+ 'JoinAsJoinB' => array(
+ 'id' => 1,
+ 'join_a_id' => 1,
+ 'join_b_id' => 2,
+ 'other' => 'New data for Join A 1 Join B 2',
+ 'created' => $ts,
+ 'updated' => $ts
+ ))),
+ 'JoinC' => array(
+ 0 => array(
+ 'id' => 2,
+ 'name' => 'Join C 2',
+ 'created' => '2008-01-03 10:56:12',
+ 'updated' => '2008-01-03 10:56:12',
+ 'JoinAsJoinC' => array(
+ 'id' => 1,
+ 'join_a_id' => 1,
+ 'join_c_id' => 2,
+ 'other' => 'New data for Join A 1 Join C 2',
+ 'created' => $ts,
+ 'updated' => $ts
+ ))));
+
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testSaveAll method
+ *
+ * @access public
+ * @return void
+ */
+ function testSaveAll() {
+ $this->loadFixtures('Post', 'Author', 'Comment', 'Attachment');
+ $TestModel =& new Post();
+
+ $result = $TestModel->find('all');
+ $this->assertEqual(count($result), 3);
+ $this->assertFalse(isset($result[3]));
+ $ts = date('Y-m-d H:i:s');
+
+ $TestModel->saveAll(array(
+ 'Post' => array(
+ 'title' => 'Post with Author',
+ 'body' => 'This post will be saved with an author'
+ ),
+ 'Author' => array(
+ 'user' => 'bob',
+ 'password' => '5f4dcc3b5aa765d61d8327deb882cf90'
+ )));
+
+ $result = $TestModel->find('all');
+ $expected = array(
+ 'Post' => array(
+ 'id' => '4',
+ 'author_id' => '5',
+ 'title' => 'Post with Author',
+ 'body' => 'This post will be saved with an author',
+ 'published' => 'N',
+ 'created' => $ts,
+ 'updated' => $ts
+ ),
+ 'Author' => array(
+ 'id' => '5',
+ 'user' => 'bob',
+ 'password' => '5f4dcc3b5aa765d61d8327deb882cf90',
+ 'created' => $ts,
+ 'updated' => $ts,
+ 'test' => 'working'
+ ));
+ $this->assertEqual($result[3], $expected);
+ $this->assertEqual(count($result), 4);
+
+ $TestModel->deleteAll(true);
+ $this->assertEqual($TestModel->find('all'), array());
+
+ // SQLite seems to reset the PK counter when that happens, so we need this to make the tests pass
+ $this->db->truncate($TestModel);
+
+ $ts = date('Y-m-d H:i:s');
+ $TestModel->saveAll(array(
+ array(
+ 'title' => 'Multi-record post 1',
+ 'body' => 'First multi-record post',
+ 'author_id' => 2
+ ),
+ array(
+ 'title' => 'Multi-record post 2',
+ 'body' => 'Second multi-record post',
+ 'author_id' => 2
+ )));
+
+ $result = $TestModel->find('all', array(
+ 'recursive' => -1,
+ 'order' => 'Post.id ASC'
+ ));
+ $expected = array(
+ array(
+ 'Post' => array(
+ 'id' => '1',
+ 'author_id' => '2',
+ 'title' => 'Multi-record post 1',
+ 'body' => 'First multi-record post',
+ 'published' => 'N',
+ 'created' => $ts,
+ 'updated' => $ts
+ )),
+ array(
+ 'Post' => array(
+ 'id' => '2',
+ 'author_id' => '2',
+ 'title' => 'Multi-record post 2',
+ 'body' => 'Second multi-record post',
+ 'published' => 'N',
+ 'created' => $ts,
+ 'updated' => $ts
+ )));
+ $this->assertEqual($result, $expected);
+
+ $TestModel =& new Comment();
+ $ts = date('Y-m-d H:i:s');
+ $result = $TestModel->saveAll(array(
+ 'Comment' => array(
+ 'article_id' => 2,
+ 'user_id' => 2,
+ 'comment' => 'New comment with attachment',
+ 'published' => 'Y'
+ ),
+ 'Attachment' => array(
+ 'attachment' => 'some_file.tgz'
+ )));
+ $this->assertTrue($result);
+
+ $result = $TestModel->find('all');
+ $expected = array(
+ 'id' => '7',
+ 'article_id' => '2',
+ 'user_id' => '2',
+ 'comment' => 'New comment with attachment',
+ 'published' => 'Y',
+ 'created' => $ts,
+ 'updated' => $ts
+ );
+ $this->assertEqual($result[6]['Comment'], $expected);
+
+ $expected = array(
+ 'id' => '7',
+ 'article_id' => '2',
+ 'user_id' => '2',
+ 'comment' => 'New comment with attachment',
+ 'published' => 'Y',
+ 'created' => $ts,
+ 'updated' => $ts
+ );
+ $this->assertEqual($result[6]['Comment'], $expected);
+
+ $expected = array(
+ 'id' => '2',
+ 'comment_id' => '7',
+ 'attachment' => 'some_file.tgz',
+ 'created' => $ts,
+ 'updated' => $ts
+ );
+ $this->assertEqual($result[6]['Attachment'], $expected);
+ }
+
+/**
+ * Test SaveAll with Habtm relations
+ *
+ * @access public
+ * @return void
+ */
+ function testSaveAllHabtm() {
+ $this->loadFixtures('Article', 'Tag', 'Comment', 'User');
+ $data = array(
+ 'Article' => array(
+ 'user_id' => 1,
+ 'title' => 'Article Has and belongs to Many Tags'
+ ),
+ 'Tag' => array(
+ 'Tag' => array(1, 2)
+ ),
+ 'Comment' => array(
+ array(
+ 'comment' => 'Article comment',
+ 'user_id' => 1
+ )));
+ $Article =& new Article();
+ $result = $Article->saveAll($data);
+ $this->assertTrue($result);
+
+ $result = $Article->read();
+ $this->assertEqual(count($result['Tag']), 2);
+ $this->assertEqual($result['Tag'][0]['tag'], 'tag1');
+ $this->assertEqual(count($result['Comment']), 1);
+ $this->assertEqual(count($result['Comment'][0]['comment']['Article comment']), 1);
+ }
+
+/**
+ * Test SaveAll with Habtm relations and extra join table fields
+ *
+ * @access public
+ * @return void
+ */
+ function testSaveAllHabtmWithExtraJoinTableFields() {
+ $this->loadFixtures('Something', 'SomethingElse', 'JoinThing');
+
+ $data = array(
+ 'Something' => array(
+ 'id' => 4,
+ 'title' => 'Extra Fields',
+ 'body' => 'Extra Fields Body',
+ 'published' => '1'
+ ),
+ 'SomethingElse' => array(
+ array('something_else_id' => 1, 'doomed' => '1'),
+ array('something_else_id' => 2, 'doomed' => '0'),
+ array('something_else_id' => 3, 'doomed' => '1')
+ )
+ );
+
+ $Something =& new Something();
+ $result = $Something->saveAll($data);
+ $this->assertTrue($result);
+ $result = $Something->read();
+
+ $this->assertEqual(count($result['SomethingElse']), 3);
+ $this->assertTrue(Set::matches('/Something[id=4]', $result));
+
+ $this->assertTrue(Set::matches('/SomethingElse[id=1]', $result));
+ $this->assertTrue(Set::matches('/SomethingElse[id=1]/JoinThing[something_else_id=1]', $result));
+ $this->assertTrue(Set::matches('/SomethingElse[id=1]/JoinThing[doomed=1]', $result));
+
+ $this->assertTrue(Set::matches('/SomethingElse[id=2]', $result));
+ $this->assertTrue(Set::matches('/SomethingElse[id=2]/JoinThing[something_else_id=2]', $result));
+ $this->assertTrue(Set::matches('/SomethingElse[id=2]/JoinThing[doomed=0]', $result));
+
+ $this->assertTrue(Set::matches('/SomethingElse[id=3]', $result));
+ $this->assertTrue(Set::matches('/SomethingElse[id=3]/JoinThing[something_else_id=3]', $result));
+ $this->assertTrue(Set::matches('/SomethingElse[id=3]/JoinThing[doomed=1]', $result));
+ }
+
+/**
+ * testSaveAllHasOne method
+ *
+ * @access public
+ * @return void
+ */
+ function testSaveAllHasOne() {
+ $model = new Comment();
+ $model->deleteAll(true);
+ $this->assertEqual($model->find('all'), array());
+
+ $model->Attachment->deleteAll(true);
+ $this->assertEqual($model->Attachment->find('all'), array());
+
+ $this->assertTrue($model->saveAll(array(
+ 'Comment' => array(
+ 'comment' => 'Comment with attachment',
+ 'article_id' => 1,
+ 'user_id' => 1
+ ),
+ 'Attachment' => array(
+ 'attachment' => 'some_file.zip'
+ ))));
+ $result = $model->find('all', array('fields' => array(
+ 'Comment.id', 'Comment.comment', 'Attachment.id',
+ 'Attachment.comment_id', 'Attachment.attachment'
+ )));
+ $expected = array(array(
+ 'Comment' => array(
+ 'id' => '1',
+ 'comment' => 'Comment with attachment'
+ ),
+ 'Attachment' => array(
+ 'id' => '1',
+ 'comment_id' => '1',
+ 'attachment' => 'some_file.zip'
+ )));
+ $this->assertEqual($result, $expected);
+
+
+ $model->Attachment->bindModel(array('belongsTo' => array('Comment')), false);
+ $data = array(
+ 'Comment' => array(
+ 'comment' => 'Comment with attachment',
+ 'article_id' => 1,
+ 'user_id' => 1
+ ),
+ 'Attachment' => array(
+ 'attachment' => 'some_file.zip'
+ ));
+ $this->assertTrue($model->saveAll($data, array('validate' => 'first')));
+ }
+
+/**
+ * testSaveAllBelongsTo method
+ *
+ * @access public
+ * @return void
+ */
+ function testSaveAllBelongsTo() {
+ $model = new Comment();
+ $model->deleteAll(true);
+ $this->assertEqual($model->find('all'), array());
+
+ $model->Article->deleteAll(true);
+ $this->assertEqual($model->Article->find('all'), array());
+
+ $this->assertTrue($model->saveAll(array(
+ 'Comment' => array(
+ 'comment' => 'Article comment',
+ 'article_id' => 1,
+ 'user_id' => 1
+ ),
+ 'Article' => array(
+ 'title' => 'Model Associations 101',
+ 'user_id' => 1
+ ))));
+ $result = $model->find('all', array('fields' => array(
+ 'Comment.id', 'Comment.comment', 'Comment.article_id', 'Article.id', 'Article.title'
+ )));
+ $expected = array(array(
+ 'Comment' => array(
+ 'id' => '1',
+ 'article_id' => '1',
+ 'comment' => 'Article comment'
+ ),
+ 'Article' => array(
+ 'id' => '1',
+ 'title' => 'Model Associations 101'
+ )));
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testSaveAllHasOneValidation method
+ *
+ * @access public
+ * @return void
+ */
+ function testSaveAllHasOneValidation() {
+ $model = new Comment();
+ $model->deleteAll(true);
+ $this->assertEqual($model->find('all'), array());
+
+ $model->Attachment->deleteAll(true);
+ $this->assertEqual($model->Attachment->find('all'), array());
+
+ $model->validate = array('comment' => 'notEmpty');
+ $model->Attachment->validate = array('attachment' => 'notEmpty');
+ $model->Attachment->bindModel(array('belongsTo' => array('Comment')));
+
+ $this->assertFalse($model->saveAll(
+ array(
+ 'Comment' => array(
+ 'comment' => '',
+ 'article_id' => 1,
+ 'user_id' => 1
+ ),
+ 'Attachment' => array('attachment' => '')
+ ),
+ array('validate' => 'first')
+ ));
+ $expected = array(
+ 'Comment' => array('comment' => 'This field cannot be left blank'),
+ 'Attachment' => array('attachment' => 'This field cannot be left blank')
+ );
+ $this->assertEqual($model->validationErrors, $expected['Comment']);
+ $this->assertEqual($model->Attachment->validationErrors, $expected['Attachment']);
+
+ $this->assertFalse($model->saveAll(
+ array(
+ 'Comment' => array('comment' => '', 'article_id' => 1, 'user_id' => 1),
+ 'Attachment' => array('attachment' => '')
+ ),
+ array('validate' => 'only')
+ ));
+ $this->assertEqual($model->validationErrors, $expected['Comment']);
+ $this->assertEqual($model->Attachment->validationErrors, $expected['Attachment']);
+ }
+
+/**
+ * testSaveAllAtomic method
+ *
+ * @access public
+ * @return void
+ */
+ function testSaveAllAtomic() {
+ $this->loadFixtures('Article', 'User');
+ $TestModel =& new Article();
+
+ $result = $TestModel->saveAll(array(
+ 'Article' => array(
+ 'title' => 'Post with Author',
+ 'body' => 'This post will be saved with an author',
+ 'user_id' => 2
+ ),
+ 'Comment' => array(
+ array('comment' => 'First new comment', 'user_id' => 2))
+ ), array('atomic' => false));
+
+ $this->assertIdentical($result, array('Article' => true, 'Comment' => array(true)));
+
+ $result = $TestModel->saveAll(array(
+ array(
+ 'id' => '1',
+ 'title' => 'Baleeted First Post',
+ 'body' => 'Baleeted!',
+ 'published' => 'N'
+ ),
+ array(
+ 'id' => '2',
+ 'title' => 'Just update the title'
+ ),
+ array(
+ 'title' => 'Creating a fourth post',
+ 'body' => 'Fourth post body',
+ 'user_id' => 2
+ )
+ ), array('atomic' => false));
+ $this->assertIdentical($result, array(true, true, true));
+
+ $TestModel->validate = array('title' => 'notEmpty', 'author_id' => 'numeric');
+ $result = $TestModel->saveAll(array(
+ array(
+ 'id' => '1',
+ 'title' => 'Un-Baleeted First Post',
+ 'body' => 'Not Baleeted!',
+ 'published' => 'Y'
+ ),
+ array(
+ 'id' => '2',
+ 'title' => '',
+ 'body' => 'Trying to get away with an empty title'
+ )
+ ), array('validate' => true, 'atomic' => false));
+
+ $this->assertIdentical($result, array(true, false));
+
+ $result = $TestModel->saveAll(array(
+ 'Article' => array('id' => 2),
+ 'Comment' => array(
+ array(
+ 'comment' => 'First new comment',
+ 'published' => 'Y',
+ 'user_id' => 1
+ ),
+ array(
+ 'comment' => 'Second new comment',
+ 'published' => 'Y',
+ 'user_id' => 2
+ ))
+ ), array('validate' => true, 'atomic' => false));
+ $this->assertIdentical($result, array('Article' => true, 'Comment' => array(true, true)));
+ }
+
+/**
+ * testSaveAllHasMany method
+ *
+ * @access public
+ * @return void
+ */
+ function testSaveAllHasMany() {
+ $this->loadFixtures('Article', 'Comment');
+ $TestModel =& new Article();
+ $TestModel->belongsTo = $TestModel->hasAndBelongsToMany = array();
+
+ $result = $TestModel->saveAll(array(
+ 'Article' => array('id' => 2),
+ 'Comment' => array(
+ array('comment' => 'First new comment', 'published' => 'Y', 'user_id' => 1),
+ array('comment' => 'Second new comment', 'published' => 'Y', 'user_id' => 2)
+ )
+ ));
+ $this->assertTrue($result);
+
+ $result = $TestModel->findById(2);
+ $expected = array(
+ 'First Comment for Second Article',
+ 'Second Comment for Second Article',
+ 'First new comment',
+ 'Second new comment'
+ );
+ $this->assertEqual(Set::extract($result['Comment'], '{n}.comment'), $expected);
+
+ $result = $TestModel->saveAll(
+ array(
+ 'Article' => array('id' => 2),
+ 'Comment' => array(
+ array(
+ 'comment' => 'Third new comment',
+ 'published' => 'Y',
+ 'user_id' => 1
+ ))),
+ array('atomic' => false)
+ );
+ $this->assertTrue($result);
+
+ $result = $TestModel->findById(2);
+ $expected = array(
+ 'First Comment for Second Article',
+ 'Second Comment for Second Article',
+ 'First new comment',
+ 'Second new comment',
+ 'Third new comment'
+ );
+ $this->assertEqual(Set::extract($result['Comment'], '{n}.comment'), $expected);
+
+ $TestModel->beforeSaveReturn = false;
+ $result = $TestModel->saveAll(
+ array(
+ 'Article' => array('id' => 2),
+ 'Comment' => array(
+ array(
+ 'comment' => 'Fourth new comment',
+ 'published' => 'Y',
+ 'user_id' => 1
+ ))),
+ array('atomic' => false)
+ );
+ $this->assertEqual($result, array('Article' => false));
+
+ $result = $TestModel->findById(2);
+ $expected = array(
+ 'First Comment for Second Article',
+ 'Second Comment for Second Article',
+ 'First new comment',
+ 'Second new comment',
+ 'Third new comment'
+ );
+ $this->assertEqual(Set::extract($result['Comment'], '{n}.comment'), $expected);
+ }
+
+/**
+ * testSaveAllHasManyValidation method
+ *
+ * @access public
+ * @return void
+ */
+ function testSaveAllHasManyValidation() {
+ $this->loadFixtures('Article', 'Comment');
+ $TestModel =& new Article();
+ $TestModel->belongsTo = $TestModel->hasAndBelongsToMany = array();
+ $TestModel->Comment->validate = array('comment' => 'notEmpty');
+
+ $result = $TestModel->saveAll(array(
+ 'Article' => array('id' => 2),
+ 'Comment' => array(
+ array('comment' => '', 'published' => 'Y', 'user_id' => 1),
+ )
+ ), array('validate' => true));
+ $expected = array('Comment' => array(false));
+ $this->assertEqual($result, $expected);
+
+ $expected = array('Comment' => array(
+ array('comment' => 'This field cannot be left blank')
+ ));
+ $this->assertEqual($TestModel->validationErrors, $expected);
+ $expected = array(
+ array('comment' => 'This field cannot be left blank')
+ );
+ $this->assertEqual($TestModel->Comment->validationErrors, $expected);
+
+ $result = $TestModel->saveAll(array(
+ 'Article' => array('id' => 2),
+ 'Comment' => array(
+ array(
+ 'comment' => '',
+ 'published' => 'Y',
+ 'user_id' => 1
+ ))
+ ), array('validate' => 'first'));
+ $this->assertFalse($result);
+ }
+
+/**
+ * test saveAll with transactions and ensure there is no missing rollback.
+ *
+ * @return void
+ */
+ function testSaveAllManyRowsTransactionNoRollback() {
+ $this->loadFixtures('Post');
+
+ Mock::generate('DboSource', 'MockTransactionDboSource');
+ $db = ConnectionManager::create('mock_transaction', array(
+ 'datasource' => 'MockTransactionDbo',
+ ));
+ $db->expectOnce('rollback');
+
+ $Post =& new Post();
+ $Post->useDbConfig = 'mock_transaction';
+
+ $Post->validate = array(
+ 'title' => array('rule' => array('notEmpty'))
+ );
+
+ $data = array(
+ array('author_id' => 1, 'title' => 'New Fourth Post'),
+ array('author_id' => 1, 'title' => '')
+ );
+ $Post->saveAll($data, array('atomic' => true));
+ }
+
+/**
+ * test saveAll with transactions and ensure there is no missing rollback.
+ *
+ * @return void
+ */
+ function testSaveAllAssociatedTransactionNoRollback() {
+ $testDb = ConnectionManager::getDataSource('test_suite');
+
+ Mock::generate('DboSource', 'MockTransactionAssociatedDboSource');
+ $db = ConnectionManager::create('mock_transaction_assoc', array(
+ 'datasource' => 'MockTransactionAssociatedDbo',
+ ));
+ $db->columns = $testDb->columns;
+
+ $db->expectOnce('rollback');
+
+ $Post =& new Post();
+ $Post->useDbConfig = 'mock_transaction_assoc';
+ $Post->Author->useDbConfig = 'mock_transaction_assoc';
+
+ $Post->Author->validate = array(
+ 'user' => array('rule' => array('notEmpty'))
+ );
+
+ $data = array(
+ 'Post' => array(
+ 'title' => 'New post',
+ 'body' => 'Content',
+ 'published' => 'Y'
+ ),
+ 'Author' => array(
+ 'user' => '',
+ 'password' => "sekret"
+ )
+ );
+ $Post->saveAll($data);
+ }
+
+/**
+ * test saveAll with nested saveAll call.
+ *
+ * @return void
+ */
+ function testSaveAllNestedSaveAll() {
+ $this->loadFixtures('Sample');
+ $TransactionTestModel =& new TransactionTestModel();
+
+ $data = array(
+ array('apple_id' => 1, 'name' => 'sample5'),
+ );
+
+ $this->assertTrue($TransactionTestModel->saveAll($data, array('atomic' => true)));
+ }
+
+/**
+ * testSaveAllTransaction method
+ *
+ * @access public
+ * @return void
+ */
+ function testSaveAllTransaction() {
+ $this->loadFixtures('Post', 'Author', 'Comment', 'Attachment');
+ $TestModel =& new Post();
+
+ $TestModel->validate = array('title' => 'notEmpty');
+ $data = array(
+ array('author_id' => 1, 'title' => 'New Fourth Post'),
+ array('author_id' => 1, 'title' => 'New Fifth Post'),
+ array('author_id' => 1, 'title' => '')
+ );
+ $ts = date('Y-m-d H:i:s');
+ $this->assertFalse($TestModel->saveAll($data));
+
+ $result = $TestModel->find('all', array('recursive' => -1));
+ $expected = array(
+ array('Post' => array(
+ 'id' => '1',
+ 'author_id' => 1,
+ 'title' => 'First Post',
+ 'body' => 'First Post Body',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:39:23',
+ 'updated' => '2007-03-18 10:41:31'
+ )),
+ array('Post' => array(
+ 'id' => '2',
+ 'author_id' => 3,
+ 'title' => 'Second Post',
+ 'body' => 'Second Post Body',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:41:23',
+ 'updated' => '2007-03-18 10:43:31'
+ )),
+ array('Post' => array(
+ 'id' => '3',
+ 'author_id' => 1,
+ 'title' => 'Third Post',
+ 'body' => 'Third Post Body',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:43:23',
+ 'updated' => '2007-03-18 10:45:31'
+ )));
+
+ if (count($result) != 3) {
+ // Database doesn't support transactions
+ $expected[] = array(
+ 'Post' => array(
+ 'id' => '4',
+ 'author_id' => 1,
+ 'title' => 'New Fourth Post',
+ 'body' => null,
+ 'published' => 'N',
+ 'created' => $ts,
+ 'updated' => $ts
+ ));
+
+ $expected[] = array(
+ 'Post' => array(
+ 'id' => '5',
+ 'author_id' => 1,
+ 'title' => 'New Fifth Post',
+ 'body' => null,
+ 'published' => 'N',
+ 'created' => $ts,
+ 'updated' => $ts
+ ));
+
+ $this->assertEqual($result, $expected);
+ // Skip the rest of the transactional tests
+ return;
+ }
+
+ $this->assertEqual($result, $expected);
+
+ $data = array(
+ array('author_id' => 1, 'title' => 'New Fourth Post'),
+ array('author_id' => 1, 'title' => ''),
+ array('author_id' => 1, 'title' => 'New Sixth Post')
+ );
+ $ts = date('Y-m-d H:i:s');
+ $this->assertFalse($TestModel->saveAll($data));
+
+ $result = $TestModel->find('all', array('recursive' => -1));
+ $expected = array(
+ array('Post' => array(
+ 'id' => '1',
+ 'author_id' => 1,
+ 'title' => 'First Post',
+ 'body' => 'First Post Body',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:39:23',
+ 'updated' => '2007-03-18 10:41:31'
+ )),
+ array('Post' => array(
+ 'id' => '2',
+ 'author_id' => 3,
+ 'title' => 'Second Post',
+ 'body' => 'Second Post Body',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:41:23',
+ 'updated' => '2007-03-18 10:43:31'
+ )),
+ array('Post' => array(
+ 'id' => '3',
+ 'author_id' => 1,
+ 'title' => 'Third Post',
+ 'body' => 'Third Post Body',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:43:23',
+ 'updated' => '2007-03-18 10:45:31'
+ )));
+
+ if (count($result) != 3) {
+ // Database doesn't support transactions
+ $expected[] = array(
+ 'Post' => array(
+ 'id' => '4',
+ 'author_id' => 1,
+ 'title' => 'New Fourth Post',
+ 'body' => 'Third Post Body',
+ 'published' => 'N',
+ 'created' => $ts,
+ 'updated' => $ts
+ ));
+
+ $expected[] = array(
+ 'Post' => array(
+ 'id' => '5',
+ 'author_id' => 1,
+ 'title' => 'Third Post',
+ 'body' => 'Third Post Body',
+ 'published' => 'N',
+ 'created' => $ts,
+ 'updated' => $ts
+ ));
+ }
+ $this->assertEqual($result, $expected);
+
+ $TestModel->validate = array('title' => 'notEmpty');
+ $data = array(
+ array('author_id' => 1, 'title' => 'New Fourth Post'),
+ array('author_id' => 1, 'title' => 'New Fifth Post'),
+ array('author_id' => 1, 'title' => 'New Sixth Post')
+ );
+ $this->assertTrue($TestModel->saveAll($data));
+
+ $result = $TestModel->find('all', array(
+ 'recursive' => -1,
+ 'fields' => array('author_id', 'title','body','published')
+ ));
+
+ $expected = array(
+ array('Post' => array(
+ 'author_id' => 1,
+ 'title' => 'First Post',
+ 'body' => 'First Post Body',
+ 'published' => 'Y'
+ )),
+ array('Post' => array(
+ 'author_id' => 3,
+ 'title' => 'Second Post',
+ 'body' => 'Second Post Body',
+ 'published' => 'Y'
+ )),
+ array('Post' => array(
+ 'author_id' => 1,
+ 'title' => 'Third Post',
+ 'body' => 'Third Post Body',
+ 'published' => 'Y'
+ )),
+ array('Post' => array(
+ 'author_id' => 1,
+ 'title' => 'New Fourth Post',
+ 'body' => '',
+ 'published' => 'N'
+ )),
+ array('Post' => array(
+ 'author_id' => 1,
+ 'title' => 'New Fifth Post',
+ 'body' => '',
+ 'published' => 'N'
+ )),
+ array('Post' => array(
+ 'author_id' => 1,
+ 'title' => 'New Sixth Post',
+ 'body' => '',
+ 'published' => 'N'
+ )));
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testSaveAllValidation method
+ *
+ * @access public
+ * @return void
+ */
+ function testSaveAllValidation() {
+ $this->loadFixtures('Post', 'Author', 'Comment', 'Attachment');
+ $TestModel =& new Post();
+
+ $data = array(
+ array(
+ 'id' => '1',
+ 'title' => 'Baleeted First Post',
+ 'body' => 'Baleeted!',
+ 'published' => 'N'
+ ),
+ array(
+ 'id' => '2',
+ 'title' => 'Just update the title'
+ ),
+ array(
+ 'title' => 'Creating a fourth post',
+ 'body' => 'Fourth post body',
+ 'author_id' => 2
+ ));
+
+ $this->assertTrue($TestModel->saveAll($data));
+
+ $result = $TestModel->find('all', array('recursive' => -1, 'order' => 'Post.id ASC'));
+ $ts = date('Y-m-d H:i:s');
+ $expected = array(
+ array(
+ 'Post' => array(
+ 'id' => '1',
+ 'author_id' => '1',
+ 'title' => 'Baleeted First Post',
+ 'body' => 'Baleeted!',
+ 'published' => 'N',
+ 'created' => '2007-03-18 10:39:23',
+ 'updated' => $ts
+ )),
+ array(
+ 'Post' => array(
+ 'id' => '2',
+ 'author_id' => '3',
+ 'title' => 'Just update the title',
+ 'body' => 'Second Post Body',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:41:23', 'updated' => $ts
+ )),
+ array(
+ 'Post' => array(
+ 'id' => '3',
+ 'author_id' => '1',
+ 'title' => 'Third Post',
+ 'body' => 'Third Post Body',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:43:23',
+ 'updated' => '2007-03-18 10:45:31'
+ )),
+ array(
+ 'Post' => array(
+ 'id' => '4',
+ 'author_id' => '2',
+ 'title' => 'Creating a fourth post',
+ 'body' => 'Fourth post body',
+ 'published' => 'N',
+ 'created' => $ts,
+ 'updated' => $ts
+ )));
+ $this->assertEqual($result, $expected);
+
+ $TestModel->validate = array('title' => 'notEmpty', 'author_id' => 'numeric');
+ $data = array(
+ array(
+ 'id' => '1',
+ 'title' => 'Un-Baleeted First Post',
+ 'body' => 'Not Baleeted!',
+ 'published' => 'Y'
+ ),
+ array(
+ 'id' => '2',
+ 'title' => '',
+ 'body' => 'Trying to get away with an empty title'
+ ));
+ $result = $TestModel->saveAll($data);
+ $this->assertEqual($result, false);
+
+ $result = $TestModel->find('all', array('recursive' => -1, 'order' => 'Post.id ASC'));
+ $errors = array(1 => array('title' => 'This field cannot be left blank'));
+ $transactionWorked = Set::matches('/Post[1][title=Baleeted First Post]', $result);
+ if (!$transactionWorked) {
+ $this->assertTrue(Set::matches('/Post[1][title=Un-Baleeted First Post]', $result));
+ $this->assertTrue(Set::matches('/Post[2][title=Just update the title]', $result));
+ }
+
+ $this->assertEqual($TestModel->validationErrors, $errors);
+
+ $TestModel->validate = array('title' => 'notEmpty', 'author_id' => 'numeric');
+ $data = array(
+ array(
+ 'id' => '1',
+ 'title' => 'Un-Baleeted First Post',
+ 'body' => 'Not Baleeted!',
+ 'published' => 'Y'
+ ),
+ array(
+ 'id' => '2',
+ 'title' => '',
+ 'body' => 'Trying to get away with an empty title'
+ ));
+ $result = $TestModel->saveAll($data, array('validate' => true, 'atomic' => false));
+ $this->assertEqual($result, array(true, false));
+ $result = $TestModel->find('all', array('recursive' => -1, 'order' => 'Post.id ASC'));
+ $errors = array(1 => array('title' => 'This field cannot be left blank'));
+ $newTs = date('Y-m-d H:i:s');
+ $expected = array(
+ array(
+ 'Post' => array(
+ 'id' => '1',
+ 'author_id' => '1',
+ 'title' => 'Un-Baleeted First Post',
+ 'body' => 'Not Baleeted!',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:39:23',
+ 'updated' => $newTs
+ )),
+ array(
+ 'Post' => array(
+ 'id' => '2',
+ 'author_id' => '3',
+ 'title' => 'Just update the title',
+ 'body' => 'Second Post Body',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:41:23',
+ 'updated' => $ts
+ )),
+ array(
+ 'Post' => array(
+ 'id' => '3',
+ 'author_id' => '1',
+ 'title' => 'Third Post',
+ 'body' => 'Third Post Body',
+ 'published' => 'Y',
+ 'created' => '2007-03-18 10:43:23',
+ 'updated' => '2007-03-18 10:45:31'
+ )),
+ array(
+ 'Post' => array(
+ 'id' => '4',
+ 'author_id' => '2',
+ 'title' => 'Creating a fourth post',
+ 'body' => 'Fourth post body',
+ 'published' => 'N',
+ 'created' => $ts,
+ 'updated' => $ts
+ )));
+ $this->assertEqual($result, $expected);
+ $this->assertEqual($TestModel->validationErrors, $errors);
+
+ $data = array(
+ array(
+ 'id' => '1',
+ 'title' => 'Re-Baleeted First Post',
+ 'body' => 'Baleeted!',
+ 'published' => 'N'
+ ),
+ array(
+ 'id' => '2',
+ 'title' => '',
+ 'body' => 'Trying to get away with an empty title'
+ ));
+ $this->assertFalse($TestModel->saveAll($data, array('validate' => 'first')));
+
+ $result = $TestModel->find('all', array('recursive' => -1, 'order' => 'Post.id ASC'));
+ $this->assertEqual($result, $expected);
+ $this->assertEqual($TestModel->validationErrors, $errors);
+
+ $data = array(
+ array(
+ 'title' => 'First new post',
+ 'body' => 'Woohoo!',
+ 'published' => 'Y'
+ ),
+ array(
+ 'title' => 'Empty body',
+ 'body' => ''
+ ));
+
+ $TestModel->validate['body'] = 'notEmpty';
+ }
+
+/**
+ * testSaveAllValidationOnly method
+ *
+ * @access public
+ * @return void
+ */
+ function testSaveAllValidationOnly() {
+ $TestModel =& new Comment();
+ $TestModel->Attachment->validate = array('attachment' => 'notEmpty');
+
+ $data = array(
+ 'Comment' => array(
+ 'comment' => 'This is the comment'
+ ),
+ 'Attachment' => array(
+ 'attachment' => ''
+ )
+ );
+
+ $result = $TestModel->saveAll($data, array('validate' => 'only'));
+ $this->assertFalse($result);
+
+ $TestModel =& new Article();
+ $TestModel->validate = array('title' => 'notEmpty');
+ $result = $TestModel->saveAll(
+ array(
+ 0 => array('title' => ''),
+ 1 => array('title' => 'title 1'),
+ 2 => array('title' => 'title 2'),
+ ),
+ array('validate'=>'only')
+ );
+ $this->assertFalse($result);
+ $expected = array(
+ 0 => array('title' => 'This field cannot be left blank'),
+ );
+ $this->assertEqual($TestModel->validationErrors, $expected);
+
+ $result = $TestModel->saveAll(
+ array(
+ 0 => array('title' => 'title 0'),
+ 1 => array('title' => ''),
+ 2 => array('title' => 'title 2'),
+ ),
+ array('validate'=>'only')
+ );
+ $this->assertFalse($result);
+ $expected = array(
+ 1 => array('title' => 'This field cannot be left blank'),
+ );
+ $this->assertEqual($TestModel->validationErrors, $expected);
+ }
+
+/**
+ * testSaveAllValidateFirst method
+ *
+ * @access public
+ * @return void
+ */
+ function testSaveAllValidateFirst() {
+ $model =& new Article();
+ $model->deleteAll(true);
+
+ $model->Comment->validate = array('comment' => 'notEmpty');
+ $result = $model->saveAll(array(
+ 'Article' => array(
+ 'title' => 'Post with Author',
+ 'body' => 'This post will be saved author'
+ ),
+ 'Comment' => array(
+ array('comment' => 'First new comment'),
+ array('comment' => '')
+ )
+ ), array('validate' => 'first'));
+
+ $this->assertFalse($result);
+
+ $result = $model->find('all');
+ $this->assertEqual($result, array());
+ $expected = array('Comment' => array(
+ 1 => array('comment' => 'This field cannot be left blank')
+ ));
+
+ $this->assertEqual($model->Comment->validationErrors, $expected['Comment']);
+
+ $this->assertIdentical($model->Comment->find('count'), 0);
+
+ $result = $model->saveAll(
+ array(
+ 'Article' => array(
+ 'title' => 'Post with Author',
+ 'body' => 'This post will be saved with an author',
+ 'user_id' => 2
+ ),
+ 'Comment' => array(
+ array(
+ 'comment' => 'Only new comment',
+ 'user_id' => 2
+ ))),
+ array('validate' => 'first')
+ );
+
+ $this->assertIdentical($result, true);
+
+ $result = $model->Comment->find('all');
+ $this->assertIdentical(count($result), 1);
+ $result = Set::extract('/Comment/article_id', $result);
+ $this->assertTrue($result[0] === 1 || $result[0] === '1');
+
+
+ $model->deleteAll(true);
+ $data = array(
+ 'Article' => array(
+ 'title' => 'Post with Author saveAlled from comment',
+ 'body' => 'This post will be saved with an author',
+ 'user_id' => 2
+ ),
+ 'Comment' => array(
+ 'comment' => 'Only new comment', 'user_id' => 2
+ ));
+
+ $result = $model->Comment->saveAll($data, array('validate' => 'first'));
+ $this->assertTrue($result);
+
+ $result = $model->find('all');
+ $this->assertEqual(
+ $result[0]['Article']['title'],
+ 'Post with Author saveAlled from comment'
+ );
+ $this->assertEqual($result[0]['Comment'][0]['comment'], 'Only new comment');
+ }
+
+/**
+ * test saveAll()'s return is correct when using atomic = false and validate = first.
+ *
+ * @return void
+ */
+ function testSaveAllValidateFirstAtomicFalse() {
+ $Something =& new Something();
+ $invalidData = array(
+ array(
+ 'title' => 'foo',
+ 'body' => 'bar',
+ 'published' => 'baz',
+ ),
+ array(
+ 'body' => 3,
+ 'published' =>'sd',
+ ),
+ );
+ $Something->create();
+ $Something->validate = array(
+ 'title' => array(
+ 'rule' => 'alphaNumeric',
+ 'required' => true,
+ ),
+ 'body' => array(
+ 'rule' => 'alphaNumeric',
+ 'required' => true,
+ 'allowEmpty' => true,
+ ),
+ );
+ $result = $Something->saveAll($invalidData, array(
+ 'atomic' => false,
+ 'validate' => 'first',
+ ));
+ $expected = array(true, false);
+ $this->assertEqual($result, $expected);
+
+ $Something =& new Something();
+ $validData = array(
+ array(
+ 'title' => 'title value',
+ 'body' => 'body value',
+ 'published' => 'baz',
+ ),
+ array(
+ 'title' => 'valid',
+ 'body' => 'this body',
+ 'published' =>'sd',
+ ),
+ );
+ $Something->create();
+ $result = $Something->saveAll($validData, array(
+ 'atomic' => false,
+ 'validate' => 'first',
+ ));
+ $expected = array(true, true);
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testUpdateWithCalculation method
+ *
+ * @access public
+ * @return void
+ */
+ function testUpdateWithCalculation() {
+ $this->loadFixtures('DataTest');
+ $model =& new DataTest();
+ $model->deleteAll(true);
+ $result = $model->saveAll(array(
+ array('count' => 5, 'float' => 1.1),
+ array('count' => 3, 'float' => 1.2),
+ array('count' => 4, 'float' => 1.3),
+ array('count' => 1, 'float' => 2.0),
+ ));
+ $this->assertTrue($result);
+
+ $result = Set::extract('/DataTest/count', $model->find('all', array('fields' => 'count')));
+ $this->assertEqual($result, array(5, 3, 4, 1));
+
+ $this->assertTrue($model->updateAll(array('count' => 'count + 2')));
+ $result = Set::extract('/DataTest/count', $model->find('all', array('fields' => 'count')));
+ $this->assertEqual($result, array(7, 5, 6, 3));
+
+ $this->assertTrue($model->updateAll(array('DataTest.count' => 'DataTest.count - 1')));
+ $result = Set::extract('/DataTest/count', $model->find('all', array('fields' => 'count')));
+ $this->assertEqual($result, array(6, 4, 5, 2));
+ }
+
+/**
+ * testSaveAllHasManyValidationOnly method
+ *
+ * @access public
+ * @return void
+ */
+ function testSaveAllHasManyValidationOnly() {
+ $this->loadFixtures('Article', 'Comment');
+ $TestModel =& new Article();
+ $TestModel->belongsTo = $TestModel->hasAndBelongsToMany = array();
+ $TestModel->Comment->validate = array('comment' => 'notEmpty');
+
+ $result = $TestModel->saveAll(
+ array(
+ 'Article' => array('id' => 2),
+ 'Comment' => array(
+ array(
+ 'id' => 1,
+ 'comment' => '',
+ 'published' => 'Y',
+ 'user_id' => 1),
+ array(
+ 'id' => 2,
+ 'comment' =>
+ 'comment',
+ 'published' => 'Y',
+ 'user_id' => 1
+ ))),
+ array('validate' => 'only')
+ );
+ $this->assertFalse($result);
+
+ $result = $TestModel->saveAll(
+ array(
+ 'Article' => array('id' => 2),
+ 'Comment' => array(
+ array(
+ 'id' => 1,
+ 'comment' => '',
+ 'published' => 'Y',
+ 'user_id' => 1
+ ),
+ array(
+ 'id' => 2,
+ 'comment' => 'comment',
+ 'published' => 'Y',
+ 'user_id' => 1
+ ),
+ array(
+ 'id' => 3,
+ 'comment' => '',
+ 'published' => 'Y',
+ 'user_id' => 1
+ ))),
+ array(
+ 'validate' => 'only',
+ 'atomic' => false
+ ));
+ $expected = array(
+ 'Article' => true,
+ 'Comment' => array(false, true, false)
+ );
+ $this->assertIdentical($result, $expected);
+
+ $expected = array('Comment' => array(
+ 0 => array('comment' => 'This field cannot be left blank'),
+ 2 => array('comment' => 'This field cannot be left blank')
+ ));
+ $this->assertEqual($TestModel->validationErrors, $expected);
+
+ $expected = array(
+ 0 => array('comment' => 'This field cannot be left blank'),
+ 2 => array('comment' => 'This field cannot be left blank')
+ );
+ $this->assertEqual($TestModel->Comment->validationErrors, $expected);
+ }
+
+/**
+ * TestFindAllWithoutForeignKey
+ *
+ * @link http://code.cakephp.org/tickets/view/69
+ * @access public
+ * @return void
+ */
+ function testFindAllForeignKey() {
+ $this->loadFixtures('ProductUpdateAll', 'GroupUpdateAll');
+ $ProductUpdateAll =& new ProductUpdateAll();
+
+ $conditions = array('Group.name' => 'group one');
+
+ $ProductUpdateAll->bindModel(array(
+ 'belongsTo' => array(
+ 'Group' => array('className' => 'GroupUpdateAll')
+ )
+ ));
+
+ $ProductUpdateAll->belongsTo = array(
+ 'Group' => array('className' => 'GroupUpdateAll', 'foreignKey' => 'group_id')
+ );
+
+ $results = $ProductUpdateAll->find('all', compact('conditions'));
+ $this->assertTrue(!empty($results));
+
+ $ProductUpdateAll->bindModel(array('belongsTo'=>array('Group')));
+ $ProductUpdateAll->belongsTo = array(
+ 'Group' => array(
+ 'className' => 'GroupUpdateAll',
+ 'foreignKey' => false,
+ 'conditions' => 'ProductUpdateAll.groupcode = Group.code'
+ ));
+
+ $resultsFkFalse = $ProductUpdateAll->find('all', compact('conditions'));
+ $this->assertTrue(!empty($resultsFkFalse));
+ $expected = array(
+ '0' => array(
+ 'ProductUpdateAll' => array(
+ 'id' => 1,
+ 'name' => 'product one',
+ 'groupcode' => 120,
+ 'group_id' => 1),
+ 'Group' => array(
+ 'id' => 1,
+ 'name' => 'group one',
+ 'code' => 120)
+ ),
+ '1' => array(
+ 'ProductUpdateAll' => array(
+ 'id' => 2,
+ 'name' => 'product two',
+ 'groupcode' => 120,
+ 'group_id' => 1),
+ 'Group' => array(
+ 'id' => 1,
+ 'name' => 'group one',
+ 'code' => 120)
+ )
+
+ );
+ $this->assertEqual($results, $expected);
+ $this->assertEqual($resultsFkFalse, $expected);
+ }
+
+/**
+ * test updateAll with empty values.
+ *
+ * @return void
+ */
+ function testUpdateAllEmptyValues() {
+ $this->loadFixtures('Author', 'Post');
+ $model = new Author();
+ $result = $model->updateAll(array('user' => '""'));
+ $this->assertTrue($result);
+ }
+
+/**
+ * testUpdateAllWithJoins
+ *
+ * @link http://code.cakephp.org/tickets/view/69
+ * @access public
+ * @return void
+ */
+ function testUpdateAllWithJoins() {
+ $this->skipIf(
+ $this->db->config['driver'] == 'postgres',
+ '%s Currently, there is no way of doing joins in an update statement in postgresql'
+ );
+ $this->loadFixtures('ProductUpdateAll', 'GroupUpdateAll');
+ $ProductUpdateAll =& new ProductUpdateAll();
+
+ $conditions = array('Group.name' => 'group one');
+
+ $ProductUpdateAll->bindModel(array('belongsTo' => array(
+ 'Group' => array('className' => 'GroupUpdateAll')))
+ );
+
+ $ProductUpdateAll->updateAll(array('name' => "'new product'"), $conditions);
+ $results = $ProductUpdateAll->find('all', array(
+ 'conditions' => array('ProductUpdateAll.name' => 'new product')
+ ));
+ $expected = array(
+ '0' => array(
+ 'ProductUpdateAll' => array(
+ 'id' => 1,
+ 'name' => 'new product',
+ 'groupcode' => 120,
+ 'group_id' => 1),
+ 'Group' => array(
+ 'id' => 1,
+ 'name' => 'group one',
+ 'code' => 120)
+ ),
+ '1' => array(
+ 'ProductUpdateAll' => array(
+ 'id' => 2,
+ 'name' => 'new product',
+ 'groupcode' => 120,
+ 'group_id' => 1),
+ 'Group' => array(
+ 'id' => 1,
+ 'name' => 'group one',
+ 'code' => 120)));
+
+ $this->assertEqual($results, $expected);
+ }
+
+/**
+ * testUpdateAllWithoutForeignKey
+ *
+ * @link http://code.cakephp.org/tickets/view/69
+ * @access public
+ * @return void
+ */
+ function testUpdateAllWithoutForeignKey() {
+ $this->skipIf(
+ $this->db->config['driver'] == 'postgres',
+ '%s Currently, there is no way of doing joins in an update statement in postgresql'
+ );
+ $this->loadFixtures('ProductUpdateAll', 'GroupUpdateAll');
+ $ProductUpdateAll =& new ProductUpdateAll();
+
+ $conditions = array('Group.name' => 'group one');
+
+ $ProductUpdateAll->bindModel(array('belongsTo' => array(
+ 'Group' => array('className' => 'GroupUpdateAll')
+ )));
+
+ $ProductUpdateAll->belongsTo = array(
+ 'Group' => array(
+ 'className' => 'GroupUpdateAll',
+ 'foreignKey' => false,
+ 'conditions' => 'ProductUpdateAll.groupcode = Group.code'
+ )
+ );
+
+ $ProductUpdateAll->updateAll(array('name' => "'new product'"), $conditions);
+ $resultsFkFalse = $ProductUpdateAll->find('all', array('conditions' => array('ProductUpdateAll.name'=>'new product')));
+ $expected = array(
+ '0' => array(
+ 'ProductUpdateAll' => array(
+ 'id' => 1,
+ 'name' => 'new product',
+ 'groupcode' => 120,
+ 'group_id' => 1),
+ 'Group' => array(
+ 'id' => 1,
+ 'name' => 'group one',
+ 'code' => 120)
+ ),
+ '1' => array(
+ 'ProductUpdateAll' => array(
+ 'id' => 2,
+ 'name' => 'new product',
+ 'groupcode' => 120,
+ 'group_id' => 1),
+ 'Group' => array(
+ 'id' => 1,
+ 'name' => 'group one',
+ 'code' => 120)));
+ $this->assertEqual($resultsFkFalse, $expected);
+ }
+
+/**
+ * test that saveAll behaves like plain save() when suplied empty data
+ *
+ * @link http://cakephp.lighthouseapp.com/projects/42648/tickets/277-test-saveall-with-validation-returns-incorrect-boolean-when-saving-empty-data
+ * @access public
+ * @return void
+ */
+ function testSaveAllEmptyData() {
+ $this->loadFixtures('Article', 'ProductUpdateAll');
+ $model =& new Article();
+ $result = $model->saveAll(array(), array('validate' => 'first'));
+ $this->assertTrue($result);
+
+ $model =& new ProductUpdateAll();
+ $result = $model->saveAll(array());
+ $this->assertFalse($result);
+ }
+
+/**
+ * test writing floats in german locale.
+ *
+ * @return void
+ */
+ function testWriteFloatAsGerman() {
+ $restore = setlocale(LC_ALL, null);
+ setlocale(LC_ALL, 'de_DE');
+
+ $model = new DataTest();
+ $result = $model->save(array(
+ 'count' => 1,
+ 'float' => 3.14593
+ ));
+ $this->assertTrue($result);
+ setlocale(LC_ALL, $restore);
+ }
+
+}
diff --git a/code/ryzom/tools/server/www/webtt/cake/tests/cases/libs/model/models.php b/code/ryzom/tools/server/www/webtt/cake/tests/cases/libs/model/models.php
new file mode 100644
index 000000000..febb073cc
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/cake/tests/cases/libs/model/models.php
@@ -0,0 +1,3594 @@
+
+ * Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
+ *
+ * Licensed under The Open Group Test Suite License
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
+ * @link http://book.cakephp.org/view/1196/Testing CakePHP(tm) Tests
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ * @since CakePHP(tm) v 1.2.0.6464
+ * @license http://www.opensource.org/licenses/opengroup.php The Open Group Test Suite License
+ */
+if (!defined('CAKEPHP_UNIT_TEST_EXECUTION')) {
+ define('CAKEPHP_UNIT_TEST_EXECUTION', 1);
+}
+
+/**
+ * Test class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class Test extends CakeTestModel {
+
+/**
+ * useTable property
+ *
+ * @var bool false
+ * @access public
+ */
+ var $useTable = false;
+
+/**
+ * name property
+ *
+ * @var string 'Test'
+ * @access public
+ */
+ var $name = 'Test';
+
+/**
+ * schema property
+ *
+ * @var array
+ * @access protected
+ */
+ var $_schema = array(
+ 'id'=> array('type' => 'integer', 'null' => '', 'default' => '1', 'length' => '8', 'key'=>'primary'),
+ 'name'=> array('type' => 'string', 'null' => '', 'default' => '', 'length' => '255'),
+ 'email'=> array('type' => 'string', 'null' => '1', 'default' => '', 'length' => '155'),
+ 'notes'=> array('type' => 'text', 'null' => '1', 'default' => 'write some notes here', 'length' => ''),
+ 'created'=> array('type' => 'date', 'null' => '1', 'default' => '', 'length' => ''),
+ 'updated'=> array('type' => 'datetime', 'null' => '1', 'default' => '', 'length' => null)
+ );
+}
+
+/**
+ * TestAlias class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class TestAlias extends CakeTestModel {
+
+/**
+ * useTable property
+ *
+ * @var bool false
+ * @access public
+ */
+ var $useTable = false;
+
+/**
+ * name property
+ *
+ * @var string 'TestAlias'
+ * @access public
+ */
+ var $name = 'TestAlias';
+
+/**
+ * alias property
+ *
+ * @var string 'TestAlias'
+ * @access public
+ */
+ var $alias = 'TestAlias';
+
+/**
+ * schema property
+ *
+ * @var array
+ * @access protected
+ */
+ var $_schema = array(
+ 'id'=> array('type' => 'integer', 'null' => '', 'default' => '1', 'length' => '8', 'key'=>'primary'),
+ 'name'=> array('type' => 'string', 'null' => '', 'default' => '', 'length' => '255'),
+ 'email'=> array('type' => 'string', 'null' => '1', 'default' => '', 'length' => '155'),
+ 'notes'=> array('type' => 'text', 'null' => '1', 'default' => 'write some notes here', 'length' => ''),
+ 'created'=> array('type' => 'date', 'null' => '1', 'default' => '', 'length' => ''),
+ 'updated'=> array('type' => 'datetime', 'null' => '1', 'default' => '', 'length' => null)
+ );
+}
+
+/**
+ * TestValidate class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class TestValidate extends CakeTestModel {
+
+/**
+ * useTable property
+ *
+ * @var bool false
+ * @access public
+ */
+ var $useTable = false;
+
+/**
+ * name property
+ *
+ * @var string 'TestValidate'
+ * @access public
+ */
+ var $name = 'TestValidate';
+
+/**
+ * schema property
+ *
+ * @var array
+ * @access protected
+ */
+ var $_schema = array(
+ 'id' => array('type' => 'integer', 'null' => '', 'default' => '', 'length' => '8'),
+ 'title' => array('type' => 'string', 'null' => '', 'default' => '', 'length' => '255'),
+ 'body' => array('type' => 'string', 'null' => '1', 'default' => '', 'length' => ''),
+ 'number' => array('type' => 'integer', 'null' => '', 'default' => '', 'length' => '8'),
+ 'created' => array('type' => 'date', 'null' => '1', 'default' => '', 'length' => ''),
+ 'modified' => array('type' => 'datetime', 'null' => '1', 'default' => '', 'length' => null)
+ );
+
+/**
+ * validateNumber method
+ *
+ * @param mixed $value
+ * @param mixed $options
+ * @access public
+ * @return void
+ */
+ function validateNumber($value, $options) {
+ $options = array_merge(array('min' => 0, 'max' => 100), $options);
+ $valid = ($value['number'] >= $options['min'] && $value['number'] <= $options['max']);
+ return $valid;
+ }
+
+/**
+ * validateTitle method
+ *
+ * @param mixed $value
+ * @access public
+ * @return void
+ */
+ function validateTitle($value) {
+ return (!empty($value) && strpos(low($value['title']), 'title-') === 0);
+ }
+}
+
+/**
+ * User class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class User extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'User'
+ * @access public
+ */
+ var $name = 'User';
+
+/**
+ * validate property
+ *
+ * @var array
+ * @access public
+ */
+ var $validate = array('user' => 'notEmpty', 'password' => 'notEmpty');
+}
+
+/**
+ * Article class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class Article extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'Article'
+ * @access public
+ */
+ var $name = 'Article';
+
+/**
+ * belongsTo property
+ *
+ * @var array
+ * @access public
+ */
+ var $belongsTo = array('User');
+
+/**
+ * hasMany property
+ *
+ * @var array
+ * @access public
+ */
+ var $hasMany = array('Comment' => array('dependent' => true));
+
+/**
+ * hasAndBelongsToMany property
+ *
+ * @var array
+ * @access public
+ */
+ var $hasAndBelongsToMany = array('Tag');
+
+/**
+ * validate property
+ *
+ * @var array
+ * @access public
+ */
+ var $validate = array('user_id' => 'numeric', 'title' => array('allowEmpty' => false, 'rule' => 'notEmpty'), 'body' => 'notEmpty');
+
+/**
+ * beforeSaveReturn property
+ *
+ * @var bool true
+ * @access public
+ */
+ var $beforeSaveReturn = true;
+
+/**
+ * beforeSave method
+ *
+ * @access public
+ * @return void
+ */
+ function beforeSave() {
+ return $this->beforeSaveReturn;
+ }
+
+/**
+ * titleDuplicate method
+ *
+ * @param mixed $title
+ * @access public
+ * @return void
+ */
+ function titleDuplicate ($title) {
+ if ($title === 'My Article Title') {
+ return false;
+ }
+ return true;
+ }
+}
+
+/**
+ * Model stub for beforeDelete testing
+ *
+ * @see #250
+ * @package cake.tests
+ */
+class BeforeDeleteComment extends CakeTestModel {
+ var $name = 'BeforeDeleteComment';
+
+ var $useTable = 'comments';
+
+ function beforeDelete($cascade = true) {
+ $db =& $this->getDataSource();
+ $db->delete($this, array($this->alias . '.' . $this->primaryKey => array(1, 3)));
+ return true;
+ }
+}
+
+/**
+ * NumericArticle class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class NumericArticle extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'NumericArticle'
+ * @access public
+ */
+ var $name = 'NumericArticle';
+
+/**
+ * useTable property
+ *
+ * @var string 'numeric_articles'
+ * @access public
+ */
+ var $useTable = 'numeric_articles';
+}
+
+/**
+ * Article10 class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class Article10 extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'Article10'
+ * @access public
+ */
+ var $name = 'Article10';
+
+/**
+ * useTable property
+ *
+ * @var string 'articles'
+ * @access public
+ */
+ var $useTable = 'articles';
+
+/**
+ * hasMany property
+ *
+ * @var array
+ * @access public
+ */
+ var $hasMany = array('Comment' => array('dependent' => true, 'exclusive' => true));
+}
+
+/**
+ * ArticleFeatured class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class ArticleFeatured extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'ArticleFeatured'
+ * @access public
+ */
+ var $name = 'ArticleFeatured';
+
+/**
+ * belongsTo property
+ *
+ * @var array
+ * @access public
+ */
+ var $belongsTo = array('User', 'Category');
+
+/**
+ * hasOne property
+ *
+ * @var array
+ * @access public
+ */
+ var $hasOne = array('Featured');
+
+/**
+ * hasMany property
+ *
+ * @var array
+ * @access public
+ */
+ var $hasMany = array('Comment' => array('className' => 'Comment', 'dependent' => true));
+
+/**
+ * hasAndBelongsToMany property
+ *
+ * @var array
+ * @access public
+ */
+ var $hasAndBelongsToMany = array('Tag');
+
+/**
+ * validate property
+ *
+ * @var array
+ * @access public
+ */
+ var $validate = array('user_id' => 'numeric', 'title' => 'notEmpty', 'body' => 'notEmpty');
+}
+
+/**
+ * Featured class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class Featured extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'Featured'
+ * @access public
+ */
+ var $name = 'Featured';
+
+/**
+ * belongsTo property
+ *
+ * @var array
+ * @access public
+ */
+ var $belongsTo = array('ArticleFeatured', 'Category');
+}
+
+/**
+ * Tag class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class Tag extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'Tag'
+ * @access public
+ */
+ var $name = 'Tag';
+}
+
+/**
+ * ArticlesTag class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class ArticlesTag extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'ArticlesTag'
+ * @access public
+ */
+ var $name = 'ArticlesTag';
+}
+
+/**
+ * ArticleFeaturedsTag class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class ArticleFeaturedsTag extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'ArticleFeaturedsTag'
+ * @access public
+ */
+ var $name = 'ArticleFeaturedsTag';
+}
+
+/**
+ * Comment class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class Comment extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'Comment'
+ * @access public
+ */
+ var $name = 'Comment';
+
+/**
+ * belongsTo property
+ *
+ * @var array
+ * @access public
+ */
+ var $belongsTo = array('Article', 'User');
+
+/**
+ * hasOne property
+ *
+ * @var array
+ * @access public
+ */
+ var $hasOne = array('Attachment' => array('dependent' => true));
+}
+
+/**
+ * Modified Comment Class has afterFind Callback
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class ModifiedComment extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'Comment'
+ * @access public
+ */
+ var $name = 'Comment';
+
+/**
+ * useTable property
+ *
+ * @var string 'comments'
+ * @access public
+ */
+ var $useTable = 'comments';
+
+/**
+ * belongsTo property
+ *
+ * @var array
+ * @access public
+ */
+ var $belongsTo = array('Article');
+
+/**
+ * afterFind callback
+ *
+ * @return void
+ */
+ function afterFind($results) {
+ if (isset($results[0])) {
+ $results[0]['Comment']['callback'] = 'Fire';
+ }
+ return $results;
+ }
+}
+
+/**
+ * Modified Comment Class has afterFind Callback
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class AgainModifiedComment extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'Comment'
+ * @access public
+ */
+ var $name = 'Comment';
+
+/**
+ * useTable property
+ *
+ * @var string 'comments'
+ * @access public
+ */
+ var $useTable = 'comments';
+
+/**
+ * belongsTo property
+ *
+ * @var array
+ * @access public
+ */
+ var $belongsTo = array('Article');
+
+/**
+ * afterFind callback
+ *
+ * @return void
+ */
+ function afterFind($results) {
+ if (isset($results[0])) {
+ $results[0]['Comment']['querytype'] = $this->findQueryType;
+ }
+ return $results;
+ }
+}
+
+/**
+ * MergeVarPluginAppModel class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class MergeVarPluginAppModel extends AppModel {
+
+/**
+ * actsAs parameter
+ *
+ * @var array
+ */
+ var $actsAs = array(
+ 'Containable'
+ );
+}
+
+/**
+ * MergeVarPluginPost class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class MergeVarPluginPost extends MergeVarPluginAppModel {
+
+/**
+ * actsAs parameter
+ *
+ * @var array
+ */
+ var $actsAs = array(
+ 'Tree'
+ );
+
+/**
+ * useTable parameter
+ *
+ * @var string
+ */
+ var $useTable = 'posts';
+}
+
+/**
+ * MergeVarPluginComment class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class MergeVarPluginComment extends MergeVarPluginAppModel {
+
+/**
+ * actsAs parameter
+ *
+ * @var array
+ */
+ var $actsAs = array(
+ 'Containable' => array('some_settings')
+ );
+
+/**
+ * useTable parameter
+ *
+ * @var string
+ */
+ var $useTable = 'comments';
+}
+
+
+/**
+ * Attachment class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class Attachment extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'Attachment'
+ * @access public
+ */
+ var $name = 'Attachment';
+}
+
+/**
+ * Category class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class Category extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'Category'
+ * @access public
+ */
+ var $name = 'Category';
+}
+
+/**
+ * CategoryThread class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class CategoryThread extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'CategoryThread'
+ * @access public
+ */
+ var $name = 'CategoryThread';
+
+/**
+ * belongsTo property
+ *
+ * @var array
+ * @access public
+ */
+ var $belongsTo = array('ParentCategory' => array('className' => 'CategoryThread', 'foreignKey' => 'parent_id'));
+}
+
+/**
+ * Apple class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class Apple extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'Apple'
+ * @access public
+ */
+ var $name = 'Apple';
+
+/**
+ * validate property
+ *
+ * @var array
+ * @access public
+ */
+ var $validate = array('name' => 'notEmpty');
+
+/**
+ * hasOne property
+ *
+ * @var array
+ * @access public
+ */
+ var $hasOne = array('Sample');
+
+/**
+ * hasMany property
+ *
+ * @var array
+ * @access public
+ */
+ var $hasMany = array('Child' => array('className' => 'Apple', 'dependent' => true));
+
+/**
+ * belongsTo property
+ *
+ * @var array
+ * @access public
+ */
+ var $belongsTo = array('Parent' => array('className' => 'Apple', 'foreignKey' => 'apple_id'));
+}
+
+/**
+ * Sample class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class Sample extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'Sample'
+ * @access public
+ */
+ var $name = 'Sample';
+
+/**
+ * belongsTo property
+ *
+ * @var string 'Apple'
+ * @access public
+ */
+ var $belongsTo = 'Apple';
+}
+
+/**
+ * AnotherArticle class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class AnotherArticle extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'AnotherArticle'
+ * @access public
+ */
+ var $name = 'AnotherArticle';
+
+/**
+ * hasMany property
+ *
+ * @var string 'Home'
+ * @access public
+ */
+ var $hasMany = 'Home';
+}
+
+/**
+ * Advertisement class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class Advertisement extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'Advertisement'
+ * @access public
+ */
+ var $name = 'Advertisement';
+
+/**
+ * hasMany property
+ *
+ * @var string 'Home'
+ * @access public
+ */
+ var $hasMany = 'Home';
+}
+
+/**
+ * Home class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class Home extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'Home'
+ * @access public
+ */
+ var $name = 'Home';
+
+/**
+ * belongsTo property
+ *
+ * @var array
+ * @access public
+ */
+ var $belongsTo = array('AnotherArticle', 'Advertisement');
+}
+
+/**
+ * Post class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class Post extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'Post'
+ * @access public
+ */
+ var $name = 'Post';
+
+/**
+ * belongsTo property
+ *
+ * @var array
+ * @access public
+ */
+ var $belongsTo = array('Author');
+
+ function beforeFind($queryData) {
+ if (isset($queryData['connection'])) {
+ $this->useDbConfig = $queryData['connection'];
+ }
+ return true;
+ }
+
+ function afterFind($results) {
+ $this->useDbConfig = 'test_suite';
+ return $results;
+ }
+}
+
+/**
+ * Author class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class Author extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'Author'
+ * @access public
+ */
+ var $name = 'Author';
+
+/**
+ * hasMany property
+ *
+ * @var array
+ * @access public
+ */
+ var $hasMany = array('Post');
+
+/**
+ * afterFind method
+ *
+ * @param mixed $results
+ * @access public
+ * @return void
+ */
+ function afterFind($results) {
+ $results[0]['Author']['test'] = 'working';
+ return $results;
+ }
+}
+
+/**
+ * ModifiedAuthor class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class ModifiedAuthor extends Author {
+
+/**
+ * name property
+ *
+ * @var string 'Author'
+ * @access public
+ */
+ var $name = 'Author';
+
+/**
+ * afterFind method
+ *
+ * @param mixed $results
+ * @access public
+ * @return void
+ */
+ function afterFind($results) {
+ foreach($results as $index => $result) {
+ $results[$index]['Author']['user'] .= ' (CakePHP)';
+ }
+ return $results;
+ }
+}
+
+/**
+ * Project class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class Project extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'Project'
+ * @access public
+ */
+ var $name = 'Project';
+
+/**
+ * hasMany property
+ *
+ * @var array
+ * @access public
+ */
+ var $hasMany = array('Thread');
+}
+
+/**
+ * Thread class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class Thread extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'Thread'
+ * @access public
+ */
+ var $name = 'Thread';
+
+/**
+ * hasMany property
+ *
+ * @var array
+ * @access public
+ */
+ var $belongsTo = array('Project');
+
+/**
+ * hasMany property
+ *
+ * @var array
+ * @access public
+ */
+ var $hasMany = array('Message');
+}
+
+/**
+ * Message class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class Message extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'Message'
+ * @access public
+ */
+ var $name = 'Message';
+
+/**
+ * hasOne property
+ *
+ * @var array
+ * @access public
+ */
+ var $hasOne = array('Bid');
+}
+
+/**
+ * Bid class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class Bid extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'Bid'
+ * @access public
+ */
+ var $name = 'Bid';
+
+/**
+ * belongsTo property
+ *
+ * @var array
+ * @access public
+ */
+ var $belongsTo = array('Message');
+}
+
+/**
+ * NodeAfterFind class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class NodeAfterFind extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'NodeAfterFind'
+ * @access public
+ */
+ var $name = 'NodeAfterFind';
+
+/**
+ * validate property
+ *
+ * @var array
+ * @access public
+ */
+ var $validate = array('name' => 'notEmpty');
+
+/**
+ * useTable property
+ *
+ * @var string 'apples'
+ * @access public
+ */
+ var $useTable = 'apples';
+
+/**
+ * hasOne property
+ *
+ * @var array
+ * @access public
+ */
+ var $hasOne = array('Sample' => array('className' => 'NodeAfterFindSample'));
+
+/**
+ * hasMany property
+ *
+ * @var array
+ * @access public
+ */
+ var $hasMany = array('Child' => array('className' => 'NodeAfterFind', 'dependent' => true));
+
+/**
+ * belongsTo property
+ *
+ * @var array
+ * @access public
+ */
+ var $belongsTo = array('Parent' => array('className' => 'NodeAfterFind', 'foreignKey' => 'apple_id'));
+
+/**
+ * afterFind method
+ *
+ * @param mixed $results
+ * @access public
+ * @return void
+ */
+ function afterFind($results) {
+ return $results;
+ }
+}
+
+/**
+ * NodeAfterFindSample class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class NodeAfterFindSample extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'NodeAfterFindSample'
+ * @access public
+ */
+ var $name = 'NodeAfterFindSample';
+
+/**
+ * useTable property
+ *
+ * @var string 'samples'
+ * @access public
+ */
+ var $useTable = 'samples';
+
+/**
+ * belongsTo property
+ *
+ * @var string 'NodeAfterFind'
+ * @access public
+ */
+ var $belongsTo = 'NodeAfterFind';
+}
+
+/**
+ * NodeNoAfterFind class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class NodeNoAfterFind extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'NodeAfterFind'
+ * @access public
+ */
+ var $name = 'NodeAfterFind';
+
+/**
+ * validate property
+ *
+ * @var array
+ * @access public
+ */
+ var $validate = array('name' => 'notEmpty');
+
+/**
+ * useTable property
+ *
+ * @var string 'apples'
+ * @access public
+ */
+ var $useTable = 'apples';
+
+/**
+ * hasOne property
+ *
+ * @var array
+ * @access public
+ */
+ var $hasOne = array('Sample' => array('className' => 'NodeAfterFindSample'));
+
+/**
+ * hasMany property
+ *
+ * @var array
+ * @access public
+ */
+ var $hasMany = array('Child' => array('className' => 'NodeAfterFind', 'dependent' => true));
+
+/**
+ * belongsTo property
+ *
+ * @var array
+ * @access public
+ */
+ var $belongsTo = array('Parent' => array('className' => 'NodeAfterFind', 'foreignKey' => 'apple_id'));
+}
+
+/**
+ * Node class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class Node extends CakeTestModel{
+
+/**
+ * name property
+ *
+ * @var string 'Node'
+ * @access public
+ */
+ var $name = 'Node';
+
+/**
+ * hasAndBelongsToMany property
+ *
+ * @var array
+ * @access public
+ */
+ var $hasAndBelongsToMany = array(
+ 'ParentNode' => array(
+ 'className' => 'Node',
+ 'joinTable' => 'dependency',
+ 'with' => 'Dependency',
+ 'foreignKey' => 'child_id',
+ 'associationForeignKey' => 'parent_id',
+ )
+ );
+}
+
+/**
+ * Dependency class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class Dependency extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'Dependency'
+ * @access public
+ */
+ var $name = 'Dependency';
+}
+
+/**
+ * ModelA class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class ModelA extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'ModelA'
+ * @access public
+ */
+ var $name = 'ModelA';
+
+/**
+ * useTable property
+ *
+ * @var string 'apples'
+ * @access public
+ */
+ var $useTable = 'apples';
+
+/**
+ * hasMany property
+ *
+ * @var array
+ * @access public
+ */
+ var $hasMany = array('ModelB', 'ModelC');
+}
+
+/**
+ * ModelB class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class ModelB extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'ModelB'
+ * @access public
+ */
+ var $name = 'ModelB';
+
+/**
+ * useTable property
+ *
+ * @var string 'messages'
+ * @access public
+ */
+ var $useTable = 'messages';
+
+/**
+ * hasMany property
+ *
+ * @var array
+ * @access public
+ */
+ var $hasMany = array('ModelD');
+}
+
+/**
+ * ModelC class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class ModelC extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'ModelC'
+ * @access public
+ */
+ var $name = 'ModelC';
+
+/**
+ * useTable property
+ *
+ * @var string 'bids'
+ * @access public
+ */
+ var $useTable = 'bids';
+
+/**
+ * hasMany property
+ *
+ * @var array
+ * @access public
+ */
+ var $hasMany = array('ModelD');
+}
+
+/**
+ * ModelD class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class ModelD extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'ModelD'
+ * @access public
+ */
+ var $name = 'ModelD';
+
+/**
+ * useTable property
+ *
+ * @var string 'threads'
+ * @access public
+ */
+ var $useTable = 'threads';
+}
+
+/**
+ * Something class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class Something extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'Something'
+ * @access public
+ */
+ var $name = 'Something';
+
+/**
+ * hasAndBelongsToMany property
+ *
+ * @var array
+ * @access public
+ */
+ var $hasAndBelongsToMany = array('SomethingElse' => array('with' => array('JoinThing' => array('doomed'))));
+}
+
+/**
+ * SomethingElse class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class SomethingElse extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'SomethingElse'
+ * @access public
+ */
+ var $name = 'SomethingElse';
+
+/**
+ * hasAndBelongsToMany property
+ *
+ * @var array
+ * @access public
+ */
+ var $hasAndBelongsToMany = array('Something' => array('with' => 'JoinThing'));
+}
+
+/**
+ * JoinThing class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class JoinThing extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'JoinThing'
+ * @access public
+ */
+ var $name = 'JoinThing';
+
+/**
+ * belongsTo property
+ *
+ * @var array
+ * @access public
+ */
+ var $belongsTo = array('Something', 'SomethingElse');
+}
+
+/**
+ * Portfolio class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class Portfolio extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'Portfolio'
+ * @access public
+ */
+ var $name = 'Portfolio';
+
+/**
+ * hasAndBelongsToMany property
+ *
+ * @var array
+ * @access public
+ */
+ var $hasAndBelongsToMany = array('Item');
+}
+
+/**
+ * Item class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class Item extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'Item'
+ * @access public
+ */
+ var $name = 'Item';
+
+/**
+ * belongsTo property
+ *
+ * @var array
+ * @access public
+ */
+ var $belongsTo = array('Syfile' => array('counterCache' => true));
+
+/**
+ * hasAndBelongsToMany property
+ *
+ * @var array
+ * @access public
+ */
+ var $hasAndBelongsToMany = array('Portfolio' => array('unique' => false));
+}
+
+/**
+ * ItemsPortfolio class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class ItemsPortfolio extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'ItemsPortfolio'
+ * @access public
+ */
+ var $name = 'ItemsPortfolio';
+}
+
+/**
+ * Syfile class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class Syfile extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'Syfile'
+ * @access public
+ */
+ var $name = 'Syfile';
+
+/**
+ * belongsTo property
+ *
+ * @var array
+ * @access public
+ */
+ var $belongsTo = array('Image');
+}
+
+/**
+ * Image class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class Image extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'Image'
+ * @access public
+ */
+ var $name = 'Image';
+}
+
+/**
+ * DeviceType class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class DeviceType extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'DeviceType'
+ * @access public
+ */
+ var $name = 'DeviceType';
+
+/**
+ * order property
+ *
+ * @var array
+ * @access public
+ */
+ var $order = array('DeviceType.order' => 'ASC');
+
+/**
+ * belongsTo property
+ *
+ * @var array
+ * @access public
+ */
+ var $belongsTo = array(
+ 'DeviceTypeCategory', 'FeatureSet', 'ExteriorTypeCategory',
+ 'Image' => array('className' => 'Document'),
+ 'Extra1' => array('className' => 'Document'),
+ 'Extra2' => array('className' => 'Document'));
+
+/**
+ * hasMany property
+ *
+ * @var array
+ * @access public
+ */
+ var $hasMany = array('Device' => array('order' => array('Device.id' => 'ASC')));
+}
+
+/**
+ * DeviceTypeCategory class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class DeviceTypeCategory extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'DeviceTypeCategory'
+ * @access public
+ */
+ var $name = 'DeviceTypeCategory';
+}
+
+/**
+ * FeatureSet class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class FeatureSet extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'FeatureSet'
+ * @access public
+ */
+ var $name = 'FeatureSet';
+}
+
+/**
+ * ExteriorTypeCategory class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class ExteriorTypeCategory extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'ExteriorTypeCategory'
+ * @access public
+ */
+ var $name = 'ExteriorTypeCategory';
+
+/**
+ * belongsTo property
+ *
+ * @var array
+ * @access public
+ */
+ var $belongsTo = array('Image' => array('className' => 'Device'));
+}
+
+/**
+ * Document class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class Document extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'Document'
+ * @access public
+ */
+ var $name = 'Document';
+
+/**
+ * belongsTo property
+ *
+ * @var array
+ * @access public
+ */
+ var $belongsTo = array('DocumentDirectory');
+}
+
+/**
+ * Device class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class Device extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'Device'
+ * @access public
+ */
+ var $name = 'Device';
+}
+
+/**
+ * DocumentDirectory class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class DocumentDirectory extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'DocumentDirectory'
+ * @access public
+ */
+ var $name = 'DocumentDirectory';
+}
+
+/**
+ * PrimaryModel class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class PrimaryModel extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'PrimaryModel'
+ * @access public
+ */
+ var $name = 'PrimaryModel';
+}
+
+/**
+ * SecondaryModel class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class SecondaryModel extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'SecondaryModel'
+ * @access public
+ */
+ var $name = 'SecondaryModel';
+}
+
+/**
+ * JoinA class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class JoinA extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'JoinA'
+ * @access public
+ */
+ var $name = 'JoinA';
+
+/**
+ * hasAndBelongsToMany property
+ *
+ * @var array
+ * @access public
+ */
+ var $hasAndBelongsToMany = array('JoinB', 'JoinC');
+}
+
+/**
+ * JoinB class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class JoinB extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'JoinB'
+ * @access public
+ */
+ var $name = 'JoinB';
+
+/**
+ * hasAndBelongsToMany property
+ *
+ * @var array
+ * @access public
+ */
+ var $hasAndBelongsToMany = array('JoinA');
+}
+
+/**
+ * JoinC class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class JoinC extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'JoinC'
+ * @access public
+ */
+ var $name = 'JoinC';
+
+/**
+ * hasAndBelongsToMany property
+ *
+ * @var array
+ * @access public
+ */
+ var $hasAndBelongsToMany = array('JoinA');
+}
+
+/**
+ * ThePaper class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class ThePaper extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'ThePaper'
+ * @access public
+ */
+ var $name = 'ThePaper';
+
+/**
+ * useTable property
+ *
+ * @var string 'apples'
+ * @access public
+ */
+ var $useTable = 'apples';
+
+/**
+ * hasOne property
+ *
+ * @var array
+ * @access public
+ */
+ var $hasOne = array('Itself' => array('className' => 'ThePaper', 'foreignKey' => 'apple_id'));
+
+/**
+ * hasAndBelongsToMany property
+ *
+ * @var array
+ * @access public
+ */
+ var $hasAndBelongsToMany = array('Monkey' => array('joinTable' => 'the_paper_monkies', 'order' => 'id'));
+}
+
+/**
+ * Monkey class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class Monkey extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'Monkey'
+ * @access public
+ */
+ var $name = 'Monkey';
+
+/**
+ * useTable property
+ *
+ * @var string 'devices'
+ * @access public
+ */
+ var $useTable = 'devices';
+}
+
+/**
+ * AssociationTest1 class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class AssociationTest1 extends CakeTestModel {
+
+/**
+ * useTable property
+ *
+ * @var string 'join_as'
+ * @access public
+ */
+ var $useTable = 'join_as';
+
+/**
+ * name property
+ *
+ * @var string 'AssociationTest1'
+ * @access public
+ */
+ var $name = 'AssociationTest1';
+
+/**
+ * hasAndBelongsToMany property
+ *
+ * @var array
+ * @access public
+ */
+ var $hasAndBelongsToMany = array('AssociationTest2' => array(
+ 'unique' => false, 'joinTable' => 'join_as_join_bs', 'foreignKey' => false
+ ));
+}
+
+/**
+ * AssociationTest2 class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class AssociationTest2 extends CakeTestModel {
+
+/**
+ * useTable property
+ *
+ * @var string 'join_bs'
+ * @access public
+ */
+ var $useTable = 'join_bs';
+
+/**
+ * name property
+ *
+ * @var string 'AssociationTest2'
+ * @access public
+ */
+ var $name = 'AssociationTest2';
+
+/**
+ * hasAndBelongsToMany property
+ *
+ * @var array
+ * @access public
+ */
+ var $hasAndBelongsToMany = array('AssociationTest1' => array(
+ 'unique' => false, 'joinTable' => 'join_as_join_bs'
+ ));
+}
+
+/**
+ * Callback class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class Callback extends CakeTestModel {
+
+}
+/**
+ * CallbackPostTestModel class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class CallbackPostTestModel extends CakeTestModel {
+ var $useTable = 'posts';
+/**
+ * variable to control return of beforeValidate
+ *
+ * @var string
+ */
+ var $beforeValidateReturn = true;
+/**
+ * variable to control return of beforeSave
+ *
+ * @var string
+ */
+ var $beforeSaveReturn = true;
+/**
+ * variable to control return of beforeDelete
+ *
+ * @var string
+ */
+ var $beforeDeleteReturn = true;
+/**
+ * beforeSave callback
+ *
+ * @return void
+ */
+ function beforeSave($options) {
+ return $this->beforeSaveReturn;
+ }
+/**
+ * beforeValidate callback
+ *
+ * @return void
+ */
+ function beforeValidate($options) {
+ return $this->beforeValidateReturn;
+ }
+/**
+ * beforeDelete callback
+ *
+ * @return void
+ */
+ function beforeDelete($cascade = true) {
+ return $this->beforeDeleteReturn;
+ }
+}
+
+/**
+ * Uuid class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class Uuid extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'Uuid'
+ * @access public
+ */
+ var $name = 'Uuid';
+}
+
+/**
+ * DataTest class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class DataTest extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'DataTest'
+ * @access public
+ */
+ var $name = 'DataTest';
+}
+
+/**
+ * TheVoid class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class TheVoid extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'TheVoid'
+ * @access public
+ */
+ var $name = 'TheVoid';
+
+/**
+ * useTable property
+ *
+ * @var bool false
+ * @access public
+ */
+ var $useTable = false;
+}
+
+/**
+ * ValidationTest1 class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class ValidationTest1 extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'ValidationTest'
+ * @access public
+ */
+ var $name = 'ValidationTest1';
+
+/**
+ * useTable property
+ *
+ * @var bool false
+ * @access public
+ */
+ var $useTable = false;
+
+/**
+ * schema property
+ *
+ * @var array
+ * @access protected
+ */
+ var $_schema = array();
+
+/**
+ * validate property
+ *
+ * @var array
+ * @access public
+ */
+ var $validate = array(
+ 'title' => 'notEmpty',
+ 'published' => 'customValidationMethod',
+ 'body' => array(
+ 'notEmpty',
+ '/^.{5,}$/s' => 'no matchy',
+ '/^[0-9A-Za-z \\.]{1,}$/s'
+ )
+ );
+
+/**
+ * customValidationMethod method
+ *
+ * @param mixed $data
+ * @access public
+ * @return void
+ */
+ function customValidationMethod($data) {
+ return $data === 1;
+ }
+
+/**
+ * Custom validator with parameters + default values
+ *
+ * @access public
+ * @return array
+ */
+ function customValidatorWithParams($data, $validator, $or = true, $ignore_on_same = 'id') {
+ $this->validatorParams = get_defined_vars();
+ unset($this->validatorParams['this']);
+ return true;
+ }
+
+/**
+ * Custom validator with messaage
+ *
+ * @access public
+ * @return array
+ */
+ function customValidatorWithMessage($data) {
+ return 'This field will *never* validate! Muhahaha!';
+ }
+/**
+ * Test validation with many parameters
+ *
+ * @return void
+ */
+ function customValidatorWithSixParams($data, $one = 1, $two = 2, $three = 3, $four = 4, $five = 5, $six = 6) {
+ $this->validatorParams = get_defined_vars();
+ unset($this->validatorParams['this']);
+ return true;
+ }
+}
+
+/**
+ * ValidationTest2 class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class ValidationTest2 extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'ValidationTest2'
+ * @access public
+ */
+ var $name = 'ValidationTest2';
+
+/**
+ * useTable property
+ *
+ * @var bool false
+ * @access public
+ */
+ var $useTable = false;
+
+/**
+ * validate property
+ *
+ * @var array
+ * @access public
+ */
+ var $validate = array(
+ 'title' => 'notEmpty',
+ 'published' => 'customValidationMethod',
+ 'body' => array(
+ 'notEmpty',
+ '/^.{5,}$/s' => 'no matchy',
+ '/^[0-9A-Za-z \\.]{1,}$/s'
+ )
+ );
+
+/**
+ * customValidationMethod method
+ *
+ * @param mixed $data
+ * @access public
+ * @return void
+ */
+ function customValidationMethod($data) {
+ return $data === 1;
+ }
+
+/**
+ * schema method
+ *
+ * @access public
+ * @return void
+ */
+ function schema() {
+ return array();
+ }
+}
+
+/**
+ * Person class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class Person extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'Person'
+ * @access public
+ */
+ var $name = 'Person';
+
+/**
+ * belongsTo property
+ *
+ * @var array
+ * @access public
+ */
+ var $belongsTo = array(
+ 'Mother' => array(
+ 'className' => 'Person',
+ 'foreignKey' => 'mother_id'),
+ 'Father' => array(
+ 'className' => 'Person',
+ 'foreignKey' => 'father_id'));
+}
+
+/**
+ * UnderscoreField class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class UnderscoreField extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'UnderscoreField'
+ * @access public
+ */
+ var $name = 'UnderscoreField';
+}
+
+/**
+ * Product class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class Product extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'Product'
+ * @access public
+ */
+ var $name = 'Product';
+}
+
+/**
+ * Story class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class Story extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'Story'
+ * @access public
+ */
+ var $name = 'Story';
+
+/**
+ * primaryKey property
+ *
+ * @var string 'story'
+ * @access public
+ */
+ var $primaryKey = 'story';
+
+/**
+ * hasAndBelongsToMany property
+ *
+ * @var array
+ * @access public
+ */
+ var $hasAndBelongsToMany = array('Tag' => array('foreignKey' => 'story'));
+
+/**
+ * validate property
+ *
+ * @var array
+ * @access public
+ */
+ var $validate = array('title' => 'notEmpty');
+}
+
+/**
+ * Cd class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class Cd extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'Cd'
+ * @access public
+ */
+ var $name = 'Cd';
+
+/**
+ * hasOne property
+ *
+ * @var array
+ * @access public
+ */
+ var $hasOne = array('OverallFavorite' => array('foreignKey' => 'model_id', 'dependent' => true, 'conditions' => array('model_type' => 'Cd')));
+}
+
+/**
+ * Book class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class Book extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'Book'
+ * @access public
+ */
+ var $name = 'Book';
+
+/**
+ * hasOne property
+ *
+ * @var array
+ * @access public
+ */
+ var $hasOne = array('OverallFavorite' => array('foreignKey' => 'model_id', 'dependent' => true, 'conditions' => 'OverallFavorite.model_type = \'Book\''));
+}
+
+/**
+ * OverallFavorite class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class OverallFavorite extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'OverallFavorite'
+ * @access public
+ */
+ var $name = 'OverallFavorite';
+}
+
+/**
+ * MyUser class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class MyUser extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'MyUser'
+ * @access public
+ */
+ var $name = 'MyUser';
+
+/**
+ * undocumented variable
+ *
+ * @var string
+ * @access public
+ */
+ var $hasAndBelongsToMany = array('MyCategory');
+}
+
+/**
+ * MyCategory class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class MyCategory extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'MyCategory'
+ * @access public
+ */
+ var $name = 'MyCategory';
+
+/**
+ * undocumented variable
+ *
+ * @var string
+ * @access public
+ */
+ var $hasAndBelongsToMany = array('MyProduct', 'MyUser');
+}
+
+/**
+ * MyProduct class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class MyProduct extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'MyProduct'
+ * @access public
+ */
+ var $name = 'MyProduct';
+
+/**
+ * undocumented variable
+ *
+ * @var string
+ * @access public
+ */
+ var $hasAndBelongsToMany = array('MyCategory');
+}
+
+/**
+ * MyCategoriesMyUser class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class MyCategoriesMyUser extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'MyCategoriesMyUser'
+ * @access public
+ */
+ var $name = 'MyCategoriesMyUser';
+}
+
+/**
+ * MyCategoriesMyProduct class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class MyCategoriesMyProduct extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'MyCategoriesMyProduct'
+ * @access public
+ */
+ var $name = 'MyCategoriesMyProduct';
+}
+
+/**
+ * I18nModel class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class I18nModel extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'I18nModel'
+ * @access public
+ */
+ var $name = 'I18nModel';
+
+/**
+ * useTable property
+ *
+ * @var string 'i18n'
+ * @access public
+ */
+ var $useTable = 'i18n';
+
+/**
+ * displayField property
+ *
+ * @var string 'field'
+ * @access public
+ */
+ var $displayField = 'field';
+}
+
+/**
+ * NumberTree class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class NumberTree extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'NumberTree'
+ * @access public
+ */
+ var $name = 'NumberTree';
+
+/**
+ * actsAs property
+ *
+ * @var array
+ * @access public
+ */
+ var $actsAs = array('Tree');
+
+/**
+ * initialize method
+ *
+ * @param int $levelLimit
+ * @param int $childLimit
+ * @param mixed $currentLevel
+ * @param mixed $parent_id
+ * @param string $prefix
+ * @param bool $hierachial
+ * @access public
+ * @return void
+ */
+ function initialize($levelLimit = 3, $childLimit = 3, $currentLevel = null, $parent_id = null, $prefix = '1', $hierachial = true) {
+ if (!$parent_id) {
+ $db =& ConnectionManager::getDataSource($this->useDbConfig);
+ $db->truncate($this->table);
+ $this->save(array($this->name => array('name' => '1. Root')));
+ $this->initialize($levelLimit, $childLimit, 1, $this->id, '1', $hierachial);
+ $this->create(array());
+ }
+
+ if (!$currentLevel || $currentLevel > $levelLimit) {
+ return;
+ }
+
+ for ($i = 1; $i <= $childLimit; $i++) {
+ $name = $prefix . '.' . $i;
+ $data = array($this->name => array('name' => $name));
+ $this->create($data);
+
+ if ($hierachial) {
+ if ($this->name == 'UnconventionalTree') {
+ $data[$this->name]['join'] = $parent_id;
+ } else {
+ $data[$this->name]['parent_id'] = $parent_id;
+ }
+ }
+ $this->save($data);
+ $this->initialize($levelLimit, $childLimit, $currentLevel + 1, $this->id, $name, $hierachial);
+ }
+ }
+}
+
+/**
+ * NumberTreeTwo class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class NumberTreeTwo extends NumberTree {
+
+/**
+ * name property
+ *
+ * @var string 'NumberTree'
+ * @access public
+ */
+ var $name = 'NumberTreeTwo';
+
+/**
+ * actsAs property
+ *
+ * @var array
+ * @access public
+ */
+ var $actsAs = array();
+}
+
+/**
+ * FlagTree class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class FlagTree extends NumberTree {
+
+/**
+ * name property
+ *
+ * @var string 'FlagTree'
+ * @access public
+ */
+ var $name = 'FlagTree';
+}
+
+/**
+ * UnconventionalTree class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class UnconventionalTree extends NumberTree {
+
+/**
+ * name property
+ *
+ * @var string 'FlagTree'
+ * @access public
+ */
+ var $name = 'UnconventionalTree';
+ var $actsAs = array(
+ 'Tree' => array(
+ 'parent' => 'join',
+ 'left' => 'left',
+ 'right' => 'right'
+ )
+ );
+}
+
+/**
+ * UuidTree class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class UuidTree extends NumberTree {
+
+/**
+ * name property
+ *
+ * @var string 'FlagTree'
+ * @access public
+ */
+ var $name = 'UuidTree';
+}
+
+/**
+ * Campaign class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class Campaign extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'Campaign'
+ * @access public
+ */
+ var $name = 'Campaign';
+
+/**
+ * hasMany property
+ *
+ * @var array
+ * @access public
+ */
+ var $hasMany = array('Ad' => array('fields' => array('id','campaign_id','name')));
+}
+
+/**
+ * Ad class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class Ad extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'Ad'
+ * @access public
+ */
+ var $name = 'Ad';
+
+/**
+ * actsAs property
+ *
+ * @var array
+ * @access public
+ */
+ var $actsAs = array('Tree');
+
+/**
+ * belongsTo property
+ *
+ * @var array
+ * @access public
+ */
+ var $belongsTo = array('Campaign');
+}
+
+/**
+ * AfterTree class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class AfterTree extends NumberTree {
+
+/**
+ * name property
+ *
+ * @var string 'AfterTree'
+ * @access public
+ */
+ var $name = 'AfterTree';
+
+/**
+ * actsAs property
+ *
+ * @var array
+ * @access public
+ */
+ var $actsAs = array('Tree');
+
+ function afterSave($created) {
+ if ($created && isset($this->data['AfterTree'])) {
+ $this->data['AfterTree']['name'] = 'Six and One Half Changed in AfterTree::afterSave() but not in database';
+ }
+ }
+}
+
+/**
+ * Nonconformant Content class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class Content extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'Content'
+ * @access public
+ */
+ var $name = 'Content';
+
+/**
+ * useTable property
+ *
+ * @var string 'Content'
+ * @access public
+ */
+ var $useTable = 'Content';
+
+/**
+ * primaryKey property
+ *
+ * @var string 'iContentId'
+ * @access public
+ */
+ var $primaryKey = 'iContentId';
+
+/**
+ * hasAndBelongsToMany property
+ *
+ * @var array
+ * @access public
+ */
+ var $hasAndBelongsToMany = array('Account' => array('className' => 'Account', 'with' => 'ContentAccount', 'joinTable' => 'ContentAccounts', 'foreignKey' => 'iContentId', 'associationForeignKey', 'iAccountId'));
+}
+
+/**
+ * Nonconformant Account class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class Account extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'Account'
+ * @access public
+ */
+ var $name = 'Account';
+
+/**
+ * useTable property
+ *
+ * @var string 'Account'
+ * @access public
+ */
+ var $useTable = 'Accounts';
+
+/**
+ * primaryKey property
+ *
+ * @var string 'iAccountId'
+ * @access public
+ */
+ var $primaryKey = 'iAccountId';
+}
+
+/**
+ * Nonconformant ContentAccount class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class ContentAccount extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'Account'
+ * @access public
+ */
+ var $name = 'ContentAccount';
+
+/**
+ * useTable property
+ *
+ * @var string 'Account'
+ * @access public
+ */
+ var $useTable = 'ContentAccounts';
+
+/**
+ * primaryKey property
+ *
+ * @var string 'iAccountId'
+ * @access public
+ */
+ var $primaryKey = 'iContentAccountsId';
+}
+
+/**
+ * FilmFile class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class FilmFile extends CakeTestModel {
+ var $name = 'FilmFile';
+}
+
+/**
+ * Basket test model
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class Basket extends CakeTestModel {
+ var $name = 'Basket';
+
+ var $belongsTo = array(
+ 'FilmFile' => array(
+ 'className' => 'FilmFile',
+ 'foreignKey' => 'object_id',
+ 'conditions' => "Basket.type = 'file'",
+ 'fields' => '',
+ 'order' => ''
+ )
+ );
+}
+
+/**
+ * TestPluginArticle class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class TestPluginArticle extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'TestPluginArticle'
+ * @access public
+ */
+ var $name = 'TestPluginArticle';
+
+/**
+ * belongsTo property
+ *
+ * @var array
+ * @access public
+ */
+ var $belongsTo = array('User');
+
+/**
+ * hasMany property
+ *
+ * @var array
+ * @access public
+ */
+ var $hasMany = array(
+ 'TestPluginComment' => array(
+ 'className' => 'TestPlugin.TestPluginComment',
+ 'foreignKey' => 'article_id',
+ 'dependent' => true
+ )
+ );
+}
+
+/**
+ * TestPluginComment class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class TestPluginComment extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'TestPluginComment'
+ * @access public
+ */
+ var $name = 'TestPluginComment';
+
+/**
+ * belongsTo property
+ *
+ * @var array
+ * @access public
+ */
+ var $belongsTo = array(
+ 'TestPluginArticle' => array(
+ 'className' => 'TestPlugin.TestPluginArticle',
+ 'foreignKey' => 'article_id',
+ ),
+ 'User'
+ );
+}
+
+/**
+ * Uuidportfolio class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class Uuidportfolio extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'Uuidportfolio'
+ * @access public
+ */
+ var $name = 'Uuidportfolio';
+
+/**
+ * hasAndBelongsToMany property
+ *
+ * @var array
+ * @access public
+ */
+ var $hasAndBelongsToMany = array('Uuiditem');
+}
+
+/**
+ * Uuiditem class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class Uuiditem extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'Item'
+ * @access public
+ */
+ var $name = 'Uuiditem';
+
+/**
+ * hasAndBelongsToMany property
+ *
+ * @var array
+ * @access public
+ */
+ var $hasAndBelongsToMany = array('Uuidportfolio' => array('with' => 'UuiditemsUuidportfolioNumericid'));
+
+}
+
+/**
+ * UuiditemsPortfolio class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class UuiditemsUuidportfolio extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'ItemsPortfolio'
+ * @access public
+ */
+ var $name = 'UuiditemsUuidportfolio';
+}
+
+/**
+ * UuiditemsPortfolioNumericid class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class UuiditemsUuidportfolioNumericid extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string
+ * @access public
+ */
+ var $name = 'UuiditemsUuidportfolioNumericid';
+}
+
+/**
+ * TranslateTestModel class.
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class TranslateTestModel extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'TranslateTestModel'
+ * @access public
+ */
+ var $name = 'TranslateTestModel';
+
+/**
+ * useTable property
+ *
+ * @var string 'i18n'
+ * @access public
+ */
+ var $useTable = 'i18n';
+
+/**
+ * displayField property
+ *
+ * @var string 'field'
+ * @access public
+ */
+ var $displayField = 'field';
+}
+
+/**
+ * TranslateTestModel class.
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class TranslateWithPrefix extends CakeTestModel {
+/**
+ * name property
+ *
+ * @var string 'TranslateTestModel'
+ * @access public
+ */
+ var $name = 'TranslateWithPrefix';
+/**
+ * tablePrefix property
+ *
+ * @var string 'i18n'
+ * @access public
+ */
+ var $tablePrefix = 'i18n_';
+/**
+ * displayField property
+ *
+ * @var string 'field'
+ * @access public
+ */
+ var $displayField = 'field';
+}
+/**
+ * TranslatedItem class.
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class TranslatedItem extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'TranslatedItem'
+ * @access public
+ */
+ var $name = 'TranslatedItem';
+
+/**
+ * cacheQueries property
+ *
+ * @var bool false
+ * @access public
+ */
+ var $cacheQueries = false;
+
+/**
+ * actsAs property
+ *
+ * @var array
+ * @access public
+ */
+ var $actsAs = array('Translate' => array('content', 'title'));
+
+/**
+ * translateModel property
+ *
+ * @var string 'TranslateTestModel'
+ * @access public
+ */
+ var $translateModel = 'TranslateTestModel';
+}
+
+/**
+ * TranslatedItem class.
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class TranslatedItem2 extends CakeTestModel {
+/**
+ * name property
+ *
+ * @var string 'TranslatedItem'
+ * @access public
+ */
+ var $name = 'TranslatedItem';
+/**
+ * cacheQueries property
+ *
+ * @var bool false
+ * @access public
+ */
+ var $cacheQueries = false;
+/**
+ * actsAs property
+ *
+ * @var array
+ * @access public
+ */
+ var $actsAs = array('Translate' => array('content', 'title'));
+/**
+ * translateModel property
+ *
+ * @var string 'TranslateTestModel'
+ * @access public
+ */
+ var $translateModel = 'TranslateWithPrefix';
+}
+/**
+ * TranslatedItemWithTable class.
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class TranslatedItemWithTable extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'TranslatedItemWithTable'
+ * @access public
+ */
+ var $name = 'TranslatedItemWithTable';
+
+/**
+ * useTable property
+ *
+ * @var string 'translated_items'
+ * @access public
+ */
+ var $useTable = 'translated_items';
+
+/**
+ * cacheQueries property
+ *
+ * @var bool false
+ * @access public
+ */
+ var $cacheQueries = false;
+
+/**
+ * actsAs property
+ *
+ * @var array
+ * @access public
+ */
+ var $actsAs = array('Translate' => array('content', 'title'));
+
+/**
+ * translateModel property
+ *
+ * @var string 'TranslateTestModel'
+ * @access public
+ */
+ var $translateModel = 'TranslateTestModel';
+
+/**
+ * translateTable property
+ *
+ * @var string 'another_i18n'
+ * @access public
+ */
+ var $translateTable = 'another_i18n';
+}
+
+/**
+ * TranslateArticleModel class.
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class TranslateArticleModel extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'TranslateArticleModel'
+ * @access public
+ */
+ var $name = 'TranslateArticleModel';
+
+/**
+ * useTable property
+ *
+ * @var string 'article_i18n'
+ * @access public
+ */
+ var $useTable = 'article_i18n';
+
+/**
+ * displayField property
+ *
+ * @var string 'field'
+ * @access public
+ */
+ var $displayField = 'field';
+}
+
+/**
+ * TranslatedArticle class.
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.model
+ */
+class TranslatedArticle extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'TranslatedArticle'
+ * @access public
+ */
+ var $name = 'TranslatedArticle';
+
+/**
+ * cacheQueries property
+ *
+ * @var bool false
+ * @access public
+ */
+ var $cacheQueries = false;
+
+/**
+ * actsAs property
+ *
+ * @var array
+ * @access public
+ */
+ var $actsAs = array('Translate' => array('title', 'body'));
+
+/**
+ * translateModel property
+ *
+ * @var string 'TranslateArticleModel'
+ * @access public
+ */
+ var $translateModel = 'TranslateArticleModel';
+
+/**
+ * belongsTo property
+ *
+ * @var array
+ * @access public
+ */
+ var $belongsTo = array('User');
+}
+
+class CounterCacheUser extends CakeTestModel {
+ var $name = 'CounterCacheUser';
+ var $alias = 'User';
+
+ var $hasMany = array('Post' => array(
+ 'className' => 'CounterCachePost',
+ 'foreignKey' => 'user_id'
+ ));
+}
+
+class CounterCachePost extends CakeTestModel {
+ var $name = 'CounterCachePost';
+ var $alias = 'Post';
+
+ var $belongsTo = array('User' => array(
+ 'className' => 'CounterCacheUser',
+ 'foreignKey' => 'user_id',
+ 'counterCache' => true
+ ));
+}
+
+class CounterCacheUserNonstandardPrimaryKey extends CakeTestModel {
+ var $name = 'CounterCacheUserNonstandardPrimaryKey';
+ var $alias = 'User';
+ var $primaryKey = 'uid';
+
+ var $hasMany = array('Post' => array(
+ 'className' => 'CounterCachePostNonstandardPrimaryKey',
+ 'foreignKey' => 'uid'
+ ));
+}
+
+class CounterCachePostNonstandardPrimaryKey extends CakeTestModel {
+ var $name = 'CounterCachePostNonstandardPrimaryKey';
+ var $alias = 'Post';
+ var $primaryKey = 'pid';
+
+ var $belongsTo = array('User' => array(
+ 'className' => 'CounterCacheUserNonstandardPrimaryKey',
+ 'foreignKey' => 'uid',
+ 'counterCache' => true
+ ));
+}
+
+class ArticleB extends CakeTestModel {
+ var $name = 'ArticleB';
+ var $useTable = 'articles';
+ var $hasAndBelongsToMany = array(
+ 'TagB' => array(
+ 'className' => 'TagB',
+ 'joinTable' => 'articles_tags',
+ 'foreignKey' => 'article_id',
+ 'associationForeignKey' => 'tag_id'
+ )
+ );
+}
+
+class TagB extends CakeTestModel {
+ var $name = 'TagB';
+ var $useTable = 'tags';
+ var $hasAndBelongsToMany = array(
+ 'ArticleB' => array(
+ 'className' => 'ArticleB',
+ 'joinTable' => 'articles_tags',
+ 'foreignKey' => 'tag_id',
+ 'associationForeignKey' => 'article_id'
+ )
+ );
+}
+
+class Fruit extends CakeTestModel {
+ var $name = 'Fruit';
+ var $hasAndBelongsToMany = array(
+ 'UuidTag' => array(
+ 'className' => 'UuidTag',
+ 'joinTable' => 'fruits_uuid_tags',
+ 'foreignKey' => 'fruit_id',
+ 'associationForeignKey' => 'uuid_tag_id',
+ 'with' => 'FruitsUuidTag'
+ )
+ );
+}
+
+class FruitsUuidTag extends CakeTestModel {
+ var $name = 'FruitsUuidTag';
+ var $primaryKey = false;
+ var $belongsTo = array(
+ 'UuidTag' => array(
+ 'className' => 'UuidTag',
+ 'foreignKey' => 'uuid_tag_id',
+ ),
+ 'Fruit' => array(
+ 'className' => 'Fruit',
+ 'foreignKey' => 'fruit_id',
+ )
+ );
+}
+
+class UuidTag extends CakeTestModel {
+ var $name = 'UuidTag';
+ var $hasAndBelongsToMany = array(
+ 'Fruit' => array(
+ 'className' => 'Fruit',
+ 'joinTable' => 'fruits_uuid_tags',
+ 'foreign_key' => 'uuid_tag_id',
+ 'associationForeignKey' => 'fruit_id',
+ 'with' => 'FruitsUuidTag'
+ )
+ );
+}
+
+class FruitNoWith extends CakeTestModel {
+ var $name = 'Fruit';
+ var $useTable = 'fruits';
+ var $hasAndBelongsToMany = array(
+ 'UuidTag' => array(
+ 'className' => 'UuidTagNoWith',
+ 'joinTable' => 'fruits_uuid_tags',
+ 'foreignKey' => 'fruit_id',
+ 'associationForeignKey' => 'uuid_tag_id',
+ )
+ );
+}
+
+class UuidTagNoWith extends CakeTestModel {
+ var $name = 'UuidTag';
+ var $useTable = 'uuid_tags';
+ var $hasAndBelongsToMany = array(
+ 'Fruit' => array(
+ 'className' => 'FruitNoWith',
+ 'joinTable' => 'fruits_uuid_tags',
+ 'foreign_key' => 'uuid_tag_id',
+ 'associationForeignKey' => 'fruit_id',
+ )
+ );
+}
+
+class ProductUpdateAll extends CakeTestModel {
+ var $name = 'ProductUpdateAll';
+ var $useTable = 'product_update_all';
+}
+
+class GroupUpdateAll extends CakeTestModel {
+ var $name = 'GroupUpdateAll';
+ var $useTable = 'group_update_all';
+}
+
+class TransactionTestModel extends CakeTestModel {
+ var $name = 'TransactionTestModel';
+ var $useTable = 'samples';
+
+ function afterSave($created) {
+ $data = array(
+ array('apple_id' => 1, 'name' => 'sample6'),
+ );
+ $this->saveAll($data, array('atomic' => true, 'callbacks' => false));
+ }
+}
\ No newline at end of file
diff --git a/code/ryzom/tools/server/www/webtt/cake/tests/cases/libs/multibyte.test.php b/code/ryzom/tools/server/www/webtt/cake/tests/cases/libs/multibyte.test.php
new file mode 100644
index 000000000..47149c708
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/cake/tests/cases/libs/multibyte.test.php
@@ -0,0 +1,9343 @@
+
+ * Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
+ *
+ * Licensed under The Open Group Test Suite License
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
+ * @link http://book.cakephp.org/view/1196/Testing CakePHP(tm) Tests
+ * @package cake
+ * @subpackage cake.tests.cases.libs
+ * @since CakePHP(tm) v 1.2.0.6833
+ * @license http://www.opensource.org/licenses/opengroup.php The Open Group Test Suite License
+ */
+App::import('Core', 'Multibyte');
+
+/**
+ * MultibyteTest class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs
+ */
+class MultibyteTest extends CakeTestCase {
+
+/**
+ * testUtf8 method
+ *
+ * @access public
+ * @return void
+ */
+ function testUtf8() {
+ $string = '!"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~';
+ $result = Multibyte::utf8($string);
+ $expected = array(33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
+ 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82,
+ 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105,
+ 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126);
+ $this->assertEqual($result, $expected);
+
+ $string = '¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈ';
+ $result = Multibyte::utf8($string);
+ $expected = array(161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181,
+ 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200);
+ $this->assertEqual($result, $expected);
+
+ $string = 'ÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿĀāĂ㥹ĆćĈĉĊċČčĎďĐđĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪīĬ';
+ $result = Multibyte::utf8($string);
+ $expected = array(201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221,
+ 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242,
+ 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263,
+ 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284,
+ 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300);
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĭĮįİıIJijĴĵĶķĸĹĺĻļĽľĿŀŁłŃńŅņŇňʼnŊŋŌōŎŏŐőŒœŔŕŖŗŘřŚśŜŝŞşŠšŢţŤťŦŧŨũŪūŬŭŮůŰűŲųŴŵŶŷŸŹźŻżŽžſƀƁƂƃƄƅƆƇƈƉƊƋƌƍƎƏƐ';
+ $result = Multibyte::utf8($string);
+ $expected = array(301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321,
+ 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342,
+ 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363,
+ 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, 382, 383, 384,
+ 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400);
+ $this->assertEqual($result, $expected);
+
+ $string = 'ƑƒƓƔƕƖƗƘƙƚƛƜƝƞƟƠơƢƣƤƥƦƧƨƩƪƫƬƭƮƯưƱƲƳƴƵƶƷƸƹƺƻƼƽƾƿǀǁǂǃDŽDždžLJLjljNJNjnjǍǎǏǐǑǒǓǔǕǖǗǘǙǚǛǜǝǞǟǠǡǢǣǤǥǦǧǨǩǪǫǬǭǮǯǰDZDzdzǴ';
+ $result = Multibyte::utf8($string);
+ $expected = array(401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 421,
+ 422, 423, 424, 425, 426, 427, 428, 429, 430, 431, 432, 433, 434, 435, 436, 437, 438, 439, 440, 441, 442,
+ 443, 444, 445, 446, 447, 448, 449, 450, 451, 452, 453, 454, 455, 456, 457, 458, 459, 460, 461, 462, 463,
+ 464, 465, 466, 467, 468, 469, 470, 471, 472, 473, 474, 475, 476, 477, 478, 479, 480, 481, 482, 483, 484,
+ 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, 500);
+ $this->assertEqual($result, $expected);
+
+ $string = 'əɚɛɜɝɞɟɠɡɢɣɤɥɦɧɨɩɪɫɬɭɮɯɰɱɲɳɴɵɶɷɸɹɺɻɼɽɾɿʀʁʂʃʄʅʆʇʈʉʊʋʌʍʎʏʐʑʒʓʔʕʖʗʘʙʚʛʜʝʞʟʠʡʢʣʤʥʦʧʨʩʪʫʬʭʮʯʰʱʲʳʴʵʶʷʸʹʺʻʼ';
+ $result = Multibyte::utf8($string);
+ $expected = array(601, 602, 603, 604, 605, 606, 607, 608, 609, 610, 611, 612, 613, 614, 615, 616, 617, 618, 619, 620, 621,
+ 622, 623, 624, 625, 626, 627, 628, 629, 630, 631, 632, 633, 634, 635, 636, 637, 638, 639, 640, 641, 642,
+ 643, 644, 645, 646, 647, 648, 649, 650, 651, 652, 653, 654, 655, 656, 657, 658, 659, 660, 661, 662, 663,
+ 664, 665, 666, 667, 668, 669, 670, 671, 672, 673, 674, 675, 676, 677, 678, 679, 680, 681, 682, 683, 684,
+ 685, 686, 687, 688, 689, 690, 691, 692, 693, 694, 695, 696, 697, 698, 699, 700);
+ $this->assertEqual($result, $expected);
+
+ $string = 'ЀЁЂЃЄЅІЇЈЉЊЋЌЍЎЏАБВГДЕЖЗИЙКЛ';
+ $result = Multibyte::utf8($string);
+ $expected = array(1024, 1025, 1026, 1027, 1028, 1029, 1030, 1031, 1032, 1033, 1034, 1035, 1036, 1037, 1038, 1039, 1040, 1041,
+ 1042, 1043, 1044, 1045, 1046, 1047, 1048, 1049, 1050, 1051);
+ $this->assertEqual($result, $expected);
+
+ $string = 'МНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыь';
+ $result = Multibyte::utf8($string);
+ $expected = array(1052, 1053, 1054, 1055, 1056, 1057, 1058, 1059, 1060, 1061, 1062, 1063, 1064, 1065, 1066, 1067, 1068, 1069,
+ 1070, 1071, 1072, 1073, 1074, 1075, 1076, 1077, 1078, 1079, 1080, 1081, 1082, 1083, 1084, 1085, 1086, 1087,
+ 1088, 1089, 1090, 1091, 1092, 1093, 1094, 1095, 1096, 1097, 1098, 1099, 1100);
+ $this->assertEqual($result, $expected);
+
+ $string = 'չպջռսվտ';
+ $result = Multibyte::utf8($string);
+ $expected = array(1401, 1402, 1403, 1404, 1405, 1406, 1407);
+ $this->assertEqual($result, $expected);
+
+ $string = 'فقكلمنهوىيًٌٍَُ';
+ $result = Multibyte::utf8($string);
+ $expected = array(1601, 1602, 1603, 1604, 1605, 1606, 1607, 1608, 1609, 1610, 1611, 1612, 1613, 1614, 1615);
+ $this->assertEqual($result, $expected);
+
+ $string = '✰✱✲✳✴✵✶✷✸✹✺✻✼✽✾✿❀❁❂❃❄❅❆❇❈❉❊❋❌❍❎❏❐❑❒❓❔❕❖❗❘❙❚❛❜❝❞';
+ $result = Multibyte::utf8($string);
+ $expected = array(10032, 10033, 10034, 10035, 10036, 10037, 10038, 10039, 10040, 10041, 10042, 10043, 10044,
+ 10045, 10046, 10047, 10048, 10049, 10050, 10051, 10052, 10053, 10054, 10055, 10056, 10057,
+ 10058, 10059, 10060, 10061, 10062, 10063, 10064, 10065, 10066, 10067, 10068, 10069, 10070,
+ 10071, 10072, 10073, 10074, 10075, 10076, 10077, 10078);
+ $this->assertEqual($result, $expected);
+
+ $string = '⺀⺁⺂⺃⺄⺅⺆⺇⺈⺉⺊⺋⺌⺍⺎⺏⺐⺑⺒⺓⺔⺕⺖⺗⺘⺙⺛⺜⺝⺞⺟⺠⺡⺢⺣⺤⺥⺦⺧⺨⺩⺪⺫⺬⺭⺮⺯⺰⺱⺲⺳⺴⺵⺶⺷⺸⺹⺺⺻⺼⺽⺾⺿⻀⻁⻂⻃⻄⻅⻆⻇⻈⻉⻊⻋⻌⻍⻎⻏⻐⻑⻒⻓⻔⻕⻖⻗⻘⻙⻚⻛⻜⻝⻞⻟⻠';
+ $result = Multibyte::utf8($string);
+ $expected = array(11904, 11905, 11906, 11907, 11908, 11909, 11910, 11911, 11912, 11913, 11914, 11915, 11916, 11917, 11918, 11919,
+ 11920, 11921, 11922, 11923, 11924, 11925, 11926, 11927, 11928, 11929, 11931, 11932, 11933, 11934, 11935, 11936,
+ 11937, 11938, 11939, 11940, 11941, 11942, 11943, 11944, 11945, 11946, 11947, 11948, 11949, 11950, 11951, 11952,
+ 11953, 11954, 11955, 11956, 11957, 11958, 11959, 11960, 11961, 11962, 11963, 11964, 11965, 11966, 11967, 11968,
+ 11969, 11970, 11971, 11972, 11973, 11974, 11975, 11976, 11977, 11978, 11979, 11980, 11981, 11982, 11983, 11984,
+ 11985, 11986, 11987, 11988, 11989, 11990, 11991, 11992, 11993, 11994, 11995, 11996, 11997, 11998, 11999, 12000);
+ $this->assertEqual($result, $expected);
+
+ $string = '⽅⽆⽇⽈⽉⽊⽋⽌⽍⽎⽏⽐⽑⽒⽓⽔⽕⽖⽗⽘⽙⽚⽛⽜⽝⽞⽟⽠⽡⽢⽣⽤⽥⽦⽧⽨⽩⽪⽫⽬⽭⽮⽯⽰⽱⽲⽳⽴⽵⽶⽷⽸⽹⽺⽻⽼⽽⽾⽿';
+ $result = Multibyte::utf8($string);
+ $expected = array(12101, 12102, 12103, 12104, 12105, 12106, 12107, 12108, 12109, 12110, 12111, 12112, 12113, 12114, 12115, 12116,
+ 12117, 12118, 12119, 12120, 12121, 12122, 12123, 12124, 12125, 12126, 12127, 12128, 12129, 12130, 12131, 12132,
+ 12133, 12134, 12135, 12136, 12137, 12138, 12139, 12140, 12141, 12142, 12143, 12144, 12145, 12146, 12147, 12148,
+ 12149, 12150, 12151, 12152, 12153, 12154, 12155, 12156, 12157, 12158, 12159);
+ $this->assertEqual($result, $expected);
+
+ $string = '눡눢눣눤눥눦눧눨눩눪눫눬눭눮눯눰눱눲눳눴눵눶눷눸눹눺눻눼눽눾눿뉀뉁뉂뉃뉄뉅뉆뉇뉈뉉뉊뉋뉌뉍뉎뉏뉐뉑뉒뉓뉔뉕뉖뉗뉘뉙뉚뉛뉜뉝뉞뉟뉠뉡뉢뉣뉤뉥뉦뉧뉨뉩뉪뉫뉬뉭뉮뉯뉰뉱뉲뉳뉴뉵뉶뉷뉸뉹뉺뉻뉼뉽뉾뉿늀늁늂늃늄';
+ $result = Multibyte::utf8($string);
+ $expected = array(45601, 45602, 45603, 45604, 45605, 45606, 45607, 45608, 45609, 45610, 45611, 45612, 45613, 45614, 45615, 45616,
+ 45617, 45618, 45619, 45620, 45621, 45622, 45623, 45624, 45625, 45626, 45627, 45628, 45629, 45630, 45631, 45632,
+ 45633, 45634, 45635, 45636, 45637, 45638, 45639, 45640, 45641, 45642, 45643, 45644, 45645, 45646, 45647, 45648,
+ 45649, 45650, 45651, 45652, 45653, 45654, 45655, 45656, 45657, 45658, 45659, 45660, 45661, 45662, 45663, 45664,
+ 45665, 45666, 45667, 45668, 45669, 45670, 45671, 45672, 45673, 45674, 45675, 45676, 45677, 45678, 45679, 45680,
+ 45681, 45682, 45683, 45684, 45685, 45686, 45687, 45688, 45689, 45690, 45691, 45692, 45693, 45694, 45695, 45696,
+ 45697, 45698, 45699, 45700);
+ $this->assertEqual($result, $expected);
+
+ $string = 'ﹰﹱﹲﹳﹴﹶﹷﹸﹹﹺﹻﹼﹽﹾﹿﺀﺁﺂﺃﺄﺅﺆﺇﺈﺉﺊﺋﺌﺍﺎﺏﺐﺑﺒﺓﺔﺕﺖﺗﺘﺙﺚﺛﺜﺝﺞﺟﺠﺡﺢﺣﺤﺥﺦﺧﺨﺩﺪﺫﺬﺭﺮﺯﺰ';
+ $result = Multibyte::utf8($string);
+ $expected = array(65136, 65137, 65138, 65139, 65140, 65141, 65142, 65143, 65144, 65145, 65146, 65147, 65148, 65149, 65150, 65151,
+ 65152, 65153, 65154, 65155, 65156, 65157, 65158, 65159, 65160, 65161, 65162, 65163, 65164, 65165, 65166, 65167,
+ 65168, 65169, 65170, 65171, 65172, 65173, 65174, 65175, 65176, 65177, 65178, 65179, 65180, 65181, 65182, 65183,
+ 65184, 65185, 65186, 65187, 65188, 65189, 65190, 65191, 65192, 65193, 65194, 65195, 65196, 65197, 65198, 65199,
+ 65200);
+ $this->assertEqual($result, $expected);
+
+ $string = 'ﺱﺲﺳﺴﺵﺶﺷﺸﺹﺺﺻﺼﺽﺾﺿﻀﻁﻂﻃﻄﻅﻆﻇﻈﻉﻊﻋﻌﻍﻎﻏﻐﻑﻒﻓﻔﻕﻖﻗﻘﻙﻚﻛﻜﻝﻞﻟﻠﻡﻢﻣﻤﻥﻦﻧﻨﻩﻪﻫﻬﻭﻮﻯﻰﻱﻲﻳﻴﻵﻶﻷﻸﻹﻺﻻﻼ';
+ $result = Multibyte::utf8($string);
+ $expected = array(65201, 65202, 65203, 65204, 65205, 65206, 65207, 65208, 65209, 65210, 65211, 65212, 65213, 65214, 65215, 65216,
+ 65217, 65218, 65219, 65220, 65221, 65222, 65223, 65224, 65225, 65226, 65227, 65228, 65229, 65230, 65231, 65232,
+ 65233, 65234, 65235, 65236, 65237, 65238, 65239, 65240, 65241, 65242, 65243, 65244, 65245, 65246, 65247, 65248,
+ 65249, 65250, 65251, 65252, 65253, 65254, 65255, 65256, 65257, 65258, 65259, 65260, 65261, 65262, 65263, 65264,
+ 65265, 65266, 65267, 65268, 65269, 65270, 65271, 65272, 65273, 65274, 65275, 65276);
+ $this->assertEqual($result, $expected);
+
+
+ $string = 'abcdefghijklmnopqrstuvwxyz';
+ $result = Multibyte::utf8($string);
+ $expected = array(65345, 65346, 65347, 65348, 65349, 65350, 65351, 65352, 65353, 65354, 65355, 65356, 65357, 65358, 65359, 65360,
+ 65361, 65362, 65363, 65364, 65365, 65366, 65367, 65368, 65369, 65370);
+ $this->assertEqual($result, $expected);
+
+
+ $string = '。「」、・ヲァィゥェォャュョッーアイウエオカキク';
+ $result = Multibyte::utf8($string);
+ $expected = array(65377, 65378, 65379, 65380, 65381, 65382, 65383, 65384, 65385, 65386, 65387, 65388, 65389, 65390, 65391, 65392,
+ 65393, 65394, 65395, 65396, 65397, 65398, 65399, 65400);
+ $this->assertEqual($result, $expected);
+
+ $string = 'ケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン゙';
+ $result = Multibyte::utf8($string);
+ $expected = array(65401, 65402, 65403, 65404, 65405, 65406, 65407, 65408, 65409, 65410, 65411, 65412, 65413, 65414, 65415, 65416,
+ 65417, 65418, 65419, 65420, 65421, 65422, 65423, 65424, 65425, 65426, 65427, 65428, 65429, 65430, 65431, 65432,
+ 65433, 65434, 65435, 65436, 65437, 65438);
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ĥēĺļŏ, Ŵőřļď!';
+ $result = Multibyte::utf8($string);
+ $expected = array(292, 275, 314, 316, 335, 44, 32, 372, 337, 345, 316, 271, 33);
+ $this->assertEqual($result, $expected);
+
+ $string = 'Hello, World!';
+ $result = Multibyte::utf8($string);
+ $expected = array(72, 101, 108, 108, 111, 44, 32, 87, 111, 114, 108, 100, 33);
+ $this->assertEqual($result, $expected);
+
+ $string = '¨';
+ $result = Multibyte::utf8($string);
+ $expected = array(168);
+ $this->assertEqual($result, $expected);
+
+ $string = '¿';
+ $result = Multibyte::utf8($string);
+ $expected = array(191);
+ $this->assertEqual($result, $expected);
+
+ $string = 'čini';
+ $result = Multibyte::utf8($string);
+ $expected = array(269, 105, 110, 105);
+ $this->assertEqual($result, $expected);
+
+ $string = 'moći';
+ $result = Multibyte::utf8($string);
+ $expected = array(109, 111, 263, 105);
+ $this->assertEqual($result, $expected);
+
+ $string = 'državni';
+ $result = Multibyte::utf8($string);
+ $expected = array(100, 114, 382, 97, 118, 110, 105);
+ $this->assertEqual($result, $expected);
+
+ $string = '把百度设为首页';
+ $result = Multibyte::utf8($string);
+ $expected = array(25226, 30334, 24230, 35774, 20026, 39318, 39029);
+ $this->assertEqual($result, $expected);
+
+ $string = '一二三周永龍';
+ $result = Multibyte::utf8($string);
+ $expected = array(19968, 20108, 19977, 21608, 27704, 40845);
+ $this->assertEqual($result, $expected);
+
+ $string = 'ԀԂԄԆԈԊԌԎԐԒ';
+ $result = Multibyte::utf8($string);
+ $expected = array(1280, 1282, 1284, 1286, 1288, 1290, 1292, 1294, 1296, 1298);
+ $this->assertEqual($result, $expected);
+
+ $string = 'ԁԃԅԇԉԋԍԏԐԒ';
+ $result = Multibyte::utf8($string);
+ $expected = array(1281, 1283, 1285, 1287, 1289, 1291, 1293, 1295, 1296, 1298);
+ $this->assertEqual($result, $expected);
+
+ $string = 'ԱԲԳԴԵԶԷԸԹԺԻԼԽԾԿՀՁՂՃՄՅՆՇՈՉՊՋՌՍՎՏՐՑՒՓՔՕՖև';
+ $result = Multibyte::utf8($string);
+ $expected = array(1329, 1330, 1331, 1332, 1333, 1334, 1335, 1336, 1337, 1338, 1339, 1340, 1341, 1342, 1343, 1344, 1345, 1346,
+ 1347, 1348, 1349, 1350, 1351, 1352, 1353, 1354, 1355, 1356, 1357, 1358, 1359, 1360, 1361, 1362, 1363, 1364,
+ 1365, 1366, 1415);
+ $this->assertEqual($result, $expected);
+
+ $string = 'աբգդեզէըթժիլխծկհձղճմյնշոչպջռսվտրցւփքօֆև';
+ $result = Multibyte::utf8($string);
+ $expected = array(1377, 1378, 1379, 1380, 1381, 1382, 1383, 1384, 1385, 1386, 1387, 1388, 1389, 1390, 1391, 1392, 1393, 1394,
+ 1395, 1396, 1397, 1398, 1399, 1400, 1401, 1402, 1403, 1404, 1405, 1406, 1407, 1408, 1409, 1410, 1411, 1412,
+ 1413, 1414, 1415);
+ $this->assertEqual($result, $expected);
+
+ $string = 'ႠႡႢႣႤႥႦႧႨႩႪႫႬႭႮႯႰႱႲႳႴႵႶႷႸႹႺႻႼႽႾႿჀჁჂჃჄჅ';
+ $result = Multibyte::utf8($string);
+ $expected = array(4256, 4257, 4258, 4259, 4260, 4261, 4262, 4263, 4264, 4265, 4266, 4267, 4268, 4269, 4270, 4271, 4272, 4273,
+ 4274, 4275, 4276, 4277, 4278, 4279, 4280, 4281, 4282, 4283, 4284, 4285, 4286, 4287, 4288, 4289, 4290, 4291,
+ 4292, 4293);
+ $this->assertEqual($result, $expected);
+
+ $string = 'ḀḂḄḆḈḊḌḎḐḒḔḖḘḚḜḞḠḢḤḦḨḪḬḮḰḲḴḶḸḺḼḾṀṂṄṆṈṊṌṎṐṒṔṖṘṚṜṞṠṢṤṦṨṪṬṮṰṲṴṶṸṺṼṾẀẂẄẆẈẊẌẎẐẒẔẖẗẘẙẚẠẢẤẦẨẪẬẮẰẲẴẶẸẺẼẾỀỂỄỆỈỊỌỎỐỒỔỖỘỚỜỞỠỢỤỦỨỪỬỮỰỲỴỶỸ';
+ $result = Multibyte::utf8($string);
+ $expected = array(7680, 7682, 7684, 7686, 7688, 7690, 7692, 7694, 7696, 7698, 7700, 7702, 7704, 7706, 7708, 7710, 7712, 7714,
+ 7716, 7718, 7720, 7722, 7724, 7726, 7728, 7730, 7732, 7734, 7736, 7738, 7740, 7742, 7744, 7746, 7748, 7750,
+ 7752, 7754, 7756, 7758, 7760, 7762, 7764, 7766, 7768, 7770, 7772, 7774, 7776, 7778, 7780, 7782, 7784, 7786,
+ 7788, 7790, 7792, 7794, 7796, 7798, 7800, 7802, 7804, 7806, 7808, 7810, 7812, 7814, 7816, 7818, 7820, 7822,
+ 7824, 7826, 7828, 7830, 7831, 7832, 7833, 7834, 7840, 7842, 7844, 7846, 7848, 7850, 7852, 7854, 7856,
+ 7858, 7860, 7862, 7864, 7866, 7868, 7870, 7872, 7874, 7876, 7878, 7880, 7882, 7884, 7886, 7888, 7890, 7892,
+ 7894, 7896, 7898, 7900, 7902, 7904, 7906, 7908, 7910, 7912, 7914, 7916, 7918, 7920, 7922, 7924, 7926, 7928);
+ $this->assertEqual($result, $expected);
+
+ $string = 'ḁḃḅḇḉḋḍḏḑḓḕḗḙḛḝḟḡḣḥḧḩḫḭḯḱḳḵḷḹḻḽḿṁṃṅṇṉṋṍṏṑṓṕṗṙṛṝṟṡṣṥṧṩṫṭṯṱṳṵṷṹṻṽṿẁẃẅẇẉẋẍẏẑẓẕẖẗẘẙẚạảấầẩẫậắằẳẵặẹẻẽếềểễệỉịọỏốồổỗộớờởỡợụủứừửữựỳỵỷỹ';
+ $result = Multibyte::utf8($string);
+ $expected = array(7681, 7683, 7685, 7687, 7689, 7691, 7693, 7695, 7697, 7699, 7701, 7703, 7705, 7707, 7709, 7711, 7713, 7715,
+ 7717, 7719, 7721, 7723, 7725, 7727, 7729, 7731, 7733, 7735, 7737, 7739, 7741, 7743, 7745, 7747, 7749, 7751,
+ 7753, 7755, 7757, 7759, 7761, 7763, 7765, 7767, 7769, 7771, 7773, 7775, 7777, 7779, 7781, 7783, 7785, 7787,
+ 7789, 7791, 7793, 7795, 7797, 7799, 7801, 7803, 7805, 7807, 7809, 7811, 7813, 7815, 7817, 7819, 7821, 7823,
+ 7825, 7827, 7829, 7830, 7831, 7832, 7833, 7834, 7841, 7843, 7845, 7847, 7849, 7851, 7853, 7855, 7857, 7859,
+ 7861, 7863, 7865, 7867, 7869, 7871, 7873, 7875, 7877, 7879, 7881, 7883, 7885, 7887, 7889, 7891, 7893, 7895,
+ 7897, 7899, 7901, 7903, 7905, 7907, 7909, 7911, 7913, 7915, 7917, 7919, 7921, 7923, 7925, 7927, 7929);
+ $this->assertEqual($result, $expected);
+
+ $string = 'ΩKÅℲ';
+ $result = Multibyte::utf8($string);
+ $expected = array(8486, 8490, 8491, 8498);
+ $this->assertEqual($result, $expected);
+
+ $string = 'ωkåⅎ';
+ $result = Multibyte::utf8($string);
+ $expected = array(969, 107, 229, 8526);
+ $this->assertEqual($result, $expected);
+
+ $string = 'ⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩⅪⅫⅬⅭⅮⅯↃ';
+ $result = Multibyte::utf8($string);
+ $expected = array(8544, 8545, 8546, 8547, 8548, 8549, 8550, 8551, 8552, 8553, 8554, 8555, 8556, 8557, 8558, 8559, 8579);
+ $this->assertEqual($result, $expected);
+
+ $string = 'ⅰⅱⅲⅳⅴⅵⅶⅷⅸⅹⅺⅻⅼⅽⅾⅿↄ';
+ $result = Multibyte::utf8($string);
+ $expected = array(8560, 8561, 8562, 8563, 8564, 8565, 8566, 8567, 8568, 8569, 8570, 8571, 8572, 8573, 8574, 8575, 8580);
+ $this->assertEqual($result, $expected);
+
+ $string = 'ⒶⒷⒸⒹⒺⒻⒼⒽⒾⒿⓀⓁⓂⓃⓄⓅⓆⓇⓈⓉⓊⓋⓌⓍⓎⓏ';
+ $result = Multibyte::utf8($string);
+ $expected = array(9398, 9399, 9400, 9401, 9402, 9403, 9404, 9405, 9406, 9407, 9408, 9409, 9410, 9411, 9412, 9413, 9414,
+ 9415, 9416, 9417, 9418, 9419, 9420, 9421, 9422, 9423);
+ $this->assertEqual($result, $expected);
+
+ $string = 'ⓐⓑⓒⓓⓔⓕⓖⓗⓘⓙⓚⓛⓜⓝⓞⓟⓠⓡⓢⓣⓤⓥⓦⓧⓨⓩ';
+ $result = Multibyte::utf8($string);
+ $expected = array(9424, 9425, 9426, 9427, 9428, 9429, 9430, 9431, 9432, 9433, 9434, 9435, 9436, 9437, 9438, 9439, 9440, 9441,
+ 9442, 9443, 9444, 9445, 9446, 9447, 9448, 9449);
+ $this->assertEqual($result, $expected);
+
+ $string = 'ⰀⰁⰂⰃⰄⰅⰆⰇⰈⰉⰊⰋⰌⰍⰎⰏⰐⰑⰒⰓⰔⰕⰖⰗⰘⰙⰚⰛⰜⰝⰞⰟⰠⰡⰢⰣⰤⰥⰦⰧⰨⰩⰪⰫⰬⰭⰮ';
+ $result = Multibyte::utf8($string);
+ $expected = array(11264, 11265, 11266, 11267, 11268, 11269, 11270, 11271, 11272, 11273, 11274, 11275, 11276, 11277, 11278,
+ 11279, 11280, 11281, 11282, 11283, 11284, 11285, 11286, 11287, 11288, 11289, 11290, 11291, 11292, 11293,
+ 11294, 11295, 11296, 11297, 11298, 11299, 11300, 11301, 11302, 11303, 11304, 11305, 11306, 11307, 11308,
+ 11309, 11310);
+ $this->assertEqual($result, $expected);
+
+ $string = 'ⰰⰱⰲⰳⰴⰵⰶⰷⰸⰹⰺⰻⰼⰽⰾⰿⱀⱁⱂⱃⱄⱅⱆⱇⱈⱉⱊⱋⱌⱍⱎⱏⱐⱑⱒⱓⱔⱕⱖⱗⱘⱙⱚⱛⱜⱝⱞ';
+ $result = Multibyte::utf8($string);
+ $expected = array(11312, 11313, 11314, 11315, 11316, 11317, 11318, 11319, 11320, 11321, 11322, 11323, 11324, 11325, 11326, 11327,
+ 11328, 11329, 11330, 11331, 11332, 11333, 11334, 11335, 11336, 11337, 11338, 11339, 11340, 11341, 11342, 11343,
+ 11344, 11345, 11346, 11347, 11348, 11349, 11350, 11351, 11352, 11353, 11354, 11355, 11356, 11357, 11358);
+ $this->assertEqual($result, $expected);
+
+ $string = 'ⲀⲂⲄⲆⲈⲊⲌⲎⲐⲒⲔⲖⲘⲚⲜⲞⲠⲢⲤⲦⲨⲪⲬⲮⲰⲲⲴⲶⲸⲺⲼⲾⳀⳂⳄⳆⳈⳊⳌⳎⳐⳒⳔⳖⳘⳚⳜⳞⳠⳢ';
+ $result = Multibyte::utf8($string);
+ $expected = array(11392, 11394, 11396, 11398, 11400, 11402, 11404, 11406, 11408, 11410, 11412, 11414, 11416, 11418, 11420,
+ 11422, 11424, 11426, 11428, 11430, 11432, 11434, 11436, 11438, 11440, 11442, 11444, 11446, 11448, 11450,
+ 11452, 11454, 11456, 11458, 11460, 11462, 11464, 11466, 11468, 11470, 11472, 11474, 11476, 11478, 11480,
+ 11482, 11484, 11486, 11488, 11490);
+ $this->assertEqual($result, $expected);
+
+ $string = 'ⲁⲃⲅⲇⲉⲋⲍⲏⲑⲓⲕⲗⲙⲛⲝⲟⲡⲣⲥⲧⲩⲫⲭⲯⲱⲳⲵⲷⲹⲻⲽⲿⳁⳃⳅⳇⳉⳋⳍⳏⳑⳓⳕⳗⳙⳛⳝⳟⳡⳣ';
+ $result = Multibyte::utf8($string);
+ $expected = array(11393, 11395, 11397, 11399, 11401, 11403, 11405, 11407, 11409, 11411, 11413, 11415, 11417, 11419, 11421, 11423,
+ 11425, 11427, 11429, 11431, 11433, 11435, 11437, 11439, 11441, 11443, 11445, 11447, 11449, 11451, 11453, 11455,
+ 11457, 11459, 11461, 11463, 11465, 11467, 11469, 11471, 11473, 11475, 11477, 11479, 11481, 11483, 11485, 11487,
+ 11489, 11491);
+ $this->assertEqual($result, $expected);
+
+
+ $string = 'fffiflffifflſtstﬓﬔﬕﬖﬗ';
+ $result = Multibyte::utf8($string);
+ $expected = array(64256, 64257, 64258, 64259, 64260, 64261, 64262, 64275, 64276, 64277, 64278, 64279);
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testAscii method
+ *
+ * @access public
+ * @return void
+ */
+ function testAscii() {
+ $utf8 = array(33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
+ 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82,
+ 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105,
+ 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126);
+ $result = Multibyte::ascii($utf8);
+
+ $expected = '!"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~';
+ $this->assertEqual($result, $expected);
+
+ $utf8 = array(161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181,
+ 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200);
+ $result = Multibyte::ascii($utf8);
+
+ $expected = '¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈ';
+ $this->assertEqual($result, $expected);
+
+ $utf8 = array(201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221,
+ 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242,
+ 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263,
+ 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284,
+ 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300);
+ $result = Multibyte::ascii($utf8);
+ $expected = 'ÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿĀāĂ㥹ĆćĈĉĊċČčĎďĐđĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪīĬ';
+ $this->assertEqual($result, $expected);
+
+ $utf8 = array(301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321,
+ 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342,
+ 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363,
+ 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, 382, 383, 384,
+ 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400);
+ $expected = 'ĭĮįİıIJijĴĵĶķĸĹĺĻļĽľĿŀŁłŃńŅņŇňʼnŊŋŌōŎŏŐőŒœŔŕŖŗŘřŚśŜŝŞşŠšŢţŤťŦŧŨũŪūŬŭŮůŰűŲųŴŵŶŷŸŹźŻżŽžſƀƁƂƃƄƅƆƇƈƉƊƋƌƍƎƏƐ';
+ $result = Multibyte::ascii($utf8);
+ $this->assertEqual($result, $expected);
+
+ $utf8 = array(401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 421,
+ 422, 423, 424, 425, 426, 427, 428, 429, 430, 431, 432, 433, 434, 435, 436, 437, 438, 439, 440, 441, 442,
+ 443, 444, 445, 446, 447, 448, 449, 450, 451, 452, 453, 454, 455, 456, 457, 458, 459, 460, 461, 462, 463,
+ 464, 465, 466, 467, 468, 469, 470, 471, 472, 473, 474, 475, 476, 477, 478, 479, 480, 481, 482, 483, 484,
+ 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, 495, 496, 497, 498, 499, 500);
+ $expected = 'ƑƒƓƔƕƖƗƘƙƚƛƜƝƞƟƠơƢƣƤƥƦƧƨƩƪƫƬƭƮƯưƱƲƳƴƵƶƷƸƹƺƻƼƽƾƿǀǁǂǃDŽDždžLJLjljNJNjnjǍǎǏǐǑǒǓǔǕǖǗǘǙǚǛǜǝǞǟǠǡǢǣǤǥǦǧǨǩǪǫǬǭǮǯǰDZDzdzǴ';
+ $result = Multibyte::ascii($utf8);
+ $this->assertEqual($result, $expected);
+
+ $utf8 = array(601, 602, 603, 604, 605, 606, 607, 608, 609, 610, 611, 612, 613, 614, 615, 616, 617, 618, 619, 620, 621,
+ 622, 623, 624, 625, 626, 627, 628, 629, 630, 631, 632, 633, 634, 635, 636, 637, 638, 639, 640, 641, 642,
+ 643, 644, 645, 646, 647, 648, 649, 650, 651, 652, 653, 654, 655, 656, 657, 658, 659, 660, 661, 662, 663,
+ 664, 665, 666, 667, 668, 669, 670, 671, 672, 673, 674, 675, 676, 677, 678, 679, 680, 681, 682, 683, 684,
+ 685, 686, 687, 688, 689, 690, 691, 692, 693, 694, 695, 696, 697, 698, 699, 700);
+ $expected = 'əɚɛɜɝɞɟɠɡɢɣɤɥɦɧɨɩɪɫɬɭɮɯɰɱɲɳɴɵɶɷɸɹɺɻɼɽɾɿʀʁʂʃʄʅʆʇʈʉʊʋʌʍʎʏʐʑʒʓʔʕʖʗʘʙʚʛʜʝʞʟʠʡʢʣʤʥʦʧʨʩʪʫʬʭʮʯʰʱʲʳʴʵʶʷʸʹʺʻʼ';
+ $result = Multibyte::ascii($utf8);
+ $this->assertEqual($result, $expected);
+
+ $utf8 = array(1024, 1025, 1026, 1027, 1028, 1029, 1030, 1031, 1032, 1033, 1034, 1035, 1036, 1037, 1038, 1039, 1040, 1041,
+ 1042, 1043, 1044, 1045, 1046, 1047, 1048, 1049, 1050, 1051);
+ $expected = 'ЀЁЂЃЄЅІЇЈЉЊЋЌЍЎЏАБВГДЕЖЗИЙКЛ';
+ $result = Multibyte::ascii($utf8);
+ $this->assertEqual($result, $expected);
+
+ $utf8 = array(1052, 1053, 1054, 1055, 1056, 1057, 1058, 1059, 1060, 1061, 1062, 1063, 1064, 1065, 1066, 1067, 1068, 1069,
+ 1070, 1071, 1072, 1073, 1074, 1075, 1076, 1077, 1078, 1079, 1080, 1081, 1082, 1083, 1084, 1085, 1086, 1087,
+ 1088, 1089, 1090, 1091, 1092, 1093, 1094, 1095, 1096, 1097, 1098, 1099, 1100);
+ $expected = 'МНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыь';
+ $result = Multibyte::ascii($utf8);
+ $this->assertEqual($result, $expected);
+
+ $utf8 = array(1401, 1402, 1403, 1404, 1405, 1406, 1407);
+ $expected = 'չպջռսվտ';
+ $result = Multibyte::ascii($utf8);
+ $this->assertEqual($result, $expected);
+
+ $utf8 = array(1601, 1602, 1603, 1604, 1605, 1606, 1607, 1608, 1609, 1610, 1611, 1612, 1613, 1614, 1615);
+ $expected = 'فقكلمنهوىيًٌٍَُ';
+ $result = Multibyte::ascii($utf8);
+ $this->assertEqual($result, $expected);
+
+ $utf8 = array(10032, 10033, 10034, 10035, 10036, 10037, 10038, 10039, 10040, 10041, 10042, 10043, 10044,
+ 10045, 10046, 10047, 10048, 10049, 10050, 10051, 10052, 10053, 10054, 10055, 10056, 10057,
+ 10058, 10059, 10060, 10061, 10062, 10063, 10064, 10065, 10066, 10067, 10068, 10069, 10070,
+ 10071, 10072, 10073, 10074, 10075, 10076, 10077, 10078);
+ $expected = '✰✱✲✳✴✵✶✷✸✹✺✻✼✽✾✿❀❁❂❃❄❅❆❇❈❉❊❋❌❍❎❏❐❑❒❓❔❕❖❗❘❙❚❛❜❝❞';
+ $result = Multibyte::ascii($utf8);
+ $this->assertEqual($result, $expected);
+
+ $utf8 = array(11904, 11905, 11906, 11907, 11908, 11909, 11910, 11911, 11912, 11913, 11914, 11915, 11916, 11917, 11918, 11919,
+ 11920, 11921, 11922, 11923, 11924, 11925, 11926, 11927, 11928, 11929, 11931, 11932, 11933, 11934, 11935, 11936,
+ 11937, 11938, 11939, 11940, 11941, 11942, 11943, 11944, 11945, 11946, 11947, 11948, 11949, 11950, 11951, 11952,
+ 11953, 11954, 11955, 11956, 11957, 11958, 11959, 11960, 11961, 11962, 11963, 11964, 11965, 11966, 11967, 11968,
+ 11969, 11970, 11971, 11972, 11973, 11974, 11975, 11976, 11977, 11978, 11979, 11980, 11981, 11982, 11983, 11984,
+ 11985, 11986, 11987, 11988, 11989, 11990, 11991, 11992, 11993, 11994, 11995, 11996, 11997, 11998, 11999, 12000);
+ $expected = '⺀⺁⺂⺃⺄⺅⺆⺇⺈⺉⺊⺋⺌⺍⺎⺏⺐⺑⺒⺓⺔⺕⺖⺗⺘⺙⺛⺜⺝⺞⺟⺠⺡⺢⺣⺤⺥⺦⺧⺨⺩⺪⺫⺬⺭⺮⺯⺰⺱⺲⺳⺴⺵⺶⺷⺸⺹⺺⺻⺼⺽⺾⺿⻀⻁⻂⻃⻄⻅⻆⻇⻈⻉⻊⻋⻌⻍⻎⻏⻐⻑⻒⻓⻔⻕⻖⻗⻘⻙⻚⻛⻜⻝⻞⻟⻠';
+ $result = Multibyte::ascii($utf8);
+ $this->assertEqual($result, $expected);
+
+ $utf8 = array(12101, 12102, 12103, 12104, 12105, 12106, 12107, 12108, 12109, 12110, 12111, 12112, 12113, 12114, 12115, 12116,
+ 12117, 12118, 12119, 12120, 12121, 12122, 12123, 12124, 12125, 12126, 12127, 12128, 12129, 12130, 12131, 12132,
+ 12133, 12134, 12135, 12136, 12137, 12138, 12139, 12140, 12141, 12142, 12143, 12144, 12145, 12146, 12147, 12148,
+ 12149, 12150, 12151, 12152, 12153, 12154, 12155, 12156, 12157, 12158, 12159);
+ $expected = '⽅⽆⽇⽈⽉⽊⽋⽌⽍⽎⽏⽐⽑⽒⽓⽔⽕⽖⽗⽘⽙⽚⽛⽜⽝⽞⽟⽠⽡⽢⽣⽤⽥⽦⽧⽨⽩⽪⽫⽬⽭⽮⽯⽰⽱⽲⽳⽴⽵⽶⽷⽸⽹⽺⽻⽼⽽⽾⽿';
+ $result = Multibyte::ascii($utf8);
+ $this->assertEqual($result, $expected);
+
+ $utf8 = array(45601, 45602, 45603, 45604, 45605, 45606, 45607, 45608, 45609, 45610, 45611, 45612, 45613, 45614, 45615, 45616,
+ 45617, 45618, 45619, 45620, 45621, 45622, 45623, 45624, 45625, 45626, 45627, 45628, 45629, 45630, 45631, 45632,
+ 45633, 45634, 45635, 45636, 45637, 45638, 45639, 45640, 45641, 45642, 45643, 45644, 45645, 45646, 45647, 45648,
+ 45649, 45650, 45651, 45652, 45653, 45654, 45655, 45656, 45657, 45658, 45659, 45660, 45661, 45662, 45663, 45664,
+ 45665, 45666, 45667, 45668, 45669, 45670, 45671, 45672, 45673, 45674, 45675, 45676, 45677, 45678, 45679, 45680,
+ 45681, 45682, 45683, 45684, 45685, 45686, 45687, 45688, 45689, 45690, 45691, 45692, 45693, 45694, 45695, 45696,
+ 45697, 45698, 45699, 45700);
+ $expected = '눡눢눣눤눥눦눧눨눩눪눫눬눭눮눯눰눱눲눳눴눵눶눷눸눹눺눻눼눽눾눿뉀뉁뉂뉃뉄뉅뉆뉇뉈뉉뉊뉋뉌뉍뉎뉏뉐뉑뉒뉓뉔뉕뉖뉗뉘뉙뉚뉛뉜뉝뉞뉟뉠뉡뉢뉣뉤뉥뉦뉧뉨뉩뉪뉫뉬뉭뉮뉯뉰뉱뉲뉳뉴뉵뉶뉷뉸뉹뉺뉻뉼뉽뉾뉿늀늁늂늃늄';
+ $result = Multibyte::ascii($utf8);
+ $this->assertEqual($result, $expected);
+
+ $utf8 = array(65136, 65137, 65138, 65139, 65140, 65141, 65142, 65143, 65144, 65145, 65146, 65147, 65148, 65149, 65150, 65151,
+ 65152, 65153, 65154, 65155, 65156, 65157, 65158, 65159, 65160, 65161, 65162, 65163, 65164, 65165, 65166, 65167,
+ 65168, 65169, 65170, 65171, 65172, 65173, 65174, 65175, 65176, 65177, 65178, 65179, 65180, 65181, 65182, 65183,
+ 65184, 65185, 65186, 65187, 65188, 65189, 65190, 65191, 65192, 65193, 65194, 65195, 65196, 65197, 65198, 65199,
+ 65200);
+ $expected = 'ﹰﹱﹲﹳﹴﹶﹷﹸﹹﹺﹻﹼﹽﹾﹿﺀﺁﺂﺃﺄﺅﺆﺇﺈﺉﺊﺋﺌﺍﺎﺏﺐﺑﺒﺓﺔﺕﺖﺗﺘﺙﺚﺛﺜﺝﺞﺟﺠﺡﺢﺣﺤﺥﺦﺧﺨﺩﺪﺫﺬﺭﺮﺯﺰ';
+ $result = Multibyte::ascii($utf8);
+ $this->assertEqual($result, $expected);
+
+ $utf8 = array(65201, 65202, 65203, 65204, 65205, 65206, 65207, 65208, 65209, 65210, 65211, 65212, 65213, 65214, 65215, 65216,
+ 65217, 65218, 65219, 65220, 65221, 65222, 65223, 65224, 65225, 65226, 65227, 65228, 65229, 65230, 65231, 65232,
+ 65233, 65234, 65235, 65236, 65237, 65238, 65239, 65240, 65241, 65242, 65243, 65244, 65245, 65246, 65247, 65248,
+ 65249, 65250, 65251, 65252, 65253, 65254, 65255, 65256, 65257, 65258, 65259, 65260, 65261, 65262, 65263, 65264,
+ 65265, 65266, 65267, 65268, 65269, 65270, 65271, 65272, 65273, 65274, 65275, 65276);
+ $expected = 'ﺱﺲﺳﺴﺵﺶﺷﺸﺹﺺﺻﺼﺽﺾﺿﻀﻁﻂﻃﻄﻅﻆﻇﻈﻉﻊﻋﻌﻍﻎﻏﻐﻑﻒﻓﻔﻕﻖﻗﻘﻙﻚﻛﻜﻝﻞﻟﻠﻡﻢﻣﻤﻥﻦﻧﻨﻩﻪﻫﻬﻭﻮﻯﻰﻱﻲﻳﻴﻵﻶﻷﻸﻹﻺﻻﻼ';
+ $result = Multibyte::ascii($utf8);
+ $this->assertEqual($result, $expected);
+
+ $utf8 = array(65345, 65346, 65347, 65348, 65349, 65350, 65351, 65352, 65353, 65354, 65355, 65356, 65357, 65358, 65359, 65360,
+ 65361, 65362, 65363, 65364, 65365, 65366, 65367, 65368, 65369, 65370);
+ $expected = 'abcdefghijklmnopqrstuvwxyz';
+ $result = Multibyte::ascii($utf8);
+ $this->assertEqual($result, $expected);
+
+ $utf8 = array(65377, 65378, 65379, 65380, 65381, 65382, 65383, 65384, 65385, 65386, 65387, 65388, 65389, 65390, 65391, 65392,
+ 65393, 65394, 65395, 65396, 65397, 65398, 65399, 65400);
+ $expected = '。「」、・ヲァィゥェォャュョッーアイウエオカキク';
+ $result = Multibyte::ascii($utf8);
+ $this->assertEqual($result, $expected);
+
+ $utf8 = array(65401, 65402, 65403, 65404, 65405, 65406, 65407, 65408, 65409, 65410, 65411, 65412, 65413, 65414, 65415, 65416,
+ 65417, 65418, 65419, 65420, 65421, 65422, 65423, 65424, 65425, 65426, 65427, 65428, 65429, 65430, 65431, 65432,
+ 65433, 65434, 65435, 65436, 65437, 65438);
+ $expected = 'ケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン゙';
+ $result = Multibyte::ascii($utf8);
+ $this->assertEqual($result, $expected);
+
+ $utf8 = array(292, 275, 314, 316, 335, 44, 32, 372, 337, 345, 316, 271, 33);
+ $expected = 'Ĥēĺļŏ, Ŵőřļď!';
+ $result = Multibyte::ascii($utf8);
+ $this->assertEqual($result, $expected);
+
+ $utf8 = array(72, 101, 108, 108, 111, 44, 32, 87, 111, 114, 108, 100, 33);
+ $expected = 'Hello, World!';
+ $result = Multibyte::ascii($utf8);
+ $this->assertEqual($result, $expected);
+
+ $utf8 = array(168);
+ $expected = '¨';
+ $result = Multibyte::ascii($utf8);
+ $this->assertEqual($result, $expected);
+
+ $utf8 = array(191);
+ $expected = '¿';
+ $result = Multibyte::ascii($utf8);
+ $this->assertEqual($result, $expected);
+
+ $utf8 = array(269, 105, 110, 105);
+ $expected = 'čini';
+ $result = Multibyte::ascii($utf8);
+ $this->assertEqual($result, $expected);
+
+ $utf8 = array(109, 111, 263, 105);
+ $expected = 'moći';
+ $result = Multibyte::ascii($utf8);
+ $this->assertEqual($result, $expected);
+
+ $utf8 = array(100, 114, 382, 97, 118, 110, 105);
+ $expected = 'državni';
+ $result = Multibyte::ascii($utf8);
+ $this->assertEqual($result, $expected);
+
+ $utf8 = array(25226, 30334, 24230, 35774, 20026, 39318, 39029);
+ $expected = '把百度设为首页';
+ $result = Multibyte::ascii($utf8);
+ $this->assertEqual($result, $expected);
+
+ $utf8 = array(19968, 20108, 19977, 21608, 27704, 40845);
+ $expected = '一二三周永龍';
+ $result = Multibyte::ascii($utf8);
+ $this->assertEqual($result, $expected);
+
+ $utf8 = array(1280, 1282, 1284, 1286, 1288, 1290, 1292, 1294, 1296, 1298);
+ $expected = 'ԀԂԄԆԈԊԌԎԐԒ';
+ $result = Multibyte::ascii($utf8);
+ $this->assertEqual($result, $expected);
+
+ $utf8 = array(1281, 1283, 1285, 1287, 1289, 1291, 1293, 1295, 1296, 1298);
+ $expected = 'ԁԃԅԇԉԋԍԏԐԒ';
+ $result = Multibyte::ascii($utf8);
+ $this->assertEqual($result, $expected);
+
+ $utf8 = array(1329, 1330, 1331, 1332, 1333, 1334, 1335, 1336, 1337, 1338, 1339, 1340, 1341, 1342, 1343, 1344, 1345, 1346, 1347,
+ 1348, 1349, 1350, 1351, 1352, 1353, 1354, 1355, 1356, 1357, 1358, 1359, 1360, 1361, 1362, 1363, 1364, 1365,
+ 1366, 1415);
+ $result = Multibyte::ascii($utf8);
+ $expected = 'ԱԲԳԴԵԶԷԸԹԺԻԼԽԾԿՀՁՂՃՄՅՆՇՈՉՊՋՌՍՎՏՐՑՒՓՔՕՖև';
+ $this->assertEqual($result, $expected);
+
+ $utf8 = array(1377, 1378, 1379, 1380, 1381, 1382, 1383, 1384, 1385, 1386, 1387, 1388, 1389, 1390, 1391, 1392, 1393, 1394,
+ 1395, 1396, 1397, 1398, 1399, 1400, 1401, 1402, 1403, 1404, 1405, 1406, 1407, 1408, 1409, 1410, 1411, 1412,
+ 1413, 1414, 1415);
+ $result = Multibyte::ascii($utf8);
+ $expected = 'աբգդեզէըթժիլխծկհձղճմյնշոչպջռսվտրցւփքօֆև';
+ $this->assertEqual($result, $expected);
+
+ $utf8 = array(4256, 4257, 4258, 4259, 4260, 4261, 4262, 4263, 4264, 4265, 4266, 4267, 4268, 4269, 4270, 4271, 4272, 4273, 4274,
+ 4275, 4276, 4277, 4278, 4279, 4280, 4281, 4282, 4283, 4284, 4285, 4286, 4287, 4288, 4289, 4290, 4291, 4292, 4293);
+ $result = Multibyte::ascii($utf8);
+ $expected = 'ႠႡႢႣႤႥႦႧႨႩႪႫႬႭႮႯႰႱႲႳႴႵႶႷႸႹႺႻႼႽႾႿჀჁჂჃჄჅ';
+ $this->assertEqual($result, $expected);
+
+ $utf8 = array(7680, 7682, 7684, 7686, 7688, 7690, 7692, 7694, 7696, 7698, 7700, 7702, 7704, 7706, 7708, 7710, 7712, 7714,
+ 7716, 7718, 7720, 7722, 7724, 7726, 7728, 7730, 7732, 7734, 7736, 7738, 7740, 7742, 7744, 7746, 7748, 7750,
+ 7752, 7754, 7756, 7758, 7760, 7762, 7764, 7766, 7768, 7770, 7772, 7774, 7776, 7778, 7780, 7782, 7784, 7786,
+ 7788, 7790, 7792, 7794, 7796, 7798, 7800, 7802, 7804, 7806, 7808, 7810, 7812, 7814, 7816, 7818, 7820, 7822,
+ 7824, 7826, 7828, 7830, 7831, 7832, 7833, 7834, 7840, 7842, 7844, 7846, 7848, 7850, 7852, 7854, 7856,
+ 7858, 7860, 7862, 7864, 7866, 7868, 7870, 7872, 7874, 7876, 7878, 7880, 7882, 7884, 7886, 7888, 7890, 7892,
+ 7894, 7896, 7898, 7900, 7902, 7904, 7906, 7908, 7910, 7912, 7914, 7916, 7918, 7920, 7922, 7924, 7926, 7928);
+ $result = Multibyte::ascii($utf8);
+ $expected = 'ḀḂḄḆḈḊḌḎḐḒḔḖḘḚḜḞḠḢḤḦḨḪḬḮḰḲḴḶḸḺḼḾṀṂṄṆṈṊṌṎṐṒṔṖṘṚṜṞṠṢṤṦṨṪṬṮṰṲṴṶṸṺṼṾẀẂẄẆẈẊẌẎẐẒẔẖẗẘẙẚẠẢẤẦẨẪẬẮẰẲẴẶẸẺẼẾỀỂỄỆỈỊỌỎỐỒỔỖỘỚỜỞỠỢỤỦỨỪỬỮỰỲỴỶỸ';
+ $this->assertEqual($result, $expected);
+
+ $utf8 = array(7681, 7683, 7685, 7687, 7689, 7691, 7693, 7695, 7697, 7699, 7701, 7703, 7705, 7707, 7709, 7711, 7713, 7715,
+ 7717, 7719, 7721, 7723, 7725, 7727, 7729, 7731, 7733, 7735, 7737, 7739, 7741, 7743, 7745, 7747, 7749, 7751,
+ 7753, 7755, 7757, 7759, 7761, 7763, 7765, 7767, 7769, 7771, 7773, 7775, 7777, 7779, 7781, 7783, 7785, 7787,
+ 7789, 7791, 7793, 7795, 7797, 7799, 7801, 7803, 7805, 7807, 7809, 7811, 7813, 7815, 7817, 7819, 7821, 7823,
+ 7825, 7827, 7829, 7830, 7831, 7832, 7833, 7834, 7841, 7843, 7845, 7847, 7849, 7851, 7853, 7855, 7857, 7859,
+ 7861, 7863, 7865, 7867, 7869, 7871, 7873, 7875, 7877, 7879, 7881, 7883, 7885, 7887, 7889, 7891, 7893, 7895,
+ 7897, 7899, 7901, 7903, 7905, 7907, 7909, 7911, 7913, 7915, 7917, 7919, 7921, 7923, 7925, 7927, 7929);
+ $result = Multibyte::ascii($utf8);
+ $expected = 'ḁḃḅḇḉḋḍḏḑḓḕḗḙḛḝḟḡḣḥḧḩḫḭḯḱḳḵḷḹḻḽḿṁṃṅṇṉṋṍṏṑṓṕṗṙṛṝṟṡṣṥṧṩṫṭṯṱṳṵṷṹṻṽṿẁẃẅẇẉẋẍẏẑẓẕẖẗẘẙẚạảấầẩẫậắằẳẵặẹẻẽếềểễệỉịọỏốồổỗộớờởỡợụủứừửữựỳỵỷỹ';
+ $this->assertEqual($result, $expected);
+
+ $utf8 = array(8486, 8490, 8491, 8498);
+ $result = Multibyte::ascii($utf8);
+ $expected = 'ΩKÅℲ';
+ $this->assertEqual($result, $expected);
+
+ $utf8 = array(969, 107, 229, 8526);
+ $result = Multibyte::ascii($utf8);
+ $expected = 'ωkåⅎ';
+ $this->assertEqual($result, $expected);
+
+ $utf8 = array(8544, 8545, 8546, 8547, 8548, 8549, 8550, 8551, 8552, 8553, 8554, 8555, 8556, 8557, 8558, 8559, 8579);
+ $result = Multibyte::ascii($utf8);
+ $expected = 'ⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩⅪⅫⅬⅭⅮⅯↃ';
+ $this->assertEqual($result, $expected);
+
+ $utf8 = array(8560, 8561, 8562, 8563, 8564, 8565, 8566, 8567, 8568, 8569, 8570, 8571, 8572, 8573, 8574, 8575, 8580);
+ $result = Multibyte::ascii($utf8);
+ $expected = 'ⅰⅱⅲⅳⅴⅵⅶⅷⅸⅹⅺⅻⅼⅽⅾⅿↄ';
+ $this->assertEqual($result, $expected);
+
+ $utf8 = array(9398, 9399, 9400, 9401, 9402, 9403, 9404, 9405, 9406, 9407, 9408, 9409, 9410, 9411, 9412, 9413, 9414,
+ 9415, 9416, 9417, 9418, 9419, 9420, 9421, 9422, 9423);
+ $result = Multibyte::ascii($utf8);
+ $expected = 'ⒶⒷⒸⒹⒺⒻⒼⒽⒾⒿⓀⓁⓂⓃⓄⓅⓆⓇⓈⓉⓊⓋⓌⓍⓎⓏ';
+ $this->assertEqual($result, $expected);
+
+ $utf8 = array(9424, 9425, 9426, 9427, 9428, 9429, 9430, 9431, 9432, 9433, 9434, 9435, 9436, 9437, 9438, 9439, 9440, 9441,
+ 9442, 9443, 9444, 9445, 9446, 9447, 9448, 9449);
+ $result = Multibyte::ascii($utf8);
+ $expected = 'ⓐⓑⓒⓓⓔⓕⓖⓗⓘⓙⓚⓛⓜⓝⓞⓟⓠⓡⓢⓣⓤⓥⓦⓧⓨⓩ';
+ $this->assertEqual($result, $expected);
+
+ $utf8 = array(11264, 11265, 11266, 11267, 11268, 11269, 11270, 11271, 11272, 11273, 11274, 11275, 11276, 11277, 11278, 11279,
+ 11280, 11281, 11282, 11283, 11284, 11285, 11286, 11287, 11288, 11289, 11290, 11291, 11292, 11293, 11294, 11295,
+ 11296, 11297, 11298, 11299, 11300, 11301, 11302, 11303, 11304, 11305, 11306, 11307, 11308, 11309, 11310);
+ $result = Multibyte::ascii($utf8);
+ $expected = 'ⰀⰁⰂⰃⰄⰅⰆⰇⰈⰉⰊⰋⰌⰍⰎⰏⰐⰑⰒⰓⰔⰕⰖⰗⰘⰙⰚⰛⰜⰝⰞⰟⰠⰡⰢⰣⰤⰥⰦⰧⰨⰩⰪⰫⰬⰭⰮ';
+ $this->assertEqual($result, $expected);
+
+ $utf8 = array(11312, 11313, 11314, 11315, 11316, 11317, 11318, 11319, 11320, 11321, 11322, 11323, 11324, 11325, 11326, 11327,
+ 11328, 11329, 11330, 11331, 11332, 11333, 11334, 11335, 11336, 11337, 11338, 11339, 11340, 11341, 11342, 11343,
+ 11344, 11345, 11346, 11347, 11348, 11349, 11350, 11351, 11352, 11353, 11354, 11355, 11356, 11357, 11358);
+ $result = Multibyte::ascii($utf8);
+ $expected = 'ⰰⰱⰲⰳⰴⰵⰶⰷⰸⰹⰺⰻⰼⰽⰾⰿⱀⱁⱂⱃⱄⱅⱆⱇⱈⱉⱊⱋⱌⱍⱎⱏⱐⱑⱒⱓⱔⱕⱖⱗⱘⱙⱚⱛⱜⱝⱞ';
+ $this->assertEqual($result, $expected);
+
+ $utf8 = array(11392, 11394, 11396, 11398, 11400, 11402, 11404, 11406, 11408, 11410, 11412, 11414, 11416, 11418, 11420,
+ 11422, 11424, 11426, 11428, 11430, 11432, 11434, 11436, 11438, 11440, 11442, 11444, 11446, 11448, 11450,
+ 11452, 11454, 11456, 11458, 11460, 11462, 11464, 11466, 11468, 11470, 11472, 11474, 11476, 11478, 11480,
+ 11482, 11484, 11486, 11488, 11490);
+ $result = Multibyte::ascii($utf8);
+ $expected = 'ⲀⲂⲄⲆⲈⲊⲌⲎⲐⲒⲔⲖⲘⲚⲜⲞⲠⲢⲤⲦⲨⲪⲬⲮⲰⲲⲴⲶⲸⲺⲼⲾⳀⳂⳄⳆⳈⳊⳌⳎⳐⳒⳔⳖⳘⳚⳜⳞⳠⳢ';
+ $this->assertEqual($result, $expected);
+
+ $utf8 = array(11393, 11395, 11397, 11399, 11401, 11403, 11405, 11407, 11409, 11411, 11413, 11415, 11417, 11419, 11421, 11423,
+ 11425, 11427, 11429, 11431, 11433, 11435, 11437, 11439, 11441, 11443, 11445, 11447, 11449, 11451, 11453, 11455,
+ 11457, 11459, 11461, 11463, 11465, 11467, 11469, 11471, 11473, 11475, 11477, 11479, 11481, 11483, 11485, 11487,
+ 11489, 11491);
+ $result = Multibyte::ascii($utf8);
+ $expected = 'ⲁⲃⲅⲇⲉⲋⲍⲏⲑⲓⲕⲗⲙⲛⲝⲟⲡⲣⲥⲧⲩⲫⲭⲯⲱⲳⲵⲷⲹⲻⲽⲿⳁⳃⳅⳇⳉⳋⳍⳏⳑⳓⳕⳗⳙⳛⳝⳟⳡⳣ';
+ $this->assertEqual($result, $expected);
+
+ $utf8 = array(64256, 64257, 64258, 64259, 64260, 64261, 64262, 64275, 64276, 64277, 64278, 64279);
+ $result = Multibyte::ascii($utf8);
+ $expected = 'fffiflffifflſtstﬓﬔﬕﬖﬗ';
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testUsingMbStripos method
+ *
+ * @access public
+ * @return void
+ */
+ function testUsingMbStripos() {
+ $string = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
+ $find = 'f';
+ $result = mb_stripos($string, $find);
+ $expected = 5;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ABCDEFGHIJKLMNOPQFRSTUVWXYZ0123456789';
+ $find = 'f';
+ $result = mb_stripos($string, $find, 6);
+ $expected = 17;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞ';
+ $find = 'å';
+ $result = mb_stripos($string, $find);
+ $expected = 5;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÅÙÚÛÜÝÞ';
+ $find = 'å';
+ $result = mb_stripos($string, $find, 6);
+ $expected = 24;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĀĂĄĆĈĊČĎĐĒĔĖĘĚĜĞĠĢĤĦĨĪĬĮIJĴĶĹĻĽĿŁŃŅŇŊŌŎŐŒŔŖŘŚŜŞŠŢŤŦŨŪŬŮŰŲŴŶŹŻŽ';
+ $find = 'ċ';
+ $result = mb_stripos($string, $find);
+ $expected = 5;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĀĂĄĆĈĊČĎĐĒĔĖĘĚĜĞĠĢĤĦĨĪĬĮIJĴĶĹĻĽĿŁĊŃŅŇŊŌŎŐŒŔŖŘŚŜŞŠŢŤŦŨŪŬŮŰŲŴŶŹŻŽ';
+ $find = 'ċ';
+ $result = mb_stripos($string, $find, 6);
+ $expected = 32;
+ $this->assertEqual($result, $expected);
+
+ $string = '!"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~';
+ $find = 'f';
+ $result = mb_stripos($string, $find);
+ $expected = 37;
+ $this->assertEqual($result, $expected);
+
+ $string = '¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈ';
+ $find = 'Μ';
+ $result = mb_stripos($string, $find);
+ $expected = 20;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿĀāĂ㥹ĆćĈĉĊċČčĎďĐđĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪīĬ';
+ $find = 'É';
+ $result = mb_stripos($string, $find, 6);
+ $expected = 32;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĭĮįİıIJijĴĵĶķĸĹĺĻļĽľĿŀŁłŃńŅņŇňʼnŊŋŌōŎŏŐőŒœŔŕŖŗŘřŚśŜŝŞşŠšŢţŤťŦŧŨũŪūŬŭŮůŰűŲųŴŵŶŷŸŹźŻżŽžſƀƁƂƃƄƅƆƇƈƉƊƋƌƍƎƏƐ';
+ $find = 'Ņ';
+ $result = mb_stripos($string, $find);
+ $expected = 24;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ƑƒƓƔƕƖƗƘƙƚƛƜƝƞƟƠơƢƣƤƥƦƧƨƩƪƫƬƭƮƯưƱƲƳƴƵƶƷƸƹƺƻƼƽƾƿǀǁǂǃDŽDždžLJLjljNJNjnjǍǎǏǐǑǒǓǔǕǖǗǘǙǚǛǜǝǞǟǠǡǢǣǤǥǦǧǨǩǪǫǬǭǮǯǰDZDzdzǴ';
+ $find = 'Ƹ';
+ $result = mb_stripos($string, $find);
+ $expected = 39;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ƑƒƓƔƕƖƗƘƙƚƛƜƝƞƟƠơƢƣƤƥƦƧƨƩƪƫƬƭƮƯưƱƲƳƴƵƶƷƸƹƺƻƼƽƾƿǀǁǂǃDŽDždžLJLjljNJNjnjǍǎǏǐǑǒǓǔǕǖǗǘǙǚǛǜǝǞǟǠǡǢǣǤǥǦǧǨǩǪǫǬǭǮǯǰDZDzdzǴ';
+ $find = 'Ƹ';
+ $result = mb_stripos($string, $find, 40);
+ $expected = 40;
+ $this->assertEqual($result, $expected);
+
+ $string = 'əɚɛɜɝɞɟɠɡɢɣɤɥɦɧɨɩɪɫɬɭɮɯɰɱɲɳɴɵɶɷɸɹɺɻɼɽɾɿʀʁʂʃʄʅʆʇʈʉʊʋʌʍʎʏʐʑʒʓʔʕʖʗʘʙʚʛʜʝʞʟʠʡʢʣʤʥʦʧʨʩʪʫʬʭʮʯʰʱʲʳʴʵʶʷʸʹʺʻʼ';
+ $find = 'Ʀ';
+ $result = mb_stripos($string, $find);
+ $expected = 39;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ЀЁЂЃЄЅІЇЈЉЊЋЌЍЎЏАБВГДЕЖЗИЙКЛ';
+ $find = 'ї';
+ $result = mb_stripos($string, $find);
+ $expected = 7;
+ $this->assertEqual($result, $expected);
+
+ $string = 'МНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыь';
+ $find = 'Р';
+ $result = mb_stripos($string, $find);
+ $expected = 4;
+ $this->assertEqual($result, $expected);
+
+ $string = 'МНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыь';
+ $find = 'Р';
+ $result = mb_stripos($string, $find, 5);
+ $expected = 36;
+ $this->assertEqual($result, $expected);
+
+ $string = 'فقكلمنهوىيًٌٍَُ';
+ $find = 'ن';
+ $result = mb_stripos($string, $find);
+ $expected = 5;
+ $this->assertEqual($result, $expected);
+
+ $string = '✰✱✲✳✴✵✶✷✸✹✺✻✼✽✾✿❀❁❂❃❄❅❆❇❈❉❊❋❌❍❎❏❐❑❒❓❔❕❖❗❘❙❚❛❜❝❞';
+ $find = '✿';
+ $result = mb_stripos($string, $find);
+ $expected = 15;
+ $this->assertEqual($result, $expected);
+
+ $string = '⺀⺁⺂⺃⺄⺅⺆⺇⺈⺉⺊⺋⺌⺍⺎⺏⺐⺑⺒⺓⺔⺕⺖⺗⺘⺙⺛⺜⺝⺞⺟⺠⺡⺢⺣⺤⺥⺦⺧⺨⺩⺪⺫⺬⺭⺮⺯⺰⺱⺲⺳⺴⺵⺶⺷⺸⺹⺺⺻⺼⺽⺾⺿⻀⻁⻂⻃⻄⻅⻆⻇⻈⻉⻊⻋⻌⻍⻎⻏⻐⻑⻒⻓⻔⻕⻖⻗⻘⻙⻚⻛⻜⻝⻞⻟⻠';
+ $find = '⺐';
+ $result = mb_stripos($string, $find);
+ $expected = 16;
+ $this->assertEqual($result, $expected);
+
+ $string = '⽅⽆⽇⽈⽉⽊⽋⽌⽍⽎⽏⽐⽑⽒⽓⽔⽕⽖⽗⽘⽙⽚⽛⽜⽝⽞⽟⽠⽡⽢⽣⽤⽥⽦⽧⽨⽩⽪⽫⽬⽭⽮⽯⽰⽱⽲⽳⽴⽵⽶⽷⽸⽹⽺⽻⽼⽽⽾⽿';
+ $find = '⽤';
+ $result = mb_stripos($string, $find);
+ $expected = 31;
+ $this->assertEqual($result, $expected);
+
+ $string = '눡눢눣눤눥눦눧눨눩눪눫눬눭눮눯눰눱눲눳눴눵눶눷눸눹눺눻눼눽눾눿뉀뉁뉂뉃뉄뉅뉆뉇뉈뉉뉊뉋뉌뉍뉎뉏뉐뉑뉒뉓뉔뉕뉖뉗뉘뉙뉚뉛뉜뉝뉞뉟뉠뉡뉢뉣뉤뉥뉦뉧뉨뉩뉪뉫뉬뉭뉮뉯뉰뉱뉲뉳뉴뉵뉶뉷뉸뉹뉺뉻뉼뉽뉾뉿늀늁늂늃늄';
+ $find = '눻';
+ $result = mb_stripos($string, $find);
+ $expected = 26;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ﹰﹱﹲﹳﹴﹶﹷﹸﹹﹺﹻﹼﹽﹾﹿﺀﺁﺂﺃﺄﺅﺆﺇﺈﺉﺊﺋﺌﺍﺎﺏﺐﺑﺒﺓﺔﺕﺖﺗﺘﺙﺚﺛﺜﺝﺞﺟﺠﺡﺢﺣﺤﺥﺦﺧﺨﺩﺪﺫﺬﺭﺮﺯﺰ';
+ $find = 'ﺞ';
+ $result = mb_stripos($string, $find);
+ $expected = 46;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ﺱﺲﺳﺴﺵﺶﺷﺸﺹﺺﺻﺼﺽﺾﺿﻀﻁﻂﻃﻄﻅﻆﻇﻈﻉﻊﻋﻌﻍﻎﻏﻐﻑﻒﻓﻔﻕﻖﻗﻘﻙﻚﻛﻜﻝﻞﻟﻠﻡﻢﻣﻤﻥﻦﻧﻨﻩﻪﻫﻬﻭﻮﻯﻰﻱﻲﻳﻴﻵﻶﻷﻸﻹﻺﻻﻼ';
+ $find = 'ﻞ';
+ $result = mb_stripos($string, $find);
+ $expected = 45;
+ $this->assertEqual($result, $expected);
+
+ $string = 'abcdefghijklmnopqrstuvwxyz';
+ $find = 'k';
+ $result = mb_stripos($string, $find);
+ $expected = 10;
+ $this->assertEqual($result, $expected);
+
+ $string = 'abcdefghijklmnopqrstuvwxyz';
+ $find = 'K';
+ $result = mb_stripos($string, $find);
+ $expected = 10;
+ $this->assertEqual($result, $expected);
+
+ $string = '。「」、・ヲァィゥェォャュョッーアイウエオカキク';
+ $find = 'ア';
+ $result = mb_stripos($string, $find);
+ $expected = 16;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン゙';
+ $find = 'ハ';
+ $result = mb_stripos($string, $find);
+ $expected = 17;
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ĥēĺļŏ, Ŵőřļď!';
+ $find = 'ő';
+ $result = mb_stripos($string, $find);
+ $expected = 8;
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ĥēĺļŏ, Ŵőřļď!';
+ $find = 'Ő';
+ $result = mb_stripos($string, $find);
+ $expected = 8;
+ $this->assertEqual($result, $expected);
+
+ $string = 'Hello, World!';
+ $find = 'O';
+ $result = mb_stripos($string, $find);
+ $expected = 4;
+ $this->assertEqual($result, $expected);
+
+ $string = 'Hello, World!';
+ $find = 'o';
+ $result = mb_stripos($string, $find);
+ $expected = 4;
+ $this->assertEqual($result, $expected);
+
+ $string = 'čini';
+ $find = 'n';
+ $result = mb_stripos($string, $find);
+ $expected = 2;
+ $this->assertEqual($result, $expected);
+
+ $string = 'čini';
+ $find = 'N';
+ $result = mb_stripos($string, $find);
+ $expected = 2;
+ $this->assertEqual($result, $expected);
+
+ $string = 'moći';
+ $find = 'ć';
+ $result = mb_stripos($string, $find);
+ $expected = 2;
+ $this->assertEqual($result, $expected);
+
+ $string = 'moći';
+ $find = 'Ć';
+ $result = mb_stripos($string, $find);
+ $expected = 2;
+ $this->assertEqual($result, $expected);
+
+ $string = 'državni';
+ $find = 'ž';
+ $result = mb_stripos($string, $find);
+ $expected = 2;
+ $this->assertEqual($result, $expected);
+
+ $string = 'državni';
+ $find = 'Ž';
+ $result = mb_stripos($string, $find);
+ $expected = 2;
+ $this->assertEqual($result, $expected);
+
+ $string = '把百度设为首页';
+ $find = '设';
+ $result = mb_stripos($string, $find);
+ $expected = 3;
+ $this->assertEqual($result, $expected);
+
+ $string = '一二三周永龍';
+ $find = '周';
+ $result = mb_stripos($string, $find);
+ $expected = 3;
+ $this->assertEqual($result, $expected);
+
+ $string = 'državni';
+ $find = 'DŽ';
+ $result = mb_stripos($string, $find);
+ $expected = false;
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testMultibyteStripos method
+ *
+ * @access public
+ * @return void
+ */
+ function testMultibyteStripos() {
+ $string = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
+ $find = 'f';
+ $result = Multibyte::stripos($string, $find);
+ $expected = 5;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ABCDEFGHIJKLMNOPQFRSTUVWXYZ0123456789';
+ $find = 'f';
+ $result = Multibyte::stripos($string, $find, 6);
+ $expected = 17;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞ';
+ $find = 'å';
+ $result = Multibyte::stripos($string, $find);
+ $expected = 5;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÅÙÚÛÜÝÞ';
+ $find = 'å';
+ $result = Multibyte::stripos($string, $find, 6);
+ $expected = 24;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĀĂĄĆĈĊČĎĐĒĔĖĘĚĜĞĠĢĤĦĨĪĬĮIJĴĶĹĻĽĿŁŃŅŇŊŌŎŐŒŔŖŘŚŜŞŠŢŤŦŨŪŬŮŰŲŴŶŹŻŽ';
+ $find = 'ċ';
+ $result = Multibyte::stripos($string, $find);
+ $expected = 5;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĀĂĄĆĈĊČĎĐĒĔĖĘĚĜĞĠĢĤĦĨĪĬĮIJĴĶĹĻĽĿŁĊŃŅŇŊŌŎŐŒŔŖŘŚŜŞŠŢŤŦŨŪŬŮŰŲŴŶŹŻŽ';
+ $find = 'ċ';
+ $result = Multibyte::stripos($string, $find, 6);
+ $expected = 32;
+ $this->assertEqual($result, $expected);
+
+ $string = '!"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~';
+ $find = 'f';
+ $result = Multibyte::stripos($string, $find);
+ $expected = 37;
+ $this->assertEqual($result, $expected);
+
+ $string = '¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈ';
+ $find = 'Μ';
+ $result = Multibyte::stripos($string, $find);
+ $expected = 20;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿĀāĂ㥹ĆćĈĉĊċČčĎďĐđĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪīĬ';
+ $find = 'É';
+ $result = Multibyte::stripos($string, $find, 6);
+ $expected = 32;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĭĮįİıIJijĴĵĶķĸĹĺĻļĽľĿŀŁłŃńŅņŇňʼnŊŋŌōŎŏŐőŒœŔŕŖŗŘřŚśŜŝŞşŠšŢţŤťŦŧŨũŪūŬŭŮůŰűŲųŴŵŶŷŸŹźŻżŽžſƀƁƂƃƄƅƆƇƈƉƊƋƌƍƎƏƐ';
+ $find = 'Ņ';
+ $result = Multibyte::stripos($string, $find);
+ $expected = 24;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ƑƒƓƔƕƖƗƘƙƚƛƜƝƞƟƠơƢƣƤƥƦƧƨƩƪƫƬƭƮƯưƱƲƳƴƵƶƷƸƹƺƻƼƽƾƿǀǁǂǃDŽDždžLJLjljNJNjnjǍǎǏǐǑǒǓǔǕǖǗǘǙǚǛǜǝǞǟǠǡǢǣǤǥǦǧǨǩǪǫǬǭǮǯǰDZDzdzǴ';
+ $find = 'Ƹ';
+ $result = Multibyte::stripos($string, $find);
+ $expected = 39;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ƑƒƓƔƕƖƗƘƙƚƛƜƝƞƟƠơƢƣƤƥƦƧƨƩƪƫƬƭƮƯưƱƲƳƴƵƶƷƸƹƺƻƼƽƾƿǀǁǂǃDŽDždžLJLjljNJNjnjǍǎǏǐǑǒǓǔǕǖǗǘǙǚǛǜǝǞǟǠǡǢǣǤǥǦǧǨǩǪǫǬǭǮǯǰDZDzdzǴ';
+ $find = 'Ƹ';
+ $result = Multibyte::stripos($string, $find, 40);
+ $expected = 40;
+ $this->assertEqual($result, $expected);
+
+ $string = 'əɚɛɜɝɞɟɠɡɢɣɤɥɦɧɨɩɪɫɬɭɮɯɰɱɲɳɴɵɶɷɸɹɺɻɼɽɾɿʀʁʂʃʄʅʆʇʈʉʊʋʌʍʎʏʐʑʒʓʔʕʖʗʘʙʚʛʜʝʞʟʠʡʢʣʤʥʦʧʨʩʪʫʬʭʮʯʰʱʲʳʴʵʶʷʸʹʺʻʼ';
+ $find = 'Ʀ';
+ $result = Multibyte::stripos($string, $find);
+ $expected = 39;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ЀЁЂЃЄЅІЇЈЉЊЋЌЍЎЏАБВГДЕЖЗИЙКЛ';
+ $find = 'ї';
+ $result = Multibyte::stripos($string, $find);
+ $expected = 7;
+ $this->assertEqual($result, $expected);
+
+ $string = 'МНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыь';
+ $find = 'Р';
+ $result = Multibyte::stripos($string, $find);
+ $expected = 4;
+ $this->assertEqual($result, $expected);
+
+ $string = 'МНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыь';
+ $find = 'Р';
+ $result = Multibyte::stripos($string, $find, 5);
+ $expected = 36;
+ $this->assertEqual($result, $expected);
+
+ $string = 'فقكلمنهوىيًٌٍَُ';
+ $find = 'ن';
+ $result = Multibyte::stripos($string, $find);
+ $expected = 5;
+ $this->assertEqual($result, $expected);
+
+ $string = '✰✱✲✳✴✵✶✷✸✹✺✻✼✽✾✿❀❁❂❃❄❅❆❇❈❉❊❋❌❍❎❏❐❑❒❓❔❕❖❗❘❙❚❛❜❝❞';
+ $find = '✿';
+ $result = Multibyte::stripos($string, $find);
+ $expected = 15;
+ $this->assertEqual($result, $expected);
+
+ $string = '⺀⺁⺂⺃⺄⺅⺆⺇⺈⺉⺊⺋⺌⺍⺎⺏⺐⺑⺒⺓⺔⺕⺖⺗⺘⺙⺛⺜⺝⺞⺟⺠⺡⺢⺣⺤⺥⺦⺧⺨⺩⺪⺫⺬⺭⺮⺯⺰⺱⺲⺳⺴⺵⺶⺷⺸⺹⺺⺻⺼⺽⺾⺿⻀⻁⻂⻃⻄⻅⻆⻇⻈⻉⻊⻋⻌⻍⻎⻏⻐⻑⻒⻓⻔⻕⻖⻗⻘⻙⻚⻛⻜⻝⻞⻟⻠';
+ $find = '⺐';
+ $result = Multibyte::stripos($string, $find);
+ $expected = 16;
+ $this->assertEqual($result, $expected);
+
+ $string = '⽅⽆⽇⽈⽉⽊⽋⽌⽍⽎⽏⽐⽑⽒⽓⽔⽕⽖⽗⽘⽙⽚⽛⽜⽝⽞⽟⽠⽡⽢⽣⽤⽥⽦⽧⽨⽩⽪⽫⽬⽭⽮⽯⽰⽱⽲⽳⽴⽵⽶⽷⽸⽹⽺⽻⽼⽽⽾⽿';
+ $find = '⽤';
+ $result = Multibyte::stripos($string, $find);
+ $expected = 31;
+ $this->assertEqual($result, $expected);
+
+ $string = '눡눢눣눤눥눦눧눨눩눪눫눬눭눮눯눰눱눲눳눴눵눶눷눸눹눺눻눼눽눾눿뉀뉁뉂뉃뉄뉅뉆뉇뉈뉉뉊뉋뉌뉍뉎뉏뉐뉑뉒뉓뉔뉕뉖뉗뉘뉙뉚뉛뉜뉝뉞뉟뉠뉡뉢뉣뉤뉥뉦뉧뉨뉩뉪뉫뉬뉭뉮뉯뉰뉱뉲뉳뉴뉵뉶뉷뉸뉹뉺뉻뉼뉽뉾뉿늀늁늂늃늄';
+ $find = '눻';
+ $result = Multibyte::stripos($string, $find);
+ $expected = 26;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ﹰﹱﹲﹳﹴﹶﹷﹸﹹﹺﹻﹼﹽﹾﹿﺀﺁﺂﺃﺄﺅﺆﺇﺈﺉﺊﺋﺌﺍﺎﺏﺐﺑﺒﺓﺔﺕﺖﺗﺘﺙﺚﺛﺜﺝﺞﺟﺠﺡﺢﺣﺤﺥﺦﺧﺨﺩﺪﺫﺬﺭﺮﺯﺰ';
+ $find = 'ﺞ';
+ $result = Multibyte::stripos($string, $find);
+ $expected = 46;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ﺱﺲﺳﺴﺵﺶﺷﺸﺹﺺﺻﺼﺽﺾﺿﻀﻁﻂﻃﻄﻅﻆﻇﻈﻉﻊﻋﻌﻍﻎﻏﻐﻑﻒﻓﻔﻕﻖﻗﻘﻙﻚﻛﻜﻝﻞﻟﻠﻡﻢﻣﻤﻥﻦﻧﻨﻩﻪﻫﻬﻭﻮﻯﻰﻱﻲﻳﻴﻵﻶﻷﻸﻹﻺﻻﻼ';
+ $find = 'ﻞ';
+ $result = Multibyte::stripos($string, $find);
+ $expected = 45;
+ $this->assertEqual($result, $expected);
+
+ $string = 'abcdefghijklmnopqrstuvwxyz';
+ $find = 'k';
+ $result = Multibyte::stripos($string, $find);
+ $expected = 10;
+ $this->assertEqual($result, $expected);
+
+ $string = 'abcdefghijklmnopqrstuvwxyz';
+ $find = 'K';
+ $result = Multibyte::stripos($string, $find);
+ $expected = 10;
+ $this->assertEqual($result, $expected);
+
+ $string = '。「」、・ヲァィゥェォャュョッーアイウエオカキク';
+ $find = 'ア';
+ $result = Multibyte::stripos($string, $find);
+ $expected = 16;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン゙';
+ $find = 'ハ';
+ $result = Multibyte::stripos($string, $find);
+ $expected = 17;
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ĥēĺļŏ, Ŵőřļď!';
+ $find = 'ő';
+ $result = Multibyte::stripos($string, $find);
+ $expected = 8;
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ĥēĺļŏ, Ŵőřļď!';
+ $find = 'Ő';
+ $result = Multibyte::stripos($string, $find);
+ $expected = 8;
+ $this->assertEqual($result, $expected);
+
+ $string = 'Hello, World!';
+ $find = 'O';
+ $result = Multibyte::stripos($string, $find);
+ $expected = 4;
+ $this->assertEqual($result, $expected);
+
+ $string = 'Hello, World!';
+ $find = 'o';
+ $result = Multibyte::stripos($string, $find);
+ $expected = 4;
+ $this->assertEqual($result, $expected);
+
+ $string = 'čini';
+ $find = 'n';
+ $result = Multibyte::stripos($string, $find);
+ $expected = 2;
+ $this->assertEqual($result, $expected);
+
+ $string = 'čini';
+ $find = 'N';
+ $result = Multibyte::stripos($string, $find);
+ $expected = 2;
+ $this->assertEqual($result, $expected);
+
+ $string = 'moći';
+ $find = 'ć';
+ $result = Multibyte::stripos($string, $find);
+ $expected = 2;
+ $this->assertEqual($result, $expected);
+
+ $string = 'moći';
+ $find = 'Ć';
+ $result = Multibyte::stripos($string, $find);
+ $expected = 2;
+ $this->assertEqual($result, $expected);
+
+ $string = 'državni';
+ $find = 'ž';
+ $result = Multibyte::stripos($string, $find);
+ $expected = 2;
+ $this->assertEqual($result, $expected);
+
+ $string = 'državni';
+ $find = 'Ž';
+ $result = Multibyte::stripos($string, $find);
+ $expected = 2;
+ $this->assertEqual($result, $expected);
+
+ $string = '把百度设为首页';
+ $find = '设';
+ $result = Multibyte::stripos($string, $find);
+ $expected = 3;
+ $this->assertEqual($result, $expected);
+
+ $string = '一二三周永龍';
+ $find = '周';
+ $result = Multibyte::stripos($string, $find);
+ $expected = 3;
+ $this->assertEqual($result, $expected);
+
+ $string = 'državni';
+ $find = 'DŽ';
+ $result = Multibyte::stripos($string, $find);
+ $expected = false;
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testUsingMbStristr method
+ *
+ * @access public
+ * @return void
+ */
+ function testUsingMbStristr() {
+ $string = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
+ $find = 'f';
+ $result = mb_stristr($string, $find);
+ $expected = 'FGHIJKLMNOPQRSTUVWXYZ0123456789';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
+ $find = 'f';
+ $result = mb_stristr($string, $find, true);
+ $expected = 'ABCDE';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞ';
+ $find = 'å';
+ $result = mb_stristr($string, $find);
+ $expected = 'ÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞ';
+ $find = 'å';
+ $result = mb_stristr($string, $find, true);
+ $expected = 'ÀÁÂÃÄ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĀĂĄĆĈĊČĎĐĒĔĖĘĚĜĞĠĢĤĦĨĪĬĮIJĴĶĹĻĽĿŁŃŅŇŊŌŎŐŒŔŖŘŚŜŞŠŢŤŦŨŪŬŮŰŲŴŶŹŻŽ';
+ $find = 'ċ';
+ $result = mb_stristr($string, $find);
+ $expected = 'ĊČĎĐĒĔĖĘĚĜĞĠĢĤĦĨĪĬĮIJĴĶĹĻĽĿŁŃŅŇŊŌŎŐŒŔŖŘŚŜŞŠŢŤŦŨŪŬŮŰŲŴŶŹŻŽ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĀĂĄĆĈĊČĎĐĒĔĖĘĚĜĞĠĢĤĦĨĪĬĮIJĴĶĹĻĽĿŁŃŅŇŊŌŎŐŒŔŖŘŚŜŞŠŢŤŦŨŪŬŮŰŲŴŶŹŻŽ';
+ $find = 'ċ';
+ $result = mb_stristr($string, $find, true);
+ $expected = 'ĀĂĄĆĈ';
+ $this->assertEqual($result, $expected);
+
+ $string = '!"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~';
+ $find = 'f';
+ $result = mb_stristr($string, $find);
+ $expected = 'FGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~';
+ $this->assertEqual($result, $expected);
+
+ $string = '!"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~';
+ $find = 'f';
+ $result = mb_stristr($string, $find, true);
+ $expected = '!"#$%&\'()*+,-./0123456789:;<=>?@ABCDE';
+ $this->assertEqual($result, $expected);
+
+ $string = '¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈ';
+ $find = 'Μ';
+ $result = mb_stristr($string, $find);
+ $expected = 'µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈ';
+ $this->assertEqual($result, $expected);
+
+ $string = '¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈ';
+ $find = 'Μ';
+ $result = mb_stristr($string, $find, true);
+ $expected = '¡¢£¤¥¦§¨©ª«¬®¯°±²³´';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿĀāĂ㥹ĆćĈĉĊċČčĎďĐđĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪīĬ';
+ $find = 'þ';
+ $result = mb_stristr($string, $find);
+ $expected = 'Þßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿĀāĂ㥹ĆćĈĉĊċČčĎďĐđĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪīĬ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿĀāĂ㥹ĆćĈĉĊċČčĎďĐđĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪīĬ';
+ $find = 'þ';
+ $result = mb_stristr($string, $find, true);
+ $expected = 'ÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĭĮįİıIJijĴĵĶķĸĹĺĻļĽľĿŀŁłŃńŅņŇňʼnŊŋŌōŎŏŐőŒœŔŕŖŗŘřŚśŜŝŞşŠšŢţŤťŦŧŨũŪūŬŭŮůŰűŲųŴŵŶŷŸŹźŻżŽžſƀƁƂƃƄƅƆƇƈƉƊƋƌƍƎƏƐ';
+ $find = 'Ņ';
+ $result = mb_stristr($string, $find);
+ $expected = 'ŅņŇňʼnŊŋŌōŎŏŐőŒœŔŕŖŗŘřŚśŜŝŞşŠšŢţŤťŦŧŨũŪūŬŭŮůŰűŲųŴŵŶŷŸŹźŻżŽžſƀƁƂƃƄƅƆƇƈƉƊƋƌƍƎƏƐ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĭĮįİıIJijĴĵĶķĸĹĺĻļĽľĿŀŁłŃńŅņŇňʼnŊŋŌōŎŏŐőŒœŔŕŖŗŘřŚśŜŝŞşŠšŢţŤťŦŧŨũŪūŬŭŮůŰűŲųŴŵŶŷŸŹźŻżŽžſƀƁƂƃƄƅƆƇƈƉƊƋƌƍƎƏƐ';
+ $find = 'Ņ';
+ $result = mb_stristr($string, $find, true);
+ $expected = 'ĭĮįİıIJijĴĵĶķĸĹĺĻļĽľĿŀŁłŃń';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ƑƒƓƔƕƖƗƘƙƚƛƜƝƞƟƠơƢƣƤƥƦƧƨƩƪƫƬƭƮƯưƱƲƳƴƵƶƷƸƹƺƻƼƽƾƿǀǁǂǃDŽDždžLJLjljNJNjnjǍǎǏǐǑǒǓǔǕǖǗǘǙǚǛǜǝǞǟǠǡǢǣǤǥǦǧǨǩǪǫǬǭǮǯǰDZDzdzǴ';
+ $find = 'Ƹ';
+ $result = mb_stristr($string, $find);
+ $expected = 'ƸƹƺƻƼƽƾƿǀǁǂǃDŽDždžLJLjljNJNjnjǍǎǏǐǑǒǓǔǕǖǗǘǙǚǛǜǝǞǟǠǡǢǣǤǥǦǧǨǩǪǫǬǭǮǯǰDZDzdzǴ';
+ $this->assertEqual($result, $expected);
+
+ $find = 'Ƹ';
+ $result = mb_stristr($string, $find, true);
+ $expected = 'ƑƒƓƔƕƖƗƘƙƚƛƜƝƞƟƠơƢƣƤƥƦƧƨƩƪƫƬƭƮƯưƱƲƳƴƵƶƷ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'əɚɛɜɝɞɟɠɡɢɣɤɥɦɧɨɩɪɫɬɭɮɯɰɱɲɳɴɵɶɷɸɹɺɻɼɽɾɿʀʁʂʃʄʅʆʇʈʉʊʋʌʍʎʏʐʑʒʓʔʕʖʗʘʙʚʛʜʝʞʟʠʡʢʣʤʥʦʧʨʩʪʫʬʭʮʯʰʱʲʳʴʵʶʷʸʹʺʻʼ';
+ $find = 'Ʀ';
+ $result = mb_stristr($string, $find);
+ $expected = 'ʀʁʂʃʄʅʆʇʈʉʊʋʌʍʎʏʐʑʒʓʔʕʖʗʘʙʚʛʜʝʞʟʠʡʢʣʤʥʦʧʨʩʪʫʬʭʮʯʰʱʲʳʴʵʶʷʸʹʺʻʼ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'əɚɛɜɝɞɟɠɡɢɣɤɥɦɧɨɩɪɫɬɭɮɯɰɱɲɳɴɵɶɷɸɹɺɻɼɽɾɿʀʁʂʃʄʅʆʇʈʉʊʋʌʍʎʏʐʑʒʓʔʕʖʗʘʙʚʛʜʝʞʟʠʡʢʣʤʥʦʧʨʩʪʫʬʭʮʯʰʱʲʳʴʵʶʷʸʹʺʻʼ';
+ $find = 'Ʀ';
+ $result = mb_stristr($string, $find, true);
+ $expected = 'əɚɛɜɝɞɟɠɡɢɣɤɥɦɧɨɩɪɫɬɭɮɯɰɱɲɳɴɵɶɷɸɹɺɻɼɽɾɿ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ЀЁЂЃЄЅІЇЈЉЊЋЌЍЎЏАБВГДЕЖЗИЙКЛ';
+ $find = 'ї';
+ $result = mb_stristr($string, $find);
+ $expected = 'ЇЈЉЊЋЌЍЎЏАБВГДЕЖЗИЙКЛ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ЀЁЂЃЄЅІЇЈЉЊЋЌЍЎЏАБВГДЕЖЗИЙКЛ';
+ $find = 'ї';
+ $result = mb_stristr($string, $find, true);
+ $expected = 'ЀЁЂЃЄЅІ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'МНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыь';
+ $find = 'Р';
+ $result = mb_stristr($string, $find);
+ $expected = 'РСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыь';
+ $this->assertEqual($result, $expected);
+
+ $string = 'МНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыь';
+ $find = 'Р';
+ $result = mb_stristr($string, $find, true);
+ $expected = 'МНОП';
+ $this->assertEqual($result, $expected);
+
+ $string = 'فقكلمنهوىيًٌٍَُ';
+ $find = 'ن';
+ $result = mb_stristr($string, $find);
+ $expected = 'نهوىيًٌٍَُ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'فقكلمنهوىيًٌٍَُ';
+ $find = 'ن';
+ $result = mb_stristr($string, $find, true);
+ $expected = 'فقكلم';
+ $this->assertEqual($result, $expected);
+
+ $string = '✰✱✲✳✴✵✶✷✸✹✺✻✼✽✾✿❀❁❂❃❄❅❆❇❈❉❊❋❌❍❎❏❐❑❒❓❔❕❖❗❘❙❚❛❜❝❞';
+ $find = '✿';
+ $result = mb_stristr($string, $find);
+ $expected = '✿❀❁❂❃❄❅❆❇❈❉❊❋❌❍❎❏❐❑❒❓❔❕❖❗❘❙❚❛❜❝❞';
+ $this->assertEqual($result, $expected);
+
+ $string = '✰✱✲✳✴✵✶✷✸✹✺✻✼✽✾✿❀❁❂❃❄❅❆❇❈❉❊❋❌❍❎❏❐❑❒❓❔❕❖❗❘❙❚❛❜❝❞';
+ $find = '✿';
+ $result = mb_stristr($string, $find, true);
+ $expected = '✰✱✲✳✴✵✶✷✸✹✺✻✼✽✾';
+ $this->assertEqual($result, $expected);
+
+ $string = '⺀⺁⺂⺃⺄⺅⺆⺇⺈⺉⺊⺋⺌⺍⺎⺏⺐⺑⺒⺓⺔⺕⺖⺗⺘⺙⺛⺜⺝⺞⺟⺠⺡⺢⺣⺤⺥⺦⺧⺨⺩⺪⺫⺬⺭⺮⺯⺰⺱⺲⺳⺴⺵⺶⺷⺸⺹⺺⺻⺼⺽⺾⺿⻀⻁⻂⻃⻄⻅⻆⻇⻈⻉⻊⻋⻌⻍⻎⻏⻐⻑⻒⻓⻔⻕⻖⻗⻘⻙⻚⻛⻜⻝⻞⻟⻠';
+ $find = '⺐';
+ $result = mb_stristr($string, $find);
+ $expected = '⺐⺑⺒⺓⺔⺕⺖⺗⺘⺙⺛⺜⺝⺞⺟⺠⺡⺢⺣⺤⺥⺦⺧⺨⺩⺪⺫⺬⺭⺮⺯⺰⺱⺲⺳⺴⺵⺶⺷⺸⺹⺺⺻⺼⺽⺾⺿⻀⻁⻂⻃⻄⻅⻆⻇⻈⻉⻊⻋⻌⻍⻎⻏⻐⻑⻒⻓⻔⻕⻖⻗⻘⻙⻚⻛⻜⻝⻞⻟⻠';
+ $this->assertEqual($result, $expected);
+
+ $string = '⺀⺁⺂⺃⺄⺅⺆⺇⺈⺉⺊⺋⺌⺍⺎⺏⺐⺑⺒⺓⺔⺕⺖⺗⺘⺙⺛⺜⺝⺞⺟⺠⺡⺢⺣⺤⺥⺦⺧⺨⺩⺪⺫⺬⺭⺮⺯⺰⺱⺲⺳⺴⺵⺶⺷⺸⺹⺺⺻⺼⺽⺾⺿⻀⻁⻂⻃⻄⻅⻆⻇⻈⻉⻊⻋⻌⻍⻎⻏⻐⻑⻒⻓⻔⻕⻖⻗⻘⻙⻚⻛⻜⻝⻞⻟⻠';
+ $find = '⺐';
+ $result = mb_stristr($string, $find, true);
+ $expected = '⺀⺁⺂⺃⺄⺅⺆⺇⺈⺉⺊⺋⺌⺍⺎⺏';
+ $this->assertEqual($result, $expected);
+
+ $string = '⽅⽆⽇⽈⽉⽊⽋⽌⽍⽎⽏⽐⽑⽒⽓⽔⽕⽖⽗⽘⽙⽚⽛⽜⽝⽞⽟⽠⽡⽢⽣⽤⽥⽦⽧⽨⽩⽪⽫⽬⽭⽮⽯⽰⽱⽲⽳⽴⽵⽶⽷⽸⽹⽺⽻⽼⽽⽾⽿';
+ $find = '⽤';
+ $result = mb_stristr($string, $find);
+ $expected = '⽤⽥⽦⽧⽨⽩⽪⽫⽬⽭⽮⽯⽰⽱⽲⽳⽴⽵⽶⽷⽸⽹⽺⽻⽼⽽⽾⽿';
+ $this->assertEqual($result, $expected);
+
+ $string = '⽅⽆⽇⽈⽉⽊⽋⽌⽍⽎⽏⽐⽑⽒⽓⽔⽕⽖⽗⽘⽙⽚⽛⽜⽝⽞⽟⽠⽡⽢⽣⽤⽥⽦⽧⽨⽩⽪⽫⽬⽭⽮⽯⽰⽱⽲⽳⽴⽵⽶⽷⽸⽹⽺⽻⽼⽽⽾⽿';
+ $find = '⽤';
+ $result = mb_stristr($string, $find, true);
+ $expected = '⽅⽆⽇⽈⽉⽊⽋⽌⽍⽎⽏⽐⽑⽒⽓⽔⽕⽖⽗⽘⽙⽚⽛⽜⽝⽞⽟⽠⽡⽢⽣';
+ $this->assertEqual($result, $expected);
+
+ $string = '눡눢눣눤눥눦눧눨눩눪눫눬눭눮눯눰눱눲눳눴눵눶눷눸눹눺눻눼눽눾눿뉀뉁뉂뉃뉄뉅뉆뉇뉈뉉뉊뉋뉌뉍뉎뉏뉐뉑뉒뉓뉔뉕뉖뉗뉘뉙뉚뉛뉜뉝뉞뉟뉠뉡뉢뉣뉤뉥뉦뉧뉨뉩뉪뉫뉬뉭뉮뉯뉰뉱뉲뉳뉴뉵뉶뉷뉸뉹뉺뉻뉼뉽뉾뉿늀늁늂늃늄';
+ $find = '눻';
+ $result = mb_stristr($string, $find);
+ $expected = '눻눼눽눾눿뉀뉁뉂뉃뉄뉅뉆뉇뉈뉉뉊뉋뉌뉍뉎뉏뉐뉑뉒뉓뉔뉕뉖뉗뉘뉙뉚뉛뉜뉝뉞뉟뉠뉡뉢뉣뉤뉥뉦뉧뉨뉩뉪뉫뉬뉭뉮뉯뉰뉱뉲뉳뉴뉵뉶뉷뉸뉹뉺뉻뉼뉽뉾뉿늀늁늂늃늄';
+ $this->assertEqual($result, $expected);
+
+ $string = '눡눢눣눤눥눦눧눨눩눪눫눬눭눮눯눰눱눲눳눴눵눶눷눸눹눺눻눼눽눾눿뉀뉁뉂뉃뉄뉅뉆뉇뉈뉉뉊뉋뉌뉍뉎뉏뉐뉑뉒뉓뉔뉕뉖뉗뉘뉙뉚뉛뉜뉝뉞뉟뉠뉡뉢뉣뉤뉥뉦뉧뉨뉩뉪뉫뉬뉭뉮뉯뉰뉱뉲뉳뉴뉵뉶뉷뉸뉹뉺뉻뉼뉽뉾뉿늀늁늂늃늄';
+ $find = '눻';
+ $result = mb_stristr($string, $find, true);
+ $expected = '눡눢눣눤눥눦눧눨눩눪눫눬눭눮눯눰눱눲눳눴눵눶눷눸눹눺';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ﹰﹱﹲﹳﹴﹶﹷﹸﹹﹺﹻﹼﹽﹾﹿﺀﺁﺂﺃﺄﺅﺆﺇﺈﺉﺊﺋﺌﺍﺎﺏﺐﺑﺒﺓﺔﺕﺖﺗﺘﺙﺚﺛﺜﺝﺞﺟﺠﺡﺢﺣﺤﺥﺦﺧﺨﺩﺪﺫﺬﺭﺮﺯﺰ';
+ $find = 'ﺞ';
+ $result = mb_stristr($string, $find);
+ $expected = 'ﺞﺟﺠﺡﺢﺣﺤﺥﺦﺧﺨﺩﺪﺫﺬﺭﺮﺯﺰ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ﹰﹱﹲﹳﹴﹶﹷﹸﹹﹺﹻﹼﹽﹾﹿﺀﺁﺂﺃﺄﺅﺆﺇﺈﺉﺊﺋﺌﺍﺎﺏﺐﺑﺒﺓﺔﺕﺖﺗﺘﺙﺚﺛﺜﺝﺞﺟﺠﺡﺢﺣﺤﺥﺦﺧﺨﺩﺪﺫﺬﺭﺮﺯﺰ';
+ $find = 'ﺞ';
+ $result = mb_stristr($string, $find, true);
+ $expected = 'ﹰﹱﹲﹳﹴﹶﹷﹸﹹﹺﹻﹼﹽﹾﹿﺀﺁﺂﺃﺄﺅﺆﺇﺈﺉﺊﺋﺌﺍﺎﺏﺐﺑﺒﺓﺔﺕﺖﺗﺘﺙﺚﺛﺜﺝ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ﺱﺲﺳﺴﺵﺶﺷﺸﺹﺺﺻﺼﺽﺾﺿﻀﻁﻂﻃﻄﻅﻆﻇﻈﻉﻊﻋﻌﻍﻎﻏﻐﻑﻒﻓﻔﻕﻖﻗﻘﻙﻚﻛﻜﻝﻞﻟﻠﻡﻢﻣﻤﻥﻦﻧﻨﻩﻪﻫﻬﻭﻮﻯﻰﻱﻲﻳﻴﻵﻶﻷﻸﻹﻺﻻﻼ';
+ $find = 'ﻞ';
+ $result = mb_stristr($string, $find);
+ $expected = 'ﻞﻟﻠﻡﻢﻣﻤﻥﻦﻧﻨﻩﻪﻫﻬﻭﻮﻯﻰﻱﻲﻳﻴﻵﻶﻷﻸﻹﻺﻻﻼ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ﺱﺲﺳﺴﺵﺶﺷﺸﺹﺺﺻﺼﺽﺾﺿﻀﻁﻂﻃﻄﻅﻆﻇﻈﻉﻊﻋﻌﻍﻎﻏﻐﻑﻒﻓﻔﻕﻖﻗﻘﻙﻚﻛﻜﻝﻞﻟﻠﻡﻢﻣﻤﻥﻦﻧﻨﻩﻪﻫﻬﻭﻮﻯﻰﻱﻲﻳﻴﻵﻶﻷﻸﻹﻺﻻﻼ';
+ $find = 'ﻞ';
+ $result = mb_stristr($string, $find, true);
+ $expected = 'ﺱﺲﺳﺴﺵﺶﺷﺸﺹﺺﺻﺼﺽﺾﺿﻀﻁﻂﻃﻄﻅﻆﻇﻈﻉﻊﻋﻌﻍﻎﻏﻐﻑﻒﻓﻔﻕﻖﻗﻘﻙﻚﻛﻜﻝ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'abcdefghijklmnopqrstuvwxyz';
+ $find = 'K';
+ $result = mb_stristr($string, $find);
+ $expected = 'klmnopqrstuvwxyz';
+ $this->assertEqual($result, $expected);
+
+ $string = 'abcdefghijklmnopqrstuvwxyz';
+ $find = 'K';
+ $result = mb_stristr($string, $find, true);
+ $expected = 'abcdefghij';
+ $this->assertEqual($result, $expected);
+
+ $string = '。「」、・ヲァィゥェォャュョッーアイウエオカキク';
+ $find = 'ア';
+ $result = mb_stristr($string, $find);
+ $expected = 'アイウエオカキク';
+ $this->assertEqual($result, $expected);
+
+ $string = '。「」、・ヲァィゥェォャュョッーアイウエオカキク';
+ $find = 'ア';
+ $result = mb_stristr($string, $find, true);
+ $expected = '。「」、・ヲァィゥェォャュョッー';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン゙';
+ $find = 'ハ';
+ $result = mb_stristr($string, $find);
+ $expected = 'ハヒフヘホマミムメモヤユヨラリルレロワン゙';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン゙';
+ $find = 'ハ';
+ $result = mb_stristr($string, $find, true);
+ $expected = 'ケコサシスセソタチツテトナニヌネノ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ĥēĺļŏ, Ŵőřļď!';
+ $find = 'Ő';
+ $result = mb_stristr($string, $find);
+ $expected = 'őřļď!';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ĥēĺļŏ, Ŵőřļď!';
+ $find = 'Ő';
+ $result = mb_stristr($string, $find, true);
+ $expected = 'Ĥēĺļŏ, Ŵ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ĥēĺļŏ, Ŵőřļď!';
+ $find = 'ĺļ';
+ $result = mb_stristr($string, $find, true);
+ $expected = 'Ĥē';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Hello, World!';
+ $find = 'O';
+ $result = mb_stristr($string, $find);
+ $expected = 'o, World!';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Hello, World!';
+ $find = 'O';
+ $result = mb_stristr($string, $find, true);
+ $expected = 'Hell';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Hello, World!';
+ $find = 'Wo';
+ $result = mb_stristr($string, $find);
+ $expected = 'World!';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Hello, World!';
+ $find = 'Wo';
+ $result = mb_stristr($string, $find, true);
+ $expected = 'Hello, ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Hello, World!';
+ $find = 'll';
+ $result = mb_stristr($string, $find);
+ $expected = 'llo, World!';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Hello, World!';
+ $find = 'll';
+ $result = mb_stristr($string, $find, true);
+ $expected = 'He';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Hello, World!';
+ $find = 'rld';
+ $result = mb_stristr($string, $find);
+ $expected = 'rld!';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Hello, World!';
+ $find = 'rld';
+ $result = mb_stristr($string, $find, true);
+ $expected = 'Hello, Wo';
+ $this->assertEqual($result, $expected);
+
+ $string = 'čini';
+ $find = 'N';
+ $result = mb_stristr($string, $find);
+ $expected = 'ni';
+ $this->assertEqual($result, $expected);
+
+ $string = 'čini';
+ $find = 'N';
+ $result = mb_stristr($string, $find, true);
+ $expected = 'či';
+ $this->assertEqual($result, $expected);
+
+ $string = 'moći';
+ $find = 'Ć';
+ $result = mb_stristr($string, $find);
+ $expected = 'ći';
+ $this->assertEqual($result, $expected);
+
+ $string = 'moći';
+ $find = 'Ć';
+ $result = mb_stristr($string, $find, true);
+ $expected = 'mo';
+ $this->assertEqual($result, $expected);
+
+ $string = 'državni';
+ $find = 'Ž';
+ $result = mb_stristr($string, $find);
+ $expected = 'žavni';
+ $this->assertEqual($result, $expected);
+
+ $string = 'državni';
+ $find = 'Ž';
+ $result = mb_stristr($string, $find, true);
+ $expected = 'dr';
+ $this->assertEqual($result, $expected);
+
+ $string = '把百度设为首页';
+ $find = '设';
+ $result = mb_stristr($string, $find);
+ $expected = '设为首页';
+ $this->assertEqual($result, $expected);
+
+ $string = '把百度设为首页';
+ $find = '设';
+ $result = mb_stristr($string, $find, true);
+ $expected = '把百度';
+ $this->assertEqual($result, $expected);
+
+ $string = '一二三周永龍';
+ $find = '周';
+ $result = mb_stristr($string, $find);
+ $expected = '周永龍';
+ $this->assertEqual($result, $expected);
+
+ $string = '一二三周永龍';
+ $find = '周';
+ $result = mb_stristr($string, $find, true);
+ $expected = '一二三';
+ $this->assertEqual($result, $expected);
+
+ $string = '一二三周永龍';
+ $find = '二周';
+ $result = mb_stristr($string, $find);
+ $expected = false;
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testMultibyteStristr method
+ *
+ * @access public
+ * @return void
+ */
+ function testMultibyteStristr() {
+ $string = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
+ $find = 'f';
+ $result = Multibyte::stristr($string, $find);
+ $expected = 'FGHIJKLMNOPQRSTUVWXYZ0123456789';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
+ $find = 'f';
+ $result = Multibyte::stristr($string, $find, true);
+ $expected = 'ABCDE';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞ';
+ $find = 'å';
+ $result = Multibyte::stristr($string, $find);
+ $expected = 'ÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞ';
+ $find = 'å';
+ $result = Multibyte::stristr($string, $find, true);
+ $expected = 'ÀÁÂÃÄ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĀĂĄĆĈĊČĎĐĒĔĖĘĚĜĞĠĢĤĦĨĪĬĮIJĴĶĹĻĽĿŁŃŅŇŊŌŎŐŒŔŖŘŚŜŞŠŢŤŦŨŪŬŮŰŲŴŶŹŻŽ';
+ $find = 'ċ';
+ $result = Multibyte::stristr($string, $find);
+ $expected = 'ĊČĎĐĒĔĖĘĚĜĞĠĢĤĦĨĪĬĮIJĴĶĹĻĽĿŁŃŅŇŊŌŎŐŒŔŖŘŚŜŞŠŢŤŦŨŪŬŮŰŲŴŶŹŻŽ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĀĂĄĆĈĊČĎĐĒĔĖĘĚĜĞĠĢĤĦĨĪĬĮIJĴĶĹĻĽĿŁŃŅŇŊŌŎŐŒŔŖŘŚŜŞŠŢŤŦŨŪŬŮŰŲŴŶŹŻŽ';
+ $find = 'ċ';
+ $result = Multibyte::stristr($string, $find, true);
+ $expected = 'ĀĂĄĆĈ';
+ $this->assertEqual($result, $expected);
+
+ $string = '!"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~';
+ $find = 'f';
+ $result = Multibyte::stristr($string, $find);
+ $expected = 'FGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~';
+ $this->assertEqual($result, $expected);
+
+ $string = '!"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~';
+ $find = 'f';
+ $result = Multibyte::stristr($string, $find, true);
+ $expected = '!"#$%&\'()*+,-./0123456789:;<=>?@ABCDE';
+ $this->assertEqual($result, $expected);
+
+ $string = '¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈ';
+ $find = 'Μ';
+ $result = Multibyte::stristr($string, $find);
+ $expected = 'µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈ';
+ $this->assertEqual($result, $expected);
+
+ $string = '¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈ';
+ $find = 'Μ';
+ $result = Multibyte::stristr($string, $find, true);
+ $expected = '¡¢£¤¥¦§¨©ª«¬®¯°±²³´';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿĀāĂ㥹ĆćĈĉĊċČčĎďĐđĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪīĬ';
+ $find = 'þ';
+ $result = Multibyte::stristr($string, $find);
+ $expected = 'Þßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿĀāĂ㥹ĆćĈĉĊċČčĎďĐđĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪīĬ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿĀāĂ㥹ĆćĈĉĊċČčĎďĐđĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪīĬ';
+ $find = 'þ';
+ $result = Multibyte::stristr($string, $find, true);
+ $expected = 'ÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĭĮįİıIJijĴĵĶķĸĹĺĻļĽľĿŀŁłŃńŅņŇňʼnŊŋŌōŎŏŐőŒœŔŕŖŗŘřŚśŜŝŞşŠšŢţŤťŦŧŨũŪūŬŭŮůŰűŲųŴŵŶŷŸŹźŻżŽžſƀƁƂƃƄƅƆƇƈƉƊƋƌƍƎƏƐ';
+ $find = 'Ņ';
+ $result = Multibyte::stristr($string, $find);
+ $expected = 'ŅņŇňʼnŊŋŌōŎŏŐőŒœŔŕŖŗŘřŚśŜŝŞşŠšŢţŤťŦŧŨũŪūŬŭŮůŰűŲųŴŵŶŷŸŹźŻżŽžſƀƁƂƃƄƅƆƇƈƉƊƋƌƍƎƏƐ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĭĮįİıIJijĴĵĶķĸĹĺĻļĽľĿŀŁłŃńŅņŇňʼnŊŋŌōŎŏŐőŒœŔŕŖŗŘřŚśŜŝŞşŠšŢţŤťŦŧŨũŪūŬŭŮůŰűŲųŴŵŶŷŸŹźŻżŽžſƀƁƂƃƄƅƆƇƈƉƊƋƌƍƎƏƐ';
+ $find = 'Ņ';
+ $result = Multibyte::stristr($string, $find, true);
+ $expected = 'ĭĮįİıIJijĴĵĶķĸĹĺĻļĽľĿŀŁłŃń';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ƑƒƓƔƕƖƗƘƙƚƛƜƝƞƟƠơƢƣƤƥƦƧƨƩƪƫƬƭƮƯưƱƲƳƴƵƶƷƸƹƺƻƼƽƾƿǀǁǂǃDŽDždžLJLjljNJNjnjǍǎǏǐǑǒǓǔǕǖǗǘǙǚǛǜǝǞǟǠǡǢǣǤǥǦǧǨǩǪǫǬǭǮǯǰDZDzdzǴ';
+ $find = 'Ƹ';
+ $result = Multibyte::stristr($string, $find);
+ $expected = 'ƸƹƺƻƼƽƾƿǀǁǂǃDŽDždžLJLjljNJNjnjǍǎǏǐǑǒǓǔǕǖǗǘǙǚǛǜǝǞǟǠǡǢǣǤǥǦǧǨǩǪǫǬǭǮǯǰDZDzdzǴ';
+ $this->assertEqual($result, $expected);
+
+ $find = 'Ƹ';
+ $result = Multibyte::stristr($string, $find, true);
+ $expected = 'ƑƒƓƔƕƖƗƘƙƚƛƜƝƞƟƠơƢƣƤƥƦƧƨƩƪƫƬƭƮƯưƱƲƳƴƵƶƷ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'əɚɛɜɝɞɟɠɡɢɣɤɥɦɧɨɩɪɫɬɭɮɯɰɱɲɳɴɵɶɷɸɹɺɻɼɽɾɿʀʁʂʃʄʅʆʇʈʉʊʋʌʍʎʏʐʑʒʓʔʕʖʗʘʙʚʛʜʝʞʟʠʡʢʣʤʥʦʧʨʩʪʫʬʭʮʯʰʱʲʳʴʵʶʷʸʹʺʻʼ';
+ $find = 'Ʀ';
+ $result = Multibyte::stristr($string, $find);
+ $expected = 'ʀʁʂʃʄʅʆʇʈʉʊʋʌʍʎʏʐʑʒʓʔʕʖʗʘʙʚʛʜʝʞʟʠʡʢʣʤʥʦʧʨʩʪʫʬʭʮʯʰʱʲʳʴʵʶʷʸʹʺʻʼ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'əɚɛɜɝɞɟɠɡɢɣɤɥɦɧɨɩɪɫɬɭɮɯɰɱɲɳɴɵɶɷɸɹɺɻɼɽɾɿʀʁʂʃʄʅʆʇʈʉʊʋʌʍʎʏʐʑʒʓʔʕʖʗʘʙʚʛʜʝʞʟʠʡʢʣʤʥʦʧʨʩʪʫʬʭʮʯʰʱʲʳʴʵʶʷʸʹʺʻʼ';
+ $find = 'Ʀ';
+ $result = Multibyte::stristr($string, $find, true);
+ $expected = 'əɚɛɜɝɞɟɠɡɢɣɤɥɦɧɨɩɪɫɬɭɮɯɰɱɲɳɴɵɶɷɸɹɺɻɼɽɾɿ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ЀЁЂЃЄЅІЇЈЉЊЋЌЍЎЏАБВГДЕЖЗИЙКЛ';
+ $find = 'ї';
+ $result = Multibyte::stristr($string, $find);
+ $expected = 'ЇЈЉЊЋЌЍЎЏАБВГДЕЖЗИЙКЛ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ЀЁЂЃЄЅІЇЈЉЊЋЌЍЎЏАБВГДЕЖЗИЙКЛ';
+ $find = 'ї';
+ $result = Multibyte::stristr($string, $find, true);
+ $expected = 'ЀЁЂЃЄЅІ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'МНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыь';
+ $find = 'Р';
+ $result = Multibyte::stristr($string, $find);
+ $expected = 'РСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыь';
+ $this->assertEqual($result, $expected);
+
+ $string = 'МНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыь';
+ $find = 'Р';
+ $result = Multibyte::stristr($string, $find, true);
+ $expected = 'МНОП';
+ $this->assertEqual($result, $expected);
+
+ $string = 'فقكلمنهوىيًٌٍَُ';
+ $find = 'ن';
+ $result = Multibyte::stristr($string, $find);
+ $expected = 'نهوىيًٌٍَُ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'فقكلمنهوىيًٌٍَُ';
+ $find = 'ن';
+ $result = Multibyte::stristr($string, $find, true);
+ $expected = 'فقكلم';
+ $this->assertEqual($result, $expected);
+
+ $string = '✰✱✲✳✴✵✶✷✸✹✺✻✼✽✾✿❀❁❂❃❄❅❆❇❈❉❊❋❌❍❎❏❐❑❒❓❔❕❖❗❘❙❚❛❜❝❞';
+ $find = '✿';
+ $result = Multibyte::stristr($string, $find);
+ $expected = '✿❀❁❂❃❄❅❆❇❈❉❊❋❌❍❎❏❐❑❒❓❔❕❖❗❘❙❚❛❜❝❞';
+ $this->assertEqual($result, $expected);
+
+ $string = '✰✱✲✳✴✵✶✷✸✹✺✻✼✽✾✿❀❁❂❃❄❅❆❇❈❉❊❋❌❍❎❏❐❑❒❓❔❕❖❗❘❙❚❛❜❝❞';
+ $find = '✿';
+ $result = Multibyte::stristr($string, $find, true);
+ $expected = '✰✱✲✳✴✵✶✷✸✹✺✻✼✽✾';
+ $this->assertEqual($result, $expected);
+
+ $string = '⺀⺁⺂⺃⺄⺅⺆⺇⺈⺉⺊⺋⺌⺍⺎⺏⺐⺑⺒⺓⺔⺕⺖⺗⺘⺙⺛⺜⺝⺞⺟⺠⺡⺢⺣⺤⺥⺦⺧⺨⺩⺪⺫⺬⺭⺮⺯⺰⺱⺲⺳⺴⺵⺶⺷⺸⺹⺺⺻⺼⺽⺾⺿⻀⻁⻂⻃⻄⻅⻆⻇⻈⻉⻊⻋⻌⻍⻎⻏⻐⻑⻒⻓⻔⻕⻖⻗⻘⻙⻚⻛⻜⻝⻞⻟⻠';
+ $find = '⺐';
+ $result = Multibyte::stristr($string, $find);
+ $expected = '⺐⺑⺒⺓⺔⺕⺖⺗⺘⺙⺛⺜⺝⺞⺟⺠⺡⺢⺣⺤⺥⺦⺧⺨⺩⺪⺫⺬⺭⺮⺯⺰⺱⺲⺳⺴⺵⺶⺷⺸⺹⺺⺻⺼⺽⺾⺿⻀⻁⻂⻃⻄⻅⻆⻇⻈⻉⻊⻋⻌⻍⻎⻏⻐⻑⻒⻓⻔⻕⻖⻗⻘⻙⻚⻛⻜⻝⻞⻟⻠';
+ $this->assertEqual($result, $expected);
+
+ $string = '⺀⺁⺂⺃⺄⺅⺆⺇⺈⺉⺊⺋⺌⺍⺎⺏⺐⺑⺒⺓⺔⺕⺖⺗⺘⺙⺛⺜⺝⺞⺟⺠⺡⺢⺣⺤⺥⺦⺧⺨⺩⺪⺫⺬⺭⺮⺯⺰⺱⺲⺳⺴⺵⺶⺷⺸⺹⺺⺻⺼⺽⺾⺿⻀⻁⻂⻃⻄⻅⻆⻇⻈⻉⻊⻋⻌⻍⻎⻏⻐⻑⻒⻓⻔⻕⻖⻗⻘⻙⻚⻛⻜⻝⻞⻟⻠';
+ $find = '⺐';
+ $result = Multibyte::stristr($string, $find, true);
+ $expected = '⺀⺁⺂⺃⺄⺅⺆⺇⺈⺉⺊⺋⺌⺍⺎⺏';
+ $this->assertEqual($result, $expected);
+
+ $string = '⽅⽆⽇⽈⽉⽊⽋⽌⽍⽎⽏⽐⽑⽒⽓⽔⽕⽖⽗⽘⽙⽚⽛⽜⽝⽞⽟⽠⽡⽢⽣⽤⽥⽦⽧⽨⽩⽪⽫⽬⽭⽮⽯⽰⽱⽲⽳⽴⽵⽶⽷⽸⽹⽺⽻⽼⽽⽾⽿';
+ $find = '⽤';
+ $result = Multibyte::stristr($string, $find);
+ $expected = '⽤⽥⽦⽧⽨⽩⽪⽫⽬⽭⽮⽯⽰⽱⽲⽳⽴⽵⽶⽷⽸⽹⽺⽻⽼⽽⽾⽿';
+ $this->assertEqual($result, $expected);
+
+ $string = '⽅⽆⽇⽈⽉⽊⽋⽌⽍⽎⽏⽐⽑⽒⽓⽔⽕⽖⽗⽘⽙⽚⽛⽜⽝⽞⽟⽠⽡⽢⽣⽤⽥⽦⽧⽨⽩⽪⽫⽬⽭⽮⽯⽰⽱⽲⽳⽴⽵⽶⽷⽸⽹⽺⽻⽼⽽⽾⽿';
+ $find = '⽤';
+ $result = Multibyte::stristr($string, $find, true);
+ $expected = '⽅⽆⽇⽈⽉⽊⽋⽌⽍⽎⽏⽐⽑⽒⽓⽔⽕⽖⽗⽘⽙⽚⽛⽜⽝⽞⽟⽠⽡⽢⽣';
+ $this->assertEqual($result, $expected);
+
+ $string = '눡눢눣눤눥눦눧눨눩눪눫눬눭눮눯눰눱눲눳눴눵눶눷눸눹눺눻눼눽눾눿뉀뉁뉂뉃뉄뉅뉆뉇뉈뉉뉊뉋뉌뉍뉎뉏뉐뉑뉒뉓뉔뉕뉖뉗뉘뉙뉚뉛뉜뉝뉞뉟뉠뉡뉢뉣뉤뉥뉦뉧뉨뉩뉪뉫뉬뉭뉮뉯뉰뉱뉲뉳뉴뉵뉶뉷뉸뉹뉺뉻뉼뉽뉾뉿늀늁늂늃늄';
+ $find = '눻';
+ $result = Multibyte::stristr($string, $find);
+ $expected = '눻눼눽눾눿뉀뉁뉂뉃뉄뉅뉆뉇뉈뉉뉊뉋뉌뉍뉎뉏뉐뉑뉒뉓뉔뉕뉖뉗뉘뉙뉚뉛뉜뉝뉞뉟뉠뉡뉢뉣뉤뉥뉦뉧뉨뉩뉪뉫뉬뉭뉮뉯뉰뉱뉲뉳뉴뉵뉶뉷뉸뉹뉺뉻뉼뉽뉾뉿늀늁늂늃늄';
+ $this->assertEqual($result, $expected);
+
+ $string = '눡눢눣눤눥눦눧눨눩눪눫눬눭눮눯눰눱눲눳눴눵눶눷눸눹눺눻눼눽눾눿뉀뉁뉂뉃뉄뉅뉆뉇뉈뉉뉊뉋뉌뉍뉎뉏뉐뉑뉒뉓뉔뉕뉖뉗뉘뉙뉚뉛뉜뉝뉞뉟뉠뉡뉢뉣뉤뉥뉦뉧뉨뉩뉪뉫뉬뉭뉮뉯뉰뉱뉲뉳뉴뉵뉶뉷뉸뉹뉺뉻뉼뉽뉾뉿늀늁늂늃늄';
+ $find = '눻';
+ $result = Multibyte::stristr($string, $find, true);
+ $expected = '눡눢눣눤눥눦눧눨눩눪눫눬눭눮눯눰눱눲눳눴눵눶눷눸눹눺';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ﹰﹱﹲﹳﹴﹶﹷﹸﹹﹺﹻﹼﹽﹾﹿﺀﺁﺂﺃﺄﺅﺆﺇﺈﺉﺊﺋﺌﺍﺎﺏﺐﺑﺒﺓﺔﺕﺖﺗﺘﺙﺚﺛﺜﺝﺞﺟﺠﺡﺢﺣﺤﺥﺦﺧﺨﺩﺪﺫﺬﺭﺮﺯﺰ';
+ $find = 'ﺞ';
+ $result = Multibyte::stristr($string, $find);
+ $expected = 'ﺞﺟﺠﺡﺢﺣﺤﺥﺦﺧﺨﺩﺪﺫﺬﺭﺮﺯﺰ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ﹰﹱﹲﹳﹴﹶﹷﹸﹹﹺﹻﹼﹽﹾﹿﺀﺁﺂﺃﺄﺅﺆﺇﺈﺉﺊﺋﺌﺍﺎﺏﺐﺑﺒﺓﺔﺕﺖﺗﺘﺙﺚﺛﺜﺝﺞﺟﺠﺡﺢﺣﺤﺥﺦﺧﺨﺩﺪﺫﺬﺭﺮﺯﺰ';
+ $find = 'ﺞ';
+ $result = Multibyte::stristr($string, $find, true);
+ $expected = 'ﹰﹱﹲﹳﹴﹶﹷﹸﹹﹺﹻﹼﹽﹾﹿﺀﺁﺂﺃﺄﺅﺆﺇﺈﺉﺊﺋﺌﺍﺎﺏﺐﺑﺒﺓﺔﺕﺖﺗﺘﺙﺚﺛﺜﺝ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ﺱﺲﺳﺴﺵﺶﺷﺸﺹﺺﺻﺼﺽﺾﺿﻀﻁﻂﻃﻄﻅﻆﻇﻈﻉﻊﻋﻌﻍﻎﻏﻐﻑﻒﻓﻔﻕﻖﻗﻘﻙﻚﻛﻜﻝﻞﻟﻠﻡﻢﻣﻤﻥﻦﻧﻨﻩﻪﻫﻬﻭﻮﻯﻰﻱﻲﻳﻴﻵﻶﻷﻸﻹﻺﻻﻼ';
+ $find = 'ﻞ';
+ $result = Multibyte::stristr($string, $find);
+ $expected = 'ﻞﻟﻠﻡﻢﻣﻤﻥﻦﻧﻨﻩﻪﻫﻬﻭﻮﻯﻰﻱﻲﻳﻴﻵﻶﻷﻸﻹﻺﻻﻼ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ﺱﺲﺳﺴﺵﺶﺷﺸﺹﺺﺻﺼﺽﺾﺿﻀﻁﻂﻃﻄﻅﻆﻇﻈﻉﻊﻋﻌﻍﻎﻏﻐﻑﻒﻓﻔﻕﻖﻗﻘﻙﻚﻛﻜﻝﻞﻟﻠﻡﻢﻣﻤﻥﻦﻧﻨﻩﻪﻫﻬﻭﻮﻯﻰﻱﻲﻳﻴﻵﻶﻷﻸﻹﻺﻻﻼ';
+ $find = 'ﻞ';
+ $result = Multibyte::stristr($string, $find, true);
+ $expected = 'ﺱﺲﺳﺴﺵﺶﺷﺸﺹﺺﺻﺼﺽﺾﺿﻀﻁﻂﻃﻄﻅﻆﻇﻈﻉﻊﻋﻌﻍﻎﻏﻐﻑﻒﻓﻔﻕﻖﻗﻘﻙﻚﻛﻜﻝ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'abcdefghijklmnopqrstuvwxyz';
+ $find = 'K';
+ $result = Multibyte::stristr($string, $find);
+ $expected = 'klmnopqrstuvwxyz';
+ $this->assertEqual($result, $expected);
+
+ $string = 'abcdefghijklmnopqrstuvwxyz';
+ $find = 'K';
+ $result = Multibyte::stristr($string, $find, true);
+ $expected = 'abcdefghij';
+ $this->assertEqual($result, $expected);
+
+ $string = '。「」、・ヲァィゥェォャュョッーアイウエオカキク';
+ $find = 'ア';
+ $result = Multibyte::stristr($string, $find);
+ $expected = 'アイウエオカキク';
+ $this->assertEqual($result, $expected);
+
+ $string = '。「」、・ヲァィゥェォャュョッーアイウエオカキク';
+ $find = 'ア';
+ $result = Multibyte::stristr($string, $find, true);
+ $expected = '。「」、・ヲァィゥェォャュョッー';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン゙';
+ $find = 'ハ';
+ $result = Multibyte::stristr($string, $find);
+ $expected = 'ハヒフヘホマミムメモヤユヨラリルレロワン゙';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン゙';
+ $find = 'ハ';
+ $result = Multibyte::stristr($string, $find, true);
+ $expected = 'ケコサシスセソタチツテトナニヌネノ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ĥēĺļŏ, Ŵőřļď!';
+ $find = 'Ő';
+ $result = Multibyte::stristr($string, $find);
+ $expected = 'őřļď!';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ĥēĺļŏ, Ŵőřļď!';
+ $find = 'Ő';
+ $result = Multibyte::stristr($string, $find, true);
+ $expected = 'Ĥēĺļŏ, Ŵ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ĥēĺļŏ, Ŵőřļď!';
+ $find = 'ĺļ';
+ $result = Multibyte::stristr($string, $find, true);
+ $expected = 'Ĥē';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Hello, World!';
+ $find = 'O';
+ $result = Multibyte::stristr($string, $find);
+ $expected = 'o, World!';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Hello, World!';
+ $find = 'O';
+ $result = Multibyte::stristr($string, $find, true);
+ $expected = 'Hell';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Hello, World!';
+ $find = 'Wo';
+ $result = Multibyte::stristr($string, $find);
+ $expected = 'World!';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Hello, World!';
+ $find = 'Wo';
+ $result = Multibyte::stristr($string, $find, true);
+ $expected = 'Hello, ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Hello, World!';
+ $find = 'll';
+ $result = Multibyte::stristr($string, $find);
+ $expected = 'llo, World!';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Hello, World!';
+ $find = 'll';
+ $result = Multibyte::stristr($string, $find, true);
+ $expected = 'He';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Hello, World!';
+ $find = 'rld';
+ $result = Multibyte::stristr($string, $find);
+ $expected = 'rld!';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Hello, World!';
+ $find = 'rld';
+ $result = Multibyte::stristr($string, $find, true);
+ $expected = 'Hello, Wo';
+ $this->assertEqual($result, $expected);
+
+ $string = 'čini';
+ $find = 'N';
+ $result = Multibyte::stristr($string, $find);
+ $expected = 'ni';
+ $this->assertEqual($result, $expected);
+
+ $string = 'čini';
+ $find = 'N';
+ $result = Multibyte::stristr($string, $find, true);
+ $expected = 'či';
+ $this->assertEqual($result, $expected);
+
+ $string = 'moći';
+ $find = 'Ć';
+ $result = Multibyte::stristr($string, $find);
+ $expected = 'ći';
+ $this->assertEqual($result, $expected);
+
+ $string = 'moći';
+ $find = 'Ć';
+ $result = Multibyte::stristr($string, $find, true);
+ $expected = 'mo';
+ $this->assertEqual($result, $expected);
+
+ $string = 'državni';
+ $find = 'Ž';
+ $result = Multibyte::stristr($string, $find);
+ $expected = 'žavni';
+ $this->assertEqual($result, $expected);
+
+ $string = 'državni';
+ $find = 'Ž';
+ $result = Multibyte::stristr($string, $find, true);
+ $expected = 'dr';
+ $this->assertEqual($result, $expected);
+
+ $string = '把百度设为首页';
+ $find = '设';
+ $result = Multibyte::stristr($string, $find);
+ $expected = '设为首页';
+ $this->assertEqual($result, $expected);
+
+ $string = '把百度设为首页';
+ $find = '设';
+ $result = Multibyte::stristr($string, $find, true);
+ $expected = '把百度';
+ $this->assertEqual($result, $expected);
+
+ $string = '一二三周永龍';
+ $find = '周';
+ $result = Multibyte::stristr($string, $find);
+ $expected = '周永龍';
+ $this->assertEqual($result, $expected);
+
+ $string = '一二三周永龍';
+ $find = '周';
+ $result = Multibyte::stristr($string, $find, true);
+ $expected = '一二三';
+ $this->assertEqual($result, $expected);
+
+ $string = '一二三周永龍';
+ $find = '二周';
+ $result = Multibyte::stristr($string, $find);
+ $expected = false;
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testUsingMbStrlen method
+ *
+ * @access public
+ * @return void
+ */
+ function testUsingMbStrlen() {
+ $string = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
+ $result = mb_strlen($string);
+ $expected = 36;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞ';
+ $result = mb_strlen($string);
+ $expected = 30;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĀĂĄĆĈĊČĎĐĒĔĖĘĚĜĞĠĢĤĦĨĪĬĮIJĴĶĹĻĽĿŁŃŅŇŊŌŎŐŒŔŖŘŚŜŞŠŢŤŦŨŪŬŮŰŲŴŶŹŻŽ';
+ $result = mb_strlen($string);
+ $expected = 61;
+ $this->assertEqual($result, $expected);
+
+ $string = '!"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~';
+ $result = mb_strlen($string);
+ $expected = 94;
+ $this->assertEqual($result, $expected);
+
+ $string = '¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈ';
+ $result = mb_strlen($string);
+ $expected = 40;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿĀāĂ㥹ĆćĈĉĊċČčĎďĐđĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪīĬ';
+ $result = mb_strlen($string);
+ $expected = 100;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĭĮįİıIJijĴĵĶķĸĹĺĻļĽľĿŀŁłŃńŅņŇňʼnŊŋŌōŎŏŐőŒœŔŕŖŗŘřŚśŜŝŞşŠšŢţŤťŦŧŨũŪūŬŭŮůŰűŲųŴŵŶŷŸŹźŻżŽžſƀƁƂƃƄƅƆƇƈƉƊƋƌƍƎƏƐ';
+ $result = mb_strlen($string);
+ $expected = 100;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ƑƒƓƔƕƖƗƘƙƚƛƜƝƞƟƠơƢƣƤƥƦƧƨƩƪƫƬƭƮƯưƱƲƳƴƵƶƷƸƹƺƻƼƽƾƿǀǁǂǃDŽDždžLJLjljNJNjnjǍǎǏǐǑǒǓǔǕǖǗǘǙǚǛǜǝǞǟǠǡǢǣǤǥǦǧǨǩǪǫǬǭǮǯǰDZDzdzǴ';
+ $result = mb_strlen($string);
+ $expected = 100;
+ $this->assertEqual($result, $expected);
+
+ $string = 'əɚɛɜɝɞɟɠɡɢɣɤɥɦɧɨɩɪɫɬɭɮɯɰɱɲɳɴɵɶɷɸɹɺɻɼɽɾɿʀʁʂʃʄʅʆʇʈʉʊʋʌʍʎʏʐʑʒʓʔʕʖʗʘʙʚʛʜʝʞʟʠʡʢʣʤʥʦʧʨʩʪʫʬʭʮʯʰʱʲʳʴʵʶʷʸʹʺʻʼ';
+ $result = mb_strlen($string);
+ $expected = 100;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ЀЁЂЃЄЅІЇЈЉЊЋЌЍЎЏАБВГДЕЖЗИЙКЛ';
+ $result = mb_strlen($string);
+ $expected = 28;
+ $this->assertEqual($result, $expected);
+
+ $string = 'МНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыь';
+ $result = mb_strlen($string);
+ $expected = 49;
+ $this->assertEqual($result, $expected);
+
+ $string = 'فقكلمنهوىيًٌٍَُ';
+ $result = mb_strlen($string);
+ $expected = 15;
+ $this->assertEqual($result, $expected);
+
+ $string = '✰✱✲✳✴✵✶✷✸✹✺✻✼✽✾✿❀❁❂❃❄❅❆❇❈❉❊❋❌❍❎❏❐❑❒❓❔❕❖❗❘❙❚❛❜❝❞';
+ $result = mb_strlen($string);
+ $expected = 47;
+ $this->assertEqual($result, $expected);
+
+ $string = '⺀⺁⺂⺃⺄⺅⺆⺇⺈⺉⺊⺋⺌⺍⺎⺏⺐⺑⺒⺓⺔⺕⺖⺗⺘⺙⺛⺜⺝⺞⺟⺠⺡⺢⺣⺤⺥⺦⺧⺨⺩⺪⺫⺬⺭⺮⺯⺰⺱⺲⺳⺴⺵⺶⺷⺸⺹⺺⺻⺼⺽⺾⺿⻀⻁⻂⻃⻄⻅⻆⻇⻈⻉⻊⻋⻌⻍⻎⻏⻐⻑⻒⻓⻔⻕⻖⻗⻘⻙⻚⻛⻜⻝⻞⻟⻠';
+ $result = mb_strlen($string);
+ $expected = 96;
+ $this->assertEqual($result, $expected);
+
+ $string = '⽅⽆⽇⽈⽉⽊⽋⽌⽍⽎⽏⽐⽑⽒⽓⽔⽕⽖⽗⽘⽙⽚⽛⽜⽝⽞⽟⽠⽡⽢⽣⽤⽥⽦⽧⽨⽩⽪⽫⽬⽭⽮⽯⽰⽱⽲⽳⽴⽵⽶⽷⽸⽹⽺⽻⽼⽽⽾⽿';
+ $result = mb_strlen($string);
+ $expected = 59;
+ $this->assertEqual($result, $expected);
+
+ $string = '눡눢눣눤눥눦눧눨눩눪눫눬눭눮눯눰눱눲눳눴눵눶눷눸눹눺눻눼눽눾눿뉀뉁뉂뉃뉄뉅뉆뉇뉈뉉뉊뉋뉌뉍뉎뉏뉐뉑뉒뉓뉔뉕뉖뉗뉘뉙뉚뉛뉜뉝뉞뉟뉠뉡뉢뉣뉤뉥뉦뉧뉨뉩뉪뉫뉬뉭뉮뉯뉰뉱뉲뉳뉴뉵뉶뉷뉸뉹뉺뉻뉼뉽뉾뉿늀늁늂늃늄';
+ $result = mb_strlen($string);
+ $expected = 100;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ﹰﹱﹲﹳﹴﹶﹷﹸﹹﹺﹻﹼﹽﹾﹿﺀﺁﺂﺃﺄﺅﺆﺇﺈﺉﺊﺋﺌﺍﺎﺏﺐﺑﺒﺓﺔﺕﺖﺗﺘﺙﺚﺛﺜﺝﺞﺟﺠﺡﺢﺣﺤﺥﺦﺧﺨﺩﺪﺫﺬﺭﺮﺯﺰ';
+ $result = mb_strlen($string);
+ $expected = 65;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ﺱﺲﺳﺴﺵﺶﺷﺸﺹﺺﺻﺼﺽﺾﺿﻀﻁﻂﻃﻄﻅﻆﻇﻈﻉﻊﻋﻌﻍﻎﻏﻐﻑﻒﻓﻔﻕﻖﻗﻘﻙﻚﻛﻜﻝﻞﻟﻠﻡﻢﻣﻤﻥﻦﻧﻨﻩﻪﻫﻬﻭﻮﻯﻰﻱﻲﻳﻴﻵﻶﻷﻸﻹﻺﻻﻼ';
+ $result = mb_strlen($string);
+ $expected = 76;
+ $this->assertEqual($result, $expected);
+
+ $string = 'abcdefghijklmnopqrstuvwxyz';
+ $result = mb_strlen($string);
+ $expected = 26;
+ $this->assertEqual($result, $expected);
+
+ $string = '。「」、・ヲァィゥェォャュョッーアイウエオカキク';
+ $result = mb_strlen($string);
+ $expected = 24;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン゙';
+ $result = mb_strlen($string);
+ $expected = 38;
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ĥēĺļŏ, Ŵőřļď!';
+ $result = mb_strlen($string);
+ $expected = 13;
+ $this->assertEqual($result, $expected);
+
+ $string = 'Hello, World!';
+ $result = mb_strlen($string);
+ $expected = 13;
+ $this->assertEqual($result, $expected);
+
+ $string = 'čini';
+ $result = mb_strlen($string);
+ $expected = 4;
+ $this->assertEqual($result, $expected);
+
+ $string = 'moći';
+ $result = mb_strlen($string);
+ $expected = 4;
+ $this->assertEqual($result, $expected);
+
+ $string = 'državni';
+ $result = mb_strlen($string);
+ $expected = 7;
+ $this->assertEqual($result, $expected);
+
+ $string = '把百度设为首页';
+ $result = mb_strlen($string);
+ $expected = 7;
+ $this->assertEqual($result, $expected);
+
+ $string = '一二三周永龍';
+ $result = mb_strlen($string);
+ $expected = 6;
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testMultibyteStrlen method
+ *
+ * @access public
+ * @return void
+ */
+ function testMultibyteStrlen() {
+ $string = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
+ $result = Multibyte::strlen($string);
+ $expected = 36;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞ';
+ $result = Multibyte::strlen($string);
+ $expected = 30;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĀĂĄĆĈĊČĎĐĒĔĖĘĚĜĞĠĢĤĦĨĪĬĮIJĴĶĹĻĽĿŁŃŅŇŊŌŎŐŒŔŖŘŚŜŞŠŢŤŦŨŪŬŮŰŲŴŶŹŻŽ';
+ $result = Multibyte::strlen($string);
+ $expected = 61;
+ $this->assertEqual($result, $expected);
+
+ $string = '!"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~';
+ $result = Multibyte::strlen($string);
+ $expected = 94;
+ $this->assertEqual($result, $expected);
+
+ $string = '¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈ';
+ $result = Multibyte::strlen($string);
+ $expected = 40;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿĀāĂ㥹ĆćĈĉĊċČčĎďĐđĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪīĬ';
+ $result = Multibyte::strlen($string);
+ $expected = 100;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĭĮįİıIJijĴĵĶķĸĹĺĻļĽľĿŀŁłŃńŅņŇňʼnŊŋŌōŎŏŐőŒœŔŕŖŗŘřŚśŜŝŞşŠšŢţŤťŦŧŨũŪūŬŭŮůŰűŲųŴŵŶŷŸŹźŻżŽžſƀƁƂƃƄƅƆƇƈƉƊƋƌƍƎƏƐ';
+ $result = Multibyte::strlen($string);
+ $expected = 100;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ƑƒƓƔƕƖƗƘƙƚƛƜƝƞƟƠơƢƣƤƥƦƧƨƩƪƫƬƭƮƯưƱƲƳƴƵƶƷƸƹƺƻƼƽƾƿǀǁǂǃDŽDždžLJLjljNJNjnjǍǎǏǐǑǒǓǔǕǖǗǘǙǚǛǜǝǞǟǠǡǢǣǤǥǦǧǨǩǪǫǬǭǮǯǰDZDzdzǴ';
+ $result = Multibyte::strlen($string);
+ $expected = 100;
+ $this->assertEqual($result, $expected);
+
+ $string = 'əɚɛɜɝɞɟɠɡɢɣɤɥɦɧɨɩɪɫɬɭɮɯɰɱɲɳɴɵɶɷɸɹɺɻɼɽɾɿʀʁʂʃʄʅʆʇʈʉʊʋʌʍʎʏʐʑʒʓʔʕʖʗʘʙʚʛʜʝʞʟʠʡʢʣʤʥʦʧʨʩʪʫʬʭʮʯʰʱʲʳʴʵʶʷʸʹʺʻʼ';
+ $result = Multibyte::strlen($string);
+ $expected = 100;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ЀЁЂЃЄЅІЇЈЉЊЋЌЍЎЏАБВГДЕЖЗИЙКЛ';
+ $result = Multibyte::strlen($string);
+ $expected = 28;
+ $this->assertEqual($result, $expected);
+
+ $string = 'МНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыь';
+ $result = Multibyte::strlen($string);
+ $expected = 49;
+ $this->assertEqual($result, $expected);
+
+ $string = 'فقكلمنهوىيًٌٍَُ';
+ $result = Multibyte::strlen($string);
+ $expected = 15;
+ $this->assertEqual($result, $expected);
+
+ $string = '✰✱✲✳✴✵✶✷✸✹✺✻✼✽✾✿❀❁❂❃❄❅❆❇❈❉❊❋❌❍❎❏❐❑❒❓❔❕❖❗❘❙❚❛❜❝❞';
+ $result = Multibyte::strlen($string);
+ $expected = 47;
+ $this->assertEqual($result, $expected);
+
+ $string = '⺀⺁⺂⺃⺄⺅⺆⺇⺈⺉⺊⺋⺌⺍⺎⺏⺐⺑⺒⺓⺔⺕⺖⺗⺘⺙⺛⺜⺝⺞⺟⺠⺡⺢⺣⺤⺥⺦⺧⺨⺩⺪⺫⺬⺭⺮⺯⺰⺱⺲⺳⺴⺵⺶⺷⺸⺹⺺⺻⺼⺽⺾⺿⻀⻁⻂⻃⻄⻅⻆⻇⻈⻉⻊⻋⻌⻍⻎⻏⻐⻑⻒⻓⻔⻕⻖⻗⻘⻙⻚⻛⻜⻝⻞⻟⻠';
+ $result = Multibyte::strlen($string);
+ $expected = 96;
+ $this->assertEqual($result, $expected);
+
+ $string = '⽅⽆⽇⽈⽉⽊⽋⽌⽍⽎⽏⽐⽑⽒⽓⽔⽕⽖⽗⽘⽙⽚⽛⽜⽝⽞⽟⽠⽡⽢⽣⽤⽥⽦⽧⽨⽩⽪⽫⽬⽭⽮⽯⽰⽱⽲⽳⽴⽵⽶⽷⽸⽹⽺⽻⽼⽽⽾⽿';
+ $result = Multibyte::strlen($string);
+ $expected = 59;
+ $this->assertEqual($result, $expected);
+
+ $string = '눡눢눣눤눥눦눧눨눩눪눫눬눭눮눯눰눱눲눳눴눵눶눷눸눹눺눻눼눽눾눿뉀뉁뉂뉃뉄뉅뉆뉇뉈뉉뉊뉋뉌뉍뉎뉏뉐뉑뉒뉓뉔뉕뉖뉗뉘뉙뉚뉛뉜뉝뉞뉟뉠뉡뉢뉣뉤뉥뉦뉧뉨뉩뉪뉫뉬뉭뉮뉯뉰뉱뉲뉳뉴뉵뉶뉷뉸뉹뉺뉻뉼뉽뉾뉿늀늁늂늃늄';
+ $result = Multibyte::strlen($string);
+ $expected = 100;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ﹰﹱﹲﹳﹴﹶﹷﹸﹹﹺﹻﹼﹽﹾﹿﺀﺁﺂﺃﺄﺅﺆﺇﺈﺉﺊﺋﺌﺍﺎﺏﺐﺑﺒﺓﺔﺕﺖﺗﺘﺙﺚﺛﺜﺝﺞﺟﺠﺡﺢﺣﺤﺥﺦﺧﺨﺩﺪﺫﺬﺭﺮﺯﺰ';
+ $result = Multibyte::strlen($string);
+ $expected = 65;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ﺱﺲﺳﺴﺵﺶﺷﺸﺹﺺﺻﺼﺽﺾﺿﻀﻁﻂﻃﻄﻅﻆﻇﻈﻉﻊﻋﻌﻍﻎﻏﻐﻑﻒﻓﻔﻕﻖﻗﻘﻙﻚﻛﻜﻝﻞﻟﻠﻡﻢﻣﻤﻥﻦﻧﻨﻩﻪﻫﻬﻭﻮﻯﻰﻱﻲﻳﻴﻵﻶﻷﻸﻹﻺﻻﻼ';
+ $result = Multibyte::strlen($string);
+ $expected = 76;
+ $this->assertEqual($result, $expected);
+
+ $string = 'abcdefghijklmnopqrstuvwxyz';
+ $result = Multibyte::strlen($string);
+ $expected = 26;
+ $this->assertEqual($result, $expected);
+
+ $string = '。「」、・ヲァィゥェォャュョッーアイウエオカキク';
+ $result = Multibyte::strlen($string);
+ $expected = 24;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン゙';
+ $result = Multibyte::strlen($string);
+ $expected = 38;
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ĥēĺļŏ, Ŵőřļď!';
+ $result = Multibyte::strlen($string);
+ $expected = 13;
+ $this->assertEqual($result, $expected);
+
+ $string = 'Hello, World!';
+ $result = Multibyte::strlen($string);
+ $expected = 13;
+ $this->assertEqual($result, $expected);
+
+ $string = 'čini';
+ $result = Multibyte::strlen($string);
+ $expected = 4;
+ $this->assertEqual($result, $expected);
+
+ $string = 'moći';
+ $result = Multibyte::strlen($string);
+ $expected = 4;
+ $this->assertEqual($result, $expected);
+
+ $string = 'državni';
+ $result = Multibyte::strlen($string);
+ $expected = 7;
+ $this->assertEqual($result, $expected);
+
+ $string = '把百度设为首页';
+ $result = Multibyte::strlen($string);
+ $expected = 7;
+ $this->assertEqual($result, $expected);
+
+ $string = '一二三周永龍';
+ $result = Multibyte::strlen($string);
+ $expected = 6;
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testUsingMbStrpos method
+ *
+ * @access public
+ * @return void
+ */
+ function testUsingMbStrpos() {
+ $string = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
+ $find = 'F';
+ $result = mb_strpos($string, $find);
+ $expected = 5;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ABCDEFGHIJKLMNOPQFRSTUVWXYZ0123456789';
+ $find = 'F';
+ $result = mb_strpos($string, $find, 6);
+ $expected = 17;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞ';
+ $find = 'Å';
+ $result = mb_strpos($string, $find);
+ $expected = 5;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÅÙÚÛÜÝÞ';
+ $find = 'Å';
+ $result = mb_strpos($string, $find, 6);
+ $expected = 24;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĀĂĄĆĈĊČĎĐĒĔĖĘĚĜĞĠĢĤĦĨĪĬĮIJĴĶĹĻĽĿŁŃŅŇŊŌŎŐŒŔŖŘŚŜŞŠŢŤŦŨŪŬŮŰŲŴŶŹŻŽ';
+ $find = 'Ċ';
+ $result = mb_strpos($string, $find);
+ $expected = 5;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĀĂĄĆĈĊČĎĐĒĔĖĘĚĜĞĠĢĤĦĨĪĬĮIJĴĶĹĻĽĿŁĊŃŅŇŊŌŎŐŒŔŖŘŚŜŞŠŢŤŦŨŪŬŮŰŲŴŶŹŻŽ';
+ $find = 'Ċ';
+ $result = mb_strpos($string, $find, 6);
+ $expected = 32;
+ $this->assertEqual($result, $expected);
+
+ $string = '!"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~';
+ $find = 'F';
+ $result = mb_strpos($string, $find);
+ $expected = 37;
+ $this->assertEqual($result, $expected);
+
+ $string = '¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈ';
+ $find = 'µ';
+ $result = mb_strpos($string, $find);
+ $expected = 20;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿĀāĂ㥹ĆćĈĉĊċČčĎďĐđĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪīĬ';
+ $find = 'é';
+ $result = mb_strpos($string, $find);
+ $expected = 32;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĭĮįİıIJijĴĵĶķĸĹĺĻļĽľĿŀŁłŃńŅņŇňʼnŊŋŌōŎŏŐőŒœŔŕŖŗŘřŚśŜŝŞşŠšŢţŤťŦŧŨũŪūŬŭŮůŰűŲųŴŵŶŷŸŹźŻżŽžſƀƁƂƃƄƅƆƇƈƉƊƋƌƍƎƏƐ';
+ $find = 'Ņ';
+ $result = mb_strpos($string, $find);
+ $expected = 24;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ƑƒƓƔƕƖƗƘƙƚƛƜƝƞƟƠơƢƣƤƥƦƧƨƩƪƫƬƭƮƯưƱƲƳƴƵƶƷƸƹƺƻƼƽƾƿǀǁǂǃDŽDždžLJLjljNJNjnjǍǎǏǐǑǒǓǔǕǖǗǘǙǚǛǜǝǞǟǠǡǢǣǤǥǦǧǨǩǪǫǬǭǮǯǰDZDzdzǴ';
+ $find = 'Ƹ';
+ $result = mb_strpos($string, $find);
+ $expected = 39;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ƑƒƓƔƕƖƗƘƙƚƛƜƝƞƟƠơƢƣƤƥƦƧƨƩƪƫƬƭƮƯưƱƲƳƴƵƶƷƸƹƺƻƼƽƾƿǀǁǂǃDŽDždžLJLjljNJNjnjǍǎǏǐǑǒǓǔǕǖǗǘǙǚǛǜǝǞǟǠǡǢǣǤǥǦǧǨǩǪǫǬǭǮǯǰDZDzdzǴ';
+ $find = 'ƹ';
+ $result = mb_strpos($string, $find);
+ $expected = 40;
+ $this->assertEqual($result, $expected);
+
+ $string = 'əɚɛɜɝɞɟɠɡɢɣɤɥɦɧɨɩɪɫɬɭɮɯɰɱɲɳɴɵɶɷɸɹɺɻɼɽɾɿʀʁʂʃʄʅʆʇʈʉʊʋʌʍʎʏʐʑʒʓʔʕʖʗʘʙʚʛʜʝʞʟʠʡʢʣʤʥʦʧʨʩʪʫʬʭʮʯʰʱʲʳʴʵʶʷʸʹʺʻʼ';
+ $find = 'ʀ';
+ $result = mb_strpos($string, $find);
+ $expected = 39;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ЀЁЂЃЄЅІЇЈЉЊЋЌЍЎЏАБВГДЕЖЗИЙКЛ';
+ $find = 'Ї';
+ $result = mb_strpos($string, $find);
+ $expected = 7;
+ $this->assertEqual($result, $expected);
+
+ $string = 'МНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыь';
+ $find = 'Р';
+ $result = mb_strpos($string, $find);
+ $expected = 4;
+ $this->assertEqual($result, $expected);
+
+ $string = 'МНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыь';
+ $find = 'р';
+ $result = mb_strpos($string, $find, 5);
+ $expected = 36;
+ $this->assertEqual($result, $expected);
+
+ $string = 'فقكلمنهوىيًٌٍَُ';
+ $find = 'ن';
+ $result = mb_strpos($string, $find);
+ $expected = 5;
+ $this->assertEqual($result, $expected);
+
+ $string = '✰✱✲✳✴✵✶✷✸✹✺✻✼✽✾✿❀❁❂❃❄❅❆❇❈❉❊❋❌❍❎❏❐❑❒❓❔❕❖❗❘❙❚❛❜❝❞';
+ $find = '✿';
+ $result = mb_strpos($string, $find);
+ $expected = 15;
+ $this->assertEqual($result, $expected);
+
+ $string = '⺀⺁⺂⺃⺄⺅⺆⺇⺈⺉⺊⺋⺌⺍⺎⺏⺐⺑⺒⺓⺔⺕⺖⺗⺘⺙⺛⺜⺝⺞⺟⺠⺡⺢⺣⺤⺥⺦⺧⺨⺩⺪⺫⺬⺭⺮⺯⺰⺱⺲⺳⺴⺵⺶⺷⺸⺹⺺⺻⺼⺽⺾⺿⻀⻁⻂⻃⻄⻅⻆⻇⻈⻉⻊⻋⻌⻍⻎⻏⻐⻑⻒⻓⻔⻕⻖⻗⻘⻙⻚⻛⻜⻝⻞⻟⻠';
+ $find = '⺐';
+ $result = mb_strpos($string, $find);
+ $expected = 16;
+ $this->assertEqual($result, $expected);
+
+ $string = '⽅⽆⽇⽈⽉⽊⽋⽌⽍⽎⽏⽐⽑⽒⽓⽔⽕⽖⽗⽘⽙⽚⽛⽜⽝⽞⽟⽠⽡⽢⽣⽤⽥⽦⽧⽨⽩⽪⽫⽬⽭⽮⽯⽰⽱⽲⽳⽴⽵⽶⽷⽸⽹⽺⽻⽼⽽⽾⽿';
+ $find = '⽤';
+ $result = mb_strpos($string, $find);
+ $expected = 31;
+ $this->assertEqual($result, $expected);
+
+ $string = '눡눢눣눤눥눦눧눨눩눪눫눬눭눮눯눰눱눲눳눴눵눶눷눸눹눺눻눼눽눾눿뉀뉁뉂뉃뉄뉅뉆뉇뉈뉉뉊뉋뉌뉍뉎뉏뉐뉑뉒뉓뉔뉕뉖뉗뉘뉙뉚뉛뉜뉝뉞뉟뉠뉡뉢뉣뉤뉥뉦뉧뉨뉩뉪뉫뉬뉭뉮뉯뉰뉱뉲뉳뉴뉵뉶뉷뉸뉹뉺뉻뉼뉽뉾뉿늀늁늂늃늄';
+ $find = '눻';
+ $result = mb_strpos($string, $find);
+ $expected = 26;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ﹰﹱﹲﹳﹴﹶﹷﹸﹹﹺﹻﹼﹽﹾﹿﺀﺁﺂﺃﺄﺅﺆﺇﺈﺉﺊﺋﺌﺍﺎﺏﺐﺑﺒﺓﺔﺕﺖﺗﺘﺙﺚﺛﺜﺝﺞﺟﺠﺡﺢﺣﺤﺥﺦﺧﺨﺩﺪﺫﺬﺭﺮﺯﺰ';
+ $find = 'ﺞ';
+ $result = mb_strpos($string, $find);
+ $expected = 46;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ﺱﺲﺳﺴﺵﺶﺷﺸﺹﺺﺻﺼﺽﺾﺿﻀﻁﻂﻃﻄﻅﻆﻇﻈﻉﻊﻋﻌﻍﻎﻏﻐﻑﻒﻓﻔﻕﻖﻗﻘﻙﻚﻛﻜﻝﻞﻟﻠﻡﻢﻣﻤﻥﻦﻧﻨﻩﻪﻫﻬﻭﻮﻯﻰﻱﻲﻳﻴﻵﻶﻷﻸﻹﻺﻻﻼ';
+ $find = 'ﻞ';
+ $result = mb_strpos($string, $find);
+ $expected = 45;
+ $this->assertEqual($result, $expected);
+
+ $string = 'abcdefghijklmnopqrstuvwxyz';
+ $find = 'k';
+ $result = mb_strpos($string, $find);
+ $expected = 10;
+ $this->assertEqual($result, $expected);
+
+ $string = 'abcdefghijklmnopqrstuvwxyz';
+ $find = 'k';
+ $result = mb_strpos($string, $find);
+ $expected = 10;
+ $this->assertEqual($result, $expected);
+
+ $string = '。「」、・ヲァィゥェォャュョッーアイウエオカキク';
+ $find = 'ア';
+ $result = mb_strpos($string, $find);
+ $expected = 16;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン゙';
+ $find = 'ハ';
+ $result = mb_strpos($string, $find);
+ $expected = 17;
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ĥēĺļŏ, Ŵőřļď!';
+ $find = 'ő';
+ $result = mb_strpos($string, $find);
+ $expected = 8;
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ĥēĺļŏ, Ŵőřļď!';
+ $find = 'ő';
+ $result = mb_strpos($string, $find);
+ $expected = 8;
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ĥēĺļŏ, Ŵőřļď!';
+ $find = 'őř';
+ $result = mb_strpos($string, $find);
+ $expected = 8;
+ $this->assertEqual($result, $expected);
+
+ $string = 'Hello, World!';
+ $find = 'o';
+ $result = mb_strpos($string, $find);
+ $expected = 4;
+ $this->assertEqual($result, $expected);
+
+ $string = 'Hello, World!';
+ $find = 'o';
+ $result = mb_strpos($string, $find, 5);
+ $expected = 8;
+ $this->assertEqual($result, $expected);
+
+ $string = 'čini';
+ $find = 'n';
+ $result = mb_strpos($string, $find);
+ $expected = 2;
+ $this->assertEqual($result, $expected);
+
+ $string = 'čini';
+ $find = 'n';
+ $result = mb_strpos($string, $find);
+ $expected = 2;
+ $this->assertEqual($result, $expected);
+
+ $string = 'moći';
+ $find = 'ć';
+ $result = mb_strpos($string, $find);
+ $expected = 2;
+ $this->assertEqual($result, $expected);
+
+ $string = 'moći';
+ $find = 'ć';
+ $result = mb_strpos($string, $find);
+ $expected = 2;
+ $this->assertEqual($result, $expected);
+
+ $string = 'državni';
+ $find = 'ž';
+ $result = mb_strpos($string, $find);
+ $expected = 2;
+ $this->assertEqual($result, $expected);
+
+ $string = '把百度设为首页';
+ $find = '设';
+ $result = mb_strpos($string, $find);
+ $expected = 3;
+ $this->assertEqual($result, $expected);
+
+ $string = '一二三周永龍';
+ $find = '周';
+ $result = mb_strpos($string, $find);
+ $expected = 3;
+ $this->assertEqual($result, $expected);
+
+ $string = '一二三周永龍';
+ $find = '一周';
+ $result = mb_strpos($string, $find);
+ $expected = false;
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testMultibyteStrpos method
+ *
+ * @access public
+ * @return void
+ */
+ function testMultibyteStrpos() {
+ $string = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
+ $find = 'F';
+ $result = Multibyte::strpos($string, $find);
+ $expected = 5;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ABCDEFGHIJKLMNOPQFRSTUVWXYZ0123456789';
+ $find = 'F';
+ $result = Multibyte::strpos($string, $find, 6);
+ $expected = 17;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞ';
+ $find = 'Å';
+ $result = Multibyte::strpos($string, $find);
+ $expected = 5;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÅÙÚÛÜÝÞ';
+ $find = 'Å';
+ $result = Multibyte::strpos($string, $find, 6);
+ $expected = 24;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĀĂĄĆĈĊČĎĐĒĔĖĘĚĜĞĠĢĤĦĨĪĬĮIJĴĶĹĻĽĿŁŃŅŇŊŌŎŐŒŔŖŘŚŜŞŠŢŤŦŨŪŬŮŰŲŴŶŹŻŽ';
+ $find = 'Ċ';
+ $result = Multibyte::strpos($string, $find);
+ $expected = 5;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĀĂĄĆĈĊČĎĐĒĔĖĘĚĜĞĠĢĤĦĨĪĬĮIJĴĶĹĻĽĿŁĊŃŅŇŊŌŎŐŒŔŖŘŚŜŞŠŢŤŦŨŪŬŮŰŲŴŶŹŻŽ';
+ $find = 'Ċ';
+ $result = Multibyte::strpos($string, $find, 6);
+ $expected = 32;
+ $this->assertEqual($result, $expected);
+
+ $string = '!"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~';
+ $find = 'F';
+ $result = Multibyte::strpos($string, $find);
+ $expected = 37;
+ $this->assertEqual($result, $expected);
+
+ $string = '¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈ';
+ $find = 'µ';
+ $result = Multibyte::strpos($string, $find);
+ $expected = 20;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿĀāĂ㥹ĆćĈĉĊċČčĎďĐđĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪīĬ';
+ $find = 'é';
+ $result = Multibyte::strpos($string, $find);
+ $expected = 32;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĭĮįİıIJijĴĵĶķĸĹĺĻļĽľĿŀŁłŃńŅņŇňʼnŊŋŌōŎŏŐőŒœŔŕŖŗŘřŚśŜŝŞşŠšŢţŤťŦŧŨũŪūŬŭŮůŰűŲųŴŵŶŷŸŹźŻżŽžſƀƁƂƃƄƅƆƇƈƉƊƋƌƍƎƏƐ';
+ $find = 'Ņ';
+ $result = Multibyte::strpos($string, $find);
+ $expected = 24;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ƑƒƓƔƕƖƗƘƙƚƛƜƝƞƟƠơƢƣƤƥƦƧƨƩƪƫƬƭƮƯưƱƲƳƴƵƶƷƸƹƺƻƼƽƾƿǀǁǂǃDŽDždžLJLjljNJNjnjǍǎǏǐǑǒǓǔǕǖǗǘǙǚǛǜǝǞǟǠǡǢǣǤǥǦǧǨǩǪǫǬǭǮǯǰDZDzdzǴ';
+ $find = 'Ƹ';
+ $result = Multibyte::strpos($string, $find);
+ $expected = 39;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ƑƒƓƔƕƖƗƘƙƚƛƜƝƞƟƠơƢƣƤƥƦƧƨƩƪƫƬƭƮƯưƱƲƳƴƵƶƷƸƹƺƻƼƽƾƿǀǁǂǃDŽDždžLJLjljNJNjnjǍǎǏǐǑǒǓǔǕǖǗǘǙǚǛǜǝǞǟǠǡǢǣǤǥǦǧǨǩǪǫǬǭǮǯǰDZDzdzǴ';
+ $find = 'ƹ';
+ $result = Multibyte::strpos($string, $find);
+ $expected = 40;
+ $this->assertEqual($result, $expected);
+
+ $string = 'əɚɛɜɝɞɟɠɡɢɣɤɥɦɧɨɩɪɫɬɭɮɯɰɱɲɳɴɵɶɷɸɹɺɻɼɽɾɿʀʁʂʃʄʅʆʇʈʉʊʋʌʍʎʏʐʑʒʓʔʕʖʗʘʙʚʛʜʝʞʟʠʡʢʣʤʥʦʧʨʩʪʫʬʭʮʯʰʱʲʳʴʵʶʷʸʹʺʻʼ';
+ $find = 'ʀ';
+ $result = Multibyte::strpos($string, $find);
+ $expected = 39;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ЀЁЂЃЄЅІЇЈЉЊЋЌЍЎЏАБВГДЕЖЗИЙКЛ';
+ $find = 'Ї';
+ $result = Multibyte::strpos($string, $find);
+ $expected = 7;
+ $this->assertEqual($result, $expected);
+
+ $string = 'МНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыь';
+ $find = 'Р';
+ $result = Multibyte::strpos($string, $find);
+ $expected = 4;
+ $this->assertEqual($result, $expected);
+
+ $string = 'МНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыь';
+ $find = 'р';
+ $result = Multibyte::strpos($string, $find, 5);
+ $expected = 36;
+ $this->assertEqual($result, $expected);
+
+ $string = 'فقكلمنهوىيًٌٍَُ';
+ $find = 'ن';
+ $result = Multibyte::strpos($string, $find);
+ $expected = 5;
+ $this->assertEqual($result, $expected);
+
+ $string = '✰✱✲✳✴✵✶✷✸✹✺✻✼✽✾✿❀❁❂❃❄❅❆❇❈❉❊❋❌❍❎❏❐❑❒❓❔❕❖❗❘❙❚❛❜❝❞';
+ $find = '✿';
+ $result = Multibyte::strpos($string, $find);
+ $expected = 15;
+ $this->assertEqual($result, $expected);
+
+ $string = '⺀⺁⺂⺃⺄⺅⺆⺇⺈⺉⺊⺋⺌⺍⺎⺏⺐⺑⺒⺓⺔⺕⺖⺗⺘⺙⺛⺜⺝⺞⺟⺠⺡⺢⺣⺤⺥⺦⺧⺨⺩⺪⺫⺬⺭⺮⺯⺰⺱⺲⺳⺴⺵⺶⺷⺸⺹⺺⺻⺼⺽⺾⺿⻀⻁⻂⻃⻄⻅⻆⻇⻈⻉⻊⻋⻌⻍⻎⻏⻐⻑⻒⻓⻔⻕⻖⻗⻘⻙⻚⻛⻜⻝⻞⻟⻠';
+ $find = '⺐';
+ $result = Multibyte::strpos($string, $find);
+ $expected = 16;
+ $this->assertEqual($result, $expected);
+
+ $string = '⽅⽆⽇⽈⽉⽊⽋⽌⽍⽎⽏⽐⽑⽒⽓⽔⽕⽖⽗⽘⽙⽚⽛⽜⽝⽞⽟⽠⽡⽢⽣⽤⽥⽦⽧⽨⽩⽪⽫⽬⽭⽮⽯⽰⽱⽲⽳⽴⽵⽶⽷⽸⽹⽺⽻⽼⽽⽾⽿';
+ $find = '⽤';
+ $result = Multibyte::strpos($string, $find);
+ $expected = 31;
+ $this->assertEqual($result, $expected);
+
+ $string = '눡눢눣눤눥눦눧눨눩눪눫눬눭눮눯눰눱눲눳눴눵눶눷눸눹눺눻눼눽눾눿뉀뉁뉂뉃뉄뉅뉆뉇뉈뉉뉊뉋뉌뉍뉎뉏뉐뉑뉒뉓뉔뉕뉖뉗뉘뉙뉚뉛뉜뉝뉞뉟뉠뉡뉢뉣뉤뉥뉦뉧뉨뉩뉪뉫뉬뉭뉮뉯뉰뉱뉲뉳뉴뉵뉶뉷뉸뉹뉺뉻뉼뉽뉾뉿늀늁늂늃늄';
+ $find = '눻';
+ $result = Multibyte::strpos($string, $find);
+ $expected = 26;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ﹰﹱﹲﹳﹴﹶﹷﹸﹹﹺﹻﹼﹽﹾﹿﺀﺁﺂﺃﺄﺅﺆﺇﺈﺉﺊﺋﺌﺍﺎﺏﺐﺑﺒﺓﺔﺕﺖﺗﺘﺙﺚﺛﺜﺝﺞﺟﺠﺡﺢﺣﺤﺥﺦﺧﺨﺩﺪﺫﺬﺭﺮﺯﺰ';
+ $find = 'ﺞ';
+ $result = Multibyte::strpos($string, $find);
+ $expected = 46;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ﺱﺲﺳﺴﺵﺶﺷﺸﺹﺺﺻﺼﺽﺾﺿﻀﻁﻂﻃﻄﻅﻆﻇﻈﻉﻊﻋﻌﻍﻎﻏﻐﻑﻒﻓﻔﻕﻖﻗﻘﻙﻚﻛﻜﻝﻞﻟﻠﻡﻢﻣﻤﻥﻦﻧﻨﻩﻪﻫﻬﻭﻮﻯﻰﻱﻲﻳﻴﻵﻶﻷﻸﻹﻺﻻﻼ';
+ $find = 'ﻞ';
+ $result = Multibyte::strpos($string, $find);
+ $expected = 45;
+ $this->assertEqual($result, $expected);
+
+ $string = 'abcdefghijklmnopqrstuvwxyz';
+ $find = 'k';
+ $result = Multibyte::strpos($string, $find);
+ $expected = 10;
+ $this->assertEqual($result, $expected);
+
+ $string = 'abcdefghijklmnopqrstuvwxyz';
+ $find = 'k';
+ $result = Multibyte::strpos($string, $find);
+ $expected = 10;
+ $this->assertEqual($result, $expected);
+
+ $string = '。「」、・ヲァィゥェォャュョッーアイウエオカキク';
+ $find = 'ア';
+ $result = Multibyte::strpos($string, $find);
+ $expected = 16;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン゙';
+ $find = 'ハ';
+ $result = Multibyte::strpos($string, $find);
+ $expected = 17;
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ĥēĺļŏ, Ŵőřļď!';
+ $find = 'ő';
+ $result = Multibyte::strpos($string, $find);
+ $expected = 8;
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ĥēĺļŏ, Ŵőřļď!';
+ $find = 'ő';
+ $result = Multibyte::strpos($string, $find);
+ $expected = 8;
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ĥēĺļŏ, Ŵőřļď!';
+ $find = 'őř';
+ $result = Multibyte::strpos($string, $find);
+ $expected = 8;
+ $this->assertEqual($result, $expected);
+
+ $string = 'Hello, World!';
+ $find = 'o';
+ $result = Multibyte::strpos($string, $find);
+ $expected = 4;
+ $this->assertEqual($result, $expected);
+
+ $string = 'Hello, World!';
+ $find = 'o';
+ $result = Multibyte::strpos($string, $find, 5);
+ $expected = 8;
+ $this->assertEqual($result, $expected);
+
+ $string = 'čini';
+ $find = 'n';
+ $result = Multibyte::strpos($string, $find);
+ $expected = 2;
+ $this->assertEqual($result, $expected);
+
+ $string = 'čini';
+ $find = 'n';
+ $result = Multibyte::strpos($string, $find);
+ $expected = 2;
+ $this->assertEqual($result, $expected);
+
+ $string = 'moći';
+ $find = 'ć';
+ $result = Multibyte::strpos($string, $find);
+ $expected = 2;
+ $this->assertEqual($result, $expected);
+
+ $string = 'moći';
+ $find = 'ć';
+ $result = Multibyte::strpos($string, $find);
+ $expected = 2;
+ $this->assertEqual($result, $expected);
+
+ $string = 'državni';
+ $find = 'ž';
+ $result = Multibyte::strpos($string, $find);
+ $expected = 2;
+ $this->assertEqual($result, $expected);
+
+ $string = '把百度设为首页';
+ $find = '设';
+ $result = Multibyte::strpos($string, $find);
+ $expected = 3;
+ $this->assertEqual($result, $expected);
+
+ $string = '一二三周永龍';
+ $find = '周';
+ $result = Multibyte::strpos($string, $find);
+ $expected = 3;
+ $this->assertEqual($result, $expected);
+
+ $string = '一二三周永龍';
+ $find = '一周';
+ $result = Multibyte::strpos($string, $find);
+ $expected = false;
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testUsingMbStrrchr method
+ *
+ * @access public
+ * @return void
+ */
+ function testUsingMbStrrchr() {
+ $string = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
+ $find = 'F';
+ $result = mb_strrchr($string, $find);
+ $expected = 'FGHIJKLMNOPQRSTUVWXYZ0123456789';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
+ $find = 'F';
+ $result = mb_strrchr($string, $find, true);
+ $expected = 'ABCDE';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞ';
+ $find = 'Å';
+ $result = mb_strrchr($string, $find);
+ $expected = 'ÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞ';
+ $find = 'Å';
+ $result = mb_strrchr($string, $find, true);
+ $expected = 'ÀÁÂÃÄ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĀĂĄĆĈĊČĎĐĒĔĖĘĚĜĞĠĢĤĦĨĪĬĮIJĴĶĹĻĽĿŁŃŅŇŊŌŎŐŒŔŖŘŚŜŞŠŢŤŦŨŪŬŮŰŲŴŶŹŻŽ';
+ $find = 'Ċ';
+ $result = mb_strrchr($string, $find);
+ $expected = 'ĊČĎĐĒĔĖĘĚĜĞĠĢĤĦĨĪĬĮIJĴĶĹĻĽĿŁŃŅŇŊŌŎŐŒŔŖŘŚŜŞŠŢŤŦŨŪŬŮŰŲŴŶŹŻŽ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĀĂĄĆĈĊČĎĐĒĔĖĘĚĜĞĠĢĤĦĨĪĬĮIJĴĶĹĻĽĿŁŃŅŇŊŌŎŐŒŔŖŘŚŜŞŠŢŤŦŨŪŬŮŰŲŴŶŹŻŽ';
+ $find = 'Ċ';
+ $result = mb_strrchr($string, $find, true);
+ $expected = 'ĀĂĄĆĈ';
+ $this->assertEqual($result, $expected);
+
+ $string = '!"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~';
+ $find = 'F';
+ $result = mb_strrchr($string, $find);
+ $expected = 'FGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~';
+ $this->assertEqual($result, $expected);
+
+ $string = '!"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~';
+ $find = 'F';
+ $result = mb_strrchr($string, $find, true);
+ $expected = '!"#$%&\'()*+,-./0123456789:;<=>?@ABCDE';
+ $this->assertEqual($result, $expected);
+
+ $string = '¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈ';
+ $find = 'µ';
+ $result = mb_strrchr($string, $find);
+ $expected = 'µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈ';
+ $this->assertEqual($result, $expected);
+
+ $string = '¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈ';
+ $find = 'µ';
+ $result = mb_strrchr($string, $find, true);
+ $expected = '¡¢£¤¥¦§¨©ª«¬®¯°±²³´';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿĀāĂ㥹ĆćĈĉĊċČčĎďĐđĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪīĬ';
+ $find = 'Þ';
+ $result = mb_strrchr($string, $find);
+ $expected = 'Þßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿĀāĂ㥹ĆćĈĉĊċČčĎďĐđĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪīĬ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿĀāĂ㥹ĆćĈĉĊċČčĎďĐđĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪīĬ';
+ $find = 'Þ';
+ $result = mb_strrchr($string, $find, true);
+ $expected = 'ÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĭĮįİıIJijĴĵĶķĸĹĺĻļĽľĿŀŁłŃńŅņŇňʼnŊŋŌōŎŏŐőŒœŔŕŖŗŘřŚśŜŝŞşŠšŢţŤťŦŧŨũŪūŬŭŮůŰűŲųŴŵŶŷŸŹźŻżŽžſƀƁƂƃƄƅƆƇƈƉƊƋƌƍƎƏƐ';
+ $find = 'Ņ';
+ $result = mb_strrchr($string, $find);
+ $expected = 'ŅņŇňʼnŊŋŌōŎŏŐőŒœŔŕŖŗŘřŚśŜŝŞşŠšŢţŤťŦŧŨũŪūŬŭŮůŰűŲųŴŵŶŷŸŹźŻżŽžſƀƁƂƃƄƅƆƇƈƉƊƋƌƍƎƏƐ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĭĮįİıIJijĴĵĶķĸĹĺĻļĽľĿŀŁłŃńŅņŇňʼnŊŋŌōŎŏŐőŒœŔŕŖŗŘřŚśŜŝŞşŠšŢţŤťŦŧŨũŪūŬŭŮůŰűŲųŴŵŶŷŸŹźŻżŽžſƀƁƂƃƄƅƆƇƈƉƊƋƌƍƎƏƐ';
+ $find = 'Ņ';
+ $result = mb_strrchr($string, $find, true);
+ $expected = 'ĭĮįİıIJijĴĵĶķĸĹĺĻļĽľĿŀŁłŃń';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ƑƒƓƔƕƖƗƘƙƚƛƜƝƞƟƠơƢƣƤƥƦƧƨƩƪƫƬƭƮƯưƱƲƳƴƵƶƷƸƹƺƻƼƽƾƿǀǁǂǃDŽDždžLJLjljNJNjnjǍǎǏǐǑǒǓǔǕǖǗǘǙǚǛǜǝǞǟǠǡǢǣǤǥǦǧǨǩǪǫǬǭǮǯǰDZDzdzǴ';
+ $find = 'Ƹ';
+ $result = mb_strrchr($string, $find);
+ $expected = 'ƸƹƺƻƼƽƾƿǀǁǂǃDŽDždžLJLjljNJNjnjǍǎǏǐǑǒǓǔǕǖǗǘǙǚǛǜǝǞǟǠǡǢǣǤǥǦǧǨǩǪǫǬǭǮǯǰDZDzdzǴ';
+ $this->assertEqual($result, $expected);
+
+ $find = 'Ƹ';
+ $result = mb_strrchr($string, $find, true);
+ $expected = 'ƑƒƓƔƕƖƗƘƙƚƛƜƝƞƟƠơƢƣƤƥƦƧƨƩƪƫƬƭƮƯưƱƲƳƴƵƶƷ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'əɚɛɜɝɞɟɠɡɢɣɤɥɦɧɨɩɪɫɬɭɮɯɰɱɲɳɴɵɶɷɸɹɺɻɼɽɾɿʀʁʂʃʄʅʆʇʈʉʊʋʌʍʎʏʐʑʒʓʔʕʖʗʘʙʚʛʜʝʞʟʠʡʢʣʤʥʦʧʨʩʪʫʬʭʮʯʰʱʲʳʴʵʶʷʸʹʺʻʼ';
+ $find = 'ʀ';
+ $result = mb_strrchr($string, $find);
+ $expected = 'ʀʁʂʃʄʅʆʇʈʉʊʋʌʍʎʏʐʑʒʓʔʕʖʗʘʙʚʛʜʝʞʟʠʡʢʣʤʥʦʧʨʩʪʫʬʭʮʯʰʱʲʳʴʵʶʷʸʹʺʻʼ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'əɚɛɜɝɞɟɠɡɢɣɤɥɦɧɨɩɪɫɬɭɮɯɰɱɲɳɴɵɶɷɸɹɺɻɼɽɾɿʀʁʂʃʄʅʆʇʈʉʊʋʌʍʎʏʐʑʒʓʔʕʖʗʘʙʚʛʜʝʞʟʠʡʢʣʤʥʦʧʨʩʪʫʬʭʮʯʰʱʲʳʴʵʶʷʸʹʺʻʼ';
+ $find = 'ʀ';
+ $result = mb_strrchr($string, $find, true);
+ $expected = 'əɚɛɜɝɞɟɠɡɢɣɤɥɦɧɨɩɪɫɬɭɮɯɰɱɲɳɴɵɶɷɸɹɺɻɼɽɾɿ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ЀЁЂЃЄЅІЇЈЉЊЋЌЍЎЏАБВГДЕЖЗИЙКЛ';
+ $find = 'Ї';
+ $result = mb_strrchr($string, $find);
+ $expected = 'ЇЈЉЊЋЌЍЎЏАБВГДЕЖЗИЙКЛ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ЀЁЂЃЄЅІЇЈЉЊЋЌЍЎЏАБВГДЕЖЗИЙКЛ';
+ $find = 'Ї';
+ $result = mb_strrchr($string, $find, true);
+ $expected = 'ЀЁЂЃЄЅІ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'МНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыь';
+ $find = 'Р';
+ $result = mb_strrchr($string, $find);
+ $expected = 'РСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыь';
+ $this->assertEqual($result, $expected);
+
+ $string = 'МНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыь';
+ $find = 'Р';
+ $result = mb_strrchr($string, $find, true);
+ $expected = 'МНОП';
+ $this->assertEqual($result, $expected);
+
+ $string = 'فقكلمنهوىيًٌٍَُ';
+ $find = 'ن';
+ $result = mb_strrchr($string, $find);
+ $expected = 'نهوىيًٌٍَُ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'فقكلمنهوىيًٌٍَُ';
+ $find = 'ن';
+ $result = mb_strrchr($string, $find, true);
+ $expected = 'فقكلم';
+ $this->assertEqual($result, $expected);
+
+ $string = '✰✱✲✳✴✵✶✷✸✹✺✻✼✽✾✿❀❁❂❃❄❅❆❇❈❉❊❋❌❍❎❏❐❑❒❓❔❕❖❗❘❙❚❛❜❝❞';
+ $find = '✿';
+ $result = mb_strrchr($string, $find);
+ $expected = '✿❀❁❂❃❄❅❆❇❈❉❊❋❌❍❎❏❐❑❒❓❔❕❖❗❘❙❚❛❜❝❞';
+ $this->assertEqual($result, $expected);
+
+ $string = '✰✱✲✳✴✵✶✷✸✹✺✻✼✽✾✿❀❁❂❃❄❅❆❇❈❉❊❋❌❍❎❏❐❑❒❓❔❕❖❗❘❙❚❛❜❝❞';
+ $find = '✿';
+ $result = mb_strrchr($string, $find, true);
+ $expected = '✰✱✲✳✴✵✶✷✸✹✺✻✼✽✾';
+ $this->assertEqual($result, $expected);
+
+ $string = '⺀⺁⺂⺃⺄⺅⺆⺇⺈⺉⺊⺋⺌⺍⺎⺏⺐⺑⺒⺓⺔⺕⺖⺗⺘⺙⺛⺜⺝⺞⺟⺠⺡⺢⺣⺤⺥⺦⺧⺨⺩⺪⺫⺬⺭⺮⺯⺰⺱⺲⺳⺴⺵⺶⺷⺸⺹⺺⺻⺼⺽⺾⺿⻀⻁⻂⻃⻄⻅⻆⻇⻈⻉⻊⻋⻌⻍⻎⻏⻐⻑⻒⻓⻔⻕⻖⻗⻘⻙⻚⻛⻜⻝⻞⻟⻠';
+ $find = '⺐';
+ $result = mb_strrchr($string, $find);
+ $expected = '⺐⺑⺒⺓⺔⺕⺖⺗⺘⺙⺛⺜⺝⺞⺟⺠⺡⺢⺣⺤⺥⺦⺧⺨⺩⺪⺫⺬⺭⺮⺯⺰⺱⺲⺳⺴⺵⺶⺷⺸⺹⺺⺻⺼⺽⺾⺿⻀⻁⻂⻃⻄⻅⻆⻇⻈⻉⻊⻋⻌⻍⻎⻏⻐⻑⻒⻓⻔⻕⻖⻗⻘⻙⻚⻛⻜⻝⻞⻟⻠';
+ $this->assertEqual($result, $expected);
+
+ $string = '⺀⺁⺂⺃⺄⺅⺆⺇⺈⺉⺊⺋⺌⺍⺎⺏⺐⺑⺒⺓⺔⺕⺖⺗⺘⺙⺛⺜⺝⺞⺟⺠⺡⺢⺣⺤⺥⺦⺧⺨⺩⺪⺫⺬⺭⺮⺯⺰⺱⺲⺳⺴⺵⺶⺷⺸⺹⺺⺻⺼⺽⺾⺿⻀⻁⻂⻃⻄⻅⻆⻇⻈⻉⻊⻋⻌⻍⻎⻏⻐⻑⻒⻓⻔⻕⻖⻗⻘⻙⻚⻛⻜⻝⻞⻟⻠';
+ $find = '⺐';
+ $result = mb_strrchr($string, $find, true);
+ $expected = '⺀⺁⺂⺃⺄⺅⺆⺇⺈⺉⺊⺋⺌⺍⺎⺏';
+ $this->assertEqual($result, $expected);
+
+ $string = '⽅⽆⽇⽈⽉⽊⽋⽌⽍⽎⽏⽐⽑⽒⽓⽔⽕⽖⽗⽘⽙⽚⽛⽜⽝⽞⽟⽠⽡⽢⽣⽤⽥⽦⽧⽨⽩⽪⽫⽬⽭⽮⽯⽰⽱⽲⽳⽴⽵⽶⽷⽸⽹⽺⽻⽼⽽⽾⽿';
+ $find = '⽤';
+ $result = mb_strrchr($string, $find);
+ $expected = '⽤⽥⽦⽧⽨⽩⽪⽫⽬⽭⽮⽯⽰⽱⽲⽳⽴⽵⽶⽷⽸⽹⽺⽻⽼⽽⽾⽿';
+ $this->assertEqual($result, $expected);
+
+ $string = '⽅⽆⽇⽈⽉⽊⽋⽌⽍⽎⽏⽐⽑⽒⽓⽔⽕⽖⽗⽘⽙⽚⽛⽜⽝⽞⽟⽠⽡⽢⽣⽤⽥⽦⽧⽨⽩⽪⽫⽬⽭⽮⽯⽰⽱⽲⽳⽴⽵⽶⽷⽸⽹⽺⽻⽼⽽⽾⽿';
+ $find = '⽤';
+ $result = mb_strrchr($string, $find, true);
+ $expected = '⽅⽆⽇⽈⽉⽊⽋⽌⽍⽎⽏⽐⽑⽒⽓⽔⽕⽖⽗⽘⽙⽚⽛⽜⽝⽞⽟⽠⽡⽢⽣';
+ $this->assertEqual($result, $expected);
+
+ $string = '눡눢눣눤눥눦눧눨눩눪눫눬눭눮눯눰눱눲눳눴눵눶눷눸눹눺눻눼눽눾눿뉀뉁뉂뉃뉄뉅뉆뉇뉈뉉뉊뉋뉌뉍뉎뉏뉐뉑뉒뉓뉔뉕뉖뉗뉘뉙뉚뉛뉜뉝뉞뉟뉠뉡뉢뉣뉤뉥뉦뉧뉨뉩뉪뉫뉬뉭뉮뉯뉰뉱뉲뉳뉴뉵뉶뉷뉸뉹뉺뉻뉼뉽뉾뉿늀늁늂늃늄';
+ $find = '눻';
+ $result = mb_strrchr($string, $find);
+ $expected = '눻눼눽눾눿뉀뉁뉂뉃뉄뉅뉆뉇뉈뉉뉊뉋뉌뉍뉎뉏뉐뉑뉒뉓뉔뉕뉖뉗뉘뉙뉚뉛뉜뉝뉞뉟뉠뉡뉢뉣뉤뉥뉦뉧뉨뉩뉪뉫뉬뉭뉮뉯뉰뉱뉲뉳뉴뉵뉶뉷뉸뉹뉺뉻뉼뉽뉾뉿늀늁늂늃늄';
+ $this->assertEqual($result, $expected);
+
+ $string = '눡눢눣눤눥눦눧눨눩눪눫눬눭눮눯눰눱눲눳눴눵눶눷눸눹눺눻눼눽눾눿뉀뉁뉂뉃뉄뉅뉆뉇뉈뉉뉊뉋뉌뉍뉎뉏뉐뉑뉒뉓뉔뉕뉖뉗뉘뉙뉚뉛뉜뉝뉞뉟뉠뉡뉢뉣뉤뉥뉦뉧뉨뉩뉪뉫뉬뉭뉮뉯뉰뉱뉲뉳뉴뉵뉶뉷뉸뉹뉺뉻뉼뉽뉾뉿늀늁늂늃늄';
+ $find = '눻';
+ $result = mb_strrchr($string, $find, true);
+ $expected = '눡눢눣눤눥눦눧눨눩눪눫눬눭눮눯눰눱눲눳눴눵눶눷눸눹눺';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ﹰﹱﹲﹳﹴﹶﹷﹸﹹﹺﹻﹼﹽﹾﹿﺀﺁﺂﺃﺄﺅﺆﺇﺈﺉﺊﺋﺌﺍﺎﺏﺐﺑﺒﺓﺔﺕﺖﺗﺘﺙﺚﺛﺜﺝﺞﺟﺠﺡﺢﺣﺤﺥﺦﺧﺨﺩﺪﺫﺬﺭﺮﺯﺰ';
+ $find = 'ﺞ';
+ $result = mb_strrchr($string, $find);
+ $expected = 'ﺞﺟﺠﺡﺢﺣﺤﺥﺦﺧﺨﺩﺪﺫﺬﺭﺮﺯﺰ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ﹰﹱﹲﹳﹴﹶﹷﹸﹹﹺﹻﹼﹽﹾﹿﺀﺁﺂﺃﺄﺅﺆﺇﺈﺉﺊﺋﺌﺍﺎﺏﺐﺑﺒﺓﺔﺕﺖﺗﺘﺙﺚﺛﺜﺝﺞﺟﺠﺡﺢﺣﺤﺥﺦﺧﺨﺩﺪﺫﺬﺭﺮﺯﺰ';
+ $find = 'ﺞ';
+ $result = mb_strrchr($string, $find, true);
+ $expected = 'ﹰﹱﹲﹳﹴﹶﹷﹸﹹﹺﹻﹼﹽﹾﹿﺀﺁﺂﺃﺄﺅﺆﺇﺈﺉﺊﺋﺌﺍﺎﺏﺐﺑﺒﺓﺔﺕﺖﺗﺘﺙﺚﺛﺜﺝ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ﺱﺲﺳﺴﺵﺶﺷﺸﺹﺺﺻﺼﺽﺾﺿﻀﻁﻂﻃﻄﻅﻆﻇﻈﻉﻊﻋﻌﻍﻎﻏﻐﻑﻒﻓﻔﻕﻖﻗﻘﻙﻚﻛﻜﻝﻞﻟﻠﻡﻢﻣﻤﻥﻦﻧﻨﻩﻪﻫﻬﻭﻮﻯﻰﻱﻲﻳﻴﻵﻶﻷﻸﻹﻺﻻﻼ';
+ $find = 'ﻞ';
+ $result = mb_strrchr($string, $find);
+ $expected = 'ﻞﻟﻠﻡﻢﻣﻤﻥﻦﻧﻨﻩﻪﻫﻬﻭﻮﻯﻰﻱﻲﻳﻴﻵﻶﻷﻸﻹﻺﻻﻼ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ﺱﺲﺳﺴﺵﺶﺷﺸﺹﺺﺻﺼﺽﺾﺿﻀﻁﻂﻃﻄﻅﻆﻇﻈﻉﻊﻋﻌﻍﻎﻏﻐﻑﻒﻓﻔﻕﻖﻗﻘﻙﻚﻛﻜﻝﻞﻟﻠﻡﻢﻣﻤﻥﻦﻧﻨﻩﻪﻫﻬﻭﻮﻯﻰﻱﻲﻳﻴﻵﻶﻷﻸﻹﻺﻻﻼ';
+ $find = 'ﻞ';
+ $result = mb_strrchr($string, $find, true);
+ $expected = 'ﺱﺲﺳﺴﺵﺶﺷﺸﺹﺺﺻﺼﺽﺾﺿﻀﻁﻂﻃﻄﻅﻆﻇﻈﻉﻊﻋﻌﻍﻎﻏﻐﻑﻒﻓﻔﻕﻖﻗﻘﻙﻚﻛﻜﻝ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'abcdefghijklmnopqrstuvwxyz';
+ $find = 'k';
+ $result = mb_strrchr($string, $find);
+ $expected = 'klmnopqrstuvwxyz';
+ $this->assertEqual($result, $expected);
+
+ $string = 'abcdefghijklmnopqrstuvwxyz';
+ $find = 'k';
+ $result = mb_strrchr($string, $find, true);
+ $expected = 'abcdefghij';
+ $this->assertEqual($result, $expected);
+
+ $string = '。「」、・ヲァィゥェォャュョッーアイウエオカキク';
+ $find = 'ア';
+ $result = mb_strrchr($string, $find);
+ $expected = 'アイウエオカキク';
+ $this->assertEqual($result, $expected);
+
+ $string = '。「」、・ヲァィゥェォャュョッーアイウエオカキク';
+ $find = 'ア';
+ $result = mb_strrchr($string, $find, true);
+ $expected = '。「」、・ヲァィゥェォャュョッー';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン゙';
+ $find = 'ハ';
+ $result = mb_strrchr($string, $find);
+ $expected = 'ハヒフヘホマミムメモヤユヨラリルレロワン゙';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン゙';
+ $find = 'ハ';
+ $result = mb_strrchr($string, $find, true);
+ $expected = 'ケコサシスセソタチツテトナニヌネノ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ĥēĺļŏ, Ŵőřļď!';
+ $find = 'ő';
+ $result = mb_strrchr($string, $find);
+ $expected = 'őřļď!';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ĥēĺļŏ, Ŵőřļď!';
+ $find = 'ő';
+ $result = mb_strrchr($string, $find, true);
+ $expected = 'Ĥēĺļŏ, Ŵ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Hello, World!';
+ $find = 'o';
+ $result = mb_strrchr($string, $find);
+ $expected = 'orld!';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Hello, World!';
+ $find = 'o';
+ $result = mb_strrchr($string, $find, true);
+ $expected = 'Hello, W';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Hello, World!';
+ $find = 'Wo';
+ $result = mb_strrchr($string, $find);
+ $expected = 'World!';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Hello, World!';
+ $find = 'Wo';
+ $result = mb_strrchr($string, $find, true);
+ $expected = 'Hello, ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Hello, World!';
+ $find = 'll';
+ $result = mb_strrchr($string, $find);
+ $expected = 'llo, World!';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Hello, World!';
+ $find = 'll';
+ $result = mb_strrchr($string, $find, true);
+ $expected = 'He';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Hello, World!';
+ $find = 'rld';
+ $result = mb_strrchr($string, $find);
+ $expected = 'rld!';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Hello, World!';
+ $find = 'rld';
+ $result = mb_strrchr($string, $find, true);
+ $expected = 'Hello, Wo';
+ $this->assertEqual($result, $expected);
+
+ $string = 'čini';
+ $find = 'n';
+ $result = mb_strrchr($string, $find);
+ $expected = 'ni';
+ $this->assertEqual($result, $expected);
+
+ $string = 'čini';
+ $find = 'n';
+ $result = mb_strrchr($string, $find, true);
+ $expected = 'či';
+ $this->assertEqual($result, $expected);
+
+ $string = 'moći';
+ $find = 'ć';
+ $result = mb_strrchr($string, $find);
+ $expected = 'ći';
+ $this->assertEqual($result, $expected);
+
+ $string = 'moći';
+ $find = 'ć';
+ $result = mb_strrchr($string, $find, true);
+ $expected = 'mo';
+ $this->assertEqual($result, $expected);
+
+ $string = 'državni';
+ $find = 'ž';
+ $result = mb_strrchr($string, $find);
+ $expected = 'žavni';
+ $this->assertEqual($result, $expected);
+
+ $string = 'državni';
+ $find = 'ž';
+ $result = mb_strrchr($string, $find, true);
+ $expected = 'dr';
+ $this->assertEqual($result, $expected);
+
+ $string = '把百度设为首页';
+ $find = '设';
+ $result = mb_strrchr($string, $find);
+ $expected = '设为首页';
+ $this->assertEqual($result, $expected);
+
+ $string = '把百度设为首页';
+ $find = '设';
+ $result = mb_strrchr($string, $find, true);
+ $expected = '把百度';
+ $this->assertEqual($result, $expected);
+
+ $string = '一二三周永龍';
+ $find = '周';
+ $result = mb_strrchr($string, $find);
+ $expected = '周永龍';
+ $this->assertEqual($result, $expected);
+
+ $string = '一二三周永龍';
+ $find = '周';
+ $result = mb_strrchr($string, $find, true);
+ $expected = '一二三';
+ $this->assertEqual($result, $expected);
+
+ $string = '一二三周永龍';
+ $find = '周龍';
+ $result = mb_strrchr($string, $find, true);
+ $expected = false;
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testMultibyteStrrchr method
+ *
+ * @access public
+ * @return void
+ */
+ function testMultibyteStrrchr() {
+ $string = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
+ $find = 'F';
+ $result = Multibyte::strrchr($string, $find);
+ $expected = 'FGHIJKLMNOPQRSTUVWXYZ0123456789';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
+ $find = 'F';
+ $result = Multibyte::strrchr($string, $find, true);
+ $expected = 'ABCDE';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞ';
+ $find = 'Å';
+ $result = Multibyte::strrchr($string, $find);
+ $expected = 'ÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞ';
+ $find = 'Å';
+ $result = Multibyte::strrchr($string, $find, true);
+ $expected = 'ÀÁÂÃÄ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĀĂĄĆĈĊČĎĐĒĔĖĘĚĜĞĠĢĤĦĨĪĬĮIJĴĶĹĻĽĿŁŃŅŇŊŌŎŐŒŔŖŘŚŜŞŠŢŤŦŨŪŬŮŰŲŴŶŹŻŽ';
+ $find = 'Ċ';
+ $result = Multibyte::strrchr($string, $find);
+ $expected = 'ĊČĎĐĒĔĖĘĚĜĞĠĢĤĦĨĪĬĮIJĴĶĹĻĽĿŁŃŅŇŊŌŎŐŒŔŖŘŚŜŞŠŢŤŦŨŪŬŮŰŲŴŶŹŻŽ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĀĂĄĆĈĊČĎĐĒĔĖĘĚĜĞĠĢĤĦĨĪĬĮIJĴĶĹĻĽĿŁŃŅŇŊŌŎŐŒŔŖŘŚŜŞŠŢŤŦŨŪŬŮŰŲŴŶŹŻŽ';
+ $find = 'Ċ';
+ $result = Multibyte::strrchr($string, $find, true);
+ $expected = 'ĀĂĄĆĈ';
+ $this->assertEqual($result, $expected);
+
+ $string = '!"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~';
+ $find = 'F';
+ $result = Multibyte::strrchr($string, $find);
+ $expected = 'FGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~';
+ $this->assertEqual($result, $expected);
+
+ $string = '!"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~';
+ $find = 'F';
+ $result = Multibyte::strrchr($string, $find, true);
+ $expected = '!"#$%&\'()*+,-./0123456789:;<=>?@ABCDE';
+ $this->assertEqual($result, $expected);
+
+ $string = '¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈ';
+ $find = 'µ';
+ $result = Multibyte::strrchr($string, $find);
+ $expected = 'µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈ';
+ $this->assertEqual($result, $expected);
+
+ $string = '¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈ';
+ $find = 'µ';
+ $result = Multibyte::strrchr($string, $find, true);
+ $expected = '¡¢£¤¥¦§¨©ª«¬®¯°±²³´';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿĀāĂ㥹ĆćĈĉĊċČčĎďĐđĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪīĬ';
+ $find = 'Þ';
+ $result = Multibyte::strrchr($string, $find);
+ $expected = 'Þßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿĀāĂ㥹ĆćĈĉĊċČčĎďĐđĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪīĬ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿĀāĂ㥹ĆćĈĉĊċČčĎďĐđĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪīĬ';
+ $find = 'Þ';
+ $result = Multibyte::strrchr($string, $find, true);
+ $expected = 'ÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĭĮįİıIJijĴĵĶķĸĹĺĻļĽľĿŀŁłŃńŅņŇňʼnŊŋŌōŎŏŐőŒœŔŕŖŗŘřŚśŜŝŞşŠšŢţŤťŦŧŨũŪūŬŭŮůŰűŲųŴŵŶŷŸŹźŻżŽžſƀƁƂƃƄƅƆƇƈƉƊƋƌƍƎƏƐ';
+ $find = 'Ņ';
+ $result = Multibyte::strrchr($string, $find);
+ $expected = 'ŅņŇňʼnŊŋŌōŎŏŐőŒœŔŕŖŗŘřŚśŜŝŞşŠšŢţŤťŦŧŨũŪūŬŭŮůŰűŲųŴŵŶŷŸŹźŻżŽžſƀƁƂƃƄƅƆƇƈƉƊƋƌƍƎƏƐ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĭĮįİıIJijĴĵĶķĸĹĺĻļĽľĿŀŁłŃńŅņŇňʼnŊŋŌōŎŏŐőŒœŔŕŖŗŘřŚśŜŝŞşŠšŢţŤťŦŧŨũŪūŬŭŮůŰűŲųŴŵŶŷŸŹźŻżŽžſƀƁƂƃƄƅƆƇƈƉƊƋƌƍƎƏƐ';
+ $find = 'Ņ';
+ $result = Multibyte::strrchr($string, $find, true);
+ $expected = 'ĭĮįİıIJijĴĵĶķĸĹĺĻļĽľĿŀŁłŃń';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ƑƒƓƔƕƖƗƘƙƚƛƜƝƞƟƠơƢƣƤƥƦƧƨƩƪƫƬƭƮƯưƱƲƳƴƵƶƷƸƹƺƻƼƽƾƿǀǁǂǃDŽDždžLJLjljNJNjnjǍǎǏǐǑǒǓǔǕǖǗǘǙǚǛǜǝǞǟǠǡǢǣǤǥǦǧǨǩǪǫǬǭǮǯǰDZDzdzǴ';
+ $find = 'Ƹ';
+ $result = Multibyte::strrchr($string, $find);
+ $expected = 'ƸƹƺƻƼƽƾƿǀǁǂǃDŽDždžLJLjljNJNjnjǍǎǏǐǑǒǓǔǕǖǗǘǙǚǛǜǝǞǟǠǡǢǣǤǥǦǧǨǩǪǫǬǭǮǯǰDZDzdzǴ';
+ $this->assertEqual($result, $expected);
+
+ $find = 'Ƹ';
+ $result = Multibyte::strrchr($string, $find, true);
+ $expected = 'ƑƒƓƔƕƖƗƘƙƚƛƜƝƞƟƠơƢƣƤƥƦƧƨƩƪƫƬƭƮƯưƱƲƳƴƵƶƷ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'əɚɛɜɝɞɟɠɡɢɣɤɥɦɧɨɩɪɫɬɭɮɯɰɱɲɳɴɵɶɷɸɹɺɻɼɽɾɿʀʁʂʃʄʅʆʇʈʉʊʋʌʍʎʏʐʑʒʓʔʕʖʗʘʙʚʛʜʝʞʟʠʡʢʣʤʥʦʧʨʩʪʫʬʭʮʯʰʱʲʳʴʵʶʷʸʹʺʻʼ';
+ $find = 'ʀ';
+ $result = Multibyte::strrchr($string, $find);
+ $expected = 'ʀʁʂʃʄʅʆʇʈʉʊʋʌʍʎʏʐʑʒʓʔʕʖʗʘʙʚʛʜʝʞʟʠʡʢʣʤʥʦʧʨʩʪʫʬʭʮʯʰʱʲʳʴʵʶʷʸʹʺʻʼ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'əɚɛɜɝɞɟɠɡɢɣɤɥɦɧɨɩɪɫɬɭɮɯɰɱɲɳɴɵɶɷɸɹɺɻɼɽɾɿʀʁʂʃʄʅʆʇʈʉʊʋʌʍʎʏʐʑʒʓʔʕʖʗʘʙʚʛʜʝʞʟʠʡʢʣʤʥʦʧʨʩʪʫʬʭʮʯʰʱʲʳʴʵʶʷʸʹʺʻʼ';
+ $find = 'ʀ';
+ $result = Multibyte::strrchr($string, $find, true);
+ $expected = 'əɚɛɜɝɞɟɠɡɢɣɤɥɦɧɨɩɪɫɬɭɮɯɰɱɲɳɴɵɶɷɸɹɺɻɼɽɾɿ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ЀЁЂЃЄЅІЇЈЉЊЋЌЍЎЏАБВГДЕЖЗИЙКЛ';
+ $find = 'Ї';
+ $result = Multibyte::strrchr($string, $find);
+ $expected = 'ЇЈЉЊЋЌЍЎЏАБВГДЕЖЗИЙКЛ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ЀЁЂЃЄЅІЇЈЉЊЋЌЍЎЏАБВГДЕЖЗИЙКЛ';
+ $find = 'Ї';
+ $result = Multibyte::strrchr($string, $find, true);
+ $expected = 'ЀЁЂЃЄЅІ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'МНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыь';
+ $find = 'Р';
+ $result = Multibyte::strrchr($string, $find);
+ $expected = 'РСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыь';
+ $this->assertEqual($result, $expected);
+
+ $string = 'МНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыь';
+ $find = 'Р';
+ $result = Multibyte::strrchr($string, $find, true);
+ $expected = 'МНОП';
+ $this->assertEqual($result, $expected);
+
+ $string = 'فقكلمنهوىيًٌٍَُ';
+ $find = 'ن';
+ $result = Multibyte::strrchr($string, $find);
+ $expected = 'نهوىيًٌٍَُ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'فقكلمنهوىيًٌٍَُ';
+ $find = 'ن';
+ $result = Multibyte::strrchr($string, $find, true);
+ $expected = 'فقكلم';
+ $this->assertEqual($result, $expected);
+
+ $string = '✰✱✲✳✴✵✶✷✸✹✺✻✼✽✾✿❀❁❂❃❄❅❆❇❈❉❊❋❌❍❎❏❐❑❒❓❔❕❖❗❘❙❚❛❜❝❞';
+ $find = '✿';
+ $result = Multibyte::strrchr($string, $find);
+ $expected = '✿❀❁❂❃❄❅❆❇❈❉❊❋❌❍❎❏❐❑❒❓❔❕❖❗❘❙❚❛❜❝❞';
+ $this->assertEqual($result, $expected);
+
+ $string = '✰✱✲✳✴✵✶✷✸✹✺✻✼✽✾✿❀❁❂❃❄❅❆❇❈❉❊❋❌❍❎❏❐❑❒❓❔❕❖❗❘❙❚❛❜❝❞';
+ $find = '✿';
+ $result = Multibyte::strrchr($string, $find, true);
+ $expected = '✰✱✲✳✴✵✶✷✸✹✺✻✼✽✾';
+ $this->assertEqual($result, $expected);
+
+ $string = '⺀⺁⺂⺃⺄⺅⺆⺇⺈⺉⺊⺋⺌⺍⺎⺏⺐⺑⺒⺓⺔⺕⺖⺗⺘⺙⺛⺜⺝⺞⺟⺠⺡⺢⺣⺤⺥⺦⺧⺨⺩⺪⺫⺬⺭⺮⺯⺰⺱⺲⺳⺴⺵⺶⺷⺸⺹⺺⺻⺼⺽⺾⺿⻀⻁⻂⻃⻄⻅⻆⻇⻈⻉⻊⻋⻌⻍⻎⻏⻐⻑⻒⻓⻔⻕⻖⻗⻘⻙⻚⻛⻜⻝⻞⻟⻠';
+ $find = '⺐';
+ $result = Multibyte::strrchr($string, $find);
+ $expected = '⺐⺑⺒⺓⺔⺕⺖⺗⺘⺙⺛⺜⺝⺞⺟⺠⺡⺢⺣⺤⺥⺦⺧⺨⺩⺪⺫⺬⺭⺮⺯⺰⺱⺲⺳⺴⺵⺶⺷⺸⺹⺺⺻⺼⺽⺾⺿⻀⻁⻂⻃⻄⻅⻆⻇⻈⻉⻊⻋⻌⻍⻎⻏⻐⻑⻒⻓⻔⻕⻖⻗⻘⻙⻚⻛⻜⻝⻞⻟⻠';
+ $this->assertEqual($result, $expected);
+
+ $string = '⺀⺁⺂⺃⺄⺅⺆⺇⺈⺉⺊⺋⺌⺍⺎⺏⺐⺑⺒⺓⺔⺕⺖⺗⺘⺙⺛⺜⺝⺞⺟⺠⺡⺢⺣⺤⺥⺦⺧⺨⺩⺪⺫⺬⺭⺮⺯⺰⺱⺲⺳⺴⺵⺶⺷⺸⺹⺺⺻⺼⺽⺾⺿⻀⻁⻂⻃⻄⻅⻆⻇⻈⻉⻊⻋⻌⻍⻎⻏⻐⻑⻒⻓⻔⻕⻖⻗⻘⻙⻚⻛⻜⻝⻞⻟⻠';
+ $find = '⺐';
+ $result = Multibyte::strrchr($string, $find, true);
+ $expected = '⺀⺁⺂⺃⺄⺅⺆⺇⺈⺉⺊⺋⺌⺍⺎⺏';
+ $this->assertEqual($result, $expected);
+
+ $string = '⽅⽆⽇⽈⽉⽊⽋⽌⽍⽎⽏⽐⽑⽒⽓⽔⽕⽖⽗⽘⽙⽚⽛⽜⽝⽞⽟⽠⽡⽢⽣⽤⽥⽦⽧⽨⽩⽪⽫⽬⽭⽮⽯⽰⽱⽲⽳⽴⽵⽶⽷⽸⽹⽺⽻⽼⽽⽾⽿';
+ $find = '⽤';
+ $result = Multibyte::strrchr($string, $find);
+ $expected = '⽤⽥⽦⽧⽨⽩⽪⽫⽬⽭⽮⽯⽰⽱⽲⽳⽴⽵⽶⽷⽸⽹⽺⽻⽼⽽⽾⽿';
+ $this->assertEqual($result, $expected);
+
+ $string = '⽅⽆⽇⽈⽉⽊⽋⽌⽍⽎⽏⽐⽑⽒⽓⽔⽕⽖⽗⽘⽙⽚⽛⽜⽝⽞⽟⽠⽡⽢⽣⽤⽥⽦⽧⽨⽩⽪⽫⽬⽭⽮⽯⽰⽱⽲⽳⽴⽵⽶⽷⽸⽹⽺⽻⽼⽽⽾⽿';
+ $find = '⽤';
+ $result = Multibyte::strrchr($string, $find, true);
+ $expected = '⽅⽆⽇⽈⽉⽊⽋⽌⽍⽎⽏⽐⽑⽒⽓⽔⽕⽖⽗⽘⽙⽚⽛⽜⽝⽞⽟⽠⽡⽢⽣';
+ $this->assertEqual($result, $expected);
+
+ $string = '눡눢눣눤눥눦눧눨눩눪눫눬눭눮눯눰눱눲눳눴눵눶눷눸눹눺눻눼눽눾눿뉀뉁뉂뉃뉄뉅뉆뉇뉈뉉뉊뉋뉌뉍뉎뉏뉐뉑뉒뉓뉔뉕뉖뉗뉘뉙뉚뉛뉜뉝뉞뉟뉠뉡뉢뉣뉤뉥뉦뉧뉨뉩뉪뉫뉬뉭뉮뉯뉰뉱뉲뉳뉴뉵뉶뉷뉸뉹뉺뉻뉼뉽뉾뉿늀늁늂늃늄';
+ $find = '눻';
+ $result = Multibyte::strrchr($string, $find);
+ $expected = '눻눼눽눾눿뉀뉁뉂뉃뉄뉅뉆뉇뉈뉉뉊뉋뉌뉍뉎뉏뉐뉑뉒뉓뉔뉕뉖뉗뉘뉙뉚뉛뉜뉝뉞뉟뉠뉡뉢뉣뉤뉥뉦뉧뉨뉩뉪뉫뉬뉭뉮뉯뉰뉱뉲뉳뉴뉵뉶뉷뉸뉹뉺뉻뉼뉽뉾뉿늀늁늂늃늄';
+ $this->assertEqual($result, $expected);
+
+ $string = '눡눢눣눤눥눦눧눨눩눪눫눬눭눮눯눰눱눲눳눴눵눶눷눸눹눺눻눼눽눾눿뉀뉁뉂뉃뉄뉅뉆뉇뉈뉉뉊뉋뉌뉍뉎뉏뉐뉑뉒뉓뉔뉕뉖뉗뉘뉙뉚뉛뉜뉝뉞뉟뉠뉡뉢뉣뉤뉥뉦뉧뉨뉩뉪뉫뉬뉭뉮뉯뉰뉱뉲뉳뉴뉵뉶뉷뉸뉹뉺뉻뉼뉽뉾뉿늀늁늂늃늄';
+ $find = '눻';
+ $result = Multibyte::strrchr($string, $find, true);
+ $expected = '눡눢눣눤눥눦눧눨눩눪눫눬눭눮눯눰눱눲눳눴눵눶눷눸눹눺';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ﹰﹱﹲﹳﹴﹶﹷﹸﹹﹺﹻﹼﹽﹾﹿﺀﺁﺂﺃﺄﺅﺆﺇﺈﺉﺊﺋﺌﺍﺎﺏﺐﺑﺒﺓﺔﺕﺖﺗﺘﺙﺚﺛﺜﺝﺞﺟﺠﺡﺢﺣﺤﺥﺦﺧﺨﺩﺪﺫﺬﺭﺮﺯﺰ';
+ $find = 'ﺞ';
+ $result = Multibyte::strrchr($string, $find);
+ $expected = 'ﺞﺟﺠﺡﺢﺣﺤﺥﺦﺧﺨﺩﺪﺫﺬﺭﺮﺯﺰ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ﹰﹱﹲﹳﹴﹶﹷﹸﹹﹺﹻﹼﹽﹾﹿﺀﺁﺂﺃﺄﺅﺆﺇﺈﺉﺊﺋﺌﺍﺎﺏﺐﺑﺒﺓﺔﺕﺖﺗﺘﺙﺚﺛﺜﺝﺞﺟﺠﺡﺢﺣﺤﺥﺦﺧﺨﺩﺪﺫﺬﺭﺮﺯﺰ';
+ $find = 'ﺞ';
+ $result = Multibyte::strrchr($string, $find, true);
+ $expected = 'ﹰﹱﹲﹳﹴﹶﹷﹸﹹﹺﹻﹼﹽﹾﹿﺀﺁﺂﺃﺄﺅﺆﺇﺈﺉﺊﺋﺌﺍﺎﺏﺐﺑﺒﺓﺔﺕﺖﺗﺘﺙﺚﺛﺜﺝ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ﺱﺲﺳﺴﺵﺶﺷﺸﺹﺺﺻﺼﺽﺾﺿﻀﻁﻂﻃﻄﻅﻆﻇﻈﻉﻊﻋﻌﻍﻎﻏﻐﻑﻒﻓﻔﻕﻖﻗﻘﻙﻚﻛﻜﻝﻞﻟﻠﻡﻢﻣﻤﻥﻦﻧﻨﻩﻪﻫﻬﻭﻮﻯﻰﻱﻲﻳﻴﻵﻶﻷﻸﻹﻺﻻﻼ';
+ $find = 'ﻞ';
+ $result = Multibyte::strrchr($string, $find);
+ $expected = 'ﻞﻟﻠﻡﻢﻣﻤﻥﻦﻧﻨﻩﻪﻫﻬﻭﻮﻯﻰﻱﻲﻳﻴﻵﻶﻷﻸﻹﻺﻻﻼ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ﺱﺲﺳﺴﺵﺶﺷﺸﺹﺺﺻﺼﺽﺾﺿﻀﻁﻂﻃﻄﻅﻆﻇﻈﻉﻊﻋﻌﻍﻎﻏﻐﻑﻒﻓﻔﻕﻖﻗﻘﻙﻚﻛﻜﻝﻞﻟﻠﻡﻢﻣﻤﻥﻦﻧﻨﻩﻪﻫﻬﻭﻮﻯﻰﻱﻲﻳﻴﻵﻶﻷﻸﻹﻺﻻﻼ';
+ $find = 'ﻞ';
+ $result = Multibyte::strrchr($string, $find, true);
+ $expected = 'ﺱﺲﺳﺴﺵﺶﺷﺸﺹﺺﺻﺼﺽﺾﺿﻀﻁﻂﻃﻄﻅﻆﻇﻈﻉﻊﻋﻌﻍﻎﻏﻐﻑﻒﻓﻔﻕﻖﻗﻘﻙﻚﻛﻜﻝ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'abcdefghijklmnopqrstuvwxyz';
+ $find = 'k';
+ $result = Multibyte::strrchr($string, $find);
+ $expected = 'klmnopqrstuvwxyz';
+ $this->assertEqual($result, $expected);
+
+ $string = 'abcdefghijklmnopqrstuvwxyz';
+ $find = 'k';
+ $result = Multibyte::strrchr($string, $find, true);
+ $expected = 'abcdefghij';
+ $this->assertEqual($result, $expected);
+
+ $string = '。「」、・ヲァィゥェォャュョッーアイウエオカキク';
+ $find = 'ア';
+ $result = Multibyte::strrchr($string, $find);
+ $expected = 'アイウエオカキク';
+ $this->assertEqual($result, $expected);
+
+ $string = '。「」、・ヲァィゥェォャュョッーアイウエオカキク';
+ $find = 'ア';
+ $result = Multibyte::strrchr($string, $find, true);
+ $expected = '。「」、・ヲァィゥェォャュョッー';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン゙';
+ $find = 'ハ';
+ $result = Multibyte::strrchr($string, $find);
+ $expected = 'ハヒフヘホマミムメモヤユヨラリルレロワン゙';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン゙';
+ $find = 'ハ';
+ $result = Multibyte::strrchr($string, $find, true);
+ $expected = 'ケコサシスセソタチツテトナニヌネノ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ĥēĺļŏ, Ŵőřļď!';
+ $find = 'ő';
+ $result = Multibyte::strrchr($string, $find);
+ $expected = 'őřļď!';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ĥēĺļŏ, Ŵőřļď!';
+ $find = 'ő';
+ $result = Multibyte::strrchr($string, $find, true);
+ $expected = 'Ĥēĺļŏ, Ŵ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Hello, World!';
+ $find = 'o';
+ $result = Multibyte::strrchr($string, $find);
+ $expected = 'orld!';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Hello, World!';
+ $find = 'o';
+ $result = Multibyte::strrchr($string, $find, true);
+ $expected = 'Hello, W';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Hello, World!';
+ $find = 'Wo';
+ $result = Multibyte::strrchr($string, $find);
+ $expected = 'World!';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Hello, World!';
+ $find = 'Wo';
+ $result = Multibyte::strrchr($string, $find, true);
+ $expected = 'Hello, ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Hello, World!';
+ $find = 'll';
+ $result = Multibyte::strrchr($string, $find);
+ $expected = 'llo, World!';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Hello, World!';
+ $find = 'll';
+ $result = Multibyte::strrchr($string, $find, true);
+ $expected = 'He';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Hello, World!';
+ $find = 'rld';
+ $result = Multibyte::strrchr($string, $find);
+ $expected = 'rld!';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Hello, World!';
+ $find = 'rld';
+ $result = Multibyte::strrchr($string, $find, true);
+ $expected = 'Hello, Wo';
+ $this->assertEqual($result, $expected);
+
+ $string = 'čini';
+ $find = 'n';
+ $result = Multibyte::strrchr($string, $find);
+ $expected = 'ni';
+ $this->assertEqual($result, $expected);
+
+ $string = 'čini';
+ $find = 'n';
+ $result = Multibyte::strrchr($string, $find, true);
+ $expected = 'či';
+ $this->assertEqual($result, $expected);
+
+ $string = 'moći';
+ $find = 'ć';
+ $result = Multibyte::strrchr($string, $find);
+ $expected = 'ći';
+ $this->assertEqual($result, $expected);
+
+ $string = 'moći';
+ $find = 'ć';
+ $result = Multibyte::strrchr($string, $find, true);
+ $expected = 'mo';
+ $this->assertEqual($result, $expected);
+
+ $string = 'državni';
+ $find = 'ž';
+ $result = Multibyte::strrchr($string, $find);
+ $expected = 'žavni';
+ $this->assertEqual($result, $expected);
+
+ $string = 'državni';
+ $find = 'ž';
+ $result = Multibyte::strrchr($string, $find, true);
+ $expected = 'dr';
+ $this->assertEqual($result, $expected);
+
+ $string = '把百度设为首页';
+ $find = '设';
+ $result = Multibyte::strrchr($string, $find);
+ $expected = '设为首页';
+ $this->assertEqual($result, $expected);
+
+ $string = '把百度设为首页';
+ $find = '设';
+ $result = Multibyte::strrchr($string, $find, true);
+ $expected = '把百度';
+ $this->assertEqual($result, $expected);
+
+ $string = '一二三周永龍';
+ $find = '周';
+ $result = Multibyte::strrchr($string, $find);
+ $expected = '周永龍';
+ $this->assertEqual($result, $expected);
+
+ $string = '一二三周永龍';
+ $find = '周';
+ $result = Multibyte::strrchr($string, $find, true);
+ $expected = '一二三';
+ $this->assertEqual($result, $expected);
+
+ $string = '一二三周永龍';
+ $find = '周龍';
+ $result = Multibyte::strrchr($string, $find, true);
+ $expected = false;
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testUsingMbStrrichr method
+ *
+ * @access public
+ * @return void
+ */
+ function testUsingMbStrrichr() {
+ $string = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
+ $find = 'F';
+ $result = mb_strrichr($string, $find);
+ $expected = 'FGHIJKLMNOPQRSTUVWXYZ0123456789';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
+ $find = 'F';
+ $result = mb_strrichr($string, $find, true);
+ $expected = 'ABCDE';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞ';
+ $find = 'Å';
+ $result = mb_strrichr($string, $find);
+ $expected = 'ÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞ';
+ $find = 'Å';
+ $result = mb_strrichr($string, $find, true);
+ $expected = 'ÀÁÂÃÄ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĀĂĄĆĈĊČĎĐĒĔĖĘĚĜĞĠĢĤĦĨĪĬĮIJĴĶĹĻĽĿŁŃŅŇŊŌŎŐŒŔŖŘŚŜŞŠŢŤŦŨŪŬŮŰŲŴŶŹŻŽ';
+ $find = 'Ċ';
+ $result = mb_strrichr($string, $find);
+ $expected = 'ĊČĎĐĒĔĖĘĚĜĞĠĢĤĦĨĪĬĮIJĴĶĹĻĽĿŁŃŅŇŊŌŎŐŒŔŖŘŚŜŞŠŢŤŦŨŪŬŮŰŲŴŶŹŻŽ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĀĂĄĆĈĊČĎĐĒĔĖĘĚĜĞĠĢĤĦĨĪĬĮIJĴĶĹĻĽĿŁŃŅŇŊŌŎŐŒŔŖŘŚŜŞŠŢŤŦŨŪŬŮŰŲŴŶŹŻŽ';
+ $find = 'Ċ';
+ $result = mb_strrichr($string, $find, true);
+ $expected = 'ĀĂĄĆĈ';
+ $this->assertEqual($result, $expected);
+
+ $string = '!"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~';
+ $find = 'F';
+ $result = mb_strrichr($string, $find);
+ $expected = 'fghijklmnopqrstuvwxyz{|}~';
+ $this->assertEqual($result, $expected);
+
+ $string = '!"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~';
+ $find = 'F';
+ $result = mb_strrichr($string, $find, true);
+ $expected = '!"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcde';
+ $this->assertEqual($result, $expected);
+
+ $string = '¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈ';
+ $find = 'µ';
+ $result = mb_strrichr($string, $find);
+ $expected = 'µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈ';
+ $this->assertEqual($result, $expected);
+
+ $string = '¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈ';
+ $find = 'µ';
+ $result = mb_strrichr($string, $find, true);
+ $expected = '¡¢£¤¥¦§¨©ª«¬®¯°±²³´';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿĀāĂ㥹ĆćĈĉĊċČčĎďĐđĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪīĬ';
+ $find = 'Þ';
+ $result = mb_strrichr($string, $find);
+ $expected = 'þÿĀāĂ㥹ĆćĈĉĊċČčĎďĐđĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪīĬ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿĀāĂ㥹ĆćĈĉĊċČčĎďĐđĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪīĬ';
+ $find = 'Þ';
+ $result = mb_strrichr($string, $find, true);
+ $expected = 'ÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüý';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĭĮįİıIJijĴĵĶķĸĹĺĻļĽľĿŀŁłŃńŅņŇňʼnŊŋŌōŎŏŐőŒœŔŕŖŗŘřŚśŜŝŞşŠšŢţŤťŦŧŨũŪūŬŭŮůŰűŲųŴŵŶŷŸŹźŻżŽžſƀƁƂƃƄƅƆƇƈƉƊƋƌƍƎƏƐ';
+ $find = 'Ņ';
+ $result = mb_strrichr($string, $find);
+ $expected = 'ņŇňʼnŊŋŌōŎŏŐőŒœŔŕŖŗŘřŚśŜŝŞşŠšŢţŤťŦŧŨũŪūŬŭŮůŰűŲųŴŵŶŷŸŹźŻżŽžſƀƁƂƃƄƅƆƇƈƉƊƋƌƍƎƏƐ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĭĮįİıIJijĴĵĶķĸĹĺĻļĽľĿŀŁłŃńŅņŇňʼnŊŋŌōŎŏŐőŒœŔŕŖŗŘřŚśŜŝŞşŠšŢţŤťŦŧŨũŪūŬŭŮůŰűŲųŴŵŶŷŸŹźŻżŽžſƀƁƂƃƄƅƆƇƈƉƊƋƌƍƎƏƐ';
+ $find = 'Ņ';
+ $result = mb_strrichr($string, $find, true);
+ $expected = 'ĭĮįİıIJijĴĵĶķĸĹĺĻļĽľĿŀŁłŃńŅ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ƑƒƓƔƕƖƗƘƙƚƛƜƝƞƟƠơƢƣƤƥƦƧƨƩƪƫƬƭƮƯưƱƲƳƴƵƶƷƸƹƺƻƼƽƾƿǀǁǂǃDŽDždžLJLjljNJNjnjǍǎǏǐǑǒǓǔǕǖǗǘǙǚǛǜǝǞǟǠǡǢǣǤǥǦǧǨǩǪǫǬǭǮǯǰDZDzdzǴ';
+ $find = 'Ƹ';
+ $result = mb_strrichr($string, $find);
+ $expected = 'ƹƺƻƼƽƾƿǀǁǂǃDŽDždžLJLjljNJNjnjǍǎǏǐǑǒǓǔǕǖǗǘǙǚǛǜǝǞǟǠǡǢǣǤǥǦǧǨǩǪǫǬǭǮǯǰDZDzdzǴ';
+ $this->assertEqual($result, $expected);
+
+ $find = 'Ƹ';
+ $result = mb_strrichr($string, $find, true);
+ $expected = 'ƑƒƓƔƕƖƗƘƙƚƛƜƝƞƟƠơƢƣƤƥƦƧƨƩƪƫƬƭƮƯưƱƲƳƴƵƶƷƸ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'əɚɛɜɝɞɟɠɡɢɣɤɥɦɧɨɩɪɫɬɭɮɯɰɱɲɳɴɵɶɷɸɹɺɻɼɽɾɿʀʁʂʃʄʅʆʇʈʉʊʋʌʍʎʏʐʑʒʓʔʕʖʗʘʙʚʛʜʝʞʟʠʡʢʣʤʥʦʧʨʩʪʫʬʭʮʯʰʱʲʳʴʵʶʷʸʹʺʻʼ';
+ $find = 'ʀ';
+ $result = mb_strrichr($string, $find);
+ $expected = 'ʀʁʂʃʄʅʆʇʈʉʊʋʌʍʎʏʐʑʒʓʔʕʖʗʘʙʚʛʜʝʞʟʠʡʢʣʤʥʦʧʨʩʪʫʬʭʮʯʰʱʲʳʴʵʶʷʸʹʺʻʼ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'əɚɛɜɝɞɟɠɡɢɣɤɥɦɧɨɩɪɫɬɭɮɯɰɱɲɳɴɵɶɷɸɹɺɻɼɽɾɿʀʁʂʃʄʅʆʇʈʉʊʋʌʍʎʏʐʑʒʓʔʕʖʗʘʙʚʛʜʝʞʟʠʡʢʣʤʥʦʧʨʩʪʫʬʭʮʯʰʱʲʳʴʵʶʷʸʹʺʻʼ';
+ $find = 'ʀ';
+ $result = mb_strrichr($string, $find, true);
+ $expected = 'əɚɛɜɝɞɟɠɡɢɣɤɥɦɧɨɩɪɫɬɭɮɯɰɱɲɳɴɵɶɷɸɹɺɻɼɽɾɿ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ЀЁЂЃЄЅІЇЈЉЊЋЌЍЎЏАБВГДЕЖЗИЙКЛ';
+ $find = 'Ї';
+ $result = mb_strrichr($string, $find);
+ $expected = 'ЇЈЉЊЋЌЍЎЏАБВГДЕЖЗИЙКЛ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ЀЁЂЃЄЅІЇЈЉЊЋЌЍЎЏАБВГДЕЖЗИЙКЛ';
+ $find = 'Ї';
+ $result = mb_strrichr($string, $find, true);
+ $expected = 'ЀЁЂЃЄЅІ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'МНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыь';
+ $find = 'Р';
+ $result = mb_strrichr($string, $find);
+ $expected = 'рстуфхцчшщъыь';
+ $this->assertEqual($result, $expected);
+
+ $string = 'МНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмноп';
+ $find = 'Р';
+ $result = mb_strrichr($string, $find, true);
+ $expected = 'МНОП';
+ $this->assertEqual($result, $expected);
+
+ $string = 'فقكلمنهوىيًٌٍَُ';
+ $find = 'ن';
+ $result = mb_strrichr($string, $find);
+ $expected = 'نهوىيًٌٍَُ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'فقكلمنهوىيًٌٍَُ';
+ $find = 'ن';
+ $result = mb_strrichr($string, $find, true);
+ $expected = 'فقكلم';
+ $this->assertEqual($result, $expected);
+
+ $string = '✰✱✲✳✴✵✶✷✸✹✺✻✼✽✾✿❀❁❂❃❄❅❆❇❈❉❊❋❌❍❎❏❐❑❒❓❔❕❖❗❘❙❚❛❜❝❞';
+ $find = '✿';
+ $result = mb_strrichr($string, $find);
+ $expected = '✿❀❁❂❃❄❅❆❇❈❉❊❋❌❍❎❏❐❑❒❓❔❕❖❗❘❙❚❛❜❝❞';
+ $this->assertEqual($result, $expected);
+
+ $string = '✰✱✲✳✴✵✶✷✸✹✺✻✼✽✾✿❀❁❂❃❄❅❆❇❈❉❊❋❌❍❎❏❐❑❒❓❔❕❖❗❘❙❚❛❜❝❞';
+ $find = '✿';
+ $result = mb_strrichr($string, $find, true);
+ $expected = '✰✱✲✳✴✵✶✷✸✹✺✻✼✽✾';
+ $this->assertEqual($result, $expected);
+
+ $string = '⺀⺁⺂⺃⺄⺅⺆⺇⺈⺉⺊⺋⺌⺍⺎⺏⺐⺑⺒⺓⺔⺕⺖⺗⺘⺙⺛⺜⺝⺞⺟⺠⺡⺢⺣⺤⺥⺦⺧⺨⺩⺪⺫⺬⺭⺮⺯⺰⺱⺲⺳⺴⺵⺶⺷⺸⺹⺺⺻⺼⺽⺾⺿⻀⻁⻂⻃⻄⻅⻆⻇⻈⻉⻊⻋⻌⻍⻎⻏⻐⻑⻒⻓⻔⻕⻖⻗⻘⻙⻚⻛⻜⻝⻞⻟⻠';
+ $find = '⺐';
+ $result = mb_strrichr($string, $find);
+ $expected = '⺐⺑⺒⺓⺔⺕⺖⺗⺘⺙⺛⺜⺝⺞⺟⺠⺡⺢⺣⺤⺥⺦⺧⺨⺩⺪⺫⺬⺭⺮⺯⺰⺱⺲⺳⺴⺵⺶⺷⺸⺹⺺⺻⺼⺽⺾⺿⻀⻁⻂⻃⻄⻅⻆⻇⻈⻉⻊⻋⻌⻍⻎⻏⻐⻑⻒⻓⻔⻕⻖⻗⻘⻙⻚⻛⻜⻝⻞⻟⻠';
+ $this->assertEqual($result, $expected);
+
+ $string = '⺀⺁⺂⺃⺄⺅⺆⺇⺈⺉⺊⺋⺌⺍⺎⺏⺐⺑⺒⺓⺔⺕⺖⺗⺘⺙⺛⺜⺝⺞⺟⺠⺡⺢⺣⺤⺥⺦⺧⺨⺩⺪⺫⺬⺭⺮⺯⺰⺱⺲⺳⺴⺵⺶⺷⺸⺹⺺⺻⺼⺽⺾⺿⻀⻁⻂⻃⻄⻅⻆⻇⻈⻉⻊⻋⻌⻍⻎⻏⻐⻑⻒⻓⻔⻕⻖⻗⻘⻙⻚⻛⻜⻝⻞⻟⻠';
+ $find = '⺐';
+ $result = mb_strrichr($string, $find, true);
+ $expected = '⺀⺁⺂⺃⺄⺅⺆⺇⺈⺉⺊⺋⺌⺍⺎⺏';
+ $this->assertEqual($result, $expected);
+
+ $string = '⽅⽆⽇⽈⽉⽊⽋⽌⽍⽎⽏⽐⽑⽒⽓⽔⽕⽖⽗⽘⽙⽚⽛⽜⽝⽞⽟⽠⽡⽢⽣⽤⽥⽦⽧⽨⽩⽪⽫⽬⽭⽮⽯⽰⽱⽲⽳⽴⽵⽶⽷⽸⽹⽺⽻⽼⽽⽾⽿';
+ $find = '⽤';
+ $result = mb_strrichr($string, $find);
+ $expected = '⽤⽥⽦⽧⽨⽩⽪⽫⽬⽭⽮⽯⽰⽱⽲⽳⽴⽵⽶⽷⽸⽹⽺⽻⽼⽽⽾⽿';
+ $this->assertEqual($result, $expected);
+
+ $string = '⽅⽆⽇⽈⽉⽊⽋⽌⽍⽎⽏⽐⽑⽒⽓⽔⽕⽖⽗⽘⽙⽚⽛⽜⽝⽞⽟⽠⽡⽢⽣⽤⽥⽦⽧⽨⽩⽪⽫⽬⽭⽮⽯⽰⽱⽲⽳⽴⽵⽶⽷⽸⽹⽺⽻⽼⽽⽾⽿';
+ $find = '⽤';
+ $result = mb_strrichr($string, $find, true);
+ $expected = '⽅⽆⽇⽈⽉⽊⽋⽌⽍⽎⽏⽐⽑⽒⽓⽔⽕⽖⽗⽘⽙⽚⽛⽜⽝⽞⽟⽠⽡⽢⽣';
+ $this->assertEqual($result, $expected);
+
+ $string = '눡눢눣눤눥눦눧눨눩눪눫눬눭눮눯눰눱눲눳눴눵눶눷눸눹눺눻눼눽눾눿뉀뉁뉂뉃뉄뉅뉆뉇뉈뉉뉊뉋뉌뉍뉎뉏뉐뉑뉒뉓뉔뉕뉖뉗뉘뉙뉚뉛뉜뉝뉞뉟뉠뉡뉢뉣뉤뉥뉦뉧뉨뉩뉪뉫뉬뉭뉮뉯뉰뉱뉲뉳뉴뉵뉶뉷뉸뉹뉺뉻뉼뉽뉾뉿늀늁늂늃늄';
+ $find = '눻';
+ $result = mb_strrichr($string, $find);
+ $expected = '눻눼눽눾눿뉀뉁뉂뉃뉄뉅뉆뉇뉈뉉뉊뉋뉌뉍뉎뉏뉐뉑뉒뉓뉔뉕뉖뉗뉘뉙뉚뉛뉜뉝뉞뉟뉠뉡뉢뉣뉤뉥뉦뉧뉨뉩뉪뉫뉬뉭뉮뉯뉰뉱뉲뉳뉴뉵뉶뉷뉸뉹뉺뉻뉼뉽뉾뉿늀늁늂늃늄';
+ $this->assertEqual($result, $expected);
+
+ $string = '눡눢눣눤눥눦눧눨눩눪눫눬눭눮눯눰눱눲눳눴눵눶눷눸눹눺눻눼눽눾눿뉀뉁뉂뉃뉄뉅뉆뉇뉈뉉뉊뉋뉌뉍뉎뉏뉐뉑뉒뉓뉔뉕뉖뉗뉘뉙뉚뉛뉜뉝뉞뉟뉠뉡뉢뉣뉤뉥뉦뉧뉨뉩뉪뉫뉬뉭뉮뉯뉰뉱뉲뉳뉴뉵뉶뉷뉸뉹뉺뉻뉼뉽뉾뉿늀늁늂늃늄';
+ $find = '눻';
+ $result = mb_strrichr($string, $find, true);
+ $expected = '눡눢눣눤눥눦눧눨눩눪눫눬눭눮눯눰눱눲눳눴눵눶눷눸눹눺';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ﹰﹱﹲﹳﹴﹶﹷﹸﹹﹺﹻﹼﹽﹾﹿﺀﺁﺂﺃﺄﺅﺆﺇﺈﺉﺊﺋﺌﺍﺎﺏﺐﺑﺒﺓﺔﺕﺖﺗﺘﺙﺚﺛﺜﺝﺞﺟﺠﺡﺢﺣﺤﺥﺦﺧﺨﺩﺪﺫﺬﺭﺮﺯﺰ';
+ $find = 'ﺞ';
+ $result = mb_strrichr($string, $find);
+ $expected = 'ﺞﺟﺠﺡﺢﺣﺤﺥﺦﺧﺨﺩﺪﺫﺬﺭﺮﺯﺰ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ﹰﹱﹲﹳﹴﹶﹷﹸﹹﹺﹻﹼﹽﹾﹿﺀﺁﺂﺃﺄﺅﺆﺇﺈﺉﺊﺋﺌﺍﺎﺏﺐﺑﺒﺓﺔﺕﺖﺗﺘﺙﺚﺛﺜﺝﺞﺟﺠﺡﺢﺣﺤﺥﺦﺧﺨﺩﺪﺫﺬﺭﺮﺯﺰ';
+ $find = 'ﺞ';
+ $result = mb_strrichr($string, $find, true);
+ $expected = 'ﹰﹱﹲﹳﹴﹶﹷﹸﹹﹺﹻﹼﹽﹾﹿﺀﺁﺂﺃﺄﺅﺆﺇﺈﺉﺊﺋﺌﺍﺎﺏﺐﺑﺒﺓﺔﺕﺖﺗﺘﺙﺚﺛﺜﺝ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ﺱﺲﺳﺴﺵﺶﺷﺸﺹﺺﺻﺼﺽﺾﺿﻀﻁﻂﻃﻄﻅﻆﻇﻈﻉﻊﻋﻌﻍﻎﻏﻐﻑﻒﻓﻔﻕﻖﻗﻘﻙﻚﻛﻜﻝﻞﻟﻠﻡﻢﻣﻤﻥﻦﻧﻨﻩﻪﻫﻬﻭﻮﻯﻰﻱﻲﻳﻴﻵﻶﻷﻸﻹﻺﻻﻼ';
+ $find = 'ﻞ';
+ $result = mb_strrichr($string, $find);
+ $expected = 'ﻞﻟﻠﻡﻢﻣﻤﻥﻦﻧﻨﻩﻪﻫﻬﻭﻮﻯﻰﻱﻲﻳﻴﻵﻶﻷﻸﻹﻺﻻﻼ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ﺱﺲﺳﺴﺵﺶﺷﺸﺹﺺﺻﺼﺽﺾﺿﻀﻁﻂﻃﻄﻅﻆﻇﻈﻉﻊﻋﻌﻍﻎﻏﻐﻑﻒﻓﻔﻕﻖﻗﻘﻙﻚﻛﻜﻝﻞﻟﻠﻡﻢﻣﻤﻥﻦﻧﻨﻩﻪﻫﻬﻭﻮﻯﻰﻱﻲﻳﻴﻵﻶﻷﻸﻹﻺﻻﻼ';
+ $find = 'ﻞ';
+ $result = mb_strrichr($string, $find, true);
+ $expected = 'ﺱﺲﺳﺴﺵﺶﺷﺸﺹﺺﺻﺼﺽﺾﺿﻀﻁﻂﻃﻄﻅﻆﻇﻈﻉﻊﻋﻌﻍﻎﻏﻐﻑﻒﻓﻔﻕﻖﻗﻘﻙﻚﻛﻜﻝ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'abcdefghijklmnopqrstuvwxyz';
+ $find = 'k';
+ $result = mb_strrichr($string, $find);
+ $expected = 'klmnopqrstuvwxyz';
+ $this->assertEqual($result, $expected);
+
+ $string = 'abcdefghijklmnopqrstuvwxyz';
+ $find = 'k';
+ $result = mb_strrichr($string, $find, true);
+ $expected = 'abcdefghij';
+ $this->assertEqual($result, $expected);
+
+ $string = '。「」、・ヲァィゥェォャュョッーアイウエオカキク';
+ $find = 'ア';
+ $result = mb_strrichr($string, $find);
+ $expected = 'アイウエオカキク';
+ $this->assertEqual($result, $expected);
+
+ $string = '。「」、・ヲァィゥェォャュョッーアイウエオカキク';
+ $find = 'ア';
+ $result = mb_strrichr($string, $find, true);
+ $expected = '。「」、・ヲァィゥェォャュョッー';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン゙';
+ $find = 'ハ';
+ $result = mb_strrichr($string, $find);
+ $expected = 'ハヒフヘホマミムメモヤユヨラリルレロワン゙';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン゙';
+ $find = 'ハ';
+ $result = mb_strrichr($string, $find, true);
+ $expected = 'ケコサシスセソタチツテトナニヌネノ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ĥēĺļŏ, Ŵőřļď!';
+ $find = 'ő';
+ $result = mb_strrichr($string, $find);
+ $expected = 'őřļď!';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ĥēĺļŏ, Ŵőřļď!';
+ $find = 'ő';
+ $result = mb_strrichr($string, $find, true);
+ $expected = 'Ĥēĺļŏ, Ŵ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Hello, World!';
+ $find = 'o';
+ $result = mb_strrichr($string, $find);
+ $expected = 'orld!';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Hello, World!';
+ $find = 'o';
+ $result = mb_strrichr($string, $find, true);
+ $expected = 'Hello, W';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Hello, World!';
+ $find = 'Wo';
+ $result = mb_strrichr($string, $find);
+ $expected = 'World!';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Hello, World!';
+ $find = 'Wo';
+ $result = mb_strrichr($string, $find, true);
+ $expected = 'Hello, ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Hello, World!';
+ $find = 'll';
+ $result = mb_strrichr($string, $find);
+ $expected = 'llo, World!';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Hello, World!';
+ $find = 'll';
+ $result = mb_strrichr($string, $find, true);
+ $expected = 'He';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Hello, World!';
+ $find = 'rld';
+ $result = mb_strrichr($string, $find);
+ $expected = 'rld!';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Hello, World!';
+ $find = 'rld';
+ $result = mb_strrichr($string, $find, true);
+ $expected = 'Hello, Wo';
+ $this->assertEqual($result, $expected);
+
+ $string = 'čini';
+ $find = 'n';
+ $result = mb_strrichr($string, $find);
+ $expected = 'ni';
+ $this->assertEqual($result, $expected);
+
+ $string = 'čini';
+ $find = 'n';
+ $result = mb_strrichr($string, $find, true);
+ $expected = 'či';
+ $this->assertEqual($result, $expected);
+
+ $string = 'moći';
+ $find = 'ć';
+ $result = mb_strrichr($string, $find);
+ $expected = 'ći';
+ $this->assertEqual($result, $expected);
+
+ $string = 'moći';
+ $find = 'ć';
+ $result = mb_strrichr($string, $find, true);
+ $expected = 'mo';
+ $this->assertEqual($result, $expected);
+
+ $string = 'državni';
+ $find = 'ž';
+ $result = mb_strrichr($string, $find);
+ $expected = 'žavni';
+ $this->assertEqual($result, $expected);
+
+ $string = 'državni';
+ $find = 'ž';
+ $result = mb_strrichr($string, $find, true);
+ $expected = 'dr';
+ $this->assertEqual($result, $expected);
+
+ $string = '把百度设为首页';
+ $find = '设';
+ $result = mb_strrichr($string, $find);
+ $expected = '设为首页';
+ $this->assertEqual($result, $expected);
+
+ $string = '把百度设为首页';
+ $find = '设';
+ $result = mb_strrichr($string, $find, true);
+ $expected = '把百度';
+ $this->assertEqual($result, $expected);
+
+ $string = '一二三周永龍';
+ $find = '周';
+ $result = mb_strrichr($string, $find);
+ $expected = '周永龍';
+ $this->assertEqual($result, $expected);
+
+ $string = '一二三周永龍';
+ $find = '周';
+ $result = mb_strrichr($string, $find, true);
+ $expected = '一二三';
+ $this->assertEqual($result, $expected);
+
+ $string = '把百度设为首页';
+ $find = '百设';
+ $result = mb_strrichr($string, $find, true);
+ $expected = false;
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testMultibyteStrrichr method
+ *
+ * @access public
+ * @return void
+ */
+ function testMultibyteStrrichr() {
+ $string = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
+ $find = 'F';
+ $result = Multibyte::strrichr($string, $find);
+ $expected = 'FGHIJKLMNOPQRSTUVWXYZ0123456789';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
+ $find = 'F';
+ $result = Multibyte::strrichr($string, $find, true);
+ $expected = 'ABCDE';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞ';
+ $find = 'Å';
+ $result = Multibyte::strrichr($string, $find);
+ $expected = 'ÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞ';
+ $find = 'Å';
+ $result = Multibyte::strrichr($string, $find, true);
+ $expected = 'ÀÁÂÃÄ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĀĂĄĆĈĊČĎĐĒĔĖĘĚĜĞĠĢĤĦĨĪĬĮIJĴĶĹĻĽĿŁŃŅŇŊŌŎŐŒŔŖŘŚŜŞŠŢŤŦŨŪŬŮŰŲŴŶŹŻŽ';
+ $find = 'Ċ';
+ $result = Multibyte::strrichr($string, $find);
+ $expected = 'ĊČĎĐĒĔĖĘĚĜĞĠĢĤĦĨĪĬĮIJĴĶĹĻĽĿŁŃŅŇŊŌŎŐŒŔŖŘŚŜŞŠŢŤŦŨŪŬŮŰŲŴŶŹŻŽ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĀĂĄĆĈĊČĎĐĒĔĖĘĚĜĞĠĢĤĦĨĪĬĮIJĴĶĹĻĽĿŁŃŅŇŊŌŎŐŒŔŖŘŚŜŞŠŢŤŦŨŪŬŮŰŲŴŶŹŻŽ';
+ $find = 'Ċ';
+ $result = Multibyte::strrichr($string, $find, true);
+ $expected = 'ĀĂĄĆĈ';
+ $this->assertEqual($result, $expected);
+
+ $string = '!"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~';
+ $find = 'F';
+ $result = Multibyte::strrichr($string, $find);
+ $expected = 'fghijklmnopqrstuvwxyz{|}~';
+ $this->assertEqual($result, $expected);
+
+ $string = '!"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~';
+ $find = 'F';
+ $result = Multibyte::strrichr($string, $find, true);
+ $expected = '!"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcde';
+ $this->assertEqual($result, $expected);
+
+ $string = '¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈ';
+ $find = 'µ';
+ $result = Multibyte::strrichr($string, $find);
+ $expected = 'µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈ';
+ $this->assertEqual($result, $expected);
+
+ $string = '¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈ';
+ $find = 'µ';
+ $result = Multibyte::strrichr($string, $find, true);
+ $expected = '¡¢£¤¥¦§¨©ª«¬®¯°±²³´';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿĀāĂ㥹ĆćĈĉĊċČčĎďĐđĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪīĬ';
+ $find = 'Þ';
+ $result = Multibyte::strrichr($string, $find);
+ $expected = 'þÿĀāĂ㥹ĆćĈĉĊċČčĎďĐđĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪīĬ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿĀāĂ㥹ĆćĈĉĊċČčĎďĐđĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪīĬ';
+ $find = 'Þ';
+ $result = Multibyte::strrichr($string, $find, true);
+ $expected = 'ÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüý';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĭĮįİıIJijĴĵĶķĸĹĺĻļĽľĿŀŁłŃńŅņŇňʼnŊŋŌōŎŏŐőŒœŔŕŖŗŘřŚśŜŝŞşŠšŢţŤťŦŧŨũŪūŬŭŮůŰűŲųŴŵŶŷŸŹźŻżŽžſƀƁƂƃƄƅƆƇƈƉƊƋƌƍƎƏƐ';
+ $find = 'Ņ';
+ $result = Multibyte::strrichr($string, $find);
+ $expected = 'ņŇňʼnŊŋŌōŎŏŐőŒœŔŕŖŗŘřŚśŜŝŞşŠšŢţŤťŦŧŨũŪūŬŭŮůŰűŲųŴŵŶŷŸŹźŻżŽžſƀƁƂƃƄƅƆƇƈƉƊƋƌƍƎƏƐ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĭĮįİıIJijĴĵĶķĸĹĺĻļĽľĿŀŁłŃńŅņŇňʼnŊŋŌōŎŏŐőŒœŔŕŖŗŘřŚśŜŝŞşŠšŢţŤťŦŧŨũŪūŬŭŮůŰűŲųŴŵŶŷŸŹźŻżŽžſƀƁƂƃƄƅƆƇƈƉƊƋƌƍƎƏƐ';
+ $find = 'Ņ';
+ $result = Multibyte::strrichr($string, $find, true);
+ $expected = 'ĭĮįİıIJijĴĵĶķĸĹĺĻļĽľĿŀŁłŃńŅ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ƑƒƓƔƕƖƗƘƙƚƛƜƝƞƟƠơƢƣƤƥƦƧƨƩƪƫƬƭƮƯưƱƲƳƴƵƶƷƸƹƺƻƼƽƾƿǀǁǂǃDŽDždžLJLjljNJNjnjǍǎǏǐǑǒǓǔǕǖǗǘǙǚǛǜǝǞǟǠǡǢǣǤǥǦǧǨǩǪǫǬǭǮǯǰDZDzdzǴ';
+ $find = 'Ƹ';
+ $result = Multibyte::strrichr($string, $find);
+ $expected = 'ƹƺƻƼƽƾƿǀǁǂǃDŽDždžLJLjljNJNjnjǍǎǏǐǑǒǓǔǕǖǗǘǙǚǛǜǝǞǟǠǡǢǣǤǥǦǧǨǩǪǫǬǭǮǯǰDZDzdzǴ';
+ $this->assertEqual($result, $expected);
+
+ $find = 'Ƹ';
+ $result = Multibyte::strrichr($string, $find, true);
+ $expected = 'ƑƒƓƔƕƖƗƘƙƚƛƜƝƞƟƠơƢƣƤƥƦƧƨƩƪƫƬƭƮƯưƱƲƳƴƵƶƷƸ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'əɚɛɜɝɞɟɠɡɢɣɤɥɦɧɨɩɪɫɬɭɮɯɰɱɲɳɴɵɶɷɸɹɺɻɼɽɾɿʀʁʂʃʄʅʆʇʈʉʊʋʌʍʎʏʐʑʒʓʔʕʖʗʘʙʚʛʜʝʞʟʠʡʢʣʤʥʦʧʨʩʪʫʬʭʮʯʰʱʲʳʴʵʶʷʸʹʺʻʼ';
+ $find = 'ʀ';
+ $result = Multibyte::strrichr($string, $find);
+ $expected = 'ʀʁʂʃʄʅʆʇʈʉʊʋʌʍʎʏʐʑʒʓʔʕʖʗʘʙʚʛʜʝʞʟʠʡʢʣʤʥʦʧʨʩʪʫʬʭʮʯʰʱʲʳʴʵʶʷʸʹʺʻʼ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'əɚɛɜɝɞɟɠɡɢɣɤɥɦɧɨɩɪɫɬɭɮɯɰɱɲɳɴɵɶɷɸɹɺɻɼɽɾɿʀʁʂʃʄʅʆʇʈʉʊʋʌʍʎʏʐʑʒʓʔʕʖʗʘʙʚʛʜʝʞʟʠʡʢʣʤʥʦʧʨʩʪʫʬʭʮʯʰʱʲʳʴʵʶʷʸʹʺʻʼ';
+ $find = 'ʀ';
+ $result = Multibyte::strrichr($string, $find, true);
+ $expected = 'əɚɛɜɝɞɟɠɡɢɣɤɥɦɧɨɩɪɫɬɭɮɯɰɱɲɳɴɵɶɷɸɹɺɻɼɽɾɿ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ЀЁЂЃЄЅІЇЈЉЊЋЌЍЎЏАБВГДЕЖЗИЙКЛ';
+ $find = 'Ї';
+ $result = Multibyte::strrichr($string, $find);
+ $expected = 'ЇЈЉЊЋЌЍЎЏАБВГДЕЖЗИЙКЛ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ЀЁЂЃЄЅІЇЈЉЊЋЌЍЎЏАБВГДЕЖЗИЙКЛ';
+ $find = 'Ї';
+ $result = Multibyte::strrichr($string, $find, true);
+ $expected = 'ЀЁЂЃЄЅІ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'МНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыь';
+ $find = 'Р';
+ $result = Multibyte::strrichr($string, $find);
+ $expected = 'рстуфхцчшщъыь';
+ $this->assertEqual($result, $expected);
+
+ $string = 'МНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмноп';
+ $find = 'Р';
+ $result = Multibyte::strrichr($string, $find, true);
+ $expected = 'МНОП';
+ $this->assertEqual($result, $expected);
+
+ $string = 'فقكلمنهوىيًٌٍَُ';
+ $find = 'ن';
+ $result = Multibyte::strrichr($string, $find);
+ $expected = 'نهوىيًٌٍَُ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'فقكلمنهوىيًٌٍَُ';
+ $find = 'ن';
+ $result = Multibyte::strrichr($string, $find, true);
+ $expected = 'فقكلم';
+ $this->assertEqual($result, $expected);
+
+ $string = '✰✱✲✳✴✵✶✷✸✹✺✻✼✽✾✿❀❁❂❃❄❅❆❇❈❉❊❋❌❍❎❏❐❑❒❓❔❕❖❗❘❙❚❛❜❝❞';
+ $find = '✿';
+ $result = Multibyte::strrichr($string, $find);
+ $expected = '✿❀❁❂❃❄❅❆❇❈❉❊❋❌❍❎❏❐❑❒❓❔❕❖❗❘❙❚❛❜❝❞';
+ $this->assertEqual($result, $expected);
+
+ $string = '✰✱✲✳✴✵✶✷✸✹✺✻✼✽✾✿❀❁❂❃❄❅❆❇❈❉❊❋❌❍❎❏❐❑❒❓❔❕❖❗❘❙❚❛❜❝❞';
+ $find = '✿';
+ $result = Multibyte::strrichr($string, $find, true);
+ $expected = '✰✱✲✳✴✵✶✷✸✹✺✻✼✽✾';
+ $this->assertEqual($result, $expected);
+
+ $string = '⺀⺁⺂⺃⺄⺅⺆⺇⺈⺉⺊⺋⺌⺍⺎⺏⺐⺑⺒⺓⺔⺕⺖⺗⺘⺙⺛⺜⺝⺞⺟⺠⺡⺢⺣⺤⺥⺦⺧⺨⺩⺪⺫⺬⺭⺮⺯⺰⺱⺲⺳⺴⺵⺶⺷⺸⺹⺺⺻⺼⺽⺾⺿⻀⻁⻂⻃⻄⻅⻆⻇⻈⻉⻊⻋⻌⻍⻎⻏⻐⻑⻒⻓⻔⻕⻖⻗⻘⻙⻚⻛⻜⻝⻞⻟⻠';
+ $find = '⺐';
+ $result = Multibyte::strrichr($string, $find);
+ $expected = '⺐⺑⺒⺓⺔⺕⺖⺗⺘⺙⺛⺜⺝⺞⺟⺠⺡⺢⺣⺤⺥⺦⺧⺨⺩⺪⺫⺬⺭⺮⺯⺰⺱⺲⺳⺴⺵⺶⺷⺸⺹⺺⺻⺼⺽⺾⺿⻀⻁⻂⻃⻄⻅⻆⻇⻈⻉⻊⻋⻌⻍⻎⻏⻐⻑⻒⻓⻔⻕⻖⻗⻘⻙⻚⻛⻜⻝⻞⻟⻠';
+ $this->assertEqual($result, $expected);
+
+ $string = '⺀⺁⺂⺃⺄⺅⺆⺇⺈⺉⺊⺋⺌⺍⺎⺏⺐⺑⺒⺓⺔⺕⺖⺗⺘⺙⺛⺜⺝⺞⺟⺠⺡⺢⺣⺤⺥⺦⺧⺨⺩⺪⺫⺬⺭⺮⺯⺰⺱⺲⺳⺴⺵⺶⺷⺸⺹⺺⺻⺼⺽⺾⺿⻀⻁⻂⻃⻄⻅⻆⻇⻈⻉⻊⻋⻌⻍⻎⻏⻐⻑⻒⻓⻔⻕⻖⻗⻘⻙⻚⻛⻜⻝⻞⻟⻠';
+ $find = '⺐';
+ $result = Multibyte::strrichr($string, $find, true);
+ $expected = '⺀⺁⺂⺃⺄⺅⺆⺇⺈⺉⺊⺋⺌⺍⺎⺏';
+ $this->assertEqual($result, $expected);
+
+ $string = '⽅⽆⽇⽈⽉⽊⽋⽌⽍⽎⽏⽐⽑⽒⽓⽔⽕⽖⽗⽘⽙⽚⽛⽜⽝⽞⽟⽠⽡⽢⽣⽤⽥⽦⽧⽨⽩⽪⽫⽬⽭⽮⽯⽰⽱⽲⽳⽴⽵⽶⽷⽸⽹⽺⽻⽼⽽⽾⽿';
+ $find = '⽤';
+ $result = Multibyte::strrichr($string, $find);
+ $expected = '⽤⽥⽦⽧⽨⽩⽪⽫⽬⽭⽮⽯⽰⽱⽲⽳⽴⽵⽶⽷⽸⽹⽺⽻⽼⽽⽾⽿';
+ $this->assertEqual($result, $expected);
+
+ $string = '⽅⽆⽇⽈⽉⽊⽋⽌⽍⽎⽏⽐⽑⽒⽓⽔⽕⽖⽗⽘⽙⽚⽛⽜⽝⽞⽟⽠⽡⽢⽣⽤⽥⽦⽧⽨⽩⽪⽫⽬⽭⽮⽯⽰⽱⽲⽳⽴⽵⽶⽷⽸⽹⽺⽻⽼⽽⽾⽿';
+ $find = '⽤';
+ $result = Multibyte::strrichr($string, $find, true);
+ $expected = '⽅⽆⽇⽈⽉⽊⽋⽌⽍⽎⽏⽐⽑⽒⽓⽔⽕⽖⽗⽘⽙⽚⽛⽜⽝⽞⽟⽠⽡⽢⽣';
+ $this->assertEqual($result, $expected);
+
+ $string = '눡눢눣눤눥눦눧눨눩눪눫눬눭눮눯눰눱눲눳눴눵눶눷눸눹눺눻눼눽눾눿뉀뉁뉂뉃뉄뉅뉆뉇뉈뉉뉊뉋뉌뉍뉎뉏뉐뉑뉒뉓뉔뉕뉖뉗뉘뉙뉚뉛뉜뉝뉞뉟뉠뉡뉢뉣뉤뉥뉦뉧뉨뉩뉪뉫뉬뉭뉮뉯뉰뉱뉲뉳뉴뉵뉶뉷뉸뉹뉺뉻뉼뉽뉾뉿늀늁늂늃늄';
+ $find = '눻';
+ $result = Multibyte::strrichr($string, $find);
+ $expected = '눻눼눽눾눿뉀뉁뉂뉃뉄뉅뉆뉇뉈뉉뉊뉋뉌뉍뉎뉏뉐뉑뉒뉓뉔뉕뉖뉗뉘뉙뉚뉛뉜뉝뉞뉟뉠뉡뉢뉣뉤뉥뉦뉧뉨뉩뉪뉫뉬뉭뉮뉯뉰뉱뉲뉳뉴뉵뉶뉷뉸뉹뉺뉻뉼뉽뉾뉿늀늁늂늃늄';
+ $this->assertEqual($result, $expected);
+
+ $string = '눡눢눣눤눥눦눧눨눩눪눫눬눭눮눯눰눱눲눳눴눵눶눷눸눹눺눻눼눽눾눿뉀뉁뉂뉃뉄뉅뉆뉇뉈뉉뉊뉋뉌뉍뉎뉏뉐뉑뉒뉓뉔뉕뉖뉗뉘뉙뉚뉛뉜뉝뉞뉟뉠뉡뉢뉣뉤뉥뉦뉧뉨뉩뉪뉫뉬뉭뉮뉯뉰뉱뉲뉳뉴뉵뉶뉷뉸뉹뉺뉻뉼뉽뉾뉿늀늁늂늃늄';
+ $find = '눻';
+ $result = Multibyte::strrichr($string, $find, true);
+ $expected = '눡눢눣눤눥눦눧눨눩눪눫눬눭눮눯눰눱눲눳눴눵눶눷눸눹눺';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ﹰﹱﹲﹳﹴﹶﹷﹸﹹﹺﹻﹼﹽﹾﹿﺀﺁﺂﺃﺄﺅﺆﺇﺈﺉﺊﺋﺌﺍﺎﺏﺐﺑﺒﺓﺔﺕﺖﺗﺘﺙﺚﺛﺜﺝﺞﺟﺠﺡﺢﺣﺤﺥﺦﺧﺨﺩﺪﺫﺬﺭﺮﺯﺰ';
+ $find = 'ﺞ';
+ $result = Multibyte::strrichr($string, $find);
+ $expected = 'ﺞﺟﺠﺡﺢﺣﺤﺥﺦﺧﺨﺩﺪﺫﺬﺭﺮﺯﺰ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ﹰﹱﹲﹳﹴﹶﹷﹸﹹﹺﹻﹼﹽﹾﹿﺀﺁﺂﺃﺄﺅﺆﺇﺈﺉﺊﺋﺌﺍﺎﺏﺐﺑﺒﺓﺔﺕﺖﺗﺘﺙﺚﺛﺜﺝﺞﺟﺠﺡﺢﺣﺤﺥﺦﺧﺨﺩﺪﺫﺬﺭﺮﺯﺰ';
+ $find = 'ﺞ';
+ $result = Multibyte::strrichr($string, $find, true);
+ $expected = 'ﹰﹱﹲﹳﹴﹶﹷﹸﹹﹺﹻﹼﹽﹾﹿﺀﺁﺂﺃﺄﺅﺆﺇﺈﺉﺊﺋﺌﺍﺎﺏﺐﺑﺒﺓﺔﺕﺖﺗﺘﺙﺚﺛﺜﺝ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ﺱﺲﺳﺴﺵﺶﺷﺸﺹﺺﺻﺼﺽﺾﺿﻀﻁﻂﻃﻄﻅﻆﻇﻈﻉﻊﻋﻌﻍﻎﻏﻐﻑﻒﻓﻔﻕﻖﻗﻘﻙﻚﻛﻜﻝﻞﻟﻠﻡﻢﻣﻤﻥﻦﻧﻨﻩﻪﻫﻬﻭﻮﻯﻰﻱﻲﻳﻴﻵﻶﻷﻸﻹﻺﻻﻼ';
+ $find = 'ﻞ';
+ $result = Multibyte::strrichr($string, $find);
+ $expected = 'ﻞﻟﻠﻡﻢﻣﻤﻥﻦﻧﻨﻩﻪﻫﻬﻭﻮﻯﻰﻱﻲﻳﻴﻵﻶﻷﻸﻹﻺﻻﻼ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ﺱﺲﺳﺴﺵﺶﺷﺸﺹﺺﺻﺼﺽﺾﺿﻀﻁﻂﻃﻄﻅﻆﻇﻈﻉﻊﻋﻌﻍﻎﻏﻐﻑﻒﻓﻔﻕﻖﻗﻘﻙﻚﻛﻜﻝﻞﻟﻠﻡﻢﻣﻤﻥﻦﻧﻨﻩﻪﻫﻬﻭﻮﻯﻰﻱﻲﻳﻴﻵﻶﻷﻸﻹﻺﻻﻼ';
+ $find = 'ﻞ';
+ $result = Multibyte::strrichr($string, $find, true);
+ $expected = 'ﺱﺲﺳﺴﺵﺶﺷﺸﺹﺺﺻﺼﺽﺾﺿﻀﻁﻂﻃﻄﻅﻆﻇﻈﻉﻊﻋﻌﻍﻎﻏﻐﻑﻒﻓﻔﻕﻖﻗﻘﻙﻚﻛﻜﻝ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'abcdefghijklmnopqrstuvwxyz';
+ $find = 'k';
+ $result = Multibyte::strrichr($string, $find);
+ $expected = 'klmnopqrstuvwxyz';
+ $this->assertEqual($result, $expected);
+
+ $string = 'abcdefghijklmnopqrstuvwxyz';
+ $find = 'k';
+ $result = Multibyte::strrichr($string, $find, true);
+ $expected = 'abcdefghij';
+ $this->assertEqual($result, $expected);
+
+ $string = '。「」、・ヲァィゥェォャュョッーアイウエオカキク';
+ $find = 'ア';
+ $result = Multibyte::strrichr($string, $find);
+ $expected = 'アイウエオカキク';
+ $this->assertEqual($result, $expected);
+
+ $string = '。「」、・ヲァィゥェォャュョッーアイウエオカキク';
+ $find = 'ア';
+ $result = Multibyte::strrichr($string, $find, true);
+ $expected = '。「」、・ヲァィゥェォャュョッー';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン゙';
+ $find = 'ハ';
+ $result = Multibyte::strrichr($string, $find);
+ $expected = 'ハヒフヘホマミムメモヤユヨラリルレロワン゙';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン゙';
+ $find = 'ハ';
+ $result = Multibyte::strrichr($string, $find, true);
+ $expected = 'ケコサシスセソタチツテトナニヌネノ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ĥēĺļŏ, Ŵőřļď!';
+ $find = 'ő';
+ $result = Multibyte::strrichr($string, $find);
+ $expected = 'őřļď!';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ĥēĺļŏ, Ŵőřļď!';
+ $find = 'ő';
+ $result = Multibyte::strrichr($string, $find, true);
+ $expected = 'Ĥēĺļŏ, Ŵ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Hello, World!';
+ $find = 'o';
+ $result = Multibyte::strrichr($string, $find);
+ $expected = 'orld!';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Hello, World!';
+ $find = 'o';
+ $result = Multibyte::strrichr($string, $find, true);
+ $expected = 'Hello, W';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Hello, World!';
+ $find = 'Wo';
+ $result = Multibyte::strrichr($string, $find);
+ $expected = 'World!';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Hello, World!';
+ $find = 'Wo';
+ $result = Multibyte::strrichr($string, $find, true);
+ $expected = 'Hello, ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Hello, World!';
+ $find = 'll';
+ $result = Multibyte::strrichr($string, $find);
+ $expected = 'llo, World!';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Hello, World!';
+ $find = 'll';
+ $result = Multibyte::strrichr($string, $find, true);
+ $expected = 'He';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Hello, World!';
+ $find = 'rld';
+ $result = Multibyte::strrichr($string, $find);
+ $expected = 'rld!';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Hello, World!';
+ $find = 'rld';
+ $result = Multibyte::strrichr($string, $find, true);
+ $expected = 'Hello, Wo';
+ $this->assertEqual($result, $expected);
+
+ $string = 'čini';
+ $find = 'n';
+ $result = Multibyte::strrichr($string, $find);
+ $expected = 'ni';
+ $this->assertEqual($result, $expected);
+
+ $string = 'čini';
+ $find = 'n';
+ $result = Multibyte::strrichr($string, $find, true);
+ $expected = 'či';
+ $this->assertEqual($result, $expected);
+
+ $string = 'moći';
+ $find = 'ć';
+ $result = Multibyte::strrichr($string, $find);
+ $expected = 'ći';
+ $this->assertEqual($result, $expected);
+
+ $string = 'moći';
+ $find = 'ć';
+ $result = Multibyte::strrichr($string, $find, true);
+ $expected = 'mo';
+ $this->assertEqual($result, $expected);
+
+ $string = 'državni';
+ $find = 'ž';
+ $result = Multibyte::strrichr($string, $find);
+ $expected = 'žavni';
+ $this->assertEqual($result, $expected);
+
+ $string = 'državni';
+ $find = 'ž';
+ $result = Multibyte::strrichr($string, $find, true);
+ $expected = 'dr';
+ $this->assertEqual($result, $expected);
+
+ $string = '把百度设为首页';
+ $find = '设';
+ $result = Multibyte::strrichr($string, $find);
+ $expected = '设为首页';
+ $this->assertEqual($result, $expected);
+
+ $string = '把百度设为首页';
+ $find = '设';
+ $result = Multibyte::strrichr($string, $find, true);
+ $expected = '把百度';
+ $this->assertEqual($result, $expected);
+
+ $string = '一二三周永龍';
+ $find = '周';
+ $result = Multibyte::strrichr($string, $find);
+ $expected = '周永龍';
+ $this->assertEqual($result, $expected);
+
+ $string = '一二三周永龍';
+ $find = '周';
+ $result = Multibyte::strrichr($string, $find, true);
+ $expected = '一二三';
+ $this->assertEqual($result, $expected);
+
+ $string = '把百度设为首页';
+ $find = '百设';
+ $result = Multibyte::strrichr($string, $find, true);
+ $expected = false;
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testUsingMbStrripos method
+ *
+ * @access public
+ * @return void
+ */
+ function testUsingMbStrripos() {
+ $string = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
+ $find = 'F';
+ $result = mb_strripos($string, $find);
+ $expected = 5;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ABCDEFGHIJKLMNOPQFRSTUVWXYZ0123456789';
+ $find = 'F';
+ $result = mb_strripos($string, $find, 6);
+ $expected = 17;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞ';
+ $find = 'Å';
+ $result = mb_strripos($string, $find);
+ $expected = 5;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÅÙÚÛÜÝÞ';
+ $find = 'Å';
+ $result = mb_strripos($string, $find, 6);
+ $expected = 24;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÅÙÚÛÜÝÞ';
+ $find = 'ÓÔ';
+ $result = mb_strripos($string, $find);
+ $expected = 19;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĀĂĄĆĈĊČĎĐĒĔĖĘĚĜĞĠĢĤĦĨĪĬĮIJĴĶĹĻĽĿŁŃŅŇŊŌŎŐŒŔŖŘŚŜŞŠŢŤŦŨŪŬŮŰŲŴŶŹŻŽ';
+ $find = 'Ċ';
+ $result = mb_strripos($string, $find);
+ $expected = 5;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĀĂĄĆĈĊČĎĐĒĔĖĘĚĜĞĠĢĤĦĨĪĬĮIJĴĶĹĻĽĿŁĊŃŅŇŊŌŎŐŒŔŖŘŚŜŞŠŢŤŦŨŪŬŮŰŲŴŶŹŻŽ';
+ $find = 'Ċ';
+ $result = mb_strripos($string, $find, 6);
+ $expected = 32;
+ $this->assertEqual($result, $expected);
+
+ $string = '!"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~';
+ $find = 'F';
+ $result = mb_strripos($string, $find);
+ $expected = 69;
+ $this->assertEqual($result, $expected);
+
+ $string = '¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈ';
+ $find = 'µ';
+ $result = mb_strripos($string, $find);
+ $expected = 20;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿĀāĂ㥹ĆćĈĉĊċČčĎďĐđĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪīĬ';
+ $find = 'é';
+ $result = mb_strripos($string, $find);
+ $expected = 32;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĭĮįİıIJijĴĵĶķĸĹĺĻļĽľĿŀŁłŃńŅņŇňʼnŊŋŌōŎŏŐőŒœŔŕŖŗŘřŚśŜŝŞşŠšŢţŤťŦŧŨũŪūŬŭŮůŰűŲųŴŵŶŷŸŹźŻżŽžſƀƁƂƃƄƅƆƇƈƉƊƋƌƍƎƏƐ';
+ $find = 'Ņ';
+ $result = mb_strripos($string, $find);
+ $expected = 25;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ƑƒƓƔƕƖƗƘƙƚƛƜƝƞƟƠơƢƣƤƥƦƧƨƩƪƫƬƭƮƯưƱƲƳƴƵƶƷƸƹƺƻƼƽƾƿǀǁǂǃDŽDždžLJLjljNJNjnjǍǎǏǐǑǒǓǔǕǖǗǘǙǚǛǜǝǞǟǠǡǢǣǤǥǦǧǨǩǪǫǬǭǮǯǰDZDzdzǴ';
+ $find = 'Ƹ';
+ $result = mb_strripos($string, $find);
+ $expected = 40;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ƑƒƓƔƕƖƗƘƙƚƛƜƝƞƟƠơƢƣƤƥƦƧƨƩƪƫƬƭƮƯưƱƲƳƴƵƶƷƸƹƺƻƼƽƾƿǀǁǂǃDŽDždžLJLjljNJNjnjǍǎǏǐǑǒǓǔǕǖǗǘǙǚǛǜǝǞǟǠǡǢǣǤǥǦǧǨǩǪǫǬǭǮǯǰDZDzdzǴ';
+ $find = 'ƹ';
+ $result = mb_strripos($string, $find);
+ $expected = 40;
+ $this->assertEqual($result, $expected);
+
+ $string = 'əɚɛɜɝɞɟɠɡɢɣɤɥɦɧɨɩɪɫɬɭɮɯɰɱɲɳɴɵɶɷɸɹɺɻɼɽɾɿʀʁʂʃʄʅʆʇʈʉʊʋʌʍʎʏʐʑʒʓʔʕʖʗʘʙʚʛʜʝʞʟʠʡʢʣʤʥʦʧʨʩʪʫʬʭʮʯʰʱʲʳʴʵʶʷʸʹʺʻʼ';
+ $find = 'ʀ';
+ $result = mb_strripos($string, $find);
+ $expected = 39;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ЀЁЂЃЄЅІЇЈЉЊЋЌЍЎЏАБВГДЕЖЗИЙКЛ';
+ $find = 'Ї';
+ $result = mb_strripos($string, $find);
+ $expected = 7;
+ $this->assertEqual($result, $expected);
+
+ $string = 'МНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыь';
+ $find = 'Р';
+ $result = mb_strripos($string, $find);
+ $expected = 36;
+ $this->assertEqual($result, $expected);
+
+ $string = 'МНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыь';
+ $find = 'р';
+ $result = mb_strripos($string, $find, 5);
+ $expected = 36;
+ $this->assertEqual($result, $expected);
+
+ $string = 'فقكلمنهوىيًٌٍَُ';
+ $find = 'ن';
+ $result = mb_strripos($string, $find);
+ $expected = 5;
+ $this->assertEqual($result, $expected);
+
+ $string = '✰✱✲✳✴✵✶✷✸✹✺✻✼✽✾✿❀❁❂❃❄❅❆❇❈❉❊❋❌❍❎❏❐❑❒❓❔❕❖❗❘❙❚❛❜❝❞';
+ $find = '✿';
+ $result = mb_strripos($string, $find);
+ $expected = 15;
+ $this->assertEqual($result, $expected);
+
+ $string = '⺀⺁⺂⺃⺄⺅⺆⺇⺈⺉⺊⺋⺌⺍⺎⺏⺐⺑⺒⺓⺔⺕⺖⺗⺘⺙⺛⺜⺝⺞⺟⺠⺡⺢⺣⺤⺥⺦⺧⺨⺩⺪⺫⺬⺭⺮⺯⺰⺱⺲⺳⺴⺵⺶⺷⺸⺹⺺⺻⺼⺽⺾⺿⻀⻁⻂⻃⻄⻅⻆⻇⻈⻉⻊⻋⻌⻍⻎⻏⻐⻑⻒⻓⻔⻕⻖⻗⻘⻙⻚⻛⻜⻝⻞⻟⻠';
+ $find = '⺐';
+ $result = mb_strripos($string, $find);
+ $expected = 16;
+ $this->assertEqual($result, $expected);
+
+ $string = '⽅⽆⽇⽈⽉⽊⽋⽌⽍⽎⽏⽐⽑⽒⽓⽔⽕⽖⽗⽘⽙⽚⽛⽜⽝⽞⽟⽠⽡⽢⽣⽤⽥⽦⽧⽨⽩⽪⽫⽬⽭⽮⽯⽰⽱⽲⽳⽴⽵⽶⽷⽸⽹⽺⽻⽼⽽⽾⽿';
+ $find = '⽤';
+ $result = mb_strripos($string, $find);
+ $expected = 31;
+ $this->assertEqual($result, $expected);
+
+ $string = '눡눢눣눤눥눦눧눨눩눪눫눬눭눮눯눰눱눲눳눴눵눶눷눸눹눺눻눼눽눾눿뉀뉁뉂뉃뉄뉅뉆뉇뉈뉉뉊뉋뉌뉍뉎뉏뉐뉑뉒뉓뉔뉕뉖뉗뉘뉙뉚뉛뉜뉝뉞뉟뉠뉡뉢뉣뉤뉥뉦뉧뉨뉩뉪뉫뉬뉭뉮뉯뉰뉱뉲뉳뉴뉵뉶뉷뉸뉹뉺뉻뉼뉽뉾뉿늀늁늂늃늄';
+ $find = '눻';
+ $result = mb_strripos($string, $find);
+ $expected = 26;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ﹰﹱﹲﹳﹴﹶﹷﹸﹹﹺﹻﹼﹽﹾﹿﺀﺁﺂﺃﺄﺅﺆﺇﺈﺉﺊﺋﺌﺍﺎﺏﺐﺑﺒﺓﺔﺕﺖﺗﺘﺙﺚﺛﺜﺝﺞﺟﺠﺡﺢﺣﺤﺥﺦﺧﺨﺩﺪﺫﺬﺭﺮﺯﺰ';
+ $find = 'ﺞ';
+ $result = mb_strripos($string, $find);
+ $expected = 46;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ﺱﺲﺳﺴﺵﺶﺷﺸﺹﺺﺻﺼﺽﺾﺿﻀﻁﻂﻃﻄﻅﻆﻇﻈﻉﻊﻋﻌﻍﻎﻏﻐﻑﻒﻓﻔﻕﻖﻗﻘﻙﻚﻛﻜﻝﻞﻟﻠﻡﻢﻣﻤﻥﻦﻧﻨﻩﻪﻫﻬﻭﻮﻯﻰﻱﻲﻳﻴﻵﻶﻷﻸﻹﻺﻻﻼ';
+ $find = 'ﻞ';
+ $result = mb_strripos($string, $find);
+ $expected = 45;
+ $this->assertEqual($result, $expected);
+
+ $string = 'abcdefghijklmnopqrstuvwxyz';
+ $find = 'k';
+ $result = mb_strripos($string, $find);
+ $expected = 10;
+ $this->assertEqual($result, $expected);
+
+ $string = 'abcdefghijklmnopqrstuvwxyz';
+ $find = 'k';
+ $result = mb_strripos($string, $find);
+ $expected = 10;
+ $this->assertEqual($result, $expected);
+
+ $string = 'abcdefghijklmnoppqrstuvwxyz';
+ $find = 'pp';
+ $result = mb_strripos($string, $find);
+ $expected = 15;
+ $this->assertEqual($result, $expected);
+
+ $string = '。「」、・ヲァィゥェォャュョッーアイウエオカキク';
+ $find = 'ア';
+ $result = mb_strripos($string, $find);
+ $expected = 16;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン゙';
+ $find = 'ハ';
+ $result = mb_strripos($string, $find);
+ $expected = 17;
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ĥēĺļŏ, Ŵőřļď!';
+ $find = 'ő';
+ $result = mb_strripos($string, $find);
+ $expected = 8;
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ĥēĺļŏ, Ŵőřļď!';
+ $find = 'ő';
+ $result = mb_strripos($string, $find);
+ $expected = 8;
+ $this->assertEqual($result, $expected);
+
+ $string = 'Hello, World!';
+ $find = 'o';
+ $result = mb_strripos($string, $find);
+ $expected = 8;
+ $this->assertEqual($result, $expected);
+
+ $string = 'Hello, World!';
+ $find = 'o';
+ $result = mb_strripos($string, $find, 5);
+ $expected = 8;
+ $this->assertEqual($result, $expected);
+
+ $string = 'čini';
+ $find = 'n';
+ $result = mb_strripos($string, $find);
+ $expected = 2;
+ $this->assertEqual($result, $expected);
+
+ $string = 'čini';
+ $find = 'n';
+ $result = mb_strripos($string, $find);
+ $expected = 2;
+ $this->assertEqual($result, $expected);
+
+ $string = 'moći';
+ $find = 'ć';
+ $result = mb_strripos($string, $find);
+ $expected = 2;
+ $this->assertEqual($result, $expected);
+
+ $string = 'moći';
+ $find = 'ć';
+ $result = mb_strripos($string, $find);
+ $expected = 2;
+ $this->assertEqual($result, $expected);
+
+ $string = 'državni';
+ $find = 'ž';
+ $result = mb_strripos($string, $find);
+ $expected = 2;
+ $this->assertEqual($result, $expected);
+
+ $string = '把百度设为首页';
+ $find = '设';
+ $result = mb_strripos($string, $find);
+ $expected = 3;
+ $this->assertEqual($result, $expected);
+
+ $string = '一二三周永龍';
+ $find = '周';
+ $result = mb_strripos($string, $find);
+ $expected = 3;
+ $this->assertEqual($result, $expected);
+
+ $string = 'državni';
+ $find = 'dž';
+ $result = mb_strripos($string, $find);
+ $expected = false;
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testMultibyteStrripos method
+ *
+ * @access public
+ * @return void
+ */
+ function testMultibyteStrripos() {
+ $string = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
+ $find = 'F';
+ $result = Multibyte::strripos($string, $find);
+ $expected = 5;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ABCDEFGHIJKLMNOPQFRSTUVWXYZ0123456789';
+ $find = 'F';
+ $result = Multibyte::strripos($string, $find, 6);
+ $expected = 17;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞ';
+ $find = 'Å';
+ $result = Multibyte::strripos($string, $find);
+ $expected = 5;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÅÙÚÛÜÝÞ';
+ $find = 'Å';
+ $result = Multibyte::strripos($string, $find, 6);
+ $expected = 24;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÅÙÚÛÜÝÞ';
+ $find = 'ÓÔ';
+ $result = Multibyte::strripos($string, $find);
+ $expected = 19;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĀĂĄĆĈĊČĎĐĒĔĖĘĚĜĞĠĢĤĦĨĪĬĮIJĴĶĹĻĽĿŁŃŅŇŊŌŎŐŒŔŖŘŚŜŞŠŢŤŦŨŪŬŮŰŲŴŶŹŻŽ';
+ $find = 'Ċ';
+ $result = Multibyte::strripos($string, $find);
+ $expected = 5;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĀĂĄĆĈĊČĎĐĒĔĖĘĚĜĞĠĢĤĦĨĪĬĮIJĴĶĹĻĽĿŁĊŃŅŇŊŌŎŐŒŔŖŘŚŜŞŠŢŤŦŨŪŬŮŰŲŴŶŹŻŽ';
+ $find = 'Ċ';
+ $result = Multibyte::strripos($string, $find, 6);
+ $expected = 32;
+ $this->assertEqual($result, $expected);
+
+ $string = '!"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~';
+ $find = 'F';
+ $result = Multibyte::strripos($string, $find);
+ $expected = 69;
+ $this->assertEqual($result, $expected);
+
+ $string = '¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈ';
+ $find = 'µ';
+ $result = Multibyte::strripos($string, $find);
+ $expected = 20;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿĀāĂ㥹ĆćĈĉĊċČčĎďĐđĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪīĬ';
+ $find = 'é';
+ $result = Multibyte::strripos($string, $find);
+ $expected = 32;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĭĮįİıIJijĴĵĶķĸĹĺĻļĽľĿŀŁłŃńŅņŇňʼnŊŋŌōŎŏŐőŒœŔŕŖŗŘřŚśŜŝŞşŠšŢţŤťŦŧŨũŪūŬŭŮůŰűŲųŴŵŶŷŸŹźŻżŽžſƀƁƂƃƄƅƆƇƈƉƊƋƌƍƎƏƐ';
+ $find = 'Ņ';
+ $result = Multibyte::strripos($string, $find);
+ $expected = 25;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ƑƒƓƔƕƖƗƘƙƚƛƜƝƞƟƠơƢƣƤƥƦƧƨƩƪƫƬƭƮƯưƱƲƳƴƵƶƷƸƹƺƻƼƽƾƿǀǁǂǃDŽDždžLJLjljNJNjnjǍǎǏǐǑǒǓǔǕǖǗǘǙǚǛǜǝǞǟǠǡǢǣǤǥǦǧǨǩǪǫǬǭǮǯǰDZDzdzǴ';
+ $find = 'Ƹ';
+ $result = Multibyte::strripos($string, $find);
+ $expected = 40;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ƑƒƓƔƕƖƗƘƙƚƛƜƝƞƟƠơƢƣƤƥƦƧƨƩƪƫƬƭƮƯưƱƲƳƴƵƶƷƸƹƺƻƼƽƾƿǀǁǂǃDŽDždžLJLjljNJNjnjǍǎǏǐǑǒǓǔǕǖǗǘǙǚǛǜǝǞǟǠǡǢǣǤǥǦǧǨǩǪǫǬǭǮǯǰDZDzdzǴ';
+ $find = 'ƹ';
+ $result = Multibyte::strripos($string, $find);
+ $expected = 40;
+ $this->assertEqual($result, $expected);
+
+ $string = 'əɚɛɜɝɞɟɠɡɢɣɤɥɦɧɨɩɪɫɬɭɮɯɰɱɲɳɴɵɶɷɸɹɺɻɼɽɾɿʀʁʂʃʄʅʆʇʈʉʊʋʌʍʎʏʐʑʒʓʔʕʖʗʘʙʚʛʜʝʞʟʠʡʢʣʤʥʦʧʨʩʪʫʬʭʮʯʰʱʲʳʴʵʶʷʸʹʺʻʼ';
+ $find = 'ʀ';
+ $result = Multibyte::strripos($string, $find);
+ $expected = 39;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ЀЁЂЃЄЅІЇЈЉЊЋЌЍЎЏАБВГДЕЖЗИЙКЛ';
+ $find = 'Ї';
+ $result = Multibyte::strripos($string, $find);
+ $expected = 7;
+ $this->assertEqual($result, $expected);
+
+ $string = 'МНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыь';
+ $find = 'Р';
+ $result = Multibyte::strripos($string, $find);
+ $expected = 36;
+ $this->assertEqual($result, $expected);
+
+ $string = 'МНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыь';
+ $find = 'р';
+ $result = Multibyte::strripos($string, $find, 5);
+ $expected = 36;
+ $this->assertEqual($result, $expected);
+
+ $string = 'فقكلمنهوىيًٌٍَُ';
+ $find = 'ن';
+ $result = Multibyte::strripos($string, $find);
+ $expected = 5;
+ $this->assertEqual($result, $expected);
+
+ $string = '✰✱✲✳✴✵✶✷✸✹✺✻✼✽✾✿❀❁❂❃❄❅❆❇❈❉❊❋❌❍❎❏❐❑❒❓❔❕❖❗❘❙❚❛❜❝❞';
+ $find = '✿';
+ $result = Multibyte::strripos($string, $find);
+ $expected = 15;
+ $this->assertEqual($result, $expected);
+
+ $string = '⺀⺁⺂⺃⺄⺅⺆⺇⺈⺉⺊⺋⺌⺍⺎⺏⺐⺑⺒⺓⺔⺕⺖⺗⺘⺙⺛⺜⺝⺞⺟⺠⺡⺢⺣⺤⺥⺦⺧⺨⺩⺪⺫⺬⺭⺮⺯⺰⺱⺲⺳⺴⺵⺶⺷⺸⺹⺺⺻⺼⺽⺾⺿⻀⻁⻂⻃⻄⻅⻆⻇⻈⻉⻊⻋⻌⻍⻎⻏⻐⻑⻒⻓⻔⻕⻖⻗⻘⻙⻚⻛⻜⻝⻞⻟⻠';
+ $find = '⺐';
+ $result = Multibyte::strripos($string, $find);
+ $expected = 16;
+ $this->assertEqual($result, $expected);
+
+ $string = '⽅⽆⽇⽈⽉⽊⽋⽌⽍⽎⽏⽐⽑⽒⽓⽔⽕⽖⽗⽘⽙⽚⽛⽜⽝⽞⽟⽠⽡⽢⽣⽤⽥⽦⽧⽨⽩⽪⽫⽬⽭⽮⽯⽰⽱⽲⽳⽴⽵⽶⽷⽸⽹⽺⽻⽼⽽⽾⽿';
+ $find = '⽤';
+ $result = Multibyte::strripos($string, $find);
+ $expected = 31;
+ $this->assertEqual($result, $expected);
+
+ $string = '눡눢눣눤눥눦눧눨눩눪눫눬눭눮눯눰눱눲눳눴눵눶눷눸눹눺눻눼눽눾눿뉀뉁뉂뉃뉄뉅뉆뉇뉈뉉뉊뉋뉌뉍뉎뉏뉐뉑뉒뉓뉔뉕뉖뉗뉘뉙뉚뉛뉜뉝뉞뉟뉠뉡뉢뉣뉤뉥뉦뉧뉨뉩뉪뉫뉬뉭뉮뉯뉰뉱뉲뉳뉴뉵뉶뉷뉸뉹뉺뉻뉼뉽뉾뉿늀늁늂늃늄';
+ $find = '눻';
+ $result = Multibyte::strripos($string, $find);
+ $expected = 26;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ﹰﹱﹲﹳﹴﹶﹷﹸﹹﹺﹻﹼﹽﹾﹿﺀﺁﺂﺃﺄﺅﺆﺇﺈﺉﺊﺋﺌﺍﺎﺏﺐﺑﺒﺓﺔﺕﺖﺗﺘﺙﺚﺛﺜﺝﺞﺟﺠﺡﺢﺣﺤﺥﺦﺧﺨﺩﺪﺫﺬﺭﺮﺯﺰ';
+ $find = 'ﺞ';
+ $result = Multibyte::strripos($string, $find);
+ $expected = 46;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ﺱﺲﺳﺴﺵﺶﺷﺸﺹﺺﺻﺼﺽﺾﺿﻀﻁﻂﻃﻄﻅﻆﻇﻈﻉﻊﻋﻌﻍﻎﻏﻐﻑﻒﻓﻔﻕﻖﻗﻘﻙﻚﻛﻜﻝﻞﻟﻠﻡﻢﻣﻤﻥﻦﻧﻨﻩﻪﻫﻬﻭﻮﻯﻰﻱﻲﻳﻴﻵﻶﻷﻸﻹﻺﻻﻼ';
+ $find = 'ﻞ';
+ $result = Multibyte::strripos($string, $find);
+ $expected = 45;
+ $this->assertEqual($result, $expected);
+
+ $string = 'abcdefghijklmnopqrstuvwxyz';
+ $find = 'k';
+ $result = Multibyte::strripos($string, $find);
+ $expected = 10;
+ $this->assertEqual($result, $expected);
+
+ $string = 'abcdefghijklmnopqrstuvwxyz';
+ $find = 'k';
+ $result = Multibyte::strripos($string, $find);
+ $expected = 10;
+ $this->assertEqual($result, $expected);
+
+ $string = 'abcdefghijklmnoppqrstuvwxyz';
+ $find = 'pp';
+ $result = Multibyte::strripos($string, $find);
+ $expected = 15;
+ $this->assertEqual($result, $expected);
+
+ $string = '。「」、・ヲァィゥェォャュョッーアイウエオカキク';
+ $find = 'ア';
+ $result = Multibyte::strripos($string, $find);
+ $expected = 16;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン゙';
+ $find = 'ハ';
+ $result = Multibyte::strripos($string, $find);
+ $expected = 17;
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ĥēĺļŏ, Ŵőřļď!';
+ $find = 'ő';
+ $result = Multibyte::strripos($string, $find);
+ $expected = 8;
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ĥēĺļŏ, Ŵőřļď!';
+ $find = 'ő';
+ $result = Multibyte::strripos($string, $find);
+ $expected = 8;
+ $this->assertEqual($result, $expected);
+
+ $string = 'Hello, World!';
+ $find = 'o';
+ $result = Multibyte::strripos($string, $find);
+ $expected = 8;
+ $this->assertEqual($result, $expected);
+
+ $string = 'Hello, World!';
+ $find = 'o';
+ $result = Multibyte::strripos($string, $find, 5);
+ $expected = 8;
+ $this->assertEqual($result, $expected);
+
+ $string = 'čini';
+ $find = 'n';
+ $result = Multibyte::strripos($string, $find);
+ $expected = 2;
+ $this->assertEqual($result, $expected);
+
+ $string = 'čini';
+ $find = 'n';
+ $result = Multibyte::strripos($string, $find);
+ $expected = 2;
+ $this->assertEqual($result, $expected);
+
+ $string = 'moći';
+ $find = 'ć';
+ $result = Multibyte::strripos($string, $find);
+ $expected = 2;
+ $this->assertEqual($result, $expected);
+
+ $string = 'moći';
+ $find = 'ć';
+ $result = Multibyte::strripos($string, $find);
+ $expected = 2;
+ $this->assertEqual($result, $expected);
+
+ $string = 'državni';
+ $find = 'ž';
+ $result = Multibyte::strripos($string, $find);
+ $expected = 2;
+ $this->assertEqual($result, $expected);
+
+ $string = '把百度设为首页';
+ $find = '设';
+ $result = Multibyte::strripos($string, $find);
+ $expected = 3;
+ $this->assertEqual($result, $expected);
+
+ $string = '一二三周永龍';
+ $find = '周';
+ $result = Multibyte::strripos($string, $find);
+ $expected = 3;
+ $this->assertEqual($result, $expected);
+
+ $string = 'državni';
+ $find = 'dž';
+ $result = Multibyte::strripos($string, $find);
+ $expected = false;
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testUsingMbStrrpos method
+ *
+ * @access public
+ * @return void
+ */
+ function testUsingMbStrrpos() {
+ $skip = extension_loaded('mbstring') && version_compare(PHP_VERSION, '5.2.0', '<');
+ if ($this->skipIf($skip, '%s PHP version does not support $offset parameter in mb_strrpos().')) {
+ return;
+ }
+ $string = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
+ $find = 'F';
+ $result = mb_strrpos($string, $find);
+ $expected = 5;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ABCDEFGHIJKLMNOPQFRSTUVWXYZ0123456789';
+ $find = 'F';
+ $result = mb_strrpos($string, $find, 6);
+ $expected = 17;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞ';
+ $find = 'Å';
+ $result = mb_strrpos($string, $find);
+ $expected = 5;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÅÙÚÛÜÝÞ';
+ $find = 'ÙÚ';
+ $result = mb_strrpos($string, $find);
+ $expected = 25;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÅÙÚÛÜÝÞ';
+ $find = 'Å';
+ $result = mb_strrpos($string, $find, 6);
+ $expected = 24;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĀĂĄĆĈĊČĎĐĒĔĖĘĚĜĞĠĢĤĦĨĪĬĮIJĴĶĹĻĽĿŁŃŅŇŊŌŎŐŒŔŖŘŚŜŞŠŢŤŦŨŪŬŮŰŲŴŶŹŻŽ';
+ $find = 'Ċ';
+ $result = mb_strrpos($string, $find);
+ $expected = 5;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĀĂĄĆĈĊČĎĐĒĔĖĘĚĜĞĠĢĤĦĨĪĬĮIJĴĶĹĻĽĿŁĊŃŅŇŊŌŎŐŒŔŖŘŚŜŞŠŢŤŦŨŪŬŮŰŲŴŶŹŻŽ';
+ $find = 'Ċ';
+ $result = mb_strrpos($string, $find, 6);
+ $expected = 32;
+ $this->assertEqual($result, $expected);
+
+ $string = '!"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~';
+ $find = 'F';
+ $result = mb_strrpos($string, $find);
+ $expected = 37;
+ $this->assertEqual($result, $expected);
+
+ $string = '¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈ';
+ $find = 'µ';
+ $result = mb_strrpos($string, $find);
+ $expected = 20;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿĀāĂ㥹ĆćĈĉĊċČčĎďĐđĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪīĬ';
+ $find = 'é';
+ $result = mb_strrpos($string, $find);
+ $expected = 32;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĭĮįİıIJijĴĵĶķĸĹĺĻļĽľĿŀŁłŃńŅņŇňʼnŊŋŌōŎŏŐőŒœŔŕŖŗŘřŚśŜŝŞşŠšŢţŤťŦŧŨũŪūŬŭŮůŰűŲųŴŵŶŷŸŹźŻżŽžſƀƁƂƃƄƅƆƇƈƉƊƋƌƍƎƏƐ';
+ $find = 'Ņ';
+ $result = mb_strrpos($string, $find);
+ $expected = 24;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ƑƒƓƔƕƖƗƘƙƚƛƜƝƞƟƠơƢƣƤƥƦƧƨƩƪƫƬƭƮƯưƱƲƳƴƵƶƷƸƹƺƻƼƽƾƿǀǁǂǃDŽDždžLJLjljNJNjnjǍǎǏǐǑǒǓǔǕǖǗǘǙǚǛǜǝǞǟǠǡǢǣǤǥǦǧǨǩǪǫǬǭǮǯǰDZDzdzǴ';
+ $find = 'Ƹ';
+ $result = mb_strrpos($string, $find);
+ $expected = 39;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ƑƒƓƔƕƖƗƘƙƚƛƜƝƞƟƠơƢƣƤƥƦƧƨƩƪƫƬƭƮƯưƱƲƳƴƵƶƷƸƹƺƻƼƽƾƿǀǁǂǃDŽDždžLJLjljNJNjnjǍǎǏǐǑǒǓǔǕǖǗǘǙǚǛǜǝǞǟǠǡǢǣǤǥǦǧǨǩǪǫǬǭǮǯǰDZDzdzǴ';
+ $find = 'ƹ';
+ $result = mb_strrpos($string, $find);
+ $expected = 40;
+ $this->assertEqual($result, $expected);
+
+ $string = 'əɚɛɜɝɞɟɠɡɢɣɤɥɦɧɨɩɪɫɬɭɮɯɰɱɲɳɴɵɶɷɸɹɺɻɼɽɾɿʀʁʂʃʄʅʆʇʈʉʊʋʌʍʎʏʐʑʒʓʔʕʖʗʘʙʚʛʜʝʞʟʠʡʢʣʤʥʦʧʨʩʪʫʬʭʮʯʰʱʲʳʴʵʶʷʸʹʺʻʼ';
+ $find = 'ʀ';
+ $result = mb_strrpos($string, $find);
+ $expected = 39;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ЀЁЂЃЄЅІЇЈЉЊЋЌЍЎЏАБВГДЕЖЗИЙКЛ';
+ $find = 'Ї';
+ $result = mb_strrpos($string, $find);
+ $expected = 7;
+ $this->assertEqual($result, $expected);
+
+ $string = 'МНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыь';
+ $find = 'Р';
+ $result = mb_strrpos($string, $find);
+ $expected = 4;
+ $this->assertEqual($result, $expected);
+
+ $string = 'МНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыь';
+ $find = 'р';
+ $result = mb_strrpos($string, $find, 5);
+ $expected = 36;
+ $this->assertEqual($result, $expected);
+
+ $string = 'فقكلمنهوىيًٌٍَُ';
+ $find = 'ن';
+ $result = mb_strrpos($string, $find);
+ $expected = 5;
+ $this->assertEqual($result, $expected);
+
+ $string = '✰✱✲✳✴✵✶✷✸✹✺✻✼✽✾✿❀❁❂❃❄❅❆❇❈❉❊❋❌❍❎❏❐❑❒❓❔❕❖❗❘❙❚❛❜❝❞';
+ $find = '✿';
+ $result = mb_strrpos($string, $find);
+ $expected = 15;
+ $this->assertEqual($result, $expected);
+
+ $string = '⺀⺁⺂⺃⺄⺅⺆⺇⺈⺉⺊⺋⺌⺍⺎⺏⺐⺑⺒⺓⺔⺕⺖⺗⺘⺙⺛⺜⺝⺞⺟⺠⺡⺢⺣⺤⺥⺦⺧⺨⺩⺪⺫⺬⺭⺮⺯⺰⺱⺲⺳⺴⺵⺶⺷⺸⺹⺺⺻⺼⺽⺾⺿⻀⻁⻂⻃⻄⻅⻆⻇⻈⻉⻊⻋⻌⻍⻎⻏⻐⻑⻒⻓⻔⻕⻖⻗⻘⻙⻚⻛⻜⻝⻞⻟⻠';
+ $find = '⺐';
+ $result = mb_strrpos($string, $find);
+ $expected = 16;
+ $this->assertEqual($result, $expected);
+
+ $string = '⽅⽆⽇⽈⽉⽊⽋⽌⽍⽎⽏⽐⽑⽒⽓⽔⽕⽖⽗⽘⽙⽚⽛⽜⽝⽞⽟⽠⽡⽢⽣⽤⽥⽦⽧⽨⽩⽪⽫⽬⽭⽮⽯⽰⽱⽲⽳⽴⽵⽶⽷⽸⽹⽺⽻⽼⽽⽾⽿';
+ $find = '⽤';
+ $result = mb_strrpos($string, $find);
+ $expected = 31;
+ $this->assertEqual($result, $expected);
+
+ $string = '눡눢눣눤눥눦눧눨눩눪눫눬눭눮눯눰눱눲눳눴눵눶눷눸눹눺눻눼눽눾눿뉀뉁뉂뉃뉄뉅뉆뉇뉈뉉뉊뉋뉌뉍뉎뉏뉐뉑뉒뉓뉔뉕뉖뉗뉘뉙뉚뉛뉜뉝뉞뉟뉠뉡뉢뉣뉤뉥뉦뉧뉨뉩뉪뉫뉬뉭뉮뉯뉰뉱뉲뉳뉴뉵뉶뉷뉸뉹뉺뉻뉼뉽뉾뉿늀늁늂늃늄';
+ $find = '눻';
+ $result = mb_strrpos($string, $find);
+ $expected = 26;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ﹰﹱﹲﹳﹴﹶﹷﹸﹹﹺﹻﹼﹽﹾﹿﺀﺁﺂﺃﺄﺅﺆﺇﺈﺉﺊﺋﺌﺍﺎﺏﺐﺑﺒﺓﺔﺕﺖﺗﺘﺙﺚﺛﺜﺝﺞﺟﺠﺡﺢﺣﺤﺥﺦﺧﺨﺩﺪﺫﺬﺭﺮﺯﺰ';
+ $find = 'ﺞ';
+ $result = mb_strrpos($string, $find);
+ $expected = 46;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ﺱﺲﺳﺴﺵﺶﺷﺸﺹﺺﺻﺼﺽﺾﺿﻀﻁﻂﻃﻄﻅﻆﻇﻈﻉﻊﻋﻌﻍﻎﻏﻐﻑﻒﻓﻔﻕﻖﻗﻘﻙﻚﻛﻜﻝﻞﻟﻠﻡﻢﻣﻤﻥﻦﻧﻨﻩﻪﻫﻬﻭﻮﻯﻰﻱﻲﻳﻴﻵﻶﻷﻸﻹﻺﻻﻼ';
+ $find = 'ﻞ';
+ $result = mb_strrpos($string, $find);
+ $expected = 45;
+ $this->assertEqual($result, $expected);
+
+ $string = 'abcdefghijklmnopqrstuvwxyz';
+ $find = 'k';
+ $result = mb_strrpos($string, $find);
+ $expected = 10;
+ $this->assertEqual($result, $expected);
+
+ $string = 'abcdefghijklmnopqrstuvwxyz';
+ $find = 'k';
+ $result = mb_strrpos($string, $find);
+ $expected = 10;
+ $this->assertEqual($result, $expected);
+
+ $string = 'abcdefghijklmnoppqrstuvwxyz';
+ $find = 'pp';
+ $result = mb_strrpos($string, $find);
+ $expected = 15;
+ $this->assertEqual($result, $expected);
+
+ $string = '。「」、・ヲァィゥェォャュョッーアイウエオカキク';
+ $find = 'ア';
+ $result = mb_strrpos($string, $find);
+ $expected = 16;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン゙';
+ $find = 'ハ';
+ $result = mb_strrpos($string, $find);
+ $expected = 17;
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ĥēĺļŏ, Ŵőřļď!';
+ $find = 'ő';
+ $result = mb_strrpos($string, $find);
+ $expected = 8;
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ĥēĺļŏ, Ŵőřļď!';
+ $find = 'ő';
+ $result = mb_strrpos($string, $find);
+ $expected = 8;
+ $this->assertEqual($result, $expected);
+
+ $string = 'Hello, World!';
+ $find = 'o';
+ $result = mb_strrpos($string, $find);
+ $expected = 8;
+ $this->assertEqual($result, $expected);
+
+ $string = 'Hello, World!';
+ $find = 'o';
+ $result = mb_strrpos($string, $find, 5);
+ $expected = 8;
+ $this->assertEqual($result, $expected);
+
+ $string = 'čini';
+ $find = 'n';
+ $result = mb_strrpos($string, $find);
+ $expected = 2;
+ $this->assertEqual($result, $expected);
+
+ $string = 'čini';
+ $find = 'n';
+ $result = mb_strrpos($string, $find);
+ $expected = 2;
+ $this->assertEqual($result, $expected);
+
+ $string = 'moći';
+ $find = 'ć';
+ $result = mb_strrpos($string, $find);
+ $expected = 2;
+ $this->assertEqual($result, $expected);
+
+ $string = 'moći';
+ $find = 'ć';
+ $result = mb_strrpos($string, $find);
+ $expected = 2;
+ $this->assertEqual($result, $expected);
+
+ $string = 'državni';
+ $find = 'ž';
+ $result = mb_strrpos($string, $find);
+ $expected = 2;
+ $this->assertEqual($result, $expected);
+
+ $string = '把百度设为首页';
+ $find = '设';
+ $result = mb_strrpos($string, $find);
+ $expected = 3;
+ $this->assertEqual($result, $expected);
+
+ $string = '一二三周永龍';
+ $find = '周';
+ $result = mb_strrpos($string, $find);
+ $expected = 3;
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ĥēĺļŏ, Ŵőřļď!';
+ $find = 'H';
+ $result = mb_strrpos($string, $find);
+ $expected = false;
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testMultibyteStrrpos method
+ *
+ * @access public
+ * @return void
+ */
+ function testMultibyteStrrpos() {
+ $string = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
+ $find = 'F';
+ $result = Multibyte::strrpos($string, $find);
+ $expected = 5;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ABCDEFGHIJKLMNOPQFRSTUVWXYZ0123456789';
+ $find = 'F';
+ $result = Multibyte::strrpos($string, $find, 6);
+ $expected = 17;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞ';
+ $find = 'Å';
+ $result = Multibyte::strrpos($string, $find);
+ $expected = 5;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÅÙÚÛÜÝÞ';
+ $find = 'Å';
+ $result = Multibyte::strrpos($string, $find, 6);
+ $expected = 24;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÅÙÚÛÜÝÞ';
+ $find = 'ÙÚ';
+ $result = Multibyte::strrpos($string, $find);
+ $expected = 25;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĀĂĄĆĈĊČĎĐĒĔĖĘĚĜĞĠĢĤĦĨĪĬĮIJĴĶĹĻĽĿŁŃŅŇŊŌŎŐŒŔŖŘŚŜŞŠŢŤŦŨŪŬŮŰŲŴŶŹŻŽ';
+ $find = 'Ċ';
+ $result = Multibyte::strrpos($string, $find);
+ $expected = 5;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĀĂĄĆĈĊČĎĐĒĔĖĘĚĜĞĠĢĤĦĨĪĬĮIJĴĶĹĻĽĿŁĊŃŅŇŊŌŎŐŒŔŖŘŚŜŞŠŢŤŦŨŪŬŮŰŲŴŶŹŻŽ';
+ $find = 'Ċ';
+ $result = Multibyte::strrpos($string, $find, 6);
+ $expected = 32;
+ $this->assertEqual($result, $expected);
+
+ $string = '!"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~';
+ $find = 'F';
+ $result = Multibyte::strrpos($string, $find);
+ $expected = 37;
+ $this->assertEqual($result, $expected);
+
+ $string = '¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈ';
+ $find = 'µ';
+ $result = Multibyte::strrpos($string, $find);
+ $expected = 20;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿĀāĂ㥹ĆćĈĉĊċČčĎďĐđĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪīĬ';
+ $find = 'é';
+ $result = Multibyte::strrpos($string, $find);
+ $expected = 32;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĭĮįİıIJijĴĵĶķĸĹĺĻļĽľĿŀŁłŃńŅņŇňʼnŊŋŌōŎŏŐőŒœŔŕŖŗŘřŚśŜŝŞşŠšŢţŤťŦŧŨũŪūŬŭŮůŰűŲųŴŵŶŷŸŹźŻżŽžſƀƁƂƃƄƅƆƇƈƉƊƋƌƍƎƏƐ';
+ $find = 'Ņ';
+ $result = Multibyte::strrpos($string, $find);
+ $expected = 24;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ƑƒƓƔƕƖƗƘƙƚƛƜƝƞƟƠơƢƣƤƥƦƧƨƩƪƫƬƭƮƯưƱƲƳƴƵƶƷƸƹƺƻƼƽƾƿǀǁǂǃDŽDždžLJLjljNJNjnjǍǎǏǐǑǒǓǔǕǖǗǘǙǚǛǜǝǞǟǠǡǢǣǤǥǦǧǨǩǪǫǬǭǮǯǰDZDzdzǴ';
+ $find = 'Ƹ';
+ $result = Multibyte::strrpos($string, $find);
+ $expected = 39;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ƑƒƓƔƕƖƗƘƙƚƛƜƝƞƟƠơƢƣƤƥƦƧƨƩƪƫƬƭƮƯưƱƲƳƴƵƶƷƸƹƺƻƼƽƾƿǀǁǂǃDŽDždžLJLjljNJNjnjǍǎǏǐǑǒǓǔǕǖǗǘǙǚǛǜǝǞǟǠǡǢǣǤǥǦǧǨǩǪǫǬǭǮǯǰDZDzdzǴ';
+ $find = 'ƹ';
+ $result = Multibyte::strrpos($string, $find);
+ $expected = 40;
+ $this->assertEqual($result, $expected);
+
+ $string = 'əɚɛɜɝɞɟɠɡɢɣɤɥɦɧɨɩɪɫɬɭɮɯɰɱɲɳɴɵɶɷɸɹɺɻɼɽɾɿʀʁʂʃʄʅʆʇʈʉʊʋʌʍʎʏʐʑʒʓʔʕʖʗʘʙʚʛʜʝʞʟʠʡʢʣʤʥʦʧʨʩʪʫʬʭʮʯʰʱʲʳʴʵʶʷʸʹʺʻʼ';
+ $find = 'ʀ';
+ $result = Multibyte::strrpos($string, $find);
+ $expected = 39;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ЀЁЂЃЄЅІЇЈЉЊЋЌЍЎЏАБВГДЕЖЗИЙКЛ';
+ $find = 'Ї';
+ $result = Multibyte::strrpos($string, $find);
+ $expected = 7;
+ $this->assertEqual($result, $expected);
+
+ $string = 'МНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыь';
+ $find = 'Р';
+ $result = Multibyte::strrpos($string, $find);
+ $expected = 4;
+ $this->assertEqual($result, $expected);
+
+ $string = 'МНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыь';
+ $find = 'р';
+ $result = Multibyte::strrpos($string, $find, 5);
+ $expected = 36;
+ $this->assertEqual($result, $expected);
+
+ $string = 'فقكلمنهوىيًٌٍَُ';
+ $find = 'ن';
+ $result = Multibyte::strrpos($string, $find);
+ $expected = 5;
+ $this->assertEqual($result, $expected);
+
+ $string = '✰✱✲✳✴✵✶✷✸✹✺✻✼✽✾✿❀❁❂❃❄❅❆❇❈❉❊❋❌❍❎❏❐❑❒❓❔❕❖❗❘❙❚❛❜❝❞';
+ $find = '✿';
+ $result = Multibyte::strrpos($string, $find);
+ $expected = 15;
+ $this->assertEqual($result, $expected);
+
+ $string = '⺀⺁⺂⺃⺄⺅⺆⺇⺈⺉⺊⺋⺌⺍⺎⺏⺐⺑⺒⺓⺔⺕⺖⺗⺘⺙⺛⺜⺝⺞⺟⺠⺡⺢⺣⺤⺥⺦⺧⺨⺩⺪⺫⺬⺭⺮⺯⺰⺱⺲⺳⺴⺵⺶⺷⺸⺹⺺⺻⺼⺽⺾⺿⻀⻁⻂⻃⻄⻅⻆⻇⻈⻉⻊⻋⻌⻍⻎⻏⻐⻑⻒⻓⻔⻕⻖⻗⻘⻙⻚⻛⻜⻝⻞⻟⻠';
+ $find = '⺐';
+ $result = Multibyte::strrpos($string, $find);
+ $expected = 16;
+ $this->assertEqual($result, $expected);
+
+ $string = '⽅⽆⽇⽈⽉⽊⽋⽌⽍⽎⽏⽐⽑⽒⽓⽔⽕⽖⽗⽘⽙⽚⽛⽜⽝⽞⽟⽠⽡⽢⽣⽤⽥⽦⽧⽨⽩⽪⽫⽬⽭⽮⽯⽰⽱⽲⽳⽴⽵⽶⽷⽸⽹⽺⽻⽼⽽⽾⽿';
+ $find = '⽤';
+ $result = Multibyte::strrpos($string, $find);
+ $expected = 31;
+ $this->assertEqual($result, $expected);
+
+ $string = '눡눢눣눤눥눦눧눨눩눪눫눬눭눮눯눰눱눲눳눴눵눶눷눸눹눺눻눼눽눾눿뉀뉁뉂뉃뉄뉅뉆뉇뉈뉉뉊뉋뉌뉍뉎뉏뉐뉑뉒뉓뉔뉕뉖뉗뉘뉙뉚뉛뉜뉝뉞뉟뉠뉡뉢뉣뉤뉥뉦뉧뉨뉩뉪뉫뉬뉭뉮뉯뉰뉱뉲뉳뉴뉵뉶뉷뉸뉹뉺뉻뉼뉽뉾뉿늀늁늂늃늄';
+ $find = '눻';
+ $result = Multibyte::strrpos($string, $find);
+ $expected = 26;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ﹰﹱﹲﹳﹴﹶﹷﹸﹹﹺﹻﹼﹽﹾﹿﺀﺁﺂﺃﺄﺅﺆﺇﺈﺉﺊﺋﺌﺍﺎﺏﺐﺑﺒﺓﺔﺕﺖﺗﺘﺙﺚﺛﺜﺝﺞﺟﺠﺡﺢﺣﺤﺥﺦﺧﺨﺩﺪﺫﺬﺭﺮﺯﺰ';
+ $find = 'ﺞ';
+ $result = Multibyte::strrpos($string, $find);
+ $expected = 46;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ﺱﺲﺳﺴﺵﺶﺷﺸﺹﺺﺻﺼﺽﺾﺿﻀﻁﻂﻃﻄﻅﻆﻇﻈﻉﻊﻋﻌﻍﻎﻏﻐﻑﻒﻓﻔﻕﻖﻗﻘﻙﻚﻛﻜﻝﻞﻟﻠﻡﻢﻣﻤﻥﻦﻧﻨﻩﻪﻫﻬﻭﻮﻯﻰﻱﻲﻳﻴﻵﻶﻷﻸﻹﻺﻻﻼ';
+ $find = 'ﻞ';
+ $result = Multibyte::strrpos($string, $find);
+ $expected = 45;
+ $this->assertEqual($result, $expected);
+
+ $string = 'abcdefghijklmnopqrstuvwxyz';
+ $find = 'k';
+ $result = Multibyte::strrpos($string, $find);
+ $expected = 10;
+ $this->assertEqual($result, $expected);
+
+ $string = 'abcdefghijklmnopqrstuvwxyz';
+ $find = 'k';
+ $result = Multibyte::strrpos($string, $find);
+ $expected = 10;
+ $this->assertEqual($result, $expected);
+
+ $string = 'abcdefghijklmnoppqrstuvwxyz';
+ $find = 'pp';
+ $result = Multibyte::strrpos($string, $find);
+ $expected = 15;
+ $this->assertEqual($result, $expected);
+
+ $string = '。「」、・ヲァィゥェォャュョッーアイウエオカキク';
+ $find = 'ア';
+ $result = Multibyte::strrpos($string, $find);
+ $expected = 16;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン゙';
+ $find = 'ハ';
+ $result = Multibyte::strrpos($string, $find);
+ $expected = 17;
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ĥēĺļŏ, Ŵőřļď!';
+ $find = 'ő';
+ $result = Multibyte::strrpos($string, $find);
+ $expected = 8;
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ĥēĺļŏ, Ŵőřļď!';
+ $find = 'ő';
+ $result = Multibyte::strrpos($string, $find);
+ $expected = 8;
+ $this->assertEqual($result, $expected);
+
+ $string = 'Hello, World!';
+ $find = 'o';
+ $result = Multibyte::strrpos($string, $find);
+ $expected = 8;
+ $this->assertEqual($result, $expected);
+
+ $string = 'Hello, World!';
+ $find = 'o';
+ $result = Multibyte::strrpos($string, $find, 5);
+ $expected = 8;
+ $this->assertEqual($result, $expected);
+
+ $string = 'čini';
+ $find = 'n';
+ $result = Multibyte::strrpos($string, $find);
+ $expected = 2;
+ $this->assertEqual($result, $expected);
+
+ $string = 'čini';
+ $find = 'n';
+ $result = Multibyte::strrpos($string, $find);
+ $expected = 2;
+ $this->assertEqual($result, $expected);
+
+ $string = 'moći';
+ $find = 'ć';
+ $result = Multibyte::strrpos($string, $find);
+ $expected = 2;
+ $this->assertEqual($result, $expected);
+
+ $string = 'moći';
+ $find = 'ć';
+ $result = Multibyte::strrpos($string, $find);
+ $expected = 2;
+ $this->assertEqual($result, $expected);
+
+ $string = 'državni';
+ $find = 'ž';
+ $result = Multibyte::strrpos($string, $find);
+ $expected = 2;
+ $this->assertEqual($result, $expected);
+
+ $string = '把百度设为首页';
+ $find = '设';
+ $result = Multibyte::strrpos($string, $find);
+ $expected = 3;
+ $this->assertEqual($result, $expected);
+
+ $string = '一二三周永龍';
+ $find = '周';
+ $result = Multibyte::strrpos($string, $find);
+ $expected = 3;
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ĥēĺļŏ, Ŵőřļď!';
+ $find = 'H';
+ $result = Multibyte::strrpos($string, $find);
+ $expected = false;
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testUsingMbStrstr method
+ *
+ * @access public
+ * @return void
+ */
+ function testUsingMbStrstr() {
+ $string = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
+ $find = 'F';
+ $result = mb_strstr($string, $find);
+ $expected = 'FGHIJKLMNOPQRSTUVWXYZ0123456789';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
+ $find = 'F';
+ $result = mb_strstr($string, $find, true);
+ $expected = 'ABCDE';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞ';
+ $find = 'Å';
+ $result = mb_strstr($string, $find);
+ $expected = 'ÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞ';
+ $find = 'Å';
+ $result = mb_strstr($string, $find, true);
+ $expected = 'ÀÁÂÃÄ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĀĂĄĆĈĊČĎĐĒĔĖĘĚĜĞĠĢĤĦĨĪĬĮIJĴĶĹĻĽĿŁŃŅŇŊŌŎŐŒŔŖŘŚŜŞŠŢŤŦŨŪŬŮŰŲŴŶŹŻŽ';
+ $find = 'Ċ';
+ $result = mb_strstr($string, $find);
+ $expected = 'ĊČĎĐĒĔĖĘĚĜĞĠĢĤĦĨĪĬĮIJĴĶĹĻĽĿŁŃŅŇŊŌŎŐŒŔŖŘŚŜŞŠŢŤŦŨŪŬŮŰŲŴŶŹŻŽ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĀĂĄĆĈĊČĎĐĒĔĖĘĚĜĞĠĢĤĦĨĪĬĮIJĴĶĹĻĽĿŁŃŅŇŊŌŎŐŒŔŖŘŚŜŞŠŢŤŦŨŪŬŮŰŲŴŶŹŻŽ';
+ $find = 'Ċ';
+ $result = mb_strstr($string, $find, true);
+ $expected = 'ĀĂĄĆĈ';
+ $this->assertEqual($result, $expected);
+
+ $string = '!"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~';
+ $find = 'F';
+ $result = mb_strstr($string, $find);
+ $expected = 'FGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~';
+ $this->assertEqual($result, $expected);
+
+ $string = '!"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~';
+ $find = 'F';
+ $result = mb_strstr($string, $find, true);
+ $expected = '!"#$%&\'()*+,-./0123456789:;<=>?@ABCDE';
+ $this->assertEqual($result, $expected);
+
+ $string = '¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈ';
+ $find = 'µ';
+ $result = mb_strstr($string, $find);
+ $expected = 'µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈ';
+ $this->assertEqual($result, $expected);
+
+ $string = '¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈ';
+ $find = 'µ';
+ $result = mb_strstr($string, $find, true);
+ $expected = '¡¢£¤¥¦§¨©ª«¬®¯°±²³´';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿĀāĂ㥹ĆćĈĉĊċČčĎďĐđĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪīĬ';
+ $find = 'Þ';
+ $result = mb_strstr($string, $find);
+ $expected = 'Þßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿĀāĂ㥹ĆćĈĉĊċČčĎďĐđĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪīĬ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿĀāĂ㥹ĆćĈĉĊċČčĎďĐđĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪīĬ';
+ $find = 'Þ';
+ $result = mb_strstr($string, $find, true);
+ $expected = 'ÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĭĮįİıIJijĴĵĶķĸĹĺĻļĽľĿŀŁłŃńŅņŇňʼnŊŋŌōŎŏŐőŒœŔŕŖŗŘřŚśŜŝŞşŠšŢţŤťŦŧŨũŪūŬŭŮůŰűŲųŴŵŶŷŸŹźŻżŽžſƀƁƂƃƄƅƆƇƈƉƊƋƌƍƎƏƐ';
+ $find = 'Ņ';
+ $result = mb_strstr($string, $find);
+ $expected = 'ŅņŇňʼnŊŋŌōŎŏŐőŒœŔŕŖŗŘřŚśŜŝŞşŠšŢţŤťŦŧŨũŪūŬŭŮůŰűŲųŴŵŶŷŸŹźŻżŽžſƀƁƂƃƄƅƆƇƈƉƊƋƌƍƎƏƐ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĭĮįİıIJijĴĵĶķĸĹĺĻļĽľĿŀŁłŃńŅņŇňʼnŊŋŌōŎŏŐőŒœŔŕŖŗŘřŚśŜŝŞşŠšŢţŤťŦŧŨũŪūŬŭŮůŰűŲųŴŵŶŷŸŹźŻżŽžſƀƁƂƃƄƅƆƇƈƉƊƋƌƍƎƏƐ';
+ $find = 'Ņ';
+ $result = mb_strstr($string, $find, true);
+ $expected = 'ĭĮįİıIJijĴĵĶķĸĹĺĻļĽľĿŀŁłŃń';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ƑƒƓƔƕƖƗƘƙƚƛƜƝƞƟƠơƢƣƤƥƦƧƨƩƪƫƬƭƮƯưƱƲƳƴƵƶƷƸƹƺƻƼƽƾƿǀǁǂǃDŽDždžLJLjljNJNjnjǍǎǏǐǑǒǓǔǕǖǗǘǙǚǛǜǝǞǟǠǡǢǣǤǥǦǧǨǩǪǫǬǭǮǯǰDZDzdzǴ';
+ $find = 'Ƹ';
+ $result = mb_strstr($string, $find);
+ $expected = 'ƸƹƺƻƼƽƾƿǀǁǂǃDŽDždžLJLjljNJNjnjǍǎǏǐǑǒǓǔǕǖǗǘǙǚǛǜǝǞǟǠǡǢǣǤǥǦǧǨǩǪǫǬǭǮǯǰDZDzdzǴ';
+ $this->assertEqual($result, $expected);
+
+ $find = 'Ƹ';
+ $result = mb_strstr($string, $find, true);
+ $expected = 'ƑƒƓƔƕƖƗƘƙƚƛƜƝƞƟƠơƢƣƤƥƦƧƨƩƪƫƬƭƮƯưƱƲƳƴƵƶƷ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'əɚɛɜɝɞɟɠɡɢɣɤɥɦɧɨɩɪɫɬɭɮɯɰɱɲɳɴɵɶɷɸɹɺɻɼɽɾɿʀʁʂʃʄʅʆʇʈʉʊʋʌʍʎʏʐʑʒʓʔʕʖʗʘʙʚʛʜʝʞʟʠʡʢʣʤʥʦʧʨʩʪʫʬʭʮʯʰʱʲʳʴʵʶʷʸʹʺʻʼ';
+ $find = 'ʀ';
+ $result = mb_strstr($string, $find);
+ $expected = 'ʀʁʂʃʄʅʆʇʈʉʊʋʌʍʎʏʐʑʒʓʔʕʖʗʘʙʚʛʜʝʞʟʠʡʢʣʤʥʦʧʨʩʪʫʬʭʮʯʰʱʲʳʴʵʶʷʸʹʺʻʼ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'əɚɛɜɝɞɟɠɡɢɣɤɥɦɧɨɩɪɫɬɭɮɯɰɱɲɳɴɵɶɷɸɹɺɻɼɽɾɿʀʁʂʃʄʅʆʇʈʉʊʋʌʍʎʏʐʑʒʓʔʕʖʗʘʙʚʛʜʝʞʟʠʡʢʣʤʥʦʧʨʩʪʫʬʭʮʯʰʱʲʳʴʵʶʷʸʹʺʻʼ';
+ $find = 'ʀ';
+ $result = mb_strstr($string, $find, true);
+ $expected = 'əɚɛɜɝɞɟɠɡɢɣɤɥɦɧɨɩɪɫɬɭɮɯɰɱɲɳɴɵɶɷɸɹɺɻɼɽɾɿ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ЀЁЂЃЄЅІЇЈЉЊЋЌЍЎЏАБВГДЕЖЗИЙКЛ';
+ $find = 'Ї';
+ $result = mb_strstr($string, $find);
+ $expected = 'ЇЈЉЊЋЌЍЎЏАБВГДЕЖЗИЙКЛ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ЀЁЂЃЄЅІЇЈЉЊЋЌЍЎЏАБВГДЕЖЗИЙКЛ';
+ $find = 'Ї';
+ $result = mb_strstr($string, $find, true);
+ $expected = 'ЀЁЂЃЄЅІ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'МНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыь';
+ $find = 'Р';
+ $result = mb_strstr($string, $find);
+ $expected = 'РСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыь';
+ $this->assertEqual($result, $expected);
+
+ $string = 'МНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыь';
+ $find = 'Р';
+ $result = mb_strstr($string, $find, true);
+ $expected = 'МНОП';
+ $this->assertEqual($result, $expected);
+
+ $string = 'فقكلمنهوىيًٌٍَُ';
+ $find = 'ن';
+ $result = mb_strstr($string, $find);
+ $expected = 'نهوىيًٌٍَُ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'فقكلمنهوىيًٌٍَُ';
+ $find = 'ن';
+ $result = mb_strstr($string, $find, true);
+ $expected = 'فقكلم';
+ $this->assertEqual($result, $expected);
+
+ $string = '✰✱✲✳✴✵✶✷✸✹✺✻✼✽✾✿❀❁❂❃❄❅❆❇❈❉❊❋❌❍❎❏❐❑❒❓❔❕❖❗❘❙❚❛❜❝❞';
+ $find = '✿';
+ $result = mb_strstr($string, $find);
+ $expected = '✿❀❁❂❃❄❅❆❇❈❉❊❋❌❍❎❏❐❑❒❓❔❕❖❗❘❙❚❛❜❝❞';
+ $this->assertEqual($result, $expected);
+
+ $string = '✰✱✲✳✴✵✶✷✸✹✺✻✼✽✾✿❀❁❂❃❄❅❆❇❈❉❊❋❌❍❎❏❐❑❒❓❔❕❖❗❘❙❚❛❜❝❞';
+ $find = '✿';
+ $result = mb_strstr($string, $find, true);
+ $expected = '✰✱✲✳✴✵✶✷✸✹✺✻✼✽✾';
+ $this->assertEqual($result, $expected);
+
+ $string = '⺀⺁⺂⺃⺄⺅⺆⺇⺈⺉⺊⺋⺌⺍⺎⺏⺐⺑⺒⺓⺔⺕⺖⺗⺘⺙⺛⺜⺝⺞⺟⺠⺡⺢⺣⺤⺥⺦⺧⺨⺩⺪⺫⺬⺭⺮⺯⺰⺱⺲⺳⺴⺵⺶⺷⺸⺹⺺⺻⺼⺽⺾⺿⻀⻁⻂⻃⻄⻅⻆⻇⻈⻉⻊⻋⻌⻍⻎⻏⻐⻑⻒⻓⻔⻕⻖⻗⻘⻙⻚⻛⻜⻝⻞⻟⻠';
+ $find = '⺐';
+ $result = mb_strstr($string, $find);
+ $expected = '⺐⺑⺒⺓⺔⺕⺖⺗⺘⺙⺛⺜⺝⺞⺟⺠⺡⺢⺣⺤⺥⺦⺧⺨⺩⺪⺫⺬⺭⺮⺯⺰⺱⺲⺳⺴⺵⺶⺷⺸⺹⺺⺻⺼⺽⺾⺿⻀⻁⻂⻃⻄⻅⻆⻇⻈⻉⻊⻋⻌⻍⻎⻏⻐⻑⻒⻓⻔⻕⻖⻗⻘⻙⻚⻛⻜⻝⻞⻟⻠';
+ $this->assertEqual($result, $expected);
+
+ $string = '⺀⺁⺂⺃⺄⺅⺆⺇⺈⺉⺊⺋⺌⺍⺎⺏⺐⺑⺒⺓⺔⺕⺖⺗⺘⺙⺛⺜⺝⺞⺟⺠⺡⺢⺣⺤⺥⺦⺧⺨⺩⺪⺫⺬⺭⺮⺯⺰⺱⺲⺳⺴⺵⺶⺷⺸⺹⺺⺻⺼⺽⺾⺿⻀⻁⻂⻃⻄⻅⻆⻇⻈⻉⻊⻋⻌⻍⻎⻏⻐⻑⻒⻓⻔⻕⻖⻗⻘⻙⻚⻛⻜⻝⻞⻟⻠';
+ $find = '⺐';
+ $result = mb_strstr($string, $find, true);
+ $expected = '⺀⺁⺂⺃⺄⺅⺆⺇⺈⺉⺊⺋⺌⺍⺎⺏';
+ $this->assertEqual($result, $expected);
+
+ $string = '⽅⽆⽇⽈⽉⽊⽋⽌⽍⽎⽏⽐⽑⽒⽓⽔⽕⽖⽗⽘⽙⽚⽛⽜⽝⽞⽟⽠⽡⽢⽣⽤⽥⽦⽧⽨⽩⽪⽫⽬⽭⽮⽯⽰⽱⽲⽳⽴⽵⽶⽷⽸⽹⽺⽻⽼⽽⽾⽿';
+ $find = '⽤';
+ $result = mb_strstr($string, $find);
+ $expected = '⽤⽥⽦⽧⽨⽩⽪⽫⽬⽭⽮⽯⽰⽱⽲⽳⽴⽵⽶⽷⽸⽹⽺⽻⽼⽽⽾⽿';
+ $this->assertEqual($result, $expected);
+
+ $string = '⽅⽆⽇⽈⽉⽊⽋⽌⽍⽎⽏⽐⽑⽒⽓⽔⽕⽖⽗⽘⽙⽚⽛⽜⽝⽞⽟⽠⽡⽢⽣⽤⽥⽦⽧⽨⽩⽪⽫⽬⽭⽮⽯⽰⽱⽲⽳⽴⽵⽶⽷⽸⽹⽺⽻⽼⽽⽾⽿';
+ $find = '⽤';
+ $result = mb_strstr($string, $find, true);
+ $expected = '⽅⽆⽇⽈⽉⽊⽋⽌⽍⽎⽏⽐⽑⽒⽓⽔⽕⽖⽗⽘⽙⽚⽛⽜⽝⽞⽟⽠⽡⽢⽣';
+ $this->assertEqual($result, $expected);
+
+ $string = '눡눢눣눤눥눦눧눨눩눪눫눬눭눮눯눰눱눲눳눴눵눶눷눸눹눺눻눼눽눾눿뉀뉁뉂뉃뉄뉅뉆뉇뉈뉉뉊뉋뉌뉍뉎뉏뉐뉑뉒뉓뉔뉕뉖뉗뉘뉙뉚뉛뉜뉝뉞뉟뉠뉡뉢뉣뉤뉥뉦뉧뉨뉩뉪뉫뉬뉭뉮뉯뉰뉱뉲뉳뉴뉵뉶뉷뉸뉹뉺뉻뉼뉽뉾뉿늀늁늂늃늄';
+ $find = '눻';
+ $result = mb_strstr($string, $find);
+ $expected = '눻눼눽눾눿뉀뉁뉂뉃뉄뉅뉆뉇뉈뉉뉊뉋뉌뉍뉎뉏뉐뉑뉒뉓뉔뉕뉖뉗뉘뉙뉚뉛뉜뉝뉞뉟뉠뉡뉢뉣뉤뉥뉦뉧뉨뉩뉪뉫뉬뉭뉮뉯뉰뉱뉲뉳뉴뉵뉶뉷뉸뉹뉺뉻뉼뉽뉾뉿늀늁늂늃늄';
+ $this->assertEqual($result, $expected);
+
+ $string = '눡눢눣눤눥눦눧눨눩눪눫눬눭눮눯눰눱눲눳눴눵눶눷눸눹눺눻눼눽눾눿뉀뉁뉂뉃뉄뉅뉆뉇뉈뉉뉊뉋뉌뉍뉎뉏뉐뉑뉒뉓뉔뉕뉖뉗뉘뉙뉚뉛뉜뉝뉞뉟뉠뉡뉢뉣뉤뉥뉦뉧뉨뉩뉪뉫뉬뉭뉮뉯뉰뉱뉲뉳뉴뉵뉶뉷뉸뉹뉺뉻뉼뉽뉾뉿늀늁늂늃늄';
+ $find = '눻';
+ $result = mb_strstr($string, $find, true);
+ $expected = '눡눢눣눤눥눦눧눨눩눪눫눬눭눮눯눰눱눲눳눴눵눶눷눸눹눺';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ﹰﹱﹲﹳﹴﹶﹷﹸﹹﹺﹻﹼﹽﹾﹿﺀﺁﺂﺃﺄﺅﺆﺇﺈﺉﺊﺋﺌﺍﺎﺏﺐﺑﺒﺓﺔﺕﺖﺗﺘﺙﺚﺛﺜﺝﺞﺟﺠﺡﺢﺣﺤﺥﺦﺧﺨﺩﺪﺫﺬﺭﺮﺯﺰ';
+ $find = 'ﺞ';
+ $result = mb_strstr($string, $find);
+ $expected = 'ﺞﺟﺠﺡﺢﺣﺤﺥﺦﺧﺨﺩﺪﺫﺬﺭﺮﺯﺰ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ﹰﹱﹲﹳﹴﹶﹷﹸﹹﹺﹻﹼﹽﹾﹿﺀﺁﺂﺃﺄﺅﺆﺇﺈﺉﺊﺋﺌﺍﺎﺏﺐﺑﺒﺓﺔﺕﺖﺗﺘﺙﺚﺛﺜﺝﺞﺟﺠﺡﺢﺣﺤﺥﺦﺧﺨﺩﺪﺫﺬﺭﺮﺯﺰ';
+ $find = 'ﺞ';
+ $result = mb_strstr($string, $find, true);
+ $expected = 'ﹰﹱﹲﹳﹴﹶﹷﹸﹹﹺﹻﹼﹽﹾﹿﺀﺁﺂﺃﺄﺅﺆﺇﺈﺉﺊﺋﺌﺍﺎﺏﺐﺑﺒﺓﺔﺕﺖﺗﺘﺙﺚﺛﺜﺝ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ﺱﺲﺳﺴﺵﺶﺷﺸﺹﺺﺻﺼﺽﺾﺿﻀﻁﻂﻃﻄﻅﻆﻇﻈﻉﻊﻋﻌﻍﻎﻏﻐﻑﻒﻓﻔﻕﻖﻗﻘﻙﻚﻛﻜﻝﻞﻟﻠﻡﻢﻣﻤﻥﻦﻧﻨﻩﻪﻫﻬﻭﻮﻯﻰﻱﻲﻳﻴﻵﻶﻷﻸﻹﻺﻻﻼ';
+ $find = 'ﻞ';
+ $result = mb_strstr($string, $find);
+ $expected = 'ﻞﻟﻠﻡﻢﻣﻤﻥﻦﻧﻨﻩﻪﻫﻬﻭﻮﻯﻰﻱﻲﻳﻴﻵﻶﻷﻸﻹﻺﻻﻼ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ﺱﺲﺳﺴﺵﺶﺷﺸﺹﺺﺻﺼﺽﺾﺿﻀﻁﻂﻃﻄﻅﻆﻇﻈﻉﻊﻋﻌﻍﻎﻏﻐﻑﻒﻓﻔﻕﻖﻗﻘﻙﻚﻛﻜﻝﻞﻟﻠﻡﻢﻣﻤﻥﻦﻧﻨﻩﻪﻫﻬﻭﻮﻯﻰﻱﻲﻳﻴﻵﻶﻷﻸﻹﻺﻻﻼ';
+ $find = 'ﻞ';
+ $result = mb_strstr($string, $find, true);
+ $expected = 'ﺱﺲﺳﺴﺵﺶﺷﺸﺹﺺﺻﺼﺽﺾﺿﻀﻁﻂﻃﻄﻅﻆﻇﻈﻉﻊﻋﻌﻍﻎﻏﻐﻑﻒﻓﻔﻕﻖﻗﻘﻙﻚﻛﻜﻝ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'abcdefghijklmnopqrstuvwxyz';
+ $find = 'k';
+ $result = mb_strstr($string, $find);
+ $expected = 'klmnopqrstuvwxyz';
+ $this->assertEqual($result, $expected);
+
+ $string = 'abcdefghijklmnopqrstuvwxyz';
+ $find = 'k';
+ $result = mb_strstr($string, $find, true);
+ $expected = 'abcdefghij';
+ $this->assertEqual($result, $expected);
+
+ $string = 'abcdefghijklmnopqrstuvwxyz';
+ $find = 'K';
+ $result = mb_strstr($string, $find);
+ $expected = false;
+ $this->assertEqual($result, $expected);
+
+ $string = '。「」、・ヲァィゥェォャュョッーアイウエオカキク';
+ $find = 'ア';
+ $result = mb_strstr($string, $find);
+ $expected = 'アイウエオカキク';
+ $this->assertEqual($result, $expected);
+
+ $string = '。「」、・ヲァィゥェォャュョッーアイウエオカキク';
+ $find = 'ア';
+ $result = mb_strstr($string, $find, true);
+ $expected = '。「」、・ヲァィゥェォャュョッー';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン゙';
+ $find = 'ハ';
+ $result = mb_strstr($string, $find);
+ $expected = 'ハヒフヘホマミムメモヤユヨラリルレロワン゙';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン゙';
+ $find = 'ハ';
+ $result = mb_strstr($string, $find, true);
+ $expected = 'ケコサシスセソタチツテトナニヌネノ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ĥēĺļŏ, Ŵőřļď!';
+ $find = 'ő';
+ $result = mb_strstr($string, $find);
+ $expected = 'őřļď!';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ĥēĺļŏ, Ŵőřļď!';
+ $find = 'ő';
+ $result = mb_strstr($string, $find, true);
+ $expected = 'Ĥēĺļŏ, Ŵ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ĥēĺļŏ, Ŵőřļď!';
+ $find = 'ĺļ';
+ $result = mb_strstr($string, $find, true);
+ $expected = 'Ĥē';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Hello, World!';
+ $find = 'o';
+ $result = mb_strstr($string, $find);
+ $expected = 'o, World!';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Hello, World!';
+ $find = 'o';
+ $result = mb_strstr($string, $find, true);
+ $expected = 'Hell';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Hello, World!';
+ $find = 'Wo';
+ $result = mb_strstr($string, $find);
+ $expected = 'World!';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Hello, World!';
+ $find = 'Wo';
+ $result = mb_strstr($string, $find, true);
+ $expected = 'Hello, ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Hello, World!';
+ $find = 'll';
+ $result = mb_strstr($string, $find);
+ $expected = 'llo, World!';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Hello, World!';
+ $find = 'll';
+ $result = mb_strstr($string, $find, true);
+ $expected = 'He';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Hello, World!';
+ $find = 'rld';
+ $result = mb_strstr($string, $find);
+ $expected = 'rld!';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Hello, World!';
+ $find = 'rld';
+ $result = mb_strstr($string, $find, true);
+ $expected = 'Hello, Wo';
+ $this->assertEqual($result, $expected);
+
+ $string = 'čini';
+ $find = 'n';
+ $result = mb_strstr($string, $find);
+ $expected = 'ni';
+ $this->assertEqual($result, $expected);
+
+ $string = 'čini';
+ $find = 'n';
+ $result = mb_strstr($string, $find, true);
+ $expected = 'či';
+ $this->assertEqual($result, $expected);
+
+ $string = 'moći';
+ $find = 'ć';
+ $result = mb_strstr($string, $find);
+ $expected = 'ći';
+ $this->assertEqual($result, $expected);
+
+ $string = 'moći';
+ $find = 'ć';
+ $result = mb_strstr($string, $find, true);
+ $expected = 'mo';
+ $this->assertEqual($result, $expected);
+
+ $string = 'državni';
+ $find = 'ž';
+ $result = mb_strstr($string, $find);
+ $expected = 'žavni';
+ $this->assertEqual($result, $expected);
+
+ $string = 'državni';
+ $find = 'ž';
+ $result = mb_strstr($string, $find, true);
+ $expected = 'dr';
+ $this->assertEqual($result, $expected);
+
+ $string = '把百度设为首页';
+ $find = '设';
+ $result = mb_strstr($string, $find);
+ $expected = '设为首页';
+ $this->assertEqual($result, $expected);
+
+ $string = '把百度设为首页';
+ $find = '设';
+ $result = mb_strstr($string, $find, true);
+ $expected = '把百度';
+ $this->assertEqual($result, $expected);
+
+ $string = '一二三周永龍';
+ $find = '周';
+ $result = mb_strstr($string, $find);
+ $expected = '周永龍';
+ $this->assertEqual($result, $expected);
+
+ $string = '一二三周永龍';
+ $find = '周';
+ $result = mb_strstr($string, $find, true);
+ $expected = '一二三';
+ $this->assertEqual($result, $expected);
+
+ $string = '一二三周永龍';
+ $find = '二周';
+ $result = mb_strstr($string, $find);
+ $expected = false;
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testMultibyteStrstr method
+ *
+ * @access public
+ * @return void
+ */
+ function testMultibyteStrstr() {
+ $string = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
+ $find = 'F';
+ $result = Multibyte::strstr($string, $find);
+ $expected = 'FGHIJKLMNOPQRSTUVWXYZ0123456789';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
+ $find = 'F';
+ $result = Multibyte::strstr($string, $find, true);
+ $expected = 'ABCDE';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞ';
+ $find = 'Å';
+ $result = Multibyte::strstr($string, $find);
+ $expected = 'ÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞ';
+ $find = 'Å';
+ $result = Multibyte::strstr($string, $find, true);
+ $expected = 'ÀÁÂÃÄ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĀĂĄĆĈĊČĎĐĒĔĖĘĚĜĞĠĢĤĦĨĪĬĮIJĴĶĹĻĽĿŁŃŅŇŊŌŎŐŒŔŖŘŚŜŞŠŢŤŦŨŪŬŮŰŲŴŶŹŻŽ';
+ $find = 'Ċ';
+ $result = Multibyte::strstr($string, $find);
+ $expected = 'ĊČĎĐĒĔĖĘĚĜĞĠĢĤĦĨĪĬĮIJĴĶĹĻĽĿŁŃŅŇŊŌŎŐŒŔŖŘŚŜŞŠŢŤŦŨŪŬŮŰŲŴŶŹŻŽ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĀĂĄĆĈĊČĎĐĒĔĖĘĚĜĞĠĢĤĦĨĪĬĮIJĴĶĹĻĽĿŁŃŅŇŊŌŎŐŒŔŖŘŚŜŞŠŢŤŦŨŪŬŮŰŲŴŶŹŻŽ';
+ $find = 'Ċ';
+ $result = Multibyte::strstr($string, $find, true);
+ $expected = 'ĀĂĄĆĈ';
+ $this->assertEqual($result, $expected);
+
+ $string = '!"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~';
+ $find = 'F';
+ $result = Multibyte::strstr($string, $find);
+ $expected = 'FGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~';
+ $this->assertEqual($result, $expected);
+
+ $string = '!"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~';
+ $find = 'F';
+ $result = Multibyte::strstr($string, $find, true);
+ $expected = '!"#$%&\'()*+,-./0123456789:;<=>?@ABCDE';
+ $this->assertEqual($result, $expected);
+
+ $string = '¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈ';
+ $find = 'µ';
+ $result = Multibyte::strstr($string, $find);
+ $expected = 'µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈ';
+ $this->assertEqual($result, $expected);
+
+ $string = '¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈ';
+ $find = 'µ';
+ $result = Multibyte::strstr($string, $find, true);
+ $expected = '¡¢£¤¥¦§¨©ª«¬®¯°±²³´';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿĀāĂ㥹ĆćĈĉĊċČčĎďĐđĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪīĬ';
+ $find = 'Þ';
+ $result = Multibyte::strstr($string, $find);
+ $expected = 'Þßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿĀāĂ㥹ĆćĈĉĊċČčĎďĐđĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪīĬ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿĀāĂ㥹ĆćĈĉĊċČčĎďĐđĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪīĬ';
+ $find = 'Þ';
+ $result = Multibyte::strstr($string, $find, true);
+ $expected = 'ÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĭĮįİıIJijĴĵĶķĸĹĺĻļĽľĿŀŁłŃńŅņŇňʼnŊŋŌōŎŏŐőŒœŔŕŖŗŘřŚśŜŝŞşŠšŢţŤťŦŧŨũŪūŬŭŮůŰűŲųŴŵŶŷŸŹźŻżŽžſƀƁƂƃƄƅƆƇƈƉƊƋƌƍƎƏƐ';
+ $find = 'Ņ';
+ $result = Multibyte::strstr($string, $find);
+ $expected = 'ŅņŇňʼnŊŋŌōŎŏŐőŒœŔŕŖŗŘřŚśŜŝŞşŠšŢţŤťŦŧŨũŪūŬŭŮůŰűŲųŴŵŶŷŸŹźŻżŽžſƀƁƂƃƄƅƆƇƈƉƊƋƌƍƎƏƐ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĭĮįİıIJijĴĵĶķĸĹĺĻļĽľĿŀŁłŃńŅņŇňʼnŊŋŌōŎŏŐőŒœŔŕŖŗŘřŚśŜŝŞşŠšŢţŤťŦŧŨũŪūŬŭŮůŰűŲųŴŵŶŷŸŹźŻżŽžſƀƁƂƃƄƅƆƇƈƉƊƋƌƍƎƏƐ';
+ $find = 'Ņ';
+ $result = Multibyte::strstr($string, $find, true);
+ $expected = 'ĭĮįİıIJijĴĵĶķĸĹĺĻļĽľĿŀŁłŃń';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ƑƒƓƔƕƖƗƘƙƚƛƜƝƞƟƠơƢƣƤƥƦƧƨƩƪƫƬƭƮƯưƱƲƳƴƵƶƷƸƹƺƻƼƽƾƿǀǁǂǃDŽDždžLJLjljNJNjnjǍǎǏǐǑǒǓǔǕǖǗǘǙǚǛǜǝǞǟǠǡǢǣǤǥǦǧǨǩǪǫǬǭǮǯǰDZDzdzǴ';
+ $find = 'Ƹ';
+ $result = Multibyte::strstr($string, $find);
+ $expected = 'ƸƹƺƻƼƽƾƿǀǁǂǃDŽDždžLJLjljNJNjnjǍǎǏǐǑǒǓǔǕǖǗǘǙǚǛǜǝǞǟǠǡǢǣǤǥǦǧǨǩǪǫǬǭǮǯǰDZDzdzǴ';
+ $this->assertEqual($result, $expected);
+
+ $find = 'Ƹ';
+ $result = Multibyte::strstr($string, $find, true);
+ $expected = 'ƑƒƓƔƕƖƗƘƙƚƛƜƝƞƟƠơƢƣƤƥƦƧƨƩƪƫƬƭƮƯưƱƲƳƴƵƶƷ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'əɚɛɜɝɞɟɠɡɢɣɤɥɦɧɨɩɪɫɬɭɮɯɰɱɲɳɴɵɶɷɸɹɺɻɼɽɾɿʀʁʂʃʄʅʆʇʈʉʊʋʌʍʎʏʐʑʒʓʔʕʖʗʘʙʚʛʜʝʞʟʠʡʢʣʤʥʦʧʨʩʪʫʬʭʮʯʰʱʲʳʴʵʶʷʸʹʺʻʼ';
+ $find = 'ʀ';
+ $result = Multibyte::strstr($string, $find);
+ $expected = 'ʀʁʂʃʄʅʆʇʈʉʊʋʌʍʎʏʐʑʒʓʔʕʖʗʘʙʚʛʜʝʞʟʠʡʢʣʤʥʦʧʨʩʪʫʬʭʮʯʰʱʲʳʴʵʶʷʸʹʺʻʼ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'əɚɛɜɝɞɟɠɡɢɣɤɥɦɧɨɩɪɫɬɭɮɯɰɱɲɳɴɵɶɷɸɹɺɻɼɽɾɿʀʁʂʃʄʅʆʇʈʉʊʋʌʍʎʏʐʑʒʓʔʕʖʗʘʙʚʛʜʝʞʟʠʡʢʣʤʥʦʧʨʩʪʫʬʭʮʯʰʱʲʳʴʵʶʷʸʹʺʻʼ';
+ $find = 'ʀ';
+ $result = Multibyte::strstr($string, $find, true);
+ $expected = 'əɚɛɜɝɞɟɠɡɢɣɤɥɦɧɨɩɪɫɬɭɮɯɰɱɲɳɴɵɶɷɸɹɺɻɼɽɾɿ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ЀЁЂЃЄЅІЇЈЉЊЋЌЍЎЏАБВГДЕЖЗИЙКЛ';
+ $find = 'Ї';
+ $result = Multibyte::strstr($string, $find);
+ $expected = 'ЇЈЉЊЋЌЍЎЏАБВГДЕЖЗИЙКЛ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ЀЁЂЃЄЅІЇЈЉЊЋЌЍЎЏАБВГДЕЖЗИЙКЛ';
+ $find = 'Ї';
+ $result = Multibyte::strstr($string, $find, true);
+ $expected = 'ЀЁЂЃЄЅІ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'МНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыь';
+ $find = 'Р';
+ $result = Multibyte::strstr($string, $find);
+ $expected = 'РСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыь';
+ $this->assertEqual($result, $expected);
+
+ $string = 'МНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыь';
+ $find = 'Р';
+ $result = Multibyte::strstr($string, $find, true);
+ $expected = 'МНОП';
+ $this->assertEqual($result, $expected);
+
+ $string = 'فقكلمنهوىيًٌٍَُ';
+ $find = 'ن';
+ $result = Multibyte::strstr($string, $find);
+ $expected = 'نهوىيًٌٍَُ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'فقكلمنهوىيًٌٍَُ';
+ $find = 'ن';
+ $result = Multibyte::strstr($string, $find, true);
+ $expected = 'فقكلم';
+ $this->assertEqual($result, $expected);
+
+ $string = '✰✱✲✳✴✵✶✷✸✹✺✻✼✽✾✿❀❁❂❃❄❅❆❇❈❉❊❋❌❍❎❏❐❑❒❓❔❕❖❗❘❙❚❛❜❝❞';
+ $find = '✿';
+ $result = Multibyte::strstr($string, $find);
+ $expected = '✿❀❁❂❃❄❅❆❇❈❉❊❋❌❍❎❏❐❑❒❓❔❕❖❗❘❙❚❛❜❝❞';
+ $this->assertEqual($result, $expected);
+
+ $string = '✰✱✲✳✴✵✶✷✸✹✺✻✼✽✾✿❀❁❂❃❄❅❆❇❈❉❊❋❌❍❎❏❐❑❒❓❔❕❖❗❘❙❚❛❜❝❞';
+ $find = '✿';
+ $result = Multibyte::strstr($string, $find, true);
+ $expected = '✰✱✲✳✴✵✶✷✸✹✺✻✼✽✾';
+ $this->assertEqual($result, $expected);
+
+ $string = '⺀⺁⺂⺃⺄⺅⺆⺇⺈⺉⺊⺋⺌⺍⺎⺏⺐⺑⺒⺓⺔⺕⺖⺗⺘⺙⺛⺜⺝⺞⺟⺠⺡⺢⺣⺤⺥⺦⺧⺨⺩⺪⺫⺬⺭⺮⺯⺰⺱⺲⺳⺴⺵⺶⺷⺸⺹⺺⺻⺼⺽⺾⺿⻀⻁⻂⻃⻄⻅⻆⻇⻈⻉⻊⻋⻌⻍⻎⻏⻐⻑⻒⻓⻔⻕⻖⻗⻘⻙⻚⻛⻜⻝⻞⻟⻠';
+ $find = '⺐';
+ $result = Multibyte::strstr($string, $find);
+ $expected = '⺐⺑⺒⺓⺔⺕⺖⺗⺘⺙⺛⺜⺝⺞⺟⺠⺡⺢⺣⺤⺥⺦⺧⺨⺩⺪⺫⺬⺭⺮⺯⺰⺱⺲⺳⺴⺵⺶⺷⺸⺹⺺⺻⺼⺽⺾⺿⻀⻁⻂⻃⻄⻅⻆⻇⻈⻉⻊⻋⻌⻍⻎⻏⻐⻑⻒⻓⻔⻕⻖⻗⻘⻙⻚⻛⻜⻝⻞⻟⻠';
+ $this->assertEqual($result, $expected);
+
+ $string = '⺀⺁⺂⺃⺄⺅⺆⺇⺈⺉⺊⺋⺌⺍⺎⺏⺐⺑⺒⺓⺔⺕⺖⺗⺘⺙⺛⺜⺝⺞⺟⺠⺡⺢⺣⺤⺥⺦⺧⺨⺩⺪⺫⺬⺭⺮⺯⺰⺱⺲⺳⺴⺵⺶⺷⺸⺹⺺⺻⺼⺽⺾⺿⻀⻁⻂⻃⻄⻅⻆⻇⻈⻉⻊⻋⻌⻍⻎⻏⻐⻑⻒⻓⻔⻕⻖⻗⻘⻙⻚⻛⻜⻝⻞⻟⻠';
+ $find = '⺐';
+ $result = Multibyte::strstr($string, $find, true);
+ $expected = '⺀⺁⺂⺃⺄⺅⺆⺇⺈⺉⺊⺋⺌⺍⺎⺏';
+ $this->assertEqual($result, $expected);
+
+ $string = '⽅⽆⽇⽈⽉⽊⽋⽌⽍⽎⽏⽐⽑⽒⽓⽔⽕⽖⽗⽘⽙⽚⽛⽜⽝⽞⽟⽠⽡⽢⽣⽤⽥⽦⽧⽨⽩⽪⽫⽬⽭⽮⽯⽰⽱⽲⽳⽴⽵⽶⽷⽸⽹⽺⽻⽼⽽⽾⽿';
+ $find = '⽤';
+ $result = Multibyte::strstr($string, $find);
+ $expected = '⽤⽥⽦⽧⽨⽩⽪⽫⽬⽭⽮⽯⽰⽱⽲⽳⽴⽵⽶⽷⽸⽹⽺⽻⽼⽽⽾⽿';
+ $this->assertEqual($result, $expected);
+
+ $string = '⽅⽆⽇⽈⽉⽊⽋⽌⽍⽎⽏⽐⽑⽒⽓⽔⽕⽖⽗⽘⽙⽚⽛⽜⽝⽞⽟⽠⽡⽢⽣⽤⽥⽦⽧⽨⽩⽪⽫⽬⽭⽮⽯⽰⽱⽲⽳⽴⽵⽶⽷⽸⽹⽺⽻⽼⽽⽾⽿';
+ $find = '⽤';
+ $result = Multibyte::strstr($string, $find, true);
+ $expected = '⽅⽆⽇⽈⽉⽊⽋⽌⽍⽎⽏⽐⽑⽒⽓⽔⽕⽖⽗⽘⽙⽚⽛⽜⽝⽞⽟⽠⽡⽢⽣';
+ $this->assertEqual($result, $expected);
+
+ $string = '눡눢눣눤눥눦눧눨눩눪눫눬눭눮눯눰눱눲눳눴눵눶눷눸눹눺눻눼눽눾눿뉀뉁뉂뉃뉄뉅뉆뉇뉈뉉뉊뉋뉌뉍뉎뉏뉐뉑뉒뉓뉔뉕뉖뉗뉘뉙뉚뉛뉜뉝뉞뉟뉠뉡뉢뉣뉤뉥뉦뉧뉨뉩뉪뉫뉬뉭뉮뉯뉰뉱뉲뉳뉴뉵뉶뉷뉸뉹뉺뉻뉼뉽뉾뉿늀늁늂늃늄';
+ $find = '눻';
+ $result = Multibyte::strstr($string, $find);
+ $expected = '눻눼눽눾눿뉀뉁뉂뉃뉄뉅뉆뉇뉈뉉뉊뉋뉌뉍뉎뉏뉐뉑뉒뉓뉔뉕뉖뉗뉘뉙뉚뉛뉜뉝뉞뉟뉠뉡뉢뉣뉤뉥뉦뉧뉨뉩뉪뉫뉬뉭뉮뉯뉰뉱뉲뉳뉴뉵뉶뉷뉸뉹뉺뉻뉼뉽뉾뉿늀늁늂늃늄';
+ $this->assertEqual($result, $expected);
+
+ $string = '눡눢눣눤눥눦눧눨눩눪눫눬눭눮눯눰눱눲눳눴눵눶눷눸눹눺눻눼눽눾눿뉀뉁뉂뉃뉄뉅뉆뉇뉈뉉뉊뉋뉌뉍뉎뉏뉐뉑뉒뉓뉔뉕뉖뉗뉘뉙뉚뉛뉜뉝뉞뉟뉠뉡뉢뉣뉤뉥뉦뉧뉨뉩뉪뉫뉬뉭뉮뉯뉰뉱뉲뉳뉴뉵뉶뉷뉸뉹뉺뉻뉼뉽뉾뉿늀늁늂늃늄';
+ $find = '눻';
+ $result = Multibyte::strstr($string, $find, true);
+ $expected = '눡눢눣눤눥눦눧눨눩눪눫눬눭눮눯눰눱눲눳눴눵눶눷눸눹눺';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ﹰﹱﹲﹳﹴﹶﹷﹸﹹﹺﹻﹼﹽﹾﹿﺀﺁﺂﺃﺄﺅﺆﺇﺈﺉﺊﺋﺌﺍﺎﺏﺐﺑﺒﺓﺔﺕﺖﺗﺘﺙﺚﺛﺜﺝﺞﺟﺠﺡﺢﺣﺤﺥﺦﺧﺨﺩﺪﺫﺬﺭﺮﺯﺰ';
+ $find = 'ﺞ';
+ $result = Multibyte::strstr($string, $find);
+ $expected = 'ﺞﺟﺠﺡﺢﺣﺤﺥﺦﺧﺨﺩﺪﺫﺬﺭﺮﺯﺰ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ﹰﹱﹲﹳﹴﹶﹷﹸﹹﹺﹻﹼﹽﹾﹿﺀﺁﺂﺃﺄﺅﺆﺇﺈﺉﺊﺋﺌﺍﺎﺏﺐﺑﺒﺓﺔﺕﺖﺗﺘﺙﺚﺛﺜﺝﺞﺟﺠﺡﺢﺣﺤﺥﺦﺧﺨﺩﺪﺫﺬﺭﺮﺯﺰ';
+ $find = 'ﺞ';
+ $result = Multibyte::strstr($string, $find, true);
+ $expected = 'ﹰﹱﹲﹳﹴﹶﹷﹸﹹﹺﹻﹼﹽﹾﹿﺀﺁﺂﺃﺄﺅﺆﺇﺈﺉﺊﺋﺌﺍﺎﺏﺐﺑﺒﺓﺔﺕﺖﺗﺘﺙﺚﺛﺜﺝ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ﺱﺲﺳﺴﺵﺶﺷﺸﺹﺺﺻﺼﺽﺾﺿﻀﻁﻂﻃﻄﻅﻆﻇﻈﻉﻊﻋﻌﻍﻎﻏﻐﻑﻒﻓﻔﻕﻖﻗﻘﻙﻚﻛﻜﻝﻞﻟﻠﻡﻢﻣﻤﻥﻦﻧﻨﻩﻪﻫﻬﻭﻮﻯﻰﻱﻲﻳﻴﻵﻶﻷﻸﻹﻺﻻﻼ';
+ $find = 'ﻞ';
+ $result = Multibyte::strstr($string, $find);
+ $expected = 'ﻞﻟﻠﻡﻢﻣﻤﻥﻦﻧﻨﻩﻪﻫﻬﻭﻮﻯﻰﻱﻲﻳﻴﻵﻶﻷﻸﻹﻺﻻﻼ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ﺱﺲﺳﺴﺵﺶﺷﺸﺹﺺﺻﺼﺽﺾﺿﻀﻁﻂﻃﻄﻅﻆﻇﻈﻉﻊﻋﻌﻍﻎﻏﻐﻑﻒﻓﻔﻕﻖﻗﻘﻙﻚﻛﻜﻝﻞﻟﻠﻡﻢﻣﻤﻥﻦﻧﻨﻩﻪﻫﻬﻭﻮﻯﻰﻱﻲﻳﻴﻵﻶﻷﻸﻹﻺﻻﻼ';
+ $find = 'ﻞ';
+ $result = Multibyte::strstr($string, $find, true);
+ $expected = 'ﺱﺲﺳﺴﺵﺶﺷﺸﺹﺺﺻﺼﺽﺾﺿﻀﻁﻂﻃﻄﻅﻆﻇﻈﻉﻊﻋﻌﻍﻎﻏﻐﻑﻒﻓﻔﻕﻖﻗﻘﻙﻚﻛﻜﻝ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'abcdefghijklmnopqrstuvwxyz';
+ $find = 'k';
+ $result = Multibyte::strstr($string, $find);
+ $expected = 'klmnopqrstuvwxyz';
+ $this->assertEqual($result, $expected);
+
+ $string = 'abcdefghijklmnopqrstuvwxyz';
+ $find = 'k';
+ $result = Multibyte::strstr($string, $find, true);
+ $expected = 'abcdefghij';
+ $this->assertEqual($result, $expected);
+
+ $string = 'abcdefghijklmnopqrstuvwxyz';
+ $find = 'K';
+ $result = Multibyte::strstr($string, $find);
+ $expected = false;
+ $this->assertEqual($result, $expected);
+
+ $string = '。「」、・ヲァィゥェォャュョッーアイウエオカキク';
+ $find = 'ア';
+ $result = Multibyte::strstr($string, $find);
+ $expected = 'アイウエオカキク';
+ $this->assertEqual($result, $expected);
+
+ $string = '。「」、・ヲァィゥェォャュョッーアイウエオカキク';
+ $find = 'ア';
+ $result = Multibyte::strstr($string, $find, true);
+ $expected = '。「」、・ヲァィゥェォャュョッー';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン゙';
+ $find = 'ハ';
+ $result = Multibyte::strstr($string, $find);
+ $expected = 'ハヒフヘホマミムメモヤユヨラリルレロワン゙';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン゙';
+ $find = 'ハ';
+ $result = Multibyte::strstr($string, $find, true);
+ $expected = 'ケコサシスセソタチツテトナニヌネノ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ĥēĺļŏ, Ŵőřļď!';
+ $find = 'ő';
+ $result = Multibyte::strstr($string, $find);
+ $expected = 'őřļď!';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ĥēĺļŏ, Ŵőřļď!';
+ $find = 'ő';
+ $result = Multibyte::strstr($string, $find, true);
+ $expected = 'Ĥēĺļŏ, Ŵ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ĥēĺļŏ, Ŵőřļď!';
+ $find = 'ĺļ';
+ $result = Multibyte::strstr($string, $find, true);
+ $expected = 'Ĥē';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Hello, World!';
+ $find = 'o';
+ $result = Multibyte::strstr($string, $find);
+ $expected = 'o, World!';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Hello, World!';
+ $find = 'o';
+ $result = Multibyte::strstr($string, $find, true);
+ $expected = 'Hell';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Hello, World!';
+ $find = 'Wo';
+ $result = Multibyte::strstr($string, $find);
+ $expected = 'World!';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Hello, World!';
+ $find = 'Wo';
+ $result = Multibyte::strstr($string, $find, true);
+ $expected = 'Hello, ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Hello, World!';
+ $find = 'll';
+ $result = Multibyte::strstr($string, $find);
+ $expected = 'llo, World!';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Hello, World!';
+ $find = 'll';
+ $result = Multibyte::strstr($string, $find, true);
+ $expected = 'He';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Hello, World!';
+ $find = 'rld';
+ $result = Multibyte::strstr($string, $find);
+ $expected = 'rld!';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Hello, World!';
+ $find = 'rld';
+ $result = Multibyte::strstr($string, $find, true);
+ $expected = 'Hello, Wo';
+ $this->assertEqual($result, $expected);
+
+ $string = 'čini';
+ $find = 'n';
+ $result = Multibyte::strstr($string, $find);
+ $expected = 'ni';
+ $this->assertEqual($result, $expected);
+
+ $string = 'čini';
+ $find = 'n';
+ $result = Multibyte::strstr($string, $find, true);
+ $expected = 'či';
+ $this->assertEqual($result, $expected);
+
+ $string = 'moći';
+ $find = 'ć';
+ $result = Multibyte::strstr($string, $find);
+ $expected = 'ći';
+ $this->assertEqual($result, $expected);
+
+ $string = 'moći';
+ $find = 'ć';
+ $result = Multibyte::strstr($string, $find, true);
+ $expected = 'mo';
+ $this->assertEqual($result, $expected);
+
+ $string = 'državni';
+ $find = 'ž';
+ $result = Multibyte::strstr($string, $find);
+ $expected = 'žavni';
+ $this->assertEqual($result, $expected);
+
+ $string = 'državni';
+ $find = 'ž';
+ $result = Multibyte::strstr($string, $find, true);
+ $expected = 'dr';
+ $this->assertEqual($result, $expected);
+
+ $string = '把百度设为首页';
+ $find = '设';
+ $result = Multibyte::strstr($string, $find);
+ $expected = '设为首页';
+ $this->assertEqual($result, $expected);
+
+ $string = '把百度设为首页';
+ $find = '设';
+ $result = Multibyte::strstr($string, $find, true);
+ $expected = '把百度';
+ $this->assertEqual($result, $expected);
+
+ $string = '一二三周永龍';
+ $find = '周';
+ $result = Multibyte::strstr($string, $find);
+ $expected = '周永龍';
+ $this->assertEqual($result, $expected);
+
+ $string = '一二三周永龍';
+ $find = '周';
+ $result = Multibyte::strstr($string, $find, true);
+ $expected = '一二三';
+ $this->assertEqual($result, $expected);
+
+ $string = '一二三周永龍';
+ $find = '二周';
+ $result = Multibyte::strstr($string, $find);
+ $expected = false;
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testUsingMbStrtolower method
+ *
+ * @access public
+ * @return void
+ */
+ function testUsingMbStrtolower() {
+ $string = '!"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`ABCDEFGHIJKLMNOPQRSTUVWXYZ{|}~';
+ $result = mb_strtolower($string);
+ $expected = '!"#$%&\'()*+,-./0123456789:;<=>?@abcdefghijklmnopqrstuvwxyz[\]^_`abcdefghijklmnopqrstuvwxyz{|}~';
+ $this->assertEqual($result, $expected);
+
+ $string = '!"#$%&\'()*+,-./0123456789:;<=>?@';
+ $result = mb_strtolower($string);
+ $expected = '!"#$%&\'()*+,-./0123456789:;<=>?@';
+ $this->assertEqual($result, $expected);
+
+ $string = 'À';
+ $result = mb_strtolower($string);
+ $expected = 'à';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Á';
+ $result = mb_strtolower($string);
+ $expected = 'á';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Â';
+ $result = mb_strtolower($string);
+ $expected = 'â';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ã';
+ $result = mb_strtolower($string);
+ $expected = 'ã';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ä';
+ $result = mb_strtolower($string);
+ $expected = 'ä';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Å';
+ $result = mb_strtolower($string);
+ $expected = 'å';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Æ';
+ $result = mb_strtolower($string);
+ $expected = 'æ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ç';
+ $result = mb_strtolower($string);
+ $expected = 'ç';
+ $this->assertEqual($result, $expected);
+
+ $string = 'È';
+ $result = mb_strtolower($string);
+ $expected = 'è';
+ $this->assertEqual($result, $expected);
+
+ $string = 'É';
+ $result = mb_strtolower($string);
+ $expected = 'é';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ê';
+ $result = mb_strtolower($string);
+ $expected = 'ê';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ë';
+ $result = mb_strtolower($string);
+ $expected = 'ë';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ì';
+ $result = mb_strtolower($string);
+ $expected = 'ì';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Í';
+ $result = mb_strtolower($string);
+ $expected = 'í';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Î';
+ $result = mb_strtolower($string);
+ $expected = 'î';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ï';
+ $result = mb_strtolower($string);
+ $expected = 'ï';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ð';
+ $result = mb_strtolower($string);
+ $expected = 'ð';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ñ';
+ $result = mb_strtolower($string);
+ $expected = 'ñ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ò';
+ $result = mb_strtolower($string);
+ $expected = 'ò';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ó';
+ $result = mb_strtolower($string);
+ $expected = 'ó';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ô';
+ $result = mb_strtolower($string);
+ $expected = 'ô';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Õ';
+ $result = mb_strtolower($string);
+ $expected = 'õ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ö';
+ $result = mb_strtolower($string);
+ $expected = 'ö';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ø';
+ $result = mb_strtolower($string);
+ $expected = 'ø';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ù';
+ $result = mb_strtolower($string);
+ $expected = 'ù';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ú';
+ $result = mb_strtolower($string);
+ $expected = 'ú';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Û';
+ $result = mb_strtolower($string);
+ $expected = 'û';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ü';
+ $result = mb_strtolower($string);
+ $expected = 'ü';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ý';
+ $result = mb_strtolower($string);
+ $expected = 'ý';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Þ';
+ $result = mb_strtolower($string);
+ $expected = 'þ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞ';
+ $result = mb_strtolower($string);
+ $expected = 'àáâãäåæçèéêëìíîïðñòóôõöøùúûüýþ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ā';
+ $result = mb_strtolower($string);
+ $expected = 'ā';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ă';
+ $result = mb_strtolower($string);
+ $expected = 'ă';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ą';
+ $result = mb_strtolower($string);
+ $expected = 'ą';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ć';
+ $result = mb_strtolower($string);
+ $expected = 'ć';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ĉ';
+ $result = mb_strtolower($string);
+ $expected = 'ĉ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ċ';
+ $result = mb_strtolower($string);
+ $expected = 'ċ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Č';
+ $result = mb_strtolower($string);
+ $expected = 'č';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ď';
+ $result = mb_strtolower($string);
+ $expected = 'ď';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Đ';
+ $result = mb_strtolower($string);
+ $expected = 'đ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ē';
+ $result = mb_strtolower($string);
+ $expected = 'ē';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ĕ';
+ $result = mb_strtolower($string);
+ $expected = 'ĕ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ė';
+ $result = mb_strtolower($string);
+ $expected = 'ė';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ę';
+ $result = mb_strtolower($string);
+ $expected = 'ę';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ě';
+ $result = mb_strtolower($string);
+ $expected = 'ě';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ĝ';
+ $result = mb_strtolower($string);
+ $expected = 'ĝ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ğ';
+ $result = mb_strtolower($string);
+ $expected = 'ğ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ġ';
+ $result = mb_strtolower($string);
+ $expected = 'ġ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ģ';
+ $result = mb_strtolower($string);
+ $expected = 'ģ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ĥ';
+ $result = mb_strtolower($string);
+ $expected = 'ĥ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ħ';
+ $result = mb_strtolower($string);
+ $expected = 'ħ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ĩ';
+ $result = mb_strtolower($string);
+ $expected = 'ĩ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ī';
+ $result = mb_strtolower($string);
+ $expected = 'ī';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ĭ';
+ $result = mb_strtolower($string);
+ $expected = 'ĭ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Į';
+ $result = mb_strtolower($string);
+ $expected = 'į';
+ $this->assertEqual($result, $expected);
+
+ $string = 'IJ';
+ $result = mb_strtolower($string);
+ $expected = 'ij';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ĵ';
+ $result = mb_strtolower($string);
+ $expected = 'ĵ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ķ';
+ $result = mb_strtolower($string);
+ $expected = 'ķ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ĺ';
+ $result = mb_strtolower($string);
+ $expected = 'ĺ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ļ';
+ $result = mb_strtolower($string);
+ $expected = 'ļ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ľ';
+ $result = mb_strtolower($string);
+ $expected = 'ľ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ŀ';
+ $result = mb_strtolower($string);
+ $expected = 'ŀ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ł';
+ $result = mb_strtolower($string);
+ $expected = 'ł';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ń';
+ $result = mb_strtolower($string);
+ $expected = 'ń';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ņ';
+ $result = mb_strtolower($string);
+ $expected = 'ņ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ň';
+ $result = mb_strtolower($string);
+ $expected = 'ň';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ŋ';
+ $result = mb_strtolower($string);
+ $expected = 'ŋ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ō';
+ $result = mb_strtolower($string);
+ $expected = 'ō';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ŏ';
+ $result = mb_strtolower($string);
+ $expected = 'ŏ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ő';
+ $result = mb_strtolower($string);
+ $expected = 'ő';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Œ';
+ $result = mb_strtolower($string);
+ $expected = 'œ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ŕ';
+ $result = mb_strtolower($string);
+ $expected = 'ŕ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ŗ';
+ $result = mb_strtolower($string);
+ $expected = 'ŗ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ř';
+ $result = mb_strtolower($string);
+ $expected = 'ř';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ś';
+ $result = mb_strtolower($string);
+ $expected = 'ś';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ŝ';
+ $result = mb_strtolower($string);
+ $expected = 'ŝ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ş';
+ $result = mb_strtolower($string);
+ $expected = 'ş';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Š';
+ $result = mb_strtolower($string);
+ $expected = 'š';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ţ';
+ $result = mb_strtolower($string);
+ $expected = 'ţ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ť';
+ $result = mb_strtolower($string);
+ $expected = 'ť';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ŧ';
+ $result = mb_strtolower($string);
+ $expected = 'ŧ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ũ';
+ $result = mb_strtolower($string);
+ $expected = 'ũ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ū';
+ $result = mb_strtolower($string);
+ $expected = 'ū';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ŭ';
+ $result = mb_strtolower($string);
+ $expected = 'ŭ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ů';
+ $result = mb_strtolower($string);
+ $expected = 'ů';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ű';
+ $result = mb_strtolower($string);
+ $expected = 'ű';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ų';
+ $result = mb_strtolower($string);
+ $expected = 'ų';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ŵ';
+ $result = mb_strtolower($string);
+ $expected = 'ŵ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ŷ';
+ $result = mb_strtolower($string);
+ $expected = 'ŷ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ź';
+ $result = mb_strtolower($string);
+ $expected = 'ź';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ż';
+ $result = mb_strtolower($string);
+ $expected = 'ż';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ž';
+ $result = mb_strtolower($string);
+ $expected = 'ž';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĀĂĄĆĈĊČĎĐĒĔĖĘĚĜĞĠĢĤĦĨĪĬĮIJĴĶĹĻĽĿŁŃŅŇŊŌŎŐŒŔŖŘŚŜŞŠŢŤŦŨŪŬŮŰŲŴŶŹŻŽ';
+ $result = mb_strtolower($string);
+ $expected = 'āăąćĉċčďđēĕėęěĝğġģĥħĩīĭįijĵķĺļľŀłńņňŋōŏőœŕŗřśŝşšţťŧũūŭůűųŵŷźżž';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĤĒĹĻŎ, ŴŐŘĻĎ!';
+ $result = mb_strtolower($string);
+ $expected = 'ĥēĺļŏ, ŵőřļď!';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĥēĺļŏ, ŵőřļď!';
+ $result = mb_strtolower($string);
+ $expected = 'ĥēĺļŏ, ŵőřļď!';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ἈΙ';
+ $result = mb_strtolower($string);
+ $expected = 'ἀι';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ԀԂԄԆԈԊԌԎԐԒ';
+ $result = mb_strtolower($string);
+ $expected = 'ԁԃԅԇԉԋԍԏԐԒ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ԱԲԳԴԵԶԷԸԹԺԻԼԽԾԿՀՁՂՃՄՅՆՇՈՉՊՋՌՍՎՏՐՑՒՓՔՕՖև';
+ $result = mb_strtolower($string);
+ $expected = 'աբգդեզէըթժիլխծկհձղճմյնշոչպջռսվտրցւփքօֆև';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ႠႡႢႣႤႥႦႧႨႩႪႫႬႭႮႯႰႱႲႳႴႵႶႷႸႹႺႻႼႽႾႿჀჁჂჃჄჅ';
+ $result = mb_strtolower($string);
+ $expected = 'ႠႡႢႣႤႥႦႧႨႩႪႫႬႭႮႯႰႱႲႳႴႵႶႷႸႹႺႻႼႽႾႿჀჁჂჃჄჅ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ḀḂḄḆḈḊḌḎḐḒḔḖḘḚḜḞḠḢḤḦḨḪḬḮḰḲḴḶḸḺḼḾṀṂṄṆṈṊṌṎṐṒṔṖṘṚṜṞṠṢṤṦṨṪṬṮṰṲṴṶṸṺṼṾẀẂẄẆẈẊẌẎẐẒẔẖẗẘẙẚẠẢẤẦẨẪẬẮẰẲẴẶẸẺẼẾỀỂỄỆỈỊỌỎỐỒỔỖỘỚỜỞỠỢỤỦỨỪỬỮỰỲỴỶỸ';
+ $result = mb_strtolower($string);
+ $expected = 'ḁḃḅḇḉḋḍḏḑḓḕḗḙḛḝḟḡḣḥḧḩḫḭḯḱḳḵḷḹḻḽḿṁṃṅṇṉṋṍṏṑṓṕṗṙṛṝṟṡṣṥṧṩṫṭṯṱṳṵṷṹṻṽṿẁẃẅẇẉẋẍẏẑẓẕẖẗẘẙẚạảấầẩẫậắằẳẵặẹẻẽếềểễệỉịọỏốồổỗộớờởỡợụủứừửữựỳỵỷỹ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ΩKÅ';
+ $result = mb_strtolower($string);
+ $expected = 'ωkå';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ΩKÅ';
+ $result = mb_strtolower($string);
+ $expected = 'ωkå';
+ $this->assertEqual($result, $expected);
+
+/*
+mb_strtolower does not work for these strings.
+
+ $string = 'ⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩⅪⅫⅬⅭⅮⅯↃ';
+ $result = mb_strtolower($string);
+ $expected = 'ⅰⅱⅲⅳⅴⅵⅶⅷⅸⅹⅺⅻⅼⅽⅾⅿↄ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ⒶⒷⒸⒹⒺⒻⒼⒽⒾⒿⓀⓁⓂⓃⓄⓅⓆⓇⓈⓉⓊⓋⓌⓍⓎⓏ';
+ $result = mb_strtolower($string);
+ $expected = 'ⓐⓑⓒⓓⓔⓕⓖⓗⓘⓙⓚⓛⓜⓝⓞⓟⓠⓡⓢⓣⓤⓥⓦⓧⓨⓩ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ⰀⰁⰂⰃⰄⰅⰆⰇⰈⰉⰊⰋⰌⰍⰎⰏⰐⰑⰒⰓⰔⰕⰖⰗⰘⰙⰚⰛⰜⰝⰞⰟⰠⰡⰢⰣⰤⰥⰦⰧⰨⰩⰪⰫⰬⰭⰮ';
+ $result = mb_strtolower($string);
+ $expected = 'ⰰⰱⰲⰳⰴⰵⰶⰷⰸⰹⰺⰻⰼⰽⰾⰿⱀⱁⱂⱃⱄⱅⱆⱇⱈⱉⱊⱋⱌⱍⱎⱏⱐⱑⱒⱓⱔⱕⱖⱗⱘⱙⱚⱛⱜⱝⱞ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ⲀⲂⲄⲆⲈⲊⲌⲎⲐⲒⲔⲖⲘⲚⲜⲞⲠⲢⲤⲦⲨⲪⲬⲮⲰⲲⲴⲶⲸⲺⲼⲾⳀⳂⳄⳆⳈⳊⳌⳎⳐⳒⳔⳖⳘⳚⳜⳞⳠⳢ';
+ $result = mb_strtolower($string);
+ $expected = 'ⲁⲃⲅⲇⲉⲋⲍⲏⲑⲓⲕⲗⲙⲛⲝⲟⲡⲣⲥⲧⲩⲫⲭⲯⲱⲳⲵⲷⲹⲻⲽⲿⳁⳃⳅⳇⳉⳋⳍⳏⳑⳓⳕⳗⳙⳛⳝⳟⳡⳣ';
+ $this->assertEqual($result, $expected);
+*/
+ $string = 'fffiflffifflſtstﬓﬔﬕﬖﬗ';
+ $result = mb_strtolower($string);
+ $expected = 'fffiflffifflſtstﬓﬔﬕﬖﬗ';
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testMultibyteStrtolower method
+ *
+ * @access public
+ * @return void
+ */
+ function testMultibyteStrtolower() {
+ $string = '!"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`ABCDEFGHIJKLMNOPQRSTUVWXYZ{|}~';
+ $result = Multibyte::strtolower($string);
+ $expected = '!"#$%&\'()*+,-./0123456789:;<=>?@abcdefghijklmnopqrstuvwxyz[\]^_`abcdefghijklmnopqrstuvwxyz{|}~';
+ $this->assertEqual($result, $expected);
+
+ $string = '!"#$%&\'()*+,-./0123456789:;<=>?@';
+ $result = Multibyte::strtolower($string);
+ $expected = '!"#$%&\'()*+,-./0123456789:;<=>?@';
+ $this->assertEqual($result, $expected);
+
+ $string = 'À';
+ $result = Multibyte::strtolower($string);
+ $expected = 'à';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Á';
+ $result = Multibyte::strtolower($string);
+ $expected = 'á';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Â';
+ $result = Multibyte::strtolower($string);
+ $expected = 'â';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ã';
+ $result = Multibyte::strtolower($string);
+ $expected = 'ã';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ä';
+ $result = Multibyte::strtolower($string);
+ $expected = 'ä';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Å';
+ $result = Multibyte::strtolower($string);
+ $expected = 'å';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Æ';
+ $result = Multibyte::strtolower($string);
+ $expected = 'æ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ç';
+ $result = Multibyte::strtolower($string);
+ $expected = 'ç';
+ $this->assertEqual($result, $expected);
+
+ $string = 'È';
+ $result = Multibyte::strtolower($string);
+ $expected = 'è';
+ $this->assertEqual($result, $expected);
+
+ $string = 'É';
+ $result = Multibyte::strtolower($string);
+ $expected = 'é';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ê';
+ $result = Multibyte::strtolower($string);
+ $expected = 'ê';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ë';
+ $result = Multibyte::strtolower($string);
+ $expected = 'ë';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ì';
+ $result = Multibyte::strtolower($string);
+ $expected = 'ì';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Í';
+ $result = Multibyte::strtolower($string);
+ $expected = 'í';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Î';
+ $result = Multibyte::strtolower($string);
+ $expected = 'î';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ï';
+ $result = Multibyte::strtolower($string);
+ $expected = 'ï';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ð';
+ $result = Multibyte::strtolower($string);
+ $expected = 'ð';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ñ';
+ $result = Multibyte::strtolower($string);
+ $expected = 'ñ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ò';
+ $result = Multibyte::strtolower($string);
+ $expected = 'ò';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ó';
+ $result = Multibyte::strtolower($string);
+ $expected = 'ó';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ô';
+ $result = Multibyte::strtolower($string);
+ $expected = 'ô';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Õ';
+ $result = Multibyte::strtolower($string);
+ $expected = 'õ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ö';
+ $result = Multibyte::strtolower($string);
+ $expected = 'ö';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ø';
+ $result = Multibyte::strtolower($string);
+ $expected = 'ø';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ù';
+ $result = Multibyte::strtolower($string);
+ $expected = 'ù';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ú';
+ $result = Multibyte::strtolower($string);
+ $expected = 'ú';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Û';
+ $result = Multibyte::strtolower($string);
+ $expected = 'û';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ü';
+ $result = Multibyte::strtolower($string);
+ $expected = 'ü';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ý';
+ $result = Multibyte::strtolower($string);
+ $expected = 'ý';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Þ';
+ $result = Multibyte::strtolower($string);
+ $expected = 'þ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞ';
+ $result = Multibyte::strtolower($string);
+ $expected = 'àáâãäåæçèéêëìíîïðñòóôõöøùúûüýþ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ā';
+ $result = Multibyte::strtolower($string);
+ $expected = 'ā';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ă';
+ $result = Multibyte::strtolower($string);
+ $expected = 'ă';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ą';
+ $result = Multibyte::strtolower($string);
+ $expected = 'ą';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ć';
+ $result = Multibyte::strtolower($string);
+ $expected = 'ć';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ĉ';
+ $result = Multibyte::strtolower($string);
+ $expected = 'ĉ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ċ';
+ $result = Multibyte::strtolower($string);
+ $expected = 'ċ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Č';
+ $result = Multibyte::strtolower($string);
+ $expected = 'č';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ď';
+ $result = Multibyte::strtolower($string);
+ $expected = 'ď';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Đ';
+ $result = Multibyte::strtolower($string);
+ $expected = 'đ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ē';
+ $result = Multibyte::strtolower($string);
+ $expected = 'ē';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ĕ';
+ $result = Multibyte::strtolower($string);
+ $expected = 'ĕ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ė';
+ $result = Multibyte::strtolower($string);
+ $expected = 'ė';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ę';
+ $result = Multibyte::strtolower($string);
+ $expected = 'ę';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ě';
+ $result = Multibyte::strtolower($string);
+ $expected = 'ě';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ĝ';
+ $result = Multibyte::strtolower($string);
+ $expected = 'ĝ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ğ';
+ $result = Multibyte::strtolower($string);
+ $expected = 'ğ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ġ';
+ $result = Multibyte::strtolower($string);
+ $expected = 'ġ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ģ';
+ $result = Multibyte::strtolower($string);
+ $expected = 'ģ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ĥ';
+ $result = Multibyte::strtolower($string);
+ $expected = 'ĥ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ħ';
+ $result = Multibyte::strtolower($string);
+ $expected = 'ħ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ĩ';
+ $result = Multibyte::strtolower($string);
+ $expected = 'ĩ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ī';
+ $result = Multibyte::strtolower($string);
+ $expected = 'ī';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ĭ';
+ $result = Multibyte::strtolower($string);
+ $expected = 'ĭ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Į';
+ $result = Multibyte::strtolower($string);
+ $expected = 'į';
+ $this->assertEqual($result, $expected);
+
+ $string = 'IJ';
+ $result = Multibyte::strtolower($string);
+ $expected = 'ij';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ĵ';
+ $result = Multibyte::strtolower($string);
+ $expected = 'ĵ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ķ';
+ $result = Multibyte::strtolower($string);
+ $expected = 'ķ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ĺ';
+ $result = Multibyte::strtolower($string);
+ $expected = 'ĺ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ļ';
+ $result = Multibyte::strtolower($string);
+ $expected = 'ļ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ľ';
+ $result = Multibyte::strtolower($string);
+ $expected = 'ľ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ŀ';
+ $result = Multibyte::strtolower($string);
+ $expected = 'ŀ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ł';
+ $result = Multibyte::strtolower($string);
+ $expected = 'ł';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ń';
+ $result = Multibyte::strtolower($string);
+ $expected = 'ń';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ņ';
+ $result = Multibyte::strtolower($string);
+ $expected = 'ņ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ň';
+ $result = Multibyte::strtolower($string);
+ $expected = 'ň';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ŋ';
+ $result = Multibyte::strtolower($string);
+ $expected = 'ŋ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ō';
+ $result = Multibyte::strtolower($string);
+ $expected = 'ō';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ŏ';
+ $result = Multibyte::strtolower($string);
+ $expected = 'ŏ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ő';
+ $result = Multibyte::strtolower($string);
+ $expected = 'ő';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Œ';
+ $result = Multibyte::strtolower($string);
+ $expected = 'œ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ŕ';
+ $result = Multibyte::strtolower($string);
+ $expected = 'ŕ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ŗ';
+ $result = Multibyte::strtolower($string);
+ $expected = 'ŗ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ř';
+ $result = Multibyte::strtolower($string);
+ $expected = 'ř';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ś';
+ $result = Multibyte::strtolower($string);
+ $expected = 'ś';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ŝ';
+ $result = Multibyte::strtolower($string);
+ $expected = 'ŝ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ş';
+ $result = Multibyte::strtolower($string);
+ $expected = 'ş';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Š';
+ $result = Multibyte::strtolower($string);
+ $expected = 'š';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ţ';
+ $result = Multibyte::strtolower($string);
+ $expected = 'ţ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ť';
+ $result = Multibyte::strtolower($string);
+ $expected = 'ť';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ŧ';
+ $result = Multibyte::strtolower($string);
+ $expected = 'ŧ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ũ';
+ $result = Multibyte::strtolower($string);
+ $expected = 'ũ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ū';
+ $result = Multibyte::strtolower($string);
+ $expected = 'ū';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ŭ';
+ $result = Multibyte::strtolower($string);
+ $expected = 'ŭ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ů';
+ $result = Multibyte::strtolower($string);
+ $expected = 'ů';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ű';
+ $result = Multibyte::strtolower($string);
+ $expected = 'ű';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ų';
+ $result = Multibyte::strtolower($string);
+ $expected = 'ų';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ŵ';
+ $result = Multibyte::strtolower($string);
+ $expected = 'ŵ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ŷ';
+ $result = Multibyte::strtolower($string);
+ $expected = 'ŷ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ź';
+ $result = Multibyte::strtolower($string);
+ $expected = 'ź';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ż';
+ $result = Multibyte::strtolower($string);
+ $expected = 'ż';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ž';
+ $result = Multibyte::strtolower($string);
+ $expected = 'ž';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĀĂĄĆĈĊČĎĐĒĔĖĘĚĜĞĠĢĤĦĨĪĬĮIJĴĶĹĻĽĿŁŃŅŇŊŌŎŐŒŔŖŘŚŜŞŠŢŤŦŨŪŬŮŰŲŴŶŹŻŽ';
+ $result = Multibyte::strtolower($string);
+ $expected = 'āăąćĉċčďđēĕėęěĝğġģĥħĩīĭįijĵķĺļľŀłńņňŋōŏőœŕŗřśŝşšţťŧũūŭůűųŵŷźżž';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĤĒĹĻŎ, ŴŐŘĻĎ!';
+ $result = Multibyte::strtolower($string);
+ $expected = 'ĥēĺļŏ, ŵőřļď!';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĥēĺļŏ, ŵőřļď!';
+ $result = Multibyte::strtolower($string);
+ $expected = 'ĥēĺļŏ, ŵőřļď!';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ἈΙ';
+ $result = Multibyte::strtolower($string);
+ $expected = 'ἀι';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ԀԂԄԆԈԊԌԎԐԒ';
+ $result = Multibyte::strtolower($string);
+ $expected = 'ԁԃԅԇԉԋԍԏԐԒ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ԱԲԳԴԵԶԷԸԹԺԻԼԽԾԿՀՁՂՃՄՅՆՇՈՉՊՋՌՍՎՏՐՑՒՓՔՕՖև';
+ $result = Multibyte::strtolower($string);
+ $expected = 'աբգդեզէըթժիլխծկհձղճմյնշոչպջռսվտրցւփքօֆև';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ႠႡႢႣႤႥႦႧႨႩႪႫႬႭႮႯႰႱႲႳႴႵႶႷႸႹႺႻႼႽႾႿჀჁჂჃჄჅ';
+ $result = Multibyte::strtolower($string);
+ $expected = 'ႠႡႢႣႤႥႦႧႨႩႪႫႬႭႮႯႰႱႲႳႴႵႶႷႸႹႺႻႼႽႾႿჀჁჂჃჄჅ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ḀḂḄḆḈḊḌḎḐḒḔḖḘḚḜḞḠḢḤḦḨḪḬḮḰḲḴḶḸḺḼḾṀṂṄṆṈṊṌṎṐṒṔṖṘṚṜṞṠṢṤṦṨṪṬṮṰṲṴṶṸṺṼṾẀẂẄẆẈẊẌẎẐẒẔẖẗẘẙẚẠẢẤẦẨẪẬẮẰẲẴẶẸẺẼẾỀỂỄỆỈỊỌỎỐỒỔỖỘỚỜỞỠỢỤỦỨỪỬỮỰỲỴỶỸ';
+ $result = Multibyte::strtolower($string);
+ $expected = 'ḁḃḅḇḉḋḍḏḑḓḕḗḙḛḝḟḡḣḥḧḩḫḭḯḱḳḵḷḹḻḽḿṁṃṅṇṉṋṍṏṑṓṕṗṙṛṝṟṡṣṥṧṩṫṭṯṱṳṵṷṹṻṽṿẁẃẅẇẉẋẍẏẑẓẕẖẗẘẙẚạảấầẩẫậắằẳẵặẹẻẽếềểễệỉịọỏốồổỗộớờởỡợụủứừửữựỳỵỷỹ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ΩKÅℲ';
+ $result = Multibyte::strtolower($string);
+ $expected = 'ωkåⅎ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ΩKÅ';
+ $result = Multibyte::strtolower($string);
+ $expected = 'ωkå';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ΩKÅ';
+ $result = Multibyte::strtolower($string);
+ $expected = 'ωkå';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩⅪⅫⅬⅭⅮⅯↃ';
+ $result = Multibyte::strtolower($string);
+ $expected = 'ⅰⅱⅲⅳⅴⅵⅶⅷⅸⅹⅺⅻⅼⅽⅾⅿↄ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ⒶⒷⒸⒹⒺⒻⒼⒽⒾⒿⓀⓁⓂⓃⓄⓅⓆⓇⓈⓉⓊⓋⓌⓍⓎⓏ';
+ $result = Multibyte::strtolower($string);
+ $expected = 'ⓐⓑⓒⓓⓔⓕⓖⓗⓘⓙⓚⓛⓜⓝⓞⓟⓠⓡⓢⓣⓤⓥⓦⓧⓨⓩ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ⰀⰁⰂⰃⰄⰅⰆⰇⰈⰉⰊⰋⰌⰍⰎⰏⰐⰑⰒⰓⰔⰕⰖⰗⰘⰙⰚⰛⰜⰝⰞⰟⰠⰡⰢⰣⰤⰥⰦⰧⰨⰩⰪⰫⰬⰭⰮ';
+ $result = Multibyte::strtolower($string);
+ $expected = 'ⰰⰱⰲⰳⰴⰵⰶⰷⰸⰹⰺⰻⰼⰽⰾⰿⱀⱁⱂⱃⱄⱅⱆⱇⱈⱉⱊⱋⱌⱍⱎⱏⱐⱑⱒⱓⱔⱕⱖⱗⱘⱙⱚⱛⱜⱝⱞ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ⲀⲂⲄⲆⲈⲊⲌⲎⲐⲒⲔⲖⲘⲚⲜⲞⲠⲢⲤⲦⲨⲪⲬⲮⲰⲲⲴⲶⲸⲺⲼⲾⳀⳂⳄⳆⳈⳊⳌⳎⳐⳒⳔⳖⳘⳚⳜⳞⳠⳢ';
+ $result = Multibyte::strtolower($string);
+ $expected = 'ⲁⲃⲅⲇⲉⲋⲍⲏⲑⲓⲕⲗⲙⲛⲝⲟⲡⲣⲥⲧⲩⲫⲭⲯⲱⲳⲵⲷⲹⲻⲽⲿⳁⳃⳅⳇⳉⳋⳍⳏⳑⳓⳕⳗⳙⳛⳝⳟⳡⳣ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'fffiflffifflſtstﬓﬔﬕﬖﬗ';
+ $result = Multibyte::strtolower($string);
+ $expected = 'fffiflffifflſtstﬓﬔﬕﬖﬗ';
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testUsingMbStrtoupper method
+ *
+ * @access public
+ * @return void
+ */
+ function testUsingMbStrtoupper() {
+ $string = '!"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~';
+ $result = mb_strtoupper($string);
+ $expected = '!"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`ABCDEFGHIJKLMNOPQRSTUVWXYZ{|}~';
+ $this->assertEqual($result, $expected);
+
+ $string = '!"#$%&\'()*+,-./0123456789:;<=>?@';
+ $result = mb_strtoupper($string);
+ $expected = '!"#$%&\'()*+,-./0123456789:;<=>?@';
+ $this->assertEqual($result, $expected);
+
+ $string = 'à';
+ $result = mb_strtoupper($string);
+ $expected = 'À';
+ $this->assertEqual($result, $expected);
+
+ $string = 'á';
+ $result = mb_strtoupper($string);
+ $expected = 'Á';
+ $this->assertEqual($result, $expected);
+
+ $string = 'â';
+ $result = mb_strtoupper($string);
+ $expected = 'Â';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ã';
+ $result = mb_strtoupper($string);
+ $expected = 'Ã';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ä';
+ $result = mb_strtoupper($string);
+ $expected = 'Ä';
+ $this->assertEqual($result, $expected);
+
+ $string = 'å';
+ $result = mb_strtoupper($string);
+ $expected = 'Å';
+ $this->assertEqual($result, $expected);
+
+ $string = 'æ';
+ $result = mb_strtoupper($string);
+ $expected = 'Æ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ç';
+ $result = mb_strtoupper($string);
+ $expected = 'Ç';
+ $this->assertEqual($result, $expected);
+
+ $string = 'è';
+ $result = mb_strtoupper($string);
+ $expected = 'È';
+ $this->assertEqual($result, $expected);
+
+ $string = 'é';
+ $result = mb_strtoupper($string);
+ $expected = 'É';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ê';
+ $result = mb_strtoupper($string);
+ $expected = 'Ê';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ë';
+ $result = mb_strtoupper($string);
+ $expected = 'Ë';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ì';
+ $result = mb_strtoupper($string);
+ $expected = 'Ì';
+ $this->assertEqual($result, $expected);
+
+ $string = 'í';
+ $result = mb_strtoupper($string);
+ $expected = 'Í';
+ $this->assertEqual($result, $expected);
+
+ $string = 'î';
+ $result = mb_strtoupper($string);
+ $expected = 'Î';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ï';
+ $result = mb_strtoupper($string);
+ $expected = 'Ï';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ð';
+ $result = mb_strtoupper($string);
+ $expected = 'Ð';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ñ';
+ $result = mb_strtoupper($string);
+ $expected = 'Ñ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ò';
+ $result = mb_strtoupper($string);
+ $expected = 'Ò';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ó';
+ $result = mb_strtoupper($string);
+ $expected = 'Ó';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ô';
+ $result = mb_strtoupper($string);
+ $expected = 'Ô';
+ $this->assertEqual($result, $expected);
+
+ $string = 'õ';
+ $result = mb_strtoupper($string);
+ $expected = 'Õ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ö';
+ $result = mb_strtoupper($string);
+ $expected = 'Ö';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ø';
+ $result = mb_strtoupper($string);
+ $expected = 'Ø';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ù';
+ $result = mb_strtoupper($string);
+ $expected = 'Ù';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ú';
+ $result = mb_strtoupper($string);
+ $expected = 'Ú';
+ $this->assertEqual($result, $expected);
+
+ $string = 'û';
+ $result = mb_strtoupper($string);
+ $expected = 'Û';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ü';
+ $result = mb_strtoupper($string);
+ $expected = 'Ü';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ý';
+ $result = mb_strtoupper($string);
+ $expected = 'Ý';
+ $this->assertEqual($result, $expected);
+
+ $string = 'þ';
+ $result = mb_strtoupper($string);
+ $expected = 'Þ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'àáâãäåæçèéêëìíîïðñòóôõöøùúûüýþ';
+ $result = mb_strtoupper($string);
+ $expected = 'ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ā';
+ $result = mb_strtoupper($string);
+ $expected = 'Ā';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ă';
+ $result = mb_strtoupper($string);
+ $expected = 'Ă';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ą';
+ $result = mb_strtoupper($string);
+ $expected = 'Ą';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ć';
+ $result = mb_strtoupper($string);
+ $expected = 'Ć';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĉ';
+ $result = mb_strtoupper($string);
+ $expected = 'Ĉ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ċ';
+ $result = mb_strtoupper($string);
+ $expected = 'Ċ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'č';
+ $result = mb_strtoupper($string);
+ $expected = 'Č';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ď';
+ $result = mb_strtoupper($string);
+ $expected = 'Ď';
+ $this->assertEqual($result, $expected);
+
+ $string = 'đ';
+ $result = mb_strtoupper($string);
+ $expected = 'Đ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ē';
+ $result = mb_strtoupper($string);
+ $expected = 'Ē';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĕ';
+ $result = mb_strtoupper($string);
+ $expected = 'Ĕ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ė';
+ $result = mb_strtoupper($string);
+ $expected = 'Ė';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ę';
+ $result = mb_strtoupper($string);
+ $expected = 'Ę';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ě';
+ $result = mb_strtoupper($string);
+ $expected = 'Ě';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĝ';
+ $result = mb_strtoupper($string);
+ $expected = 'Ĝ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ğ';
+ $result = mb_strtoupper($string);
+ $expected = 'Ğ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ġ';
+ $result = mb_strtoupper($string);
+ $expected = 'Ġ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ģ';
+ $result = mb_strtoupper($string);
+ $expected = 'Ģ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĥ';
+ $result = mb_strtoupper($string);
+ $expected = 'Ĥ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ħ';
+ $result = mb_strtoupper($string);
+ $expected = 'Ħ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĩ';
+ $result = mb_strtoupper($string);
+ $expected = 'Ĩ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ī';
+ $result = mb_strtoupper($string);
+ $expected = 'Ī';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĭ';
+ $result = mb_strtoupper($string);
+ $expected = 'Ĭ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'į';
+ $result = mb_strtoupper($string);
+ $expected = 'Į';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ij';
+ $result = mb_strtoupper($string);
+ $expected = 'IJ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĵ';
+ $result = mb_strtoupper($string);
+ $expected = 'Ĵ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ķ';
+ $result = mb_strtoupper($string);
+ $expected = 'Ķ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĺ';
+ $result = mb_strtoupper($string);
+ $expected = 'Ĺ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ļ';
+ $result = mb_strtoupper($string);
+ $expected = 'Ļ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ľ';
+ $result = mb_strtoupper($string);
+ $expected = 'Ľ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ŀ';
+ $result = mb_strtoupper($string);
+ $expected = 'Ŀ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ł';
+ $result = mb_strtoupper($string);
+ $expected = 'Ł';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ń';
+ $result = mb_strtoupper($string);
+ $expected = 'Ń';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ņ';
+ $result = mb_strtoupper($string);
+ $expected = 'Ņ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ň';
+ $result = mb_strtoupper($string);
+ $expected = 'Ň';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ŋ';
+ $result = mb_strtoupper($string);
+ $expected = 'Ŋ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ō';
+ $result = mb_strtoupper($string);
+ $expected = 'Ō';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ŏ';
+ $result = mb_strtoupper($string);
+ $expected = 'Ŏ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ő';
+ $result = mb_strtoupper($string);
+ $expected = 'Ő';
+ $this->assertEqual($result, $expected);
+
+ $string = 'œ';
+ $result = mb_strtoupper($string);
+ $expected = 'Œ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ŕ';
+ $result = mb_strtoupper($string);
+ $expected = 'Ŕ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ŗ';
+ $result = mb_strtoupper($string);
+ $expected = 'Ŗ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ř';
+ $result = mb_strtoupper($string);
+ $expected = 'Ř';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ś';
+ $result = mb_strtoupper($string);
+ $expected = 'Ś';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ŝ';
+ $result = mb_strtoupper($string);
+ $expected = 'Ŝ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ş';
+ $result = mb_strtoupper($string);
+ $expected = 'Ş';
+ $this->assertEqual($result, $expected);
+
+ $string = 'š';
+ $result = mb_strtoupper($string);
+ $expected = 'Š';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ţ';
+ $result = mb_strtoupper($string);
+ $expected = 'Ţ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ť';
+ $result = mb_strtoupper($string);
+ $expected = 'Ť';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ŧ';
+ $result = mb_strtoupper($string);
+ $expected = 'Ŧ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ũ';
+ $result = mb_strtoupper($string);
+ $expected = 'Ũ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ū';
+ $result = mb_strtoupper($string);
+ $expected = 'Ū';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ŭ';
+ $result = mb_strtoupper($string);
+ $expected = 'Ŭ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ů';
+ $result = mb_strtoupper($string);
+ $expected = 'Ů';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ű';
+ $result = mb_strtoupper($string);
+ $expected = 'Ű';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ų';
+ $result = mb_strtoupper($string);
+ $expected = 'Ų';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ŵ';
+ $result = mb_strtoupper($string);
+ $expected = 'Ŵ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ŷ';
+ $result = mb_strtoupper($string);
+ $expected = 'Ŷ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ź';
+ $result = mb_strtoupper($string);
+ $expected = 'Ź';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ż';
+ $result = mb_strtoupper($string);
+ $expected = 'Ż';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ž';
+ $result = mb_strtoupper($string);
+ $expected = 'Ž';
+ $this->assertEqual($result, $expected);
+
+ $string = 'āăąćĉċčďđēĕėęěĝğġģĥħĩīĭįijĵķĺļľŀłńņňŋōŏőœŕŗřśŝşšţťŧũūŭůűųŵŷźżž';
+ $result = mb_strtoupper($string);
+ $expected = 'ĀĂĄĆĈĊČĎĐĒĔĖĘĚĜĞĠĢĤĦĨĪĬĮIJĴĶĹĻĽĿŁŃŅŇŊŌŎŐŒŔŖŘŚŜŞŠŢŤŦŨŪŬŮŰŲŴŶŹŻŽ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ĥēĺļŏ, Ŵőřļď!';
+ $result = mb_strtoupper($string);
+ $expected = 'ĤĒĹĻŎ, ŴŐŘĻĎ!';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ἀι';
+ $result = mb_strtoupper($string);
+ $expected = 'ἈΙ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ԁԃԅԇԉԋԍԏԐԒ';
+ $result = mb_strtoupper($string);
+ $expected = 'ԀԂԄԆԈԊԌԎԐԒ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'աբգդեզէըթժիլխծկհձղճմյնշոչպջռսվտրցւփքօֆև';
+ $result = mb_strtoupper($string);
+ $expected = 'ԱԲԳԴԵԶԷԸԹԺԻԼԽԾԿՀՁՂՃՄՅՆՇՈՉՊՋՌՍՎՏՐՑՒՓՔՕՖև';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ႠႡႢႣႤႥႦႧႨႩႪႫႬႭႮႯႰႱႲႳႴႵႶႷႸႹႺႻႼႽႾႿჀჁჂჃჄჅ';
+ $result = mb_strtoupper($string);
+ $expected = 'ႠႡႢႣႤႥႦႧႨႩႪႫႬႭႮႯႰႱႲႳႴႵႶႷႸႹႺႻႼႽႾႿჀჁჂჃჄჅ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ḁḃḅḇḉḋḍḏḑḓḕḗḙḛḝḟḡḣḥḧḩḫḭḯḱḳḵḷḹḻḽḿṁṃṅṇṉṋṍṏṑṓṕṗṙṛṝṟṡṣṥṧṩṫṭṯṱṳṵṷṹṻṽṿẁẃẅẇẉẋẍẏẑẓẕẖẗẘẙẚạảấầẩẫậắằẳẵặẹẻẽếềểễệỉịọỏốồổỗộớờởỡợụủứừửữựỳỵỷỹ';
+ $result = mb_strtoupper($string);
+ $expected = 'ḀḂḄḆḈḊḌḎḐḒḔḖḘḚḜḞḠḢḤḦḨḪḬḮḰḲḴḶḸḺḼḾṀṂṄṆṈṊṌṎṐṒṔṖṘṚṜṞṠṢṤṦṨṪṬṮṰṲṴṶṸṺṼṾẀẂẄẆẈẊẌẎẐẒẔẖẗẘẙẚẠẢẤẦẨẪẬẮẰẲẴẶẸẺẼẾỀỂỄỆỈỊỌỎỐỒỔỖỘỚỜỞỠỢỤỦỨỪỬỮỰỲỴỶỸ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ωkå';
+ $result = mb_strtoupper($string);
+ $expected = 'ΩKÅ';
+ $this->assertEqual($result, $expected);
+
+/*
+mb_strtoupper does not work for these strings.
+
+ $string = 'ⅰⅱⅲⅳⅴⅵⅶⅷⅸⅹⅺⅻⅼⅽⅾⅿↄ';
+ $result = mb_strtoupper($string);
+ $expected = 'ⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩⅪⅫⅬⅭⅮⅯↃ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ⓐⓑⓒⓓⓔⓕⓖⓗⓘⓙⓚⓛⓜⓝⓞⓟⓠⓡⓢⓣⓤⓥⓦⓧⓨⓩ';
+ $result = mb_strtoupper($string);
+ $expected = 'ⒶⒷⒸⒹⒺⒻⒼⒽⒾⒿⓀⓁⓂⓃⓄⓅⓆⓇⓈⓉⓊⓋⓌⓍⓎⓏ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ⰰⰱⰲⰳⰴⰵⰶⰷⰸⰹⰺⰻⰼⰽⰾⰿⱀⱁⱂⱃⱄⱅⱆⱇⱈⱉⱊⱋⱌⱍⱎⱏⱐⱑⱒⱓⱔⱕⱖⱗⱘⱙⱚⱛⱜⱝⱞ';
+ $result = mb_strtoupper($string);
+ $expected = 'ⰀⰁⰂⰃⰄⰅⰆⰇⰈⰉⰊⰋⰌⰍⰎⰏⰐⰑⰒⰓⰔⰕⰖⰗⰘⰙⰚⰛⰜⰝⰞⰟⰠⰡⰢⰣⰤⰥⰦⰧⰨⰩⰪⰫⰬⰭⰮ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ⲁⲃⲅⲇⲉⲋⲍⲏⲑⲓⲕⲗⲙⲛⲝⲟⲡⲣⲥⲧⲩⲫⲭⲯⲱⲳⲵⲷⲹⲻⲽⲿⳁⳃⳅⳇⳉⳋⳍⳏⳑⳓⳕⳗⳙⳛⳝⳟⳡⳣ';
+ $result = mb_strtoupper($string);
+ $expected = 'ⲀⲂⲄⲆⲈⲊⲌⲎⲐⲒⲔⲖⲘⲚⲜⲞⲠⲢⲤⲦⲨⲪⲬⲮⲰⲲⲴⲶⲸⲺⲼⲾⳀⳂⳄⳆⳈⳊⳌⳎⳐⳒⳔⳖⳘⳚⳜⳞⳠⳢ';
+ $this->assertEqual($result, $expected);
+*/
+ $string = 'fffiflffifflſtstﬓﬔﬕﬖﬗ';
+ $result = mb_strtoupper($string);
+ $expected = 'fffiflffifflſtstﬓﬔﬕﬖﬗ';
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testMultibyteStrtoupper method
+ *
+ * @access public
+ * @return void
+ */
+ function testMultibyteStrtoupper() {
+ $string = '!"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~';
+ $result = Multibyte::strtoupper($string);
+ $expected = '!"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`ABCDEFGHIJKLMNOPQRSTUVWXYZ{|}~';
+ $this->assertEqual($result, $expected);
+
+ $string = '!"#$%&\'()*+,-./0123456789:;<=>?@';
+ $result = Multibyte::strtoupper($string);
+ $expected = '!"#$%&\'()*+,-./0123456789:;<=>?@';
+ $this->assertEqual($result, $expected);
+
+ $string = 'à';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'À';
+ $this->assertEqual($result, $expected);
+
+ $string = 'á';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'Á';
+ $this->assertEqual($result, $expected);
+
+ $string = 'â';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'Â';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ã';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'Ã';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ä';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'Ä';
+ $this->assertEqual($result, $expected);
+
+ $string = 'å';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'Å';
+ $this->assertEqual($result, $expected);
+
+ $string = 'æ';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'Æ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ç';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'Ç';
+ $this->assertEqual($result, $expected);
+
+ $string = 'è';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'È';
+ $this->assertEqual($result, $expected);
+
+ $string = 'é';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'É';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ê';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'Ê';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ë';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'Ë';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ì';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'Ì';
+ $this->assertEqual($result, $expected);
+
+ $string = 'í';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'Í';
+ $this->assertEqual($result, $expected);
+
+ $string = 'î';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'Î';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ï';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'Ï';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ð';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'Ð';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ñ';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'Ñ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ò';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'Ò';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ó';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'Ó';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ô';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'Ô';
+ $this->assertEqual($result, $expected);
+
+ $string = 'õ';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'Õ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ö';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'Ö';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ø';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'Ø';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ù';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'Ù';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ú';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'Ú';
+ $this->assertEqual($result, $expected);
+
+ $string = 'û';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'Û';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ü';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'Ü';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ý';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'Ý';
+ $this->assertEqual($result, $expected);
+
+ $string = 'þ';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'Þ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'àáâãäåæçèéêëìíîïðñòóôõöøùúûüýþ';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ā';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'Ā';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ă';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'Ă';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ą';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'Ą';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ć';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'Ć';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĉ';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'Ĉ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ċ';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'Ċ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'č';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'Č';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ď';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'Ď';
+ $this->assertEqual($result, $expected);
+
+ $string = 'đ';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'Đ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ē';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'Ē';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĕ';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'Ĕ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ė';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'Ė';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ę';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'Ę';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ě';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'Ě';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĝ';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'Ĝ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ğ';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'Ğ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ġ';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'Ġ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ģ';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'Ģ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĥ';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'Ĥ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ħ';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'Ħ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĩ';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'Ĩ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ī';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'Ī';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĭ';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'Ĭ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'į';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'Į';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ij';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'IJ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĵ';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'Ĵ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ķ';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'Ķ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĺ';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'Ĺ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ļ';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'Ļ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ľ';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'Ľ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ŀ';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'Ŀ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ł';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'Ł';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ń';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'Ń';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ņ';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'Ņ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ň';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'Ň';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ŋ';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'Ŋ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ō';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'Ō';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ŏ';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'Ŏ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ő';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'Ő';
+ $this->assertEqual($result, $expected);
+
+ $string = 'œ';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'Œ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ŕ';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'Ŕ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ŗ';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'Ŗ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ř';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'Ř';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ś';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'Ś';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ŝ';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'Ŝ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ş';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'Ş';
+ $this->assertEqual($result, $expected);
+
+ $string = 'š';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'Š';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ţ';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'Ţ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ť';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'Ť';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ŧ';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'Ŧ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ũ';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'Ũ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ū';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'Ū';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ŭ';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'Ŭ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ů';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'Ů';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ű';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'Ű';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ų';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'Ų';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ŵ';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'Ŵ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ŷ';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'Ŷ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ź';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'Ź';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ż';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'Ż';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ž';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'Ž';
+ $this->assertEqual($result, $expected);
+
+ $string = 'āăąćĉċčďđēĕėęěĝğġģĥħĩīĭįijĵķĺļľŀłńņňŋōŏőœŕŗřśŝşšţťŧũūŭůűųŵŷźżž';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'ĀĂĄĆĈĊČĎĐĒĔĖĘĚĜĞĠĢĤĦĨĪĬĮIJĴĶĹĻĽĿŁŃŅŇŊŌŎŐŒŔŖŘŚŜŞŠŢŤŦŨŪŬŮŰŲŴŶŹŻŽ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ĥēĺļŏ, Ŵőřļď!';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'ĤĒĹĻŎ, ŴŐŘĻĎ!';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ἀι';
+ $result = mb_strtoupper($string);
+ $expected = 'ἈΙ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ἀι';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'ἈΙ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ԁԃԅԇԉԋԍԏԐԒ';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'ԀԂԄԆԈԊԌԎԐԒ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'աբգդեզէըթժիլխծկհձղճմյնշոչպջռսվտրցւփքօֆև';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'ԱԲԳԴԵԶԷԸԹԺԻԼԽԾԿՀՁՂՃՄՅՆՇՈՉՊՋՌՍՎՏՐՑՒՓՔՕՖև';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ႠႡႢႣႤႥႦႧႨႩႪႫႬႭႮႯႰႱႲႳႴႵႶႷႸႹႺႻႼႽႾႿჀჁჂჃჄჅ';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'ႠႡႢႣႤႥႦႧႨႩႪႫႬႭႮႯႰႱႲႳႴႵႶႷႸႹႺႻႼႽႾႿჀჁჂჃჄჅ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ḁḃḅḇḉḋḍḏḑḓḕḗḙḛḝḟḡḣḥḧḩḫḭḯḱḳḵḷḹḻḽḿṁṃṅṇṉṋṍṏṑṓṕṗṙṛṝṟṡṣṥṧṩṫṭṯṱṳṵṷṹṻṽṿẁẃẅẇẉẋẍẏẑẓẕẖẗẘẙẚạảấầẩẫậắằẳẵặẹẻẽếềểễệỉịọỏốồổỗộớờởỡợụủứừửữựỳỵỷỹ';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'ḀḂḄḆḈḊḌḎḐḒḔḖḘḚḜḞḠḢḤḦḨḪḬḮḰḲḴḶḸḺḼḾṀṂṄṆṈṊṌṎṐṒṔṖṘṚṜṞṠṢṤṦṨṪṬṮṰṲṴṶṸṺṼṾẀẂẄẆẈẊẌẎẐẒẔẖẗẘẙẚẠẢẤẦẨẪẬẮẰẲẴẶẸẺẼẾỀỂỄỆỈỊỌỎỐỒỔỖỘỚỜỞỠỢỤỦỨỪỬỮỰỲỴỶỸ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ωkåⅎ';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'ΩKÅℲ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ωkå';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'ΩKÅ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ⅰⅱⅲⅳⅴⅵⅶⅷⅸⅹⅺⅻⅼⅽⅾⅿↄ';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'ⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩⅪⅫⅬⅭⅮⅯↃ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ⓐⓑⓒⓓⓔⓕⓖⓗⓘⓙⓚⓛⓜⓝⓞⓟⓠⓡⓢⓣⓤⓥⓦⓧⓨⓩ';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'ⒶⒷⒸⒹⒺⒻⒼⒽⒾⒿⓀⓁⓂⓃⓄⓅⓆⓇⓈⓉⓊⓋⓌⓍⓎⓏ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ⰰⰱⰲⰳⰴⰵⰶⰷⰸⰹⰺⰻⰼⰽⰾⰿⱀⱁⱂⱃⱄⱅⱆⱇⱈⱉⱊⱋⱌⱍⱎⱏⱐⱑⱒⱓⱔⱕⱖⱗⱘⱙⱚⱛⱜⱝⱞ';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'ⰀⰁⰂⰃⰄⰅⰆⰇⰈⰉⰊⰋⰌⰍⰎⰏⰐⰑⰒⰓⰔⰕⰖⰗⰘⰙⰚⰛⰜⰝⰞⰟⰠⰡⰢⰣⰤⰥⰦⰧⰨⰩⰪⰫⰬⰭⰮ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ⲁⲃⲅⲇⲉⲋⲍⲏⲑⲓⲕⲗⲙⲛⲝⲟⲡⲣⲥⲧⲩⲫⲭⲯⲱⲳⲵⲷⲹⲻⲽⲿⳁⳃⳅⳇⳉⳋⳍⳏⳑⳓⳕⳗⳙⳛⳝⳟⳡⳣ';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'ⲀⲂⲄⲆⲈⲊⲌⲎⲐⲒⲔⲖⲘⲚⲜⲞⲠⲢⲤⲦⲨⲪⲬⲮⲰⲲⲴⲶⲸⲺⲼⲾⳀⳂⳄⳆⳈⳊⳌⳎⳐⳒⳔⳖⳘⳚⳜⳞⳠⳢ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'fffiflffifflſtstﬓﬔﬕﬖﬗ';
+ $result = Multibyte::strtoupper($string);
+ $expected = 'fffiflffifflſtstﬓﬔﬕﬖﬗ';
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testUsingMbSubstrCount method
+ *
+ * @access public
+ * @return void
+ */
+ function testUsingMbSubstrCount() {
+ $string = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
+ $find = 'F';
+ $result = mb_substr_count($string, $find);
+ $expected = 1;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ABCDEFGHIJKLMNOPQFRSFTUVWXYZ0F12345F6789';
+ $find = 'F';
+ $result = mb_substr_count($string, $find);
+ $expected = 5;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ÀÁÂÃÄÅÆÇÈÉÅÊËÌÍÎÏÐÑÒÓÔÅÕÖØÅÙÚÛÅÜÝÞ';
+ $find = 'Å';
+ $result = mb_substr_count($string, $find);
+ $expected = 5;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ÀÁÙÚÂÃÄÅÆÇÈÙÚÉÊËÌÍÎÏÐÑÒÓÔÕÖØÅÙÚÛÜÝÞÙÚ';
+ $find = 'ÙÚ';
+ $result = mb_substr_count($string, $find);
+ $expected = 4;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ÀÁÂÃÄÅÆÇÈÉÊÅËÌÍÎÏÐÑÒÓÔÕÅÖØÅÙÚÅÛÜÅÝÞÅ';
+ $find = 'Å';
+ $result = mb_substr_count($string, $find);
+ $expected = 7;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĊĀĂĄĆĈĊČĎĐĒĔĖĊĘĚĜĞĠĢĤĦĨĪĬĮĊIJĴĶĹĻĽĿŁŃŅŇŊŌĊŎŐŒŔŖŘŚŜŞŠŢĊŤŦŨŪŬŮŰĊŲŴŶŹŻŽ';
+ $find = 'Ċ';
+ $result = mb_substr_count($string, $find);
+ $expected = 7;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĀĂĄĆĈĊČĎĐĒĔĖĘĚĜĊĞĠĢĤĦĨĪĬĮIJĴĶĹĻĽĿŁĊŃŅĊŇŊŌŎŐŒŔŖĊŘŚŜŞŠŢŤŦŨŪŬŮŰŲŴŶŹŻŽ';
+ $find = 'Ċ';
+ $result = mb_substr_count($string, $find);
+ $expected = 5;
+ $this->assertEqual($result, $expected);
+
+ $string = '!"#$%&\'()*+,-./012F34567F89:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghiFjklmnopqFrstuvwFxyz{|}~';
+ $find = 'F';
+ $result = mb_substr_count($string, $find);
+ $expected = 6;
+ $this->assertEqual($result, $expected);
+
+ $string = '¡¢£¤¥µ¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁµÂõÄÅÆǵÈ';
+ $find = 'µ';
+ $result = mb_substr_count($string, $find);
+ $expected = 5;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôÕÖõö÷øùúûüýþÿĀāĂ㥹ĆćĈĉÕÖĊċČčĎďĐđĒēĔĕĖėĘęĚěĜĝÕÖĞğĠġĢģĤĥĦÕÖħĨĩĪīĬ';
+ $find = 'ÕÖ';
+ $result = mb_substr_count($string, $find);
+ $expected = 5;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĭĮįİıIJijĴĵĶķĸĹĺĻļĽľĿŀŁłŃńŅņŇňʼnŊŋŌōĵĶķĸĹŎŏŐőŒœŔŕŖŗŘřŚśŜŝŞşŠšĵĶķĸĹŢţŤťŦŧŨũŪūŬŭŮůŰűŲųĵĶķĸĹŴŵŶŷŸŹźŻżŽžſƀƁƂƃƄƅƆƇƈƉƊƋƌƍƎƏƐ';
+ $find = 'ĵĶķĸĹ';
+ $result = mb_substr_count($string, $find);
+ $expected = 4;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ƑƒƓƔƕƖƸƗƘƙƚƛƜƝƞƟƠơƢƣƤƥƦƧƨƩƪƫƬƭƮƯưƱƲƳƴƵƶƷƸƹƺƻƼƽƾƿǀǁǂǃDŽDždžLJLjljNJƸNjnjǍǎǏǐǑǒǓƸǔǕǖǗǘǙǚƸǛǜǝǞǟǠǡǢǣǤǥǦǧǨǩǪǫǬǭǮǯǰDZDzdzǴ';
+ $find = 'Ƹ';
+ $result = mb_substr_count($string, $find);
+ $expected = 5;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ƑƒƓƔƕƖƗƘƙƚƛƜƝƞƟƹƠơƢƣƤƥƦƧƨƩƹƪƫƬƭƮƯưƱƲƳƴƹƵƶƷƸƹƺƻƼƽƾƿǀǁǂƹǃDŽDždžLJLjljNJNjnjǍǎǏǐǑǒǓǔǕǖǗǘǙǚǛǜǝǞǟǠǡǢǣǤǥǦǧǨǩǪǫǬǭǮǯǰDZDzdzǴ';
+ $find = 'ƹ';
+ $result = mb_substr_count($string, $find);
+ $expected = 5;
+ $this->assertEqual($result, $expected);
+
+ $string = 'əɚɛɜɝɞʀɟɠɡɢɣɤɥɦɧɨɩɪɫɬɭɮɯɰɱɲɳɴɵɶɷɸɹɺɻɼɽɾɿʀʁʂʃʄʅʆʀʇʈʉʊʋʌʍʎʏʐʑʒʓʔʕʖʗʘʙʚʛʜʝʞʟʠʡʢʣʤʥʦʧʀʨʩʪʫʬʭʮʯʰʱʲʳʴʵʶʷʸʹʺʀʻʼ';
+ $find = 'ʀ';
+ $result = mb_substr_count($string, $find);
+ $expected = 5;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ЀЁЂЃЄЅІЇЈЉЊЋЌЍЇЎЏАБВГДЕЖЗИЙКЛ';
+ $find = 'Ї';
+ $result = mb_substr_count($string, $find);
+ $expected = 2;
+ $this->assertEqual($result, $expected);
+
+ $string = 'МНОПРСРТУФХЦЧШЩЪЫЬРЭЮЯабРвгдежзийклРмнопрстуфхцчшщъыь';
+ $find = 'Р';
+ $result = mb_substr_count($string, $find);
+ $expected = 5;
+ $this->assertEqual($result, $expected);
+
+ $string = 'МНОПРСрТУФХЦЧШЩЪЫрЬЭЮЯабвгдежзийклмнопррстуфхцчшщъыь';
+ $find = 'р';
+ $result = mb_substr_count($string, $find);
+ $expected = 4;
+ $this->assertEqual($result, $expected);
+
+ $string = 'فنقكلنمنهونىينًٌٍَُ';
+ $find = 'ن';
+ $result = mb_substr_count($string, $find);
+ $expected = 5;
+ $this->assertEqual($result, $expected);
+
+ $string = '✰✱✲✳✿✴✵✶✷✸✿✹✺✻✼✽✾✿❀❁❂❃❄❅❆✿❇❈❉❊❋❌❍❎❏❐❑❒❓❔❕❖❗❘❙❚❛❜❝❞';
+ $find = '✿';
+ $result = mb_substr_count($string, $find);
+ $expected = 4;
+ $this->assertEqual($result, $expected);
+
+ $string = '⺀⺁⺂⺃⺄⺅⺆⺇⺈⺉⺐⺊⺋⺌⺍⺎⺏⺐⺑⺒⺓⺔⺕⺖⺗⺘⺙⺛⺜⺝⺞⺟⺠⺡⺢⺣⺤⺥⺦⺧⺨⺐⺩⺪⺫⺬⺭⺮⺯⺰⺱⺲⺳⺴⺵⺶⺷⺸⺹⺺⺻⺼⺽⺾⺿⻀⻁⻂⻃⻄⻅⻆⻇⻈⻉⺐⻊⻋⻌⻍⻎⻏⻐⻑⻒⻓⻔⻕⻖⻗⻘⻙⻚⻛⻜⻝⻞⻟⻠';
+ $find = '⺐';
+ $result = mb_substr_count($string, $find);
+ $expected = 4;
+ $this->assertEqual($result, $expected);
+
+ $string = '⽅⽆⽇⽈⽉⽊⽋⽌⽍⽎⽏⽐⽑⽒⽓⽔⽕⽖⽤⽗⽘⽙⽚⽛⽜⽝⽞⽟⽠⽡⽢⽣⽤⽥⽦⽧⽨⽩⽪⽫⽬⽭⽮⽯⽰⽱⽲⽳⽴⽵⽤⽶⽷⽸⽹⽺⽻⽼⽽⽾⽿';
+ $find = '⽤';
+ $result = mb_substr_count($string, $find);
+ $expected = 3;
+ $this->assertEqual($result, $expected);
+
+ $string = '눡눢눣눤눥눦눺눻눼눧눨눩눪눫눬눭눮눯눰눱눲눳눴눵눶눷눸눹눺눻눼눽눾눿뉀뉁뉂뉃뉄뉅뉆뉇뉈뉉뉊뉋뉌뉍뉎뉏뉐뉑뉒뉓뉔뉕눺눻눼뉖뉗뉘뉙뉚뉛뉜뉝눺눻눼뉞뉟뉠뉡뉢뉣뉤뉥뉦뉧뉨뉩뉪뉫뉬뉭뉮뉯뉰뉱뉲뉳뉴뉵뉶뉷뉸뉹뉺뉻뉼뉽뉾뉿늀늁늂늃늄';
+ $find = '눺눻눼';
+ $result = mb_substr_count($string, $find);
+ $expected = 4;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ﺞﺟﺠﺡﹰﹱﹲﹳﹴﹶﹷﹸﹹﹺﹻﹼﹽﹾﹿﺀﺁﺂﺃﺄﺅﺞﺟﺠﺡﺆﺇﺞﺟﺠﺡﺈﺉﺊﺋﺌﺍﺎﺏﺐﺑﺒﺓﺔﺕﺖﺗﺘﺙﺚﺛﺜﺝﺞﺟﺠﺡﺢﺣﺤﺥﺦﺧﺨﺩﺪﺫﺬﺭﺮﺯﺰ';
+ $find = 'ﺞﺟﺠﺡ';
+ $result = mb_substr_count($string, $find);
+ $expected = 4;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ﺱﺲﺳﺴﺵﺶﺷﺸﺹﺺﺻﺼﻞﺽﺾﺿﻀﻁﻂﻃﻄﻅﻆﻇﻈﻉﻊﻋﻌﻍﻎﻏﻐﻑﻒﻓﻔﻞﻕﻖﻗﻘﻙﻚﻛﻜﻝﻞﻟﻠﻡﻢﻣﻤﻥﻦﻧﻨﻩﻪﻫﻬﻭﻮﻯﻰﻱﻲﻳﻴﻵﻶﻷﻞﻸﻹﻺﻞﻻﻼ';
+ $find = 'ﻞ';
+ $result = mb_substr_count($string, $find);
+ $expected = 5;
+ $this->assertEqual($result, $expected);
+
+ $string = 'abcdkefghijklmnopqrstuvwxkyz';
+ $find = 'k';
+ $result = mb_substr_count($string, $find);
+ $expected = 3;
+ $this->assertEqual($result, $expected);
+
+ $string = 'abklmcdefghijklmnopqrstuvklmwxyz';
+ $find = 'klm';
+ $result = mb_substr_count($string, $find);
+ $expected = 3;
+ $this->assertEqual($result, $expected);
+
+ $string = 'abcdppefghijklmnoppqrstuvwxyz';
+ $find = 'ppe';
+ $result = mb_substr_count($string, $find);
+ $expected = 1;
+ $this->assertEqual($result, $expected);
+
+ $string = '。「」、・ヲァィゥェォャュョッーアイウエオカキク';
+ $find = 'ア';
+ $result = mb_substr_count($string, $find);
+ $expected = 1;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン゙';
+ $find = 'ハ';
+ $result = mb_substr_count($string, $find);
+ $expected = 1;
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ĥēĺļŏ, Ŵőřļď!';
+ $find = 'ő';
+ $result = mb_substr_count($string, $find);
+ $expected = 1;
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ĥēĺļŏ, Ŵőřļď!';
+ $find = 'ĺļ';
+ $result = mb_substr_count($string, $find);
+ $expected = 1;
+ $this->assertEqual($result, $expected);
+
+ $string = 'Hello, World!';
+ $find = 'o';
+ $result = mb_substr_count($string, $find);
+ $expected = 2;
+ $this->assertEqual($result, $expected);
+
+ $string = 'Hello, World!';
+ $find = 'rl';
+ $result = mb_substr_count($string, $find);
+ $expected = 1;
+ $this->assertEqual($result, $expected);
+
+ $string = 'čini';
+ $find = 'n';
+ $result = mb_substr_count($string, $find);
+ $expected = 1;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ničiničiini';
+ $find = 'n';
+ $result = mb_substr_count($string, $find);
+ $expected = 3;
+ $this->assertEqual($result, $expected);
+
+ $string = 'moći';
+ $find = 'ć';
+ $result = mb_substr_count($string, $find);
+ $expected = 1;
+ $this->assertEqual($result, $expected);
+
+ $string = 'moćimoćimoćmćioći';
+ $find = 'ći';
+ $result = mb_substr_count($string, $find);
+ $expected = 4;
+ $this->assertEqual($result, $expected);
+
+ $string = 'državni';
+ $find = 'ž';
+ $result = mb_substr_count($string, $find);
+ $expected = 1;
+ $this->assertEqual($result, $expected);
+
+ $string = '把百度设为首页';
+ $find = '设';
+ $result = mb_substr_count($string, $find);
+ $expected = 1;
+ $this->assertEqual($result, $expected);
+
+ $string = '一二三周永龍';
+ $find = '周';
+ $result = mb_substr_count($string, $find);
+ $expected = 1;
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ĥēĺļŏ, Ŵőřļď!';
+ $find = 'H';
+ $result = mb_substr_count($string, $find);
+ $expected = false;
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testMultibyteSubstrCount method
+ *
+ * @access public
+ * @return void
+ */
+ function testMultibyteSubstrCount() {
+ $string = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
+ $find = 'F';
+ $result = Multibyte::substrCount($string, $find);
+ $expected = 1;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ABCDEFGHIJKLMNOPQFRSFTUVWXYZ0F12345F6789';
+ $find = 'F';
+ $result = Multibyte::substrCount($string, $find);
+ $expected = 5;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ÀÁÂÃÄÅÆÇÈÉÅÊËÌÍÎÏÐÑÒÓÔÅÕÖØÅÙÚÛÅÜÝÞ';
+ $find = 'Å';
+ $result = Multibyte::substrCount($string, $find);
+ $expected = 5;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ÀÁÙÚÂÃÄÅÆÇÈÙÚÉÊËÌÍÎÏÐÑÒÓÔÕÖØÅÙÚÛÜÝÞÙÚ';
+ $find = 'ÙÚ';
+ $result = Multibyte::substrCount($string, $find);
+ $expected = 4;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ÀÁÂÃÄÅÆÇÈÉÊÅËÌÍÎÏÐÑÒÓÔÕÅÖØÅÙÚÅÛÜÅÝÞÅ';
+ $find = 'Å';
+ $result = Multibyte::substrCount($string, $find);
+ $expected = 7;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĊĀĂĄĆĈĊČĎĐĒĔĖĊĘĚĜĞĠĢĤĦĨĪĬĮĊIJĴĶĹĻĽĿŁŃŅŇŊŌĊŎŐŒŔŖŘŚŜŞŠŢĊŤŦŨŪŬŮŰĊŲŴŶŹŻŽ';
+ $find = 'Ċ';
+ $result = Multibyte::substrCount($string, $find);
+ $expected = 7;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĀĂĄĆĈĊČĎĐĒĔĖĘĚĜĊĞĠĢĤĦĨĪĬĮIJĴĶĹĻĽĿŁĊŃŅĊŇŊŌŎŐŒŔŖĊŘŚŜŞŠŢŤŦŨŪŬŮŰŲŴŶŹŻŽ';
+ $find = 'Ċ';
+ $result = Multibyte::substrCount($string, $find);
+ $expected = 5;
+ $this->assertEqual($result, $expected);
+
+ $string = '!"#$%&\'()*+,-./012F34567F89:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghiFjklmnopqFrstuvwFxyz{|}~';
+ $find = 'F';
+ $result = Multibyte::substrCount($string, $find);
+ $expected = 6;
+ $this->assertEqual($result, $expected);
+
+ $string = '¡¢£¤¥µ¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁµÂõÄÅÆǵÈ';
+ $find = 'µ';
+ $result = Multibyte::substrCount($string, $find);
+ $expected = 5;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôÕÖõö÷øùúûüýþÿĀāĂ㥹ĆćĈĉÕÖĊċČčĎďĐđĒēĔĕĖėĘęĚěĜĝÕÖĞğĠġĢģĤĥĦÕÖħĨĩĪīĬ';
+ $find = 'ÕÖ';
+ $result = Multibyte::substrCount($string, $find);
+ $expected = 5;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĭĮįİıIJijĴĵĶķĸĹĺĻļĽľĿŀŁłŃńŅņŇňʼnŊŋŌōĵĶķĸĹŎŏŐőŒœŔŕŖŗŘřŚśŜŝŞşŠšĵĶķĸĹŢţŤťŦŧŨũŪūŬŭŮůŰűŲųĵĶķĸĹŴŵŶŷŸŹźŻżŽžſƀƁƂƃƄƅƆƇƈƉƊƋƌƍƎƏƐ';
+ $find = 'ĵĶķĸĹ';
+ $result = Multibyte::substrCount($string, $find);
+ $expected = 4;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ƑƒƓƔƕƖƸƗƘƙƚƛƜƝƞƟƠơƢƣƤƥƦƧƨƩƪƫƬƭƮƯưƱƲƳƴƵƶƷƸƹƺƻƼƽƾƿǀǁǂǃDŽDždžLJLjljNJƸNjnjǍǎǏǐǑǒǓƸǔǕǖǗǘǙǚƸǛǜǝǞǟǠǡǢǣǤǥǦǧǨǩǪǫǬǭǮǯǰDZDzdzǴ';
+ $find = 'Ƹ';
+ $result = Multibyte::substrCount($string, $find);
+ $expected = 5;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ƑƒƓƔƕƖƗƘƙƚƛƜƝƞƟƹƠơƢƣƤƥƦƧƨƩƹƪƫƬƭƮƯưƱƲƳƴƹƵƶƷƸƹƺƻƼƽƾƿǀǁǂƹǃDŽDždžLJLjljNJNjnjǍǎǏǐǑǒǓǔǕǖǗǘǙǚǛǜǝǞǟǠǡǢǣǤǥǦǧǨǩǪǫǬǭǮǯǰDZDzdzǴ';
+ $find = 'ƹ';
+ $result = Multibyte::substrCount($string, $find);
+ $expected = 5;
+ $this->assertEqual($result, $expected);
+
+ $string = 'əɚɛɜɝɞʀɟɠɡɢɣɤɥɦɧɨɩɪɫɬɭɮɯɰɱɲɳɴɵɶɷɸɹɺɻɼɽɾɿʀʁʂʃʄʅʆʀʇʈʉʊʋʌʍʎʏʐʑʒʓʔʕʖʗʘʙʚʛʜʝʞʟʠʡʢʣʤʥʦʧʀʨʩʪʫʬʭʮʯʰʱʲʳʴʵʶʷʸʹʺʀʻʼ';
+ $find = 'ʀ';
+ $result = Multibyte::substrCount($string, $find);
+ $expected = 5;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ЀЁЂЃЄЅІЇЈЉЊЋЌЍЇЎЏАБВГДЕЖЗИЙКЛ';
+ $find = 'Ї';
+ $result = Multibyte::substrCount($string, $find);
+ $expected = 2;
+ $this->assertEqual($result, $expected);
+
+ $string = 'МНОПРСРТУФХЦЧШЩЪЫЬРЭЮЯабРвгдежзийклРмнопрстуфхцчшщъыь';
+ $find = 'Р';
+ $result = Multibyte::substrCount($string, $find);
+ $expected = 5;
+ $this->assertEqual($result, $expected);
+
+ $string = 'МНОПРСрТУФХЦЧШЩЪЫрЬЭЮЯабвгдежзийклмнопррстуфхцчшщъыь';
+ $find = 'р';
+ $result = Multibyte::substrCount($string, $find);
+ $expected = 4;
+ $this->assertEqual($result, $expected);
+
+ $string = 'فنقكلنمنهونىينًٌٍَُ';
+ $find = 'ن';
+ $result = Multibyte::substrCount($string, $find);
+ $expected = 5;
+ $this->assertEqual($result, $expected);
+
+ $string = '✰✱✲✳✿✴✵✶✷✸✿✹✺✻✼✽✾✿❀❁❂❃❄❅❆✿❇❈❉❊❋❌❍❎❏❐❑❒❓❔❕❖❗❘❙❚❛❜❝❞';
+ $find = '✿';
+ $result = Multibyte::substrCount($string, $find);
+ $expected = 4;
+ $this->assertEqual($result, $expected);
+
+ $string = '⺀⺁⺂⺃⺄⺅⺆⺇⺈⺉⺐⺊⺋⺌⺍⺎⺏⺐⺑⺒⺓⺔⺕⺖⺗⺘⺙⺛⺜⺝⺞⺟⺠⺡⺢⺣⺤⺥⺦⺧⺨⺐⺩⺪⺫⺬⺭⺮⺯⺰⺱⺲⺳⺴⺵⺶⺷⺸⺹⺺⺻⺼⺽⺾⺿⻀⻁⻂⻃⻄⻅⻆⻇⻈⻉⺐⻊⻋⻌⻍⻎⻏⻐⻑⻒⻓⻔⻕⻖⻗⻘⻙⻚⻛⻜⻝⻞⻟⻠';
+ $find = '⺐';
+ $result = Multibyte::substrCount($string, $find);
+ $expected = 4;
+ $this->assertEqual($result, $expected);
+
+ $string = '⽅⽆⽇⽈⽉⽊⽋⽌⽍⽎⽏⽐⽑⽒⽓⽔⽕⽖⽤⽗⽘⽙⽚⽛⽜⽝⽞⽟⽠⽡⽢⽣⽤⽥⽦⽧⽨⽩⽪⽫⽬⽭⽮⽯⽰⽱⽲⽳⽴⽵⽤⽶⽷⽸⽹⽺⽻⽼⽽⽾⽿';
+ $find = '⽤';
+ $result = Multibyte::substrCount($string, $find);
+ $expected = 3;
+ $this->assertEqual($result, $expected);
+
+ $string = '눡눢눣눤눥눦눺눻눼눧눨눩눪눫눬눭눮눯눰눱눲눳눴눵눶눷눸눹눺눻눼눽눾눿뉀뉁뉂뉃뉄뉅뉆뉇뉈뉉뉊뉋뉌뉍뉎뉏뉐뉑뉒뉓뉔뉕눺눻눼뉖뉗뉘뉙뉚뉛뉜뉝눺눻눼뉞뉟뉠뉡뉢뉣뉤뉥뉦뉧뉨뉩뉪뉫뉬뉭뉮뉯뉰뉱뉲뉳뉴뉵뉶뉷뉸뉹뉺뉻뉼뉽뉾뉿늀늁늂늃늄';
+ $find = '눺눻눼';
+ $result = Multibyte::substrCount($string, $find);
+ $expected = 4;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ﺞﺟﺠﺡﹰﹱﹲﹳﹴﹶﹷﹸﹹﹺﹻﹼﹽﹾﹿﺀﺁﺂﺃﺄﺅﺞﺟﺠﺡﺆﺇﺞﺟﺠﺡﺈﺉﺊﺋﺌﺍﺎﺏﺐﺑﺒﺓﺔﺕﺖﺗﺘﺙﺚﺛﺜﺝﺞﺟﺠﺡﺢﺣﺤﺥﺦﺧﺨﺩﺪﺫﺬﺭﺮﺯﺰ';
+ $find = 'ﺞﺟﺠﺡ';
+ $result = Multibyte::substrCount($string, $find);
+ $expected = 4;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ﺱﺲﺳﺴﺵﺶﺷﺸﺹﺺﺻﺼﻞﺽﺾﺿﻀﻁﻂﻃﻄﻅﻆﻇﻈﻉﻊﻋﻌﻍﻎﻏﻐﻑﻒﻓﻔﻞﻕﻖﻗﻘﻙﻚﻛﻜﻝﻞﻟﻠﻡﻢﻣﻤﻥﻦﻧﻨﻩﻪﻫﻬﻭﻮﻯﻰﻱﻲﻳﻴﻵﻶﻷﻞﻸﻹﻺﻞﻻﻼ';
+ $find = 'ﻞ';
+ $result = Multibyte::substrCount($string, $find);
+ $expected = 5;
+ $this->assertEqual($result, $expected);
+
+ $string = 'abcdkefghijklmnopqrstuvwxkyz';
+ $find = 'k';
+ $result = Multibyte::substrCount($string, $find);
+ $expected = 3;
+ $this->assertEqual($result, $expected);
+
+ $string = 'abklmcdefghijklmnopqrstuvklmwxyz';
+ $find = 'klm';
+ $result = Multibyte::substrCount($string, $find);
+ $expected = 3;
+ $this->assertEqual($result, $expected);
+
+ $string = 'abcdppefghijklmnoppqrstuvwxyz';
+ $find = 'ppe';
+ $result = Multibyte::substrCount($string, $find);
+ $expected = 1;
+ $this->assertEqual($result, $expected);
+
+ $string = '。「」、・ヲァィゥェォャュョッーアイウエオカキク';
+ $find = 'ア';
+ $result = Multibyte::substrCount($string, $find);
+ $expected = 1;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン゙';
+ $find = 'ハ';
+ $result = Multibyte::substrCount($string, $find);
+ $expected = 1;
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ĥēĺļŏ, Ŵőřļď!';
+ $find = 'ő';
+ $result = Multibyte::substrCount($string, $find);
+ $expected = 1;
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ĥēĺļŏ, Ŵőřļď!';
+ $find = 'ĺļ';
+ $result = Multibyte::substrCount($string, $find);
+ $expected = 1;
+ $this->assertEqual($result, $expected);
+
+ $string = 'Hello, World!';
+ $find = 'o';
+ $result = Multibyte::substrCount($string, $find);
+ $expected = 2;
+ $this->assertEqual($result, $expected);
+
+ $string = 'Hello, World!';
+ $find = 'rl';
+ $result = Multibyte::substrCount($string, $find);
+ $expected = 1;
+ $this->assertEqual($result, $expected);
+
+ $string = 'čini';
+ $find = 'n';
+ $result = Multibyte::substrCount($string, $find);
+ $expected = 1;
+ $this->assertEqual($result, $expected);
+
+ $string = 'ničiničiini';
+ $find = 'n';
+ $result = Multibyte::substrCount($string, $find);
+ $expected = 3;
+ $this->assertEqual($result, $expected);
+
+ $string = 'moći';
+ $find = 'ć';
+ $result = Multibyte::substrCount($string, $find);
+ $expected = 1;
+ $this->assertEqual($result, $expected);
+
+ $string = 'moćimoćimoćmćioći';
+ $find = 'ći';
+ $result = Multibyte::substrCount($string, $find);
+ $expected = 4;
+ $this->assertEqual($result, $expected);
+
+ $string = 'državni';
+ $find = 'ž';
+ $result = Multibyte::substrCount($string, $find);
+ $expected = 1;
+ $this->assertEqual($result, $expected);
+
+ $string = '把百度设为首页';
+ $find = '设';
+ $result = Multibyte::substrCount($string, $find);
+ $expected = 1;
+ $this->assertEqual($result, $expected);
+
+ $string = '一二三周永龍';
+ $find = '周';
+ $result = Multibyte::substrCount($string, $find);
+ $expected = 1;
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ĥēĺļŏ, Ŵőřļď!';
+ $find = 'H';
+ $result = Multibyte::substrCount($string, $find);
+ $expected = false;
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testUsingMbSubstr method
+ *
+ * @access public
+ * @return void
+ */
+ function testUsingMbSubstr() {
+ $string = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
+ $result = mb_substr($string, 4, 7);
+ $expected = 'EFGHIJK';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞ';
+ $result = mb_substr($string, 4, 7);
+ $expected = 'ÄÅÆÇÈÉÊ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĀĂĄĆĈĊČĎĐĒĔĖĘĚĜĞĠĢĤĦĨĪĬĮIJĴĶĹĻĽĿŁŃŅŇŊŌŎŐŒŔŖŘŚŜŞŠŢŤŦŨŪŬŮŰŲŴŶŹŻŽ';
+ $find = 'Ċ';
+ $result = mb_substr($string, 4, 7);
+ $expected = 'ĈĊČĎĐĒĔ';
+ $this->assertEqual($result, $expected);
+
+ $string = '!"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~';
+ $result = mb_substr($string, 4, 7);
+ $expected = '%&\'()*+';
+ $this->assertEqual($result, $expected);
+
+ $string = '¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈ';
+ $result = mb_substr($string, 4);
+ $expected = '¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿĀāĂ㥹ĆćĈĉĊċČčĎďĐđĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪīĬ';
+ $result = mb_substr($string, 4, 7);
+ $expected = 'ÍÎÏÐÑÒÓ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĭĮįİıIJijĴĵĶķĸĹĺĻļĽľĿŀŁłŃńŅņŇňʼnŊŋŌōŎŏŐőŒœŔŕŖŗŘřŚśŜŝŞşŠšŢţŤťŦŧŨũŪūŬŭŮůŰűŲųŴŵŶŷŸŹźŻżŽžſƀƁƂƃƄƅƆƇƈƉƊƋƌƍƎƏƐ';
+ $result = mb_substr($string, 4, 7);
+ $expected = 'ıIJijĴĵĶķ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ƑƒƓƔƕƖƗƘƙƚƛƜƝƞƟƠơƢƣƤƥƦƧƨƩƪƫƬƭƮƯưƱƲƳƴƵƶƷƸƹƺƻƼƽƾƿǀǁǂǃDŽDždžLJLjljNJNjnjǍǎǏǐǑǒǓǔǕǖǗǘǙǚǛǜǝǞǟǠǡǢǣǤǥǦǧǨǩǪǫǬǭǮǯǰDZDzdzǴ';
+ $result = mb_substr($string, 25);
+ $expected = 'ƪƫƬƭƮƯưƱƲƳƴƵƶƷƸƹƺƻƼƽƾƿǀǁǂǃDŽDždžLJLjljNJNjnjǍǎǏǐǑǒǓǔǕǖǗǘǙǚǛǜǝǞǟǠǡǢǣǤǥǦǧǨǩǪǫǬǭǮǯǰDZDzdzǴ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'əɚɛɜɝɞɟɠɡɢɣɤɥɦɧɨɩɪɫɬɭɮɯɰɱɲɳɴɵɶɷɸɹɺɻɼɽɾɿʀʁʂʃʄʅʆʇʈʉʊʋʌʍʎʏʐʑʒʓʔʕʖʗʘʙʚʛʜʝʞʟʠʡʢʣʤʥʦʧʨʩʪʫʬʭʮʯʰʱʲʳʴʵʶʷʸʹʺʻʼ';
+ $result = mb_substr($string, 3);
+ $expected = 'ɜɝɞɟɠɡɢɣɤɥɦɧɨɩɪɫɬɭɮɯɰɱɲɳɴɵɶɷɸɹɺɻɼɽɾɿʀʁʂʃʄʅʆʇʈʉʊʋʌʍʎʏʐʑʒʓʔʕʖʗʘʙʚʛʜʝʞʟʠʡʢʣʤʥʦʧʨʩʪʫʬʭʮʯʰʱʲʳʴʵʶʷʸʹʺʻʼ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ЀЁЂЃЄЅІЇЈЉЊЋЌЍЎЏАБВГДЕЖЗИЙКЛ';
+ $result = mb_substr($string, 3);
+ $expected = 'ЃЄЅІЇЈЉЊЋЌЍЎЏАБВГДЕЖЗИЙКЛ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'МНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыь';
+ $result = mb_substr($string, 3, 16);
+ $expected = 'ПРСТУФХЦЧШЩЪЫЬЭЮ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'فقكلمنهوىيًٌٍَُ';
+ $result = mb_substr($string, 3, 6);
+ $expected = 'لمنهوى';
+ $this->assertEqual($result, $expected);
+
+ $string = '✰✱✲✳✴✵✶✷✸✹✺✻✼✽✾✿❀❁❂❃❄❅❆❇❈❉❊❋❌❍❎❏❐❑❒❓❔❕❖❗❘❙❚❛❜❝❞';
+ $result = mb_substr($string, 6, 14);
+ $expected = '✶✷✸✹✺✻✼✽✾✿❀❁❂❃';
+ $this->assertEqual($result, $expected);
+
+ $string = '⺀⺁⺂⺃⺄⺅⺆⺇⺈⺉⺊⺋⺌⺍⺎⺏⺐⺑⺒⺓⺔⺕⺖⺗⺘⺙⺛⺜⺝⺞⺟⺠⺡⺢⺣⺤⺥⺦⺧⺨⺩⺪⺫⺬⺭⺮⺯⺰⺱⺲⺳⺴⺵⺶⺷⺸⺹⺺⺻⺼⺽⺾⺿⻀⻁⻂⻃⻄⻅⻆⻇⻈⻉⻊⻋⻌⻍⻎⻏⻐⻑⻒⻓⻔⻕⻖⻗⻘⻙⻚⻛⻜⻝⻞⻟⻠';
+ $result = mb_substr($string, 8, 13);
+ $expected = '⺈⺉⺊⺋⺌⺍⺎⺏⺐⺑⺒⺓⺔';
+ $this->assertEqual($result, $expected);
+
+ $string = '⽅⽆⽇⽈⽉⽊⽋⽌⽍⽎⽏⽐⽑⽒⽓⽔⽕⽖⽗⽘⽙⽚⽛⽜⽝⽞⽟⽠⽡⽢⽣⽤⽥⽦⽧⽨⽩⽪⽫⽬⽭⽮⽯⽰⽱⽲⽳⽴⽵⽶⽷⽸⽹⽺⽻⽼⽽⽾⽿';
+ $result = mb_substr($string, 12, 24);
+ $expected = '⽑⽒⽓⽔⽕⽖⽗⽘⽙⽚⽛⽜⽝⽞⽟⽠⽡⽢⽣⽤⽥⽦⽧⽨';
+ $this->assertEqual($result, $expected);
+
+ $string = '눡눢눣눤눥눦눧눨눩눪눫눬눭눮눯눰눱눲눳눴눵눶눷눸눹눺눻눼눽눾눿뉀뉁뉂뉃뉄뉅뉆뉇뉈뉉뉊뉋뉌뉍뉎뉏뉐뉑뉒뉓뉔뉕뉖뉗뉘뉙뉚뉛뉜뉝뉞뉟뉠뉡뉢뉣뉤뉥뉦뉧뉨뉩뉪뉫뉬뉭뉮뉯뉰뉱뉲뉳뉴뉵뉶뉷뉸뉹뉺뉻뉼뉽뉾뉿늀늁늂늃늄';
+ $result = mb_substr($string, 12, 24);
+ $expected = '눭눮눯눰눱눲눳눴눵눶눷눸눹눺눻눼눽눾눿뉀뉁뉂뉃뉄';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ﹰﹱﹲﹳﹴﹶﹷﹸﹹﹺﹻﹼﹽﹾﹿﺀﺁﺂﺃﺄﺅﺆﺇﺈﺉﺊﺋﺌﺍﺎﺏﺐﺑﺒﺓﺔﺕﺖﺗﺘﺙﺚﺛﺜﺝﺞﺟﺠﺡﺢﺣﺤﺥﺦﺧﺨﺩﺪﺫﺬﺭﺮﺯﺰ';
+ $result = mb_substr($string, 12);
+ $expected = 'ﹼﹽﹾﹿﺀﺁﺂﺃﺄﺅﺆﺇﺈﺉﺊﺋﺌﺍﺎﺏﺐﺑﺒﺓﺔﺕﺖﺗﺘﺙﺚﺛﺜﺝﺞﺟﺠﺡﺢﺣﺤﺥﺦﺧﺨﺩﺪﺫﺬﺭﺮﺯﺰ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ﺱﺲﺳﺴﺵﺶﺷﺸﺹﺺﺻﺼﺽﺾﺿﻀﻁﻂﻃﻄﻅﻆﻇﻈﻉﻊﻋﻌﻍﻎﻏﻐﻑﻒﻓﻔﻕﻖﻗﻘﻙﻚﻛﻜﻝﻞﻟﻠﻡﻢﻣﻤﻥﻦﻧﻨﻩﻪﻫﻬﻭﻮﻯﻰﻱﻲﻳﻴﻵﻶﻷﻸﻹﻺﻻﻼ';
+ $result = mb_substr($string, 24, 12);
+ $expected = 'ﻉﻊﻋﻌﻍﻎﻏﻐﻑﻒﻓﻔ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'abcdefghijklmnopqrstuvwxyz';
+ $result = mb_substr($string, 11, 2);
+ $expected = 'lm';
+ $this->assertEqual($result, $expected);
+
+ $string = '。「」、・ヲァィゥェォャュョッーアイウエオカキク';
+ $result = mb_substr($string, 7, 11);
+ $expected = 'ィゥェォャュョッーアイ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン゙';
+ $result = mb_substr($string, 13, 13);
+ $expected = 'ニヌネノハヒフヘホマミムメ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ĥēĺļŏ, Ŵőřļď!';
+ $result = mb_substr($string, 3, 4);
+ $expected = 'ļŏ, ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Hello, World!';
+ $result = mb_substr($string, 3, 4);
+ $expected = 'lo, ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'čini';
+ $result = mb_substr($string, 3);
+ $expected = 'i';
+ $this->assertEqual($result, $expected);
+
+ $string = 'moći';
+ $result = mb_substr($string, 1);
+ $expected = 'oći';
+ $this->assertEqual($result, $expected);
+
+ $string = 'državni';
+ $result = mb_substr($string, 0, 2);
+ $expected = 'dr';
+ $this->assertEqual($result, $expected);
+
+ $string = '把百度设为首页';
+ $result = mb_substr($string, 3, 3);
+ $expected = '设为首';
+ $this->assertEqual($result, $expected);
+
+ $string = '一二三周永龍';
+ $result = mb_substr($string, 0, 1);
+ $expected = '一';
+ $this->assertEqual($result, $expected);
+
+ $string = '一二三周永龍';
+ $result = mb_substr($string, 6);
+ $expected = false;
+ $this->assertEqual($result, $expected);
+
+ $string = '一二三周永龍';
+ $result = mb_substr($string, 0);
+ $expected = '一二三周永龍';
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testMultibyteSubstr method
+ *
+ * @access public
+ * @return void
+ */
+ function testMultibyteSubstr() {
+ $string = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
+ $result = Multibyte::substr($string, 4, 7);
+ $expected = 'EFGHIJK';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞ';
+ $result = Multibyte::substr($string, 4, 7);
+ $expected = 'ÄÅÆÇÈÉÊ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĀĂĄĆĈĊČĎĐĒĔĖĘĚĜĞĠĢĤĦĨĪĬĮIJĴĶĹĻĽĿŁŃŅŇŊŌŎŐŒŔŖŘŚŜŞŠŢŤŦŨŪŬŮŰŲŴŶŹŻŽ';
+ $find = 'Ċ';
+ $result = Multibyte::substr($string, 4, 7);
+ $expected = 'ĈĊČĎĐĒĔ';
+ $this->assertEqual($result, $expected);
+
+ $string = '!"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~';
+ $result = Multibyte::substr($string, 4, 7);
+ $expected = '%&\'()*+';
+ $this->assertEqual($result, $expected);
+
+ $string = '¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈ';
+ $result = Multibyte::substr($string, 4);
+ $expected = '¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿĀāĂ㥹ĆćĈĉĊċČčĎďĐđĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪīĬ';
+ $result = Multibyte::substr($string, 4, 7);
+ $expected = 'ÍÎÏÐÑÒÓ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĭĮįİıIJijĴĵĶķĸĹĺĻļĽľĿŀŁłŃńŅņŇňʼnŊŋŌōŎŏŐőŒœŔŕŖŗŘřŚśŜŝŞşŠšŢţŤťŦŧŨũŪūŬŭŮůŰűŲųŴŵŶŷŸŹźŻżŽžſƀƁƂƃƄƅƆƇƈƉƊƋƌƍƎƏƐ';
+ $result = Multibyte::substr($string, 4, 7);
+ $expected = 'ıIJijĴĵĶķ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ƑƒƓƔƕƖƗƘƙƚƛƜƝƞƟƠơƢƣƤƥƦƧƨƩƪƫƬƭƮƯưƱƲƳƴƵƶƷƸƹƺƻƼƽƾƿǀǁǂǃDŽDždžLJLjljNJNjnjǍǎǏǐǑǒǓǔǕǖǗǘǙǚǛǜǝǞǟǠǡǢǣǤǥǦǧǨǩǪǫǬǭǮǯǰDZDzdzǴ';
+ $result = Multibyte::substr($string, 25);
+ $expected = 'ƪƫƬƭƮƯưƱƲƳƴƵƶƷƸƹƺƻƼƽƾƿǀǁǂǃDŽDždžLJLjljNJNjnjǍǎǏǐǑǒǓǔǕǖǗǘǙǚǛǜǝǞǟǠǡǢǣǤǥǦǧǨǩǪǫǬǭǮǯǰDZDzdzǴ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'əɚɛɜɝɞɟɠɡɢɣɤɥɦɧɨɩɪɫɬɭɮɯɰɱɲɳɴɵɶɷɸɹɺɻɼɽɾɿʀʁʂʃʄʅʆʇʈʉʊʋʌʍʎʏʐʑʒʓʔʕʖʗʘʙʚʛʜʝʞʟʠʡʢʣʤʥʦʧʨʩʪʫʬʭʮʯʰʱʲʳʴʵʶʷʸʹʺʻʼ';
+ $result = Multibyte::substr($string, 3);
+ $expected = 'ɜɝɞɟɠɡɢɣɤɥɦɧɨɩɪɫɬɭɮɯɰɱɲɳɴɵɶɷɸɹɺɻɼɽɾɿʀʁʂʃʄʅʆʇʈʉʊʋʌʍʎʏʐʑʒʓʔʕʖʗʘʙʚʛʜʝʞʟʠʡʢʣʤʥʦʧʨʩʪʫʬʭʮʯʰʱʲʳʴʵʶʷʸʹʺʻʼ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ЀЁЂЃЄЅІЇЈЉЊЋЌЍЎЏАБВГДЕЖЗИЙКЛ';
+ $result = Multibyte::substr($string, 3);
+ $expected = 'ЃЄЅІЇЈЉЊЋЌЍЎЏАБВГДЕЖЗИЙКЛ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'МНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыь';
+ $result = Multibyte::substr($string, 3, 16);
+ $expected = 'ПРСТУФХЦЧШЩЪЫЬЭЮ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'فقكلمنهوىيًٌٍَُ';
+ $result = Multibyte::substr($string, 3, 6);
+ $expected = 'لمنهوى';
+ $this->assertEqual($result, $expected);
+
+ $string = '✰✱✲✳✴✵✶✷✸✹✺✻✼✽✾✿❀❁❂❃❄❅❆❇❈❉❊❋❌❍❎❏❐❑❒❓❔❕❖❗❘❙❚❛❜❝❞';
+ $result = Multibyte::substr($string, 6, 14);
+ $expected = '✶✷✸✹✺✻✼✽✾✿❀❁❂❃';
+ $this->assertEqual($result, $expected);
+
+ $string = '⺀⺁⺂⺃⺄⺅⺆⺇⺈⺉⺊⺋⺌⺍⺎⺏⺐⺑⺒⺓⺔⺕⺖⺗⺘⺙⺛⺜⺝⺞⺟⺠⺡⺢⺣⺤⺥⺦⺧⺨⺩⺪⺫⺬⺭⺮⺯⺰⺱⺲⺳⺴⺵⺶⺷⺸⺹⺺⺻⺼⺽⺾⺿⻀⻁⻂⻃⻄⻅⻆⻇⻈⻉⻊⻋⻌⻍⻎⻏⻐⻑⻒⻓⻔⻕⻖⻗⻘⻙⻚⻛⻜⻝⻞⻟⻠';
+ $result = Multibyte::substr($string, 8, 13);
+ $expected = '⺈⺉⺊⺋⺌⺍⺎⺏⺐⺑⺒⺓⺔';
+ $this->assertEqual($result, $expected);
+
+ $string = '⽅⽆⽇⽈⽉⽊⽋⽌⽍⽎⽏⽐⽑⽒⽓⽔⽕⽖⽗⽘⽙⽚⽛⽜⽝⽞⽟⽠⽡⽢⽣⽤⽥⽦⽧⽨⽩⽪⽫⽬⽭⽮⽯⽰⽱⽲⽳⽴⽵⽶⽷⽸⽹⽺⽻⽼⽽⽾⽿';
+ $result = Multibyte::substr($string, 12, 24);
+ $expected = '⽑⽒⽓⽔⽕⽖⽗⽘⽙⽚⽛⽜⽝⽞⽟⽠⽡⽢⽣⽤⽥⽦⽧⽨';
+ $this->assertEqual($result, $expected);
+
+ $string = '눡눢눣눤눥눦눧눨눩눪눫눬눭눮눯눰눱눲눳눴눵눶눷눸눹눺눻눼눽눾눿뉀뉁뉂뉃뉄뉅뉆뉇뉈뉉뉊뉋뉌뉍뉎뉏뉐뉑뉒뉓뉔뉕뉖뉗뉘뉙뉚뉛뉜뉝뉞뉟뉠뉡뉢뉣뉤뉥뉦뉧뉨뉩뉪뉫뉬뉭뉮뉯뉰뉱뉲뉳뉴뉵뉶뉷뉸뉹뉺뉻뉼뉽뉾뉿늀늁늂늃늄';
+ $result = Multibyte::substr($string, 12, 24);
+ $expected = '눭눮눯눰눱눲눳눴눵눶눷눸눹눺눻눼눽눾눿뉀뉁뉂뉃뉄';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ﹰﹱﹲﹳﹴﹶﹷﹸﹹﹺﹻﹼﹽﹾﹿﺀﺁﺂﺃﺄﺅﺆﺇﺈﺉﺊﺋﺌﺍﺎﺏﺐﺑﺒﺓﺔﺕﺖﺗﺘﺙﺚﺛﺜﺝﺞﺟﺠﺡﺢﺣﺤﺥﺦﺧﺨﺩﺪﺫﺬﺭﺮﺯﺰ';
+ $result = Multibyte::substr($string, 12);
+ $expected = 'ﹼﹽﹾﹿﺀﺁﺂﺃﺄﺅﺆﺇﺈﺉﺊﺋﺌﺍﺎﺏﺐﺑﺒﺓﺔﺕﺖﺗﺘﺙﺚﺛﺜﺝﺞﺟﺠﺡﺢﺣﺤﺥﺦﺧﺨﺩﺪﺫﺬﺭﺮﺯﺰ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ﺱﺲﺳﺴﺵﺶﺷﺸﺹﺺﺻﺼﺽﺾﺿﻀﻁﻂﻃﻄﻅﻆﻇﻈﻉﻊﻋﻌﻍﻎﻏﻐﻑﻒﻓﻔﻕﻖﻗﻘﻙﻚﻛﻜﻝﻞﻟﻠﻡﻢﻣﻤﻥﻦﻧﻨﻩﻪﻫﻬﻭﻮﻯﻰﻱﻲﻳﻴﻵﻶﻷﻸﻹﻺﻻﻼ';
+ $result = Multibyte::substr($string, 24, 12);
+ $expected = 'ﻉﻊﻋﻌﻍﻎﻏﻐﻑﻒﻓﻔ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'abcdefghijklmnopqrstuvwxyz';
+ $result = Multibyte::substr($string, 11, 2);
+ $expected = 'lm';
+ $this->assertEqual($result, $expected);
+
+ $string = '。「」、・ヲァィゥェォャュョッーアイウエオカキク';
+ $result = Multibyte::substr($string, 7, 11);
+ $expected = 'ィゥェォャュョッーアイ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン゙';
+ $result = Multibyte::substr($string, 13, 13);
+ $expected = 'ニヌネノハヒフヘホマミムメ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ĥēĺļŏ, Ŵőřļď!';
+ $result = Multibyte::substr($string, 3, 4);
+ $expected = 'ļŏ, ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Hello, World!';
+ $result = Multibyte::substr($string, 3, 4);
+ $expected = 'lo, ';
+ $this->assertEqual($result, $expected);
+
+ $string = 'čini';
+ $result = Multibyte::substr($string, 3);
+ $expected = 'i';
+ $this->assertEqual($result, $expected);
+
+ $string = 'moći';
+ $result = Multibyte::substr($string, 1);
+ $expected = 'oći';
+ $this->assertEqual($result, $expected);
+
+ $string = 'državni';
+ $result = Multibyte::substr($string, 0, 2);
+ $expected = 'dr';
+ $this->assertEqual($result, $expected);
+
+ $string = '把百度设为首页';
+ $result = Multibyte::substr($string, 3, 3);
+ $expected = '设为首';
+ $this->assertEqual($result, $expected);
+
+ $string = '一二三周永龍';
+ $result = Multibyte::substr($string, 0, 1);
+ $expected = '一';
+ $this->assertEqual($result, $expected);
+
+ $string = '一二三周永龍';
+ $result = Multibyte::substr($string, 6);
+ $expected = false;
+ $this->assertEqual($result, $expected);
+
+ $string = '一二三周永龍';
+ $result = Multibyte::substr($string, 0);
+ $expected = '一二三周永龍';
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testMultibyteSubstr method
+ *
+ * @access public
+ * @return void
+ */
+ function testMultibyteMimeEncode() {
+ $string = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
+ $result = Multibyte::mimeEncode($string);
+ $this->assertEqual($result, $string);
+
+ $string = 'ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞ';
+ $result = Multibyte::mimeEncode($string);
+ $expected = '=?UTF-8?B?w4DDgcOCw4PDhMOFw4bDh8OIw4nDisOLw4zDjcOOw4/DkMORw5LDk8OUw5U=?=' . "\r\n" .
+ ' =?UTF-8?B?w5bDmMOZw5rDm8Ocw53Dng==?=';
+ $this->assertEqual($result, $expected);
+ $result = Multibyte::mimeEncode($string, null, "\n");
+ $expected = '=?UTF-8?B?w4DDgcOCw4PDhMOFw4bDh8OIw4nDisOLw4zDjcOOw4/DkMORw5LDk8OUw5U=?=' . "\n" .
+ ' =?UTF-8?B?w5bDmMOZw5rDm8Ocw53Dng==?=';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĀĂĄĆĈĊČĎĐĒĔĖĘĚĜĞĠĢĤĦĨĪĬĮIJĴĶĹĻĽĿŁŃŅŇŊŌŎŐŒŔŖŘŚŜŞŠŢŤŦŨŪŬŮŰŲŴŶŹŻŽ';
+ $result = Multibyte::mimeEncode($string);
+ $expected = '=?UTF-8?B?xIDEgsSExIbEiMSKxIzEjsSQxJLElMSWxJjEmsScxJ7EoMSixKTEpsSoxKo=?=' . "\r\n" .
+ ' =?UTF-8?B?xKzErsSyxLTEtsS5xLvEvcS/xYHFg8WFxYfFisWMxY7FkMWSxZTFlsWYxZo=?=' . "\r\n" .
+ ' =?UTF-8?B?xZzFnsWgxaLFpMWmxajFqsWsxa7FsMWyxbTFtsW5xbvFvQ==?=';
+ $this->assertEqual($result, $expected);
+
+ $string = '!"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~';
+ $result = Multibyte::mimeEncode($string);
+ $expected = '=?UTF-8?B?ISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xN?=' . "\r\n" .
+ ' =?UTF-8?B?Tk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6?=' . "\r\n" .
+ ' =?UTF-8?B?e3x9fg==?=';
+ $this->assertEqual($result, $expected);
+
+ $string = '¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈ';
+ $result = Multibyte::mimeEncode($string);
+ $expected = '=?UTF-8?B?wqHCosKjwqTCpcKmwqfCqMKpwqrCq8Kswq3CrsKvwrDCscKywrPCtMK1wrY=?=' . "\r\n" .
+ ' =?UTF-8?B?wrfCuMK5wrrCu8K8wr3CvsK/w4DDgcOCw4PDhMOFw4bDh8OI?=';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿĀāĂ㥹ĆćĈĉĊċČčĎďĐđĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪīĬ';
+ $result = Multibyte::mimeEncode($string);
+ $expected = '=?UTF-8?B?w4nDisOLw4zDjcOOw4/DkMORw5LDk8OUw5XDlsOXw5jDmcOaw5vDnMOdw54=?=' . "\r\n" .
+ ' =?UTF-8?B?w5/DoMOhw6LDo8Okw6XDpsOnw6jDqcOqw6vDrMOtw67Dr8Oww7HDssOzw7Q=?=' . "\r\n" .
+ ' =?UTF-8?B?w7XDtsO3w7jDucO6w7vDvMO9w77Dv8SAxIHEgsSDxITEhcSGxIfEiMSJxIo=?=' . "\r\n" .
+ ' =?UTF-8?B?xIvEjMSNxI7Ej8SQxJHEksSTxJTElcSWxJfEmMSZxJrEm8ScxJ3EnsSfxKA=?=' . "\r\n" .
+ ' =?UTF-8?B?xKHEosSjxKTEpcSmxKfEqMSpxKrEq8Ss?=';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ĭĮįİıIJijĴĵĶķĸĹĺĻļĽľĿŀŁłŃńŅņŇňʼnŊŋŌōŎŏŐőŒœŔŕŖŗŘřŚśŜŝŞşŠšŢţŤťŦŧŨũŪūŬŭŮůŰűŲųŴŵŶŷŸŹźŻżŽžſƀƁƂƃƄƅƆƇƈƉƊƋƌƍƎƏƐ';
+ $result = Multibyte::mimeEncode($string);
+ $expected = '=?UTF-8?B?xK3ErsSvxLDEscSyxLPEtMS1xLbEt8S4xLnEusS7xLzEvcS+xL/FgMWBxYI=?=' . "\r\n" .
+ ' =?UTF-8?B?xYPFhMWFxYbFh8WIxYnFisWLxYzFjcWOxY/FkMWRxZLFk8WUxZXFlsWXxZg=?=' . "\r\n" .
+ ' =?UTF-8?B?xZnFmsWbxZzFncWexZ/FoMWhxaLFo8WkxaXFpsWnxajFqcWqxavFrMWtxa4=?=' . "\r\n" .
+ ' =?UTF-8?B?xa/FsMWxxbLFs8W0xbXFtsW3xbjFucW6xbvFvMW9xb7Fv8aAxoHGgsaDxoQ=?=' . "\r\n" .
+ ' =?UTF-8?B?xoXGhsaHxojGicaKxovGjMaNxo7Gj8aQ?=';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ƑƒƓƔƕƖƗƘƙƚƛƜƝƞƟƠơƢƣƤƥƦƧƨƩƪƫƬƭƮƯưƱƲƳƴƵƶƷƸƹƺƻƼƽƾƿǀǁǂǃDŽDždžLJLjljNJNjnjǍǎǏǐǑǒǓǔǕǖǗǘǙǚǛǜǝǞǟǠǡǢǣǤǥǦǧǨǩǪǫǬǭǮǯǰDZDzdzǴ';
+ $result = Multibyte::mimeEncode($string);
+ $expected = '=?UTF-8?B?xpHGksaTxpTGlcaWxpfGmMaZxprGm8acxp3GnsafxqDGocaixqPGpMalxqY=?=' . "\r\n" .
+ ' =?UTF-8?B?xqfGqMapxqrGq8asxq3GrsavxrDGscayxrPGtMa1xrbGt8a4xrnGusa7xrw=?=' . "\r\n" .
+ ' =?UTF-8?B?xr3Gvsa/x4DHgceCx4PHhMeFx4bHh8eIx4nHiseLx4zHjceOx4/HkMeRx5I=?=' . "\r\n" .
+ ' =?UTF-8?B?x5PHlMeVx5bHl8eYx5nHmsebx5zHnceex5/HoMehx6LHo8ekx6XHpsenx6g=?=' . "\r\n" .
+ ' =?UTF-8?B?x6nHqserx6zHrceux6/HsMexx7LHs8e0?=';
+ $this->assertEqual($result, $expected);
+
+ $string = 'əɚɛɜɝɞɟɠɡɢɣɤɥɦɧɨɩɪɫɬɭɮɯɰɱɲɳɴɵɶɷɸɹɺɻɼɽɾɿʀʁʂʃʄʅʆʇʈʉʊʋʌʍʎʏʐʑʒʓʔʕʖʗʘʙʚʛʜʝʞʟʠʡʢʣʤʥʦʧʨʩʪʫʬʭʮʯʰʱʲʳʴʵʶʷʸʹʺʻʼ';
+ $result = Multibyte::mimeEncode($string);
+ $expected = '=?UTF-8?B?yZnJmsmbyZzJncmeyZ/JoMmhyaLJo8mkyaXJpsmnyajJqcmqyavJrMmtya4=?=' . "\r\n" .
+ ' =?UTF-8?B?ya/JsMmxybLJs8m0ybXJtsm3ybjJucm6ybvJvMm9yb7Jv8qAyoHKgsqDyoQ=?=' . "\r\n" .
+ ' =?UTF-8?B?yoXKhsqHyojKicqKyovKjMqNyo7Kj8qQypHKksqTypTKlcqWypfKmMqZypo=?=' . "\r\n" .
+ ' =?UTF-8?B?ypvKnMqdyp7Kn8qgyqHKosqjyqTKpcqmyqfKqMqpyqrKq8qsyq3KrsqvyrA=?=' . "\r\n" .
+ ' =?UTF-8?B?yrHKssqzyrTKtcq2yrfKuMq5yrrKu8q8?=';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ЀЁЂЃЄЅІЇЈЉЊЋЌЍЎЏАБВГДЕЖЗИЙКЛ';
+ $result = Multibyte::mimeEncode($string);
+ $expected = '=?UTF-8?B?0IDQgdCC0IPQhNCF0IbQh9CI0InQitCL0IzQjdCO0I/QkNCR0JLQk9CU0JU=?=' . "\r\n" .
+ ' =?UTF-8?B?0JbQl9CY0JnQmtCb?=';
+ $this->assertEqual($result, $expected);
+
+ $string = 'МНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыь';
+ $result = Multibyte::mimeEncode($string);
+ $expected = '=?UTF-8?B?0JzQndCe0J/QoNCh0KLQo9Ck0KXQptCn0KjQqdCq0KvQrNCt0K7Qr9Cw0LE=?=' . "\r\n" .
+ ' =?UTF-8?B?0LLQs9C00LXQttC30LjQudC60LvQvNC90L7Qv9GA0YHRgtGD0YTRhdGG0Yc=?=' . "\r\n" .
+ ' =?UTF-8?B?0YjRidGK0YvRjA==?=';
+ $this->assertEqual($result, $expected);
+
+ $string = 'فقكلمنهوىيًٌٍَُ';
+ $result = Multibyte::mimeEncode($string);
+ $expected = '=?UTF-8?B?2YHZgtmD2YTZhdmG2YfZiNmJ2YrZi9mM2Y3ZjtmP?=';
+ $this->assertEqual($result, $expected);
+
+ $string = '✰✱✲✳✴✵✶✷✸✹✺✻✼✽✾✿❀❁❂❃❄❅❆❇❈❉❊❋❌❍❎❏❐❑❒❓❔❕❖❗❘❙❚❛❜❝❞';
+ $result = Multibyte::mimeEncode($string);
+ $expected = '=?UTF-8?B?4pyw4pyx4pyy4pyz4py04py14py24py34py44py54py64py74py84py94py+?=' . "\r\n" .
+ ' =?UTF-8?B?4py/4p2A4p2B4p2C4p2D4p2E4p2F4p2G4p2H4p2I4p2J4p2K4p2L4p2M4p2N?=' . "\r\n" .
+ ' =?UTF-8?B?4p2O4p2P4p2Q4p2R4p2S4p2T4p2U4p2V4p2W4p2X4p2Y4p2Z4p2a4p2b4p2c?=' . "\r\n" .
+ ' =?UTF-8?B?4p2d4p2e?=';
+ $this->assertEqual($result, $expected);
+
+ $string = '⺀⺁⺂⺃⺄⺅⺆⺇⺈⺉⺊⺋⺌⺍⺎⺏⺐⺑⺒⺓⺔⺕⺖⺗⺘⺙⺛⺜⺝⺞⺟⺠⺡⺢⺣⺤⺥⺦⺧⺨⺩⺪⺫⺬⺭⺮⺯⺰⺱⺲⺳⺴⺵⺶⺷⺸⺹⺺⺻⺼⺽⺾⺿⻀⻁⻂⻃⻄⻅⻆⻇⻈⻉⻊⻋⻌⻍⻎⻏⻐⻑⻒⻓⻔⻕⻖⻗⻘⻙⻚⻛⻜⻝⻞⻟⻠';
+ $result = Multibyte::mimeEncode($string);
+ $expected = '=?UTF-8?B?4rqA4rqB4rqC4rqD4rqE4rqF4rqG4rqH4rqI4rqJ4rqK4rqL4rqM4rqN4rqO?=' . "\r\n" .
+ ' =?UTF-8?B?4rqP4rqQ4rqR4rqS4rqT4rqU4rqV4rqW4rqX4rqY4rqZ4rqb4rqc4rqd4rqe?=' . "\r\n" .
+ ' =?UTF-8?B?4rqf4rqg4rqh4rqi4rqj4rqk4rql4rqm4rqn4rqo4rqp4rqq4rqr4rqs4rqt?=' . "\r\n" .
+ ' =?UTF-8?B?4rqu4rqv4rqw4rqx4rqy4rqz4rq04rq14rq24rq34rq44rq54rq64rq74rq8?=' . "\r\n" .
+ ' =?UTF-8?B?4rq94rq+4rq/4ruA4ruB4ruC4ruD4ruE4ruF4ruG4ruH4ruI4ruJ4ruK4ruL?=' . "\r\n" .
+ ' =?UTF-8?B?4ruM4ruN4ruO4ruP4ruQ4ruR4ruS4ruT4ruU4ruV4ruW4ruX4ruY4ruZ4rua?=' . "\r\n" .
+ ' =?UTF-8?B?4rub4ruc4rud4rue4ruf4rug?=';
+ $this->assertEqual($result, $expected);
+
+ $string = '⽅⽆⽇⽈⽉⽊⽋⽌⽍⽎⽏⽐⽑⽒⽓⽔⽕⽖⽗⽘⽙⽚⽛⽜⽝⽞⽟⽠⽡⽢⽣⽤⽥⽦⽧⽨⽩⽪⽫⽬⽭⽮⽯⽰⽱⽲⽳⽴⽵⽶⽷⽸⽹⽺⽻⽼⽽⽾⽿';
+ $result = Multibyte::mimeEncode($string);
+ $expected = '=?UTF-8?B?4r2F4r2G4r2H4r2I4r2J4r2K4r2L4r2M4r2N4r2O4r2P4r2Q4r2R4r2S4r2T?=' . "\r\n" .
+ ' =?UTF-8?B?4r2U4r2V4r2W4r2X4r2Y4r2Z4r2a4r2b4r2c4r2d4r2e4r2f4r2g4r2h4r2i?=' . "\r\n" .
+ ' =?UTF-8?B?4r2j4r2k4r2l4r2m4r2n4r2o4r2p4r2q4r2r4r2s4r2t4r2u4r2v4r2w4r2x?=' . "\r\n" .
+ ' =?UTF-8?B?4r2y4r2z4r204r214r224r234r244r254r264r274r284r294r2+4r2/?=';
+ $this->assertEqual($result, $expected);
+
+ $string = '눡눢눣눤눥눦눧눨눩눪눫눬눭눮눯눰눱눲눳눴눵눶눷눸눹눺눻눼눽눾눿뉀뉁뉂뉃뉄뉅뉆뉇뉈뉉뉊뉋뉌뉍뉎뉏뉐뉑뉒뉓뉔뉕뉖뉗뉘뉙뉚뉛뉜뉝뉞뉟뉠뉡뉢뉣뉤뉥뉦뉧뉨뉩뉪뉫뉬뉭뉮뉯뉰뉱뉲뉳뉴뉵뉶뉷뉸뉹뉺뉻뉼뉽뉾뉿늀늁늂늃늄';
+ $result = Multibyte::mimeEncode($string);
+ $expected = '=?UTF-8?B?64ih64ii64ij64ik64il64im64in64io64ip64iq64ir64is64it64iu64iv?=' . "\r\n" .
+ ' =?UTF-8?B?64iw64ix64iy64iz64i064i164i264i364i464i564i664i764i864i964i+?=' . "\r\n" .
+ ' =?UTF-8?B?64i/64mA64mB64mC64mD64mE64mF64mG64mH64mI64mJ64mK64mL64mM64mN?=' . "\r\n" .
+ ' =?UTF-8?B?64mO64mP64mQ64mR64mS64mT64mU64mV64mW64mX64mY64mZ64ma64mb64mc?=' . "\r\n" .
+ ' =?UTF-8?B?64md64me64mf64mg64mh64mi64mj64mk64ml64mm64mn64mo64mp64mq64mr?=' . "\r\n" .
+ ' =?UTF-8?B?64ms64mt64mu64mv64mw64mx64my64mz64m064m164m264m364m464m564m6?=' . "\r\n" .
+ ' =?UTF-8?B?64m764m864m964m+64m/64qA64qB64qC64qD64qE?=';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ﹰﹱﹲﹳﹴﹶﹷﹸﹹﹺﹻﹼﹽﹾﹿﺀﺁﺂﺃﺄﺅﺆﺇﺈﺉﺊﺋﺌﺍﺎﺏﺐﺑﺒﺓﺔﺕﺖﺗﺘﺙﺚﺛﺜﺝﺞﺟﺠﺡﺢﺣﺤﺥﺦﺧﺨﺩﺪﺫﺬﺭﺮﺯﺰ';
+ $result = Multibyte::mimeEncode($string);
+ $expected = '=?UTF-8?B?77mw77mx77my77mz77m077m177m277m377m477m577m677m777m877m977m+?=' . "\r\n" .
+ ' =?UTF-8?B?77m/77qA77qB77qC77qD77qE77qF77qG77qH77qI77qJ77qK77qL77qM77qN?=' . "\r\n" .
+ ' =?UTF-8?B?77qO77qP77qQ77qR77qS77qT77qU77qV77qW77qX77qY77qZ77qa77qb77qc?=' . "\r\n" .
+ ' =?UTF-8?B?77qd77qe77qf77qg77qh77qi77qj77qk77ql77qm77qn77qo77qp77qq77qr?=' . "\r\n" .
+ ' =?UTF-8?B?77qs77qt77qu77qv77qw?=';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ﺱﺲﺳﺴﺵﺶﺷﺸﺹﺺﺻﺼﺽﺾﺿﻀﻁﻂﻃﻄﻅﻆﻇﻈﻉﻊﻋﻌﻍﻎﻏﻐﻑﻒﻓﻔﻕﻖﻗﻘﻙﻚﻛﻜﻝﻞﻟﻠﻡﻢﻣﻤﻥﻦﻧﻨﻩﻪﻫﻬﻭﻮﻯﻰﻱﻲﻳﻴﻵﻶﻷﻸﻹﻺﻻﻼ';
+ $result = Multibyte::mimeEncode($string);
+ $expected = '=?UTF-8?B?77qx77qy77qz77q077q177q277q377q477q577q677q777q877q977q+77q/?=' . "\r\n" .
+ ' =?UTF-8?B?77uA77uB77uC77uD77uE77uF77uG77uH77uI77uJ77uK77uL77uM77uN77uO?=' . "\r\n" .
+ ' =?UTF-8?B?77uP77uQ77uR77uS77uT77uU77uV77uW77uX77uY77uZ77ua77ub77uc77ud?=' . "\r\n" .
+ ' =?UTF-8?B?77ue77uf77ug77uh77ui77uj77uk77ul77um77un77uo77up77uq77ur77us?=' . "\r\n" .
+ ' =?UTF-8?B?77ut77uu77uv77uw77ux77uy77uz77u077u177u277u377u477u577u677u7?=' . "\r\n" .
+ ' =?UTF-8?B?77u8?=';
+ $this->assertEqual($result, $expected);
+
+ $string = 'abcdefghijklmnopqrstuvwxyz';
+ $result = Multibyte::mimeEncode($string);
+ $expected = '=?UTF-8?B?772B772C772D772E772F772G772H772I772J772K772L772M772N772O772P?=' . "\r\n" .
+ ' =?UTF-8?B?772Q772R772S772T772U772V772W772X772Y772Z772a?=';
+ $this->assertEqual($result, $expected);
+
+ $string = '。「」、・ヲァィゥェォャュョッーアイウエオカキク';
+ $result = Multibyte::mimeEncode($string);
+ $expected = '=?UTF-8?B?772h772i772j772k772l772m772n772o772p772q772r772s772t772u772v?=' . "\r\n" .
+ ' =?UTF-8?B?772w772x772y772z77207721772277237724?=';
+ $this->assertEqual($result, $expected);
+
+ $string = 'ケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン゙';
+ $result = Multibyte::mimeEncode($string);
+ $expected = '=?UTF-8?B?77257726772777287729772+772/776A776B776C776D776E776F776G776H?=' . "\r\n" .
+ ' =?UTF-8?B?776I776J776K776L776M776N776O776P776Q776R776S776T776U776V776W?=' . "\r\n" .
+ ' =?UTF-8?B?776X776Y776Z776a776b776c776d776e?=';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Ĥēĺļŏ, Ŵőřļď!';
+ $result = Multibyte::mimeEncode($string);
+ $expected = '=?UTF-8?B?xKTEk8S6xLzFjywgxbTFkcWZxLzEjyE=?=';
+ $this->assertEqual($result, $expected);
+
+ $string = 'Hello, World!';
+ $result = Multibyte::mimeEncode($string);
+ $this->assertEqual($result, $string);
+
+ $string = 'čini';
+ $result = Multibyte::mimeEncode($string);
+ $expected = '=?UTF-8?B?xI1pbmk=?=';
+ $this->assertEqual($result, $expected);
+
+ $string = 'moći';
+ $result = Multibyte::mimeEncode($string);
+ $expected = '=?UTF-8?B?bW/Eh2k=?=';
+ $this->assertEqual($result, $expected);
+
+ $string = 'državni';
+ $result = Multibyte::mimeEncode($string);
+ $expected = '=?UTF-8?B?ZHLFvmF2bmk=?=';
+ $this->assertEqual($result, $expected);
+
+ $string = '把百度设为首页';
+ $result = Multibyte::mimeEncode($string);
+ $expected = '=?UTF-8?B?5oqK55m+5bqm6K6+5Li66aaW6aG1?=';
+ $this->assertEqual($result, $expected);
+
+ $string = '一二三周永龍';
+ $result = Multibyte::mimeEncode($string);
+ $expected = '=?UTF-8?B?5LiA5LqM5LiJ5ZGo5rC46b6N?=';
+ $this->assertEqual($result, $expected);
+ }
+}
diff --git a/code/ryzom/tools/server/www/webtt/cake/tests/cases/libs/object.test.php b/code/ryzom/tools/server/www/webtt/cake/tests/cases/libs/object.test.php
new file mode 100644
index 000000000..36efe658c
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/cake/tests/cases/libs/object.test.php
@@ -0,0 +1,866 @@
+
+ * Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
+ *
+ * Licensed under The Open Group Test Suite License
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
+ * @link http://book.cakephp.org/view/1196/Testing CakePHP(tm) Tests
+ * @package cake
+ * @subpackage cake.tests.cases.libs
+ * @since CakePHP(tm) v 1.2.0.5432
+ * @license http://www.opensource.org/licenses/opengroup.php The Open Group Test Suite License
+ */
+App::import('Core', array('Object', 'Controller', 'Model'));
+
+/**
+ * RequestActionPost class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.object
+ */
+class RequestActionPost extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'ControllerPost'
+ * @access public
+ */
+ var $name = 'RequestActionPost';
+
+/**
+ * useTable property
+ *
+ * @var string 'posts'
+ * @access public
+ */
+ var $useTable = 'posts';
+}
+
+/**
+ * RequestActionController class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs
+ */
+class RequestActionController extends Controller {
+
+/**
+* uses property
+*
+* @var array
+* @access public
+*/
+ var $uses = array('RequestActionPost');
+
+/**
+* test_request_action method
+*
+* @access public
+* @return void
+*/
+ function test_request_action() {
+ return 'This is a test';
+ }
+
+/**
+* another_ra_test method
+*
+* @param mixed $id
+* @param mixed $other
+* @access public
+* @return void
+*/
+ function another_ra_test($id, $other) {
+ return $id + $other;
+ }
+
+/**
+ * normal_request_action method
+ *
+ * @access public
+ * @return void
+ */
+ function normal_request_action() {
+ return 'Hello World';
+ }
+
+/**
+ * returns $this->here
+ *
+ * @return void
+ */
+ function return_here() {
+ return $this->here;
+ }
+
+/**
+ * paginate_request_action method
+ *
+ * @access public
+ * @return void
+ */
+ function paginate_request_action() {
+ $data = $this->paginate();
+ return true;
+ }
+
+/**
+ * post pass, testing post passing
+ *
+ * @return array
+ */
+ function post_pass() {
+ return $this->data;
+ }
+
+/**
+ * test param passing and parsing.
+ *
+ * @return array
+ */
+ function params_pass() {
+ return $this->params;
+ }
+}
+
+/**
+ * RequestActionPersistentController class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs
+ */
+class RequestActionPersistentController extends Controller {
+
+/**
+* uses property
+*
+* @var array
+* @access public
+*/
+ var $uses = array('PersisterOne');
+
+/**
+* persistModel property
+*
+* @var array
+* @access public
+*/
+ var $persistModel = true;
+
+/**
+ * post pass, testing post passing
+ *
+ * @return array
+ */
+ function index() {
+ return 'This is a test';
+ }
+}
+
+/**
+ * TestObject class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs
+ */
+class TestObject extends Object {
+
+/**
+ * firstName property
+ *
+ * @var string 'Joel'
+ * @access public
+ */
+ var $firstName = 'Joel';
+
+/**
+ * lastName property
+ *
+ * @var string 'Moss'
+ * @access public
+ */
+ var $lastName = 'Moss';
+
+/**
+ * methodCalls property
+ *
+ * @var array
+ * @access public
+ */
+ var $methodCalls = array();
+
+/**
+ * emptyMethod method
+ *
+ * @access public
+ * @return void
+ */
+ function emptyMethod() {
+ $this->methodCalls[] = 'emptyMethod';
+ }
+
+/**
+ * oneParamMethod method
+ *
+ * @param mixed $param
+ * @access public
+ * @return void
+ */
+ function oneParamMethod($param) {
+ $this->methodCalls[] = array('oneParamMethod' => array($param));
+ }
+
+/**
+ * twoParamMethod method
+ *
+ * @param mixed $param
+ * @param mixed $param2
+ * @access public
+ * @return void
+ */
+ function twoParamMethod($param, $param2) {
+ $this->methodCalls[] = array('twoParamMethod' => array($param, $param2));
+ }
+
+/**
+ * threeParamMethod method
+ *
+ * @param mixed $param
+ * @param mixed $param2
+ * @param mixed $param3
+ * @access public
+ * @return void
+ */
+ function threeParamMethod($param, $param2, $param3) {
+ $this->methodCalls[] = array('threeParamMethod' => array($param, $param2, $param3));
+ }
+ /**
+ * fourParamMethod method
+ *
+ * @param mixed $param
+ * @param mixed $param2
+ * @param mixed $param3
+ * @param mixed $param4
+ * @access public
+ * @return void
+ */
+ function fourParamMethod($param, $param2, $param3, $param4) {
+ $this->methodCalls[] = array('fourParamMethod' => array($param, $param2, $param3, $param4));
+ }
+ /**
+ * fiveParamMethod method
+ *
+ * @param mixed $param
+ * @param mixed $param2
+ * @param mixed $param3
+ * @param mixed $param4
+ * @param mixed $param5
+ * @access public
+ * @return void
+ */
+ function fiveParamMethod($param, $param2, $param3, $param4, $param5) {
+ $this->methodCalls[] = array('fiveParamMethod' => array($param, $param2, $param3, $param4, $param5));
+ }
+
+/**
+ * crazyMethod method
+ *
+ * @param mixed $param
+ * @param mixed $param2
+ * @param mixed $param3
+ * @param mixed $param4
+ * @param mixed $param5
+ * @param mixed $param6
+ * @param mixed $param7
+ * @access public
+ * @return void
+ */
+ function crazyMethod($param, $param2, $param3, $param4, $param5, $param6, $param7 = null) {
+ $this->methodCalls[] = array('crazyMethod' => array($param, $param2, $param3, $param4, $param5, $param6, $param7));
+ }
+
+/**
+ * methodWithOptionalParam method
+ *
+ * @param mixed $param
+ * @access public
+ * @return void
+ */
+ function methodWithOptionalParam($param = null) {
+ $this->methodCalls[] = array('methodWithOptionalParam' => array($param));
+ }
+
+/**
+ * testPersist
+ *
+ * @return void
+ */
+ function testPersist($name, $return = null, &$object, $type = null) {
+ return $this->_persist($name, $return, $object, $type);
+ }
+}
+
+/**
+ * ObjectTestModel class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs
+ */
+class ObjectTestModel extends CakeTestModel {
+ var $useTable = false;
+ var $name = 'ObjectTestModel';
+}
+
+/**
+ * Object Test class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs
+ */
+class ObjectTest extends CakeTestCase {
+
+/**
+ * fixtures
+ *
+ * @var string
+ */
+ var $fixtures = array('core.post', 'core.test_plugin_comment', 'core.comment');
+
+/**
+ * setUp method
+ *
+ * @access public
+ * @return void
+ */
+ function setUp() {
+ $this->object = new TestObject();
+ }
+
+/**
+ * tearDown method
+ *
+ * @access public
+ * @return void
+ */
+ function tearDown() {
+ unset($this->object);
+ }
+
+/**
+ * endTest
+ *
+ * @access public
+ * @return void
+ */
+ function endTest() {
+ App::build();
+ }
+
+/**
+ * testLog method
+ *
+ * @access public
+ * @return void
+ */
+ function testLog() {
+ @unlink(LOGS . 'error.log');
+ $this->assertTrue($this->object->log('Test warning 1'));
+ $this->assertTrue($this->object->log(array('Test' => 'warning 2')));
+ $result = file(LOGS . 'error.log');
+ $this->assertPattern('/^2[0-9]{3}-[0-9]+-[0-9]+ [0-9]+:[0-9]+:[0-9]+ Error: Test warning 1$/', $result[0]);
+ $this->assertPattern('/^2[0-9]{3}-[0-9]+-[0-9]+ [0-9]+:[0-9]+:[0-9]+ Error: Array$/', $result[1]);
+ $this->assertPattern('/^\($/', $result[2]);
+ $this->assertPattern('/\[Test\] => warning 2$/', $result[3]);
+ $this->assertPattern('/^\)$/', $result[4]);
+ unlink(LOGS . 'error.log');
+
+ @unlink(LOGS . 'error.log');
+ $this->assertTrue($this->object->log('Test warning 1', LOG_WARNING));
+ $this->assertTrue($this->object->log(array('Test' => 'warning 2'), LOG_WARNING));
+ $result = file(LOGS . 'error.log');
+ $this->assertPattern('/^2[0-9]{3}-[0-9]+-[0-9]+ [0-9]+:[0-9]+:[0-9]+ Warning: Test warning 1$/', $result[0]);
+ $this->assertPattern('/^2[0-9]{3}-[0-9]+-[0-9]+ [0-9]+:[0-9]+:[0-9]+ Warning: Array$/', $result[1]);
+ $this->assertPattern('/^\($/', $result[2]);
+ $this->assertPattern('/\[Test\] => warning 2$/', $result[3]);
+ $this->assertPattern('/^\)$/', $result[4]);
+ unlink(LOGS . 'error.log');
+ }
+
+/**
+ * testSet method
+ *
+ * @access public
+ * @return void
+ */
+ function testSet() {
+ $this->object->_set('a string');
+ $this->assertEqual($this->object->firstName, 'Joel');
+
+ $this->object->_set(array('firstName'));
+ $this->assertEqual($this->object->firstName, 'Joel');
+
+ $this->object->_set(array('firstName' => 'Ashley'));
+ $this->assertEqual($this->object->firstName, 'Ashley');
+
+ $this->object->_set(array('firstName' => 'Joel', 'lastName' => 'Moose'));
+ $this->assertEqual($this->object->firstName, 'Joel');
+ $this->assertEqual($this->object->lastName, 'Moose');
+ }
+
+/**
+ * testPersist method
+ *
+ * @access public
+ * @return void
+ */
+ function testPersist() {
+ ClassRegistry::flush();
+
+ $cacheDisable = Configure::read('Cache.disable');
+ Configure::write('Cache.disable', false);
+ @unlink(CACHE . 'persistent' . DS . 'testmodel.php');
+ $test = new stdClass;
+ $this->assertFalse($this->object->testPersist('TestModel', null, $test));
+ $this->assertFalse($this->object->testPersist('TestModel', true, $test));
+ $this->assertTrue($this->object->testPersist('TestModel', null, $test));
+ $this->assertTrue(file_exists(CACHE . 'persistent' . DS . 'testmodel.php'));
+ $this->assertTrue($this->object->testPersist('TestModel', true, $test));
+ $this->assertEqual($this->object->TestModel, $test);
+
+ @unlink(CACHE . 'persistent' . DS . 'testmodel.php');
+
+ $model =& new ObjectTestModel();
+ $expected = ClassRegistry::keys();
+
+ ClassRegistry::flush();
+ $data = array('object_test_model' => $model);
+ $this->assertFalse($this->object->testPersist('ObjectTestModel', true, $data));
+ $this->assertTrue(file_exists(CACHE . 'persistent' . DS . 'objecttestmodel.php'));
+
+ $this->object->testPersist('ObjectTestModel', true, $model, 'registry');
+
+ $result = ClassRegistry::keys();
+ $this->assertEqual($result, $expected);
+
+ $newModel = ClassRegistry::getObject('object_test_model');
+ $this->assertEqual('ObjectTestModel', $newModel->name);
+
+ @unlink(CACHE . 'persistent' . DS . 'objecttestmodel.php');
+
+ Configure::write('Cache.disable', $cacheDisable);
+ }
+
+/**
+ * testPersistWithRequestAction method
+ *
+ * @access public
+ * @return void
+ */
+ function testPersistWithBehavior() {
+ ClassRegistry::flush();
+
+ $cacheDisable = Configure::read('Cache.disable');
+ Configure::write('Cache.disable', false);
+
+ App::build(array(
+ 'models' => array(TEST_CAKE_CORE_INCLUDE_PATH . 'tests' . DS . 'test_app' . DS . 'models' . DS),
+ 'plugins' => array(TEST_CAKE_CORE_INCLUDE_PATH . 'tests' . DS . 'test_app' . DS . 'plugins'. DS),
+ 'behaviors' => array(TEST_CAKE_CORE_INCLUDE_PATH . 'tests' . DS . 'test_app' . DS . 'models'. DS . 'behaviors' . DS),
+ ), true);
+
+ $this->assertFalse(class_exists('PersisterOneBehaviorBehavior'));
+ $this->assertFalse(class_exists('PersisterTwoBehaviorBehavior'));
+ $this->assertFalse(class_exists('TestPluginPersisterBehavior'));
+ $this->assertFalse(class_exists('TestPluginAuthors'));
+
+ $Controller = new RequestActionPersistentController();
+ $Controller->persistModel = true;
+ $Controller->constructClasses();
+
+ $this->assertTrue(file_exists(CACHE . 'persistent' . DS . 'persisterone.php'));
+ $this->assertTrue(file_exists(CACHE . 'persistent' . DS . 'persisteroneregistry.php'));
+
+ $contents = file_get_contents(CACHE . 'persistent' . DS . 'persisteroneregistry.php');
+ $contents = str_replace('"PersisterOne"', '"PersisterTwo"', $contents);
+ $contents = str_replace('persister_one', 'persister_two', $contents);
+ $contents = str_replace('test_plugin_comment', 'test_plugin_authors', $contents);
+ $result = file_put_contents(CACHE . 'persistent' . DS . 'persisteroneregistry.php', $contents);
+
+ $this->assertTrue(class_exists('PersisterOneBehaviorBehavior'));
+ $this->assertTrue(class_exists('TestPluginPersisterOneBehavior'));
+ $this->assertTrue(class_exists('TestPluginComment'));
+ $this->assertFalse(class_exists('PersisterTwoBehaviorBehavior'));
+ $this->assertFalse(class_exists('TestPluginPersisterTwoBehavior'));
+ $this->assertFalse(class_exists('TestPluginAuthors'));
+
+ $Controller = new RequestActionPersistentController();
+ $Controller->persistModel = true;
+ $Controller->constructClasses();
+
+ $this->assertTrue(class_exists('PersisterOneBehaviorBehavior'));
+ $this->assertTrue(class_exists('PersisterTwoBehaviorBehavior'));
+ $this->assertTrue(class_exists('TestPluginPersisterTwoBehavior'));
+ $this->assertTrue(class_exists('TestPluginAuthors'));
+
+ @unlink(CACHE . 'persistent' . DS . 'persisterone.php');
+ @unlink(CACHE . 'persistent' . DS . 'persisteroneregistry.php');
+ }
+
+/**
+ * testPersistWithBehaviorAndRequestAction method
+ *
+ * @see testPersistWithBehavior
+ * @access public
+ * @return void
+ */
+ function testPersistWithBehaviorAndRequestAction() {
+ ClassRegistry::flush();
+
+ $cacheDisable = Configure::read('Cache.disable');
+ Configure::write('Cache.disable', false);
+
+ $this->assertFalse(class_exists('ContainableBehavior'));
+
+ App::build(array(
+ 'models' => array(TEST_CAKE_CORE_INCLUDE_PATH . 'tests' . DS . 'test_app' . DS . 'models' . DS),
+ 'behaviors' => array(TEST_CAKE_CORE_INCLUDE_PATH . 'tests' . DS . 'test_app' . DS . 'models'. DS . 'behaviors' . DS),
+ ), true);
+
+ $this->assertFalse(class_exists('PersistOneBehaviorBehavior'));
+ $this->assertFalse(class_exists('PersistTwoBehaviorBehavior'));
+
+ $Controller = new RequestActionPersistentController();
+ $Controller->persistModel = true;
+ $Controller->constructClasses();
+
+ $this->assertTrue(file_exists(CACHE . 'persistent' . DS . 'persisterone.php'));
+ $this->assertTrue(file_exists(CACHE . 'persistent' . DS . 'persisteroneregistry.php'));
+
+ $keys = ClassRegistry::keys();
+ $this->assertEqual($keys, array(
+ 'persister_one',
+ 'comment',
+ 'test_plugin_comment',
+ 'test_plugin.test_plugin_comment',
+ 'persister_one_behavior_behavior',
+ 'test_plugin_persister_one_behavior',
+ 'test_plugin.test_plugin_persister_one_behavior'
+ ));
+
+ ob_start();
+ $Controller->set('content_for_layout', 'cool');
+ $Controller->render('index', 'ajax', '/layouts/ajax');
+ $result = ob_get_clean();
+
+ $keys = ClassRegistry::keys();
+ $this->assertEqual($keys, array(
+ 'persister_one',
+ 'comment',
+ 'test_plugin_comment',
+ 'test_plugin.test_plugin_comment',
+ 'persister_one_behavior_behavior',
+ 'test_plugin_persister_one_behavior',
+ 'test_plugin.test_plugin_persister_one_behavior',
+ 'view'
+ ));
+ $result = $this->object->requestAction('/request_action_persistent/index');
+ $expected = 'This is a test';
+ $this->assertEqual($result, $expected);
+
+ @unlink(CACHE . 'persistent' . DS . 'persisterone.php');
+ @unlink(CACHE . 'persistent' . DS . 'persisteroneregistry.php');
+
+ $Controller = new RequestActionPersistentController();
+ $Controller->persistModel = true;
+ $Controller->constructClasses();
+
+ @unlink(CACHE . 'persistent' . DS . 'persisterone.php');
+ @unlink(CACHE . 'persistent' . DS . 'persisteroneregistry.php');
+
+ Configure::write('Cache.disable', $cacheDisable);
+ }
+
+/**
+ * testToString method
+ *
+ * @access public
+ * @return void
+ */
+ function testToString() {
+ $result = strtolower($this->object->toString());
+ $this->assertEqual($result, 'testobject');
+ }
+
+/**
+ * testMethodDispatching method
+ *
+ * @access public
+ * @return void
+ */
+ function testMethodDispatching() {
+ $this->object->emptyMethod();
+ $expected = array('emptyMethod');
+ $this->assertIdentical($this->object->methodCalls, $expected);
+
+ $this->object->oneParamMethod('Hello');
+ $expected[] = array('oneParamMethod' => array('Hello'));
+ $this->assertIdentical($this->object->methodCalls, $expected);
+
+ $this->object->twoParamMethod(true, false);
+ $expected[] = array('twoParamMethod' => array(true, false));
+ $this->assertIdentical($this->object->methodCalls, $expected);
+
+ $this->object->threeParamMethod(true, false, null);
+ $expected[] = array('threeParamMethod' => array(true, false, null));
+ $this->assertIdentical($this->object->methodCalls, $expected);
+
+ $this->object->crazyMethod(1, 2, 3, 4, 5, 6, 7);
+ $expected[] = array('crazyMethod' => array(1, 2, 3, 4, 5, 6, 7));
+ $this->assertIdentical($this->object->methodCalls, $expected);
+
+ $this->object = new TestObject();
+ $this->assertIdentical($this->object->methodCalls, array());
+
+ $this->object->dispatchMethod('emptyMethod');
+ $expected = array('emptyMethod');
+ $this->assertIdentical($this->object->methodCalls, $expected);
+
+ $this->object->dispatchMethod('oneParamMethod', array('Hello'));
+ $expected[] = array('oneParamMethod' => array('Hello'));
+ $this->assertIdentical($this->object->methodCalls, $expected);
+
+ $this->object->dispatchMethod('twoParamMethod', array(true, false));
+ $expected[] = array('twoParamMethod' => array(true, false));
+ $this->assertIdentical($this->object->methodCalls, $expected);
+
+ $this->object->dispatchMethod('threeParamMethod', array(true, false, null));
+ $expected[] = array('threeParamMethod' => array(true, false, null));
+ $this->assertIdentical($this->object->methodCalls, $expected);
+
+ $this->object->dispatchMethod('fourParamMethod', array(1, 2, 3, 4));
+ $expected[] = array('fourParamMethod' => array(1, 2, 3, 4));
+ $this->assertIdentical($this->object->methodCalls, $expected);
+
+ $this->object->dispatchMethod('fiveParamMethod', array(1, 2, 3, 4, 5));
+ $expected[] = array('fiveParamMethod' => array(1, 2, 3, 4, 5));
+ $this->assertIdentical($this->object->methodCalls, $expected);
+
+ $this->object->dispatchMethod('crazyMethod', array(1, 2, 3, 4, 5, 6, 7));
+ $expected[] = array('crazyMethod' => array(1, 2, 3, 4, 5, 6, 7));
+ $this->assertIdentical($this->object->methodCalls, $expected);
+
+ $this->object->dispatchMethod('methodWithOptionalParam', array('Hello'));
+ $expected[] = array('methodWithOptionalParam' => array("Hello"));
+ $this->assertIdentical($this->object->methodCalls, $expected);
+
+ $this->object->dispatchMethod('methodWithOptionalParam');
+ $expected[] = array('methodWithOptionalParam' => array(null));
+ $this->assertIdentical($this->object->methodCalls, $expected);
+ }
+
+/**
+ * testRequestAction method
+ *
+ * @access public
+ * @return void
+ */
+ function testRequestAction() {
+ App::build(array(
+ 'models' => array(TEST_CAKE_CORE_INCLUDE_PATH . 'tests' . DS . 'test_app' . DS . 'models' . DS),
+ 'views' => array(TEST_CAKE_CORE_INCLUDE_PATH . 'tests' . DS . 'test_app' . DS . 'views' . DS),
+ 'controllers' => array(TEST_CAKE_CORE_INCLUDE_PATH . 'tests' . DS . 'test_app' . DS . 'controllers' . DS)
+ ));
+ $result = $this->object->requestAction('');
+ $this->assertFalse($result);
+
+ $result = $this->object->requestAction('/request_action/test_request_action');
+ $expected = 'This is a test';
+ $this->assertEqual($result, $expected);;
+
+ $result = $this->object->requestAction('/request_action/another_ra_test/2/5');
+ $expected = 7;
+ $this->assertEqual($result, $expected);
+
+ $result = $this->object->requestAction('/tests_apps/index', array('return'));
+ $expected = 'This is the TestsAppsController index view';
+ $this->assertEqual($result, $expected);
+
+ $result = $this->object->requestAction('/tests_apps/some_method');
+ $expected = 5;
+ $this->assertEqual($result, $expected);
+
+ $result = $this->object->requestAction('/request_action/paginate_request_action');
+ $this->assertTrue($result);
+
+ $result = $this->object->requestAction('/request_action/normal_request_action');
+ $expected = 'Hello World';
+ $this->assertEqual($result, $expected);
+
+ App::build();
+ }
+
+/**
+ * test requestAction() and plugins.
+ *
+ * @return void
+ */
+ function testRequestActionPlugins() {
+ App::build(array(
+ 'plugins' => array(TEST_CAKE_CORE_INCLUDE_PATH . 'tests' . DS . 'test_app' . DS . 'plugins' . DS),
+ ));
+ App::objects('plugin', null, false);
+ Router::reload();
+
+ $result = $this->object->requestAction('/test_plugin/tests/index', array('return'));
+ $expected = 'test plugin index';
+ $this->assertEqual($result, $expected);
+
+ $result = $this->object->requestAction('/test_plugin/tests/index/some_param', array('return'));
+ $expected = 'test plugin index';
+ $this->assertEqual($result, $expected);
+
+ $result = $this->object->requestAction(
+ array('controller' => 'tests', 'action' => 'index', 'plugin' => 'test_plugin'), array('return')
+ );
+ $expected = 'test plugin index';
+ $this->assertEqual($result, $expected);
+
+ $result = $this->object->requestAction('/test_plugin/tests/some_method');
+ $expected = 25;
+ $this->assertEqual($result, $expected);
+
+ $result = $this->object->requestAction(
+ array('controller' => 'tests', 'action' => 'some_method', 'plugin' => 'test_plugin')
+ );
+ $expected = 25;
+ $this->assertEqual($result, $expected);
+
+ App::build();
+ App::objects('plugin', null, false);
+ }
+
+/**
+ * test requestAction() with arrays.
+ *
+ * @return void
+ */
+ function testRequestActionArray() {
+ App::build(array(
+ 'models' => array(TEST_CAKE_CORE_INCLUDE_PATH . 'tests' . DS . 'test_app' . DS . 'models' . DS),
+ 'views' => array(TEST_CAKE_CORE_INCLUDE_PATH . 'tests' . DS . 'test_app' . DS . 'views' . DS),
+ 'controllers' => array(TEST_CAKE_CORE_INCLUDE_PATH . 'tests' . DS . 'test_app' . DS . 'controllers' . DS)
+ ));
+
+ $result = $this->object->requestAction(
+ array('controller' => 'request_action', 'action' => 'test_request_action')
+ );
+ $expected = 'This is a test';
+ $this->assertEqual($result, $expected);
+
+ $result = $this->object->requestAction(
+ array('controller' => 'request_action', 'action' => 'another_ra_test'),
+ array('pass' => array('5', '7'))
+ );
+ $expected = 12;
+ $this->assertEqual($result, $expected);
+
+ $result = $this->object->requestAction(
+ array('controller' => 'tests_apps', 'action' => 'index'), array('return')
+ );
+ $expected = 'This is the TestsAppsController index view';
+ $this->assertEqual($result, $expected);
+
+ $result = $this->object->requestAction(array('controller' => 'tests_apps', 'action' => 'some_method'));
+ $expected = 5;
+ $this->assertEqual($result, $expected);
+
+ $result = $this->object->requestAction(
+ array('controller' => 'request_action', 'action' => 'normal_request_action')
+ );
+ $expected = 'Hello World';
+ $this->assertEqual($result, $expected);
+
+ $result = $this->object->requestAction(
+ array('controller' => 'request_action', 'action' => 'paginate_request_action')
+ );
+ $this->assertTrue($result);
+
+ $result = $this->object->requestAction(
+ array('controller' => 'request_action', 'action' => 'paginate_request_action'),
+ array('pass' => array(5), 'named' => array('param' => 'value'))
+ );
+ $this->assertTrue($result);
+
+ App::build();
+ }
+
+/**
+ * Test that requestAction() is populating $this->params properly
+ *
+ * @access public
+ * @return void
+ */
+ function testRequestActionParamParseAndPass() {
+ $result = $this->object->requestAction('/request_action/params_pass');
+ $this->assertTrue(isset($result['url']['url']));
+ $this->assertEqual($result['url']['url'], '/request_action/params_pass');
+ $this->assertEqual($result['controller'], 'request_action');
+ $this->assertEqual($result['action'], 'params_pass');
+ $this->assertEqual($result['form'], array());
+ $this->assertEqual($result['plugin'], null);
+
+ $result = $this->object->requestAction('/request_action/params_pass/sort:desc/limit:5');
+ $expected = array('sort' => 'desc', 'limit' => 5,);
+ $this->assertEqual($result['named'], $expected);
+
+ $result = $this->object->requestAction(
+ array('controller' => 'request_action', 'action' => 'params_pass'),
+ array('named' => array('sort' => 'desc', 'limit' => 5))
+ );
+ $this->assertEqual($result['named'], $expected);
+ }
+
+/**
+ * test requestAction and POST parameter passing, and not passing when url is an array.
+ *
+ * @access public
+ * @return void
+ */
+ function testRequestActionPostPassing() {
+ $_tmp = $_POST;
+
+ $_POST = array('data' => array(
+ 'item' => 'value'
+ ));
+ $result = $this->object->requestAction(array('controller' => 'request_action', 'action' => 'post_pass'));
+ $expected = array();
+ $this->assertEqual($expected, $result);
+
+ $result = $this->object->requestAction(array('controller' => 'request_action', 'action' => 'post_pass'), array('data' => $_POST['data']));
+ $expected = $_POST['data'];
+ $this->assertEqual($expected, $result);
+
+ $result = $this->object->requestAction('/request_action/post_pass');
+ $expected = $_POST['data'];
+ $this->assertEqual($expected, $result);
+
+ $_POST = $_tmp;
+ }
+
+/**
+ * testCakeError
+ *
+ * @return void
+ */
+ function testCakeError() {
+
+ }
+}
diff --git a/code/ryzom/tools/server/www/webtt/cake/tests/cases/libs/overloadable.test.php b/code/ryzom/tools/server/www/webtt/cake/tests/cases/libs/overloadable.test.php
new file mode 100644
index 000000000..2b0fd31a8
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/cake/tests/cases/libs/overloadable.test.php
@@ -0,0 +1,39 @@
+
+ * Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
+ *
+ * Licensed under The Open Group Test Suite License
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
+ * @link http://book.cakephp.org/view/1196/Testing CakePHP(tm) Tests
+ * @package cake
+ * @subpackage cake.tests.cases.libs
+ * @since CakePHP(tm) v 1.2.0.5432
+ * @license http://www.opensource.org/licenses/opengroup.php The Open Group Test Suite License
+ */
+App::import('Core', 'Overloadable');
+
+/**
+ * OverloadableTest class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs
+ */
+class OverloadableTest extends CakeTestCase {
+
+/**
+ * skip method
+ *
+ * @access public
+ * @return void
+ */
+ function skip() {
+ $this->skipIf(true, ' %s OverloadableTest not implemented');
+ }
+}
diff --git a/code/ryzom/tools/server/www/webtt/cake/tests/cases/libs/router.test.php b/code/ryzom/tools/server/www/webtt/cake/tests/cases/libs/router.test.php
new file mode 100644
index 000000000..0d199655d
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/cake/tests/cases/libs/router.test.php
@@ -0,0 +1,2672 @@
+
+ * Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
+ *
+ * Licensed under The Open Group Test Suite License
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
+ * @link http://book.cakephp.org/view/1196/Testing CakePHP(tm) Tests
+ * @package cake
+ * @subpackage cake.tests.cases.libs
+ * @since CakePHP(tm) v 1.2.0.4206
+ * @license http://www.opensource.org/licenses/opengroup.php The Open Group Test Suite License
+ */
+App::import('Core', array('Router'));
+
+if (!defined('FULL_BASE_URL')) {
+ define('FULL_BASE_URL', 'http://cakephp.org');
+}
+
+/**
+ * RouterTest class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs
+ */
+class RouterTest extends CakeTestCase {
+
+/**
+ * setUp method
+ *
+ * @access public
+ * @return void
+ */
+ function setUp() {
+ $this->_routing = Configure::read('Routing');
+ Configure::write('Routing', array('admin' => null, 'prefixes' => array()));
+ Router::reload();
+ $this->router =& Router::getInstance();
+ }
+
+/**
+ * end the test and reset the environment
+ *
+ * @return void
+ */
+ function endTest() {
+ Configure::write('Routing', $this->_routing);
+ }
+
+/**
+ * testReturnedInstanceReference method
+ *
+ * @access public
+ * @return void
+ */
+ function testReturnedInstanceReference() {
+ $this->router->testVar = 'test';
+ $this->assertIdentical($this->router, Router::getInstance());
+ unset($this->router->testVar);
+ }
+
+/**
+ * testFullBaseURL method
+ *
+ * @access public
+ * @return void
+ */
+ function testFullBaseURL() {
+ $this->assertPattern('/^http(s)?:\/\//', Router::url('/', true));
+ $this->assertPattern('/^http(s)?:\/\//', Router::url(null, true));
+ $this->assertPattern('/^http(s)?:\/\//', Router::url(array('full_base' => true)));
+ $this->assertIdentical(FULL_BASE_URL . '/', Router::url(array('full_base' => true)));
+ }
+
+/**
+ * testRouteDefaultParams method
+ *
+ * @access public
+ * @return void
+ */
+ function testRouteDefaultParams() {
+ Router::connect('/:controller', array('controller' => 'posts'));
+ $this->assertEqual(Router::url(array('action' => 'index')), '/');
+ }
+
+/**
+ * testRouterIdentity method
+ *
+ * @access public
+ * @return void
+ */
+ function testRouterIdentity() {
+ $router2 = new Router();
+ $this->assertEqual(get_object_vars($this->router), get_object_vars($router2));
+ }
+
+/**
+ * testResourceRoutes method
+ *
+ * @access public
+ * @return void
+ */
+ function testResourceRoutes() {
+ Router::mapResources('Posts');
+
+ $_SERVER['REQUEST_METHOD'] = 'GET';
+ $result = Router::parse('/posts');
+ $this->assertEqual($result, array('pass' => array(), 'named' => array(), 'plugin' => '', 'controller' => 'posts', 'action' => 'index', '[method]' => 'GET'));
+ $this->assertEqual($this->router->__resourceMapped, array('posts'));
+
+ $_SERVER['REQUEST_METHOD'] = 'GET';
+ $result = Router::parse('/posts/13');
+ $this->assertEqual($result, array('pass' => array('13'), 'named' => array(), 'plugin' => '', 'controller' => 'posts', 'action' => 'view', 'id' => '13', '[method]' => 'GET'));
+ $this->assertEqual($this->router->__resourceMapped, array('posts'));
+
+ $_SERVER['REQUEST_METHOD'] = 'POST';
+ $result = Router::parse('/posts');
+ $this->assertEqual($result, array('pass' => array(), 'named' => array(), 'plugin' => '', 'controller' => 'posts', 'action' => 'add', '[method]' => 'POST'));
+ $this->assertEqual($this->router->__resourceMapped, array('posts'));
+
+ $_SERVER['REQUEST_METHOD'] = 'PUT';
+ $result = Router::parse('/posts/13');
+ $this->assertEqual($result, array('pass' => array('13'), 'named' => array(), 'plugin' => '', 'controller' => 'posts', 'action' => 'edit', 'id' => '13', '[method]' => 'PUT'));
+ $this->assertEqual($this->router->__resourceMapped, array('posts'));
+
+ $result = Router::parse('/posts/475acc39-a328-44d3-95fb-015000000000');
+ $this->assertEqual($result, array('pass' => array('475acc39-a328-44d3-95fb-015000000000'), 'named' => array(), 'plugin' => '', 'controller' => 'posts', 'action' => 'edit', 'id' => '475acc39-a328-44d3-95fb-015000000000', '[method]' => 'PUT'));
+ $this->assertEqual($this->router->__resourceMapped, array('posts'));
+
+ $_SERVER['REQUEST_METHOD'] = 'DELETE';
+ $result = Router::parse('/posts/13');
+ $this->assertEqual($result, array('pass' => array('13'), 'named' => array(), 'plugin' => '', 'controller' => 'posts', 'action' => 'delete', 'id' => '13', '[method]' => 'DELETE'));
+ $this->assertEqual($this->router->__resourceMapped, array('posts'));
+
+ $_SERVER['REQUEST_METHOD'] = 'GET';
+ $result = Router::parse('/posts/add');
+ $this->assertEqual($result, array('pass' => array(), 'named' => array(), 'plugin' => '', 'controller' => 'posts', 'action' => 'add'));
+ $this->assertEqual($this->router->__resourceMapped, array('posts'));
+
+ Router::reload();
+ Router::mapResources('Posts', array('id' => '[a-z0-9_]+'));
+
+ $_SERVER['REQUEST_METHOD'] = 'GET';
+ $result = Router::parse('/posts/add');
+ $this->assertEqual($result, array('pass' => array('add'), 'named' => array(), 'plugin' => '', 'controller' => 'posts', 'action' => 'view', 'id' => 'add', '[method]' => 'GET'));
+ $this->assertEqual($this->router->__resourceMapped, array('posts'));
+
+ $_SERVER['REQUEST_METHOD'] = 'PUT';
+ $result = Router::parse('/posts/name');
+ $this->assertEqual($result, array('pass' => array('name'), 'named' => array(), 'plugin' => '', 'controller' => 'posts', 'action' => 'edit', 'id' => 'name', '[method]' => 'PUT'));
+ $this->assertEqual($this->router->__resourceMapped, array('posts'));
+ }
+
+/**
+ * testMultipleResourceRoute method
+ *
+ * @access public
+ * @return void
+ */
+ function testMultipleResourceRoute() {
+ Router::connect('/:controller', array('action' => 'index', '[method]' => array('GET', 'POST')));
+
+ $_SERVER['REQUEST_METHOD'] = 'GET';
+ $result = Router::parse('/posts');
+ $this->assertEqual($result, array('pass' => array(), 'named' => array(), 'plugin' => '', 'controller' => 'posts', 'action' => 'index', '[method]' => array('GET', 'POST')));
+
+ $_SERVER['REQUEST_METHOD'] = 'POST';
+ $result = Router::parse('/posts');
+ $this->assertEqual($result, array('pass' => array(), 'named' => array(), 'plugin' => '', 'controller' => 'posts', 'action' => 'index', '[method]' => array('GET', 'POST')));
+ }
+
+/**
+ * testGenerateUrlResourceRoute method
+ *
+ * @access public
+ * @return void
+ */
+ function testGenerateUrlResourceRoute() {
+ Router::mapResources('Posts');
+
+ $result = Router::url(array('controller' => 'posts', 'action' => 'index', '[method]' => 'GET'));
+ $expected = '/posts';
+ $this->assertEqual($result, $expected);
+
+ $result = Router::url(array('controller' => 'posts', 'action' => 'view', '[method]' => 'GET', 'id' => 10));
+ $expected = '/posts/10';
+ $this->assertEqual($result, $expected);
+
+ $result = Router::url(array('controller' => 'posts', 'action' => 'add', '[method]' => 'POST'));
+ $expected = '/posts';
+ $this->assertEqual($result, $expected);
+
+ $result = Router::url(array('controller' => 'posts', 'action' => 'edit', '[method]' => 'PUT', 'id' => 10));
+ $expected = '/posts/10';
+ $this->assertEqual($result, $expected);
+
+ $result = Router::url(array('controller' => 'posts', 'action' => 'delete', '[method]' => 'DELETE', 'id' => 10));
+ $expected = '/posts/10';
+ $this->assertEqual($result, $expected);
+
+ $result = Router::url(array('controller' => 'posts', 'action' => 'edit', '[method]' => 'POST', 'id' => 10));
+ $expected = '/posts/10';
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testUrlNormalization method
+ *
+ * @access public
+ * @return void
+ */
+ function testUrlNormalization() {
+ $expected = '/users/logout';
+
+ $result = Router::normalize('/users/logout/');
+ $this->assertEqual($result, $expected);
+
+ $result = Router::normalize('//users//logout//');
+ $this->assertEqual($result, $expected);
+
+ $result = Router::normalize('users/logout');
+ $this->assertEqual($result, $expected);
+
+ $result = Router::normalize(array('controller' => 'users', 'action' => 'logout'));
+ $this->assertEqual($result, $expected);
+
+ $result = Router::normalize('/');
+ $this->assertEqual($result, '/');
+
+ $result = Router::normalize('http://google.com/');
+ $this->assertEqual($result, 'http://google.com/');
+
+ $result = Router::normalize('http://google.com//');
+ $this->assertEqual($result, 'http://google.com//');
+
+ $result = Router::normalize('/users/login/scope://foo');
+ $this->assertEqual($result, '/users/login/scope:/foo');
+
+ $result = Router::normalize('/recipe/recipes/add');
+ $this->assertEqual($result, '/recipe/recipes/add');
+
+ Router::setRequestInfo(array(array(), array('base' => '/us')));
+ $result = Router::normalize('/us/users/logout/');
+ $this->assertEqual($result, '/users/logout');
+
+ Router::reload();
+
+ Router::setRequestInfo(array(array(), array('base' => '/cake_12')));
+ $result = Router::normalize('/cake_12/users/logout/');
+ $this->assertEqual($result, '/users/logout');
+
+ Router::reload();
+ $_back = Configure::read('App.baseUrl');
+ Configure::write('App.baseUrl', '/');
+
+ Router::setRequestInfo(array(array(), array('base' => '/')));
+ $result = Router::normalize('users/login');
+ $this->assertEqual($result, '/users/login');
+ Configure::write('App.baseUrl', $_back);
+
+ Router::reload();
+ Router::setRequestInfo(array(array(), array('base' => 'beer')));
+ $result = Router::normalize('beer/admin/beers_tags/add');
+ $this->assertEqual($result, '/admin/beers_tags/add');
+
+ $result = Router::normalize('/admin/beers_tags/add');
+ $this->assertEqual($result, '/admin/beers_tags/add');
+ }
+
+/**
+ * test generation of basic urls.
+ *
+ * @access public
+ * @return void
+ */
+ function testUrlGenerationBasic() {
+ extract(Router::getNamedExpressions());
+
+ Router::setRequestInfo(array(
+ array(
+ 'pass' => array(), 'action' => 'index', 'plugin' => null, 'controller' => 'subscribe',
+ 'admin' => true, 'url' => array('url' => '')
+ ),
+ array(
+ 'base' => '/magazine', 'here' => '/magazine',
+ 'webroot' => '/magazine/', 'passedArgs' => array('page' => 2), 'namedArgs' => array('page' => 2),
+ )
+ ));
+ $result = Router::url();
+ $this->assertEqual('/magazine', $result);
+
+ Router::reload();
+
+ Router::connect('/', array('controller' => 'pages', 'action' => 'display', 'home'));
+ $out = Router::url(array('controller' => 'pages', 'action' => 'display', 'home'));
+ $this->assertEqual($out, '/');
+
+ Router::connect('/pages/*', array('controller' => 'pages', 'action' => 'display'));
+ $result = Router::url(array('controller' => 'pages', 'action' => 'display', 'about'));
+ $expected = '/pages/about';
+ $this->assertEqual($result, $expected);
+
+ Router::reload();
+ Router::connect('/:plugin/:id/*', array('controller' => 'posts', 'action' => 'view'), array('id' => $ID));
+ Router::parse('/');
+
+ $result = Router::url(array('plugin' => 'cake_plugin', 'controller' => 'posts', 'action' => 'view', 'id' => '1'));
+ $expected = '/cake_plugin/1';
+ $this->assertEqual($result, $expected);
+
+ $result = Router::url(array('plugin' => 'cake_plugin', 'controller' => 'posts', 'action' => 'view', 'id' => '1', '0'));
+ $expected = '/cake_plugin/1/0';
+ $this->assertEqual($result, $expected);
+
+ Router::reload();
+ Router::connect('/:controller/:action/:id', array(), array('id' => $ID));
+ Router::parse('/');
+
+ $result = Router::url(array('controller' => 'posts', 'action' => 'view', 'id' => '1'));
+ $expected = '/posts/view/1';
+ $this->assertEqual($result, $expected);
+
+ Router::reload();
+ Router::connect('/:controller/:id', array('action' => 'view'));
+ Router::parse('/');
+
+ $result = Router::url(array('controller' => 'posts', 'action' => 'view', 'id' => '1'));
+ $expected = '/posts/1';
+ $this->assertEqual($result, $expected);
+
+ $result = Router::url(array('controller' => 'posts', 'action' => 'index', '0'));
+ $expected = '/posts/index/0';
+ $this->assertEqual($result, $expected);
+
+ Router::connect('/view/*', array('controller' => 'posts', 'action' => 'view'));
+ Router::promote();
+ $result = Router::url(array('controller' => 'posts', 'action' => 'view', '1'));
+ $expected = '/view/1';
+ $this->assertEqual($result, $expected);
+
+ Router::reload();
+ Router::setRequestInfo(array(
+ array('pass' => array(), 'action' => 'index', 'plugin' => null, 'controller' => 'real_controller_name', 'url' => array('url' => '')),
+ array(
+ 'base' => '/', 'here' => '/',
+ 'webroot' => '/', 'passedArgs' => array('page' => 2), 'namedArgs' => array('page' => 2),
+ )
+ ));
+ Router::connect('short_controller_name/:action/*', array('controller' => 'real_controller_name'));
+ Router::parse('/');
+
+ $result = Router::url(array('controller' => 'real_controller_name', 'page' => '1'));
+ $expected = '/short_controller_name/index/page:1';
+ $this->assertEqual($result, $expected);
+
+ $result = Router::url(array('action' => 'add'));
+ $expected = '/short_controller_name/add';
+ $this->assertEqual($result, $expected);
+
+ Router::reload();
+ Router::parse('/');
+ Router::setRequestInfo(array(
+ array('pass' => array(), 'action' => 'index', 'plugin' => null, 'controller' => 'users', 'url' => array('url' => 'users')),
+ array(
+ 'base' => '/', 'here' => '/',
+ 'webroot' => '/', 'passedArgs' => array(), 'argSeparator' => ':', 'namedArgs' => array(),
+ )
+ ));
+
+ $result = Router::url(array('action' => 'login'));
+ $expected = '/users/login';
+ $this->assertEqual($result, $expected);
+
+ Router::reload();
+ Router::connect('/page/*', array('plugin' => null, 'controller' => 'pages', 'action' => 'view'));
+ Router::parse('/');
+
+ $result = Router::url(array('plugin' => 'my_plugin', 'controller' => 'pages', 'action' => 'view', 'my-page'));
+ $expected = '/my_plugin/pages/view/my-page';
+ $this->assertEqual($result, $expected);
+
+ Router::reload();
+ Router::connect('/contact/:action', array('plugin' => 'contact', 'controller' => 'contact'));
+ Router::parse('/');
+
+ $result = Router::url(array('plugin' => 'contact', 'controller' => 'contact', 'action' => 'me'));
+
+ $expected = '/contact/me';
+ $this->assertEqual($result, $expected);
+
+ Router::reload();
+ Router::setRequestInfo(array(
+ array(
+ 'pass' => array(), 'action' => 'index', 'plugin' => 'myplugin', 'controller' => 'mycontroller',
+ 'admin' => false, 'url' => array('url' => array())
+ ),
+ array(
+ 'base' => '/', 'here' => '/',
+ 'webroot' => '/', 'passedArgs' => array(), 'namedArgs' => array(),
+ )
+ ));
+
+ $result = Router::url(array('plugin' => null, 'controller' => 'myothercontroller'));
+ $expected = '/myothercontroller';
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * Test generation of routes with query string parameters.
+ *
+ * @return void
+ **/
+ function testUrlGenerationWithQueryStrings() {
+ $result = Router::url(array('controller' => 'posts', 'action'=>'index', '0', '?' => 'var=test&var2=test2'));
+ $expected = '/posts/index/0?var=test&var2=test2';
+ $this->assertEqual($result, $expected);
+
+ $result = Router::url(array('controller' => 'posts', '0', '?' => 'var=test&var2=test2'));
+ $this->assertEqual($result, $expected);
+
+ $result = Router::url(array('controller' => 'posts', '0', '?' => array('var' => 'test', 'var2' => 'test2')));
+ $this->assertEqual($result, $expected);
+
+ $result = Router::url(array('controller' => 'posts', '0', '?' => array('var' => null)));
+ $this->assertEqual($result, '/posts/index/0');
+
+ $result = Router::url(array('controller' => 'posts', '0', '?' => 'var=test&var2=test2', '#' => 'unencoded string %'));
+ $expected = '/posts/index/0?var=test&var2=test2#unencoded+string+%25';
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * test that regex validation of keyed route params is working.
+ *
+ * @return void
+ **/
+ function testUrlGenerationWithRegexQualifiedParams() {
+ Router::connect(
+ ':language/galleries',
+ array('controller' => 'galleries', 'action' => 'index'),
+ array('language' => '[a-z]{3}')
+ );
+
+ Router::connect(
+ '/:language/:admin/:controller/:action/*',
+ array('admin' => 'admin'),
+ array('language' => '[a-z]{3}', 'admin' => 'admin')
+ );
+
+ Router::connect('/:language/:controller/:action/*',
+ array(),
+ array('language' => '[a-z]{3}')
+ );
+
+ $result = Router::url(array('admin' => false, 'language' => 'dan', 'action' => 'index', 'controller' => 'galleries'));
+ $expected = '/dan/galleries';
+ $this->assertEqual($result, $expected);
+
+ $result = Router::url(array('admin' => false, 'language' => 'eng', 'action' => 'index', 'controller' => 'galleries'));
+ $expected = '/eng/galleries';
+ $this->assertEqual($result, $expected);
+
+ Router::reload();
+ Router::connect('/:language/pages',
+ array('controller' => 'pages', 'action' => 'index'),
+ array('language' => '[a-z]{3}')
+ );
+ Router::connect('/:language/:controller/:action/*', array(), array('language' => '[a-z]{3}'));
+
+ $result = Router::url(array('language' => 'eng', 'action' => 'index', 'controller' => 'pages'));
+ $expected = '/eng/pages';
+ $this->assertEqual($result, $expected);
+
+ $result = Router::url(array('language' => 'eng', 'controller' => 'pages'));
+ $this->assertEqual($result, $expected);
+
+ $result = Router::url(array('language' => 'eng', 'controller' => 'pages', 'action' => 'add'));
+ $expected = '/eng/pages/add';
+ $this->assertEqual($result, $expected);
+
+ Router::reload();
+ Router::connect('/forestillinger/:month/:year/*',
+ array('plugin' => 'shows', 'controller' => 'shows', 'action' => 'calendar'),
+ array('month' => '0[1-9]|1[012]', 'year' => '[12][0-9]{3}')
+ );
+ Router::parse('/');
+
+ $result = Router::url(array('plugin' => 'shows', 'controller' => 'shows', 'action' => 'calendar', 'month' => 10, 'year' => 2007, 'min-forestilling'));
+ $expected = '/forestillinger/10/2007/min-forestilling';
+ $this->assertEqual($result, $expected);
+
+ Router::reload();
+ Router::connect('/kalender/:month/:year/*',
+ array('plugin' => 'shows', 'controller' => 'shows', 'action' => 'calendar'),
+ array('month' => '0[1-9]|1[012]', 'year' => '[12][0-9]{3}')
+ );
+ Router::connect('/kalender/*', array('plugin' => 'shows', 'controller' => 'shows', 'action' => 'calendar'));
+ Router::parse('/');
+
+ $result = Router::url(array('plugin' => 'shows', 'controller' => 'shows', 'action' => 'calendar', 'min-forestilling'));
+ $expected = '/kalender/min-forestilling';
+ $this->assertEqual($result, $expected);
+
+ $result = Router::url(array('plugin' => 'shows', 'controller' => 'shows', 'action' => 'calendar', 'year' => 2007, 'month' => 10, 'min-forestilling'));
+ $expected = '/kalender/10/2007/min-forestilling';
+ $this->assertEqual($result, $expected);
+
+ Router::reload();
+ Router::connect('/:controller/:action/*', array(), array(
+ 'controller' => 'source|wiki|commits|tickets|comments|view',
+ 'action' => 'branches|history|branch|logs|view|start|add|edit|modify'
+ ));
+ Router::defaults(false);
+ $result = Router::parse('/foo/bar');
+ $expected = array('pass' => array(), 'named' => array());
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * Test url generation with an admin prefix
+ *
+ * @access public
+ * @return void
+ */
+ function testUrlGenerationWithAdminPrefix() {
+ Configure::write('Routing.admin', 'admin');
+ Router::reload();
+
+ Router::connectNamed(array('event', 'lang'));
+ Router::connect('/', array('controller' => 'pages', 'action' => 'display', 'home'));
+ Router::connect('/pages/contact_us', array('controller' => 'pages', 'action' => 'contact_us'));
+ Router::connect('/pages/*', array('controller' => 'pages', 'action' => 'display'));
+ Router::connect('/reset/*', array('admin' => true, 'controller' => 'users', 'action' => 'reset'));
+ Router::connect('/tests', array('controller' => 'tests', 'action' => 'index'));
+ Router::parseExtensions('rss');
+
+ Router::setRequestInfo(array(
+ array('pass' => array(), 'named' => array(), 'controller' => 'registrations', 'action' => 'admin_index', 'plugin' => '', 'prefix' => 'admin', 'admin' => true, 'url' => array('ext' => 'html', 'url' => 'admin/registrations/index'), 'form' => array()),
+ array('base' => '', 'here' => '/admin/registrations/index', 'webroot' => '/')
+ ));
+
+ $result = Router::url(array('page' => 2));
+ $expected = '/admin/registrations/index/page:2';
+ $this->assertEqual($result, $expected);
+
+ Router::reload();
+ Router::setRequestInfo(array(
+ array(
+ 'pass' => array(), 'action' => 'admin_index', 'plugin' => null, 'controller' => 'subscriptions',
+ 'admin' => true, 'url' => array('url' => 'admin/subscriptions/index/page:2'),
+ ),
+ array(
+ 'base' => '/magazine', 'here' => '/magazine/admin/subscriptions/index/page:2',
+ 'webroot' => '/magazine/', 'passedArgs' => array('page' => 2),
+ )
+ ));
+ Router::parse('/');
+
+ $result = Router::url(array('page' => 3));
+ $expected = '/magazine/admin/subscriptions/index/page:3';
+ $this->assertEqual($result, $expected);
+
+ Router::reload();
+ Router::connect('/admin/subscriptions/:action/*', array('controller' => 'subscribe', 'admin' => true, 'prefix' => 'admin'));
+ Router::parse('/');
+ Router::setRequestInfo(array(
+ array(
+ 'pass' => array(), 'action' => 'admin_index', 'plugin' => null, 'controller' => 'subscribe',
+ 'admin' => true, 'url' => array('url' => 'admin/subscriptions/edit/1')
+ ),
+ array(
+ 'base' => '/magazine', 'here' => '/magazine/admin/subscriptions/edit/1',
+ 'webroot' => '/magazine/', 'passedArgs' => array('page' => 2), 'namedArgs' => array('page' => 2),
+ )
+ ));
+
+ $result = Router::url(array('action' => 'edit', 1));
+ $expected = '/magazine/admin/subscriptions/edit/1';
+ $this->assertEqual($result, $expected);
+
+ $result = Router::url(array('admin' => true, 'controller' => 'users', 'action' => 'login'));
+ $expected = '/magazine/admin/users/login';
+ $this->assertEqual($result, $expected);
+
+
+ Router::reload();
+ Router::setRequestInfo(array(
+ array('pass' => array(), 'admin' => true, 'action' => 'index', 'plugin' => null, 'controller' => 'users', 'url' => array('url' => 'users')),
+ array(
+ 'base' => '/', 'here' => '/',
+ 'webroot' => '/', 'passedArgs' => array(), 'argSeparator' => ':', 'namedArgs' => array(),
+ )
+ ));
+ Router::connect('/page/*', array('controller' => 'pages', 'action' => 'view', 'admin' => true, 'prefix' => 'admin'));
+ Router::parse('/');
+
+ $result = Router::url(array('admin' => true, 'controller' => 'pages', 'action' => 'view', 'my-page'));
+ $expected = '/page/my-page';
+ $this->assertEqual($result, $expected);
+
+ Configure::write('Routing.admin', 'admin');
+ Router::reload();
+
+ Router::setRequestInfo(array(
+ array('plugin' => null, 'controller' => 'pages', 'action' => 'admin_add', 'pass' => array(), 'prefix' => 'admin', 'admin' => true, 'form' => array(), 'url' => array('url' => 'admin/pages/add')),
+ array('plugin' => null, 'controller' => null, 'action' => null, 'base' => '', 'here' => '/admin/pages/add', 'webroot' => '/')
+ ));
+ Router::parse('/');
+
+ $result = Router::url(array('plugin' => null, 'controller' => 'pages', 'action' => 'add', 'id' => false));
+ $expected = '/admin/pages/add';
+ $this->assertEqual($result, $expected);
+
+
+ Router::reload();
+ Router::parse('/');
+ Router::setRequestInfo(array(
+ array('plugin' => null, 'controller' => 'pages', 'action' => 'admin_add', 'pass' => array(), 'prefix' => 'admin', 'admin' => true, 'form' => array(), 'url' => array('url' => 'admin/pages/add')),
+ array('plugin' => null, 'controller' => null, 'action' => null, 'base' => '', 'here' => '/admin/pages/add', 'webroot' => '/')
+ ));
+
+ $result = Router::url(array('plugin' => null, 'controller' => 'pages', 'action' => 'add', 'id' => false));
+ $expected = '/admin/pages/add';
+ $this->assertEqual($result, $expected);
+
+ Router::reload();
+ Router::connect('/admin/:controller/:action/:id', array('admin' => true), array('id' => '[0-9]+'));
+ Router::parse('/');
+ Router::setRequestInfo(array(
+ array ('plugin' => null, 'controller' => 'pages', 'action' => 'admin_edit', 'pass' => array('284'), 'prefix' => 'admin', 'admin' => true, 'form' => array(), 'url' => array('url' => 'admin/pages/edit/284')),
+ array ('plugin' => null, 'controller' => null, 'action' => null, 'base' => '', 'here' => '/admin/pages/edit/284', 'webroot' => '/')
+ ));
+
+ $result = Router::url(array('plugin' => null, 'controller' => 'pages', 'action' => 'edit', 'id' => '284'));
+ $expected = '/admin/pages/edit/284';
+ $this->assertEqual($result, $expected);
+
+
+ Router::reload();
+ Router::parse('/');
+ Router::setRequestInfo(array(
+ array ('plugin' => null, 'controller' => 'pages', 'action' => 'admin_add', 'pass' => array(), 'prefix' => 'admin', 'admin' => true, 'form' => array(), 'url' => array('url' => 'admin/pages/add')),
+ array ('plugin' => null, 'controller' => null, 'action' => null, 'base' => '', 'here' => '/admin/pages/add', 'webroot' => '/')
+ ));
+
+ $result = Router::url(array('plugin' => null, 'controller' => 'pages', 'action' => 'add', 'id' => false));
+ $expected = '/admin/pages/add';
+ $this->assertEqual($result, $expected);
+
+
+ Router::reload();
+ Router::parse('/');
+ Router::setRequestInfo(array(
+ array('plugin' => null, 'controller' => 'pages', 'action' => 'admin_edit', 'pass' => array('284'), 'prefix' => 'admin', 'admin' => true, 'form' => array(), 'url' => array('url' => 'admin/pages/edit/284')),
+ array('plugin' => null, 'controller' => null, 'action' => null, 'base' => '', 'here' => '/admin/pages/edit/284', 'webroot' => '/')
+ ));
+
+ $result = Router::url(array('plugin' => null, 'controller' => 'pages', 'action' => 'edit', 284));
+ $expected = '/admin/pages/edit/284';
+ $this->assertEqual($result, $expected);
+
+
+ Router::reload();
+ Router::connect('/admin/posts/*', array('controller' => 'posts', 'action' => 'index', 'admin' => true));
+ Router::parse('/');
+ Router::setRequestInfo(array(
+ array('pass' => array(), 'action' => 'admin_index', 'plugin' => null, 'controller' => 'posts', 'prefix' => 'admin', 'admin' => true, 'url' => array('url' => 'admin/posts')),
+ array('base' => '', 'here' => '/admin/posts', 'webroot' => '/')
+ ));
+
+ $result = Router::url(array('all'));
+ $expected = '/admin/posts/all';
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testUrlGenerationWithExtensions method
+ *
+ * @access public
+ * @return void
+ */
+ function testUrlGenerationWithExtensions() {
+ Router::parse('/');
+ $result = Router::url(array('plugin' => null, 'controller' => 'articles', 'action' => 'add', 'id' => null, 'ext' => 'json'));
+ $expected = '/articles/add.json';
+ $this->assertEqual($result, $expected);
+
+ $result = Router::url(array('plugin' => null, 'controller' => 'articles', 'action' => 'add', 'ext' => 'json'));
+ $expected = '/articles/add.json';
+ $this->assertEqual($result, $expected);
+
+ $result = Router::url(array('plugin' => null, 'controller' => 'articles', 'action' => 'index', 'id' => null, 'ext' => 'json'));
+ $expected = '/articles.json';
+ $this->assertEqual($result, $expected);
+
+ $result = Router::url(array('plugin' => null, 'controller' => 'articles', 'action' => 'index', 'ext' => 'json'));
+ $expected = '/articles.json';
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testPluginUrlGeneration method
+ *
+ * @access public
+ * @return void
+ */
+ function testUrlGenerationPlugins() {
+ Router::setRequestInfo(array(
+ array(
+ 'controller' => 'controller', 'action' => 'index', 'form' => array(),
+ 'url' => array(), 'plugin' => 'test'
+ ),
+ array(
+ 'base' => '/base', 'here' => '/clients/sage/portal/donations', 'webroot' => '/base/',
+ 'passedArgs' => array(), 'argSeparator' => ':', 'namedArgs' => array()
+ )
+ ));
+
+ $this->assertEqual(Router::url('read/1'), '/base/test/controller/read/1');
+
+ Router::reload();
+ Router::connect('/:lang/:plugin/:controller/*', array('action' => 'index'));
+
+ Router::setRequestInfo(array(
+ array(
+ 'lang' => 'en',
+ 'plugin' => 'shows', 'controller' => 'shows', 'action' => 'index', 'pass' =>
+ array(), 'form' => array(), 'url' =>
+ array('url' => 'en/shows/')),
+ array('plugin' => NULL, 'controller' => NULL, 'action' => NULL, 'base' => '',
+ 'here' => '/en/shows/', 'webroot' => '/')
+ ));
+
+ Router::parse('/en/shows/');
+
+ $result = Router::url(array(
+ 'lang' => 'en',
+ 'controller' => 'shows', 'action' => 'index', 'page' => '1',
+ ));
+ $expected = '/en/shows/shows/page:1';
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * test that you can leave active plugin routes with plugin = null
+ *
+ * @return void
+ */
+ function testCanLeavePlugin() {
+ Router::reload();
+ Router::connect(
+ '/admin/other/:controller/:action/*',
+ array(
+ 'admin' => 1,
+ 'plugin' => 'aliased',
+ 'prefix' => 'admin'
+ )
+ );
+ Router::setRequestInfo(array(
+ array(
+ 'pass' => array(),
+ 'admin' => true,
+ 'prefix' => 'admin',
+ 'plugin' => 'this',
+ 'action' => 'admin_index',
+ 'controller' => 'interesting',
+ 'url' => array('url' => 'admin/this/interesting/index'),
+ ),
+ array(
+ 'base' => '',
+ 'here' => '/admin/this/interesting/index',
+ 'webroot' => '/',
+ 'passedArgs' => array(),
+ )
+ ));
+ $result = Router::url(array('plugin' => null, 'controller' => 'posts', 'action' => 'index'));
+ $this->assertEqual($result, '/admin/posts');
+
+ $result = Router::url(array('controller' => 'posts', 'action' => 'index'));
+ $this->assertEqual($result, '/admin/this/posts');
+
+ $result = Router::url(array('plugin' => 'aliased', 'controller' => 'posts', 'action' => 'index'));
+ $this->assertEqual($result, '/admin/other/posts/index');
+ }
+
+/**
+ * testUrlParsing method
+ *
+ * @access public
+ * @return void
+ */
+ function testUrlParsing() {
+ extract(Router::getNamedExpressions());
+
+ Router::connect('/posts/:value/:somevalue/:othervalue/*', array('controller' => 'posts', 'action' => 'view'), array('value','somevalue', 'othervalue'));
+ $result = Router::parse('/posts/2007/08/01/title-of-post-here');
+ $expected = array('value' => '2007', 'somevalue' => '08', 'othervalue' => '01', 'controller' => 'posts', 'action' => 'view', 'plugin' =>'', 'pass' => array('0' => 'title-of-post-here'), 'named' => array());
+ $this->assertEqual($result, $expected);
+
+ $this->router->routes = array();
+ Router::connect('/posts/:year/:month/:day/*', array('controller' => 'posts', 'action' => 'view'), array('year' => $Year, 'month' => $Month, 'day' => $Day));
+ $result = Router::parse('/posts/2007/08/01/title-of-post-here');
+ $expected = array('year' => '2007', 'month' => '08', 'day' => '01', 'controller' => 'posts', 'action' => 'view', 'plugin' =>'', 'pass' => array('0' => 'title-of-post-here'), 'named' => array());
+ $this->assertEqual($result, $expected);
+
+ $this->router->routes = array();
+ Router::connect('/posts/:day/:year/:month/*', array('controller' => 'posts', 'action' => 'view'), array('year' => $Year, 'month' => $Month, 'day' => $Day));
+ $result = Router::parse('/posts/01/2007/08/title-of-post-here');
+ $expected = array('day' => '01', 'year' => '2007', 'month' => '08', 'controller' => 'posts', 'action' => 'view', 'plugin' =>'', 'pass' => array('0' => 'title-of-post-here'), 'named' => array());
+ $this->assertEqual($result, $expected);
+
+ $this->router->routes = array();
+ Router::connect('/posts/:month/:day/:year/*', array('controller' => 'posts', 'action' => 'view'), array('year' => $Year, 'month' => $Month, 'day' => $Day));
+ $result = Router::parse('/posts/08/01/2007/title-of-post-here');
+ $expected = array('month' => '08', 'day' => '01', 'year' => '2007', 'controller' => 'posts', 'action' => 'view', 'plugin' =>'', 'pass' => array('0' => 'title-of-post-here'), 'named' => array());
+ $this->assertEqual($result, $expected);
+
+ $this->router->routes = array();
+ Router::connect('/posts/:year/:month/:day/*', array('controller' => 'posts', 'action' => 'view'));
+ $result = Router::parse('/posts/2007/08/01/title-of-post-here');
+ $expected = array('year' => '2007', 'month' => '08', 'day' => '01', 'controller' => 'posts', 'action' => 'view', 'plugin' =>'', 'pass' => array('0' => 'title-of-post-here'), 'named' => array());
+ $this->assertEqual($result, $expected);
+
+ Router::reload();
+ $result = Router::parse('/pages/display/home');
+ $expected = array('plugin' => null, 'pass' => array('home'), 'controller' => 'pages', 'action' => 'display', 'named' => array());
+ $this->assertEqual($result, $expected);
+
+ $result = Router::parse('pages/display/home/');
+ $this->assertEqual($result, $expected);
+
+ $result = Router::parse('pages/display/home');
+ $this->assertEqual($result, $expected);
+
+ Router::reload();
+ Router::connect('/page/*', array('controller' => 'test'));
+ $result = Router::parse('/page/my-page');
+ $expected = array('pass' => array('my-page'), 'plugin' => null, 'controller' => 'test', 'action' => 'index');
+
+ Router::reload();
+ Router::connect('/:language/contact', array('language' => 'eng', 'plugin' => 'contact', 'controller' => 'contact', 'action' => 'index'), array('language' => '[a-z]{3}'));
+ $result = Router::parse('/eng/contact');
+ $expected = array('pass' => array(), 'named' => array(), 'language' => 'eng', 'plugin' => 'contact', 'controller' => 'contact', 'action' => 'index');
+ $this->assertEqual($result, $expected);
+
+ Router::reload();
+ Router::connect('/forestillinger/:month/:year/*',
+ array('plugin' => 'shows', 'controller' => 'shows', 'action' => 'calendar'),
+ array('month' => '0[1-9]|1[012]', 'year' => '[12][0-9]{3}')
+ );
+
+ $result = Router::parse('/forestillinger/10/2007/min-forestilling');
+ $expected = array('pass' => array('min-forestilling'), 'plugin' => 'shows', 'controller' => 'shows', 'action' => 'calendar', 'year' => 2007, 'month' => 10, 'named' => array());
+ $this->assertEqual($result, $expected);
+
+ Router::reload();
+ Router::connect('/:controller/:action/*');
+ Router::connect('/', array('plugin' => 'pages', 'controller' => 'pages', 'action' => 'display'));
+ $result = Router::parse('/');
+ $expected = array('pass' => array(), 'named' => array(), 'controller' => 'pages', 'action' => 'display', 'plugin' => 'pages');
+ $this->assertEqual($result, $expected);
+
+ $result = Router::parse('/posts/edit/0');
+ $expected = array('pass' => array(0), 'named' => array(), 'controller' => 'posts', 'action' => 'edit', 'plugin' => null);
+ $this->assertEqual($result, $expected);
+
+ Router::reload();
+ Router::connect('/posts/:id::url_title', array('controller' => 'posts', 'action' => 'view'), array('pass' => array('id', 'url_title'), 'id' => '[\d]+'));
+ $result = Router::parse('/posts/5:sample-post-title');
+ $expected = array('pass' => array('5', 'sample-post-title'), 'named' => array(), 'id' => 5, 'url_title' => 'sample-post-title', 'plugin' => null, 'controller' => 'posts', 'action' => 'view');
+ $this->assertEqual($result, $expected);
+
+ Router::reload();
+ Router::connect('/posts/:id::url_title/*', array('controller' => 'posts', 'action' => 'view'), array('pass' => array('id', 'url_title'), 'id' => '[\d]+'));
+ $result = Router::parse('/posts/5:sample-post-title/other/params/4');
+ $expected = array('pass' => array('5', 'sample-post-title', 'other', 'params', '4'), 'named' => array(), 'id' => 5, 'url_title' => 'sample-post-title', 'plugin' => null, 'controller' => 'posts', 'action' => 'view');
+ $this->assertEqual($result, $expected);
+
+ Router::reload();
+ Router::connect('/posts/:url_title-(uuid::id)', array('controller' => 'posts', 'action' => 'view'), array('pass' => array('id', 'url_title'), 'id' => $UUID));
+ $result = Router::parse('/posts/sample-post-title-(uuid:47fc97a9-019c-41d1-a058-1fa3cbdd56cb)');
+ $expected = array('pass' => array('47fc97a9-019c-41d1-a058-1fa3cbdd56cb', 'sample-post-title'), 'named' => array(), 'id' => '47fc97a9-019c-41d1-a058-1fa3cbdd56cb', 'url_title' => 'sample-post-title', 'plugin' => null, 'controller' => 'posts', 'action' => 'view');
+ $this->assertEqual($result, $expected);
+
+ Router::reload();
+ Router::connect('/posts/view/*', array('controller' => 'posts', 'action' => 'view'), array('named' => false));
+ $result = Router::parse('/posts/view/foo:bar/routing:fun');
+ $expected = array('pass' => array('foo:bar', 'routing:fun'), 'named' => array(), 'plugin' => null, 'controller' => 'posts', 'action' => 'view');
+ $this->assertEqual($result, $expected);
+
+ Router::reload();
+ Router::connect('/posts/view/*', array('controller' => 'posts', 'action' => 'view'), array('named' => array('foo', 'answer')));
+ $result = Router::parse('/posts/view/foo:bar/routing:fun/answer:42');
+ $expected = array('pass' => array('routing:fun'), 'named' => array('foo' => 'bar', 'answer' => '42'), 'plugin' => null, 'controller' => 'posts', 'action' => 'view');
+ $this->assertEqual($result, $expected);
+
+ Router::reload();
+ Router::connect('/posts/view/*', array('controller' => 'posts', 'action' => 'view'), array('named' => array('foo', 'answer'), 'greedy' => true));
+ $result = Router::parse('/posts/view/foo:bar/routing:fun/answer:42');
+ $expected = array('pass' => array(), 'named' => array('foo' => 'bar', 'routing' => 'fun', 'answer' => '42'), 'plugin' => null, 'controller' => 'posts', 'action' => 'view');
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * test that the persist key works.
+ *
+ * @return void
+ */
+ function testPersistentParameters() {
+ Router::reload();
+ Router::connect(
+ '/:lang/:color/posts/view/*',
+ array('controller' => 'posts', 'action' => 'view'),
+ array('persist' => array('lang', 'color')
+ ));
+ Router::connect(
+ '/:lang/:color/posts/index',
+ array('controller' => 'posts', 'action' => 'index'),
+ array('persist' => array('lang')
+ ));
+ Router::connect('/:lang/:color/posts/edit/*', array('controller' => 'posts', 'action' => 'edit'));
+ Router::connect('/about', array('controller' => 'pages', 'action' => 'view', 'about'));
+ Router::parse('/en/red/posts/view/5');
+
+ Router::setRequestInfo(array(
+ array('controller' => 'posts', 'action' => 'view', 'lang' => 'en', 'color' => 'red', 'form' => array(), 'url' => array(), 'plugin' => null),
+ array('base' => '/', 'here' => '/en/red/posts/view/5', 'webroot' => '/', 'passedArgs' => array(), 'argSeparator' => ':', 'namedArgs' => array())
+ ));
+ $expected = '/en/red/posts/view/6';
+ $result = Router::url(array('controller' => 'posts', 'action' => 'view', 6));
+ $this->assertEqual($result, $expected);
+
+ $expected = '/en/blue/posts/index';
+ $result = Router::url(array('controller' => 'posts', 'action' => 'index', 'color' => 'blue'));
+ $this->assertEqual($result, $expected);
+
+ $expected = '/posts/edit/6';
+ $result = Router::url(array('controller' => 'posts', 'action' => 'edit', 6, 'color' => null, 'lang' => null));
+ $this->assertEqual($result, $expected);
+
+ $expected = '/posts';
+ $result = Router::url(array('controller' => 'posts', 'action' => 'index'));
+ $this->assertEqual($result, $expected);
+
+ $expected = '/posts/edit/7';
+ $result = Router::url(array('controller' => 'posts', 'action' => 'edit', 7));
+ $this->assertEqual($result, $expected);
+
+ $expected = '/about';
+ $result = Router::url(array('controller' => 'pages', 'action' => 'view', 'about'));
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testUuidRoutes method
+ *
+ * @access public
+ * @return void
+ */
+ function testUuidRoutes() {
+ Router::connect(
+ '/subjects/add/:category_id',
+ array('controller' => 'subjects', 'action' => 'add'),
+ array('category_id' => '\w{8}-\w{4}-\w{4}-\w{4}-\w{12}')
+ );
+ $result = Router::parse('/subjects/add/4795d601-19c8-49a6-930e-06a8b01d17b7');
+ $expected = array('pass' => array(), 'named' => array(), 'category_id' => '4795d601-19c8-49a6-930e-06a8b01d17b7', 'plugin' => null, 'controller' => 'subjects', 'action' => 'add');
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testRouteSymmetry method
+ *
+ * @access public
+ * @return void
+ */
+ function testRouteSymmetry() {
+ Router::connect(
+ "/:extra/page/:slug/*",
+ array('controller' => 'pages', 'action' => 'view', 'extra' => null),
+ array("extra" => '[a-z1-9_]*', "slug" => '[a-z1-9_]+', "action" => 'view')
+ );
+
+ $result = Router::parse('/some_extra/page/this_is_the_slug');
+ $expected = array('pass' => array(), 'named' => array(), 'plugin' => null, 'controller' => 'pages', 'action' => 'view', 'slug' => 'this_is_the_slug', 'extra' => 'some_extra');
+ $this->assertEqual($result, $expected);
+
+ $result = Router::parse('/page/this_is_the_slug');
+ $expected = array('pass' => array(), 'named' => array(), 'plugin' => null, 'controller' => 'pages', 'action' => 'view', 'slug' => 'this_is_the_slug', 'extra' => null);
+ $this->assertEqual($result, $expected);
+
+ Router::reload();
+ Router::connect(
+ "/:extra/page/:slug/*",
+ array('controller' => 'pages', 'action' => 'view', 'extra' => null),
+ array("extra" => '[a-z1-9_]*', "slug" => '[a-z1-9_]+')
+ );
+ Router::parse('/');
+
+ $result = Router::url(array('admin' => null, 'plugin' => null, 'controller' => 'pages', 'action' => 'view', 'slug' => 'this_is_the_slug', 'extra' => null));
+ $expected = '/page/this_is_the_slug';
+ $this->assertEqual($result, $expected);
+
+ $result = Router::url(array('admin' => null, 'plugin' => null, 'controller' => 'pages', 'action' => 'view', 'slug' => 'this_is_the_slug', 'extra' => 'some_extra'));
+ $expected = '/some_extra/page/this_is_the_slug';
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * Test that Routing.prefixes and Routing.admin are used when a Router instance is created
+ * or reset
+ *
+ * @return void
+ */
+ function testRoutingPrefixesSetting() {
+ $restore = Configure::read('Routing');
+
+ Configure::write('Routing.admin', 'admin');
+ Configure::write('Routing.prefixes', array('member', 'super_user'));
+ Router::reload();
+ $result = Router::prefixes();
+ $expected = array('admin', 'member', 'super_user');
+ $this->assertEqual($result, $expected);
+
+ Configure::write('Routing.prefixes', 'member');
+ Router::reload();
+ $result = Router::prefixes();
+ $expected = array('admin', 'member');
+ $this->assertEqual($result, $expected);
+
+ Configure::write('Routing', $restore);
+ }
+
+/**
+ * test compatibility with old Routing.admin config setting.
+ *
+ * @access public
+ * @return void
+ * @todo Once Routing.admin is removed update these tests.
+ */
+ function testAdminRoutingCompatibility() {
+ Configure::write('Routing.admin', 'admin');
+
+ Router::reload();
+ Router::connect('/admin', array('admin' => true, 'controller' => 'users'));
+ $result = Router::parse('/admin');
+
+ $expected = array('pass' => array(), 'named' => array(), 'plugin' => '', 'controller' => 'users', 'action' => 'index', 'admin' => true, 'prefix' => 'admin');
+ $this->assertEqual($result, $expected);
+
+ $result = Router::url(array('admin' => true, 'controller' => 'posts', 'action' => 'index', '0', '?' => 'var=test&var2=test2'));
+ $expected = '/admin/posts/index/0?var=test&var2=test2';
+ $this->assertEqual($result, $expected);
+
+ Router::reload();
+ Router::parse('/');
+ $result = Router::url(array('admin' => false, 'controller' => 'posts', 'action' => 'index', '0', '?' => 'var=test&var2=test2'));
+ $expected = '/posts/index/0?var=test&var2=test2';
+ $this->assertEqual($result, $expected);
+
+ Router::reload();
+ Router::setRequestInfo(array(
+ array('admin' => true, 'controller' => 'controller', 'action' => 'index', 'form' => array(), 'url' => array(), 'plugin' => null),
+ array('base' => '/', 'here' => '/', 'webroot' => '/base/', 'passedArgs' => array(), 'argSeparator' => ':', 'namedArgs' => array())
+ ));
+
+ Router::parse('/');
+ $result = Router::url(array('admin' => false, 'controller' => 'posts', 'action' => 'index', '0', '?' => 'var=test&var2=test2'));
+ $expected = '/posts/index/0?var=test&var2=test2';
+ $this->assertEqual($result, $expected);
+
+ $result = Router::url(array('controller' => 'posts', 'action' => 'index', '0', '?' => 'var=test&var2=test2'));
+ $expected = '/admin/posts/index/0?var=test&var2=test2';
+ $this->assertEqual($result, $expected);
+
+ Router::reload();
+ $result = Router::parse('admin/users/view/');
+ $expected = array('pass' => array(), 'named' => array(), 'controller' => 'users', 'action' => 'view', 'plugin' => null, 'prefix' => 'admin', 'admin' => true);
+ $this->assertEqual($result, $expected);
+
+ Configure::write('Routing.admin', 'beheer');
+
+ Router::reload();
+ Router::setRequestInfo(array(
+ array('beheer' => true, 'controller' => 'posts', 'action' => 'index', 'form' => array(), 'url' => array(), 'plugin' => null),
+ array('base' => '/', 'here' => '/beheer/posts/index', 'webroot' => '/', 'passedArgs' => array(), 'argSeparator' => ':', 'namedArgs' => array())
+ ));
+
+ $result = Router::parse('beheer/users/view/');
+ $expected = array('pass' => array(), 'named' => array(), 'controller' => 'users', 'action' => 'view', 'plugin' => null, 'prefix' => 'beheer', 'beheer' => true);
+ $this->assertEqual($result, $expected);
+
+
+ $result = Router::url(array('controller' => 'posts', 'action' => 'index', '0', '?' => 'var=test&var2=test2'));
+ $expected = '/beheer/posts/index/0?var=test&var2=test2';
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * Test prefix routing and plugin combinations
+ *
+ * @return void
+ */
+ function testPrefixRoutingAndPlugins() {
+ Configure::write('Routing.prefixes', array('admin'));
+ $paths = App::path('plugins');
+ App::build(array(
+ 'plugins' => array(
+ TEST_CAKE_CORE_INCLUDE_PATH . 'tests' . DS . 'test_app' . DS . 'plugins' . DS
+ )
+ ), true);
+ App::objects('plugin', null, false);
+
+ Router::reload();
+ Router::setRequestInfo(array(
+ array('admin' => true, 'controller' => 'controller', 'action' => 'action',
+ 'form' => array(), 'url' => array(), 'plugin' => null, 'prefix' => 'admin'),
+ array('base' => '/', 'here' => '/', 'webroot' => '/base/', 'passedArgs' => array(),
+ 'argSeparator' => ':', 'namedArgs' => array())
+ ));
+ Router::parse('/');
+
+ $result = Router::url(array('plugin' => 'test_plugin', 'controller' => 'test_plugin', 'action' => 'index'));
+ $expected = '/admin/test_plugin';
+ $this->assertEqual($result, $expected);
+
+ Router::reload();
+ Router::parse('/');
+ Router::setRequestInfo(array(
+ array(
+ 'plugin' => 'test_plugin', 'controller' => 'show_tickets', 'action' => 'admin_edit',
+ 'pass' => array('6'), 'prefix' => 'admin', 'admin' => true, 'form' => array(),
+ 'url' => array('url' => 'admin/shows/show_tickets/edit/6')
+ ),
+ array(
+ 'plugin' => null, 'controller' => null, 'action' => null, 'base' => '',
+ 'here' => '/admin/shows/show_tickets/edit/6', 'webroot' => '/'
+ )
+ ));
+
+ $result = Router::url(array(
+ 'plugin' => 'test_plugin', 'controller' => 'show_tickets', 'action' => 'edit', 6,
+ 'admin' => true, 'prefix' => 'admin'
+ ));
+ $expected = '/admin/test_plugin/show_tickets/edit/6';
+ $this->assertEqual($result, $expected);
+
+ $result = Router::url(array(
+ 'plugin' => 'test_plugin', 'controller' => 'show_tickets', 'action' => 'index', 'admin' => true
+ ));
+ $expected = '/admin/test_plugin/show_tickets';
+ $this->assertEqual($result, $expected);
+
+ App::build(array('plugins' => $paths));
+ }
+
+/**
+ * testExtensionParsingSetting method
+ *
+ * @access public
+ * @return void
+ */
+ function testExtensionParsingSetting() {
+ $router =& Router::getInstance();
+ $this->assertFalse($this->router->__parseExtensions);
+
+ $router->parseExtensions();
+ $this->assertTrue($this->router->__parseExtensions);
+ }
+
+/**
+ * testExtensionParsing method
+ *
+ * @access public
+ * @return void
+ */
+ function testExtensionParsing() {
+ Router::parseExtensions();
+
+ $result = Router::parse('/posts.rss');
+ $expected = array('plugin' => null, 'controller' => 'posts', 'action' => 'index', 'url' => array('ext' => 'rss'), 'pass'=> array(), 'named' => array());
+ $this->assertEqual($result, $expected);
+
+ $result = Router::parse('/posts/view/1.rss');
+ $expected = array('plugin' => null, 'controller' => 'posts', 'action' => 'view', 'pass' => array('1'), 'named' => array(), 'url' => array('ext' => 'rss'), 'named' => array());
+ $this->assertEqual($result, $expected);
+
+ $result = Router::parse('/posts/view/1.rss?query=test');
+ $this->assertEqual($result, $expected);
+
+ $result = Router::parse('/posts/view/1.atom');
+ $expected['url'] = array('ext' => 'atom');
+ $this->assertEqual($result, $expected);
+
+ Router::reload();
+ Router::parseExtensions('rss', 'xml');
+
+ $result = Router::parse('/posts.xml');
+ $expected = array('plugin' => null, 'controller' => 'posts', 'action' => 'index', 'url' => array('ext' => 'xml'), 'pass'=> array(), 'named' => array());
+ $this->assertEqual($result, $expected);
+
+ $result = Router::parse('/posts.atom?hello=goodbye');
+ $expected = array('plugin' => null, 'controller' => 'posts.atom', 'action' => 'index', 'pass' => array(), 'named' => array(), 'url' => array('ext' => 'html'));
+ $this->assertEqual($result, $expected);
+
+ Router::reload();
+ Router::parseExtensions();
+ $result = $this->router->__parseExtension('/posts.atom');
+ $expected = array('ext' => 'atom', 'url' => '/posts');
+ $this->assertEqual($result, $expected);
+
+ Router::reload();
+ Router::connect('/controller/action', array('controller' => 'controller', 'action' => 'action', 'url' => array('ext' => 'rss')));
+ $result = Router::parse('/controller/action');
+ $expected = array('controller' => 'controller', 'action' => 'action', 'plugin' => null, 'url' => array('ext' => 'rss'), 'named' => array(), 'pass' => array());
+ $this->assertEqual($result, $expected);
+
+ Router::reload();
+ Router::parseExtensions('rss');
+ Router::connect('/controller/action', array('controller' => 'controller', 'action' => 'action', 'url' => array('ext' => 'rss')));
+ $result = Router::parse('/controller/action');
+ $expected = array('controller' => 'controller', 'action' => 'action', 'plugin' => null, 'url' => array('ext' => 'rss'), 'named' => array(), 'pass' => array());
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testQuerystringGeneration method
+ *
+ * @access public
+ * @return void
+ */
+ function testQuerystringGeneration() {
+ $result = Router::url(array('controller' => 'posts', 'action'=>'index', '0', '?' => 'var=test&var2=test2'));
+ $expected = '/posts/index/0?var=test&var2=test2';
+ $this->assertEqual($result, $expected);
+
+ $result = Router::url(array('controller' => 'posts', 'action'=>'index', '0', '?' => array('var' => 'test', 'var2' => 'test2')));
+ $this->assertEqual($result, $expected);
+
+ $expected .= '&more=test+data';
+ $result = Router::url(array('controller' => 'posts', 'action'=>'index', '0', '?' => array('var' => 'test', 'var2' => 'test2', 'more' => 'test data')));
+ $this->assertEqual($result, $expected);
+
+// Test bug #4614
+ $restore = ini_get('arg_separator.output');
+ ini_set('arg_separator.output', '&');
+ $result = Router::url(array('controller' => 'posts', 'action'=>'index', '0', '?' => array('var' => 'test', 'var2' => 'test2', 'more' => 'test data')));
+ $this->assertEqual($result, $expected);
+ ini_set('arg_separator.output', $restore);
+
+ $result = Router::url(array('controller' => 'posts', 'action'=>'index', '0', '?' => array('var' => 'test', 'var2' => 'test2')), array('escape' => true));
+ $expected = '/posts/index/0?var=test&var2=test2';
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testConnectNamed method
+ *
+ * @access public
+ * @return void
+ */
+ function testConnectNamed() {
+ $named = Router::connectNamed(false, array('default' => true));
+ $this->assertFalse($named['greedy']);
+ $this->assertEqual(array_keys($named['rules']), $named['default']);
+
+ Router::reload();
+ Router::connect('/foo/*', array('controller' => 'bar', 'action' => 'fubar'));
+ Router::connectNamed(array(), array('argSeparator' => '='));
+ $result = Router::parse('/foo/param1=value1/param2=value2');
+ $expected = array('pass' => array(), 'named' => array('param1' => 'value1', 'param2' => 'value2'), 'controller' => 'bar', 'action' => 'fubar', 'plugin' => null);
+ $this->assertEqual($result, $expected);
+
+ Router::reload();
+ Router::connect('/controller/action/*', array('controller' => 'controller', 'action' => 'action'), array('named' => array('param1' => 'value[\d]')));
+ Router::connectNamed(array(), array('greedy' => false, 'argSeparator' => '='));
+ $result = Router::parse('/controller/action/param1=value1/param2=value2');
+ $expected = array('pass' => array('param2=value2'), 'named' => array('param1' => 'value1'), 'controller' => 'controller', 'action' => 'action', 'plugin' => null);
+ $this->assertEqual($result, $expected);
+
+ Router::reload();
+ Router::connect('/:controller/:action/*');
+ Router::connectNamed(array('page'), array('default' => false, 'greedy' => false));
+ $result = Router::parse('/categories/index?limit=5');
+ $this->assertTrue(empty($result['named']));
+ }
+
+/**
+ * testNamedArgsUrlGeneration method
+ *
+ * @access public
+ * @return void
+ */
+ function testNamedArgsUrlGeneration() {
+ $result = Router::url(array('controller' => 'posts', 'action' => 'index', 'published' => 1, 'deleted' => 1));
+ $expected = '/posts/index/published:1/deleted:1';
+ $this->assertEqual($result, $expected);
+
+ $result = Router::url(array('controller' => 'posts', 'action' => 'index', 'published' => 0, 'deleted' => 0));
+ $expected = '/posts/index/published:0/deleted:0';
+ $this->assertEqual($result, $expected);
+
+ Router::reload();
+ extract(Router::getNamedExpressions());
+ Router::connectNamed(array('file'=> '[\w\.\-]+\.(html|png)'));
+ Router::connect('/', array('controller' => 'graphs', 'action' => 'index'));
+ Router::connect('/:id/*', array('controller' => 'graphs', 'action' => 'view'), array('id' => $ID));
+
+ $result = Router::url(array('controller' => 'graphs', 'action' => 'view', 'id' => 12, 'file' => 'asdf.png'));
+ $expected = '/12/file:asdf.png';
+ $this->assertEqual($result, $expected);
+
+ $result = Router::url(array('controller' => 'graphs', 'action' => 'view', 12, 'file' => 'asdf.foo'));
+ $expected = '/graphs/view/12/file:asdf.foo';
+ $this->assertEqual($result, $expected);
+
+ Configure::write('Routing.admin', 'admin');
+
+ Router::reload();
+ Router::setRequestInfo(array(
+ array('admin' => true, 'controller' => 'controller', 'action' => 'index', 'form' => array(), 'url' => array(), 'plugin' => null),
+ array('base' => '/', 'here' => '/', 'webroot' => '/base/', 'passedArgs' => array(), 'argSeparator' => ':', 'namedArgs' => array())
+ ));
+ Router::parse('/');
+
+ $result = Router::url(array('page' => 1, 0 => null, 'sort' => 'controller', 'direction' => 'asc', 'order' => null));
+ $expected = "/admin/controller/index/page:1/sort:controller/direction:asc";
+ $this->assertEqual($result, $expected);
+
+ Router::reload();
+ Router::setRequestInfo(array(
+ array('admin' => true, 'controller' => 'controller', 'action' => 'index', 'form' => array(), 'url' => array(), 'plugin' => null),
+ array('base' => '/', 'here' => '/', 'webroot' => '/base/', 'passedArgs' => array('type'=> 'whatever'), 'argSeparator' => ':', 'namedArgs' => array('type'=> 'whatever'))
+ ));
+
+ $result = Router::parse('/admin/controller/index/type:whatever');
+ $result = Router::url(array('type'=> 'new'));
+ $expected = "/admin/controller/index/type:new";
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testNamedArgsUrlParsing method
+ *
+ * @access public
+ * @return void
+ */
+ function testNamedArgsUrlParsing() {
+ $Router =& Router::getInstance();
+ Router::reload();
+ $result = Router::parse('/controller/action/param1:value1:1/param2:value2:3/param:value');
+ $expected = array('pass' => array(), 'named' => array('param1' => 'value1:1', 'param2' => 'value2:3', 'param' => 'value'), 'controller' => 'controller', 'action' => 'action', 'plugin' => null);
+ $this->assertEqual($result, $expected);
+
+ Router::reload();
+ $result = Router::connectNamed(false);
+ $this->assertEqual(array_keys($result['rules']), array());
+ $this->assertFalse($result['greedy']);
+ $result = Router::parse('/controller/action/param1:value1:1/param2:value2:3/param:value');
+ $expected = array('pass' => array('param1:value1:1', 'param2:value2:3', 'param:value'), 'named' => array(), 'controller' => 'controller', 'action' => 'action', 'plugin' => null);
+ $this->assertEqual($result, $expected);
+
+ Router::reload();
+ $result = Router::connectNamed(true);
+ $this->assertEqual(array_keys($result['rules']), $Router->named['default']);
+ $this->assertTrue($result['greedy']);
+ Router::reload();
+ Router::connectNamed(array('param1' => 'not-matching'));
+ $result = Router::parse('/controller/action/param1:value1:1/param2:value2:3/param:value');
+ $expected = array('pass' => array('param1:value1:1'), 'named' => array('param2' => 'value2:3', 'param' => 'value'), 'controller' => 'controller', 'action' => 'action', 'plugin' => null);
+ $this->assertEqual($result, $expected);
+
+ Router::reload();
+ Router::connect('/foo/:action/*', array('controller' => 'bar'), array('named' => array('param1' => array('action' => 'index')), 'greedy' => true));
+ $result = Router::parse('/foo/index/param1:value1:1/param2:value2:3/param:value');
+ $expected = array('pass' => array(), 'named' => array('param1' => 'value1:1', 'param2' => 'value2:3', 'param' => 'value'), 'controller' => 'bar', 'action' => 'index', 'plugin' => null);
+ $this->assertEqual($result, $expected);
+
+ $result = Router::parse('/foo/view/param1:value1:1/param2:value2:3/param:value');
+ $expected = array('pass' => array('param1:value1:1'), 'named' => array('param2' => 'value2:3', 'param' => 'value'), 'controller' => 'bar', 'action' => 'view', 'plugin' => null);
+ $this->assertEqual($result, $expected);
+
+ Router::reload();
+ Router::connectNamed(array('param1' => '[\d]', 'param2' => '[a-z]', 'param3' => '[\d]'));
+ $result = Router::parse('/controller/action/param1:1/param2:2/param3:3');
+ $expected = array('pass' => array('param2:2'), 'named' => array('param1' => '1', 'param3' => '3'), 'controller' => 'controller', 'action' => 'action', 'plugin' => null);
+ $this->assertEqual($result, $expected);
+
+ Router::reload();
+ Router::connectNamed(array('param1' => '[\d]', 'param2' => true, 'param3' => '[\d]'));
+ $result = Router::parse('/controller/action/param1:1/param2:2/param3:3');
+ $expected = array('pass' => array(), 'named' => array('param1' => '1', 'param2' => '2', 'param3' => '3'), 'controller' => 'controller', 'action' => 'action', 'plugin' => null);
+ $this->assertEqual($result, $expected);
+
+ Router::reload();
+ Router::connectNamed(array('param1' => 'value[\d]+:[\d]+'), array('greedy' => false));
+ $result = Router::parse('/controller/action/param1:value1:1/param2:value2:3/param3:value');
+ $expected = array('pass' => array('param2:value2:3', 'param3:value'), 'named' => array('param1' => 'value1:1'), 'controller' => 'controller', 'action' => 'action', 'plugin' => null);
+ $this->assertEqual($result, $expected);
+
+ Router::reload();
+ Router::connect('/foo/*', array('controller' => 'bar', 'action' => 'fubar'), array('named' => array('param1' => 'value[\d]:[\d]')));
+ Router::connectNamed(array(), array('greedy' => false));
+ $result = Router::parse('/foo/param1:value1:1/param2:value2:3/param3:value');
+ $expected = array('pass' => array('param2:value2:3', 'param3:value'), 'named' => array('param1' => 'value1:1'), 'controller' => 'bar', 'action' => 'fubar', 'plugin' => null);
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * test url generation with legacy (1.2) style prefix routes.
+ *
+ * @access public
+ * @return void
+ * @todo Remove tests related to legacy style routes.
+ * @see testUrlGenerationWithAutoPrefixes
+ */
+ function testUrlGenerationWithLegacyPrefixes() {
+ Router::reload();
+ Router::connect('/protected/:controller/:action/*', array(
+ 'prefix' => 'protected',
+ 'protected' => true
+ ));
+ Router::parse('/');
+
+ Router::setRequestInfo(array(
+ array('plugin' => null, 'controller' => 'images', 'action' => 'index', 'pass' => array(), 'prefix' => null, 'admin' => false, 'form' => array(), 'url' => array('url' => 'images/index')),
+ array('plugin' => null, 'controller' => null, 'action' => null, 'base' => '', 'here' => '/images/index', 'webroot' => '/')
+ ));
+
+ $result = Router::url(array('protected' => true));
+ $expected = '/protected/images/index';
+ $this->assertEqual($result, $expected);
+
+ $result = Router::url(array('controller' => 'images', 'action' => 'add'));
+ $expected = '/images/add';
+ $this->assertEqual($result, $expected);
+
+ $result = Router::url(array('controller' => 'images', 'action' => 'add', 'protected' => true));
+ $expected = '/protected/images/add';
+ $this->assertEqual($result, $expected);
+
+ $result = Router::url(array('action' => 'edit', 1));
+ $expected = '/images/edit/1';
+ $this->assertEqual($result, $expected);
+
+ $result = Router::url(array('action' => 'edit', 1, 'protected' => true));
+ $expected = '/protected/images/edit/1';
+ $this->assertEqual($result, $expected);
+
+ $result = Router::url(array('action' => 'protected_edit', 1, 'protected' => true));
+ $expected = '/protected/images/edit/1';
+ $this->assertEqual($result, $expected);
+
+ $result = Router::url(array('action' => 'edit', 1, 'protected' => true));
+ $expected = '/protected/images/edit/1';
+ $this->assertEqual($result, $expected);
+
+ $result = Router::url(array('controller' => 'others', 'action' => 'edit', 1));
+ $expected = '/others/edit/1';
+ $this->assertEqual($result, $expected);
+
+ $result = Router::url(array('controller' => 'others', 'action' => 'edit', 1, 'protected' => true));
+ $expected = '/protected/others/edit/1';
+ $this->assertEqual($result, $expected);
+
+ $result = Router::url(array('controller' => 'others', 'action' => 'edit', 1, 'protected' => true, 'page' => 1));
+ $expected = '/protected/others/edit/1/page:1';
+ $this->assertEqual($result, $expected);
+
+ Router::connectNamed(array('random'));
+ $result = Router::url(array('controller' => 'others', 'action' => 'edit', 1, 'protected' => true, 'random' => 'my-value'));
+ $expected = '/protected/others/edit/1/random:my-value';
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * test newer style automatically generated prefix routes.
+ *
+ * @return void
+ */
+ function testUrlGenerationWithAutoPrefixes() {
+ Configure::write('Routing.prefixes', array('protected'));
+ Router::reload();
+ Router::parse('/');
+
+ Router::setRequestInfo(array(
+ array('plugin' => null, 'controller' => 'images', 'action' => 'index', 'pass' => array(), 'prefix' => null, 'protected' => false, 'form' => array(), 'url' => array('url' => 'images/index')),
+ array('base' => '', 'here' => '/images/index', 'webroot' => '/')
+ ));
+
+ $result = Router::url(array('controller' => 'images', 'action' => 'add'));
+ $expected = '/images/add';
+ $this->assertEqual($result, $expected);
+
+ $result = Router::url(array('controller' => 'images', 'action' => 'add', 'protected' => true));
+ $expected = '/protected/images/add';
+ $this->assertEqual($result, $expected);
+
+ $result = Router::url(array('action' => 'edit', 1));
+ $expected = '/images/edit/1';
+ $this->assertEqual($result, $expected);
+
+ $result = Router::url(array('action' => 'edit', 1, 'protected' => true));
+ $expected = '/protected/images/edit/1';
+ $this->assertEqual($result, $expected);
+
+ $result = Router::url(array('action' => 'protected_edit', 1, 'protected' => true));
+ $expected = '/protected/images/edit/1';
+ $this->assertEqual($result, $expected);
+
+ $result = Router::url(array('action' => 'protectededit', 1, 'protected' => true));
+ $expected = '/protected/images/protectededit/1';
+ $this->assertEqual($result, $expected);
+
+ $result = Router::url(array('action' => 'edit', 1, 'protected' => true));
+ $expected = '/protected/images/edit/1';
+ $this->assertEqual($result, $expected);
+
+ $result = Router::url(array('controller' => 'others', 'action' => 'edit', 1));
+ $expected = '/others/edit/1';
+ $this->assertEqual($result, $expected);
+
+ $result = Router::url(array('controller' => 'others', 'action' => 'edit', 1, 'protected' => true));
+ $expected = '/protected/others/edit/1';
+ $this->assertEqual($result, $expected);
+
+ $result = Router::url(array('controller' => 'others', 'action' => 'edit', 1, 'protected' => true, 'page' => 1));
+ $expected = '/protected/others/edit/1/page:1';
+ $this->assertEqual($result, $expected);
+
+ Router::connectNamed(array('random'));
+ $result = Router::url(array('controller' => 'others', 'action' => 'edit', 1, 'protected' => true, 'random' => 'my-value'));
+ $expected = '/protected/others/edit/1/random:my-value';
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * test that auto-generated prefix routes persist
+ *
+ * @return void
+ */
+ function testAutoPrefixRoutePersistence() {
+ Configure::write('Routing.prefixes', array('protected'));
+ Router::reload();
+ Router::parse('/');
+
+ Router::setRequestInfo(array(
+ array('plugin' => null, 'controller' => 'images', 'action' => 'index', 'pass' => array(), 'prefix' => 'protected', 'protected' => true, 'form' => array(), 'url' => array('url' => 'protected/images/index')),
+ array('base' => '', 'here' => '/protected/images/index', 'webroot' => '/')
+ ));
+
+ $result = Router::url(array('controller' => 'images', 'action' => 'add'));
+ $expected = '/protected/images/add';
+ $this->assertEqual($result, $expected);
+
+ $result = Router::url(array('controller' => 'images', 'action' => 'add', 'protected' => false));
+ $expected = '/images/add';
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * test that setting a prefix override the current one
+ *
+ * @return void
+ */
+ function testPrefixOverride() {
+ Configure::write('Routing.prefixes', array('protected', 'admin'));
+ Router::reload();
+ Router::parse('/');
+
+ Router::setRequestInfo(array(
+ array('plugin' => null, 'controller' => 'images', 'action' => 'index', 'pass' => array(), 'prefix' => 'protected', 'protected' => true, 'form' => array(), 'url' => array('url' => 'protected/images/index')),
+ array('base' => '', 'here' => '/protected/images/index', 'webroot' => '/')
+ ));
+
+ $result = Router::url(array('controller' => 'images', 'action' => 'add', 'admin' => true));
+ $expected = '/admin/images/add';
+ $this->assertEqual($result, $expected);
+
+ Router::setRequestInfo(array(
+ array('plugin' => null, 'controller' => 'images', 'action' => 'index', 'pass' => array(), 'prefix' => 'admin', 'admin' => true, 'form' => array(), 'url' => array('url' => 'admin/images/index')),
+ array('base' => '', 'here' => '/admin/images/index', 'webroot' => '/')
+ ));
+ $result = Router::url(array('controller' => 'images', 'action' => 'add', 'protected' => true));
+ $expected = '/protected/images/add';
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testRemoveBase method
+ *
+ * @access public
+ * @return void
+ */
+ function testRemoveBase() {
+ Router::setRequestInfo(array(
+ array('controller' => 'controller', 'action' => 'index', 'form' => array(), 'url' => array(), 'bare' => 0, 'plugin' => null),
+ array('base' => '/base', 'here' => '/', 'webroot' => '/base/', 'passedArgs' => array(), 'argSeparator' => ':', 'namedArgs' => array())
+ ));
+
+ $result = Router::url(array('controller' => 'my_controller', 'action' => 'my_action'));
+ $expected = '/base/my_controller/my_action';
+ $this->assertEqual($result, $expected);
+
+ $result = Router::url(array('controller' => 'my_controller', 'action' => 'my_action', 'base' => false));
+ $expected = '/my_controller/my_action';
+ $this->assertEqual($result, $expected);
+
+ $result = Router::url(array('controller' => 'my_controller', 'action' => 'my_action', 'base' => true));
+ $expected = '/base/my_controller/my_action/base:1';
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testPagesUrlParsing method
+ *
+ * @access public
+ * @return void
+ */
+ function testPagesUrlParsing() {
+ Router::connect('/', array('controller' => 'pages', 'action' => 'display', 'home'));
+ Router::connect('/pages/*', array('controller' => 'pages', 'action' => 'display'));
+
+ $result = Router::parse('/');
+ $expected = array('pass'=> array('home'), 'named' => array(), 'plugin' => null, 'controller' => 'pages', 'action' => 'display');
+ $this->assertEqual($result, $expected);
+
+ $result = Router::parse('/pages/home/');
+ $expected = array('pass' => array('home'), 'named' => array(), 'plugin' => null, 'controller' => 'pages', 'action' => 'display');
+ $this->assertEqual($result, $expected);
+
+ Router::reload();
+ Router::connect('/', array('controller' => 'pages', 'action' => 'display', 'home'));
+
+ $result = Router::parse('/pages/display/home/parameter:value');
+ $expected = array('pass' => array('home'), 'named' => array('parameter' => 'value'), 'plugin' => null, 'controller' => 'pages', 'action' => 'display');
+ $this->assertEqual($result, $expected);
+
+ Router::reload();
+ Router::connect('/', array('controller' => 'pages', 'action' => 'display', 'home'));
+
+ $result = Router::parse('/');
+ $expected = array('pass' => array('home'), 'named' => array(), 'plugin' => null, 'controller' => 'pages', 'action' => 'display');
+ $this->assertEqual($result, $expected);
+
+ $result = Router::parse('/pages/display/home/event:value');
+ $expected = array('pass' => array('home'), 'named' => array('event' => 'value'), 'plugin' => null, 'controller' => 'pages', 'action' => 'display');
+ $this->assertEqual($result, $expected);
+
+ $result = Router::parse('/pages/display/home/event:Val_u2');
+ $expected = array('pass' => array('home'), 'named' => array('event' => 'Val_u2'), 'plugin' => null, 'controller' => 'pages', 'action' => 'display');
+ $this->assertEqual($result, $expected);
+
+ $result = Router::parse('/pages/display/home/event:val-ue');
+ $expected = array('pass' => array('home'), 'named' => array('event' => 'val-ue'), 'plugin' => null, 'controller' => 'pages', 'action' => 'display');
+ $this->assertEqual($result, $expected);
+
+ Router::reload();
+ Router::connect('/', array('controller' => 'posts', 'action' => 'index'));
+ Router::connect('/pages/*', array('controller' => 'pages', 'action' => 'display'));
+ $result = Router::parse('/pages/contact/');
+
+ $expected = array('pass'=>array('contact'), 'named' => array(), 'plugin'=> null, 'controller'=>'pages', 'action'=>'display');
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * test that requests with a trailing dot don't loose the do.
+ *
+ * @return void
+ */
+ function testParsingWithTrailingPeriod() {
+ Router::reload();
+ $result = Router::parse('/posts/view/something.');
+ $this->assertEqual($result['pass'][0], 'something.', 'Period was chopped off %s');
+
+ $result = Router::parse('/posts/view/something. . .');
+ $this->assertEqual($result['pass'][0], 'something. . .', 'Period was chopped off %s');
+ }
+
+/**
+ * test that requests with a trailing dot don't loose the do.
+ *
+ * @return void
+ */
+ function testParsingWithTrailingPeriodAndParseExtensions() {
+ Router::reload();
+ Router::parseExtensions('json');
+
+ $result = Router::parse('/posts/view/something.');
+ $this->assertEqual($result['pass'][0], 'something.', 'Period was chopped off %s');
+
+ $result = Router::parse('/posts/view/something. . .');
+ $this->assertEqual($result['pass'][0], 'something. . .', 'Period was chopped off %s');
+ }
+
+/**
+ * test that patterns work for :action
+ *
+ * @return void
+ */
+ function testParsingWithPatternOnAction() {
+ Router::reload();
+ Router::connect(
+ '/blog/:action/*',
+ array('controller' => 'blog_posts'),
+ array('action' => 'other|actions')
+ );
+ $result = Router::parse('/blog/other');
+ $expected = array(
+ 'plugin' => null,
+ 'controller' => 'blog_posts',
+ 'action' => 'other',
+ 'pass' => array(),
+ 'named' => array()
+ );
+ $this->assertEqual($expected, $result);
+
+ $result = Router::parse('/blog/foobar');
+ $expected = array(
+ 'plugin' => null,
+ 'controller' => 'blog',
+ 'action' => 'foobar',
+ 'pass' => array(),
+ 'named' => array()
+ );
+ $this->assertEqual($expected, $result);
+
+ $result = Router::url(array('controller' => 'blog_posts', 'action' => 'foo'));
+ $this->assertEqual('/blog_posts/foo', $result);
+
+ $result = Router::url(array('controller' => 'blog_posts', 'action' => 'actions'));
+ $this->assertEqual('/blog/actions', $result);
+ }
+
+/**
+ * testParsingWithPrefixes method
+ *
+ * @access public
+ * @return void
+ */
+ function testParsingWithPrefixes() {
+ $adminParams = array('prefix' => 'admin', 'admin' => true);
+ Router::connect('/admin/:controller', $adminParams);
+ Router::connect('/admin/:controller/:action', $adminParams);
+ Router::connect('/admin/:controller/:action/*', $adminParams);
+
+ Router::setRequestInfo(array(
+ array('controller' => 'controller', 'action' => 'index', 'form' => array(), 'url' => array(), 'plugin' => null),
+ array('base' => '/base', 'here' => '/', 'webroot' => '/base/', 'passedArgs' => array(), 'argSeparator' => ':', 'namedArgs' => array())
+ ));
+
+ $result = Router::parse('/admin/posts/');
+ $expected = array('pass' => array(), 'named' => array(), 'prefix' => 'admin', 'plugin' => null, 'controller' => 'posts', 'action' => 'index', 'admin' => true);
+ $this->assertEqual($result, $expected);
+
+ $result = Router::parse('/admin/posts');
+ $this->assertEqual($result, $expected);
+
+ $result = Router::url(array('admin' => true, 'controller' => 'posts'));
+ $expected = '/base/admin/posts';
+ $this->assertEqual($result, $expected);
+
+ $result = Router::prefixes();
+ $expected = array('admin');
+ $this->assertEqual($result, $expected);
+
+ Router::reload();
+
+ $prefixParams = array('prefix' => 'members', 'members' => true);
+ Router::connect('/members/:controller', $prefixParams);
+ Router::connect('/members/:controller/:action', $prefixParams);
+ Router::connect('/members/:controller/:action/*', $prefixParams);
+
+ Router::setRequestInfo(array(
+ array('controller' => 'controller', 'action' => 'index', 'form' => array(), 'url' => array(), 'plugin' => null),
+ array('base' => '/base', 'here' => '/', 'webroot' => '/', 'passedArgs' => array(), 'argSeparator' => ':', 'namedArgs' => array())
+ ));
+
+ $result = Router::parse('/members/posts/index');
+ $expected = array('pass' => array(), 'named' => array(), 'prefix' => 'members', 'plugin' => null, 'controller' => 'posts', 'action' => 'index', 'members' => true);
+ $this->assertEqual($result, $expected);
+
+ $result = Router::url(array('members' => true, 'controller' => 'posts', 'action' =>'index', 'page' => 2));
+ $expected = '/base/members/posts/index/page:2';
+ $this->assertEqual($result, $expected);
+
+ $result = Router::url(array('members' => true, 'controller' => 'users', 'action' => 'add'));
+ $expected = '/base/members/users/add';
+ $this->assertEqual($result, $expected);
+
+ $result = Router::parse('/posts/index');
+ $expected = array('pass' => array(), 'named' => array(), 'plugin' => null, 'controller' => 'posts', 'action' => 'index');
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * Tests URL generation with flags and prefixes in and out of context
+ *
+ * @access public
+ * @return void
+ */
+ function testUrlWritingWithPrefixes() {
+ Router::connect('/company/:controller/:action/*', array('prefix' => 'company', 'company' => true));
+ Router::connect('/login', array('controller' => 'users', 'action' => 'login'));
+
+ $result = Router::url(array('controller' => 'users', 'action' => 'login', 'company' => true));
+ $expected = '/company/users/login';
+ $this->assertEqual($result, $expected);
+
+ Router::setRequestInfo(array(
+ array('controller' => 'users', 'action' => 'login', 'company' => true, 'form' => array(), 'url' => array(), 'plugin' => null),
+ array('base' => '/', 'here' => '/', 'webroot' => '/base/')
+ ));
+
+ $result = Router::url(array('controller' => 'users', 'action' => 'login', 'company' => false));
+ $expected = '/login';
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * test url generation with prefixes and custom routes
+ *
+ * @return void
+ */
+ function testUrlWritingWithPrefixesAndCustomRoutes() {
+ Router::connect(
+ '/admin/login',
+ array('controller' => 'users', 'action' => 'login', 'prefix' => 'admin', 'admin' => true)
+ );
+ Router::setRequestInfo(array(
+ array('controller' => 'posts', 'action' => 'index', 'admin' => true, 'prefix' => 'admin',
+ 'form' => array(), 'url' => array(), 'plugin' => null
+ ),
+ array('base' => '/', 'here' => '/', 'webroot' => '/')
+ ));
+ $result = Router::url(array('controller' => 'users', 'action' => 'login', 'admin' => true));
+ $this->assertEqual($result, '/admin/login');
+
+ $result = Router::url(array('controller' => 'users', 'action' => 'login'));
+ $this->assertEqual($result, '/admin/login');
+
+ $result = Router::url(array('controller' => 'users', 'action' => 'admin_login'));
+ $this->assertEqual($result, '/admin/login');
+ }
+
+/**
+ * testPassedArgsOrder method
+ *
+ * @access public
+ * @return void
+ */
+ function testPassedArgsOrder() {
+ Router::connect('/test-passed/*', array('controller' => 'pages', 'action' => 'display', 'home'));
+ Router::connect('/test2/*', array('controller' => 'pages', 'action' => 'display', 2));
+ Router::connect('/test/*', array('controller' => 'pages', 'action' => 'display', 1));
+ Router::parse('/');
+
+ $result = Router::url(array('controller' => 'pages', 'action' => 'display', 1, 'whatever'));
+ $expected = '/test/whatever';
+ $this->assertEqual($result, $expected);
+
+ $result = Router::url(array('controller' => 'pages', 'action' => 'display', 2, 'whatever'));
+ $expected = '/test2/whatever';
+ $this->assertEqual($result, $expected);
+
+ $result = Router::url(array('controller' => 'pages', 'action' => 'display', 'home', 'whatever'));
+ $expected = '/test-passed/whatever';
+ $this->assertEqual($result, $expected);
+
+ Configure::write('Routing.prefixes', array('admin'));
+ Router::reload();
+
+ Router::setRequestInfo(array(
+ array('plugin' => null, 'controller' => 'images', 'action' => 'index', 'pass' => array(), 'named' => array(), 'prefix' => 'protected', 'protected' => true, 'form' => array(), 'url' => array ('url' => 'protected/images/index')),
+ array('plugin' => null, 'controller' => null, 'action' => null, 'base' => '', 'here' => '/protected/images/index', 'webroot' => '/')
+ ));
+
+ Router::connect('/protected/:controller/:action/*', array(
+ 'controller' => 'users',
+ 'action' => 'index',
+ 'prefix' => 'protected'
+ ));
+
+ Router::parse('/');
+ $result = Router::url(array('controller' => 'images', 'action' => 'add'));
+ $expected = '/protected/images/add';
+ $this->assertEqual($result, $expected);
+
+ $result = Router::prefixes();
+ $expected = array('admin', 'protected');
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testRegexRouteMatching method
+ *
+ * @access public
+ * @return void
+ */
+ function testRegexRouteMatching() {
+ Router::connect('/:locale/:controller/:action/*', array(), array('locale' => 'dan|eng'));
+
+ $result = Router::parse('/test/test_action');
+ $expected = array('pass' => array(), 'named' => array(), 'controller' => 'test', 'action' => 'test_action', 'plugin' => null);
+ $this->assertEqual($result, $expected);
+
+ $result = Router::parse('/eng/test/test_action');
+ $expected = array('pass' => array(), 'named' => array(), 'locale' => 'eng', 'controller' => 'test', 'action' => 'test_action', 'plugin' => null);
+ $this->assertEqual($result, $expected);
+
+ $result = Router::parse('/badness/test/test_action');
+ $expected = array('pass' => array('test_action'), 'named' => array(), 'controller' => 'badness', 'action' => 'test', 'plugin' => null);
+ $this->assertEqual($result, $expected);
+
+ Router::reload();
+ Router::connect('/:locale/:controller/:action/*', array(), array('locale' => 'dan|eng'));
+
+ Router::setRequestInfo(array(
+ array('plugin' => null, 'controller' => 'test', 'action' => 'index', 'pass' => array(), 'form' => array(), 'url' => array ('url' => 'test/test_action')),
+ array('plugin' => null, 'controller' => null, 'action' => null, 'base' => '', 'here' => '/test/test_action', 'webroot' => '/')
+ ));
+
+ $result = Router::url(array('action' => 'test_another_action'));
+ $expected = '/test/test_another_action';
+ $this->assertEqual($result, $expected);
+
+ $result = Router::url(array('action' => 'test_another_action', 'locale' => 'eng'));
+ $expected = '/eng/test/test_another_action';
+ $this->assertEqual($result, $expected);
+
+ $result = Router::url(array('action' => 'test_another_action', 'locale' => 'badness'));
+ $expected = '/test/test_another_action/locale:badness';
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testStripPlugin
+ *
+ * @return void
+ * @access public
+ */
+ function testStripPlugin() {
+ $pluginName = 'forums';
+ $url = 'example.com/' . $pluginName . '/';
+ $expected = 'example.com';
+
+ $this->assertEqual(Router::stripPlugin($url, $pluginName), $expected);
+ $this->assertEqual(Router::stripPlugin($url), $url);
+ $this->assertEqual(Router::stripPlugin($url, null), $url);
+ }
+/**
+ * testCurentRoute
+ *
+ * This test needs some improvement and actual requestAction() usage
+ *
+ * @return void
+ * @access public
+ */
+ function testCurrentRoute() {
+ $url = array('controller' => 'pages', 'action' => 'display', 'government');
+ Router::connect('/government', $url);
+ Router::parse('/government');
+ $route =& Router::currentRoute();
+ $this->assertEqual(array_merge($url, array('plugin' => null)), $route->defaults);
+ }
+/**
+ * testRequestRoute
+ *
+ * @return void
+ * @access public
+ */
+ function testRequestRoute() {
+ $url = array('controller' => 'products', 'action' => 'display', 5);
+ Router::connect('/government', $url);
+ Router::parse('/government');
+ $route =& Router::requestRoute();
+ $this->assertEqual(array_merge($url, array('plugin' => null)), $route->defaults);
+
+ // test that the first route is matched
+ $newUrl = array('controller' => 'products', 'action' => 'display', 6);
+ Router::connect('/government', $url);
+ Router::parse('/government');
+ $route =& Router::requestRoute();
+ $this->assertEqual(array_merge($url, array('plugin' => null)), $route->defaults);
+
+ // test that an unmatched route does not change the current route
+ $newUrl = array('controller' => 'products', 'action' => 'display', 6);
+ Router::connect('/actor', $url);
+ Router::parse('/government');
+ $route =& Router::requestRoute();
+ $this->assertEqual(array_merge($url, array('plugin' => null)), $route->defaults);
+ }
+/**
+ * testGetParams
+ *
+ * @return void
+ * @access public
+ */
+ function testGetParams() {
+ $paths = array('base' => '/', 'here' => '/products/display/5', 'webroot' => '/webroot');
+ $params = array('param1' => '1', 'param2' => '2');
+ Router::setRequestInfo(array($params, $paths));
+ $expected = array(
+ 'plugin' => null, 'controller' => false, 'action' => false,
+ 'param1' => '1', 'param2' => '2'
+ );
+ $this->assertEqual(Router::getparams(), $expected);
+ $this->assertEqual(Router::getparam('controller'), false);
+ $this->assertEqual(Router::getparam('param1'), '1');
+ $this->assertEqual(Router::getparam('param2'), '2');
+
+ Router::reload();
+
+ $params = array('controller' => 'pages', 'action' => 'display');
+ Router::setRequestInfo(array($params, $paths));
+ $expected = array('plugin' => null, 'controller' => 'pages', 'action' => 'display');
+ $this->assertEqual(Router::getparams(), $expected);
+ $this->assertEqual(Router::getparams(true), $expected);
+ }
+
+/**
+ * test that connectDefaults() can disable default route connection
+ *
+ * @return void
+ */
+ function testDefaultsMethod() {
+ Router::defaults(false);
+ Router::connect('/test/*', array('controller' => 'pages', 'action' => 'display', 2));
+ $result = Router::parse('/posts/edit/5');
+ $this->assertFalse(isset($result['controller']));
+ $this->assertFalse(isset($result['action']));
+ }
+
+/**
+ * test that the required default routes are connected.
+ *
+ * @return void
+ */
+ function testConnectDefaultRoutes() {
+ App::build(array(
+ 'plugins' => array(
+ TEST_CAKE_CORE_INCLUDE_PATH . 'tests' . DS . 'test_app' . DS . 'plugins' . DS
+ )
+ ), true);
+ App::objects('plugin', null, false);
+ Router::reload();
+
+ $result = Router::url(array('plugin' => 'plugin_js', 'controller' => 'js_file', 'action' => 'index'));
+ $this->assertEqual($result, '/plugin_js/js_file');
+
+ $result = Router::parse('/plugin_js/js_file');
+ $expected = array(
+ 'plugin' => 'plugin_js', 'controller' => 'js_file', 'action' => 'index',
+ 'named' => array(), 'pass' => array()
+ );
+ $this->assertEqual($result, $expected);
+
+ $result = Router::url(array('plugin' => 'test_plugin', 'controller' => 'test_plugin', 'action' => 'index'));
+ $this->assertEqual($result, '/test_plugin');
+
+ $result = Router::parse('/test_plugin');
+ $expected = array(
+ 'plugin' => 'test_plugin', 'controller' => 'test_plugin', 'action' => 'index',
+ 'named' => array(), 'pass' => array()
+ );
+
+ $this->assertEqual($result, $expected, 'Plugin shortcut route broken. %s');
+ }
+
+/**
+ * test using a custom route class for route connection
+ *
+ * @return void
+ */
+ function testUsingCustomRouteClass() {
+ Mock::generate('CakeRoute', 'MockConnectedRoute');
+ $routes = Router::connect(
+ '/:slug',
+ array('controller' => 'posts', 'action' => 'view'),
+ array('routeClass' => 'MockConnectedRoute', 'slug' => '[a-z_-]+')
+ );
+ $this->assertTrue(is_a($routes[0], 'MockConnectedRoute'), 'Incorrect class used. %s');
+ $expected = array('controller' => 'posts', 'action' => 'view', 'slug' => 'test');
+ $routes[0]->setReturnValue('parse', $expected);
+ $result = Router::parse('/test');
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * test reversing parameter arrays back into strings.
+ *
+ * @return void
+ */
+ function testRouterReverse() {
+ $params = array(
+ 'controller' => 'posts',
+ 'action' => 'view',
+ 'pass' => array(1),
+ 'named' => array(),
+ 'url' => array(),
+ 'autoRender' => 1,
+ 'bare' => 1,
+ 'return' => 1,
+ 'requested' => 1
+ );
+ $result = Router::reverse($params);
+ $this->assertEqual($result, '/posts/view/1');
+
+ $params = array(
+ 'controller' => 'posts',
+ 'action' => 'index',
+ 'pass' => array(1),
+ 'named' => array('page' => 1, 'sort' => 'Article.title', 'direction' => 'desc'),
+ 'url' => array()
+ );
+ $result = Router::reverse($params);
+ $this->assertEqual($result, '/posts/index/1/page:1/sort:Article.title/direction:desc');
+
+ Router::connect('/:lang/:controller/:action/*', array(), array('lang' => '[a-z]{3}'));
+ $params = array(
+ 'lang' => 'eng',
+ 'controller' => 'posts',
+ 'action' => 'view',
+ 'pass' => array(1),
+ 'named' => array(),
+ 'url' => array('url' => 'eng/posts/view/1')
+ );
+ $result = Router::reverse($params);
+ $this->assertEqual($result, '/eng/posts/view/1');
+
+ $params = array(
+ 'lang' => 'eng',
+ 'controller' => 'posts',
+ 'action' => 'view',
+ 'pass' => array(1),
+ 'named' => array(),
+ 'url' => array('url' => 'eng/posts/view/1', 'foo' => 'bar', 'baz' => 'quu'),
+ 'paging' => array(),
+ 'models' => array()
+ );
+ $result = Router::reverse($params);
+ $this->assertEqual($result, '/eng/posts/view/1?foo=bar&baz=quu');
+ }
+}
+
+/**
+ * Test case for CakeRoute
+ *
+ * @package cake.tests.cases.libs.
+ **/
+class CakeRouteTestCase extends CakeTestCase {
+/**
+ * startTest method
+ *
+ * @access public
+ * @return void
+ */
+ function startTest() {
+ $this->_routing = Configure::read('Routing');
+ Configure::write('Routing', array('admin' => null, 'prefixes' => array()));
+ Router::reload();
+ }
+
+/**
+ * end the test and reset the environment
+ *
+ * @return void
+ **/
+ function endTest() {
+ Configure::write('Routing', $this->_routing);
+ }
+
+/**
+ * Test the construction of a CakeRoute
+ *
+ * @return void
+ **/
+ function testConstruction() {
+ $route =& new CakeRoute('/:controller/:action/:id', array(), array('id' => '[0-9]+'));
+
+ $this->assertEqual($route->template, '/:controller/:action/:id');
+ $this->assertEqual($route->defaults, array());
+ $this->assertEqual($route->options, array('id' => '[0-9]+'));
+ $this->assertFalse($route->compiled());
+ }
+
+/**
+ * test Route compiling.
+ *
+ * @return void
+ **/
+ function testBasicRouteCompiling() {
+ $route =& new CakeRoute('/', array('controller' => 'pages', 'action' => 'display', 'home'));
+ $result = $route->compile();
+ $expected = '#^/*$#';
+ $this->assertEqual($result, $expected);
+ $this->assertEqual($route->keys, array());
+
+ $route =& new CakeRoute('/:controller/:action', array('controller' => 'posts'));
+ $result = $route->compile();
+
+ $this->assertPattern($result, '/posts/edit');
+ $this->assertPattern($result, '/posts/super_delete');
+ $this->assertNoPattern($result, '/posts');
+ $this->assertNoPattern($result, '/posts/super_delete/1');
+
+ $route =& new CakeRoute('/posts/foo:id', array('controller' => 'posts', 'action' => 'view'));
+ $result = $route->compile();
+
+ $this->assertPattern($result, '/posts/foo:1');
+ $this->assertPattern($result, '/posts/foo:param');
+ $this->assertNoPattern($result, '/posts');
+ $this->assertNoPattern($result, '/posts/');
+
+ $this->assertEqual($route->keys, array('id'));
+
+ $route =& new CakeRoute('/:plugin/:controller/:action/*', array('plugin' => 'test_plugin', 'action' => 'index'));
+ $result = $route->compile();
+ $this->assertPattern($result, '/test_plugin/posts/index');
+ $this->assertPattern($result, '/test_plugin/posts/edit/5');
+ $this->assertPattern($result, '/test_plugin/posts/edit/5/name:value/nick:name');
+ }
+
+/**
+ * test route names with - in them.
+ *
+ * @return void
+ */
+ function testHyphenNames() {
+ $route =& new CakeRoute('/articles/:date-from/:date-to', array(
+ 'controller' => 'articles', 'action' => 'index'
+ ));
+ $expected = array(
+ 'controller' => 'articles',
+ 'action' => 'index',
+ 'date-from' => '2009-07-31',
+ 'date-to' => '2010-07-31',
+ 'named' => array(),
+ 'pass' => array()
+ );
+ $result = $route->parse('/articles/2009-07-31/2010-07-31');
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * test that route parameters that overlap don't cause errors.
+ *
+ * @return void
+ */
+ function testRouteParameterOverlap() {
+ $route =& new CakeRoute('/invoices/add/:idd/:id', array('controller' => 'invoices', 'action' => 'add'));
+ $result = $route->compile();
+ $this->assertPattern($result, '/invoices/add/1/3');
+
+ $route =& new CakeRoute('/invoices/add/:id/:idd', array('controller' => 'invoices', 'action' => 'add'));
+ $result = $route->compile();
+ $this->assertPattern($result, '/invoices/add/1/3');
+ }
+
+/**
+ * test compiling routes with keys that have patterns
+ *
+ * @return void
+ **/
+ function testRouteCompilingWithParamPatterns() {
+ extract(Router::getNamedExpressions());
+
+ $route = new CakeRoute(
+ '/:controller/:action/:id',
+ array(),
+ array('id' => $ID)
+ );
+ $result = $route->compile();
+ $this->assertPattern($result, '/posts/edit/1');
+ $this->assertPattern($result, '/posts/view/518098');
+ $this->assertNoPattern($result, '/posts/edit/name-of-post');
+ $this->assertNoPattern($result, '/posts/edit/4/other:param');
+ $this->assertEqual($route->keys, array('controller', 'action', 'id'));
+
+ $route =& new CakeRoute(
+ '/:lang/:controller/:action/:id',
+ array('controller' => 'testing4'),
+ array('id' => $ID, 'lang' => '[a-z]{3}')
+ );
+ $result = $route->compile();
+ $this->assertPattern($result, '/eng/posts/edit/1');
+ $this->assertPattern($result, '/cze/articles/view/1');
+ $this->assertNoPattern($result, '/language/articles/view/2');
+ $this->assertNoPattern($result, '/eng/articles/view/name-of-article');
+ $this->assertEqual($route->keys, array('lang', 'controller', 'action', 'id'));
+
+ foreach (array(':', '@', ';', '$', '-') as $delim) {
+ $route =& new CakeRoute('/posts/:id' . $delim . ':title');
+ $result = $route->compile();
+
+ $this->assertPattern($result, '/posts/1' . $delim . 'name-of-article');
+ $this->assertPattern($result, '/posts/13244' . $delim . 'name-of_Article[]');
+ $this->assertNoPattern($result, '/posts/11!nameofarticle');
+ $this->assertNoPattern($result, '/posts/11');
+
+ $this->assertEqual($route->keys, array('id', 'title'));
+ }
+
+ $route =& new CakeRoute(
+ '/posts/:id::title/:year',
+ array('controller' => 'posts', 'action' => 'view'),
+ array('id' => $ID, 'year' => $Year, 'title' => '[a-z-_]+')
+ );
+ $result = $route->compile();
+ $this->assertPattern($result, '/posts/1:name-of-article/2009/');
+ $this->assertPattern($result, '/posts/13244:name-of-article/1999');
+ $this->assertNoPattern($result, '/posts/hey_now:nameofarticle');
+ $this->assertNoPattern($result, '/posts/:nameofarticle/2009');
+ $this->assertNoPattern($result, '/posts/:nameofarticle/01');
+ $this->assertEqual($route->keys, array('id', 'title', 'year'));
+
+ $route =& new CakeRoute(
+ '/posts/:url_title-(uuid::id)',
+ array('controller' => 'posts', 'action' => 'view'),
+ array('pass' => array('id', 'url_title'), 'id' => $ID)
+ );
+ $result = $route->compile();
+ $this->assertPattern($result, '/posts/some_title_for_article-(uuid:12534)/');
+ $this->assertPattern($result, '/posts/some_title_for_article-(uuid:12534)');
+ $this->assertNoPattern($result, '/posts/');
+ $this->assertNoPattern($result, '/posts/nameofarticle');
+ $this->assertNoPattern($result, '/posts/nameofarticle-12347');
+ $this->assertEqual($route->keys, array('url_title', 'id'));
+ }
+
+/**
+ * test more complex route compiling & parsing with mid route greedy stars
+ * and optional routing parameters
+ *
+ * @return void
+ */
+ function testComplexRouteCompilingAndParsing() {
+ extract(Router::getNamedExpressions());
+
+ $route =& new CakeRoute(
+ '/posts/:month/:day/:year/*',
+ array('controller' => 'posts', 'action' => 'view'),
+ array('year' => $Year, 'month' => $Month, 'day' => $Day)
+ );
+ $result = $route->compile();
+ $this->assertPattern($result, '/posts/08/01/2007/title-of-post');
+ $result = $route->parse('/posts/08/01/2007/title-of-post');
+
+ $this->assertEqual(count($result), 8);
+ $this->assertEqual($result['controller'], 'posts');
+ $this->assertEqual($result['action'], 'view');
+ $this->assertEqual($result['year'], '2007');
+ $this->assertEqual($result['month'], '08');
+ $this->assertEqual($result['day'], '01');
+
+ $route =& new CakeRoute(
+ "/:extra/page/:slug/*",
+ array('controller' => 'pages', 'action' => 'view', 'extra' => null),
+ array("extra" => '[a-z1-9_]*', "slug" => '[a-z1-9_]+', "action" => 'view')
+ );
+ $result = $route->compile();
+
+ $this->assertPattern($result, '/some_extra/page/this_is_the_slug');
+ $this->assertPattern($result, '/page/this_is_the_slug');
+ $this->assertEqual($route->keys, array('extra', 'slug'));
+ $this->assertEqual($route->options, array('extra' => '[a-z1-9_]*', 'slug' => '[a-z1-9_]+', 'action' => 'view'));
+ $expected = array(
+ 'controller' => 'pages',
+ 'action' => 'view',
+ 'extra' => null,
+ );
+ $this->assertEqual($route->defaults, $expected);
+
+ $route =& new CakeRoute(
+ '/:controller/:action/*',
+ array('project' => false),
+ array(
+ 'controller' => 'source|wiki|commits|tickets|comments|view',
+ 'action' => 'branches|history|branch|logs|view|start|add|edit|modify'
+ )
+ );
+ $this->assertFalse($route->parse('/chaw_test/wiki'));
+
+ $result = $route->compile();
+ $this->assertNoPattern($result, '/some_project/source');
+ $this->assertPattern($result, '/source/view');
+ $this->assertPattern($result, '/source/view/other/params');
+ $this->assertNoPattern($result, '/chaw_test/wiki');
+ $this->assertNoPattern($result, '/source/wierd_action');
+ }
+
+/**
+ * test that routes match their pattern.
+ *
+ * @return void
+ **/
+ function testMatchBasic() {
+ $route = new CakeRoute('/:controller/:action/:id', array('plugin' => null));
+ $result = $route->match(array('controller' => 'posts', 'action' => 'view', 'plugin' => null));
+ $this->assertFalse($result);
+
+ $result = $route->match(array('plugin' => null, 'controller' => 'posts', 'action' => 'view', 0));
+ $this->assertFalse($result);
+
+ $result = $route->match(array('plugin' => null, 'controller' => 'posts', 'action' => 'view', 'id' => 1));
+ $this->assertEqual($result, '/posts/view/1');
+
+ $route =& new CakeRoute('/', array('controller' => 'pages', 'action' => 'display', 'home'));
+ $result = $route->match(array('controller' => 'pages', 'action' => 'display', 'home'));
+ $this->assertEqual($result, '/');
+
+ $result = $route->match(array('controller' => 'pages', 'action' => 'display', 'about'));
+ $this->assertFalse($result);
+
+
+ $route =& new CakeRoute('/pages/*', array('controller' => 'pages', 'action' => 'display'));
+ $result = $route->match(array('controller' => 'pages', 'action' => 'display', 'home'));
+ $this->assertEqual($result, '/pages/home');
+
+ $result = $route->match(array('controller' => 'pages', 'action' => 'display', 'about'));
+ $this->assertEqual($result, '/pages/about');
+
+
+ $route =& new CakeRoute('/blog/:action', array('controller' => 'posts'));
+ $result = $route->match(array('controller' => 'posts', 'action' => 'view'));
+ $this->assertEqual($result, '/blog/view');
+
+ $result = $route->match(array('controller' => 'nodes', 'action' => 'view'));
+ $this->assertFalse($result);
+
+ $result = $route->match(array('controller' => 'posts', 'action' => 'view', 1));
+ $this->assertFalse($result);
+
+ $result = $route->match(array('controller' => 'posts', 'action' => 'view', 'id' => 2));
+ $this->assertFalse($result);
+
+
+ $route =& new CakeRoute('/foo/:controller/:action', array('action' => 'index'));
+ $result = $route->match(array('controller' => 'posts', 'action' => 'view'));
+ $this->assertEqual($result, '/foo/posts/view');
+
+
+ $route =& new CakeRoute('/:plugin/:id/*', array('controller' => 'posts', 'action' => 'view'));
+ $result = $route->match(array('plugin' => 'test', 'controller' => 'posts', 'action' => 'view', 'id' => '1'));
+ $this->assertEqual($result, '/test/1/');
+
+ $result = $route->match(array('plugin' => 'fo', 'controller' => 'posts', 'action' => 'view', 'id' => '1', '0'));
+ $this->assertEqual($result, '/fo/1/0');
+
+ $result = $route->match(array('plugin' => 'fo', 'controller' => 'nodes', 'action' => 'view', 'id' => 1));
+ $this->assertFalse($result);
+
+ $result = $route->match(array('plugin' => 'fo', 'controller' => 'posts', 'action' => 'edit', 'id' => 1));
+ $this->assertFalse($result);
+
+ $route =& new CakeRoute('/admin/subscriptions/:action/*', array(
+ 'controller' => 'subscribe', 'admin' => true, 'prefix' => 'admin'
+ ));
+
+ $url = array('controller' => 'subscribe', 'admin' => true, 'action' => 'edit', 1);
+ $result = $route->match($url);
+ $expected = '/admin/subscriptions/edit/1';
+ $this->assertEqual($result, $expected);
+
+ $route =& new CakeRoute('/articles/:date-from/:date-to', array(
+ 'controller' => 'articles', 'action' => 'index'
+ ));
+ $url = array(
+ 'controller' => 'articles',
+ 'action' => 'index',
+ 'date-from' => '2009-07-31',
+ 'date-to' => '2010-07-31'
+ );
+
+ $result = $route->match($url);
+ $expected = '/articles/2009-07-31/2010-07-31';
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * test match() with greedy routes, named parameters and passed args.
+ *
+ * @return void
+ */
+ function testMatchWithNamedParametersAndPassedArgs() {
+ Router::connectNamed(true);
+
+ $route = new CakeRoute('/:controller/:action/*', array('plugin' => null));
+ $result = $route->match(array('controller' => 'posts', 'action' => 'index', 'plugin' => null, 'page' => 1));
+ $this->assertEqual($result, '/posts/index/page:1');
+
+ $result = $route->match(array('controller' => 'posts', 'action' => 'view', 'plugin' => null, 5));
+ $this->assertEqual($result, '/posts/view/5');
+
+ $result = $route->match(array('controller' => 'posts', 'action' => 'view', 'plugin' => null, 5, 'page' => 1, 'limit' => 20, 'order' => 'title'));
+ $this->assertEqual($result, '/posts/view/5/page:1/limit:20/order:title');
+
+
+ $route =& new CakeRoute('/test2/*', array('controller' => 'pages', 'action' => 'display', 2));
+ $result = $route->match(array('controller' => 'pages', 'action' => 'display', 1));
+ $this->assertFalse($result);
+
+ $result = $route->match(array('controller' => 'pages', 'action' => 'display', 2, 'something'));
+ $this->assertEqual($result, '/test2/something');
+
+ $result = $route->match(array('controller' => 'pages', 'action' => 'display', 5, 'something'));
+ $this->assertFalse($result);
+ }
+
+/**
+ * test that match with patterns works.
+ *
+ * @return void
+ */
+ function testMatchWithPatterns() {
+ $route =& new CakeRoute('/:controller/:action/:id', array('plugin' => null), array('id' => '[0-9]+'));
+ $result = $route->match(array('controller' => 'posts', 'action' => 'view', 'id' => 'foo'));
+ $this->assertFalse($result);
+
+ $result = $route->match(array('plugin' => null, 'controller' => 'posts', 'action' => 'view', 'id' => '9'));
+ $this->assertEqual($result, '/posts/view/9');
+
+ $result = $route->match(array('plugin' => null, 'controller' => 'posts', 'action' => 'view', 'id' => '922'));
+ $this->assertEqual($result, '/posts/view/922');
+
+ $result = $route->match(array('plugin' => null, 'controller' => 'posts', 'action' => 'view', 'id' => 'a99'));
+ $this->assertFalse($result);
+ }
+
+/**
+ * test that patterns work for :action
+ *
+ * @return void
+ */
+ function testPatternOnAction() {
+ $route =& new CakeRoute(
+ '/blog/:action/*',
+ array('controller' => 'blog_posts'),
+ array('action' => 'other|actions')
+ );
+ $result = $route->match(array('controller' => 'blog_posts', 'action' => 'foo'));
+ $this->assertFalse($result);
+
+ $result = $route->match(array('controller' => 'blog_posts', 'action' => 'actions'));
+ $this->assertTrue($result);
+
+ $result = $route->parse('/blog/other');
+ $expected = array('controller' => 'blog_posts', 'action' => 'other', 'pass' => array(), 'named' => array());
+ $this->assertEqual($expected, $result);
+
+ $result = $route->parse('/blog/foobar');
+ $this->assertFalse($result);
+ }
+
+/**
+ * test persistParams ability to persist parameters from $params and remove params.
+ *
+ * @return void
+ */
+ function testPersistParams() {
+ $route =& new CakeRoute(
+ '/:lang/:color/blog/:action',
+ array('controller' => 'posts'),
+ array('persist' => array('lang', 'color'))
+ );
+ $url = array('controller' => 'posts', 'action' => 'index');
+ $params = array('lang' => 'en', 'color' => 'blue');
+ $result = $route->persistParams($url, $params);
+ $this->assertEqual($result['lang'], 'en');
+ $this->assertEqual($result['color'], 'blue');
+
+ $url = array('controller' => 'posts', 'action' => 'index', 'color' => 'red');
+ $params = array('lang' => 'en', 'color' => 'blue');
+ $result = $route->persistParams($url, $params);
+ $this->assertEqual($result['lang'], 'en');
+ $this->assertEqual($result['color'], 'red');
+ }
+
+/**
+ * test the parse method of CakeRoute.
+ *
+ * @return void
+ */
+ function testParse() {
+ extract(Router::getNamedExpressions());
+ $route =& new CakeRoute('/:controller/:action/:id', array('controller' => 'testing4', 'id' => null), array('id' => $ID));
+ $route->compile();
+ $result = $route->parse('/posts/view/1');
+ $this->assertEqual($result['controller'], 'posts');
+ $this->assertEqual($result['action'], 'view');
+ $this->assertEqual($result['id'], '1');
+
+ $route =& new Cakeroute(
+ '/admin/:controller',
+ array('prefix' => 'admin', 'admin' => 1, 'action' => 'index')
+ );
+ $route->compile();
+ $result = $route->parse('/admin/');
+ $this->assertFalse($result);
+
+ $result = $route->parse('/admin/posts');
+ $this->assertEqual($result['controller'], 'posts');
+ $this->assertEqual($result['action'], 'index');
+ }
+}
+
+/**
+ * test case for PluginShortRoute
+ *
+ * @package cake.tests.libs
+ */
+class PluginShortRouteTestCase extends CakeTestCase {
+/**
+ * startTest method
+ *
+ * @access public
+ * @return void
+ */
+ function startTest() {
+ $this->_routing = Configure::read('Routing');
+ Configure::write('Routing', array('admin' => null, 'prefixes' => array()));
+ Router::reload();
+ }
+
+/**
+ * end the test and reset the environment
+ *
+ * @return void
+ **/
+ function endTest() {
+ Configure::write('Routing', $this->_routing);
+ }
+
+/**
+ * test the parsing of routes.
+ *
+ * @return void
+ */
+ function testParsing() {
+ $route =& new PluginShortRoute('/:plugin', array('action' => 'index'), array('plugin' => 'foo|bar'));
+
+ $result = $route->parse('/foo');
+ $this->assertEqual($result['plugin'], 'foo');
+ $this->assertEqual($result['controller'], 'foo');
+ $this->assertEqual($result['action'], 'index');
+
+ $result = $route->parse('/wrong');
+ $this->assertFalse($result, 'Wrong plugin name matched %s');
+ }
+
+/**
+ * test the reverse routing of the plugin shortcut urls.
+ *
+ * @return void
+ */
+ function testMatch() {
+ $route =& new PluginShortRoute('/:plugin', array('action' => 'index'), array('plugin' => 'foo|bar'));
+
+ $result = $route->match(array('plugin' => 'foo', 'controller' => 'posts', 'action' => 'index'));
+ $this->assertFalse($result, 'plugin controller mismatch was converted. %s');
+
+ $result = $route->match(array('plugin' => 'foo', 'controller' => 'foo', 'action' => 'index'));
+ $this->assertEqual($result, '/foo');
+ }
+}
diff --git a/code/ryzom/tools/server/www/webtt/cake/tests/cases/libs/sanitize.test.php b/code/ryzom/tools/server/www/webtt/cake/tests/cases/libs/sanitize.test.php
new file mode 100644
index 000000000..34bb5f497
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/cake/tests/cases/libs/sanitize.test.php
@@ -0,0 +1,523 @@
+
+ * Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
+ *
+ * Licensed under The Open Group Test Suite License
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
+ * @link http://book.cakephp.org/view/1196/Testing CakePHP(tm) Tests
+ * @package cake
+ * @subpackage cake.tests.cases.libs
+ * @since CakePHP(tm) v 1.2.0.5428
+ * @license http://www.opensource.org/licenses/opengroup.php The Open Group Test Suite License
+ */
+App::import('Core', 'Sanitize');
+
+/**
+ * DataTest class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs
+ */
+class SanitizeDataTest extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'SanitizeDataTest'
+ * @access public
+ */
+ var $name = 'SanitizeDataTest';
+
+/**
+ * useTable property
+ *
+ * @var string 'data_tests'
+ * @access public
+ */
+ var $useTable = 'data_tests';
+}
+
+/**
+ * Article class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs
+ */
+class SanitizeArticle extends CakeTestModel {
+
+/**
+ * name property
+ *
+ * @var string 'Article'
+ * @access public
+ */
+ var $name = 'SanitizeArticle';
+
+/**
+ * useTable property
+ *
+ * @var string 'articles'
+ * @access public
+ */
+ var $useTable = 'articles';
+}
+
+/**
+ * SanitizeTest class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs
+ */
+class SanitizeTest extends CakeTestCase {
+
+/**
+ * autoFixtures property
+ *
+ * @var bool false
+ * @access public
+ */
+ var $autoFixtures = false;
+
+/**
+ * fixtures property
+ *
+ * @var array
+ * @access public
+ */
+ var $fixtures = array('core.data_test', 'core.article');
+
+/**
+ * startTest method
+ *
+ * @param mixed $method
+ * @access public
+ * @return void
+ */
+ function startTest($method) {
+ parent::startTest($method);
+ $this->_initDb();
+ }
+
+/**
+ * testEscapeAlphaNumeric method
+ *
+ * @access public
+ * @return void
+ */
+ function testEscapeAlphaNumeric() {
+ $resultAlpha = Sanitize::escape('abc', 'test_suite');
+ $this->assertEqual($resultAlpha, 'abc');
+
+ $resultNumeric = Sanitize::escape('123', 'test_suite');
+ $this->assertEqual($resultNumeric, '123');
+
+ $resultNumeric = Sanitize::escape(1234, 'test_suite');
+ $this->assertEqual($resultNumeric, 1234);
+
+ $resultNumeric = Sanitize::escape(1234.23, 'test_suite');
+ $this->assertEqual($resultNumeric, 1234.23);
+
+ $resultNumeric = Sanitize::escape('#1234.23', 'test_suite');
+ $this->assertEqual($resultNumeric, '#1234.23');
+
+ $resultNull = Sanitize::escape(null, 'test_suite');
+ $this->assertEqual($resultNull, null);
+
+ $resultNull = Sanitize::escape(false, 'test_suite');
+ $this->assertEqual($resultNull, false);
+
+ $resultNull = Sanitize::escape(true, 'test_suite');
+ $this->assertEqual($resultNull, true);
+ }
+
+/**
+ * testClean method
+ *
+ * @access public
+ * @return void
+ */
+ function testClean() {
+ $string = 'test & "quote" \'other\' ;.$ symbol.' . "\r" . 'another line';
+ $expected = 'test & "quote" 'other' ;.$ symbol.another line';
+ $result = Sanitize::clean($string, array('connection' => 'test_suite'));
+ $this->assertEqual($result, $expected);
+
+ $string = 'test & "quote" \'other\' ;.$ symbol.' . "\r" . 'another line';
+ $expected = 'test & ' . Sanitize::escape('"quote"', 'test_suite') . ' ' . Sanitize::escape('\'other\'', 'test_suite') . ' ;.$ symbol.another line';
+ $result = Sanitize::clean($string, array('encode' => false, 'connection' => 'test_suite'));
+ $this->assertEqual($result, $expected);
+
+ $string = 'test & "quote" \'other\' ;.$ \\$ symbol.' . "\r" . 'another line';
+ $expected = 'test & "quote" \'other\' ;.$ $ symbol.another line';
+ $result = Sanitize::clean($string, array('encode' => false, 'escape' => false, 'connection' => 'test_suite'));
+ $this->assertEqual($result, $expected);
+
+ $string = 'test & "quote" \'other\' ;.$ \\$ symbol.' . "\r" . 'another line';
+ $expected = 'test & "quote" \'other\' ;.$ \\$ symbol.another line';
+ $result = Sanitize::clean($string, array('encode' => false, 'escape' => false, 'dollar' => false, 'connection' => 'test_suite'));
+ $this->assertEqual($result, $expected);
+
+ $string = 'test & "quote" \'other\' ;.$ symbol.' . "\r" . 'another line';
+ $expected = 'test & "quote" \'other\' ;.$ symbol.' . "\r" . 'another line';
+ $result = Sanitize::clean($string, array('encode' => false, 'escape' => false, 'carriage' => false, 'connection' => 'test_suite'));
+ $this->assertEqual($result, $expected);
+
+ $array = array(array('test & "quote" \'other\' ;.$ symbol.' . "\r" . 'another line'));
+ $expected = array(array('test & "quote" 'other' ;.$ symbol.another line'));
+ $result = Sanitize::clean($array, array('connection' => 'test_suite'));
+ $this->assertEqual($result, $expected);
+
+ $array = array(array('test & "quote" \'other\' ;.$ \\$ symbol.' . "\r" . 'another line'));
+ $expected = array(array('test & "quote" \'other\' ;.$ $ symbol.another line'));
+ $result = Sanitize::clean($array, array('encode' => false, 'escape' => false, 'connection' => 'test_suite'));
+ $this->assertEqual($result, $expected);
+
+ $array = array(array('test odd Ä spacesé'));
+ $expected = array(array('test odd Ä spacesé'));
+ $result = Sanitize::clean($array, array('odd_spaces' => false, 'escape' => false, 'connection' => 'test_suite'));
+ $this->assertEqual($result, $expected);
+
+ $array = array(array('\\$', array('key' => 'test & "quote" \'other\' ;.$ \\$ symbol.' . "\r" . 'another line')));
+ $expected = array(array('$', array('key' => 'test & "quote" \'other\' ;.$ $ symbol.another line')));
+ $result = Sanitize::clean($array, array('encode' => false, 'escape' => false));
+ $this->assertEqual($result, $expected);
+
+ $string = '';
+ $expected = '';
+ $result = Sanitize::clean($string);
+ $this->assertEqual($string, $expected);
+
+ $data = array(
+ 'Grant' => array(
+ 'title' => '2 o clock grant',
+ 'grant_peer_review_id' => 3,
+ 'institution_id' => 5,
+ 'created_by' => 1,
+ 'modified_by' => 1,
+ 'created' => '2010-07-15 14:11:00',
+ 'modified' => '2010-07-19 10:45:41'
+ ),
+ 'GrantsMember' => array(
+ 0 => array(
+ 'id' => 68,
+ 'grant_id' => 120,
+ 'member_id' => 16,
+ 'program_id' => 29,
+ 'pi_percent_commitment' => 1
+ )
+ )
+ );
+ $result = Sanitize::clean($data);
+ $this->assertEqual($result, $data);
+ }
+
+/**
+ * testHtml method
+ *
+ * @access public
+ * @return void
+ */
+ function testHtml() {
+ $string = 'This is a test string & so is this
';
+ $expected = 'This is a test string & so is this';
+ $result = Sanitize::html($string, array('remove' => true));
+ $this->assertEqual($result, $expected);
+
+ $string = 'The "lazy" dog \'jumped\' & flew over the moon. If (1+1) = 2 is true, (2-1) = 1 is also true';
+ $expected = 'The "lazy" dog 'jumped' & flew over the moon. If (1+1) = 2 <em>is</em> true, (2-1) = 1 is also true';
+ $result = Sanitize::html($string);
+ $this->assertEqual($result, $expected);
+
+ $string = 'The "lazy" dog \'jumped\'';
+ $expected = 'The "lazy" dog \'jumped\'';
+ $result = Sanitize::html($string, array('quotes' => ENT_COMPAT));
+ $this->assertEqual($result, $expected);
+
+ $string = 'The "lazy" dog \'jumped\'';
+ $result = Sanitize::html($string, array('quotes' => ENT_NOQUOTES));
+ $this->assertEqual($result, $string);
+
+ $string = 'The "lazy" dog \'jumped\' & flew over the moon. If (1+1) = 2 is true, (2-1) = 1 is also true';
+ $expected = 'The "lazy" dog 'jumped' & flew over the moon. If (1+1) = 2 <em>is</em> true, (2-1) = 1 is also true';
+ $result = Sanitize::html($string);
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testStripWhitespace method
+ *
+ * @access public
+ * @return void
+ */
+ function testStripWhitespace() {
+ $string = "This sentence \t\t\t has lots of \n\n white\nspace \rthat \r\n needs to be \t \n trimmed.";
+ $expected = "This sentence has lots of whitespace that needs to be trimmed.";
+ $result = Sanitize::stripWhitespace($string);
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testParanoid method
+ *
+ * @access public
+ * @return void
+ */
+ function testParanoid() {
+ $string = 'I would like to !%@#% & dance & sing ^$&*()-+';
+ $expected = 'Iwouldliketodancesing';
+ $result = Sanitize::paranoid($string);
+ $this->assertEqual($result, $expected);
+
+ $string = array('This |s th% s0ng that never ends it g*es',
+ 'on and on my friends, b^ca#use it is the',
+ 'so&g th===t never ends.');
+ $expected = array('This s th% s0ng that never ends it g*es',
+ 'on and on my friends bcause it is the',
+ 'sog tht never ends.');
+ $result = Sanitize::paranoid($string, array('%', '*', '.', ' '));
+ $this->assertEqual($result, $expected);
+
+ $string = "anything' OR 1 = 1";
+ $expected = 'anythingOR11';
+ $result = Sanitize::paranoid($string);
+ $this->assertEqual($result, $expected);
+
+ $string = "x' AND email IS NULL; --";
+ $expected = 'xANDemailISNULL';
+ $result = Sanitize::paranoid($string);
+ $this->assertEqual($result, $expected);
+
+ $string = "x' AND 1=(SELECT COUNT(*) FROM users); --";
+ $expected = "xAND1SELECTCOUNTFROMusers";
+ $result = Sanitize::paranoid($string);
+ $this->assertEqual($result, $expected);
+
+ $string = "x'; DROP TABLE members; --";
+ $expected = "xDROPTABLEmembers";
+ $result = Sanitize::paranoid($string);
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testStripImages method
+ *
+ * @access public
+ * @return void
+ */
+ function testStripImages() {
+ $string = ' ';
+ $expected = 'my image ';
+ $result = Sanitize::stripImages($string);
+ $this->assertEqual($result, $expected);
+
+ $string = ' ';
+ $expected = '';
+ $result = Sanitize::stripImages($string);
+ $this->assertEqual($result, $expected);
+
+ $string = ' ';
+ $expected = 'test image alt ';
+ $result = Sanitize::stripImages($string);
+ $this->assertEqual($result, $expected);
+
+ $string = ' ';
+ $expected = ' ';
+ $result = Sanitize::stripImages($string);
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testStripScripts method
+ *
+ * @access public
+ * @return void
+ */
+ function testStripScripts() {
+ $string = ' ';
+ $expected = '';
+ $result = Sanitize::stripScripts($string);
+ $this->assertEqual($result, $expected);
+
+ $string = ' ' . "\n" . ' ' . "\n" . ' ' . "\n" . ' ';
+ $expected = "\n" . ' ' . "\n" . ' '."\n".' ';
+ $result = Sanitize::stripScripts($string);
+ $this->assertEqual($result, $expected);
+
+ $string = '';
+ $expected = '';
+ $result = Sanitize::stripScripts($string);
+ $this->assertEqual($result, $expected);
+
+ $string = '';
+ $expected = '';
+ $result = Sanitize::stripScripts($string);
+ $this->assertEqual($result, $expected);
+
+ $string = '';
+ $expected = '';
+ $result = Sanitize::stripScripts($string);
+ $this->assertEqual($result, $expected);
+
+ $string = '';
+ $expected = '';
+ $result = Sanitize::stripScripts($string);
+ $this->assertEqual($result, $expected);
+
+ $string = <<
+
+
+text
+HTML;
+ $expected = "text\n\ntext";
+ $result = Sanitize::stripScripts($string);
+ $this->assertEqual($result, $expected);
+
+ $string = <<
+
+
+text
+HTML;
+ $expected = "text\n\ntext";
+ $result = Sanitize::stripScripts($string);
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testStripAll method
+ *
+ * @access public
+ * @return void
+ */
+ function testStripAll() {
+ $string = ' "/>';
+ $expected ='"/>';
+ $result = Sanitize::stripAll($string);
+ $this->assertEqual($result, $expected);
+
+ $string = ' ';
+ $expected = '';
+ $result = Sanitize::stripAll($string);
+ $this->assertEqual($result, $expected);
+
+ $string = '<';
+ $expected = '<';
+ $result = Sanitize::stripAll($string);
+ $this->assertEqual($result, $expected);
+
+ $string = ' '."\n".
+ "This is ok \t\n text
\n".
+ ' '."\n".
+ '';
+ $expected = 'This is ok text
';
+ $result = Sanitize::stripAll($string);
+ $this->assertEqual($result, $expected);
+
+ }
+
+/**
+ * testStripTags method
+ *
+ * @access public
+ * @return void
+ */
+ function testStripTags() {
+ $string = 'Headline My Link could go to a bad site
';
+ $expected = 'HeadlineMy Link could go to a bad site
';
+ $result = Sanitize::stripTags($string, 'h2', 'a');
+ $this->assertEqual($result, $expected);
+
+ $string = '';
+ $expected = ' ';
+ $result = Sanitize::stripTags($string, 'script');
+ $this->assertEqual($result, $expected);
+
+ $string = 'Important Additional information here . Read even more here
';
+ $expected = 'ImportantAdditional information here . Read even more here
';
+ $result = Sanitize::stripTags($string, 'h2', 'a');
+ $this->assertEqual($result, $expected);
+
+ $string = 'Important Additional information here . Read even more here
';
+ $expected = 'ImportantAdditional information here . Read even more here
';
+ $result = Sanitize::stripTags($string, 'h2', 'a', 'img');
+ $this->assertEqual($result, $expected);
+
+ $string = 'Important message! This message will self destruct!';
+ $expected = 'Important message! This message will self destruct!';
+ $result = Sanitize::stripTags($string, 'b');
+ $this->assertEqual($result, $expected);
+
+ $string = 'Important message! This message will self destruct!';
+ $expected = 'Important message! This message will self destruct!';
+ $result = Sanitize::stripTags($string, 'b');
+ $this->assertEqual($result, $expected);
+
+ $string = 'Important Additional information here . Read even more here
';
+ $expected = 'ImportantAdditional information here . Read even more here
';
+ $result = Sanitize::stripTags($string, 'h2', 'a', 'img');
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testFormatColumns method
+ *
+ * @access public
+ * @return void
+ */
+ function testFormatColumns() {
+ $this->loadFixtures('DataTest', 'Article');
+
+ $this->DataTest =& new SanitizeDataTest(array('alias' => 'DataTest'));
+ $data = array('DataTest' => array(
+ 'id' => 'z',
+ 'count' => '12a',
+ 'float' => '2.31456',
+ 'updated' => '2008-01-01'
+ )
+ );
+ $this->DataTest->set($data);
+ $expected = array('DataTest' => array(
+ 'id' => '0',
+ 'count' => '12',
+ 'float' => 2.31456,
+ 'updated' => '2008-01-01 00:00:00',
+ ));
+ Sanitize::formatColumns($this->DataTest);
+ $result = $this->DataTest->data;
+ $this->assertEqual($result, $expected);
+
+ $this->Article =& new SanitizeArticle(array('alias' => 'Article'));
+ $data = array('Article' => array(
+ 'id' => 'ZB',
+ 'user_id' => '12',
+ 'title' => 'title of article',
+ 'body' => 'body text',
+ 'published' => 'QQQQQQQ',
+ ));
+ $this->Article->set($data);
+ $expected = array('Article' => array(
+ 'id' => '0',
+ 'user_id' => '12',
+ 'title' => 'title of article',
+ 'body' => 'body text',
+ 'published' => 'QQQQQQQ',
+ ));
+ Sanitize::formatColumns($this->Article);
+ $result = $this->Article->data;
+ $this->assertEqual($result, $expected);
+ }
+}
diff --git a/code/ryzom/tools/server/www/webtt/cake/tests/cases/libs/security.test.php b/code/ryzom/tools/server/www/webtt/cake/tests/cases/libs/security.test.php
new file mode 100644
index 000000000..ec2819a62
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/cake/tests/cases/libs/security.test.php
@@ -0,0 +1,173 @@
+
+ * Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
+ *
+ * Licensed under The Open Group Test Suite License
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
+ * @link http://book.cakephp.org/view/1196/Testing CakePHP(tm) Tests
+ * @package cake
+ * @subpackage cake.tests.cases.libs
+ * @since CakePHP(tm) v 1.2.0.5432
+ * @license http://www.opensource.org/licenses/opengroup.php The Open Group Test Suite License
+ */
+App::import('Core', 'Security');
+
+/**
+ * SecurityTest class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs
+ */
+class SecurityTest extends CakeTestCase {
+
+/**
+ * sut property
+ *
+ * @var mixed null
+ * @access public
+ */
+ var $sut = null;
+
+/**
+ * setUp method
+ *
+ * @access public
+ * @return void
+ */
+ function setUp() {
+ $this->sut =& Security::getInstance();
+ }
+
+/**
+ * testInactiveMins method
+ *
+ * @access public
+ * @return void
+ */
+ function testInactiveMins() {
+ Configure::write('Security.level', 'high');
+ $this->assertEqual(10, Security::inactiveMins());
+
+ Configure::write('Security.level', 'medium');
+ $this->assertEqual(100, Security::inactiveMins());
+
+ Configure::write('Security.level', 'low');
+ $this->assertEqual(300, Security::inactiveMins());
+ }
+
+/**
+ * testGenerateAuthkey method
+ *
+ * @access public
+ * @return void
+ */
+ function testGenerateAuthkey() {
+ $this->assertEqual(strlen(Security::generateAuthKey()), 40);
+ }
+
+/**
+ * testValidateAuthKey method
+ *
+ * @access public
+ * @return void
+ */
+ function testValidateAuthKey() {
+ $authKey = Security::generateAuthKey();
+ $this->assertTrue(Security::validateAuthKey($authKey));
+ }
+
+/**
+ * testHash method
+ *
+ * @access public
+ * @return void
+ */
+ function testHash() {
+ $Security =& Security::getInstance();
+ $_hashType = $Security->hashType;
+
+ $key = 'someKey';
+ $hash = 'someHash';
+
+ $this->assertIdentical(strlen(Security::hash($key, null, false)), 40);
+ $this->assertIdentical(strlen(Security::hash($key, 'sha1', false)), 40);
+ $this->assertIdentical(strlen(Security::hash($key, null, true)), 40);
+ $this->assertIdentical(strlen(Security::hash($key, 'sha1', true)), 40);
+
+ $result = Security::hash($key, null, $hash);
+ $this->assertIdentical($result, 'e38fcb877dccb6a94729a81523851c931a46efb1');
+
+ $result = Security::hash($key, 'sha1', $hash);
+ $this->assertIdentical($result, 'e38fcb877dccb6a94729a81523851c931a46efb1');
+
+ $hashType = 'sha1';
+ Security::setHash($hashType);
+ $this->assertIdentical($this->sut->hashType, $hashType);
+ $this->assertIdentical(strlen(Security::hash($key, null, true)), 40);
+ $this->assertIdentical(strlen(Security::hash($key, null, false)), 40);
+
+ $this->assertIdentical(strlen(Security::hash($key, 'md5', false)), 32);
+ $this->assertIdentical(strlen(Security::hash($key, 'md5', true)), 32);
+
+ $hashType = 'md5';
+ Security::setHash($hashType);
+ $this->assertIdentical($this->sut->hashType, $hashType);
+ $this->assertIdentical(strlen(Security::hash($key, null, false)), 32);
+ $this->assertIdentical(strlen(Security::hash($key, null, true)), 32);
+
+ if (!function_exists('hash') && !function_exists('mhash')) {
+ $this->assertIdentical(strlen(Security::hash($key, 'sha256', false)), 32);
+ $this->assertIdentical(strlen(Security::hash($key, 'sha256', true)), 32);
+ } else {
+ $this->assertIdentical(strlen(Security::hash($key, 'sha256', false)), 64);
+ $this->assertIdentical(strlen(Security::hash($key, 'sha256', true)), 64);
+ }
+
+ Security::setHash($_hashType);
+ }
+
+/**
+ * testCipher method
+ *
+ * @access public
+ * @return void
+ */
+ function testCipher() {
+ $length = 10;
+ $txt = '';
+ for ($i = 0; $i < $length; $i++) {
+ $txt .= mt_rand(0, 255);
+ }
+ $key = 'my_key';
+ $result = Security::cipher($txt, $key);
+ $this->assertEqual(Security::cipher($result, $key), $txt);
+
+ $txt = '';
+ $key = 'my_key';
+ $result = Security::cipher($txt, $key);
+ $this->assertEqual(Security::cipher($result, $key), $txt);
+
+ $txt = 'some_text';
+ $key = '';
+ $result = Security::cipher($txt, $key);
+ $this->assertError();
+ $this->assertIdentical($result, '');
+
+ $txt = 123456;
+ $key = 'my_key';
+ $result = Security::cipher($txt, $key);
+ $this->assertEqual(Security::cipher($result, $key), $txt);
+
+ $txt = '123456';
+ $key = 'my_key';
+ $result = Security::cipher($txt, $key);
+ $this->assertEqual(Security::cipher($result, $key), $txt);
+ }
+}
diff --git a/code/ryzom/tools/server/www/webtt/cake/tests/cases/libs/set.test.php b/code/ryzom/tools/server/www/webtt/cake/tests/cases/libs/set.test.php
new file mode 100644
index 000000000..33ca7283e
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/cake/tests/cases/libs/set.test.php
@@ -0,0 +1,3098 @@
+
+ * Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
+ *
+ * Licensed under The Open Group Test Suite License
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
+ * @link http://book.cakephp.org/view/1196/Testing CakePHP(tm) Tests
+ * @package cake
+ * @subpackage cake.tests.cases.libs
+ * @since CakePHP(tm) v 1.2.0.4206
+ * @license http://www.opensource.org/licenses/opengroup.php The Open Group Test Suite License
+ */
+App::import('Core', 'Set');
+
+/**
+ * SetTest class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs
+ */
+class SetTest extends CakeTestCase {
+
+/**
+ * testNumericKeyExtraction method
+ *
+ * @access public
+ * @return void
+ */
+ function testNumericKeyExtraction() {
+ $data = array('plugin' => null, 'controller' => '', 'action' => '', 1, 'whatever');
+ $this->assertIdentical(Set::extract($data, '{n}'), array(1, 'whatever'));
+ $this->assertIdentical(Set::diff($data, Set::extract($data, '{n}')), array('plugin' => null, 'controller' => '', 'action' => ''));
+ }
+
+/**
+ * testEnum method
+ *
+ * @access public
+ * @return void
+ */
+ function testEnum() {
+ $result = Set::enum(1, 'one, two');
+ $this->assertIdentical($result, 'two');
+ $result = Set::enum(2, 'one, two');
+ $this->assertNull($result);
+
+ $set = array('one', 'two');
+ $result = Set::enum(0, $set);
+ $this->assertIdentical($result, 'one');
+ $result = Set::enum(1, $set);
+ $this->assertIdentical($result, 'two');
+
+ $result = Set::enum(1, array('one', 'two'));
+ $this->assertIdentical($result, 'two');
+ $result = Set::enum(2, array('one', 'two'));
+ $this->assertNull($result);
+
+ $result = Set::enum('first', array('first' => 'one', 'second' => 'two'));
+ $this->assertIdentical($result, 'one');
+ $result = Set::enum('third', array('first' => 'one', 'second' => 'two'));
+ $this->assertNull($result);
+
+ $result = Set::enum('no', array('no' => 0, 'yes' => 1));
+ $this->assertIdentical($result, 0);
+ $result = Set::enum('not sure', array('no' => 0, 'yes' => 1));
+ $this->assertNull($result);
+
+ $result = Set::enum(0);
+ $this->assertIdentical($result, 'no');
+ $result = Set::enum(1);
+ $this->assertIdentical($result, 'yes');
+ $result = Set::enum(2);
+ $this->assertNull($result);
+ }
+
+/**
+ * testFilter method
+ *
+ * @access public
+ * @return void
+ */
+ function testFilter() {
+ $result = Set::filter(array('0', false, true, 0, array('one thing', 'I can tell you', 'is you got to be', false)));
+ $expected = array('0', 2 => true, 3 => 0, 4 => array('one thing', 'I can tell you', 'is you got to be', false));
+ $this->assertIdentical($result, $expected);
+ }
+
+/**
+ * testNumericArrayCheck method
+ *
+ * @access public
+ * @return void
+ */
+ function testNumericArrayCheck() {
+ $data = array('one');
+ $this->assertTrue(Set::numeric(array_keys($data)));
+
+ $data = array(1 => 'one');
+ $this->assertFalse(Set::numeric($data));
+
+ $data = array('one');
+ $this->assertFalse(Set::numeric($data));
+
+ $data = array('one' => 'two');
+ $this->assertFalse(Set::numeric($data));
+
+ $data = array('one' => 1);
+ $this->assertTrue(Set::numeric($data));
+
+ $data = array(0);
+ $this->assertTrue(Set::numeric($data));
+
+ $data = array('one', 'two', 'three', 'four', 'five');
+ $this->assertTrue(Set::numeric(array_keys($data)));
+
+ $data = array(1 => 'one', 2 => 'two', 3 => 'three', 4 => 'four', 5 => 'five');
+ $this->assertTrue(Set::numeric(array_keys($data)));
+
+ $data = array('1' => 'one', 2 => 'two', 3 => 'three', 4 => 'four', 5 => 'five');
+ $this->assertTrue(Set::numeric(array_keys($data)));
+
+ $data = array('one', 2 => 'two', 3 => 'three', 4 => 'four', 'a' => 'five');
+ $this->assertFalse(Set::numeric(array_keys($data)));
+ }
+
+/**
+ * testKeyCheck method
+ *
+ * @access public
+ * @return void
+ */
+ function testKeyCheck() {
+ $data = array('Multi' => array('dimensonal' => array('array')));
+ $this->assertTrue(Set::check($data, 'Multi.dimensonal'));
+ $this->assertFalse(Set::check($data, 'Multi.dimensonal.array'));
+
+ $data = array(
+ array(
+ 'Article' => array('id' => '1', 'user_id' => '1', 'title' => 'First Article', 'body' => 'First Article Body', 'published' => 'Y', 'created' => '2007-03-18 10:39:23', 'updated' => '2007-03-18 10:41:31'),
+ 'User' => array('id' => '1', 'user' => 'mariano', 'password' => '5f4dcc3b5aa765d61d8327deb882cf99', 'created' => '2007-03-17 01:16:23', 'updated' => '2007-03-17 01:18:31'),
+ 'Comment' => array(
+ array('id' => '1', 'article_id' => '1', 'user_id' => '2', 'comment' => 'First Comment for First Article', 'published' => 'Y', 'created' => '2007-03-18 10:45:23', 'updated' => '2007-03-18 10:47:31'),
+ array('id' => '2', 'article_id' => '1', 'user_id' => '4', 'comment' => 'Second Comment for First Article', 'published' => 'Y', 'created' => '2007-03-18 10:47:23', 'updated' => '2007-03-18 10:49:31'),
+ ),
+ 'Tag' => array(
+ array('id' => '1', 'tag' => 'tag1', 'created' => '2007-03-18 12:22:23', 'updated' => '2007-03-18 12:24:31'),
+ array('id' => '2', 'tag' => 'tag2', 'created' => '2007-03-18 12:24:23', 'updated' => '2007-03-18 12:26:31')
+ )
+ ),
+ array(
+ 'Article' => array('id' => '3', 'user_id' => '1', 'title' => 'Third Article', 'body' => 'Third Article Body', 'published' => 'Y', 'created' => '2007-03-18 10:43:23', 'updated' => '2007-03-18 10:45:31'),
+ 'User' => array('id' => '1', 'user' => 'mariano', 'password' => '5f4dcc3b5aa765d61d8327deb882cf99', 'created' => '2007-03-17 01:16:23', 'updated' => '2007-03-17 01:18:31'),
+ 'Comment' => array(),
+ 'Tag' => array()
+ )
+ );
+ $this->assertTrue(Set::check($data, '0.Article.user_id'));
+ $this->assertTrue(Set::check($data, '0.Comment.0.id'));
+ $this->assertFalse(Set::check($data, '0.Comment.0.id.0'));
+ $this->assertTrue(Set::check($data, '0.Article.user_id'));
+ $this->assertFalse(Set::check($data, '0.Article.user_id.a'));
+ }
+
+/**
+ * testMerge method
+ *
+ * @access public
+ * @return void
+ */
+ function testMerge() {
+ $r = Set::merge(array('foo'));
+ $this->assertIdentical($r, array('foo'));
+
+ $r = Set::merge('foo');
+ $this->assertIdentical($r, array('foo'));
+
+ $r = Set::merge('foo', 'bar');
+ $this->assertIdentical($r, array('foo', 'bar'));
+
+ if (substr(PHP_VERSION, 0, 1) >= 5) {
+ $r = eval('class StaticSetCaller{static function merge($a, $b){return Set::merge($a, $b);}} return StaticSetCaller::merge("foo", "bar");');
+ $this->assertIdentical($r, array('foo', 'bar'));
+ }
+
+ $r = Set::merge('foo', array('user' => 'bob', 'no-bar'), 'bar');
+ $this->assertIdentical($r, array('foo', 'user' => 'bob', 'no-bar', 'bar'));
+
+ $a = array('foo', 'foo2');
+ $b = array('bar', 'bar2');
+ $this->assertIdentical(Set::merge($a, $b), array('foo', 'foo2', 'bar', 'bar2'));
+
+ $a = array('foo' => 'bar', 'bar' => 'foo');
+ $b = array('foo' => 'no-bar', 'bar' => 'no-foo');
+ $this->assertIdentical(Set::merge($a, $b), array('foo' => 'no-bar', 'bar' => 'no-foo'));
+
+ $a = array('users' => array('bob', 'jim'));
+ $b = array('users' => array('lisa', 'tina'));
+ $this->assertIdentical(Set::merge($a, $b), array('users' => array('bob', 'jim', 'lisa', 'tina')));
+
+ $a = array('users' => array('jim', 'bob'));
+ $b = array('users' => 'none');
+ $this->assertIdentical(Set::merge($a, $b), array('users' => 'none'));
+
+ $a = array('users' => array('lisa' => array('id' => 5, 'pw' => 'secret')), 'cakephp');
+ $b = array('users' => array('lisa' => array('pw' => 'new-pass', 'age' => 23)), 'ice-cream');
+ $this->assertIdentical(Set::merge($a, $b), array('users' => array('lisa' => array('id' => 5, 'pw' => 'new-pass', 'age' => 23)), 'cakephp', 'ice-cream'));
+
+ $c = array('users' => array('lisa' => array('pw' => 'you-will-never-guess', 'age' => 25, 'pet' => 'dog')), 'chocolate');
+ $expected = array('users' => array('lisa' => array('id' => 5, 'pw' => 'you-will-never-guess', 'age' => 25, 'pet' => 'dog')), 'cakephp', 'ice-cream', 'chocolate');
+ $this->assertIdentical(Set::merge($a, $b, $c), $expected);
+
+ $this->assertIdentical(Set::merge($a, $b, array(), $c), $expected);
+
+ $r = Set::merge($a, $b, $c);
+ $this->assertIdentical($r, $expected);
+
+ $a = array('Tree', 'CounterCache',
+ 'Upload' => array('folder' => 'products',
+ 'fields' => array('image_1_id', 'image_2_id', 'image_3_id', 'image_4_id', 'image_5_id')));
+ $b = array('Cacheable' => array('enabled' => false),
+ 'Limit',
+ 'Bindable',
+ 'Validator',
+ 'Transactional');
+
+ $expected = array('Tree', 'CounterCache',
+ 'Upload' => array('folder' => 'products',
+ 'fields' => array('image_1_id', 'image_2_id', 'image_3_id', 'image_4_id', 'image_5_id')),
+ 'Cacheable' => array('enabled' => false),
+ 'Limit',
+ 'Bindable',
+ 'Validator',
+ 'Transactional');
+
+ $this->assertIdentical(Set::merge($a, $b), $expected);
+
+ $expected = array('Tree' => null, 'CounterCache' => null,
+ 'Upload' => array('folder' => 'products',
+ 'fields' => array('image_1_id', 'image_2_id', 'image_3_id', 'image_4_id', 'image_5_id')),
+ 'Cacheable' => array('enabled' => false),
+ 'Limit' => null,
+ 'Bindable' => null,
+ 'Validator' => null,
+ 'Transactional' => null);
+
+ $this->assertIdentical(Set::normalize(Set::merge($a, $b)), $expected);
+ }
+
+/**
+ * testSort method
+ *
+ * @access public
+ * @return void
+ */
+ function testSort() {
+ $a = array(
+ 0 => array('Person' => array('name' => 'Jeff'), 'Friend' => array(array('name' => 'Nate'))),
+ 1 => array('Person' => array('name' => 'Tracy'),'Friend' => array(array('name' => 'Lindsay')))
+ );
+ $b = array(
+ 0 => array('Person' => array('name' => 'Tracy'),'Friend' => array(array('name' => 'Lindsay'))),
+ 1 => array('Person' => array('name' => 'Jeff'), 'Friend' => array(array('name' => 'Nate')))
+
+ );
+ $a = Set::sort($a, '{n}.Friend.{n}.name', 'asc');
+ $this->assertIdentical($a, $b);
+
+ $b = array(
+ 0 => array('Person' => array('name' => 'Jeff'), 'Friend' => array(array('name' => 'Nate'))),
+ 1 => array('Person' => array('name' => 'Tracy'),'Friend' => array(array('name' => 'Lindsay')))
+ );
+ $a = array(
+ 0 => array('Person' => array('name' => 'Tracy'),'Friend' => array(array('name' => 'Lindsay'))),
+ 1 => array('Person' => array('name' => 'Jeff'), 'Friend' => array(array('name' => 'Nate')))
+
+ );
+ $a = Set::sort($a, '{n}.Friend.{n}.name', 'desc');
+ $this->assertIdentical($a, $b);
+
+ $a = array(
+ 0 => array('Person' => array('name' => 'Jeff'), 'Friend' => array(array('name' => 'Nate'))),
+ 1 => array('Person' => array('name' => 'Tracy'),'Friend' => array(array('name' => 'Lindsay'))),
+ 2 => array('Person' => array('name' => 'Adam'),'Friend' => array(array('name' => 'Bob')))
+ );
+ $b = array(
+ 0 => array('Person' => array('name' => 'Adam'),'Friend' => array(array('name' => 'Bob'))),
+ 1 => array('Person' => array('name' => 'Jeff'), 'Friend' => array(array('name' => 'Nate'))),
+ 2 => array('Person' => array('name' => 'Tracy'),'Friend' => array(array('name' => 'Lindsay')))
+ );
+ $a = Set::sort($a, '{n}.Person.name', 'asc');
+ $this->assertIdentical($a, $b);
+
+ $a = array(
+ array(7,6,4),
+ array(3,4,5),
+ array(3,2,1),
+ );
+
+ $b = array(
+ array(3,2,1),
+ array(3,4,5),
+ array(7,6,4),
+ );
+
+ $a = Set::sort($a, '{n}.{n}', 'asc');
+ $this->assertIdentical($a, $b);
+
+ $a = array(
+ array(7,6,4),
+ array(3,4,5),
+ array(3,2,array(1,1,1)),
+ );
+
+ $b = array(
+ array(3,2,array(1,1,1)),
+ array(3,4,5),
+ array(7,6,4),
+ );
+
+ $a = Set::sort($a, '{n}', 'asc');
+ $this->assertIdentical($a, $b);
+
+ $a = array(
+ 0 => array('Person' => array('name' => 'Jeff')),
+ 1 => array('Shirt' => array('color' => 'black'))
+ );
+ $b = array(
+ 0 => array('Shirt' => array('color' => 'black')),
+ 1 => array('Person' => array('name' => 'Jeff')),
+ );
+ $a = Set::sort($a, '{n}.Person.name', 'ASC');
+ $this->assertIdentical($a, $b);
+
+ $names = array(
+ array('employees' => array(array('name' => array('first' => 'John', 'last' => 'Doe')))),
+ array('employees' => array(array('name' => array('first' => 'Jane', 'last' => 'Doe')))),
+ array('employees' => array(array('name' => array()))),
+ array('employees' => array(array('name' => array())))
+ );
+ $result = Set::sort($names, '{n}.employees.0.name', 'asc', 1);
+ $expected = array(
+ array('employees' => array(array('name' => array('first' => 'John', 'last' => 'Doe')))),
+ array('employees' => array(array('name' => array('first' => 'Jane', 'last' => 'Doe')))),
+ array('employees' => array(array('name' => array()))),
+ array('employees' => array(array('name' => array())))
+ );
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * test sorting with out of order keys.
+ *
+ * @return void
+ */
+ function testSortWithOutOfOrderKeys() {
+ $data = array(
+ 9 => array('class' => 510, 'test2' => 2),
+ 1 => array('class' => 500, 'test2' => 1),
+ 2 => array('class' => 600, 'test2' => 2),
+ 5 => array('class' => 625, 'test2' => 4),
+ 0 => array('class' => 605, 'test2' => 3),
+ );
+ $expected = array(
+ array('class' => 500, 'test2' => 1),
+ array('class' => 510, 'test2' => 2),
+ array('class' => 600, 'test2' => 2),
+ array('class' => 605, 'test2' => 3),
+ array('class' => 625, 'test2' => 4),
+ );
+ $result = Set::sort($data, '{n}.class', 'asc');
+ $this->assertEqual($expected, $result);
+
+ $result = Set::sort($data, '{n}.test2', 'asc');
+ $this->assertEqual($expected, $result);
+ }
+
+/**
+ * testExtract method
+ *
+ * @access public
+ * @return void
+ */
+ function testExtract() {
+ $a = array(
+ array(
+ 'Article' => array('id' => '1', 'user_id' => '1', 'title' => 'First Article', 'body' => 'First Article Body', 'published' => 'Y', 'created' => '2007-03-18 10:39:23', 'updated' => '2007-03-18 10:41:31'),
+ 'User' => array('id' => '1', 'user' => 'mariano', 'password' => '5f4dcc3b5aa765d61d8327deb882cf99', 'created' => '2007-03-17 01:16:23', 'updated' => '2007-03-17 01:18:31'),
+ 'Comment' => array(
+ array('id' => '1', 'article_id' => '1', 'user_id' => '2', 'comment' => 'First Comment for First Article', 'published' => 'Y', 'created' => '2007-03-18 10:45:23', 'updated' => '2007-03-18 10:47:31'),
+ array('id' => '2', 'article_id' => '1', 'user_id' => '4', 'comment' => 'Second Comment for First Article', 'published' => 'Y', 'created' => '2007-03-18 10:47:23', 'updated' => '2007-03-18 10:49:31'),
+ ),
+ 'Tag' => array(
+ array('id' => '1', 'tag' => 'tag1', 'created' => '2007-03-18 12:22:23', 'updated' => '2007-03-18 12:24:31'),
+ array('id' => '2', 'tag' => 'tag2', 'created' => '2007-03-18 12:24:23', 'updated' => '2007-03-18 12:26:31')
+ ),
+ 'Deep' => array(
+ 'Nesting' => array(
+ 'test' => array(
+ 1 => 'foo',
+ 2 => array(
+ 'and' => array('more' => 'stuff')
+ )
+ )
+ )
+ )
+ ),
+ array(
+ 'Article' => array('id' => '3', 'user_id' => '1', 'title' => 'Third Article', 'body' => 'Third Article Body', 'published' => 'Y', 'created' => '2007-03-18 10:43:23', 'updated' => '2007-03-18 10:45:31'),
+ 'User' => array('id' => '2', 'user' => 'mariano', 'password' => '5f4dcc3b5aa765d61d8327deb882cf99', 'created' => '2007-03-17 01:16:23', 'updated' => '2007-03-17 01:18:31'),
+ 'Comment' => array(),
+ 'Tag' => array()
+ ),
+ array(
+ 'Article' => array('id' => '3', 'user_id' => '1', 'title' => 'Third Article', 'body' => 'Third Article Body', 'published' => 'Y', 'created' => '2007-03-18 10:43:23', 'updated' => '2007-03-18 10:45:31'),
+ 'User' => array('id' => '3', 'user' => 'mariano', 'password' => '5f4dcc3b5aa765d61d8327deb882cf99', 'created' => '2007-03-17 01:16:23', 'updated' => '2007-03-17 01:18:31'),
+ 'Comment' => array(),
+ 'Tag' => array()
+ ),
+ array(
+ 'Article' => array('id' => '3', 'user_id' => '1', 'title' => 'Third Article', 'body' => 'Third Article Body', 'published' => 'Y', 'created' => '2007-03-18 10:43:23', 'updated' => '2007-03-18 10:45:31'),
+ 'User' => array('id' => '4', 'user' => 'mariano', 'password' => '5f4dcc3b5aa765d61d8327deb882cf99', 'created' => '2007-03-17 01:16:23', 'updated' => '2007-03-17 01:18:31'),
+ 'Comment' => array(),
+ 'Tag' => array()
+ ),
+ array(
+ 'Article' => array('id' => '3', 'user_id' => '1', 'title' => 'Third Article', 'body' => 'Third Article Body', 'published' => 'Y', 'created' => '2007-03-18 10:43:23', 'updated' => '2007-03-18 10:45:31'),
+ 'User' => array('id' => '5', 'user' => 'mariano', 'password' => '5f4dcc3b5aa765d61d8327deb882cf99', 'created' => '2007-03-17 01:16:23', 'updated' => '2007-03-17 01:18:31'),
+ 'Comment' => array(),
+ 'Tag' => array()
+ )
+ );
+ $b = array('Deep' => $a[0]['Deep']);
+ $c = array(
+ array('a' => array('I' => array('a' => 1))),
+ array(
+ 'a' => array(
+ 2
+ )
+ ),
+ array('a' => array('II' => array('a' => 3, 'III' => array('a' => array('foo' => 4))))),
+ );
+
+ $expected = array(array('a' => $c[2]['a']));
+ $r = Set::extract('/a/II[a=3]/..', $c);
+ $this->assertEqual($r, $expected);
+
+ $expected = array(1, 2, 3, 4, 5);
+ $this->assertEqual(Set::extract('/User/id', $a), $expected);
+
+ $expected = array(1, 2, 3, 4, 5);
+ $this->assertEqual(Set::extract('/User/id', $a), $expected);
+
+ $expected = array(
+ array('id' => 1), array('id' => 2), array('id' => 3), array('id' => 4), array('id' => 5)
+ );
+
+ $r = Set::extract('/User/id', $a, array('flatten' => false));
+ $this->assertEqual($r, $expected);
+
+ $expected = array(array('test' => $a[0]['Deep']['Nesting']['test']));
+ $this->assertEqual(Set::extract('/Deep/Nesting/test', $a), $expected);
+ $this->assertEqual(Set::extract('/Deep/Nesting/test', $b), $expected);
+
+ $expected = array(array('test' => $a[0]['Deep']['Nesting']['test']));
+ $r = Set::extract('/Deep/Nesting/test/1/..', $a);
+ $this->assertEqual($r, $expected);
+
+ $expected = array(array('test' => $a[0]['Deep']['Nesting']['test']));
+ $r = Set::extract('/Deep/Nesting/test/2/and/../..', $a);
+ $this->assertEqual($r, $expected);
+
+ $expected = array(array('test' => $a[0]['Deep']['Nesting']['test']));
+ $r = Set::extract('/Deep/Nesting/test/2/../../../Nesting/test/2/..', $a);
+ $this->assertEqual($r, $expected);
+
+ $expected = array(2);
+ $r = Set::extract('/User[2]/id', $a);
+ $this->assertEqual($r, $expected);
+
+ $expected = array(4, 5);
+ $r = Set::extract('/User[id>3]/id', $a);
+ $this->assertEqual($r, $expected);
+
+ $expected = array(2, 3);
+ $r = Set::extract('/User[id>1][id<=3]/id', $a);
+ $this->assertEqual($r, $expected);
+
+ $expected = array(array('I'), array('II'));
+ $r = Set::extract('/a/@*', $c);
+ $this->assertEqual($r, $expected);
+
+ $single = array(
+ 'User' => array(
+ 'id' => 4,
+ 'name' => 'Neo',
+ )
+ );
+ $tricky = array(
+ 0 => array(
+ 'User' => array(
+ 'id' => 1,
+ 'name' => 'John',
+ )
+ ),
+ 1 => array(
+ 'User' => array(
+ 'id' => 2,
+ 'name' => 'Bob',
+ )
+ ),
+ 2 => array(
+ 'User' => array(
+ 'id' => 3,
+ 'name' => 'Tony',
+ )
+ ),
+ 'User' => array(
+ 'id' => 4,
+ 'name' => 'Neo',
+ )
+ );
+
+ $expected = array(1, 2, 3, 4);
+ $r = Set::extract('/User/id', $tricky);
+ $this->assertEqual($r, $expected);
+
+ $expected = array(4);
+ $r = Set::extract('/User/id', $single);
+ $this->assertEqual($r, $expected);
+
+ $expected = array(1, 3);
+ $r = Set::extract('/User[name=/n/]/id', $tricky);
+ $this->assertEqual($r, $expected);
+
+ $expected = array(4);
+ $r = Set::extract('/User[name=/N/]/id', $tricky);
+ $this->assertEqual($r, $expected);
+
+ $expected = array(1, 3, 4);
+ $r = Set::extract('/User[name=/N/i]/id', $tricky);
+ $this->assertEqual($r, $expected);
+
+ $expected = array(array('id', 'name'), array('id', 'name'), array('id', 'name'), array('id', 'name'));
+ $r = Set::extract('/User/@*', $tricky);
+ $this->assertEqual($r, $expected);
+
+ $common = array(
+ array(
+ 'Article' => array(
+ 'id' => 1,
+ 'name' => 'Article 1',
+ ),
+ 'Comment' => array(
+ array(
+ 'id' => 1,
+ 'user_id' => 5,
+ 'article_id' => 1,
+ 'text' => 'Comment 1',
+ ),
+ array(
+ 'id' => 2,
+ 'user_id' => 23,
+ 'article_id' => 1,
+ 'text' => 'Comment 2',
+ ),
+ array(
+ 'id' => 3,
+ 'user_id' => 17,
+ 'article_id' => 1,
+ 'text' => 'Comment 3',
+ ),
+ ),
+ ),
+ array(
+ 'Article' => array(
+ 'id' => 2,
+ 'name' => 'Article 2',
+ ),
+ 'Comment' => array(
+ array(
+ 'id' => 4,
+ 'user_id' => 2,
+ 'article_id' => 2,
+ 'text' => 'Comment 4',
+ 'addition' => '',
+ ),
+ array(
+ 'id' => 5,
+ 'user_id' => 23,
+ 'article_id' => 2,
+ 'text' => 'Comment 5',
+ 'addition' => 'foo',
+ ),
+ ),
+ ),
+ array(
+ 'Article' => array(
+ 'id' => 3,
+ 'name' => 'Article 3',
+ ),
+ 'Comment' => array(),
+ )
+ );
+
+ $r = Set::extract('/Comment/id', $common);
+ $expected = array(1, 2, 3, 4, 5);
+ $this->assertEqual($r, $expected);
+
+ $expected = array(1, 2, 4, 5);
+ $r = Set::extract('/Comment[id!=3]/id', $common);
+ $this->assertEqual($r, $expected);
+
+ $r = Set::extract('/', $common);
+ $this->assertEqual($r, $common);
+
+ $expected = array(1, 2, 4, 5);
+ $r = Set::extract($common, '/Comment[id!=3]/id');
+ $this->assertEqual($r, $expected);
+
+ $expected = array($common[0]['Comment'][2]);
+ $r = Set::extract($common, '/Comment/2');
+ $this->assertEqual($r, $expected);
+
+ $expected = array($common[0]['Comment'][0]);
+ $r = Set::extract($common, '/Comment[1]/.[id=1]');
+ $this->assertEqual($r, $expected);
+
+ $expected = array($common[1]['Comment'][1]);
+ $r = Set::extract($common, '/1/Comment/.[2]');
+ $this->assertEqual($r, $expected);
+
+ $expected = array();
+ $r = Set::extract('/User/id', array());
+ $this->assertEqual($r, $expected);
+
+ $expected = array(5);
+ $r = Set::extract('/Comment/id[:last]', $common);
+ $this->assertEqual($r, $expected);
+
+ $expected = array(1);
+ $r = Set::extract('/Comment/id[:first]', $common);
+ $this->assertEqual($r, $expected);
+
+ $expected = array(3);
+ $r = Set::extract('/Article[:last]/id', $common);
+ $this->assertEqual($r, $expected);
+
+ $expected = array(array('Comment' => $common[1]['Comment'][0]));
+ $r = Set::extract('/Comment[addition=]', $common);
+ $this->assertEqual($r, $expected);
+
+ $habtm = array(
+ array(
+ 'Post' => array(
+ 'id' => 1,
+ 'title' => 'great post',
+ ),
+ 'Comment' => array(
+ array(
+ 'id' => 1,
+ 'text' => 'foo',
+ 'User' => array(
+ 'id' => 1,
+ 'name' => 'bob'
+ ),
+ ),
+ array(
+ 'id' => 2,
+ 'text' => 'bar',
+ 'User' => array(
+ 'id' => 2,
+ 'name' => 'tod'
+ ),
+ ),
+ ),
+ ),
+ array(
+ 'Post' => array(
+ 'id' => 2,
+ 'title' => 'fun post',
+ ),
+ 'Comment' => array(
+ array(
+ 'id' => 3,
+ 'text' => '123',
+ 'User' => array(
+ 'id' => 3,
+ 'name' => 'dan'
+ ),
+ ),
+ array(
+ 'id' => 4,
+ 'text' => '987',
+ 'User' => array(
+ 'id' => 4,
+ 'name' => 'jim'
+ ),
+ ),
+ ),
+ ),
+ );
+
+ $r = Set::extract('/Comment/User[name=/bob|dan/]/..', $habtm);
+ $this->assertEqual($r[0]['Comment']['User']['name'], 'bob');
+ $this->assertEqual($r[1]['Comment']['User']['name'], 'dan');
+ $this->assertEqual(count($r), 2);
+
+ $r = Set::extract('/Comment/User[name=/bob|tod/]/..', $habtm);
+ $this->assertEqual($r[0]['Comment']['User']['name'], 'bob');
+
+ $this->assertEqual($r[1]['Comment']['User']['name'], 'tod');
+ $this->assertEqual(count($r), 2);
+
+ $tree = array(
+ array(
+ 'Category' => array('name' => 'Category 1'),
+ 'children' => array(array('Category' => array('name' => 'Category 1.1')))
+ ),
+ array(
+ 'Category' => array('name' => 'Category 2'),
+ 'children' => array(
+ array('Category' => array('name' => 'Category 2.1')),
+ array('Category' => array('name' => 'Category 2.2'))
+ )
+ ),
+ array(
+ 'Category' => array('name' => 'Category 3'),
+ 'children' => array(array('Category' => array('name' => 'Category 3.1')))
+ )
+ );
+
+ $expected = array(array('Category' => $tree[1]['Category']));
+ $r = Set::extract('/Category[name=Category 2]', $tree);
+ $this->assertEqual($r, $expected);
+
+ $expected = array(
+ array('Category' => $tree[1]['Category'], 'children' => $tree[1]['children'])
+ );
+ $r = Set::extract('/Category[name=Category 2]/..', $tree);
+ $this->assertEqual($r, $expected);
+
+ $expected = array(
+ array('children' => $tree[1]['children'][0]),
+ array('children' => $tree[1]['children'][1])
+ );
+ $r = Set::extract('/Category[name=Category 2]/../children', $tree);
+ $this->assertEqual($r, $expected);
+
+ $habtm = array(
+ array(
+ 'Post' => array(
+ 'id' => 1,
+ 'title' => 'great post',
+ ),
+ 'Comment' => array(
+ array(
+ 'id' => 1,
+ 'text' => 'foo',
+ 'User' => array(
+ 'id' => 1,
+ 'name' => 'bob'
+ ),
+ ),
+ array(
+ 'id' => 2,
+ 'text' => 'bar',
+ 'User' => array(
+ 'id' => 2,
+ 'name' => 'tod'
+ ),
+ ),
+ ),
+ ),
+ array(
+ 'Post' => array(
+ 'id' => 2,
+ 'title' => 'fun post',
+ ),
+ 'Comment' => array(
+ array(
+ 'id' => 3,
+ 'text' => '123',
+ 'User' => array(
+ 'id' => 3,
+ 'name' => 'dan'
+ ),
+ ),
+ array(
+ 'id' => 4,
+ 'text' => '987',
+ 'User' => array(
+ 'id' => 4,
+ 'name' => 'jim'
+ ),
+ ),
+ ),
+ ),
+ );
+
+ $r = Set::extract('/Comment/User[name=/\w+/]/..', $habtm);
+ $this->assertEqual($r[0]['Comment']['User']['name'], 'bob');
+ $this->assertEqual($r[1]['Comment']['User']['name'], 'tod');
+ $this->assertEqual($r[2]['Comment']['User']['name'], 'dan');
+ $this->assertEqual($r[3]['Comment']['User']['name'], 'dan');
+ $this->assertEqual(count($r), 4);
+
+ $r = Set::extract('/Comment/User[name=/[a-z]+/]/..', $habtm);
+ $this->assertEqual($r[0]['Comment']['User']['name'], 'bob');
+ $this->assertEqual($r[1]['Comment']['User']['name'], 'tod');
+ $this->assertEqual($r[2]['Comment']['User']['name'], 'dan');
+ $this->assertEqual($r[3]['Comment']['User']['name'], 'dan');
+ $this->assertEqual(count($r), 4);
+
+ $r = Set::extract('/Comment/User[name=/bob|dan/]/..', $habtm);
+ $this->assertEqual($r[0]['Comment']['User']['name'], 'bob');
+ $this->assertEqual($r[1]['Comment']['User']['name'], 'dan');
+ $this->assertEqual(count($r), 2);
+
+ $r = Set::extract('/Comment/User[name=/bob|tod/]/..', $habtm);
+ $this->assertEqual($r[0]['Comment']['User']['name'], 'bob');
+ $this->assertEqual($r[1]['Comment']['User']['name'], 'tod');
+ $this->assertEqual(count($r), 2);
+
+ $mixedKeys = array(
+ 'User' => array(
+ 0 => array(
+ 'id' => 4,
+ 'name' => 'Neo'
+ ),
+ 1 => array(
+ 'id' => 5,
+ 'name' => 'Morpheus'
+ ),
+ 'stringKey' => array()
+ )
+ );
+ $expected = array('Neo', 'Morpheus');
+ $r = Set::extract('/User/name', $mixedKeys);
+ $this->assertEqual($r, $expected);
+
+ $f = array(
+ array(
+ 'file' => array(
+ 'name' => 'zipfile.zip',
+ 'type' => 'application/zip',
+ 'tmp_name' => '/tmp/php178.tmp',
+ 'error' => 0,
+ 'size' => '564647'
+ )
+ ),
+ array(
+ 'file' => array(
+ 'name' => 'zipfile2.zip',
+ 'type' => 'application/x-zip-compressed',
+ 'tmp_name' => '/tmp/php179.tmp',
+ 'error' => 0,
+ 'size' => '354784'
+ )
+ ),
+ array(
+ 'file' => array(
+ 'name' => 'picture.jpg',
+ 'type' => 'image/jpeg',
+ 'tmp_name' => '/tmp/php180.tmp',
+ 'error' => 0,
+ 'size' => '21324'
+ )
+ )
+ );
+ $expected = array(array('name' => 'zipfile2.zip','type' => 'application/x-zip-compressed','tmp_name' => '/tmp/php179.tmp','error' => 0,'size' => '354784'));
+ $r = Set::extract('/file/.[type=application/x-zip-compressed]', $f);
+ $this->assertEqual($r, $expected);
+
+ $expected = array(array('name' => 'zipfile.zip','type' => 'application/zip','tmp_name' => '/tmp/php178.tmp','error' => 0,'size' => '564647'));
+ $r = Set::extract('/file/.[type=application/zip]', $f);
+ $this->assertEqual($r, $expected);
+
+ $f = array(
+ array(
+ 'file' => array(
+ 'name' => 'zipfile.zip',
+ 'type' => 'application/zip',
+ 'tmp_name' => '/tmp/php178.tmp',
+ 'error' => 0,
+ 'size' => '564647'
+ )
+ ),
+ array(
+ 'file' => array(
+ 'name' => 'zipfile2.zip',
+ 'type' => 'application/x zip compressed',
+ 'tmp_name' => '/tmp/php179.tmp',
+ 'error' => 0,
+ 'size' => '354784'
+ )
+ ),
+ array(
+ 'file' => array(
+ 'name' => 'picture.jpg',
+ 'type' => 'image/jpeg',
+ 'tmp_name' => '/tmp/php180.tmp',
+ 'error' => 0,
+ 'size' => '21324'
+ )
+ )
+ );
+ $expected = array(array('name' => 'zipfile2.zip','type' => 'application/x zip compressed','tmp_name' => '/tmp/php179.tmp','error' => 0,'size' => '354784'));
+ $r = Set::extract('/file/.[type=application/x zip compressed]', $f);
+ $this->assertEqual($r, $expected);
+
+ $expected = array(
+ array('name' => 'zipfile.zip','type' => 'application/zip','tmp_name' => '/tmp/php178.tmp','error' => 0,'size' => '564647'),
+ array('name' => 'zipfile2.zip','type' => 'application/x zip compressed','tmp_name' => '/tmp/php179.tmp','error' => 0,'size' => '354784')
+ );
+ $r = Set::extract('/file/.[tmp_name=/tmp\/php17/]', $f);
+ $this->assertEqual($r, $expected);
+
+ $hasMany = array(
+ 'Node' => array(
+ 'id' => 1,
+ 'name' => 'First',
+ 'state' => 50
+ ),
+ 'ParentNode' => array(
+ 0 => array(
+ 'id' => 2,
+ 'name' => 'Second',
+ 'state' => 60,
+ )
+ )
+ );
+ $result = Set::extract('/ParentNode/name', $hasMany);
+ $expected = array('Second');
+ $this->assertEqual($result, $expected);
+
+ $data = array(
+ array(
+ 'Category' => array(
+ 'id' => 1,
+ 'name' => 'First'
+ ),
+ 0 => array(
+ 'value' => 50
+ )
+ ),
+ array(
+ 'Category' => array(
+ 'id' => 2,
+ 'name' => 'Second'
+ ),
+ 0 => array(
+ 'value' => 60
+ )
+ )
+ );
+ $expected = array(
+ array(
+ 'Category' => array(
+ 'id' => 1,
+ 'name' => 'First'
+ ),
+ 0 => array(
+ 'value' => 50
+ )
+ )
+ );
+ $result = Set::extract('/Category[id=1]/..', $data);
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * test parent selectors with extract
+ *
+ * @return void
+ */
+ function testExtractParentSelector() {
+ $tree = array(
+ array(
+ 'Category' => array(
+ 'name' => 'Category 1'
+ ),
+ 'children' => array(
+ array(
+ 'Category' => array(
+ 'name' => 'Category 1.1'
+ )
+ )
+ )
+ ),
+ array(
+ 'Category' => array(
+ 'name' => 'Category 2'
+ ),
+ 'children' => array(
+ array(
+ 'Category' => array(
+ 'name' => 'Category 2.1'
+ )
+ ),
+ array(
+ 'Category' => array(
+ 'name' => 'Category 2.2'
+ )
+ ),
+ )
+ ),
+ array(
+ 'Category' => array(
+ 'name' => 'Category 3'
+ ),
+ 'children' => array(
+ array(
+ 'Category' => array(
+ 'name' => 'Category 3.1'
+ )
+ )
+ )
+ )
+ );
+ $expected = array(array('Category' => $tree[1]['Category']));
+ $r = Set::extract('/Category[name=Category 2]', $tree);
+ $this->assertEqual($r, $expected);
+
+ $expected = array(array('Category' => $tree[1]['Category'], 'children' => $tree[1]['children']));
+ $r = Set::extract('/Category[name=Category 2]/..', $tree);
+ $this->assertEqual($r, $expected);
+
+ $expected = array(array('children' => $tree[1]['children'][0]), array('children' => $tree[1]['children'][1]));
+ $r = Set::extract('/Category[name=Category 2]/../children', $tree);
+ $this->assertEqual($r, $expected);
+
+ $single = array(
+ array(
+ 'CallType' => array(
+ 'name' => 'Internal Voice'
+ ),
+ 'x' => array(
+ 'hour' => 7
+ )
+ )
+ );
+
+ $expected = array(7);
+ $r = Set::extract('/CallType[name=Internal Voice]/../x/hour', $single);
+ $this->assertEqual($r, $expected);
+
+ $multiple = array(
+ array(
+ 'CallType' => array(
+ 'name' => 'Internal Voice'
+ ),
+ 'x' => array(
+ 'hour' => 7
+ )
+ ),
+ array(
+ 'CallType' => array(
+ 'name' => 'Internal Voice'
+ ),
+ 'x' => array(
+ 'hour' => 2
+ )
+ ),
+ array(
+ 'CallType' => array(
+ 'name' => 'Internal Voice'
+ ),
+ 'x' => array(
+ 'hour' => 1
+ )
+ )
+ );
+
+ $expected = array(7,2,1);
+ $r = Set::extract('/CallType[name=Internal Voice]/../x/hour', $multiple);
+ $this->assertEqual($r, $expected);
+
+ $a = array(
+ 'Model' => array(
+ '0' => array(
+ 'id' => 18,
+ 'SubModelsModel' => array(
+ 'id' => 1,
+ 'submodel_id' => 66,
+ 'model_id' => 18,
+ 'type' => 1
+ ),
+ ),
+ '1' => array(
+ 'id' => 0,
+ 'SubModelsModel' => array(
+ 'id' => 2,
+ 'submodel_id' => 66,
+ 'model_id' => 0,
+ 'type' => 1
+ ),
+ ),
+ '2' => array(
+ 'id' => 17,
+ 'SubModelsModel' => array(
+ 'id' => 3,
+ 'submodel_id' => 66,
+ 'model_id' => 17,
+ 'type' => 2
+ ),
+ ),
+ '3' => array(
+ 'id' => 0,
+ 'SubModelsModel' => array(
+ 'id' => 4,
+ 'submodel_id' => 66,
+ 'model_id' => 0,
+ 'type' => 2
+ )
+ )
+ )
+ );
+
+ $expected = array(
+ array(
+ 'Model' => array(
+ 'id' => 17,
+ 'SubModelsModel' => array(
+ 'id' => 3,
+ 'submodel_id' => 66,
+ 'model_id' => 17,
+ 'type' => 2
+ ),
+ )
+ ),
+ array(
+ 'Model' => array(
+ 'id' => 0,
+ 'SubModelsModel' => array(
+ 'id' => 4,
+ 'submodel_id' => 66,
+ 'model_id' => 0,
+ 'type' => 2
+ )
+ )
+ )
+ );
+ $r = Set::extract('/Model/SubModelsModel[type=2]/..', $a);
+ $this->assertEqual($r, $expected);
+ }
+
+/**
+ * test that extract() still works when arrays don't contain a 0 index.
+ *
+ * @return void
+ */
+ function testExtractWithNonZeroArrays() {
+ $nonZero = array(
+ 1 => array(
+ 'User' => array(
+ 'id' => 1,
+ 'name' => 'John',
+ )
+ ),
+ 2 => array(
+ 'User' => array(
+ 'id' => 2,
+ 'name' => 'Bob',
+ )
+ ),
+ 3 => array(
+ 'User' => array(
+ 'id' => 3,
+ 'name' => 'Tony',
+ )
+ )
+ );
+ $expected = array(1, 2, 3);
+ $r = Set::extract('/User/id', $nonZero);
+ $this->assertEqual($r, $expected);
+
+ $expected = array(
+ array('User' => array('id' => 1, 'name' => 'John')),
+ array('User' => array('id' => 2, 'name' => 'Bob')),
+ array('User' => array('id' => 3, 'name' => 'Tony')),
+ );
+ $result = Set::extract('/User', $nonZero);
+ $this->assertEqual($result, $expected);
+
+ $nonSequential = array(
+ 'User' => array(
+ 0 => array('id' => 1),
+ 2 => array('id' => 2),
+ 6 => array('id' => 3),
+ 9 => array('id' => 4),
+ 3 => array('id' => 5),
+ ),
+ );
+
+ $nonZero = array(
+ 'User' => array(
+ 2 => array('id' => 1),
+ 4 => array('id' => 2),
+ 6 => array('id' => 3),
+ 9 => array('id' => 4),
+ 3 => array('id' => 5),
+ ),
+ );
+
+ $expected = array(1, 2, 3, 4, 5);
+ $this->assertEqual(Set::extract('/User/id', $nonSequential), $expected);
+
+ $result = Set::extract('/User/id', $nonZero);
+ $this->assertEqual($result, $expected, 'Failed non zero array key extract');
+
+ $expected = array(1, 2, 3, 4, 5);
+ $this->assertEqual(Set::extract('/User/id', $nonSequential), $expected);
+
+ $result = Set::extract('/User/id', $nonZero);
+ $this->assertEqual($result, $expected, 'Failed non zero array key extract');
+
+ $startingAtOne = array(
+ 'Article' => array(
+ 1 => array(
+ 'id' => 1,
+ 'approved' => 1,
+ ),
+ )
+ );
+
+ $expected = array(0 => array('Article' => array('id' => 1, 'approved' => 1)));
+ $result = Set::extract('/Article[approved=1]', $startingAtOne);
+ $this->assertEqual($result, $expected);
+
+ $items = array(
+ 240 => array(
+ 'A' => array(
+ 'field1' => 'a240',
+ 'field2' => 'a240',
+ ),
+ 'B' => array(
+ 'field1' => 'b240',
+ 'field2' => 'b240'
+ ),
+ )
+ );
+
+ $expected = array(
+ 0 => 'b240'
+ );
+
+ $result = Set::extract('/B/field1', $items);
+ $this->assertIdentical($result, $expected);
+ $this->assertIdentical($result, Set::extract('{n}.B.field1', $items));
+ }
+/**
+ * testExtractWithArrays method
+ *
+ * @access public
+ * @return void
+ */
+ function testExtractWithArrays() {
+ $data = array(
+ 'Level1' => array(
+ 'Level2' => array('test1', 'test2'),
+ 'Level2bis' => array('test3', 'test4')
+ )
+ );
+ $this->assertEqual(Set::extract('/Level1/Level2', $data), array(array('Level2' => array('test1', 'test2'))));
+ $this->assertEqual(Set::extract('/Level1/Level2bis', $data), array(array('Level2bis' => array('test3', 'test4'))));
+ }
+
+/**
+ * test extract() with elements that have non-array children.
+ *
+ * @return void
+ */
+ function testExtractWithNonArrayElements() {
+ $data = array(
+ 'node' => array(
+ array('foo'),
+ 'bar'
+ )
+ );
+ $result = Set::extract('/node', $data);
+ $expected = array(
+ array('node' => array('foo')),
+ 'bar'
+ );
+ $this->assertEqual($result, $expected);
+
+ $data = array(
+ 'node' => array(
+ 'foo' => array('bar'),
+ 'bar' => array('foo')
+ )
+ );
+ $result = Set::extract('/node', $data);
+ $expected = array(
+ array('foo' => array('bar')),
+ array('bar' => array('foo')),
+ );
+ $this->assertEqual($result, $expected);
+
+ $data = array(
+ 'node' => array(
+ 'foo' => array(
+ 'bar'
+ ),
+ 'bar' => 'foo'
+ )
+ );
+ $result = Set::extract('/node', $data);
+ $expected = array(
+ array('foo' => array('bar')),
+ 'foo'
+ );
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testMatches method
+ *
+ * @access public
+ * @return void
+ */
+ function testMatches() {
+ $a = array(
+ array('Article' => array('id' => 1, 'title' => 'Article 1')),
+ array('Article' => array('id' => 2, 'title' => 'Article 2')),
+ array('Article' => array('id' => 3, 'title' => 'Article 3'))
+ );
+
+ $this->assertTrue(Set::matches(array('id=2'), $a[1]['Article']));
+ $this->assertFalse(Set::matches(array('id>2'), $a[1]['Article']));
+ $this->assertTrue(Set::matches(array('id>=2'), $a[1]['Article']));
+ $this->assertFalse(Set::matches(array('id>=3'), $a[1]['Article']));
+ $this->assertTrue(Set::matches(array('id<=2'), $a[1]['Article']));
+ $this->assertFalse(Set::matches(array('id<2'), $a[1]['Article']));
+ $this->assertTrue(Set::matches(array('id>1'), $a[1]['Article']));
+ $this->assertTrue(Set::matches(array('id>1', 'id<3', 'id!=0'), $a[1]['Article']));
+
+ $this->assertTrue(Set::matches(array('3'), null, 3));
+ $this->assertTrue(Set::matches(array('5'), null, 5));
+
+ $this->assertTrue(Set::matches(array('id'), $a[1]['Article']));
+ $this->assertTrue(Set::matches(array('id', 'title'), $a[1]['Article']));
+ $this->assertFalse(Set::matches(array('non-existant'), $a[1]['Article']));
+
+ $this->assertTrue(Set::matches('/Article[id=2]', $a));
+ $this->assertFalse(Set::matches('/Article[id=4]', $a));
+ $this->assertTrue(Set::matches(array(), $a));
+
+ $r = array(
+ 'Attachment' => array(
+ 'keep' => array()
+ ),
+ 'Comment' => array(
+ 'keep' => array(
+ 'Attachment' => array(
+ 'fields' => array(
+ 0 => 'attachment',
+ ),
+ ),
+ )
+ ),
+ 'User' => array(
+ 'keep' => array()
+ ),
+ 'Article' => array(
+ 'keep' => array(
+ 'Comment' => array(
+ 'fields' => array(
+ 0 => 'comment',
+ 1 => 'published',
+ ),
+ ),
+ 'User' => array(
+ 'fields' => array(
+ 0 => 'user',
+ ),
+ ),
+ )
+ )
+ );
+
+ $this->assertTrue(Set::matches('/Article/keep/Comment', $r));
+ $this->assertEqual(Set::extract('/Article/keep/Comment/fields', $r), array('comment', 'published'));
+ $this->assertEqual(Set::extract('/Article/keep/User/fields', $r), array('user'));
+
+
+ }
+
+/**
+ * testSetExtractReturnsEmptyArray method
+ *
+ * @access public
+ * @return void
+ */
+ function testSetExtractReturnsEmptyArray() {
+
+ $this->assertIdentical(Set::extract(array(), '/Post/id'), array());
+
+ $this->assertIdentical(Set::extract('/Post/id', array()), array());
+
+ $this->assertIdentical(Set::extract('/Post/id', array(
+ array('Post' => array('name' => 'bob')),
+ array('Post' => array('name' => 'jim'))
+ )), array());
+
+ $this->assertIdentical(Set::extract(array(), 'Message.flash'), null);
+
+ }
+
+/**
+ * testClassicExtract method
+ *
+ * @access public
+ * @return void
+ */
+ function testClassicExtract() {
+ $a = array(
+ array('Article' => array('id' => 1, 'title' => 'Article 1')),
+ array('Article' => array('id' => 2, 'title' => 'Article 2')),
+ array('Article' => array('id' => 3, 'title' => 'Article 3'))
+ );
+
+ $result = Set::extract($a, '{n}.Article.id');
+ $expected = array( 1, 2, 3 );
+ $this->assertIdentical($result, $expected);
+
+ $result = Set::extract($a, '{n}.Article.title');
+ $expected = array( 'Article 1', 'Article 2', 'Article 3' );
+ $this->assertIdentical($result, $expected);
+
+ $result = Set::extract($a, '1.Article.title');
+ $expected = 'Article 2';
+ $this->assertIdentical($result, $expected);
+
+ $result = Set::extract($a, '3.Article.title');
+ $expected = null;
+ $this->assertIdentical($result, $expected);
+
+ $a = array(
+ array(
+ 'Article' => array('id' => 1, 'title' => 'Article 1',
+ 'User' => array('id' => 1, 'username' => 'mariano.iglesias'))
+ ),
+ array(
+ 'Article' => array('id' => 2, 'title' => 'Article 2',
+ 'User' => array('id' => 1, 'username' => 'mariano.iglesias'))
+ ),
+ array(
+ 'Article' => array('id' => 3, 'title' => 'Article 3',
+ 'User' => array('id' => 2, 'username' => 'phpnut'))
+ )
+ );
+
+ $result = Set::extract($a, '{n}.Article.User.username');
+ $expected = array( 'mariano.iglesias', 'mariano.iglesias', 'phpnut' );
+ $this->assertIdentical($result, $expected);
+
+ $a = array(
+ array('Article' => array('id' => 1, 'title' => 'Article 1',
+ 'Comment' => array(
+ array('id' => 10, 'title' => 'Comment 10'),
+ array('id' => 11, 'title' => 'Comment 11'),
+ array('id' => 12, 'title' => 'Comment 12')))),
+ array('Article' => array('id' => 2, 'title' => 'Article 2',
+ 'Comment' => array(
+ array('id' => 13, 'title' => 'Comment 13'),
+ array('id' => 14, 'title' => 'Comment 14')))),
+ array('Article' => array('id' => 3, 'title' => 'Article 3')));
+
+ $result = Set::extract($a, '{n}.Article.Comment.{n}.id');
+ $expected = array (array(10, 11, 12), array(13, 14), null);
+ $this->assertIdentical($result, $expected);
+
+ $result = Set::extract($a, '{n}.Article.Comment.{n}.title');
+ $expected = array(
+ array('Comment 10', 'Comment 11', 'Comment 12'),
+ array('Comment 13', 'Comment 14'),
+ null
+ );
+ $this->assertIdentical($result, $expected);
+
+ $a = array(array('1day' => '20 sales'), array('1day' => '2 sales'));
+ $result = Set::extract($a, '{n}.1day');
+ $expected = array('20 sales', '2 sales');
+ $this->assertIdentical($result, $expected);
+
+ $a = array(
+ 'pages' => array('name' => 'page'),
+ 'fruites' => array('name' => 'fruit'),
+ 0 => array('name' => 'zero')
+ );
+ $result = Set::extract($a, '{s}.name');
+ $expected = array('page','fruit');
+ $this->assertIdentical($result, $expected);
+
+ $a = array(
+ 0 => array('pages' => array('name' => 'page')),
+ 1 => array('fruites'=> array('name' => 'fruit')),
+ 'test' => array(array('name' => 'jippi')),
+ 'dot.test' => array(array('name' => 'jippi'))
+ );
+
+ $result = Set::extract($a, '{n}.{s}.name');
+ $expected = array(0 => array('page'), 1 => array('fruit'));
+ $this->assertIdentical($result, $expected);
+
+ $result = Set::extract($a, '{s}.{n}.name');
+ $expected = array(array('jippi'), array('jippi'));
+ $this->assertIdentical($result, $expected);
+
+ $result = Set::extract($a,'{\w+}.{\w+}.name');
+ $expected = array(
+ array('pages' => 'page'),
+ array('fruites' => 'fruit'),
+ 'test' => array('jippi'),
+ 'dot.test' => array('jippi')
+ );
+ $this->assertIdentical($result, $expected);
+
+ $result = Set::extract($a,'{\d+}.{\w+}.name');
+ $expected = array(array('pages' => 'page'), array('fruites' => 'fruit'));
+ $this->assertIdentical($result, $expected);
+
+ $result = Set::extract($a,'{n}.{\w+}.name');
+ $expected = array(array('pages' => 'page'), array('fruites' => 'fruit'));
+ $this->assertIdentical($result, $expected);
+
+ $result = Set::extract($a,'{s}.{\d+}.name');
+ $expected = array(array('jippi'), array('jippi'));
+ $this->assertIdentical($result, $expected);
+
+ $result = Set::extract($a,'{s}');
+ $expected = array(array(array('name' => 'jippi')), array(array('name' => 'jippi')));
+ $this->assertIdentical($result, $expected);
+
+ $result = Set::extract($a,'{[a-z]}');
+ $expected = array(
+ 'test' => array(array('name' => 'jippi')),
+ 'dot.test' => array(array('name' => 'jippi'))
+ );
+ $this->assertIdentical($result, $expected);
+
+ $result = Set::extract($a, '{dot\.test}.{n}');
+ $expected = array('dot.test' => array(array('name' => 'jippi')));
+ $this->assertIdentical($result, $expected);
+
+ $a = new stdClass();
+ $a->articles = array(
+ array('Article' => array('id' => 1, 'title' => 'Article 1')),
+ array('Article' => array('id' => 2, 'title' => 'Article 2')),
+ array('Article' => array('id' => 3, 'title' => 'Article 3')));
+
+ $result = Set::extract($a, 'articles.{n}.Article.id');
+ $expected = array( 1, 2, 3 );
+ $this->assertIdentical($result, $expected);
+
+ $result = Set::extract($a, 'articles.{n}.Article.title');
+ $expected = array( 'Article 1', 'Article 2', 'Article 3' );
+ $this->assertIdentical($result, $expected);
+ }
+
+/**
+ * testInsert method
+ *
+ * @access public
+ * @return void
+ */
+ function testInsert() {
+ $a = array(
+ 'pages' => array('name' => 'page')
+ );
+
+ $result = Set::insert($a, 'files', array('name' => 'files'));
+ $expected = array(
+ 'pages' => array('name' => 'page'),
+ 'files' => array('name' => 'files')
+ );
+ $this->assertIdentical($result, $expected);
+
+ $a = array(
+ 'pages' => array('name' => 'page')
+ );
+ $result = Set::insert($a, 'pages.name', array());
+ $expected = array(
+ 'pages' => array('name' => array()),
+ );
+ $this->assertIdentical($result, $expected);
+
+ $a = array(
+ 'pages' => array(
+ 0 => array('name' => 'main'),
+ 1 => array('name' => 'about')
+ )
+ );
+
+ $result = Set::insert($a, 'pages.1.vars', array('title' => 'page title'));
+ $expected = array(
+ 'pages' => array(
+ 0 => array('name' => 'main'),
+ 1 => array('name' => 'about', 'vars' => array('title' => 'page title'))
+ )
+ );
+ $this->assertIdentical($result, $expected);
+ }
+
+/**
+ * testRemove method
+ *
+ * @access public
+ * @return void
+ */
+ function testRemove() {
+ $a = array(
+ 'pages' => array('name' => 'page'),
+ 'files' => array('name' => 'files')
+ );
+
+ $result = Set::remove($a, 'files', array('name' => 'files'));
+ $expected = array(
+ 'pages' => array('name' => 'page')
+ );
+ $this->assertIdentical($result, $expected);
+
+ $a = array(
+ 'pages' => array(
+ 0 => array('name' => 'main'),
+ 1 => array('name' => 'about', 'vars' => array('title' => 'page title'))
+ )
+ );
+
+ $result = Set::remove($a, 'pages.1.vars', array('title' => 'page title'));
+ $expected = array(
+ 'pages' => array(
+ 0 => array('name' => 'main'),
+ 1 => array('name' => 'about')
+ )
+ );
+ $this->assertIdentical($result, $expected);
+
+ $result = Set::remove($a, 'pages.2.vars', array('title' => 'page title'));
+ $expected = $a;
+ $this->assertIdentical($result, $expected);
+ }
+
+/**
+ * testCheck method
+ *
+ * @access public
+ * @return void
+ */
+ function testCheck() {
+ $set = array(
+ 'My Index 1' => array('First' => 'The first item')
+ );
+ $this->assertTrue(Set::check($set, 'My Index 1.First'));
+ $this->assertTrue(Set::check($set, 'My Index 1'));
+ $this->assertTrue(Set::check($set, array()));
+
+ $set = array(
+ 'My Index 1' => array('First' => array('Second' => array('Third' => array('Fourth' => 'Heavy. Nesting.'))))
+ );
+ $this->assertTrue(Set::check($set, 'My Index 1.First.Second'));
+ $this->assertTrue(Set::check($set, 'My Index 1.First.Second.Third'));
+ $this->assertTrue(Set::check($set, 'My Index 1.First.Second.Third.Fourth'));
+ $this->assertFalse(Set::check($set, 'My Index 1.First.Seconds.Third.Fourth'));
+ }
+
+/**
+ * testWritingWithFunkyKeys method
+ *
+ * @access public
+ * @return void
+ */
+ function testWritingWithFunkyKeys() {
+ $set = Set::insert(array(), 'Session Test', "test");
+ $this->assertEqual(Set::extract($set, 'Session Test'), 'test');
+
+ $set = Set::remove($set, 'Session Test');
+ $this->assertFalse(Set::check($set, 'Session Test'));
+
+ $this->assertTrue($set = Set::insert(array(), 'Session Test.Test Case', "test"));
+ $this->assertTrue(Set::check($set, 'Session Test.Test Case'));
+ }
+
+/**
+ * testDiff method
+ *
+ * @access public
+ * @return void
+ */
+ function testDiff() {
+ $a = array(
+ 0 => array('name' => 'main'),
+ 1 => array('name' => 'about')
+ );
+ $b = array(
+ 0 => array('name' => 'main'),
+ 1 => array('name' => 'about'),
+ 2 => array('name' => 'contact')
+ );
+
+ $result = Set::diff($a, $b);
+ $expected = array(
+ 2 => array('name' => 'contact')
+ );
+ $this->assertIdentical($result, $expected);
+
+ $result = Set::diff($a, array());
+ $expected = $a;
+ $this->assertIdentical($result, $expected);
+
+ $result = Set::diff(array(), $b);
+ $expected = $b;
+ $this->assertIdentical($result, $expected);
+
+ $b = array(
+ 0 => array('name' => 'me'),
+ 1 => array('name' => 'about')
+ );
+
+ $result = Set::diff($a, $b);
+ $expected = array(
+ 0 => array('name' => 'main')
+ );
+ $this->assertIdentical($result, $expected);
+
+ $a = array();
+ $b = array('name' => 'bob', 'address' => 'home');
+ $result = Set::diff($a, $b);
+ $this->assertIdentical($result, $b);
+
+
+ $a = array('name' => 'bob', 'address' => 'home');
+ $b = array();
+ $result = Set::diff($a, $b);
+ $this->assertIdentical($result, $a);
+
+ $a = array('key' => true, 'another' => false, 'name' => 'me');
+ $b = array('key' => 1, 'another' => 0);
+ $expected = array('name' => 'me');
+ $result = Set::diff($a, $b);
+ $this->assertIdentical($result, $expected);
+
+ $a = array('key' => 'value', 'another' => null, 'name' => 'me');
+ $b = array('key' => 'differentValue', 'another' => null);
+ $expected = array('key' => 'value', 'name' => 'me');
+ $result = Set::diff($a, $b);
+ $this->assertIdentical($result, $expected);
+
+ $a = array('key' => 'value', 'another' => null, 'name' => 'me');
+ $b = array('key' => 'differentValue', 'another' => 'value');
+ $expected = array('key' => 'value', 'another' => null, 'name' => 'me');
+ $result = Set::diff($a, $b);
+ $this->assertIdentical($result, $expected);
+
+ $a = array('key' => 'value', 'another' => null, 'name' => 'me');
+ $b = array('key' => 'differentValue', 'another' => 'value');
+ $expected = array('key' => 'differentValue', 'another' => 'value', 'name' => 'me');
+ $result = Set::diff($b, $a);
+ $this->assertIdentical($result, $expected);
+
+ $a = array('key' => 'value', 'another' => null, 'name' => 'me');
+ $b = array(0 => 'differentValue', 1 => 'value');
+ $expected = $a + $b;
+ $result = Set::diff($a, $b);
+ $this->assertIdentical($result, $expected);
+ }
+
+/**
+ * testContains method
+ *
+ * @access public
+ * @return void
+ */
+ function testContains() {
+ $a = array(
+ 0 => array('name' => 'main'),
+ 1 => array('name' => 'about')
+ );
+ $b = array(
+ 0 => array('name' => 'main'),
+ 1 => array('name' => 'about'),
+ 2 => array('name' => 'contact'),
+ 'a' => 'b'
+ );
+
+ $this->assertTrue(Set::contains($a, $a));
+ $this->assertFalse(Set::contains($a, $b));
+ $this->assertTrue(Set::contains($b, $a));
+ }
+
+/**
+ * testCombine method
+ *
+ * @access public
+ * @return void
+ */
+ function testCombine() {
+ $result = Set::combine(array(), '{n}.User.id', '{n}.User.Data');
+ $this->assertFalse($result);
+ $result = Set::combine('', '{n}.User.id', '{n}.User.Data');
+ $this->assertFalse($result);
+
+ $a = array(
+ array('User' => array('id' => 2, 'group_id' => 1,
+ 'Data' => array('user' => 'mariano.iglesias','name' => 'Mariano Iglesias'))),
+ array('User' => array('id' => 14, 'group_id' => 2,
+ 'Data' => array('user' => 'phpnut', 'name' => 'Larry E. Masters'))),
+ array('User' => array('id' => 25, 'group_id' => 1,
+ 'Data' => array('user' => 'gwoo','name' => 'The Gwoo'))));
+ $result = Set::combine($a, '{n}.User.id');
+ $expected = array(2 => null, 14 => null, 25 => null);
+ $this->assertIdentical($result, $expected);
+
+ $result = Set::combine($a, '{n}.User.id', '{n}.User.non-existant');
+ $expected = array(2 => null, 14 => null, 25 => null);
+ $this->assertIdentical($result, $expected);
+
+ $result = Set::combine($a, '{n}.User.id', '{n}.User.Data');
+ $expected = array(
+ 2 => array('user' => 'mariano.iglesias', 'name' => 'Mariano Iglesias'),
+ 14 => array('user' => 'phpnut', 'name' => 'Larry E. Masters'),
+ 25 => array('user' => 'gwoo', 'name' => 'The Gwoo'));
+ $this->assertIdentical($result, $expected);
+
+ $result = Set::combine($a, '{n}.User.id', '{n}.User.Data.name');
+ $expected = array(
+ 2 => 'Mariano Iglesias',
+ 14 => 'Larry E. Masters',
+ 25 => 'The Gwoo');
+ $this->assertIdentical($result, $expected);
+
+ $result = Set::combine($a, '{n}.User.id', '{n}.User.Data', '{n}.User.group_id');
+ $expected = array(
+ 1 => array(
+ 2 => array('user' => 'mariano.iglesias', 'name' => 'Mariano Iglesias'),
+ 25 => array('user' => 'gwoo', 'name' => 'The Gwoo')),
+ 2 => array(
+ 14 => array('user' => 'phpnut', 'name' => 'Larry E. Masters')));
+ $this->assertIdentical($result, $expected);
+
+ $result = Set::combine($a, '{n}.User.id', '{n}.User.Data.name', '{n}.User.group_id');
+ $expected = array(
+ 1 => array(
+ 2 => 'Mariano Iglesias',
+ 25 => 'The Gwoo'),
+ 2 => array(
+ 14 => 'Larry E. Masters'));
+ $this->assertIdentical($result, $expected);
+
+ $result = Set::combine($a, '{n}.User.id');
+ $expected = array(2 => null, 14 => null, 25 => null);
+ $this->assertIdentical($result, $expected);
+
+ $result = Set::combine($a, '{n}.User.id', '{n}.User.Data');
+ $expected = array(
+ 2 => array('user' => 'mariano.iglesias', 'name' => 'Mariano Iglesias'),
+ 14 => array('user' => 'phpnut', 'name' => 'Larry E. Masters'),
+ 25 => array('user' => 'gwoo', 'name' => 'The Gwoo'));
+ $this->assertIdentical($result, $expected);
+
+ $result = Set::combine($a, '{n}.User.id', '{n}.User.Data.name');
+ $expected = array(2 => 'Mariano Iglesias', 14 => 'Larry E. Masters', 25 => 'The Gwoo');
+ $this->assertIdentical($result, $expected);
+
+ $result = Set::combine($a, '{n}.User.id', '{n}.User.Data', '{n}.User.group_id');
+ $expected = array(
+ 1 => array(
+ 2 => array('user' => 'mariano.iglesias', 'name' => 'Mariano Iglesias'),
+ 25 => array('user' => 'gwoo', 'name' => 'The Gwoo')),
+ 2 => array(
+ 14 => array('user' => 'phpnut', 'name' => 'Larry E. Masters')));
+ $this->assertIdentical($result, $expected);
+
+ $result = Set::combine($a, '{n}.User.id', '{n}.User.Data.name', '{n}.User.group_id');
+ $expected = array(
+ 1 => array(
+ 2 => 'Mariano Iglesias',
+ 25 => 'The Gwoo'),
+ 2 => array(
+ 14 => 'Larry E. Masters'));
+ $this->assertIdentical($result, $expected);
+
+ $result = Set::combine($a, '{n}.User.id', array('{0}: {1}', '{n}.User.Data.user', '{n}.User.Data.name'), '{n}.User.group_id');
+ $expected = array (
+ 1 => array (
+ 2 => 'mariano.iglesias: Mariano Iglesias',
+ 25 => 'gwoo: The Gwoo'),
+ 2 => array (14 => 'phpnut: Larry E. Masters'));
+ $this->assertIdentical($result, $expected);
+
+ $result = Set::combine($a, array('{0}: {1}', '{n}.User.Data.user', '{n}.User.Data.name'), '{n}.User.id');
+ $expected = array('mariano.iglesias: Mariano Iglesias' => 2, 'phpnut: Larry E. Masters' => 14, 'gwoo: The Gwoo' => 25);
+ $this->assertIdentical($result, $expected);
+
+ $result = Set::combine($a, array('{1}: {0}', '{n}.User.Data.user', '{n}.User.Data.name'), '{n}.User.id');
+ $expected = array('Mariano Iglesias: mariano.iglesias' => 2, 'Larry E. Masters: phpnut' => 14, 'The Gwoo: gwoo' => 25);
+ $this->assertIdentical($result, $expected);
+
+ $result = Set::combine($a, array('%1$s: %2$d', '{n}.User.Data.user', '{n}.User.id'), '{n}.User.Data.name');
+ $expected = array('mariano.iglesias: 2' => 'Mariano Iglesias', 'phpnut: 14' => 'Larry E. Masters', 'gwoo: 25' => 'The Gwoo');
+ $this->assertIdentical($result, $expected);
+
+ $result = Set::combine($a, array('%2$d: %1$s', '{n}.User.Data.user', '{n}.User.id'), '{n}.User.Data.name');
+ $expected = array('2: mariano.iglesias' => 'Mariano Iglesias', '14: phpnut' => 'Larry E. Masters', '25: gwoo' => 'The Gwoo');
+ $this->assertIdentical($result, $expected);
+
+ $b = new stdClass();
+ $b->users = array(
+ array('User' => array('id' => 2, 'group_id' => 1,
+ 'Data' => array('user' => 'mariano.iglesias','name' => 'Mariano Iglesias'))),
+ array('User' => array('id' => 14, 'group_id' => 2,
+ 'Data' => array('user' => 'phpnut', 'name' => 'Larry E. Masters'))),
+ array('User' => array('id' => 25, 'group_id' => 1,
+ 'Data' => array('user' => 'gwoo','name' => 'The Gwoo'))));
+ $result = Set::combine($b, 'users.{n}.User.id');
+ $expected = array(2 => null, 14 => null, 25 => null);
+ $this->assertIdentical($result, $expected);
+
+ $result = Set::combine($b, 'users.{n}.User.id', 'users.{n}.User.non-existant');
+ $expected = array(2 => null, 14 => null, 25 => null);
+ $this->assertIdentical($result, $expected);
+
+ $result = Set::combine($a, 'fail', 'fail');
+ $this->assertEqual($result, array());
+ }
+
+/**
+ * testMapReverse method
+ *
+ * @access public
+ * @return void
+ */
+ function testMapReverse() {
+ $result = Set::reverse(null);
+ $this->assertEqual($result, null);
+
+ $result = Set::reverse(false);
+ $this->assertEqual($result, false);
+
+ $expected = array(
+ 'Array1' => array(
+ 'Array1Data1' => 'Array1Data1 value 1', 'Array1Data2' => 'Array1Data2 value 2'),
+ 'Array2' => array(
+ 0 => array('Array2Data1' => 1, 'Array2Data2' => 'Array2Data2 value 2', 'Array2Data3' => 'Array2Data3 value 2', 'Array2Data4' => 'Array2Data4 value 4'),
+ 1 => array('Array2Data1' => 2, 'Array2Data2' => 'Array2Data2 value 2', 'Array2Data3' => 'Array2Data3 value 2', 'Array2Data4' => 'Array2Data4 value 4'),
+ 2 => array('Array2Data1' => 3, 'Array2Data2' => 'Array2Data2 value 2', 'Array2Data3' => 'Array2Data3 value 2', 'Array2Data4' => 'Array2Data4 value 4'),
+ 3 => array('Array2Data1' => 4, 'Array2Data2' => 'Array2Data2 value 2', 'Array2Data3' => 'Array2Data3 value 2', 'Array2Data4' => 'Array2Data4 value 4'),
+ 4 => array('Array2Data1' => 5, 'Array2Data2' => 'Array2Data2 value 2', 'Array2Data3' => 'Array2Data3 value 2', 'Array2Data4' => 'Array2Data4 value 4')),
+ 'Array3' => array(
+ 0 => array('Array3Data1' => 1, 'Array3Data2' => 'Array3Data2 value 2', 'Array3Data3' => 'Array3Data3 value 2', 'Array3Data4' => 'Array3Data4 value 4'),
+ 1 => array('Array3Data1' => 2, 'Array3Data2' => 'Array3Data2 value 2', 'Array3Data3' => 'Array3Data3 value 2', 'Array3Data4' => 'Array3Data4 value 4'),
+ 2 => array('Array3Data1' => 3, 'Array3Data2' => 'Array3Data2 value 2', 'Array3Data3' => 'Array3Data3 value 2', 'Array3Data4' => 'Array3Data4 value 4'),
+ 3 => array('Array3Data1' => 4, 'Array3Data2' => 'Array3Data2 value 2', 'Array3Data3' => 'Array3Data3 value 2', 'Array3Data4' => 'Array3Data4 value 4'),
+ 4 => array('Array3Data1' => 5, 'Array3Data2' => 'Array3Data2 value 2', 'Array3Data3' => 'Array3Data3 value 2', 'Array3Data4' => 'Array3Data4 value 4')));
+ $map = Set::map($expected, true);
+ $this->assertEqual($map->Array1->Array1Data1, $expected['Array1']['Array1Data1']);
+ $this->assertEqual($map->Array2[0]->Array2Data1, $expected['Array2'][0]['Array2Data1']);
+
+ $result = Set::reverse($map);
+ $this->assertIdentical($result, $expected);
+
+ $expected = array(
+ 'Post' => array('id'=> 1, 'title' => 'First Post'),
+ 'Comment' => array(
+ array('id'=> 1, 'title' => 'First Comment'),
+ array('id'=> 2, 'title' => 'Second Comment')
+ ),
+ 'Tag' => array(
+ array('id'=> 1, 'title' => 'First Tag'),
+ array('id'=> 2, 'title' => 'Second Tag')
+ ),
+ );
+ $map = Set::map($expected);
+ $this->assertIdentical($map->title, $expected['Post']['title']);
+ foreach ($map->Comment as $comment) {
+ $ids[] = $comment->id;
+ }
+ $this->assertIdentical($ids, array(1, 2));
+
+ $expected = array(
+ 'Array1' => array(
+ 'Array1Data1' => 'Array1Data1 value 1', 'Array1Data2' => 'Array1Data2 value 2', 'Array1Data3' => 'Array1Data3 value 3','Array1Data4' => 'Array1Data4 value 4',
+ 'Array1Data5' => 'Array1Data5 value 5', 'Array1Data6' => 'Array1Data6 value 6', 'Array1Data7' => 'Array1Data7 value 7', 'Array1Data8' => 'Array1Data8 value 8'),
+ 'string' => 1,
+ 'another' => 'string',
+ 'some' => 'thing else',
+ 'Array2' => array(
+ 0 => array('Array2Data1' => 1, 'Array2Data2' => 'Array2Data2 value 2', 'Array2Data3' => 'Array2Data3 value 2', 'Array2Data4' => 'Array2Data4 value 4'),
+ 1 => array('Array2Data1' => 2, 'Array2Data2' => 'Array2Data2 value 2', 'Array2Data3' => 'Array2Data3 value 2', 'Array2Data4' => 'Array2Data4 value 4'),
+ 2 => array('Array2Data1' => 3, 'Array2Data2' => 'Array2Data2 value 2', 'Array2Data3' => 'Array2Data3 value 2', 'Array2Data4' => 'Array2Data4 value 4'),
+ 3 => array('Array2Data1' => 4, 'Array2Data2' => 'Array2Data2 value 2', 'Array2Data3' => 'Array2Data3 value 2', 'Array2Data4' => 'Array2Data4 value 4'),
+ 4 => array('Array2Data1' => 5, 'Array2Data2' => 'Array2Data2 value 2', 'Array2Data3' => 'Array2Data3 value 2', 'Array2Data4' => 'Array2Data4 value 4')),
+ 'Array3' => array(
+ 0 => array('Array3Data1' => 1, 'Array3Data2' => 'Array3Data2 value 2', 'Array3Data3' => 'Array3Data3 value 2', 'Array3Data4' => 'Array3Data4 value 4'),
+ 1 => array('Array3Data1' => 2, 'Array3Data2' => 'Array3Data2 value 2', 'Array3Data3' => 'Array3Data3 value 2', 'Array3Data4' => 'Array3Data4 value 4'),
+ 2 => array('Array3Data1' => 3, 'Array3Data2' => 'Array3Data2 value 2', 'Array3Data3' => 'Array3Data3 value 2', 'Array3Data4' => 'Array3Data4 value 4'),
+ 3 => array('Array3Data1' => 4, 'Array3Data2' => 'Array3Data2 value 2', 'Array3Data3' => 'Array3Data3 value 2', 'Array3Data4' => 'Array3Data4 value 4'),
+ 4 => array('Array3Data1' => 5, 'Array3Data2' => 'Array3Data2 value 2', 'Array3Data3' => 'Array3Data3 value 2', 'Array3Data4' => 'Array3Data4 value 4')));
+ $map = Set::map($expected, true);
+ $result = Set::reverse($map);
+ $this->assertIdentical($result, $expected);
+
+ $expected = array(
+ 'Array1' => array(
+ 'Array1Data1' => 'Array1Data1 value 1', 'Array1Data2' => 'Array1Data2 value 2', 'Array1Data3' => 'Array1Data3 value 3','Array1Data4' => 'Array1Data4 value 4',
+ 'Array1Data5' => 'Array1Data5 value 5', 'Array1Data6' => 'Array1Data6 value 6', 'Array1Data7' => 'Array1Data7 value 7', 'Array1Data8' => 'Array1Data8 value 8'),
+ 'string' => 1,
+ 'another' => 'string',
+ 'some' => 'thing else',
+ 'Array2' => array(
+ 0 => array('Array2Data1' => 1, 'Array2Data2' => 'Array2Data2 value 2', 'Array2Data3' => 'Array2Data3 value 2', 'Array2Data4' => 'Array2Data4 value 4'),
+ 1 => array('Array2Data1' => 2, 'Array2Data2' => 'Array2Data2 value 2', 'Array2Data3' => 'Array2Data3 value 2', 'Array2Data4' => 'Array2Data4 value 4'),
+ 2 => array('Array2Data1' => 3, 'Array2Data2' => 'Array2Data2 value 2', 'Array2Data3' => 'Array2Data3 value 2', 'Array2Data4' => 'Array2Data4 value 4'),
+ 3 => array('Array2Data1' => 4, 'Array2Data2' => 'Array2Data2 value 2', 'Array2Data3' => 'Array2Data3 value 2', 'Array2Data4' => 'Array2Data4 value 4'),
+ 4 => array('Array2Data1' => 5, 'Array2Data2' => 'Array2Data2 value 2', 'Array2Data3' => 'Array2Data3 value 2', 'Array2Data4' => 'Array2Data4 value 4')),
+ 'string2' => 1,
+ 'another2' => 'string',
+ 'some2' => 'thing else',
+ 'Array3' => array(
+ 0 => array('Array3Data1' => 1, 'Array3Data2' => 'Array3Data2 value 2', 'Array3Data3' => 'Array3Data3 value 2', 'Array3Data4' => 'Array3Data4 value 4'),
+ 1 => array('Array3Data1' => 2, 'Array3Data2' => 'Array3Data2 value 2', 'Array3Data3' => 'Array3Data3 value 2', 'Array3Data4' => 'Array3Data4 value 4'),
+ 2 => array('Array3Data1' => 3, 'Array3Data2' => 'Array3Data2 value 2', 'Array3Data3' => 'Array3Data3 value 2', 'Array3Data4' => 'Array3Data4 value 4'),
+ 3 => array('Array3Data1' => 4, 'Array3Data2' => 'Array3Data2 value 2', 'Array3Data3' => 'Array3Data3 value 2', 'Array3Data4' => 'Array3Data4 value 4'),
+ 4 => array('Array3Data1' => 5, 'Array3Data2' => 'Array3Data2 value 2', 'Array3Data3' => 'Array3Data3 value 2', 'Array3Data4' => 'Array3Data4 value 4')),
+ 'string3' => 1,
+ 'another3' => 'string',
+ 'some3' => 'thing else');
+ $map = Set::map($expected, true);
+ $result = Set::reverse($map);
+ $this->assertIdentical($result, $expected);
+
+ $expected = array('User' => array('psword'=> 'whatever', 'Icon' => array('id'=> 851)));
+ $map = Set::map($expected);
+ $result = Set::reverse($map);
+ $this->assertIdentical($result, $expected);
+
+ $expected = array('User' => array('psword'=> 'whatever', 'Icon' => array('id'=> 851)));
+ $class = new stdClass;
+ $class->User = new stdClass;
+ $class->User->psword = 'whatever';
+ $class->User->Icon = new stdClass;
+ $class->User->Icon->id = 851;
+ $result = Set::reverse($class);
+ $this->assertIdentical($result, $expected);
+
+ $expected = array('User' => array('psword'=> 'whatever', 'Icon' => array('id'=> 851), 'Profile' => array('name' => 'Some Name', 'address' => 'Some Address')));
+ $class = new stdClass;
+ $class->User = new stdClass;
+ $class->User->psword = 'whatever';
+ $class->User->Icon = new stdClass;
+ $class->User->Icon->id = 851;
+ $class->User->Profile = new stdClass;
+ $class->User->Profile->name = 'Some Name';
+ $class->User->Profile->address = 'Some Address';
+
+ $result = Set::reverse($class);
+ $this->assertIdentical($result, $expected);
+
+ $expected = array('User' => array('psword'=> 'whatever',
+ 'Icon' => array('id'=> 851),
+ 'Profile' => array('name' => 'Some Name', 'address' => 'Some Address'),
+ 'Comment' => array(
+ array('id' => 1, 'article_id' => 1, 'user_id' => 1, 'comment' => 'First Comment for First Article', 'published' => 'Y', 'created' => '2007-03-18 10:47:23', 'updated' => '2007-03-18 10:49:31'),
+ array('id' => 2, 'article_id' => 1, 'user_id' => 2, 'comment' => 'Second Comment for First Article', 'published' => 'Y', 'created' => '2007-03-18 10:47:23', 'updated' => '2007-03-18 10:49:31'))));
+
+ $class = new stdClass;
+ $class->User = new stdClass;
+ $class->User->psword = 'whatever';
+ $class->User->Icon = new stdClass;
+ $class->User->Icon->id = 851;
+ $class->User->Profile = new stdClass;
+ $class->User->Profile->name = 'Some Name';
+ $class->User->Profile->address = 'Some Address';
+ $class->User->Comment = new stdClass;
+ $class->User->Comment->{'0'} = new stdClass;
+ $class->User->Comment->{'0'}->id = 1;
+ $class->User->Comment->{'0'}->article_id = 1;
+ $class->User->Comment->{'0'}->user_id = 1;
+ $class->User->Comment->{'0'}->comment = 'First Comment for First Article';
+ $class->User->Comment->{'0'}->published = 'Y';
+ $class->User->Comment->{'0'}->created = '2007-03-18 10:47:23';
+ $class->User->Comment->{'0'}->updated = '2007-03-18 10:49:31';
+ $class->User->Comment->{'1'} = new stdClass;
+ $class->User->Comment->{'1'}->id = 2;
+ $class->User->Comment->{'1'}->article_id = 1;
+ $class->User->Comment->{'1'}->user_id = 2;
+ $class->User->Comment->{'1'}->comment = 'Second Comment for First Article';
+ $class->User->Comment->{'1'}->published = 'Y';
+ $class->User->Comment->{'1'}->created = '2007-03-18 10:47:23';
+ $class->User->Comment->{'1'}->updated = '2007-03-18 10:49:31';
+
+ $result = Set::reverse($class);
+ $this->assertIdentical($result, $expected);
+
+ $expected = array('User' => array('psword'=> 'whatever',
+ 'Icon' => array('id'=> 851),
+ 'Profile' => array('name' => 'Some Name', 'address' => 'Some Address'),
+ 'Comment' => array(
+ array('id' => 1, 'article_id' => 1, 'user_id' => 1, 'comment' => 'First Comment for First Article', 'published' => 'Y', 'created' => '2007-03-18 10:47:23', 'updated' => '2007-03-18 10:49:31'),
+ array('id' => 2, 'article_id' => 1, 'user_id' => 2, 'comment' => 'Second Comment for First Article', 'published' => 'Y', 'created' => '2007-03-18 10:47:23', 'updated' => '2007-03-18 10:49:31'))));
+
+ $class = new stdClass;
+ $class->User = new stdClass;
+ $class->User->psword = 'whatever';
+ $class->User->Icon = new stdClass;
+ $class->User->Icon->id = 851;
+ $class->User->Profile = new stdClass;
+ $class->User->Profile->name = 'Some Name';
+ $class->User->Profile->address = 'Some Address';
+ $class->User->Comment = array();
+ $comment = new stdClass;
+ $comment->id = 1;
+ $comment->article_id = 1;
+ $comment->user_id = 1;
+ $comment->comment = 'First Comment for First Article';
+ $comment->published = 'Y';
+ $comment->created = '2007-03-18 10:47:23';
+ $comment->updated = '2007-03-18 10:49:31';
+ $comment2 = new stdClass;
+ $comment2->id = 2;
+ $comment2->article_id = 1;
+ $comment2->user_id = 2;
+ $comment2->comment = 'Second Comment for First Article';
+ $comment2->published = 'Y';
+ $comment2->created = '2007-03-18 10:47:23';
+ $comment2->updated = '2007-03-18 10:49:31';
+ $class->User->Comment = array($comment, $comment2);
+ $result = Set::reverse($class);
+ $this->assertIdentical($result, $expected);
+
+ $model = new Model(array('id' => false, 'name' => 'Model', 'table' => false));
+ $expected = array(
+ 'Behaviors' => array('modelName' => 'Model', '_attached' => array(), '_disabled' => array(), '__methods' => array(), '__mappedMethods' => array()),
+ 'useDbConfig' => 'default', 'useTable' => false, 'displayField' => null, 'id' => false, 'data' => array(), 'table' => 'models', 'primaryKey' => 'id', '_schema' => null, 'validate' => array(),
+ 'validationErrors' => array(), 'tablePrefix' => null, 'name' => 'Model', 'alias' => 'Model', 'tableToModel' => array(), 'logTransactions' => false, 'cacheQueries' => false,
+ 'belongsTo' => array(), 'hasOne' => array(), 'hasMany' => array(), 'hasAndBelongsToMany' => array(), 'actsAs' => null, 'whitelist' => array(), 'cacheSources' => true,
+ 'findQueryType' => null, 'recursive' => 1, 'order' => null, 'virtualFields' => array(),
+ '__associationKeys' => array(
+ 'belongsTo' => array('className', 'foreignKey', 'conditions', 'fields', 'order', 'counterCache'),
+ 'hasOne' => array('className', 'foreignKey', 'conditions', 'fields', 'order', 'dependent'),
+ 'hasMany' => array('className', 'foreignKey', 'conditions', 'fields', 'order', 'limit', 'offset', 'dependent', 'exclusive', 'finderQuery', 'counterQuery'),
+ 'hasAndBelongsToMany' => array('className', 'joinTable', 'with', 'foreignKey', 'associationForeignKey', 'conditions', 'fields', 'order', 'limit', 'offset', 'unique', 'finderQuery', 'deleteQuery', 'insertQuery')),
+ '__associations' => array('belongsTo', 'hasOne', 'hasMany', 'hasAndBelongsToMany'), '__backAssociation' => array(), '__insertID' => null, '__numRows' => null, '__affectedRows' => null,
+ '_findMethods' => array('all' => true, 'first' => true, 'count' => true, 'neighbors' => true, 'list' => true, 'threaded' => true));
+ $result = Set::reverse($model);
+
+ ksort($result);
+ ksort($expected);
+
+ $this->assertIdentical($result, $expected);
+
+ $class = new stdClass;
+ $class->User = new stdClass;
+ $class->User->id = 100;
+ $class->someString = 'this is some string';
+ $class->Profile = new stdClass;
+ $class->Profile->name = 'Joe Mamma';
+
+ $result = Set::reverse($class);
+ $expected = array('User' => array('id' => '100'), 'someString'=> 'this is some string', 'Profile' => array('name' => 'Joe Mamma'));
+ $this->assertEqual($result, $expected);
+
+ $class = new stdClass;
+ $class->User = new stdClass;
+ $class->User->id = 100;
+ $class->User->_name_ = 'User';
+ $class->Profile = new stdClass;
+ $class->Profile->name = 'Joe Mamma';
+ $class->Profile->_name_ = 'Profile';
+
+ $result = Set::reverse($class);
+ $expected = array('User' => array('id' => '100'), 'Profile' => array('name' => 'Joe Mamma'));
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testFormatting method
+ *
+ * @access public
+ * @return void
+ */
+ function testFormatting() {
+ $data = array(
+ array('Person' => array('first_name' => 'Nate', 'last_name' => 'Abele', 'city' => 'Boston', 'state' => 'MA', 'something' => '42')),
+ array('Person' => array('first_name' => 'Larry', 'last_name' => 'Masters', 'city' => 'Boondock', 'state' => 'TN', 'something' => '{0}')),
+ array('Person' => array('first_name' => 'Garrett', 'last_name' => 'Woodworth', 'city' => 'Venice Beach', 'state' => 'CA', 'something' => '{1}')));
+
+ $result = Set::format($data, '{1}, {0}', array('{n}.Person.first_name', '{n}.Person.last_name'));
+ $expected = array('Abele, Nate', 'Masters, Larry', 'Woodworth, Garrett');
+ $this->assertEqual($result, $expected);
+
+ $result = Set::format($data, '{0}, {1}', array('{n}.Person.last_name', '{n}.Person.first_name'));
+ $this->assertEqual($result, $expected);
+
+ $result = Set::format($data, '{0}, {1}', array('{n}.Person.city', '{n}.Person.state'));
+ $expected = array('Boston, MA', 'Boondock, TN', 'Venice Beach, CA');
+ $this->assertEqual($result, $expected);
+
+ $result = Set::format($data, '{{0}, {1}}', array('{n}.Person.city', '{n}.Person.state'));
+ $expected = array('{Boston, MA}', '{Boondock, TN}', '{Venice Beach, CA}');
+ $this->assertEqual($result, $expected);
+
+ $result = Set::format($data, '{{0}, {1}}', array('{n}.Person.something', '{n}.Person.something'));
+ $expected = array('{42, 42}', '{{0}, {0}}', '{{1}, {1}}');
+ $this->assertEqual($result, $expected);
+
+ $result = Set::format($data, '{%2$d, %1$s}', array('{n}.Person.something', '{n}.Person.something'));
+ $expected = array('{42, 42}', '{0, {0}}', '{0, {1}}');
+ $this->assertEqual($result, $expected);
+
+ $result = Set::format($data, '{%1$s, %1$s}', array('{n}.Person.something', '{n}.Person.something'));
+ $expected = array('{42, 42}', '{{0}, {0}}', '{{1}, {1}}');
+ $this->assertEqual($result, $expected);
+
+ $result = Set::format($data, '%2$d, %1$s', array('{n}.Person.first_name', '{n}.Person.something'));
+ $expected = array('42, Nate', '0, Larry', '0, Garrett');
+ $this->assertEqual($result, $expected);
+
+ $result = Set::format($data, '%1$s, %2$d', array('{n}.Person.first_name', '{n}.Person.something'));
+ $expected = array('Nate, 42', 'Larry, 0', 'Garrett, 0');
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testCountDim method
+ *
+ * @access public
+ * @return void
+ */
+ function testCountDim() {
+ $data = array('one', '2', 'three');
+ $result = Set::countDim($data);
+ $this->assertEqual($result, 1);
+
+ $data = array('1' => '1.1', '2', '3');
+ $result = Set::countDim($data);
+ $this->assertEqual($result, 1);
+
+ $data = array('1' => array('1.1' => '1.1.1'), '2', '3' => array('3.1' => '3.1.1'));
+ $result = Set::countDim($data);
+ $this->assertEqual($result, 2);
+
+ $data = array('1' => '1.1', '2', '3' => array('3.1' => '3.1.1'));
+ $result = Set::countDim($data);
+ $this->assertEqual($result, 1);
+
+ $data = array('1' => '1.1', '2', '3' => array('3.1' => '3.1.1'));
+ $result = Set::countDim($data, true);
+ $this->assertEqual($result, 2);
+
+ $data = array('1' => array('1.1' => '1.1.1'), '2', '3' => array('3.1' => array('3.1.1' => '3.1.1.1')));
+ $result = Set::countDim($data);
+ $this->assertEqual($result, 2);
+
+ $data = array('1' => array('1.1' => '1.1.1'), '2', '3' => array('3.1' => array('3.1.1' => '3.1.1.1')));
+ $result = Set::countDim($data, true);
+ $this->assertEqual($result, 3);
+
+ $data = array('1' => array('1.1' => '1.1.1'), array('2' => array('2.1' => array('2.1.1' => '2.1.1.1'))), '3' => array('3.1' => array('3.1.1' => '3.1.1.1')));
+ $result = Set::countDim($data, true);
+ $this->assertEqual($result, 4);
+
+ $data = array('1' => array('1.1' => '1.1.1'), array('2' => array('2.1' => array('2.1.1' => array('2.1.1.1')))), '3' => array('3.1' => array('3.1.1' => '3.1.1.1')));
+ $result = Set::countDim($data, true);
+ $this->assertEqual($result, 5);
+
+ $data = array('1' => array('1.1' => '1.1.1'), array('2' => array('2.1' => array('2.1.1' => array('2.1.1.1' => '2.1.1.1.1')))), '3' => array('3.1' => array('3.1.1' => '3.1.1.1')));
+ $result = Set::countDim($data, true);
+ $this->assertEqual($result, 5);
+
+ $set = array('1' => array('1.1' => '1.1.1'), array('2' => array('2.1' => array('2.1.1' => array('2.1.1.1' => '2.1.1.1.1')))), '3' => array('3.1' => array('3.1.1' => '3.1.1.1')));
+ $result = Set::countDim($set, false, 0);
+ $this->assertEqual($result, 2);
+
+ $result = Set::countDim($set, true);
+ $this->assertEqual($result, 5);
+ }
+
+/**
+ * testMapNesting method
+ *
+ * @access public
+ * @return void
+ */
+ function testMapNesting() {
+ $expected = array(
+ array(
+ "IndexedPage" => array(
+ "id" => 1,
+ "url" => 'http://blah.com/',
+ 'hash' => '68a9f053b19526d08e36c6a9ad150737933816a5',
+ 'headers' => array(
+ 'Date' => "Wed, 14 Nov 2007 15:51:42 GMT",
+ 'Server' => "Apache",
+ 'Expires' => "Thu, 19 Nov 1981 08:52:00 GMT",
+ 'Cache-Control' => "private",
+ 'Pragma' => "no-cache",
+ 'Content-Type' => "text/html; charset=UTF-8",
+ 'X-Original-Transfer-Encoding' => "chunked",
+ 'Content-Length' => "50210",
+ ),
+ 'meta' => array(
+ 'keywords' => array('testing','tests'),
+ 'description'=>'describe me',
+ ),
+ 'get_vars' => '',
+ 'post_vars' => array(),
+ 'cookies' => array('PHPSESSID' => "dde9896ad24595998161ffaf9e0dbe2d"),
+ 'redirect' => '',
+ 'created' => "1195055503",
+ 'updated' => "1195055503",
+ )
+ ),
+ array(
+ "IndexedPage" => array(
+ "id" => 2,
+ "url" => 'http://blah.com/',
+ 'hash' => '68a9f053b19526d08e36c6a9ad150737933816a5',
+ 'headers' => array(
+ 'Date' => "Wed, 14 Nov 2007 15:51:42 GMT",
+ 'Server' => "Apache",
+ 'Expires' => "Thu, 19 Nov 1981 08:52:00 GMT",
+ 'Cache-Control' => "private",
+ 'Pragma' => "no-cache",
+ 'Content-Type' => "text/html; charset=UTF-8",
+ 'X-Original-Transfer-Encoding' => "chunked",
+ 'Content-Length' => "50210",
+ ),
+ 'meta' => array(
+ 'keywords' => array('testing','tests'),
+ 'description'=>'describe me',
+ ),
+ 'get_vars' => '',
+ 'post_vars' => array(),
+ 'cookies' => array('PHPSESSID' => "dde9896ad24595998161ffaf9e0dbe2d"),
+ 'redirect' => '',
+ 'created' => "1195055503",
+ 'updated' => "1195055503",
+ ),
+ )
+ );
+
+ $mapped = Set::map($expected);
+ $ids = array();
+
+ foreach($mapped as $object) {
+ $ids[] = $object->id;
+ }
+ $this->assertEqual($ids, array(1, 2));
+ $this->assertEqual(get_object_vars($mapped[0]->headers), $expected[0]['IndexedPage']['headers']);
+
+ $result = Set::reverse($mapped);
+ $this->assertIdentical($result, $expected);
+
+ $data = array(
+ array(
+ "IndexedPage" => array(
+ "id" => 1,
+ "url" => 'http://blah.com/',
+ 'hash' => '68a9f053b19526d08e36c6a9ad150737933816a5',
+ 'get_vars' => '',
+ 'redirect' => '',
+ 'created' => "1195055503",
+ 'updated' => "1195055503",
+ )
+ ),
+ array(
+ "IndexedPage" => array(
+ "id" => 2,
+ "url" => 'http://blah.com/',
+ 'hash' => '68a9f053b19526d08e36c6a9ad150737933816a5',
+ 'get_vars' => '',
+ 'redirect' => '',
+ 'created' => "1195055503",
+ 'updated' => "1195055503",
+ ),
+ )
+ );
+ $mapped = Set::map($data);
+
+ $expected = new stdClass();
+ $expected->_name_ = 'IndexedPage';
+ $expected->id = 2;
+ $expected->url = 'http://blah.com/';
+ $expected->hash = '68a9f053b19526d08e36c6a9ad150737933816a5';
+ $expected->get_vars = '';
+ $expected->redirect = '';
+ $expected->created = "1195055503";
+ $expected->updated = "1195055503";
+ $this->assertIdentical($mapped[1], $expected);
+
+ $ids = array();
+
+ foreach($mapped as $object) {
+ $ids[] = $object->id;
+ }
+ $this->assertEqual($ids, array(1, 2));
+
+ $result = Set::map(null);
+ $expected = null;
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testNestedMappedData method
+ *
+ * @access public
+ * @return void
+ */
+ function testNestedMappedData() {
+ $result = Set::map(array(
+ array(
+ 'Post' => array('id' => '1', 'author_id' => '1', 'title' => 'First Post', 'body' => 'First Post Body', 'published' => 'Y', 'created' => '2007-03-18 10:39:23', 'updated' => '2007-03-18 10:41:31'),
+ 'Author' => array('id' => '1', 'user' => 'mariano', 'password' => '5f4dcc3b5aa765d61d8327deb882cf99', 'created' => '2007-03-17 01:16:23', 'updated' => '2007-03-17 01:18:31', 'test' => 'working'),
+ )
+ , array(
+ 'Post' => array('id' => '2', 'author_id' => '3', 'title' => 'Second Post', 'body' => 'Second Post Body', 'published' => 'Y', 'created' => '2007-03-18 10:41:23', 'updated' => '2007-03-18 10:43:31'),
+ 'Author' => array('id' => '3', 'user' => 'larry', 'password' => '5f4dcc3b5aa765d61d8327deb882cf99', 'created' => '2007-03-17 01:20:23', 'updated' => '2007-03-17 01:22:31', 'test' => 'working'),
+ )
+ ));
+
+ $expected = new stdClass;
+ $expected->_name_ = 'Post';
+ $expected->id = '1';
+ $expected->author_id = '1';
+ $expected->title = 'First Post';
+ $expected->body = 'First Post Body';
+ $expected->published = 'Y';
+ $expected->created = "2007-03-18 10:39:23";
+ $expected->updated = "2007-03-18 10:41:31";
+
+ $expected->Author = new stdClass;
+ $expected->Author->id = '1';
+ $expected->Author->user = 'mariano';
+ $expected->Author->password = '5f4dcc3b5aa765d61d8327deb882cf99';
+ $expected->Author->created = "2007-03-17 01:16:23";
+ $expected->Author->updated = "2007-03-17 01:18:31";
+ $expected->Author->test = "working";
+ $expected->Author->_name_ = 'Author';
+
+ $expected2 = new stdClass;
+ $expected2->_name_ = 'Post';
+ $expected2->id = '2';
+ $expected2->author_id = '3';
+ $expected2->title = 'Second Post';
+ $expected2->body = 'Second Post Body';
+ $expected2->published = 'Y';
+ $expected2->created = "2007-03-18 10:41:23";
+ $expected2->updated = "2007-03-18 10:43:31";
+
+ $expected2->Author = new stdClass;
+ $expected2->Author->id = '3';
+ $expected2->Author->user = 'larry';
+ $expected2->Author->password = '5f4dcc3b5aa765d61d8327deb882cf99';
+ $expected2->Author->created = "2007-03-17 01:20:23";
+ $expected2->Author->updated = "2007-03-17 01:22:31";
+ $expected2->Author->test = "working";
+ $expected2->Author->_name_ = 'Author';
+
+ $test = array();
+ $test[0] = $expected;
+ $test[1] = $expected2;
+
+ $this->assertIdentical($test, $result);
+
+ $result = Set::map(
+ array(
+ 'Post' => array('id' => '1', 'author_id' => '1', 'title' => 'First Post', 'body' => 'First Post Body', 'published' => 'Y', 'created' => '2007-03-18 10:39:23', 'updated' => '2007-03-18 10:41:31'),
+ 'Author' => array('id' => '1', 'user' => 'mariano', 'password' => '5f4dcc3b5aa765d61d8327deb882cf99', 'created' => '2007-03-17 01:16:23', 'updated' => '2007-03-17 01:18:31', 'test' => 'working'),
+ )
+ );
+ $expected = new stdClass;
+ $expected->_name_ = 'Post';
+ $expected->id = '1';
+ $expected->author_id = '1';
+ $expected->title = 'First Post';
+ $expected->body = 'First Post Body';
+ $expected->published = 'Y';
+ $expected->created = "2007-03-18 10:39:23";
+ $expected->updated = "2007-03-18 10:41:31";
+
+ $expected->Author = new stdClass;
+ $expected->Author->id = '1';
+ $expected->Author->user = 'mariano';
+ $expected->Author->password = '5f4dcc3b5aa765d61d8327deb882cf99';
+ $expected->Author->created = "2007-03-17 01:16:23";
+ $expected->Author->updated = "2007-03-17 01:18:31";
+ $expected->Author->test = "working";
+ $expected->Author->_name_ = 'Author';
+ $this->assertIdentical($expected, $result);
+
+ //Case where extra HABTM fields come back in a result
+ $data = array(
+ 'User' => array(
+ 'id' => 1,
+ 'email' => 'user@example.com',
+ 'first_name' => 'John',
+ 'last_name' => 'Smith',
+ ),
+ 'Piece' => array(
+ array(
+ 'id' => 1,
+ 'title' => 'Moonlight Sonata',
+ 'composer' => 'Ludwig van Beethoven',
+ 'PiecesUser' => array(
+ 'id' => 1,
+ 'created' => '2008-01-01 00:00:00',
+ 'modified' => '2008-01-01 00:00:00',
+ 'piece_id' => 1,
+ 'user_id' => 2,
+ )
+ ),
+ array(
+ 'id' => 2,
+ 'title' => 'Moonlight Sonata 2',
+ 'composer' => 'Ludwig van Beethoven',
+ 'PiecesUser' => array(
+ 'id' => 2,
+ 'created' => '2008-01-01 00:00:00',
+ 'modified' => '2008-01-01 00:00:00',
+ 'piece_id' => 2,
+ 'user_id' => 2,
+ )
+ )
+ )
+ );
+
+ $result = Set::map($data);
+
+ $expected = new stdClass();
+ $expected->_name_ = 'User';
+ $expected->id = 1;
+ $expected->email = 'user@example.com';
+ $expected->first_name = 'John';
+ $expected->last_name = 'Smith';
+
+ $piece = new stdClass();
+ $piece->id = 1;
+ $piece->title = 'Moonlight Sonata';
+ $piece->composer = 'Ludwig van Beethoven';
+
+ $piece->PiecesUser = new stdClass();
+ $piece->PiecesUser->id = 1;
+ $piece->PiecesUser->created = '2008-01-01 00:00:00';
+ $piece->PiecesUser->modified = '2008-01-01 00:00:00';
+ $piece->PiecesUser->piece_id = 1;
+ $piece->PiecesUser->user_id = 2;
+ $piece->PiecesUser->_name_ = 'PiecesUser';
+
+ $piece->_name_ = 'Piece';
+
+
+ $piece2 = new stdClass();
+ $piece2->id = 2;
+ $piece2->title = 'Moonlight Sonata 2';
+ $piece2->composer = 'Ludwig van Beethoven';
+
+ $piece2->PiecesUser = new stdClass();
+ $piece2->PiecesUser->id = 2;
+ $piece2->PiecesUser->created = '2008-01-01 00:00:00';
+ $piece2->PiecesUser->modified = '2008-01-01 00:00:00';
+ $piece2->PiecesUser->piece_id = 2;
+ $piece2->PiecesUser->user_id = 2;
+ $piece2->PiecesUser->_name_ = 'PiecesUser';
+
+ $piece2->_name_ = 'Piece';
+
+ $expected->Piece = array($piece, $piece2);
+
+ $this->assertIdentical($expected, $result);
+
+ //Same data, but should work if _name_ has been manually defined:
+ $data = array(
+ 'User' => array(
+ 'id' => 1,
+ 'email' => 'user@example.com',
+ 'first_name' => 'John',
+ 'last_name' => 'Smith',
+ '_name_' => 'FooUser',
+ ),
+ 'Piece' => array(
+ array(
+ 'id' => 1,
+ 'title' => 'Moonlight Sonata',
+ 'composer' => 'Ludwig van Beethoven',
+ '_name_' => 'FooPiece',
+ 'PiecesUser' => array(
+ 'id' => 1,
+ 'created' => '2008-01-01 00:00:00',
+ 'modified' => '2008-01-01 00:00:00',
+ 'piece_id' => 1,
+ 'user_id' => 2,
+ '_name_' => 'FooPiecesUser',
+ )
+ ),
+ array(
+ 'id' => 2,
+ 'title' => 'Moonlight Sonata 2',
+ 'composer' => 'Ludwig van Beethoven',
+ '_name_' => 'FooPiece',
+ 'PiecesUser' => array(
+ 'id' => 2,
+ 'created' => '2008-01-01 00:00:00',
+ 'modified' => '2008-01-01 00:00:00',
+ 'piece_id' => 2,
+ 'user_id' => 2,
+ '_name_' => 'FooPiecesUser',
+ )
+ )
+ )
+ );
+
+ $result = Set::map($data);
+
+ $expected = new stdClass();
+ $expected->_name_ = 'FooUser';
+ $expected->id = 1;
+ $expected->email = 'user@example.com';
+ $expected->first_name = 'John';
+ $expected->last_name = 'Smith';
+
+ $piece = new stdClass();
+ $piece->id = 1;
+ $piece->title = 'Moonlight Sonata';
+ $piece->composer = 'Ludwig van Beethoven';
+ $piece->_name_ = 'FooPiece';
+ $piece->PiecesUser = new stdClass();
+ $piece->PiecesUser->id = 1;
+ $piece->PiecesUser->created = '2008-01-01 00:00:00';
+ $piece->PiecesUser->modified = '2008-01-01 00:00:00';
+ $piece->PiecesUser->piece_id = 1;
+ $piece->PiecesUser->user_id = 2;
+ $piece->PiecesUser->_name_ = 'FooPiecesUser';
+
+ $piece2 = new stdClass();
+ $piece2->id = 2;
+ $piece2->title = 'Moonlight Sonata 2';
+ $piece2->composer = 'Ludwig van Beethoven';
+ $piece2->_name_ = 'FooPiece';
+ $piece2->PiecesUser = new stdClass();
+ $piece2->PiecesUser->id = 2;
+ $piece2->PiecesUser->created = '2008-01-01 00:00:00';
+ $piece2->PiecesUser->modified = '2008-01-01 00:00:00';
+ $piece2->PiecesUser->piece_id = 2;
+ $piece2->PiecesUser->user_id = 2;
+ $piece2->PiecesUser->_name_ = 'FooPiecesUser';
+
+ $expected->Piece = array($piece, $piece2);
+
+ $this->assertIdentical($expected, $result);
+ }
+
+/**
+ * testPushDiff method
+ *
+ * @access public
+ * @return void
+ */
+ function testPushDiff() {
+ $array1 = array('ModelOne' => array('id'=>1001, 'field_one'=>'a1.m1.f1', 'field_two'=>'a1.m1.f2'));
+ $array2 = array('ModelTwo' => array('id'=>1002, 'field_one'=>'a2.m2.f1', 'field_two'=>'a2.m2.f2'));
+
+ $result = Set::pushDiff($array1, $array2);
+
+ $this->assertIdentical($result, $array1 + $array2);
+
+ $array3 = array('ModelOne' => array('id'=>1003, 'field_one'=>'a3.m1.f1', 'field_two'=>'a3.m1.f2', 'field_three'=>'a3.m1.f3'));
+ $result = Set::pushDiff($array1, $array3);
+
+ $expected = array('ModelOne' => array('id'=>1001, 'field_one'=>'a1.m1.f1', 'field_two'=>'a1.m1.f2', 'field_three'=>'a3.m1.f3'));
+ $this->assertIdentical($result, $expected);
+
+
+ $array1 = array(
+ 0 => array('ModelOne' => array('id'=>1001, 'field_one'=>'s1.0.m1.f1', 'field_two'=>'s1.0.m1.f2')),
+ 1 => array('ModelTwo' => array('id'=>1002, 'field_one'=>'s1.1.m2.f2', 'field_two'=>'s1.1.m2.f2')));
+ $array2 = array(
+ 0 => array('ModelOne' => array('id'=>1001, 'field_one'=>'s2.0.m1.f1', 'field_two'=>'s2.0.m1.f2')),
+ 1 => array('ModelTwo' => array('id'=>1002, 'field_one'=>'s2.1.m2.f2', 'field_two'=>'s2.1.m2.f2')));
+
+ $result = Set::pushDiff($array1, $array2);
+ $this->assertIdentical($result, $array1);
+
+ $array3 = array(0 => array('ModelThree' => array('id'=>1003, 'field_one'=>'s3.0.m3.f1', 'field_two'=>'s3.0.m3.f2')));
+
+ $result = Set::pushDiff($array1, $array3);
+ $expected = array(
+ 0 => array('ModelOne' => array('id'=>1001, 'field_one'=>'s1.0.m1.f1', 'field_two'=>'s1.0.m1.f2'),
+ 'ModelThree' => array('id'=>1003, 'field_one'=>'s3.0.m3.f1', 'field_two'=>'s3.0.m3.f2')),
+ 1 => array('ModelTwo' => array('id'=>1002, 'field_one'=>'s1.1.m2.f2', 'field_two'=>'s1.1.m2.f2')));
+ $this->assertIdentical($result, $expected);
+
+ $result = Set::pushDiff($array1, null);
+ $this->assertIdentical($result, $array1);
+
+ $result = Set::pushDiff($array1, $array2);
+ $this->assertIdentical($result, $array1+$array2);
+ }
+
+/**
+ * testSetApply method
+ * @access public
+ * @return void
+ *
+ */
+ function testApply() {
+ $data = array(
+ array('Movie' => array('id' => 1, 'title' => 'movie 3', 'rating' => 5)),
+ array('Movie' => array('id' => 1, 'title' => 'movie 1', 'rating' => 1)),
+ array('Movie' => array('id' => 1, 'title' => 'movie 2', 'rating' => 3))
+ );
+
+ $result = Set::apply('/Movie/rating', $data, 'array_sum');
+ $expected = 9;
+ $this->assertEqual($result, $expected);
+
+ if (PHP5) {
+ $result = Set::apply('/Movie/rating', $data, 'array_product');
+ $expected = 15;
+ $this->assertEqual($result, $expected);
+ }
+
+ $result = Set::apply('/Movie/title', $data, 'ucfirst', array('type' => 'map'));
+ $expected = array('Movie 3', 'Movie 1', 'Movie 2');
+ $this->assertEqual($result, $expected);
+
+ $result = Set::apply('/Movie/title', $data, 'strtoupper', array('type' => 'map'));
+ $expected = array('MOVIE 3', 'MOVIE 1', 'MOVIE 2');
+ $this->assertEqual($result, $expected);
+
+ $result = Set::apply('/Movie/rating', $data, array('SetTest', '_method'), array('type' => 'reduce'));
+ $expected = 9;
+ $this->assertEqual($result, $expected);
+
+ $result = Set::apply('/Movie/rating', $data, 'strtoupper', array('type' => 'non existing type'));
+ $expected = null;
+ $this->assertEqual($result, $expected);
+
+ }
+
+/**
+ * Helper method to test Set::apply()
+ *
+ * @access protected
+ * @return void
+ */
+ function _method($val1, $val2) {
+ $val1 += $val2;
+ return $val1;
+ }
+
+/**
+ * testXmlSetReverse method
+ *
+ * @access public
+ * @return void
+ */
+ function testXmlSetReverse() {
+ App::import('Core', 'Xml');
+
+ $string = '
+
+
+ Cake PHP Google Group
+ http://groups.google.com/group/cake-php
+ Search this group before posting anything. There are over 20,000 posts and it's very likely your question was answered before. Visit the IRC channel #cakephp at irc.freenode.net for live chat with users and developers of Cake. If you post, tell us the version of Cake, PHP, and database.
+ en
+ -
+
constructng result array when using findall
+ http://groups.google.com/group/cake-php/msg/49bc00f3bc651b4f
+ i'm using cakephp to construct a logical data model array that will be <br> passed to a flex app. I have the following model association: <br> ServiceDay->(hasMany)ServiceTi me->(hasMany)ServiceTimePrice. So what <br> the current output from my findall is something like this example: <br> <p>Array( <br> [0] => Array(
+ http://groups.google.com/group/cake-php/msg/49bc00f3bc651b4f
+ bmil...@gmail.com(bpscrugs)
+ Fri, 28 Dec 2007 00:44:14 UT
+
+ -
+
Re: share views between actions?
+ http://groups.google.com/group/cake-php/msg/8b350d898707dad8
+ Then perhaps you might do us all a favour and refrain from replying to <br> things you do not understand. That goes especially for asinine comments. <br> Indeed. <br> To sum up: <br> No comment. <br> In my day, a simple "RTFM" would suffice. I'll keep in mind to ignore any <br> further responses from you. <br> You (and I) were referring to the *online documentation*, not other
+ http://groups.google.com/group/cake-php/msg/8b350d898707dad8
+ subtropolis.z...@gmail.com(subtropolis zijn)
+ Fri, 28 Dec 2007 00:45:01 UT
+
+
+ ';
+ $xml = new Xml($string);
+ $result = Set::reverse($xml);
+ $expected = array('Rss' => array(
+ 'version' => '2.0',
+ 'Channel' => array(
+ 'title' => 'Cake PHP Google Group',
+ 'link' => 'http://groups.google.com/group/cake-php',
+ 'description' => 'Search this group before posting anything. There are over 20,000 posts and it's very likely your question was answered before. Visit the IRC channel #cakephp at irc.freenode.net for live chat with users and developers of Cake. If you post, tell us the version of Cake, PHP, and database.',
+ 'language' => 'en',
+ 'Item' => array(
+ array(
+ 'title' => 'constructng result array when using findall',
+ 'link' => 'http://groups.google.com/group/cake-php/msg/49bc00f3bc651b4f',
+ 'description' => "i'm using cakephp to construct a logical data model array that will be passed to a flex app. I have the following model association: ServiceDay->(hasMany)ServiceTi me->(hasMany)ServiceTimePrice. So what the current output from my findall is something like this example: Array( [0] => Array(",
+ 'guid' => array('isPermaLink' => 'true', 'value' => 'http://groups.google.com/group/cake-php/msg/49bc00f3bc651b4f'),
+ 'author' => 'bmil...@gmail.com(bpscrugs)',
+ 'pubDate' => 'Fri, 28 Dec 2007 00:44:14 UT',
+ ),
+ array(
+ 'title' => 'Re: share views between actions?',
+ 'link' => 'http://groups.google.com/group/cake-php/msg/8b350d898707dad8',
+ 'description' => 'Then perhaps you might do us all a favour and refrain from replying to things you do not understand. That goes especially for asinine comments. Indeed. To sum up: No comment. In my day, a simple "RTFM" would suffice. I\'ll keep in mind to ignore any further responses from you. You (and I) were referring to the *online documentation*, not other',
+ 'guid' => array('isPermaLink' => 'true', 'value' => 'http://groups.google.com/group/cake-php/msg/8b350d898707dad8'),
+ 'author' => 'subtropolis.z...@gmail.com(subtropolis zijn)',
+ 'pubDate' => 'Fri, 28 Dec 2007 00:45:01 UT'
+ )
+ )
+ )
+ ));
+ $this->assertEqual($result, $expected);
+ $string =' ';
+
+ $xml = new Xml($string);
+ $result = Set::reverse($xml);
+ $expected = array('Data' => array('Post' => array('title' => 'Title of this post', 'description' => 'cool')));
+ $this->assertEqual($result, $expected);
+
+ $xml = new Xml('An example of a correctly reversed XMLNode ');
+ $result = Set::reverse($xml);
+ $expected = array('Example' =>
+ array(
+ 'Item' => array(
+ 'title' => 'An example of a correctly reversed XMLNode',
+ 'desc' => array(),
+ )
+ )
+ );
+ $this->assertIdentical($result, $expected);
+
+ $xml = new Xml('title1 title2 ');
+ $result = Set::reverse($xml);
+ $expected =
+ array('Example' => array(
+ 'Item' => array(
+ 'attr' => '123',
+ 'Titles' => array(
+ 'Title' => array('title1', 'title2')
+ )
+ )
+ )
+ );
+ $this->assertIdentical($result, $expected);
+
+ $xml = new Xml('list textforitems ');
+ $result = Set::reverse($xml);
+ $expected =
+ array('Example' => array(
+ 'attr' => 'ex_attr',
+ 'Item' => array(
+ 'attr' => '123',
+ 'titles' => 'list',
+ 'value' => 'textforitems'
+ )
+ )
+ );
+ $this->assertIdentical($result, $expected);
+
+ $string = '
+
+
+ Cake PHP Google Group
+ http://groups.google.com/group/cake-php
+ Search this group before posting anything. There are over 20,000 posts and it's very likely your question was answered before. Visit the IRC channel #cakephp at irc.freenode.net for live chat with users and developers of Cake. If you post, tell us the version of Cake, PHP, and database.
+ en
+ -
+
constructng result array when using findall
+ http://groups.google.com/group/cake-php/msg/49bc00f3bc651b4f
+ i'm using cakephp to construct a logical data model array that will be <br> passed to a flex app. I have the following model association: <br> ServiceDay->(hasMany)ServiceTi me->(hasMany)ServiceTimePrice. So what <br> the current output from my findall is something like this example: <br> <p>Array( <br> [0] => Array(
+ cakephp
+
+
+ http://groups.google.com/group/cake-php/msg/49bc00f3bc651b4f
+ bmil...@gmail.com(bpscrugs)
+ Fri, 28 Dec 2007 00:44:14 UT
+
+ -
+
Re: share views between actions?
+ http://groups.google.com/group/cake-php/msg/8b350d898707dad8
+ Then perhaps you might do us all a favour and refrain from replying to <br> things you do not understand. That goes especially for asinine comments. <br> Indeed. <br> To sum up: <br> No comment. <br> In my day, a simple "RTFM" would suffice. I'll keep in mind to ignore any <br> further responses from you. <br> You (and I) were referring to the *online documentation*, not other
+ cakephp
+
+
+ http://groups.google.com/group/cake-php/msg/8b350d898707dad8
+ subtropolis.z...@gmail.com(subtropolis zijn)
+ Fri, 28 Dec 2007 00:45:01 UT
+
+
+ ';
+
+ $xml = new Xml($string);
+ $result = Set::reverse($xml);
+
+ $expected = array('Rss' => array(
+ 'version' => '2.0',
+ 'Channel' => array(
+ 'title' => 'Cake PHP Google Group',
+ 'link' => 'http://groups.google.com/group/cake-php',
+ 'description' => 'Search this group before posting anything. There are over 20,000 posts and it's very likely your question was answered before. Visit the IRC channel #cakephp at irc.freenode.net for live chat with users and developers of Cake. If you post, tell us the version of Cake, PHP, and database.',
+ 'language' => 'en',
+ 'Item' => array(
+ array(
+ 'title' => 'constructng result array when using findall',
+ 'link' => 'http://groups.google.com/group/cake-php/msg/49bc00f3bc651b4f',
+ 'description' => "i'm using cakephp to construct a logical data model array that will be passed to a flex app. I have the following model association: ServiceDay->(hasMany)ServiceTi me->(hasMany)ServiceTimePrice. So what the current output from my findall is something like this example:
Array( [0] => Array(",
+ 'creator' => 'cakephp',
+ 'Category' => array('cakephp', 'model'),
+ 'guid' => array('isPermaLink' => 'true', 'value' => 'http://groups.google.com/group/cake-php/msg/49bc00f3bc651b4f'),
+ 'author' => 'bmil...@gmail.com(bpscrugs)',
+ 'pubDate' => 'Fri, 28 Dec 2007 00:44:14 UT',
+ ),
+ array(
+ 'title' => 'Re: share views between actions?',
+ 'link' => 'http://groups.google.com/group/cake-php/msg/8b350d898707dad8',
+ 'description' => 'Then perhaps you might do us all a favour and refrain from replying to things you do not understand. That goes especially for asinine comments. Indeed. To sum up: No comment. In my day, a simple "RTFM" would suffice. I\'ll keep in mind to ignore any further responses from you. You (and I) were referring to the *online documentation*, not other',
+ 'creator' => 'cakephp',
+ 'Category' => array('cakephp', 'model'),
+ 'guid' => array('isPermaLink' => 'true', 'value' => 'http://groups.google.com/group/cake-php/msg/8b350d898707dad8'),
+ 'author' => 'subtropolis.z...@gmail.com(subtropolis zijn)',
+ 'pubDate' => 'Fri, 28 Dec 2007 00:45:01 UT'
+ )
+ )
+ )
+ ));
+ $this->assertEqual($result, $expected);
+
+ $text = '
+
+
+ xri://$xrds*simple
+ 2008-04-13T07:34:58Z
+
+ http://oauth.net/core/1.0/endpoint/authorize
+ http://oauth.net/core/1.0/parameters/auth-header
+ http://oauth.net/core/1.0/parameters/uri-query
+ https://ma.gnolia.com/oauth/authorize
+ http://ma.gnolia.com/oauth/authorize
+
+
+
+ xri://$xrds*simple
+
+ http://oauth.net/discovery/1.0
+ #oauth
+
+
+ ';
+
+ $xml = new Xml($text);
+ $result = Set::reverse($xml);
+
+ $expected = array('XRDS' => array(
+ 'xmlns' => 'xri://$xrds',
+ 'XRD' => array(
+ array(
+ 'xml:id' => 'oauth',
+ 'xmlns' => 'xri://$XRD*($v*2.0)',
+ 'version' => '2.0',
+ 'Type' => 'xri://$xrds*simple',
+ 'Expires' => '2008-04-13T07:34:58Z',
+ 'Service' => array(
+ 'Type' => array(
+ 'http://oauth.net/core/1.0/endpoint/authorize',
+ 'http://oauth.net/core/1.0/parameters/auth-header',
+ 'http://oauth.net/core/1.0/parameters/uri-query'
+ ),
+ 'URI' => array(
+ array(
+ 'value' => 'https://ma.gnolia.com/oauth/authorize',
+ 'priority' => '10',
+ ),
+ array(
+ 'value' => 'http://ma.gnolia.com/oauth/authorize',
+ 'priority' => '20'
+ )
+ )
+ )
+ ),
+ array(
+ 'xmlns' => 'xri://$XRD*($v*2.0)',
+ 'version' => '2.0',
+ 'Type' => 'xri://$xrds*simple',
+ 'Service' => array(
+ 'priority' => '10',
+ 'Type' => 'http://oauth.net/discovery/1.0',
+ 'URI' => '#oauth'
+ )
+ )
+ )
+ ));
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * testStrictKeyCheck method
+ *
+ * @access public
+ * @return void
+ */
+ function testStrictKeyCheck() {
+ $set = array('a' => 'hi');
+ $this->assertFalse(Set::check($set, 'a.b'));
+ }
+
+/**
+ * Tests Set::flatten
+ *
+ * @access public
+ * @return void
+ */
+ function testFlatten() {
+ $data = array('Larry', 'Curly', 'Moe');
+ $result = Set::flatten($data);
+ $this->assertEqual($result, $data);
+
+ $data[9] = 'Shemp';
+ $result = Set::flatten($data);
+ $this->assertEqual($result, $data);
+
+ $data = array(
+ array(
+ 'Post' => array('id' => '1', 'author_id' => '1', 'title' => 'First Post'),
+ 'Author' => array('id' => '1', 'user' => 'nate', 'password' => 'foo'),
+ ),
+ array(
+ 'Post' => array('id' => '2', 'author_id' => '3', 'title' => 'Second Post', 'body' => 'Second Post Body'),
+ 'Author' => array('id' => '3', 'user' => 'larry', 'password' => null),
+ )
+ );
+
+ $result = Set::flatten($data);
+ $expected = array(
+ '0.Post.id' => '1', '0.Post.author_id' => '1', '0.Post.title' => 'First Post', '0.Author.id' => '1',
+ '0.Author.user' => 'nate', '0.Author.password' => 'foo', '1.Post.id' => '2', '1.Post.author_id' => '3',
+ '1.Post.title' => 'Second Post', '1.Post.body' => 'Second Post Body', '1.Author.id' => '3',
+ '1.Author.user' => 'larry', '1.Author.password' => null
+ );
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * test normalization
+ *
+ * @return void
+ */
+ function testNormalizeStrings() {
+ $result = Set::normalize('one,two,three');
+ $expected = array('one' => null, 'two' => null, 'three' => null);
+ $this->assertEqual($expected, $result);
+
+ $result = Set::normalize('one two three', true, ' ');
+ $expected = array('one' => null, 'two' => null, 'three' => null);
+ $this->assertEqual($expected, $result);
+
+ $result = Set::normalize('one , two , three ', true, ',', true);
+ $expected = array('one' => null, 'two' => null, 'three' => null);
+ $this->assertEqual($expected, $result);
+ }
+
+/**
+ * test normalizing arrays
+ *
+ * @return void
+ */
+ function testNormalizeArrays() {
+ $result = Set::normalize(array('one', 'two', 'three'));
+ $expected = array('one' => null, 'two' => null, 'three' => null);
+ $this->assertEqual($expected, $result);
+
+ $result = Set::normalize(array('one', 'two', 'three'), false);
+ $expected = array('one', 'two', 'three');
+ $this->assertEqual($expected, $result);
+
+ $result = Set::normalize(array('one' => 1, 'two' => 2, 'three' => 3, 'four'), false);
+ $expected = array('one' => 1, 'two' => 2, 'three' => 3, 'four' => null);
+ $this->assertEqual($expected, $result);
+
+ $result = Set::normalize(array('one' => 1, 'two' => 2, 'three' => 3, 'four'));
+ $expected = array('one' => 1, 'two' => 2, 'three' => 3, 'four' => null);
+ $this->assertEqual($expected, $result);
+
+ $result = Set::normalize(array('one' => array('a', 'b', 'c' => 'cee'), 'two' => 2, 'three'));
+ $expected = array('one' => array('a', 'b', 'c' => 'cee'), 'two' => 2, 'three' => null);
+ $this->assertEqual($expected, $result);
+ }
+}
diff --git a/code/ryzom/tools/server/www/webtt/cake/tests/cases/libs/string.test.php b/code/ryzom/tools/server/www/webtt/cake/tests/cases/libs/string.test.php
new file mode 100644
index 000000000..da284d35d
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/cake/tests/cases/libs/string.test.php
@@ -0,0 +1,310 @@
+assertTrue($match);
+ }
+
+/**
+ * testMultipleUuidGeneration method
+ *
+ * @access public
+ * @return void
+ */
+ function testMultipleUuidGeneration() {
+ $check = array();
+ $count = mt_rand(10, 1000);
+ $pattern = "/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/";
+
+ for($i = 0; $i < $count; $i++) {
+ $result = String::uuid();
+ $match = preg_match($pattern, $result);
+ $this->assertTrue($match);
+ $this->assertFalse(in_array($result, $check));
+ $check[] = $result;
+ }
+ }
+
+/**
+ * testInsert method
+ *
+ * @access public
+ * @return void
+ */
+ function testInsert() {
+ $string = 'some string';
+ $expected = 'some string';
+ $result = String::insert($string, array());
+ $this->assertEqual($result, $expected);
+
+ $string = '2 + 2 = :sum. Cake is :adjective.';
+ $expected = '2 + 2 = 4. Cake is yummy.';
+ $result = String::insert($string, array('sum' => '4', 'adjective' => 'yummy'));
+ $this->assertEqual($result, $expected);
+
+ $string = '2 + 2 = %sum. Cake is %adjective.';
+ $result = String::insert($string, array('sum' => '4', 'adjective' => 'yummy'), array('before' => '%'));
+ $this->assertEqual($result, $expected);
+
+ $string = '2 + 2 = 2sum2. Cake is 9adjective9.';
+ $result = String::insert($string, array('sum' => '4', 'adjective' => 'yummy'), array('format' => '/([\d])%s\\1/'));
+ $this->assertEqual($result, $expected);
+
+ $string = '2 + 2 = 12sum21. Cake is 23adjective45.';
+ $expected = '2 + 2 = 4. Cake is 23adjective45.';
+ $result = String::insert($string, array('sum' => '4', 'adjective' => 'yummy'), array('format' => '/([\d])([\d])%s\\2\\1/'));
+ $this->assertEqual($result, $expected);
+
+ $string = ':web :web_site';
+ $expected = 'www http';
+ $result = String::insert($string, array('web' => 'www', 'web_site' => 'http'));
+ $this->assertEqual($result, $expected);
+
+ $string = '2 + 2 = .';
+ $expected = '2 + 2 = '4', 'adjective' => 'yummy'), array('before' => '<', 'after' => '>'));
+ $this->assertEqual($result, $expected);
+
+ $string = '2 + 2 = \:sum. Cake is :adjective.';
+ $expected = '2 + 2 = :sum. Cake is yummy.';
+ $result = String::insert($string, array('sum' => '4', 'adjective' => 'yummy'));
+ $this->assertEqual($result, $expected);
+
+ $string = '2 + 2 = !:sum. Cake is :adjective.';
+ $result = String::insert($string, array('sum' => '4', 'adjective' => 'yummy'), array('escape' => '!'));
+ $this->assertEqual($result, $expected);
+
+ $string = '2 + 2 = \%sum. Cake is %adjective.';
+ $expected = '2 + 2 = %sum. Cake is yummy.';
+ $result = String::insert($string, array('sum' => '4', 'adjective' => 'yummy'), array('before' => '%'));
+ $this->assertEqual($result, $expected);
+
+ $string = ':a :b \:a :a';
+ $expected = '1 2 :a 1';
+ $result = String::insert($string, array('a' => 1, 'b' => 2));
+ $this->assertEqual($result, $expected);
+
+ $string = ':a :b :c';
+ $expected = '2 3';
+ $result = String::insert($string, array('b' => 2, 'c' => 3), array('clean' => true));
+ $this->assertEqual($result, $expected);
+
+ $string = ':a :b :c';
+ $expected = '1 3';
+ $result = String::insert($string, array('a' => 1, 'c' => 3), array('clean' => true));
+ $this->assertEqual($result, $expected);
+
+ $string = ':a :b :c';
+ $expected = '2 3';
+ $result = String::insert($string, array('b' => 2, 'c' => 3), array('clean' => true));
+ $this->assertEqual($result, $expected);
+
+ $string = ':a, :b and :c';
+ $expected = '2 and 3';
+ $result = String::insert($string, array('b' => 2, 'c' => 3), array('clean' => true));
+ $this->assertEqual($result, $expected);
+
+ $string = '":a, :b and :c"';
+ $expected = '"1, 2"';
+ $result = String::insert($string, array('a' => 1, 'b' => 2), array('clean' => true));
+ $this->assertEqual($result, $expected);
+
+ $string = '"${a}, ${b} and ${c}"';
+ $expected = '"1, 2"';
+ $result = String::insert($string, array('a' => 1, 'b' => 2), array('before' => '${', 'after' => '}', 'clean' => true));
+ $this->assertEqual($result, $expected);
+
+ $string = '';
+ $expected = ' ';
+ $result = String::insert($string, array('src' => 'foo'), array('clean' => 'html'));
+
+ $this->assertEqual($result, $expected);
+
+ $string = '';
+ $expected = ' ';
+ $result = String::insert($string, array('src' => 'foo'), array('clean' => 'html'));
+ $this->assertEqual($result, $expected);
+
+ $string = '';
+ $expected = ' ';
+ $result = String::insert($string, array('src' => 'foo', 'extra' => 'bar'), array('clean' => 'html'));
+ $this->assertEqual($result, $expected);
+
+ $result = String::insert("this is a ? string", "test");
+ $expected = "this is a test string";
+ $this->assertEqual($result, $expected);
+
+ $result = String::insert("this is a ? string with a ? ? ?", array('long', 'few?', 'params', 'you know'));
+ $expected = "this is a long string with a few? params you know";
+ $this->assertEqual($result, $expected);
+
+ $result = String::insert('update saved_urls set url = :url where id = :id', array('url' => 'http://www.testurl.com/param1:url/param2:id','id' => 1));
+ $expected = "update saved_urls set url = http://www.testurl.com/param1:url/param2:id where id = 1";
+ $this->assertEqual($result, $expected);
+
+ $result = String::insert('update saved_urls set url = :url where id = :id', array('id' => 1, 'url' => 'http://www.testurl.com/param1:url/param2:id'));
+ $expected = "update saved_urls set url = http://www.testurl.com/param1:url/param2:id where id = 1";
+ $this->assertEqual($result, $expected);
+
+ $result = String::insert(':me cake. :subject :verb fantastic.', array('me' => 'I :verb', 'subject' => 'cake', 'verb' => 'is'));
+ $expected = "I :verb cake. cake is fantastic.";
+ $this->assertEqual($result, $expected);
+
+ $result = String::insert(':I.am: :not.yet: passing.', array('I.am' => 'We are'), array('before' => ':', 'after' => ':', 'clean' => array('replacement' => ' of course', 'method' => 'text')));
+ $expected = "We are of course passing.";
+ $this->assertEqual($result, $expected);
+
+ $result = String::insert(
+ ':I.am: :not.yet: passing.',
+ array('I.am' => 'We are'),
+ array('before' => ':', 'after' => ':', 'clean' => true)
+ );
+ $expected = "We are passing.";
+ $this->assertEqual($result, $expected);
+
+ $result = String::insert('?-pended result', array('Pre'));
+ $expected = "Pre-pended result";
+ $this->assertEqual($result, $expected);
+
+ $string = 'switching :timeout / :timeout_count';
+ $expected = 'switching 5 / 10';
+ $result = String::insert($string, array('timeout' => 5, 'timeout_count' => 10));
+ $this->assertEqual($result, $expected);
+
+ $string = 'switching :timeout / :timeout_count';
+ $expected = 'switching 5 / 10';
+ $result = String::insert($string, array('timeout_count' => 10, 'timeout' => 5));
+ $this->assertEqual($result, $expected);
+
+ $string = 'switching :timeout_count by :timeout';
+ $expected = 'switching 10 by 5';
+ $result = String::insert($string, array('timeout' => 5, 'timeout_count' => 10));
+ $this->assertEqual($result, $expected);
+
+ $string = 'switching :timeout_count by :timeout';
+ $expected = 'switching 10 by 5';
+ $result = String::insert($string, array('timeout_count' => 10, 'timeout' => 5));
+ $this->assertEqual($result, $expected);
+ }
+
+/**
+ * test Clean Insert
+ *
+ * @return void
+ */
+ function testCleanInsert() {
+ $result = String::cleanInsert(':incomplete', array(
+ 'clean' => true, 'before' => ':', 'after' => ''
+ ));
+ $this->assertEqual($result, '');
+
+ $result = String::cleanInsert(':incomplete', array(
+ 'clean' => array('method' => 'text', 'replacement' => 'complete'),
+ 'before' => ':', 'after' => '')
+ );
+ $this->assertEqual($result, 'complete');
+
+ $result = String::cleanInsert(':in.complete', array(
+ 'clean' => true, 'before' => ':', 'after' => ''
+ ));
+ $this->assertEqual($result, '');
+
+ $result = String::cleanInsert(':in.complete and', array(
+ 'clean' => true, 'before' => ':', 'after' => '')
+ );
+ $this->assertEqual($result, '');
+
+ $result = String::cleanInsert(':in.complete or stuff', array(
+ 'clean' => true, 'before' => ':', 'after' => ''
+ ));
+ $this->assertEqual($result, 'stuff');
+
+ $result = String::cleanInsert(
+ 'Text here
',
+ array('clean' => 'html', 'before' => ':', 'after' => '')
+ );
+ $this->assertEqual($result, 'Text here
');
+ }
+
+/**
+ * Tests that non-insertable variables (i.e. arrays) are skipped when used as values in
+ * String::insert().
+ *
+ * @return void
+ */
+ function testAutoIgnoreBadInsertData() {
+ $data = array('foo' => 'alpha', 'bar' => 'beta', 'fale' => array());
+ $result = String::insert('(:foo > :bar || :fale!)', $data, array('clean' => 'text'));
+ $this->assertEqual($result, '(alpha > beta || !)');
+ }
+
+/**
+ * testTokenize method
+ *
+ * @access public
+ * @return void
+ */
+ function testTokenize() {
+ $result = String::tokenize('A,(short,boring test)');
+ $expected = array('A', '(short,boring test)');
+ $this->assertEqual($result, $expected);
+
+ $result = String::tokenize('A,(short,more interesting( test)');
+ $expected = array('A', '(short,more interesting( test)');
+ $this->assertEqual($result, $expected);
+
+ $result = String::tokenize('A,(short,very interesting( test))');
+ $expected = array('A', '(short,very interesting( test))');
+ $this->assertEqual($result, $expected);
+
+ $result = String::tokenize('"single tag"', ' ', '"', '"');
+ $expected = array('"single tag"');
+ $this->assertEqual($expected, $result);
+
+ $result = String::tokenize('tagA "single tag" tagB', ' ', '"', '"');
+ $expected = array('tagA', '"single tag"', 'tagB');
+ $this->assertEqual($expected, $result);
+ }
+
+ function testReplaceWithQuestionMarkInString() {
+ $string = ':a, :b and :c?';
+ $expected = '2 and 3?';
+ $result = String::insert($string, array('b' => 2, 'c' => 3), array('clean' => true));
+ $this->assertEqual($expected, $result);
+ }
+}
diff --git a/code/ryzom/tools/server/www/webtt/cake/tests/cases/libs/test_manager.test.php b/code/ryzom/tools/server/www/webtt/cake/tests/cases/libs/test_manager.test.php
new file mode 100644
index 000000000..a55149988
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/cake/tests/cases/libs/test_manager.test.php
@@ -0,0 +1,120 @@
+
+ * Copyright 2005-2010, Cake Software Foundation, Inc.
+ * 1785 E. Sahara Avenue, Suite 490-204
+ * Las Vegas, Nevada 89104
+ *
+ * Licensed under The Open Group Test Suite License
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
+ * @link http://book.cakephp.org/view/1196/Testing CakePHP(tm) Tests
+ * @package cake
+ * @subpackage cake.tests.cases.libs
+ * @since CakePHP(tm) v 1.2.0.4206
+ * @license http://www.opensource.org/licenses/opengroup.php The Open Group Test Suite License
+ */
+
+/**
+ * TestManagerTest class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs
+ */
+class TestManagerTest extends CakeTestCase {
+
+/**
+ * setUp method
+ *
+ * @return void
+ * @access public
+ */
+ function setUp() {
+ $this->TestManager =& new TestManager();
+ $this->Reporter =& new CakeHtmlReporter();
+ }
+
+/**
+ * testRunAllTests method
+ *
+ * @return void
+ * @access public
+ */
+ function testRunAllTests() {
+ $folder =& new Folder($this->TestManager->_getTestsPath());
+ $extension = str_replace('.', '\.', $this->TestManager->getExtension('test'));
+ $out = $folder->findRecursive('.*' . $extension);
+
+ $reporter =& new CakeHtmlReporter();
+ $list = $this->TestManager->runAllTests($reporter, true);
+
+ $this->assertEqual(count($out), count($list));
+ }
+
+/**
+ * testRunTestCase method
+ *
+ * @return void
+ * @access public
+ */
+ function testRunTestCase() {
+ $file = md5(time());
+ $result = $this->TestManager->runTestCase($file, $this->Reporter);
+ $this->assertError('Test case ' . $file . ' cannot be found');
+ $this->assertFalse($result);
+
+ $file = str_replace(CORE_TEST_CASES, '', __FILE__);
+ $result = $this->TestManager->runTestCase($file, $this->Reporter, true);
+ $this->assertTrue($result);
+ }
+
+/**
+ * testRunGroupTest method
+ *
+ * @return void
+ * @access public
+ */
+ function testRunGroupTest() {
+ }
+
+/**
+ * testAddTestCasesFromDirectory method
+ *
+ * @return void
+ * @access public
+ */
+ function testAddTestCasesFromDirectory() {
+ }
+
+/**
+ * testAddTestFile method
+ *
+ * @return void
+ * @access public
+ */
+ function testAddTestFile() {
+ }
+
+/**
+ * testGetTestCaseList method
+ *
+ * @return void
+ * @access public
+ */
+ function testGetTestCaseList() {
+ }
+
+/**
+ * testGetGroupTestList method
+ *
+ * @return void
+ * @access public
+ */
+ function testGetGroupTestList() {
+ }
+}
diff --git a/code/ryzom/tools/server/www/webtt/cake/tests/cases/libs/validation.test.php b/code/ryzom/tools/server/www/webtt/cake/tests/cases/libs/validation.test.php
new file mode 100644
index 000000000..f9908c071
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/cake/tests/cases/libs/validation.test.php
@@ -0,0 +1,2209 @@
+
+ * Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
+ *
+ * Licensed under The Open Group Test Suite License
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
+ * @link http://book.cakephp.org/view/1196/Testing CakePHP(tm) Tests
+ * @package cake
+ * @subpackage cake.tests.cases.libs
+ * @since CakePHP(tm) v 1.2.0.4206
+ * @license http://www.opensource.org/licenses/opengroup.php The Open Group Test Suite License
+ */
+App::import('Core', 'Validation');
+
+/**
+ * CustomValidator class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs
+ */
+class CustomValidator {
+
+/**
+ * Makes sure that a given $email address is valid and unique
+ *
+ * @param string $email
+ * @return boolean
+ * @access public
+ */
+ function customValidate($check) {
+ return preg_match('/^[0-9]{3}$/', $check);
+ }
+}
+
+/**
+ * TestNlValidation class
+ *
+ * Used to test pass through of Validation
+ *
+ * @package cake.tests.cases.libs
+ */
+class TestNlValidation {
+/**
+ * postal function, for testing postal pass through.
+ *
+ * @param string $check
+ * @return void
+ */
+ function postal($check) {
+ return true;
+ }
+/**
+ * ssn function for testing ssn pass through
+ *
+ * @return void
+ */
+ function ssn($check) {
+ return true;
+ }
+}
+
+/**
+ * TestDeValidation class
+ *
+ * Used to test pass through of Validation
+ *
+ * @package cake.tests.cases.libs
+ */
+class TestDeValidation {
+/**
+ * phone function, for testing phone pass through.
+ *
+ * @param string $check
+ * @return void
+ */
+ function phone($check) {
+ return true;
+ }
+}
+
+/**
+ * Test Case for Validation Class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs
+ */
+class ValidationTest extends CakeTestCase {
+
+/**
+ * Validation property
+ *
+ * @var mixed null
+ * @access public
+ */
+ var $Validation = null;
+
+/**
+ * setup method
+ *
+ * @access public
+ * @return void
+ */
+ function setUp() {
+ $this->Validation =& Validation::getInstance();
+ $this->_appEncoding = Configure::read('App.encoding');
+ }
+
+/**
+ * tearDown method
+ *
+ * @access public
+ * @return void
+ */
+ function tearDown() {
+ Configure::write('App.encoding', $this->_appEncoding);
+ }
+
+/**
+ * testNotEmpty method
+ *
+ * @access public
+ * @return void
+ */
+ function testNotEmpty() {
+ $this->assertTrue(Validation::notEmpty('abcdefg'));
+ $this->assertTrue(Validation::notEmpty('fasdf '));
+ $this->assertTrue(Validation::notEmpty('fooo'.chr(243).'blabla'));
+ $this->assertTrue(Validation::notEmpty('abçďĕʑʘπй'));
+ $this->assertTrue(Validation::notEmpty('José'));
+ $this->assertTrue(Validation::notEmpty('é'));
+ $this->assertTrue(Validation::notEmpty('π'));
+ $this->assertFalse(Validation::notEmpty("\t "));
+ $this->assertFalse(Validation::notEmpty(""));
+
+ }
+
+/**
+ * testNotEmptyISO88591Encoding method
+ *
+ * @return void
+ * @access public
+ */
+ function testNotEmptyISO88591AppEncoding() {
+ Configure::write('App.encoding', 'ISO-8859-1');
+ $this->assertTrue(Validation::notEmpty('abcdefg'));
+ $this->assertTrue(Validation::notEmpty('fasdf '));
+ $this->assertTrue(Validation::notEmpty('fooo'.chr(243).'blabla'));
+ $this->assertTrue(Validation::notEmpty('abçďĕʑʘπй'));
+ $this->assertTrue(Validation::notEmpty('José'));
+ $this->assertTrue(Validation::notEmpty(utf8_decode('José')));
+ $this->assertFalse(Validation::notEmpty("\t "));
+ $this->assertFalse(Validation::notEmpty(""));
+ }
+
+/**
+ * testAlphaNumeric method
+ *
+ * @access public
+ * @return void
+ */
+ function testAlphaNumeric() {
+ $this->assertTrue(Validation::alphaNumeric('frferrf'));
+ $this->assertTrue(Validation::alphaNumeric('12234'));
+ $this->assertTrue(Validation::alphaNumeric('1w2e2r3t4y'));
+ $this->assertTrue(Validation::alphaNumeric('0'));
+ $this->assertTrue(Validation::alphaNumeric('abçďĕʑʘπй'));
+ $this->assertTrue(Validation::alphaNumeric('ˇˆๆゞ'));
+ $this->assertTrue(Validation::alphaNumeric('אกあアꀀ豈'));
+ $this->assertTrue(Validation::alphaNumeric('Džᾈᾨ'));
+ $this->assertTrue(Validation::alphaNumeric('ÆΔΩЖÇ'));
+
+
+ $this->assertFalse(Validation::alphaNumeric('12 234'));
+ $this->assertFalse(Validation::alphaNumeric('dfd 234'));
+ $this->assertFalse(Validation::alphaNumeric("\n"));
+ $this->assertFalse(Validation::alphaNumeric("\t"));
+ $this->assertFalse(Validation::alphaNumeric("\r"));
+ $this->assertFalse(Validation::alphaNumeric(' '));
+ $this->assertFalse(Validation::alphaNumeric(''));
+ }
+
+/**
+ * testAlphaNumericPassedAsArray method
+ *
+ * @access public
+ * @return void
+ */
+ function testAlphaNumericPassedAsArray() {
+ $this->assertTrue(Validation::alphaNumeric(array('check' => 'frferrf')));
+ $this->assertTrue(Validation::alphaNumeric(array('check' => '12234')));
+ $this->assertTrue(Validation::alphaNumeric(array('check' => '1w2e2r3t4y')));
+ $this->assertTrue(Validation::alphaNumeric(array('check' => '0')));
+ $this->assertFalse(Validation::alphaNumeric(array('check' => '12 234')));
+ $this->assertFalse(Validation::alphaNumeric(array('check' => 'dfd 234')));
+ $this->assertFalse(Validation::alphaNumeric(array('check' => "\n")));
+ $this->assertFalse(Validation::alphaNumeric(array('check' => "\t")));
+ $this->assertFalse(Validation::alphaNumeric(array('check' => "\r")));
+ $this->assertFalse(Validation::alphaNumeric(array('check' => ' ')));
+ $this->assertFalse(Validation::alphaNumeric(array('check' => '')));
+ }
+
+/**
+ * testBetween method
+ *
+ * @access public
+ * @return void
+ */
+ function testBetween() {
+ $this->assertTrue(Validation::between('abcdefg', 1, 7));
+ $this->assertTrue(Validation::between('', 0, 7));
+ $this->assertTrue(Validation::between('אกあアꀀ豈', 1, 7));
+
+ $this->assertFalse(Validation::between('abcdefg', 1, 6));
+ $this->assertFalse(Validation::between('ÆΔΩЖÇ', 1, 3));
+ }
+
+/**
+ * testBlank method
+ *
+ * @access public
+ * @return void
+ */
+ function testBlank() {
+ $this->assertTrue(Validation::blank(''));
+ $this->assertTrue(Validation::blank(' '));
+ $this->assertTrue(Validation::blank("\n"));
+ $this->assertTrue(Validation::blank("\t"));
+ $this->assertTrue(Validation::blank("\r"));
+ $this->assertFalse(Validation::blank(' Blank'));
+ $this->assertFalse(Validation::blank('Blank'));
+ }
+
+/**
+ * testBlankAsArray method
+ *
+ * @access public
+ * @return void
+ */
+ function testBlankAsArray() {
+ $this->assertTrue(Validation::blank(array('check' => '')));
+ $this->assertTrue(Validation::blank(array('check' => ' ')));
+ $this->assertTrue(Validation::blank(array('check' => "\n")));
+ $this->assertTrue(Validation::blank(array('check' => "\t")));
+ $this->assertTrue(Validation::blank(array('check' => "\r")));
+ $this->assertFalse(Validation::blank(array('check' => ' Blank')));
+ $this->assertFalse(Validation::blank(array('check' => 'Blank')));
+ }
+
+/**
+ * testcc method
+ *
+ * @access public
+ * @return void
+ */
+ function testcc() {
+ //American Express
+ $this->assertTrue(Validation::cc('370482756063980', array('amex')));
+ $this->assertTrue(Validation::cc('349106433773483', array('amex')));
+ $this->assertTrue(Validation::cc('344671486204764', array('amex')));
+ $this->assertTrue(Validation::cc('344042544509943', array('amex')));
+ $this->assertTrue(Validation::cc('377147515754475', array('amex')));
+ $this->assertTrue(Validation::cc('375239372816422', array('amex')));
+ $this->assertTrue(Validation::cc('376294341957707', array('amex')));
+ $this->assertTrue(Validation::cc('341779292230411', array('amex')));
+ $this->assertTrue(Validation::cc('341646919853372', array('amex')));
+ $this->assertTrue(Validation::cc('348498616319346', array('amex')));
+ //BankCard
+ $this->assertTrue(Validation::cc('5610745867413420', array('bankcard')));
+ $this->assertTrue(Validation::cc('5610376649499352', array('bankcard')));
+ $this->assertTrue(Validation::cc('5610091936000694', array('bankcard')));
+ $this->assertTrue(Validation::cc('5602248780118788', array('bankcard')));
+ $this->assertTrue(Validation::cc('5610631567676765', array('bankcard')));
+ $this->assertTrue(Validation::cc('5602238211270795', array('bankcard')));
+ $this->assertTrue(Validation::cc('5610173951215470', array('bankcard')));
+ $this->assertTrue(Validation::cc('5610139705753702', array('bankcard')));
+ $this->assertTrue(Validation::cc('5602226032150551', array('bankcard')));
+ $this->assertTrue(Validation::cc('5602223993735777', array('bankcard')));
+ //Diners Club 14
+ $this->assertTrue(Validation::cc('30155483651028', array('diners')));
+ $this->assertTrue(Validation::cc('36371312803821', array('diners')));
+ $this->assertTrue(Validation::cc('38801277489875', array('diners')));
+ $this->assertTrue(Validation::cc('30348560464296', array('diners')));
+ $this->assertTrue(Validation::cc('30349040317708', array('diners')));
+ $this->assertTrue(Validation::cc('36567413559978', array('diners')));
+ $this->assertTrue(Validation::cc('36051554732702', array('diners')));
+ $this->assertTrue(Validation::cc('30391842198191', array('diners')));
+ $this->assertTrue(Validation::cc('30172682197745', array('diners')));
+ $this->assertTrue(Validation::cc('30162056566641', array('diners')));
+ $this->assertTrue(Validation::cc('30085066927745', array('diners')));
+ $this->assertTrue(Validation::cc('36519025221976', array('diners')));
+ $this->assertTrue(Validation::cc('30372679371044', array('diners')));
+ $this->assertTrue(Validation::cc('38913939150124', array('diners')));
+ $this->assertTrue(Validation::cc('36852899094637', array('diners')));
+ $this->assertTrue(Validation::cc('30138041971120', array('diners')));
+ $this->assertTrue(Validation::cc('36184047836838', array('diners')));
+ $this->assertTrue(Validation::cc('30057460264462', array('diners')));
+ $this->assertTrue(Validation::cc('38980165212050', array('diners')));
+ $this->assertTrue(Validation::cc('30356516881240', array('diners')));
+ $this->assertTrue(Validation::cc('38744810033182', array('diners')));
+ $this->assertTrue(Validation::cc('30173638706621', array('diners')));
+ $this->assertTrue(Validation::cc('30158334709185', array('diners')));
+ $this->assertTrue(Validation::cc('30195413721186', array('diners')));
+ $this->assertTrue(Validation::cc('38863347694793', array('diners')));
+ $this->assertTrue(Validation::cc('30275627009113', array('diners')));
+ $this->assertTrue(Validation::cc('30242860404971', array('diners')));
+ $this->assertTrue(Validation::cc('30081877595151', array('diners')));
+ $this->assertTrue(Validation::cc('38053196067461', array('diners')));
+ $this->assertTrue(Validation::cc('36520379984870', array('diners')));
+ //2004 MasterCard/Diners Club Alliance International 14
+ $this->assertTrue(Validation::cc('36747701998969', array('diners')));
+ $this->assertTrue(Validation::cc('36427861123159', array('diners')));
+ $this->assertTrue(Validation::cc('36150537602386', array('diners')));
+ $this->assertTrue(Validation::cc('36582388820610', array('diners')));
+ $this->assertTrue(Validation::cc('36729045250216', array('diners')));
+ //2004 MasterCard/Diners Club Alliance US & Canada 16
+ $this->assertTrue(Validation::cc('5597511346169950', array('diners')));
+ $this->assertTrue(Validation::cc('5526443162217562', array('diners')));
+ $this->assertTrue(Validation::cc('5577265786122391', array('diners')));
+ $this->assertTrue(Validation::cc('5534061404676989', array('diners')));
+ $this->assertTrue(Validation::cc('5545313588374502', array('diners')));
+ //Discover
+ $this->assertTrue(Validation::cc('6011802876467237', array('disc')));
+ $this->assertTrue(Validation::cc('6506432777720955', array('disc')));
+ $this->assertTrue(Validation::cc('6011126265283942', array('disc')));
+ $this->assertTrue(Validation::cc('6502187151579252', array('disc')));
+ $this->assertTrue(Validation::cc('6506600836002298', array('disc')));
+ $this->assertTrue(Validation::cc('6504376463615189', array('disc')));
+ $this->assertTrue(Validation::cc('6011440907005377', array('disc')));
+ $this->assertTrue(Validation::cc('6509735979634270', array('disc')));
+ $this->assertTrue(Validation::cc('6011422366775856', array('disc')));
+ $this->assertTrue(Validation::cc('6500976374623323', array('disc')));
+ //enRoute
+ $this->assertTrue(Validation::cc('201496944158937', array('enroute')));
+ $this->assertTrue(Validation::cc('214945833739665', array('enroute')));
+ $this->assertTrue(Validation::cc('214982692491187', array('enroute')));
+ $this->assertTrue(Validation::cc('214901395949424', array('enroute')));
+ $this->assertTrue(Validation::cc('201480676269187', array('enroute')));
+ $this->assertTrue(Validation::cc('214911922887807', array('enroute')));
+ $this->assertTrue(Validation::cc('201485025457250', array('enroute')));
+ $this->assertTrue(Validation::cc('201402662758866', array('enroute')));
+ $this->assertTrue(Validation::cc('214981579370225', array('enroute')));
+ $this->assertTrue(Validation::cc('201447595859877', array('enroute')));
+ //JCB 15 digit
+ $this->assertTrue(Validation::cc('210034762247893', array('jcb')));
+ $this->assertTrue(Validation::cc('180078671678892', array('jcb')));
+ $this->assertTrue(Validation::cc('180010559353736', array('jcb')));
+ $this->assertTrue(Validation::cc('210095474464258', array('jcb')));
+ $this->assertTrue(Validation::cc('210006675562188', array('jcb')));
+ $this->assertTrue(Validation::cc('210063299662662', array('jcb')));
+ $this->assertTrue(Validation::cc('180032506857825', array('jcb')));
+ $this->assertTrue(Validation::cc('210057919192738', array('jcb')));
+ $this->assertTrue(Validation::cc('180031358949367', array('jcb')));
+ $this->assertTrue(Validation::cc('180033802147846', array('jcb')));
+ //JCB 16 digit
+ $this->assertTrue(Validation::cc('3096806857839939', array('jcb')));
+ $this->assertTrue(Validation::cc('3158699503187091', array('jcb')));
+ $this->assertTrue(Validation::cc('3112549607186579', array('jcb')));
+ $this->assertTrue(Validation::cc('3112332922425604', array('jcb')));
+ $this->assertTrue(Validation::cc('3112001541159239', array('jcb')));
+ $this->assertTrue(Validation::cc('3112162495317841', array('jcb')));
+ $this->assertTrue(Validation::cc('3337562627732768', array('jcb')));
+ $this->assertTrue(Validation::cc('3337107161330775', array('jcb')));
+ $this->assertTrue(Validation::cc('3528053736003621', array('jcb')));
+ $this->assertTrue(Validation::cc('3528915255020360', array('jcb')));
+ $this->assertTrue(Validation::cc('3096786059660921', array('jcb')));
+ $this->assertTrue(Validation::cc('3528264799292320', array('jcb')));
+ $this->assertTrue(Validation::cc('3096469164130136', array('jcb')));
+ $this->assertTrue(Validation::cc('3112127443822853', array('jcb')));
+ $this->assertTrue(Validation::cc('3096849995802328', array('jcb')));
+ $this->assertTrue(Validation::cc('3528090735127407', array('jcb')));
+ $this->assertTrue(Validation::cc('3112101006819234', array('jcb')));
+ $this->assertTrue(Validation::cc('3337444428040784', array('jcb')));
+ $this->assertTrue(Validation::cc('3088043154151061', array('jcb')));
+ $this->assertTrue(Validation::cc('3088295969414866', array('jcb')));
+ $this->assertTrue(Validation::cc('3158748843158575', array('jcb')));
+ $this->assertTrue(Validation::cc('3158709206148538', array('jcb')));
+ $this->assertTrue(Validation::cc('3158365159575324', array('jcb')));
+ $this->assertTrue(Validation::cc('3158671691305165', array('jcb')));
+ $this->assertTrue(Validation::cc('3528523028771093', array('jcb')));
+ $this->assertTrue(Validation::cc('3096057126267870', array('jcb')));
+ $this->assertTrue(Validation::cc('3158514047166834', array('jcb')));
+ $this->assertTrue(Validation::cc('3528274546125962', array('jcb')));
+ $this->assertTrue(Validation::cc('3528890967705733', array('jcb')));
+ $this->assertTrue(Validation::cc('3337198811307545', array('jcb')));
+ //Maestro (debit card)
+ $this->assertTrue(Validation::cc('5020147409985219', array('maestro')));
+ $this->assertTrue(Validation::cc('5020931809905616', array('maestro')));
+ $this->assertTrue(Validation::cc('5020412965470224', array('maestro')));
+ $this->assertTrue(Validation::cc('5020129740944022', array('maestro')));
+ $this->assertTrue(Validation::cc('5020024696747943', array('maestro')));
+ $this->assertTrue(Validation::cc('5020581514636509', array('maestro')));
+ $this->assertTrue(Validation::cc('5020695008411987', array('maestro')));
+ $this->assertTrue(Validation::cc('5020565359718977', array('maestro')));
+ $this->assertTrue(Validation::cc('6339931536544062', array('maestro')));
+ $this->assertTrue(Validation::cc('6465028615704406', array('maestro')));
+ //Mastercard
+ $this->assertTrue(Validation::cc('5580424361774366', array('mc')));
+ $this->assertTrue(Validation::cc('5589563059318282', array('mc')));
+ $this->assertTrue(Validation::cc('5387558333690047', array('mc')));
+ $this->assertTrue(Validation::cc('5163919215247175', array('mc')));
+ $this->assertTrue(Validation::cc('5386742685055055', array('mc')));
+ $this->assertTrue(Validation::cc('5102303335960674', array('mc')));
+ $this->assertTrue(Validation::cc('5526543403964565', array('mc')));
+ $this->assertTrue(Validation::cc('5538725892618432', array('mc')));
+ $this->assertTrue(Validation::cc('5119543573129778', array('mc')));
+ $this->assertTrue(Validation::cc('5391174753915767', array('mc')));
+ $this->assertTrue(Validation::cc('5510994113980714', array('mc')));
+ $this->assertTrue(Validation::cc('5183720260418091', array('mc')));
+ $this->assertTrue(Validation::cc('5488082196086704', array('mc')));
+ $this->assertTrue(Validation::cc('5484645164161834', array('mc')));
+ $this->assertTrue(Validation::cc('5171254350337031', array('mc')));
+ $this->assertTrue(Validation::cc('5526987528136452', array('mc')));
+ $this->assertTrue(Validation::cc('5504148941409358', array('mc')));
+ $this->assertTrue(Validation::cc('5240793507243615', array('mc')));
+ $this->assertTrue(Validation::cc('5162114693017107', array('mc')));
+ $this->assertTrue(Validation::cc('5163104807404753', array('mc')));
+ $this->assertTrue(Validation::cc('5590136167248365', array('mc')));
+ $this->assertTrue(Validation::cc('5565816281038948', array('mc')));
+ $this->assertTrue(Validation::cc('5467639122779531', array('mc')));
+ $this->assertTrue(Validation::cc('5297350261550024', array('mc')));
+ $this->assertTrue(Validation::cc('5162739131368058', array('mc')));
+ //Solo 16
+ $this->assertTrue(Validation::cc('6767432107064987', array('solo')));
+ $this->assertTrue(Validation::cc('6334667758225411', array('solo')));
+ $this->assertTrue(Validation::cc('6767037421954068', array('solo')));
+ $this->assertTrue(Validation::cc('6767823306394854', array('solo')));
+ $this->assertTrue(Validation::cc('6334768185398134', array('solo')));
+ $this->assertTrue(Validation::cc('6767286729498589', array('solo')));
+ $this->assertTrue(Validation::cc('6334972104431261', array('solo')));
+ $this->assertTrue(Validation::cc('6334843427400616', array('solo')));
+ $this->assertTrue(Validation::cc('6767493947881311', array('solo')));
+ $this->assertTrue(Validation::cc('6767194235798817', array('solo')));
+ //Solo 18
+ $this->assertTrue(Validation::cc('676714834398858593', array('solo')));
+ $this->assertTrue(Validation::cc('676751666435130857', array('solo')));
+ $this->assertTrue(Validation::cc('676781908573924236', array('solo')));
+ $this->assertTrue(Validation::cc('633488724644003240', array('solo')));
+ $this->assertTrue(Validation::cc('676732252338067316', array('solo')));
+ $this->assertTrue(Validation::cc('676747520084495821', array('solo')));
+ $this->assertTrue(Validation::cc('633465488901381957', array('solo')));
+ $this->assertTrue(Validation::cc('633487484858610484', array('solo')));
+ $this->assertTrue(Validation::cc('633453764680740694', array('solo')));
+ $this->assertTrue(Validation::cc('676768613295414451', array('solo')));
+ //Solo 19
+ $this->assertTrue(Validation::cc('6767838565218340113', array('solo')));
+ $this->assertTrue(Validation::cc('6767760119829705181', array('solo')));
+ $this->assertTrue(Validation::cc('6767265917091593668', array('solo')));
+ $this->assertTrue(Validation::cc('6767938856947440111', array('solo')));
+ $this->assertTrue(Validation::cc('6767501945697390076', array('solo')));
+ $this->assertTrue(Validation::cc('6334902868716257379', array('solo')));
+ $this->assertTrue(Validation::cc('6334922127686425532', array('solo')));
+ $this->assertTrue(Validation::cc('6334933119080706440', array('solo')));
+ $this->assertTrue(Validation::cc('6334647959628261714', array('solo')));
+ $this->assertTrue(Validation::cc('6334527312384101382', array('solo')));
+ //Switch 16
+ $this->assertTrue(Validation::cc('5641829171515733', array('switch')));
+ $this->assertTrue(Validation::cc('5641824852820809', array('switch')));
+ $this->assertTrue(Validation::cc('6759129648956909', array('switch')));
+ $this->assertTrue(Validation::cc('6759626072268156', array('switch')));
+ $this->assertTrue(Validation::cc('5641822698388957', array('switch')));
+ $this->assertTrue(Validation::cc('5641827123105470', array('switch')));
+ $this->assertTrue(Validation::cc('5641823755819553', array('switch')));
+ $this->assertTrue(Validation::cc('5641821939587682', array('switch')));
+ $this->assertTrue(Validation::cc('4936097148079186', array('switch')));
+ $this->assertTrue(Validation::cc('5641829739125009', array('switch')));
+ $this->assertTrue(Validation::cc('5641822860725507', array('switch')));
+ $this->assertTrue(Validation::cc('4936717688865831', array('switch')));
+ $this->assertTrue(Validation::cc('6759487613615441', array('switch')));
+ $this->assertTrue(Validation::cc('5641821346840617', array('switch')));
+ $this->assertTrue(Validation::cc('5641825793417126', array('switch')));
+ $this->assertTrue(Validation::cc('5641821302759595', array('switch')));
+ $this->assertTrue(Validation::cc('6759784969918837', array('switch')));
+ $this->assertTrue(Validation::cc('5641824910667036', array('switch')));
+ $this->assertTrue(Validation::cc('6759139909636173', array('switch')));
+ $this->assertTrue(Validation::cc('6333425070638022', array('switch')));
+ $this->assertTrue(Validation::cc('5641823910382067', array('switch')));
+ $this->assertTrue(Validation::cc('4936295218139423', array('switch')));
+ $this->assertTrue(Validation::cc('6333031811316199', array('switch')));
+ $this->assertTrue(Validation::cc('4936912044763198', array('switch')));
+ $this->assertTrue(Validation::cc('4936387053303824', array('switch')));
+ $this->assertTrue(Validation::cc('6759535838760523', array('switch')));
+ $this->assertTrue(Validation::cc('6333427174594051', array('switch')));
+ $this->assertTrue(Validation::cc('5641829037102700', array('switch')));
+ $this->assertTrue(Validation::cc('5641826495463046', array('switch')));
+ $this->assertTrue(Validation::cc('6333480852979946', array('switch')));
+ $this->assertTrue(Validation::cc('5641827761302876', array('switch')));
+ $this->assertTrue(Validation::cc('5641825083505317', array('switch')));
+ $this->assertTrue(Validation::cc('6759298096003991', array('switch')));
+ $this->assertTrue(Validation::cc('4936119165483420', array('switch')));
+ $this->assertTrue(Validation::cc('4936190990500993', array('switch')));
+ $this->assertTrue(Validation::cc('4903356467384927', array('switch')));
+ $this->assertTrue(Validation::cc('6333372765092554', array('switch')));
+ $this->assertTrue(Validation::cc('5641821330950570', array('switch')));
+ $this->assertTrue(Validation::cc('6759841558826118', array('switch')));
+ $this->assertTrue(Validation::cc('4936164540922452', array('switch')));
+ //Switch 18
+ $this->assertTrue(Validation::cc('493622764224625174', array('switch')));
+ $this->assertTrue(Validation::cc('564182823396913535', array('switch')));
+ $this->assertTrue(Validation::cc('675917308304801234', array('switch')));
+ $this->assertTrue(Validation::cc('675919890024220298', array('switch')));
+ $this->assertTrue(Validation::cc('633308376862556751', array('switch')));
+ $this->assertTrue(Validation::cc('564182377633208779', array('switch')));
+ $this->assertTrue(Validation::cc('564182870014926787', array('switch')));
+ $this->assertTrue(Validation::cc('675979788553829819', array('switch')));
+ $this->assertTrue(Validation::cc('493668394358130935', array('switch')));
+ $this->assertTrue(Validation::cc('493637431790930965', array('switch')));
+ $this->assertTrue(Validation::cc('633321438601941513', array('switch')));
+ $this->assertTrue(Validation::cc('675913800898840986', array('switch')));
+ $this->assertTrue(Validation::cc('564182592016841547', array('switch')));
+ $this->assertTrue(Validation::cc('564182428380440899', array('switch')));
+ $this->assertTrue(Validation::cc('493696376827623463', array('switch')));
+ $this->assertTrue(Validation::cc('675977939286485757', array('switch')));
+ $this->assertTrue(Validation::cc('490302699502091579', array('switch')));
+ $this->assertTrue(Validation::cc('564182085013662230', array('switch')));
+ $this->assertTrue(Validation::cc('493693054263310167', array('switch')));
+ $this->assertTrue(Validation::cc('633321755966697525', array('switch')));
+ $this->assertTrue(Validation::cc('675996851719732811', array('switch')));
+ $this->assertTrue(Validation::cc('493699211208281028', array('switch')));
+ $this->assertTrue(Validation::cc('493697817378356614', array('switch')));
+ $this->assertTrue(Validation::cc('675968224161768150', array('switch')));
+ $this->assertTrue(Validation::cc('493669416873337627', array('switch')));
+ $this->assertTrue(Validation::cc('564182439172549714', array('switch')));
+ $this->assertTrue(Validation::cc('675926914467673598', array('switch')));
+ $this->assertTrue(Validation::cc('564182565231977809', array('switch')));
+ $this->assertTrue(Validation::cc('675966282607849002', array('switch')));
+ $this->assertTrue(Validation::cc('493691609704348548', array('switch')));
+ $this->assertTrue(Validation::cc('675933118546065120', array('switch')));
+ $this->assertTrue(Validation::cc('493631116677238592', array('switch')));
+ $this->assertTrue(Validation::cc('675921142812825938', array('switch')));
+ $this->assertTrue(Validation::cc('633338311815675113', array('switch')));
+ $this->assertTrue(Validation::cc('633323539867338621', array('switch')));
+ $this->assertTrue(Validation::cc('675964912740845663', array('switch')));
+ $this->assertTrue(Validation::cc('633334008833727504', array('switch')));
+ $this->assertTrue(Validation::cc('493631941273687169', array('switch')));
+ $this->assertTrue(Validation::cc('564182971729706785', array('switch')));
+ $this->assertTrue(Validation::cc('633303461188963496', array('switch')));
+ //Switch 19
+ $this->assertTrue(Validation::cc('6759603460617628716', array('switch')));
+ $this->assertTrue(Validation::cc('4936705825268647681', array('switch')));
+ $this->assertTrue(Validation::cc('5641829846600479183', array('switch')));
+ $this->assertTrue(Validation::cc('6759389846573792530', array('switch')));
+ $this->assertTrue(Validation::cc('4936189558712637603', array('switch')));
+ $this->assertTrue(Validation::cc('5641822217393868189', array('switch')));
+ $this->assertTrue(Validation::cc('4903075563780057152', array('switch')));
+ $this->assertTrue(Validation::cc('4936510653566569547', array('switch')));
+ $this->assertTrue(Validation::cc('4936503083627303364', array('switch')));
+ $this->assertTrue(Validation::cc('4936777334398116272', array('switch')));
+ $this->assertTrue(Validation::cc('5641823876900554860', array('switch')));
+ $this->assertTrue(Validation::cc('6759619236903407276', array('switch')));
+ $this->assertTrue(Validation::cc('6759011470269978117', array('switch')));
+ $this->assertTrue(Validation::cc('6333175833997062502', array('switch')));
+ $this->assertTrue(Validation::cc('6759498728789080439', array('switch')));
+ $this->assertTrue(Validation::cc('4903020404168157841', array('switch')));
+ $this->assertTrue(Validation::cc('6759354334874804313', array('switch')));
+ $this->assertTrue(Validation::cc('6759900856420875115', array('switch')));
+ $this->assertTrue(Validation::cc('5641827269346868860', array('switch')));
+ $this->assertTrue(Validation::cc('5641828995047453870', array('switch')));
+ $this->assertTrue(Validation::cc('6333321884754806543', array('switch')));
+ $this->assertTrue(Validation::cc('6333108246283715901', array('switch')));
+ $this->assertTrue(Validation::cc('6759572372800700102', array('switch')));
+ $this->assertTrue(Validation::cc('4903095096797974933', array('switch')));
+ $this->assertTrue(Validation::cc('6333354315797920215', array('switch')));
+ $this->assertTrue(Validation::cc('6759163746089433755', array('switch')));
+ $this->assertTrue(Validation::cc('6759871666634807647', array('switch')));
+ $this->assertTrue(Validation::cc('5641827883728575248', array('switch')));
+ $this->assertTrue(Validation::cc('4936527975051407847', array('switch')));
+ $this->assertTrue(Validation::cc('5641823318396882141', array('switch')));
+ $this->assertTrue(Validation::cc('6759123772311123708', array('switch')));
+ $this->assertTrue(Validation::cc('4903054736148271088', array('switch')));
+ $this->assertTrue(Validation::cc('4936477526808883952', array('switch')));
+ $this->assertTrue(Validation::cc('4936433964890967966', array('switch')));
+ $this->assertTrue(Validation::cc('6333245128906049344', array('switch')));
+ $this->assertTrue(Validation::cc('4936321036970553134', array('switch')));
+ $this->assertTrue(Validation::cc('4936111816358702773', array('switch')));
+ $this->assertTrue(Validation::cc('4936196077254804290', array('switch')));
+ $this->assertTrue(Validation::cc('6759558831206830183', array('switch')));
+ $this->assertTrue(Validation::cc('5641827998830403137', array('switch')));
+ //VISA 13 digit
+ $this->assertTrue(Validation::cc('4024007174754', array('visa')));
+ $this->assertTrue(Validation::cc('4104816460717', array('visa')));
+ $this->assertTrue(Validation::cc('4716229700437', array('visa')));
+ $this->assertTrue(Validation::cc('4539305400213', array('visa')));
+ $this->assertTrue(Validation::cc('4728260558665', array('visa')));
+ $this->assertTrue(Validation::cc('4929100131792', array('visa')));
+ $this->assertTrue(Validation::cc('4024007117308', array('visa')));
+ $this->assertTrue(Validation::cc('4539915491024', array('visa')));
+ $this->assertTrue(Validation::cc('4539790901139', array('visa')));
+ $this->assertTrue(Validation::cc('4485284914909', array('visa')));
+ $this->assertTrue(Validation::cc('4782793022350', array('visa')));
+ $this->assertTrue(Validation::cc('4556899290685', array('visa')));
+ $this->assertTrue(Validation::cc('4024007134774', array('visa')));
+ $this->assertTrue(Validation::cc('4333412341316', array('visa')));
+ $this->assertTrue(Validation::cc('4539534204543', array('visa')));
+ $this->assertTrue(Validation::cc('4485640373626', array('visa')));
+ $this->assertTrue(Validation::cc('4929911445746', array('visa')));
+ $this->assertTrue(Validation::cc('4539292550806', array('visa')));
+ $this->assertTrue(Validation::cc('4716523014030', array('visa')));
+ $this->assertTrue(Validation::cc('4024007125152', array('visa')));
+ $this->assertTrue(Validation::cc('4539758883311', array('visa')));
+ $this->assertTrue(Validation::cc('4024007103258', array('visa')));
+ $this->assertTrue(Validation::cc('4916933155767', array('visa')));
+ $this->assertTrue(Validation::cc('4024007159672', array('visa')));
+ $this->assertTrue(Validation::cc('4716935544871', array('visa')));
+ $this->assertTrue(Validation::cc('4929415177779', array('visa')));
+ $this->assertTrue(Validation::cc('4929748547896', array('visa')));
+ $this->assertTrue(Validation::cc('4929153468612', array('visa')));
+ $this->assertTrue(Validation::cc('4539397132104', array('visa')));
+ $this->assertTrue(Validation::cc('4485293435540', array('visa')));
+ $this->assertTrue(Validation::cc('4485799412720', array('visa')));
+ $this->assertTrue(Validation::cc('4916744757686', array('visa')));
+ $this->assertTrue(Validation::cc('4556475655426', array('visa')));
+ $this->assertTrue(Validation::cc('4539400441625', array('visa')));
+ $this->assertTrue(Validation::cc('4485437129173', array('visa')));
+ $this->assertTrue(Validation::cc('4716253605320', array('visa')));
+ $this->assertTrue(Validation::cc('4539366156589', array('visa')));
+ $this->assertTrue(Validation::cc('4916498061392', array('visa')));
+ $this->assertTrue(Validation::cc('4716127163779', array('visa')));
+ $this->assertTrue(Validation::cc('4024007183078', array('visa')));
+ $this->assertTrue(Validation::cc('4041553279654', array('visa')));
+ $this->assertTrue(Validation::cc('4532380121960', array('visa')));
+ $this->assertTrue(Validation::cc('4485906062491', array('visa')));
+ $this->assertTrue(Validation::cc('4539365115149', array('visa')));
+ $this->assertTrue(Validation::cc('4485146516702', array('visa')));
+ //VISA 16 digit
+ $this->assertTrue(Validation::cc('4916375389940009', array('visa')));
+ $this->assertTrue(Validation::cc('4929167481032610', array('visa')));
+ $this->assertTrue(Validation::cc('4485029969061519', array('visa')));
+ $this->assertTrue(Validation::cc('4485573845281759', array('visa')));
+ $this->assertTrue(Validation::cc('4485669810383529', array('visa')));
+ $this->assertTrue(Validation::cc('4929615806560327', array('visa')));
+ $this->assertTrue(Validation::cc('4556807505609535', array('visa')));
+ $this->assertTrue(Validation::cc('4532611336232890', array('visa')));
+ $this->assertTrue(Validation::cc('4532201952422387', array('visa')));
+ $this->assertTrue(Validation::cc('4485073797976290', array('visa')));
+ $this->assertTrue(Validation::cc('4024007157580969', array('visa')));
+ $this->assertTrue(Validation::cc('4053740470212274', array('visa')));
+ $this->assertTrue(Validation::cc('4716265831525676', array('visa')));
+ $this->assertTrue(Validation::cc('4024007100222966', array('visa')));
+ $this->assertTrue(Validation::cc('4539556148303244', array('visa')));
+ $this->assertTrue(Validation::cc('4532449879689709', array('visa')));
+ $this->assertTrue(Validation::cc('4916805467840986', array('visa')));
+ $this->assertTrue(Validation::cc('4532155644440233', array('visa')));
+ $this->assertTrue(Validation::cc('4467977802223781', array('visa')));
+ $this->assertTrue(Validation::cc('4539224637000686', array('visa')));
+ $this->assertTrue(Validation::cc('4556629187064965', array('visa')));
+ $this->assertTrue(Validation::cc('4532970205932943', array('visa')));
+ $this->assertTrue(Validation::cc('4821470132041850', array('visa')));
+ $this->assertTrue(Validation::cc('4916214267894485', array('visa')));
+ $this->assertTrue(Validation::cc('4024007169073284', array('visa')));
+ $this->assertTrue(Validation::cc('4716783351296122', array('visa')));
+ $this->assertTrue(Validation::cc('4556480171913795', array('visa')));
+ $this->assertTrue(Validation::cc('4929678411034997', array('visa')));
+ $this->assertTrue(Validation::cc('4682061913519392', array('visa')));
+ $this->assertTrue(Validation::cc('4916495481746474', array('visa')));
+ $this->assertTrue(Validation::cc('4929007108460499', array('visa')));
+ $this->assertTrue(Validation::cc('4539951357838586', array('visa')));
+ $this->assertTrue(Validation::cc('4716482691051558', array('visa')));
+ $this->assertTrue(Validation::cc('4916385069917516', array('visa')));
+ $this->assertTrue(Validation::cc('4929020289494641', array('visa')));
+ $this->assertTrue(Validation::cc('4532176245263774', array('visa')));
+ $this->assertTrue(Validation::cc('4556242273553949', array('visa')));
+ $this->assertTrue(Validation::cc('4481007485188614', array('visa')));
+ $this->assertTrue(Validation::cc('4716533372139623', array('visa')));
+ $this->assertTrue(Validation::cc('4929152038152632', array('visa')));
+ $this->assertTrue(Validation::cc('4539404037310550', array('visa')));
+ $this->assertTrue(Validation::cc('4532800925229140', array('visa')));
+ $this->assertTrue(Validation::cc('4916845885268360', array('visa')));
+ $this->assertTrue(Validation::cc('4394514669078434', array('visa')));
+ $this->assertTrue(Validation::cc('4485611378115042', array('visa')));
+ //Visa Electron
+ $this->assertTrue(Validation::cc('4175003346287100', array('electron')));
+ $this->assertTrue(Validation::cc('4913042516577228', array('electron')));
+ $this->assertTrue(Validation::cc('4917592325659381', array('electron')));
+ $this->assertTrue(Validation::cc('4917084924450511', array('electron')));
+ $this->assertTrue(Validation::cc('4917994610643999', array('electron')));
+ $this->assertTrue(Validation::cc('4175005933743585', array('electron')));
+ $this->assertTrue(Validation::cc('4175008373425044', array('electron')));
+ $this->assertTrue(Validation::cc('4913119763664154', array('electron')));
+ $this->assertTrue(Validation::cc('4913189017481812', array('electron')));
+ $this->assertTrue(Validation::cc('4913085104968622', array('electron')));
+ $this->assertTrue(Validation::cc('4175008803122021', array('electron')));
+ $this->assertTrue(Validation::cc('4913294453962489', array('electron')));
+ $this->assertTrue(Validation::cc('4175009797419290', array('electron')));
+ $this->assertTrue(Validation::cc('4175005028142917', array('electron')));
+ $this->assertTrue(Validation::cc('4913940802385364', array('electron')));
+ //Voyager
+ $this->assertTrue(Validation::cc('869940697287073', array('voyager')));
+ $this->assertTrue(Validation::cc('869934523596112', array('voyager')));
+ $this->assertTrue(Validation::cc('869958670174621', array('voyager')));
+ $this->assertTrue(Validation::cc('869921250068209', array('voyager')));
+ $this->assertTrue(Validation::cc('869972521242198', array('voyager')));
+ }
+
+/**
+ * testLuhn method
+ *
+ * @access public
+ * @return void
+ */
+ function testLuhn() {
+ $this->Validation->deep = true;
+
+ //American Express
+ $this->Validation->check = '370482756063980';
+ $this->assertTrue($this->Validation->_luhn());
+ //BankCard
+ $this->Validation->check = '5610745867413420';
+ $this->assertTrue($this->Validation->_luhn());
+ //Diners Club 14
+ $this->Validation->check = '30155483651028';
+ $this->assertTrue($this->Validation->_luhn());
+ //2004 MasterCard/Diners Club Alliance International 14
+ $this->Validation->check = '36747701998969';
+ $this->assertTrue($this->Validation->_luhn());
+ //2004 MasterCard/Diners Club Alliance US & Canada 16
+ $this->Validation->check = '5597511346169950';
+ $this->assertTrue($this->Validation->_luhn());
+ //Discover
+ $this->Validation->check = '6011802876467237';
+ $this->assertTrue($this->Validation->_luhn());
+ //enRoute
+ $this->Validation->check = '201496944158937';
+ $this->assertTrue($this->Validation->_luhn());
+ //JCB 15 digit
+ $this->Validation->check = '210034762247893';
+ $this->assertTrue($this->Validation->_luhn());
+ //JCB 16 digit
+ $this->Validation->check = '3096806857839939';
+ $this->assertTrue($this->Validation->_luhn());
+ //Maestro (debit card)
+ $this->Validation->check = '5020147409985219';
+ $this->assertTrue($this->Validation->_luhn());
+ //Mastercard
+ $this->Validation->check = '5580424361774366';
+ $this->assertTrue($this->Validation->_luhn());
+ //Solo 16
+ $this->Validation->check = '6767432107064987';
+ $this->assertTrue($this->Validation->_luhn());
+ //Solo 18
+ $this->Validation->check = '676714834398858593';
+ $this->assertTrue($this->Validation->_luhn());
+ //Solo 19
+ $this->Validation->check = '6767838565218340113';
+ $this->assertTrue($this->Validation->_luhn());
+ //Switch 16
+ $this->Validation->check = '5641829171515733';
+ $this->assertTrue($this->Validation->_luhn());
+ //Switch 18
+ $this->Validation->check = '493622764224625174';
+ $this->assertTrue($this->Validation->_luhn());
+ //Switch 19
+ $this->Validation->check = '6759603460617628716';
+ $this->assertTrue($this->Validation->_luhn());
+ //VISA 13 digit
+ $this->Validation->check = '4024007174754';
+ $this->assertTrue($this->Validation->_luhn());
+ //VISA 16 digit
+ $this->Validation->check = '4916375389940009';
+ $this->assertTrue($this->Validation->_luhn());
+ //Visa Electron
+ $this->Validation->check = '4175003346287100';
+ $this->assertTrue($this->Validation->_luhn());
+ //Voyager
+ $this->Validation->check = '869940697287073';
+ $this->assertTrue($this->Validation->_luhn());
+
+ $this->Validation->check = '0000000000000000';
+ $this->assertFalse($this->Validation->_luhn());
+
+ $this->Validation->check = '869940697287173';
+ $this->assertFalse($this->Validation->_luhn());
+ }
+
+/**
+ * testCustomRegexForCc method
+ *
+ * @access public
+ * @return void
+ */
+ function testCustomRegexForCc() {
+ $this->assertTrue(Validation::cc('12332105933743585', null, null, '/123321\\d{11}/'));
+ $this->assertFalse(Validation::cc('1233210593374358', null, null, '/123321\\d{11}/'));
+ $this->assertFalse(Validation::cc('12312305933743585', null, null, '/123321\\d{11}/'));
+ }
+
+/**
+ * testCustomRegexForCcWithLuhnCheck method
+ *
+ * @access public
+ * @return void
+ */
+ function testCustomRegexForCcWithLuhnCheck() {
+ $this->assertTrue(Validation::cc('12332110426226941', null, true, '/123321\\d{11}/'));
+ $this->assertFalse(Validation::cc('12332105933743585', null, true, '/123321\\d{11}/'));
+ $this->assertFalse(Validation::cc('12332105933743587', null, true, '/123321\\d{11}/'));
+ $this->assertFalse(Validation::cc('12312305933743585', null, true, '/123321\\d{11}/'));
+ }
+
+/**
+ * testFastCc method
+ *
+ * @access public
+ * @return void
+ */
+ function testFastCc() {
+ // too short
+ $this->assertFalse(Validation::cc('123456789012'));
+ //American Express
+ $this->assertTrue(Validation::cc('370482756063980'));
+ //Diners Club 14
+ $this->assertTrue(Validation::cc('30155483651028'));
+ //2004 MasterCard/Diners Club Alliance International 14
+ $this->assertTrue(Validation::cc('36747701998969'));
+ //2004 MasterCard/Diners Club Alliance US & Canada 16
+ $this->assertTrue(Validation::cc('5597511346169950'));
+ //Discover
+ $this->assertTrue(Validation::cc('6011802876467237'));
+ //Mastercard
+ $this->assertTrue(Validation::cc('5580424361774366'));
+ //VISA 13 digit
+ $this->assertTrue(Validation::cc('4024007174754'));
+ //VISA 16 digit
+ $this->assertTrue(Validation::cc('4916375389940009'));
+ //Visa Electron
+ $this->assertTrue(Validation::cc('4175003346287100'));
+ }
+
+/**
+ * testAllCc method
+ *
+ * @access public
+ * @return void
+ */
+ function testAllCc() {
+ //American Express
+ $this->assertTrue(Validation::cc('370482756063980', 'all'));
+ //BankCard
+ $this->assertTrue(Validation::cc('5610745867413420', 'all'));
+ //Diners Club 14
+ $this->assertTrue(Validation::cc('30155483651028', 'all'));
+ //2004 MasterCard/Diners Club Alliance International 14
+ $this->assertTrue(Validation::cc('36747701998969', 'all'));
+ //2004 MasterCard/Diners Club Alliance US & Canada 16
+ $this->assertTrue(Validation::cc('5597511346169950', 'all'));
+ //Discover
+ $this->assertTrue(Validation::cc('6011802876467237', 'all'));
+ //enRoute
+ $this->assertTrue(Validation::cc('201496944158937', 'all'));
+ //JCB 15 digit
+ $this->assertTrue(Validation::cc('210034762247893', 'all'));
+ //JCB 16 digit
+ $this->assertTrue(Validation::cc('3096806857839939', 'all'));
+ //Maestro (debit card)
+ $this->assertTrue(Validation::cc('5020147409985219', 'all'));
+ //Mastercard
+ $this->assertTrue(Validation::cc('5580424361774366', 'all'));
+ //Solo 16
+ $this->assertTrue(Validation::cc('6767432107064987', 'all'));
+ //Solo 18
+ $this->assertTrue(Validation::cc('676714834398858593', 'all'));
+ //Solo 19
+ $this->assertTrue(Validation::cc('6767838565218340113', 'all'));
+ //Switch 16
+ $this->assertTrue(Validation::cc('5641829171515733', 'all'));
+ //Switch 18
+ $this->assertTrue(Validation::cc('493622764224625174', 'all'));
+ //Switch 19
+ $this->assertTrue(Validation::cc('6759603460617628716', 'all'));
+ //VISA 13 digit
+ $this->assertTrue(Validation::cc('4024007174754', 'all'));
+ //VISA 16 digit
+ $this->assertTrue(Validation::cc('4916375389940009', 'all'));
+ //Visa Electron
+ $this->assertTrue(Validation::cc('4175003346287100', 'all'));
+ //Voyager
+ $this->assertTrue(Validation::cc('869940697287073', 'all'));
+ }
+
+/**
+ * testAllCcDeep method
+ *
+ * @access public
+ * @return void
+ */
+ function testAllCcDeep() {
+ //American Express
+ $this->assertTrue(Validation::cc('370482756063980', 'all', true));
+ //BankCard
+ $this->assertTrue(Validation::cc('5610745867413420', 'all', true));
+ //Diners Club 14
+ $this->assertTrue(Validation::cc('30155483651028', 'all', true));
+ //2004 MasterCard/Diners Club Alliance International 14
+ $this->assertTrue(Validation::cc('36747701998969', 'all', true));
+ //2004 MasterCard/Diners Club Alliance US & Canada 16
+ $this->assertTrue(Validation::cc('5597511346169950', 'all', true));
+ //Discover
+ $this->assertTrue(Validation::cc('6011802876467237', 'all', true));
+ //enRoute
+ $this->assertTrue(Validation::cc('201496944158937', 'all', true));
+ //JCB 15 digit
+ $this->assertTrue(Validation::cc('210034762247893', 'all', true));
+ //JCB 16 digit
+ $this->assertTrue(Validation::cc('3096806857839939', 'all', true));
+ //Maestro (debit card)
+ $this->assertTrue(Validation::cc('5020147409985219', 'all', true));
+ //Mastercard
+ $this->assertTrue(Validation::cc('5580424361774366', 'all', true));
+ //Solo 16
+ $this->assertTrue(Validation::cc('6767432107064987', 'all', true));
+ //Solo 18
+ $this->assertTrue(Validation::cc('676714834398858593', 'all', true));
+ //Solo 19
+ $this->assertTrue(Validation::cc('6767838565218340113', 'all', true));
+ //Switch 16
+ $this->assertTrue(Validation::cc('5641829171515733', 'all', true));
+ //Switch 18
+ $this->assertTrue(Validation::cc('493622764224625174', 'all', true));
+ //Switch 19
+ $this->assertTrue(Validation::cc('6759603460617628716', 'all', true));
+ //VISA 13 digit
+ $this->assertTrue(Validation::cc('4024007174754', 'all', true));
+ //VISA 16 digit
+ $this->assertTrue(Validation::cc('4916375389940009', 'all', true));
+ //Visa Electron
+ $this->assertTrue(Validation::cc('4175003346287100', 'all', true));
+ //Voyager
+ $this->assertTrue(Validation::cc('869940697287073', 'all', true));
+ }
+
+/**
+ * testComparison method
+ *
+ * @access public
+ * @return void
+ */
+ function testComparison() {
+ $this->assertFalse(Validation::comparison(7, null, 6));
+ $this->assertTrue(Validation::comparison(7, 'is greater', 6));
+ $this->assertTrue(Validation::comparison(7, '>', 6));
+ $this->assertTrue(Validation::comparison(6, 'is less', 7));
+ $this->assertTrue(Validation::comparison(6, '<', 7));
+ $this->assertTrue(Validation::comparison(7, 'greater or equal', 7));
+ $this->assertTrue(Validation::comparison(7, '>=', 7));
+ $this->assertTrue(Validation::comparison(7, 'greater or equal', 6));
+ $this->assertTrue(Validation::comparison(7, '>=', 6));
+ $this->assertTrue(Validation::comparison(6, 'less or equal', 7));
+ $this->assertTrue(Validation::comparison(6, '<=', 7));
+ $this->assertTrue(Validation::comparison(7, 'equal to', 7));
+ $this->assertTrue(Validation::comparison(7, '==', 7));
+ $this->assertTrue(Validation::comparison(7, 'not equal', 6));
+ $this->assertTrue(Validation::comparison(7, '!=', 6));
+ $this->assertFalse(Validation::comparison(6, 'is greater', 7));
+ $this->assertFalse(Validation::comparison(6, '>', 7));
+ $this->assertFalse(Validation::comparison(7, 'is less', 6));
+ $this->assertFalse(Validation::comparison(7, '<', 6));
+ $this->assertFalse(Validation::comparison(6, 'greater or equal', 7));
+ $this->assertFalse(Validation::comparison(6, '>=', 7));
+ $this->assertFalse(Validation::comparison(6, 'greater or equal', 7));
+ $this->assertFalse(Validation::comparison(6, '>=', 7));
+ $this->assertFalse(Validation::comparison(7, 'less or equal', 6));
+ $this->assertFalse(Validation::comparison(7, '<=', 6));
+ $this->assertFalse(Validation::comparison(7, 'equal to', 6));
+ $this->assertFalse(Validation::comparison(7, '==', 6));
+ $this->assertFalse(Validation::comparison(7, 'not equal', 7));
+ $this->assertFalse(Validation::comparison(7, '!=', 7));
+ }
+
+/**
+ * testComparisonAsArray method
+ *
+ * @access public
+ * @return void
+ */
+ function testComparisonAsArray() {
+ $this->assertTrue(Validation::comparison(array('check1' => 7, 'operator' => 'is greater', 'check2' => 6)));
+ $this->assertTrue(Validation::comparison(array('check1' => 7, 'operator' => '>', 'check2' => 6)));
+ $this->assertTrue(Validation::comparison(array('check1' => 6, 'operator' => 'is less', 'check2' => 7)));
+ $this->assertTrue(Validation::comparison(array('check1' => 6, 'operator' => '<', 'check2' => 7)));
+ $this->assertTrue(Validation::comparison(array('check1' => 7, 'operator' => 'greater or equal', 'check2' => 7)));
+ $this->assertTrue(Validation::comparison(array('check1' => 7, 'operator' => '>=', 'check2' => 7)));
+ $this->assertTrue(Validation::comparison(array('check1' => 7, 'operator' => 'greater or equal','check2' => 6)));
+ $this->assertTrue(Validation::comparison(array('check1' => 7, 'operator' => '>=', 'check2' => 6)));
+ $this->assertTrue(Validation::comparison(array('check1' => 6, 'operator' => 'less or equal', 'check2' => 7)));
+ $this->assertTrue(Validation::comparison(array('check1' => 6, 'operator' => '<=', 'check2' => 7)));
+ $this->assertTrue(Validation::comparison(array('check1' => 7, 'operator' => 'equal to', 'check2' => 7)));
+ $this->assertTrue(Validation::comparison(array('check1' => 7, 'operator' => '==', 'check2' => 7)));
+ $this->assertTrue(Validation::comparison(array('check1' => 7, 'operator' => 'not equal', 'check2' => 6)));
+ $this->assertTrue(Validation::comparison(array('check1' => 7, 'operator' => '!=', 'check2' => 6)));
+ $this->assertFalse(Validation::comparison(array('check1' => 6, 'operator' => 'is greater', 'check2' => 7)));
+ $this->assertFalse(Validation::comparison(array('check1' => 6, 'operator' => '>', 'check2' => 7)));
+ $this->assertFalse(Validation::comparison(array('check1' => 7, 'operator' => 'is less', 'check2' => 6)));
+ $this->assertFalse(Validation::comparison(array('check1' => 7, 'operator' => '<', 'check2' => 6)));
+ $this->assertFalse(Validation::comparison(array('check1' => 6, 'operator' => 'greater or equal', 'check2' => 7)));
+ $this->assertFalse(Validation::comparison(array('check1' => 6, 'operator' => '>=', 'check2' => 7)));
+ $this->assertFalse(Validation::comparison(array('check1' => 6, 'operator' => 'greater or equal', 'check2' => 7)));
+ $this->assertFalse(Validation::comparison(array('check1' => 6, 'operator' => '>=', 'check2' => 7)));
+ $this->assertFalse(Validation::comparison(array('check1' => 7, 'operator' => 'less or equal', 'check2' => 6)));
+ $this->assertFalse(Validation::comparison(array('check1' => 7, 'operator' => '<=', 'check2' => 6)));
+ $this->assertFalse(Validation::comparison(array('check1' => 7, 'operator' => 'equal to', 'check2' => 6)));
+ $this->assertFalse(Validation::comparison(array('check1' => 7, 'operator' => '==','check2' => 6)));
+ $this->assertFalse(Validation::comparison(array('check1' => 7, 'operator' => 'not equal', 'check2' => 7)));
+ $this->assertFalse(Validation::comparison(array('check1' => 7, 'operator' => '!=', 'check2' => 7)));
+ }
+
+/**
+ * testCustom method
+ *
+ * @access public
+ * @return void
+ */
+ function testCustom() {
+ $this->assertTrue(Validation::custom('12345', '/(?assertFalse(Validation::custom('Text', '/(?assertFalse(Validation::custom('123.45', '/(?assertFalse(Validation::custom('missing regex'));
+ }
+
+/**
+ * testCustomAsArray method
+ *
+ * @access public
+ * @return void
+ */
+ function testCustomAsArray() {
+ $this->assertTrue(Validation::custom(array('check' => '12345', 'regex' => '/(?assertFalse(Validation::custom(array('check' => 'Text', 'regex' => '/(?assertFalse(Validation::custom(array('check' => '123.45', 'regex' => '/(?assertTrue(Validation::date('27-12-2006', array('dmy')));
+ $this->assertTrue(Validation::date('27.12.2006', array('dmy')));
+ $this->assertTrue(Validation::date('27/12/2006', array('dmy')));
+ $this->assertTrue(Validation::date('27 12 2006', array('dmy')));
+ $this->assertFalse(Validation::date('00-00-0000', array('dmy')));
+ $this->assertFalse(Validation::date('00.00.0000', array('dmy')));
+ $this->assertFalse(Validation::date('00/00/0000', array('dmy')));
+ $this->assertFalse(Validation::date('00 00 0000', array('dmy')));
+ $this->assertFalse(Validation::date('31-11-2006', array('dmy')));
+ $this->assertFalse(Validation::date('31.11.2006', array('dmy')));
+ $this->assertFalse(Validation::date('31/11/2006', array('dmy')));
+ $this->assertFalse(Validation::date('31 11 2006', array('dmy')));
+ }
+
+/**
+ * testDateDdmmyyyyLeapYear method
+ *
+ * @access public
+ * @return void
+ */
+ function testDateDdmmyyyyLeapYear() {
+ $this->assertTrue(Validation::date('29-02-2004', array('dmy')));
+ $this->assertTrue(Validation::date('29.02.2004', array('dmy')));
+ $this->assertTrue(Validation::date('29/02/2004', array('dmy')));
+ $this->assertTrue(Validation::date('29 02 2004', array('dmy')));
+ $this->assertFalse(Validation::date('29-02-2006', array('dmy')));
+ $this->assertFalse(Validation::date('29.02.2006', array('dmy')));
+ $this->assertFalse(Validation::date('29/02/2006', array('dmy')));
+ $this->assertFalse(Validation::date('29 02 2006', array('dmy')));
+ }
+
+/**
+ * testDateDdmmyy method
+ *
+ * @access public
+ * @return void
+ */
+ function testDateDdmmyy() {
+ $this->assertTrue(Validation::date('27-12-06', array('dmy')));
+ $this->assertTrue(Validation::date('27.12.06', array('dmy')));
+ $this->assertTrue(Validation::date('27/12/06', array('dmy')));
+ $this->assertTrue(Validation::date('27 12 06', array('dmy')));
+ $this->assertFalse(Validation::date('00-00-00', array('dmy')));
+ $this->assertFalse(Validation::date('00.00.00', array('dmy')));
+ $this->assertFalse(Validation::date('00/00/00', array('dmy')));
+ $this->assertFalse(Validation::date('00 00 00', array('dmy')));
+ $this->assertFalse(Validation::date('31-11-06', array('dmy')));
+ $this->assertFalse(Validation::date('31.11.06', array('dmy')));
+ $this->assertFalse(Validation::date('31/11/06', array('dmy')));
+ $this->assertFalse(Validation::date('31 11 06', array('dmy')));
+ }
+
+/**
+ * testDateDdmmyyLeapYear method
+ *
+ * @access public
+ * @return void
+ */
+ function testDateDdmmyyLeapYear() {
+ $this->assertTrue(Validation::date('29-02-04', array('dmy')));
+ $this->assertTrue(Validation::date('29.02.04', array('dmy')));
+ $this->assertTrue(Validation::date('29/02/04', array('dmy')));
+ $this->assertTrue(Validation::date('29 02 04', array('dmy')));
+ $this->assertFalse(Validation::date('29-02-06', array('dmy')));
+ $this->assertFalse(Validation::date('29.02.06', array('dmy')));
+ $this->assertFalse(Validation::date('29/02/06', array('dmy')));
+ $this->assertFalse(Validation::date('29 02 06', array('dmy')));
+ }
+
+/**
+ * testDateDmyy method
+ *
+ * @access public
+ * @return void
+ */
+ function testDateDmyy() {
+ $this->assertTrue(Validation::date('7-2-06', array('dmy')));
+ $this->assertTrue(Validation::date('7.2.06', array('dmy')));
+ $this->assertTrue(Validation::date('7/2/06', array('dmy')));
+ $this->assertTrue(Validation::date('7 2 06', array('dmy')));
+ $this->assertFalse(Validation::date('0-0-00', array('dmy')));
+ $this->assertFalse(Validation::date('0.0.00', array('dmy')));
+ $this->assertFalse(Validation::date('0/0/00', array('dmy')));
+ $this->assertFalse(Validation::date('0 0 00', array('dmy')));
+ $this->assertFalse(Validation::date('32-2-06', array('dmy')));
+ $this->assertFalse(Validation::date('32.2.06', array('dmy')));
+ $this->assertFalse(Validation::date('32/2/06', array('dmy')));
+ $this->assertFalse(Validation::date('32 2 06', array('dmy')));
+ }
+
+/**
+ * testDateDmyyLeapYear method
+ *
+ * @access public
+ * @return void
+ */
+ function testDateDmyyLeapYear() {
+ $this->assertTrue(Validation::date('29-2-04', array('dmy')));
+ $this->assertTrue(Validation::date('29.2.04', array('dmy')));
+ $this->assertTrue(Validation::date('29/2/04', array('dmy')));
+ $this->assertTrue(Validation::date('29 2 04', array('dmy')));
+ $this->assertFalse(Validation::date('29-2-06', array('dmy')));
+ $this->assertFalse(Validation::date('29.2.06', array('dmy')));
+ $this->assertFalse(Validation::date('29/2/06', array('dmy')));
+ $this->assertFalse(Validation::date('29 2 06', array('dmy')));
+ }
+
+/**
+ * testDateDmyyyy method
+ *
+ * @access public
+ * @return void
+ */
+ function testDateDmyyyy() {
+ $this->assertTrue(Validation::date('7-2-2006', array('dmy')));
+ $this->assertTrue(Validation::date('7.2.2006', array('dmy')));
+ $this->assertTrue(Validation::date('7/2/2006', array('dmy')));
+ $this->assertTrue(Validation::date('7 2 2006', array('dmy')));
+ $this->assertFalse(Validation::date('0-0-0000', array('dmy')));
+ $this->assertFalse(Validation::date('0.0.0000', array('dmy')));
+ $this->assertFalse(Validation::date('0/0/0000', array('dmy')));
+ $this->assertFalse(Validation::date('0 0 0000', array('dmy')));
+ $this->assertFalse(Validation::date('32-2-2006', array('dmy')));
+ $this->assertFalse(Validation::date('32.2.2006', array('dmy')));
+ $this->assertFalse(Validation::date('32/2/2006', array('dmy')));
+ $this->assertFalse(Validation::date('32 2 2006', array('dmy')));
+ }
+
+/**
+ * testDateDmyyyyLeapYear method
+ *
+ * @access public
+ * @return void
+ */
+ function testDateDmyyyyLeapYear() {
+ $this->assertTrue(Validation::date('29-2-2004', array('dmy')));
+ $this->assertTrue(Validation::date('29.2.2004', array('dmy')));
+ $this->assertTrue(Validation::date('29/2/2004', array('dmy')));
+ $this->assertTrue(Validation::date('29 2 2004', array('dmy')));
+ $this->assertFalse(Validation::date('29-2-2006', array('dmy')));
+ $this->assertFalse(Validation::date('29.2.2006', array('dmy')));
+ $this->assertFalse(Validation::date('29/2/2006', array('dmy')));
+ $this->assertFalse(Validation::date('29 2 2006', array('dmy')));
+ }
+
+/**
+ * testDateMmddyyyy method
+ *
+ * @access public
+ * @return void
+ */
+ function testDateMmddyyyy() {
+ $this->assertTrue(Validation::date('12-27-2006', array('mdy')));
+ $this->assertTrue(Validation::date('12.27.2006', array('mdy')));
+ $this->assertTrue(Validation::date('12/27/2006', array('mdy')));
+ $this->assertTrue(Validation::date('12 27 2006', array('mdy')));
+ $this->assertFalse(Validation::date('00-00-0000', array('mdy')));
+ $this->assertFalse(Validation::date('00.00.0000', array('mdy')));
+ $this->assertFalse(Validation::date('00/00/0000', array('mdy')));
+ $this->assertFalse(Validation::date('00 00 0000', array('mdy')));
+ $this->assertFalse(Validation::date('11-31-2006', array('mdy')));
+ $this->assertFalse(Validation::date('11.31.2006', array('mdy')));
+ $this->assertFalse(Validation::date('11/31/2006', array('mdy')));
+ $this->assertFalse(Validation::date('11 31 2006', array('mdy')));
+ }
+
+/**
+ * testDateMmddyyyyLeapYear method
+ *
+ * @access public
+ * @return void
+ */
+ function testDateMmddyyyyLeapYear() {
+ $this->assertTrue(Validation::date('02-29-2004', array('mdy')));
+ $this->assertTrue(Validation::date('02.29.2004', array('mdy')));
+ $this->assertTrue(Validation::date('02/29/2004', array('mdy')));
+ $this->assertTrue(Validation::date('02 29 2004', array('mdy')));
+ $this->assertFalse(Validation::date('02-29-2006', array('mdy')));
+ $this->assertFalse(Validation::date('02.29.2006', array('mdy')));
+ $this->assertFalse(Validation::date('02/29/2006', array('mdy')));
+ $this->assertFalse(Validation::date('02 29 2006', array('mdy')));
+ }
+
+/**
+ * testDateMmddyy method
+ *
+ * @access public
+ * @return void
+ */
+ function testDateMmddyy() {
+ $this->assertTrue(Validation::date('12-27-06', array('mdy')));
+ $this->assertTrue(Validation::date('12.27.06', array('mdy')));
+ $this->assertTrue(Validation::date('12/27/06', array('mdy')));
+ $this->assertTrue(Validation::date('12 27 06', array('mdy')));
+ $this->assertFalse(Validation::date('00-00-00', array('mdy')));
+ $this->assertFalse(Validation::date('00.00.00', array('mdy')));
+ $this->assertFalse(Validation::date('00/00/00', array('mdy')));
+ $this->assertFalse(Validation::date('00 00 00', array('mdy')));
+ $this->assertFalse(Validation::date('11-31-06', array('mdy')));
+ $this->assertFalse(Validation::date('11.31.06', array('mdy')));
+ $this->assertFalse(Validation::date('11/31/06', array('mdy')));
+ $this->assertFalse(Validation::date('11 31 06', array('mdy')));
+ }
+
+/**
+ * testDateMmddyyLeapYear method
+ *
+ * @access public
+ * @return void
+ */
+ function testDateMmddyyLeapYear() {
+ $this->assertTrue(Validation::date('02-29-04', array('mdy')));
+ $this->assertTrue(Validation::date('02.29.04', array('mdy')));
+ $this->assertTrue(Validation::date('02/29/04', array('mdy')));
+ $this->assertTrue(Validation::date('02 29 04', array('mdy')));
+ $this->assertFalse(Validation::date('02-29-06', array('mdy')));
+ $this->assertFalse(Validation::date('02.29.06', array('mdy')));
+ $this->assertFalse(Validation::date('02/29/06', array('mdy')));
+ $this->assertFalse(Validation::date('02 29 06', array('mdy')));
+ }
+
+/**
+ * testDateMdyy method
+ *
+ * @access public
+ * @return void
+ */
+ function testDateMdyy() {
+ $this->assertTrue(Validation::date('2-7-06', array('mdy')));
+ $this->assertTrue(Validation::date('2.7.06', array('mdy')));
+ $this->assertTrue(Validation::date('2/7/06', array('mdy')));
+ $this->assertTrue(Validation::date('2 7 06', array('mdy')));
+ $this->assertFalse(Validation::date('0-0-00', array('mdy')));
+ $this->assertFalse(Validation::date('0.0.00', array('mdy')));
+ $this->assertFalse(Validation::date('0/0/00', array('mdy')));
+ $this->assertFalse(Validation::date('0 0 00', array('mdy')));
+ $this->assertFalse(Validation::date('2-32-06', array('mdy')));
+ $this->assertFalse(Validation::date('2.32.06', array('mdy')));
+ $this->assertFalse(Validation::date('2/32/06', array('mdy')));
+ $this->assertFalse(Validation::date('2 32 06', array('mdy')));
+ }
+
+/**
+ * testDateMdyyLeapYear method
+ *
+ * @access public
+ * @return void
+ */
+ function testDateMdyyLeapYear() {
+ $this->assertTrue(Validation::date('2-29-04', array('mdy')));
+ $this->assertTrue(Validation::date('2.29.04', array('mdy')));
+ $this->assertTrue(Validation::date('2/29/04', array('mdy')));
+ $this->assertTrue(Validation::date('2 29 04', array('mdy')));
+ $this->assertFalse(Validation::date('2-29-06', array('mdy')));
+ $this->assertFalse(Validation::date('2.29.06', array('mdy')));
+ $this->assertFalse(Validation::date('2/29/06', array('mdy')));
+ $this->assertFalse(Validation::date('2 29 06', array('mdy')));
+ }
+
+/**
+ * testDateMdyyyy method
+ *
+ * @access public
+ * @return void
+ */
+ function testDateMdyyyy() {
+ $this->assertTrue(Validation::date('2-7-2006', array('mdy')));
+ $this->assertTrue(Validation::date('2.7.2006', array('mdy')));
+ $this->assertTrue(Validation::date('2/7/2006', array('mdy')));
+ $this->assertTrue(Validation::date('2 7 2006', array('mdy')));
+ $this->assertFalse(Validation::date('0-0-0000', array('mdy')));
+ $this->assertFalse(Validation::date('0.0.0000', array('mdy')));
+ $this->assertFalse(Validation::date('0/0/0000', array('mdy')));
+ $this->assertFalse(Validation::date('0 0 0000', array('mdy')));
+ $this->assertFalse(Validation::date('2-32-2006', array('mdy')));
+ $this->assertFalse(Validation::date('2.32.2006', array('mdy')));
+ $this->assertFalse(Validation::date('2/32/2006', array('mdy')));
+ $this->assertFalse(Validation::date('2 32 2006', array('mdy')));
+ }
+
+/**
+ * testDateMdyyyyLeapYear method
+ *
+ * @access public
+ * @return void
+ */
+ function testDateMdyyyyLeapYear() {
+ $this->assertTrue(Validation::date('2-29-2004', array('mdy')));
+ $this->assertTrue(Validation::date('2.29.2004', array('mdy')));
+ $this->assertTrue(Validation::date('2/29/2004', array('mdy')));
+ $this->assertTrue(Validation::date('2 29 2004', array('mdy')));
+ $this->assertFalse(Validation::date('2-29-2006', array('mdy')));
+ $this->assertFalse(Validation::date('2.29.2006', array('mdy')));
+ $this->assertFalse(Validation::date('2/29/2006', array('mdy')));
+ $this->assertFalse(Validation::date('2 29 2006', array('mdy')));
+ }
+
+/**
+ * testDateYyyymmdd method
+ *
+ * @access public
+ * @return void
+ */
+ function testDateYyyymmdd() {
+ $this->assertTrue(Validation::date('2006-12-27', array('ymd')));
+ $this->assertTrue(Validation::date('2006.12.27', array('ymd')));
+ $this->assertTrue(Validation::date('2006/12/27', array('ymd')));
+ $this->assertTrue(Validation::date('2006 12 27', array('ymd')));
+ $this->assertFalse(Validation::date('2006-11-31', array('ymd')));
+ $this->assertFalse(Validation::date('2006.11.31', array('ymd')));
+ $this->assertFalse(Validation::date('2006/11/31', array('ymd')));
+ $this->assertFalse(Validation::date('2006 11 31', array('ymd')));
+ }
+
+/**
+ * testDateYyyymmddLeapYear method
+ *
+ * @access public
+ * @return void
+ */
+ function testDateYyyymmddLeapYear() {
+ $this->assertTrue(Validation::date('2004-02-29', array('ymd')));
+ $this->assertTrue(Validation::date('2004.02.29', array('ymd')));
+ $this->assertTrue(Validation::date('2004/02/29', array('ymd')));
+ $this->assertTrue(Validation::date('2004 02 29', array('ymd')));
+ $this->assertFalse(Validation::date('2006-02-29', array('ymd')));
+ $this->assertFalse(Validation::date('2006.02.29', array('ymd')));
+ $this->assertFalse(Validation::date('2006/02/29', array('ymd')));
+ $this->assertFalse(Validation::date('2006 02 29', array('ymd')));
+ }
+
+/**
+ * testDateYymmdd method
+ *
+ * @access public
+ * @return void
+ */
+ function testDateYymmdd() {
+ $this->assertTrue(Validation::date('06-12-27', array('ymd')));
+ $this->assertTrue(Validation::date('06.12.27', array('ymd')));
+ $this->assertTrue(Validation::date('06/12/27', array('ymd')));
+ $this->assertTrue(Validation::date('06 12 27', array('ymd')));
+ $this->assertFalse(Validation::date('12/27/2600', array('ymd')));
+ $this->assertFalse(Validation::date('12.27.2600', array('ymd')));
+ $this->assertFalse(Validation::date('12/27/2600', array('ymd')));
+ $this->assertFalse(Validation::date('12 27 2600', array('ymd')));
+ $this->assertFalse(Validation::date('06-11-31', array('ymd')));
+ $this->assertFalse(Validation::date('06.11.31', array('ymd')));
+ $this->assertFalse(Validation::date('06/11/31', array('ymd')));
+ $this->assertFalse(Validation::date('06 11 31', array('ymd')));
+ }
+
+/**
+ * testDateYymmddLeapYear method
+ *
+ * @access public
+ * @return void
+ */
+ function testDateYymmddLeapYear() {
+ $this->assertTrue(Validation::date('2004-02-29', array('ymd')));
+ $this->assertTrue(Validation::date('2004.02.29', array('ymd')));
+ $this->assertTrue(Validation::date('2004/02/29', array('ymd')));
+ $this->assertTrue(Validation::date('2004 02 29', array('ymd')));
+ $this->assertFalse(Validation::date('2006-02-29', array('ymd')));
+ $this->assertFalse(Validation::date('2006.02.29', array('ymd')));
+ $this->assertFalse(Validation::date('2006/02/29', array('ymd')));
+ $this->assertFalse(Validation::date('2006 02 29', array('ymd')));
+ }
+
+/**
+ * testDateDdMMMMyyyy method
+ *
+ * @access public
+ * @return void
+ */
+ function testDateDdMMMMyyyy() {
+ $this->assertTrue(Validation::date('27 December 2006', array('dMy')));
+ $this->assertTrue(Validation::date('27 Dec 2006', array('dMy')));
+ $this->assertFalse(Validation::date('2006 Dec 27', array('dMy')));
+ $this->assertFalse(Validation::date('2006 December 27', array('dMy')));
+ }
+
+/**
+ * testDateDdMMMMyyyyLeapYear method
+ *
+ * @access public
+ * @return void
+ */
+ function testDateDdMMMMyyyyLeapYear() {
+ $this->assertTrue(Validation::date('29 February 2004', array('dMy')));
+ $this->assertFalse(Validation::date('29 February 2006', array('dMy')));
+ }
+
+/**
+ * testDateMmmmDdyyyy method
+ *
+ * @access public
+ * @return void
+ */
+ function testDateMmmmDdyyyy() {
+ $this->assertTrue(Validation::date('December 27, 2006', array('Mdy')));
+ $this->assertTrue(Validation::date('Dec 27, 2006', array('Mdy')));
+ $this->assertTrue(Validation::date('December 27 2006', array('Mdy')));
+ $this->assertTrue(Validation::date('Dec 27 2006', array('Mdy')));
+ $this->assertFalse(Validation::date('27 Dec 2006', array('Mdy')));
+ $this->assertFalse(Validation::date('2006 December 27', array('Mdy')));
+ }
+
+/**
+ * testDateMmmmDdyyyyLeapYear method
+ *
+ * @access public
+ * @return void
+ */
+ function testDateMmmmDdyyyyLeapYear() {
+ $this->assertTrue(Validation::date('February 29, 2004', array('Mdy')));
+ $this->assertTrue(Validation::date('Feb 29, 2004', array('Mdy')));
+ $this->assertTrue(Validation::date('February 29 2004', array('Mdy')));
+ $this->assertTrue(Validation::date('Feb 29 2004', array('Mdy')));
+ $this->assertFalse(Validation::date('February 29, 2006', array('Mdy')));
+ }
+
+/**
+ * testDateMy method
+ *
+ * @access public
+ * @return void
+ */
+ function testDateMy() {
+ $this->assertTrue(Validation::date('December 2006', array('My')));
+ $this->assertTrue(Validation::date('Dec 2006', array('My')));
+ $this->assertTrue(Validation::date('December/2006', array('My')));
+ $this->assertTrue(Validation::date('Dec/2006', array('My')));
+ }
+
+/**
+ * testDateMyNumeric method
+ *
+ * @access public
+ * @return void
+ */
+ function testDateMyNumeric() {
+ $this->assertTrue(Validation::date('12/2006', array('my')));
+ $this->assertTrue(Validation::date('12-2006', array('my')));
+ $this->assertTrue(Validation::date('12.2006', array('my')));
+ $this->assertTrue(Validation::date('12 2006', array('my')));
+ $this->assertFalse(Validation::date('12/06', array('my')));
+ $this->assertFalse(Validation::date('12-06', array('my')));
+ $this->assertFalse(Validation::date('12.06', array('my')));
+ $this->assertFalse(Validation::date('12 06', array('my')));
+ }
+
+/**
+ * testTime method
+ *
+ * @access public
+ * @return void
+ */
+ function testTime() {
+ $this->assertTrue(Validation::time('00:00'));
+ $this->assertTrue(Validation::time('23:59'));
+ $this->assertFalse(Validation::time('24:00'));
+ $this->assertTrue(Validation::time('12:00'));
+ $this->assertTrue(Validation::time('12:01'));
+ $this->assertTrue(Validation::time('12:01am'));
+ $this->assertTrue(Validation::time('12:01pm'));
+ $this->assertTrue(Validation::time('1pm'));
+ $this->assertTrue(Validation::time('01:00'));
+ $this->assertFalse(Validation::time('1:00'));
+ $this->assertTrue(Validation::time('1:00pm'));
+ $this->assertFalse(Validation::time('13:00pm'));
+ $this->assertFalse(Validation::time('9:00'));
+ }
+
+/**
+ * testBoolean method
+ *
+ * @access public
+ * @return void
+ */
+ function testBoolean() {
+ $this->assertTrue(Validation::boolean('0'));
+ $this->assertTrue(Validation::boolean('1'));
+ $this->assertTrue(Validation::boolean(0));
+ $this->assertTrue(Validation::boolean(1));
+ $this->assertTrue(Validation::boolean(true));
+ $this->assertTrue(Validation::boolean(false));
+ $this->assertFalse(Validation::boolean('true'));
+ $this->assertFalse(Validation::boolean('false'));
+ $this->assertFalse(Validation::boolean('-1'));
+ $this->assertFalse(Validation::boolean('2'));
+ $this->assertFalse(Validation::boolean('Boo!'));
+ }
+
+/**
+ * testDateCustomRegx method
+ *
+ * @access public
+ * @return void
+ */
+ function testDateCustomRegx() {
+ $this->assertTrue(Validation::date('2006-12-27', null, '%^(19|20)[0-9]{2}[- /.](0[1-9]|1[012])[- /.](0[1-9]|[12][0-9]|3[01])$%'));
+ $this->assertFalse(Validation::date('12-27-2006', null, '%^(19|20)[0-9]{2}[- /.](0[1-9]|1[012])[- /.](0[1-9]|[12][0-9]|3[01])$%'));
+ }
+
+/**
+ * testDecimal method
+ *
+ * @access public
+ * @return void
+ */
+ function testDecimal() {
+ $this->assertTrue(Validation::decimal('+1234.54321'));
+ $this->assertTrue(Validation::decimal('-1234.54321'));
+ $this->assertTrue(Validation::decimal('1234.54321'));
+ $this->assertTrue(Validation::decimal('+0123.45e6'));
+ $this->assertTrue(Validation::decimal('-0123.45e6'));
+ $this->assertTrue(Validation::decimal('0123.45e6'));
+ $this->assertFalse(Validation::decimal('string'));
+ $this->assertFalse(Validation::decimal('1234'));
+ $this->assertFalse(Validation::decimal('-1234'));
+ $this->assertFalse(Validation::decimal('+1234'));
+ }
+
+/**
+ * testDecimalWithPlaces method
+ *
+ * @access public
+ * @return void
+ */
+ function testDecimalWithPlaces() {
+ $this->assertTrue(Validation::decimal('.27', '2'));
+ $this->assertTrue(Validation::decimal(.27, 2));
+ $this->assertTrue(Validation::decimal(-.27, 2));
+ $this->assertTrue(Validation::decimal(+.27, 2));
+ $this->assertTrue(Validation::decimal('.277', '3'));
+ $this->assertTrue(Validation::decimal(.277, 3));
+ $this->assertTrue(Validation::decimal(-.277, 3));
+ $this->assertTrue(Validation::decimal(+.277, 3));
+ $this->assertTrue(Validation::decimal('1234.5678', '4'));
+ $this->assertTrue(Validation::decimal(1234.5678, 4));
+ $this->assertTrue(Validation::decimal(-1234.5678, 4));
+ $this->assertTrue(Validation::decimal(+1234.5678, 4));
+ $this->assertFalse(Validation::decimal('1234.5678', '3'));
+ $this->assertFalse(Validation::decimal(1234.5678, 3));
+ $this->assertFalse(Validation::decimal(-1234.5678, 3));
+ $this->assertFalse(Validation::decimal(+1234.5678, 3));
+ }
+
+/**
+ * testDecimalCustomRegex method
+ *
+ * @access public
+ * @return void
+ */
+ function testDecimalCustomRegex() {
+ $this->assertTrue(Validation::decimal('1.54321', null, '/^[-+]?[0-9]+(\\.[0-9]+)?$/s'));
+ $this->assertFalse(Validation::decimal('.54321', null, '/^[-+]?[0-9]+(\\.[0-9]+)?$/s'));
+ }
+
+/**
+ * testEmail method
+ *
+ * @access public
+ * @return void
+ */
+ function testEmail() {
+ $this->assertTrue(Validation::email('abc.efg@domain.com'));
+ $this->assertTrue(Validation::email('efg@domain.com'));
+ $this->assertTrue(Validation::email('abc-efg@domain.com'));
+ $this->assertTrue(Validation::email('abc_efg@domain.com'));
+ $this->assertTrue(Validation::email('raw@test.ra.ru'));
+ $this->assertTrue(Validation::email('abc-efg@domain-hyphened.com'));
+ $this->assertTrue(Validation::email("p.o'malley@domain.com"));
+ $this->assertTrue(Validation::email('abc+efg@domain.com'));
+ $this->assertTrue(Validation::email('abc&efg@domain.com'));
+ $this->assertTrue(Validation::email('abc.efg@12345.com'));
+ $this->assertTrue(Validation::email('abc.efg@12345.co.jp'));
+ $this->assertTrue(Validation::email('abc@g.cn'));
+ $this->assertTrue(Validation::email('abc@x.com'));
+ $this->assertTrue(Validation::email('henrik@sbcglobal.net'));
+ $this->assertTrue(Validation::email('sani@sbcglobal.net'));
+
+ // all ICANN TLDs
+ $this->assertTrue(Validation::email('abc@example.aero'));
+ $this->assertTrue(Validation::email('abc@example.asia'));
+ $this->assertTrue(Validation::email('abc@example.biz'));
+ $this->assertTrue(Validation::email('abc@example.cat'));
+ $this->assertTrue(Validation::email('abc@example.com'));
+ $this->assertTrue(Validation::email('abc@example.coop'));
+ $this->assertTrue(Validation::email('abc@example.edu'));
+ $this->assertTrue(Validation::email('abc@example.gov'));
+ $this->assertTrue(Validation::email('abc@example.info'));
+ $this->assertTrue(Validation::email('abc@example.int'));
+ $this->assertTrue(Validation::email('abc@example.jobs'));
+ $this->assertTrue(Validation::email('abc@example.mil'));
+ $this->assertTrue(Validation::email('abc@example.mobi'));
+ $this->assertTrue(Validation::email('abc@example.museum'));
+ $this->assertTrue(Validation::email('abc@example.name'));
+ $this->assertTrue(Validation::email('abc@example.net'));
+ $this->assertTrue(Validation::email('abc@example.org'));
+ $this->assertTrue(Validation::email('abc@example.pro'));
+ $this->assertTrue(Validation::email('abc@example.tel'));
+ $this->assertTrue(Validation::email('abc@example.travel'));
+ $this->assertTrue(Validation::email('someone@st.t-com.hr'));
+
+ // strange, but technically valid email addresses
+ $this->assertTrue(Validation::email('S=postmaster/OU=rz/P=uni-frankfurt/A=d400/C=de@gateway.d400.de'));
+ $this->assertTrue(Validation::email('customer/department=shipping@example.com'));
+ $this->assertTrue(Validation::email('$A12345@example.com'));
+ $this->assertTrue(Validation::email('!def!xyz%abc@example.com'));
+ $this->assertTrue(Validation::email('_somename@example.com'));
+
+ // invalid addresses
+ $this->assertFalse(Validation::email('abc@example'));
+ $this->assertFalse(Validation::email('abc@example.c'));
+ $this->assertFalse(Validation::email('abc@example.com.'));
+ $this->assertFalse(Validation::email('abc.@example.com'));
+ $this->assertFalse(Validation::email('abc@example..com'));
+ $this->assertFalse(Validation::email('abc@example.com.a'));
+ $this->assertFalse(Validation::email('abc@example.toolong'));
+ $this->assertFalse(Validation::email('abc;@example.com'));
+ $this->assertFalse(Validation::email('abc@example.com;'));
+ $this->assertFalse(Validation::email('abc@efg@example.com'));
+ $this->assertFalse(Validation::email('abc@@example.com'));
+ $this->assertFalse(Validation::email('abc efg@example.com'));
+ $this->assertFalse(Validation::email('abc,efg@example.com'));
+ $this->assertFalse(Validation::email('abc@sub,example.com'));
+ $this->assertFalse(Validation::email("abc@sub'example.com"));
+ $this->assertFalse(Validation::email('abc@sub/example.com'));
+ $this->assertFalse(Validation::email('abc@yahoo!.com'));
+ $this->assertFalse(Validation::email("Nyrée.surname@example.com"));
+ $this->assertFalse(Validation::email('abc@example_underscored.com'));
+ $this->assertFalse(Validation::email('raw@test.ra.ru....com'));
+ }
+
+/**
+ * testEmailDeep method
+ *
+ * @access public
+ * @return void
+ */
+ function testEmailDeep() {
+ $found = gethostbynamel('example.abcd');
+ if ($this->skipIf($found, 'Your DNS service responds for non-existant domains, skipping deep email checks. %s')) {
+ return;
+ }
+ $this->assertTrue(Validation::email('abc.efg@cakephp.org', true));
+ $this->assertFalse(Validation::email('abc.efg@caphpkeinvalid.com', true));
+ $this->assertFalse(Validation::email('abc@example.abcd', true));
+ }
+
+/**
+ * testEmailCustomRegex method
+ *
+ * @access public
+ * @return void
+ */
+ function testEmailCustomRegex() {
+ $this->assertTrue(Validation::email('abc.efg@cakephp.org', null, '/^[A-Z0-9._%-]+@[A-Z0-9.-]+\\.[A-Z]{2,4}$/i'));
+ $this->assertFalse(Validation::email('abc.efg@com.caphpkeinvalid', null, '/^[A-Z0-9._%-]+@[A-Z0-9.-]+\\.[A-Z]{2,4}$/i'));
+ }
+
+/**
+ * testEqualTo method
+ *
+ * @access public
+ * @return void
+ */
+ function testEqualTo() {
+ $this->assertTrue(Validation::equalTo("1", "1"));
+ $this->assertFalse(Validation::equalTo(1, "1"));
+ $this->assertFalse(Validation::equalTo("", null));
+ $this->assertFalse(Validation::equalTo("", false));
+ $this->assertFalse(Validation::equalTo(0, false));
+ $this->assertFalse(Validation::equalTo(null, false));
+ }
+
+/**
+ * testIp method
+ *
+ * @access public
+ * @return void
+ */
+ function testIpv4() {
+ $this->assertTrue(Validation::ip('0.0.0.0', 'IPv4'));
+ $this->assertTrue(Validation::ip('192.168.1.156', 'IPv4'));
+ $this->assertTrue(Validation::ip('255.255.255.255', 'IPv4'));
+
+ $this->assertFalse(Validation::ip('127.0.0', 'IPv4'));
+ $this->assertFalse(Validation::ip('127.0.0.a', 'IPv4'));
+ $this->assertFalse(Validation::ip('127.0.0.256', 'IPv4'));
+
+ $this->assertFalse(Validation::ip('2001:0db8:85a3:0000:0000:8a2e:0370:7334', 'IPv4'));
+ }
+
+/**
+ * testIp v6
+ *
+ * @access public
+ * @return void
+ */
+ function testIpv6() {
+ $this->assertTrue(Validation::ip('2001:0db8:85a3:0000:0000:8a2e:0370:7334', 'IPv6'));
+ $this->assertTrue(Validation::ip('2001:db8:85a3:0:0:8a2e:370:7334', 'IPv6'));
+ $this->assertTrue(Validation::ip('2001:db8:85a3::8a2e:370:7334', 'IPv6'));
+ $this->assertTrue(Validation::ip('2001:0db8:0000:0000:0000:0000:1428:57ab', 'IPv6'));
+ $this->assertTrue(Validation::ip('2001:0db8:0000:0000:0000::1428:57ab', 'IPv6'));
+ $this->assertTrue(Validation::ip('2001:0db8:0:0:0:0:1428:57ab', 'IPv6'));
+ $this->assertTrue(Validation::ip('2001:0db8:0:0::1428:57ab', 'IPv6'));
+ $this->assertTrue(Validation::ip('2001:0db8::1428:57ab', 'IPv6'));
+ $this->assertTrue(Validation::ip('2001:db8::1428:57ab', 'IPv6'));
+ $this->assertTrue(Validation::ip('0000:0000:0000:0000:0000:0000:0000:0001', 'IPv6'));
+ $this->assertTrue(Validation::ip('::1', 'IPv6'));
+ $this->assertTrue(Validation::ip('::ffff:12.34.56.78', 'IPv6'));
+ $this->assertTrue(Validation::ip('::ffff:0c22:384e', 'IPv6'));
+ $this->assertTrue(Validation::ip('2001:0db8:1234:0000:0000:0000:0000:0000', 'IPv6'));
+ $this->assertTrue(Validation::ip('2001:0db8:1234:ffff:ffff:ffff:ffff:ffff', 'IPv6'));
+ $this->assertTrue(Validation::ip('2001:db8:a::123', 'IPv6'));
+ $this->assertTrue(Validation::ip('fe80::', 'IPv6'));
+ $this->assertTrue(Validation::ip('::ffff:192.0.2.128', 'IPv6'));
+ $this->assertTrue(Validation::ip('::ffff:c000:280', 'IPv6'));
+
+ $this->assertFalse(Validation::ip('123', 'IPv6'));
+ $this->assertFalse(Validation::ip('ldkfj', 'IPv6'));
+ $this->assertFalse(Validation::ip('2001::FFD3::57ab', 'IPv6'));
+ $this->assertFalse(Validation::ip('2001:db8:85a3::8a2e:37023:7334', 'IPv6'));
+ $this->assertFalse(Validation::ip('2001:db8:85a3::8a2e:370k:7334', 'IPv6'));
+ $this->assertFalse(Validation::ip('1:2:3:4:5:6:7:8:9', 'IPv6'));
+ $this->assertFalse(Validation::ip('1::2::3', 'IPv6'));
+ $this->assertFalse(Validation::ip('1:::3:4:5', 'IPv6'));
+ $this->assertFalse(Validation::ip('1:2:3::4:5:6:7:8:9', 'IPv6'));
+ $this->assertFalse(Validation::ip('::ffff:2.3.4', 'IPv6'));
+ $this->assertFalse(Validation::ip('::ffff:257.1.2.3', 'IPv6'));
+
+ $this->assertFalse(Validation::ip('0.0.0.0', 'IPv6'));
+ }
+
+/**
+ * testIpBoth method
+ *
+ * @return void
+ * @access public
+ */
+ function testIpBoth() {
+ $this->assertTrue(Validation::ip('0.0.0.0'));
+ $this->assertTrue(Validation::ip('192.168.1.156'));
+ $this->assertTrue(Validation::ip('255.255.255.255'));
+
+ $this->assertFalse(Validation::ip('127.0.0'));
+ $this->assertFalse(Validation::ip('127.0.0.a'));
+ $this->assertFalse(Validation::ip('127.0.0.256'));
+
+ $this->assertTrue(Validation::ip('2001:0db8:85a3:0000:0000:8a2e:0370:7334'));
+ $this->assertTrue(Validation::ip('2001:db8:85a3:0:0:8a2e:370:7334'));
+ $this->assertTrue(Validation::ip('2001:db8:85a3::8a2e:370:7334'));
+
+ $this->assertFalse(Validation::ip('2001:db8:85a3::8a2e:37023:7334'));
+ $this->assertFalse(Validation::ip('2001:db8:85a3::8a2e:370k:7334'));
+ $this->assertFalse(Validation::ip('1:2:3:4:5:6:7:8:9'));
+ }
+
+/**
+ * testMaxLength method
+ *
+ * @access public
+ * @return void
+ */
+ function testMaxLength() {
+ $this->assertTrue(Validation::maxLength('ab', 3));
+ $this->assertTrue(Validation::maxLength('abc', 3));
+ $this->assertTrue(Validation::maxLength('ÆΔΩЖÇ', 10));
+
+ $this->assertFalse(Validation::maxLength('abcd', 3));
+ $this->assertFalse(Validation::maxLength('ÆΔΩЖÇ', 3));
+ }
+
+/**
+ * testMinLength method
+ *
+ * @access public
+ * @return void
+ */
+ function testMinLength() {
+ $this->assertFalse(Validation::minLength('ab', 3));
+ $this->assertFalse(Validation::minLength('ÆΔΩЖÇ', 10));
+
+ $this->assertTrue(Validation::minLength('abc', 3));
+ $this->assertTrue(Validation::minLength('abcd', 3));
+ $this->assertTrue(Validation::minLength('ÆΔΩЖÇ', 2));
+ }
+
+/**
+ * testUrl method
+ *
+ * @access public
+ * @return void
+ */
+ function testUrl() {
+ $this->assertTrue(Validation::url('http://www.cakephp.org'));
+ $this->assertTrue(Validation::url('http://cakephp.org'));
+ $this->assertTrue(Validation::url('http://www.cakephp.org/somewhere#anchor'));
+ $this->assertTrue(Validation::url('http://192.168.0.1'));
+ $this->assertTrue(Validation::url('https://www.cakephp.org'));
+ $this->assertTrue(Validation::url('https://cakephp.org'));
+ $this->assertTrue(Validation::url('https://www.cakephp.org/somewhere#anchor'));
+ $this->assertTrue(Validation::url('https://192.168.0.1'));
+ $this->assertTrue(Validation::url('ftps://www.cakephp.org/pub/cake'));
+ $this->assertTrue(Validation::url('ftps://cakephp.org/pub/cake'));
+ $this->assertTrue(Validation::url('ftps://192.168.0.1/pub/cake'));
+ $this->assertTrue(Validation::url('ftp://www.cakephp.org/pub/cake'));
+ $this->assertTrue(Validation::url('ftp://cakephp.org/pub/cake'));
+ $this->assertTrue(Validation::url('ftp://192.168.0.1/pub/cake'));
+ $this->assertFalse(Validation::url('ftps://256.168.0.1/pub/cake'));
+ $this->assertFalse(Validation::url('ftp://256.168.0.1/pub/cake'));
+ $this->assertTrue(Validation::url('https://my.domain.com/gizmo/app?class=MySip;proc=start'));
+ $this->assertTrue(Validation::url('www.domain.tld'));
+ $this->assertFalse(Validation::url('http://w_w.domain.co_m'));
+ $this->assertFalse(Validation::url('http://www.domain.12com'));
+ $this->assertFalse(Validation::url('http://www.domain.longttldnotallowed'));
+ $this->assertFalse(Validation::url('http://www.-invaliddomain.tld'));
+ $this->assertFalse(Validation::url('http://www.domain.-invalidtld'));
+ $this->assertTrue(Validation::url('http://123456789112345678921234567893123456789412345678951234567896123.com'));
+ $this->assertFalse(Validation::url('http://this-domain-is-too-loooooong-by-icann-rules-maximum-length-is-63.com'));
+ $this->assertTrue(Validation::url('http://www.domain.com/blogs/index.php?blog=6&tempskin=_rss2'));
+ $this->assertTrue(Validation::url('http://www.domain.com/blogs/parenth()eses.php'));
+ $this->assertTrue(Validation::url('http://www.domain.com/index.php?get=params&get2=params'));
+ $this->assertTrue(Validation::url('http://www.domain.com/ndex.php?get=params&get2=params#anchor'));
+ $this->assertFalse(Validation::url('http://www.domain.com/fakeenco%ode'));
+ $this->assertTrue(Validation::url('http://www.domain.com/real%20url%20encodeing'));
+ $this->assertTrue(Validation::url('http://en.wikipedia.org/wiki/Architectural_pattern_(computer_science)'));
+ $this->assertFalse(Validation::url('http://en.(wikipedia).org/'));
+ $this->assertFalse(Validation::url('www.cakephp.org', true));
+ $this->assertTrue(Validation::url('http://www.cakephp.org', true));
+ $this->assertTrue(Validation::url('http://example.com/~userdir/'));
+ $this->assertTrue(Validation::url('http://example.com/~userdir/subdir/index.html'));
+ $this->assertTrue(Validation::url('http://www.zwischenraume.de'));
+ $this->assertTrue(Validation::url('http://www.zwischenraume.cz'));
+ $this->assertTrue(Validation::url('http://www.last.fm/music/浜崎あゆみ'), 'utf8 path failed');
+ $this->assertTrue(Validation::url('http://www.electrohome.ro/images/239537750-284232-215_300[1].jpg'));
+
+ $this->assertTrue(Validation::url('http://cakephp.org:80'));
+ $this->assertTrue(Validation::url('http://cakephp.org:443'));
+ $this->assertTrue(Validation::url('http://cakephp.org:2000'));
+ $this->assertTrue(Validation::url('http://cakephp.org:27000'));
+ $this->assertTrue(Validation::url('http://cakephp.org:65000'));
+
+ $this->assertTrue(Validation::url('[2001:0db8::1428:57ab]'));
+ $this->assertTrue(Validation::url('[::1]'));
+ $this->assertTrue(Validation::url('[2001:0db8::1428:57ab]:80'));
+ $this->assertTrue(Validation::url('[::1]:80'));
+ $this->assertTrue(Validation::url('http://[2001:0db8::1428:57ab]'));
+ $this->assertTrue(Validation::url('http://[::1]'));
+ $this->assertTrue(Validation::url('http://[2001:0db8::1428:57ab]:80'));
+ $this->assertTrue(Validation::url('http://[::1]:80'));
+
+ $this->assertFalse(Validation::url('[1::2::3]'));
+ }
+
+ function testUuid() {
+ $this->assertTrue(Validation::uuid('550e8400-e29b-11d4-a716-446655440000'));
+ $this->assertFalse(Validation::uuid('BRAP-e29b-11d4-a716-446655440000'));
+ $this->assertTrue(Validation::uuid('550E8400-e29b-11D4-A716-446655440000'));
+ $this->assertFalse(Validation::uuid('550e8400-e29b11d4-a716-446655440000'));
+ $this->assertFalse(Validation::uuid('550e8400-e29b-11d4-a716-4466440000'));
+ $this->assertFalse(Validation::uuid('550e8400-e29b-11d4-a71-446655440000'));
+ $this->assertFalse(Validation::uuid('550e8400-e29b-11d-a716-446655440000'));
+ $this->assertFalse(Validation::uuid('550e8400-e29-11d4-a716-446655440000'));
+ }
+
+/**
+ * testInList method
+ *
+ * @access public
+ * @return void
+ */
+ function testInList() {
+ $this->assertTrue(Validation::inList('one', array('one', 'two')));
+ $this->assertTrue(Validation::inList('two', array('one', 'two')));
+ $this->assertFalse(Validation::inList('three', array('one', 'two')));
+ }
+
+/**
+ * testRange method
+ *
+ * @access public
+ * @return void
+ */
+ function testRange() {
+ $this->assertFalse(Validation::range(20, 100, 1));
+ $this->assertTrue(Validation::range(20, 1, 100));
+ $this->assertFalse(Validation::range(.5, 1, 100));
+ $this->assertTrue(Validation::range(.5, 0, 100));
+ $this->assertTrue(Validation::range(5));
+ $this->assertTrue(Validation::range(-5, -10, 1));
+ $this->assertFalse(Validation::range('word'));
+ }
+
+/**
+ * testExtension method
+ *
+ * @access public
+ * @return void
+ */
+ function testExtension() {
+ $this->assertTrue(Validation::extension('extension.jpeg'));
+ $this->assertTrue(Validation::extension('extension.JPEG'));
+ $this->assertTrue(Validation::extension('extension.gif'));
+ $this->assertTrue(Validation::extension('extension.GIF'));
+ $this->assertTrue(Validation::extension('extension.png'));
+ $this->assertTrue(Validation::extension('extension.jpg'));
+ $this->assertTrue(Validation::extension('extension.JPG'));
+ $this->assertFalse(Validation::extension('noextension'));
+ $this->assertTrue(Validation::extension('extension.pdf', array('PDF')));
+ $this->assertFalse(Validation::extension('extension.jpg', array('GIF')));
+ $this->assertTrue(Validation::extension(array('extension.JPG', 'extension.gif', 'extension.png')));
+ $this->assertTrue(Validation::extension(array('file' => array('name' => 'file.jpg'))));
+ $this->assertTrue(Validation::extension(array('file1' => array('name' => 'file.jpg'),
+ 'file2' => array('name' => 'file.jpg'),
+ 'file3' => array('name' => 'file.jpg'))));
+ $this->assertFalse(Validation::extension(array('file1' => array('name' => 'file.jpg'),
+ 'file2' => array('name' => 'file.jpg'),
+ 'file3' => array('name' => 'file.jpg')), array('gif')));
+
+ $this->assertFalse(Validation::extension(array('noextension', 'extension.JPG', 'extension.gif', 'extension.png')));
+ $this->assertFalse(Validation::extension(array('extension.pdf', 'extension.JPG', 'extension.gif', 'extension.png')));
+ }
+
+/**
+ * testMoney method
+ *
+ * @access public
+ * @return void
+ */
+ function testMoney() {
+ $this->assertTrue(Validation::money('$100'));
+ $this->assertTrue(Validation::money('$100.11'));
+ $this->assertTrue(Validation::money('$100.112'));
+ $this->assertFalse(Validation::money('$100.1'));
+ $this->assertFalse(Validation::money('$100.1111'));
+ $this->assertFalse(Validation::money('text'));
+
+ $this->assertTrue(Validation::money('100', 'right'));
+ $this->assertTrue(Validation::money('100.11$', 'right'));
+ $this->assertTrue(Validation::money('100.112$', 'right'));
+ $this->assertFalse(Validation::money('100.1$', 'right'));
+ $this->assertFalse(Validation::money('100.1111$', 'right'));
+
+ $this->assertTrue(Validation::money('€100'));
+ $this->assertTrue(Validation::money('€100.11'));
+ $this->assertTrue(Validation::money('€100.112'));
+ $this->assertFalse(Validation::money('€100.1'));
+ $this->assertFalse(Validation::money('€100.1111'));
+
+ $this->assertTrue(Validation::money('100', 'right'));
+ $this->assertTrue(Validation::money('100.11€', 'right'));
+ $this->assertTrue(Validation::money('100.112€', 'right'));
+ $this->assertFalse(Validation::money('100.1€', 'right'));
+ $this->assertFalse(Validation::money('100.1111€', 'right'));
+ }
+
+/**
+ * Test Multiple Select Validation
+ *
+ * @access public
+ * @return void
+ */
+ function testMultiple() {
+ $this->assertTrue(Validation::multiple(array(0, 1, 2, 3)));
+ $this->assertTrue(Validation::multiple(array(50, 32, 22, 0)));
+ $this->assertTrue(Validation::multiple(array('str', 'var', 'enum', 0)));
+ $this->assertFalse(Validation::multiple(''));
+ $this->assertFalse(Validation::multiple(null));
+ $this->assertFalse(Validation::multiple(array()));
+ $this->assertFalse(Validation::multiple(array(0)));
+ $this->assertFalse(Validation::multiple(array('0')));
+
+ $this->assertTrue(Validation::multiple(array(0, 3, 4, 5), array('in' => range(0, 10))));
+ $this->assertFalse(Validation::multiple(array(0, 15, 20, 5), array('in' => range(0, 10))));
+ $this->assertFalse(Validation::multiple(array(0, 5, 10, 11), array('in' => range(0, 10))));
+ $this->assertFalse(Validation::multiple(array('boo', 'foo', 'bar'), array('in' => array('foo', 'bar', 'baz'))));
+
+ $this->assertTrue(Validation::multiple(array(0, 5, 10, 11), array('max' => 3)));
+ $this->assertFalse(Validation::multiple(array(0, 5, 10, 11, 55), array('max' => 3)));
+ $this->assertTrue(Validation::multiple(array('foo', 'bar', 'baz'), array('max' => 3)));
+ $this->assertFalse(Validation::multiple(array('foo', 'bar', 'baz', 'squirrel'), array('max' => 3)));
+
+ $this->assertTrue(Validation::multiple(array(0, 5, 10, 11), array('min' => 3)));
+ $this->assertTrue(Validation::multiple(array(0, 5, 10, 11, 55), array('min' => 3)));
+ $this->assertFalse(Validation::multiple(array('foo', 'bar', 'baz'), array('min' => 5)));
+ $this->assertFalse(Validation::multiple(array('foo', 'bar', 'baz', 'squirrel'), array('min' => 10)));
+
+ $this->assertTrue(Validation::multiple(array(0, 5, 9), array('in' => range(0, 10), 'max' => 5)));
+ $this->assertFalse(Validation::multiple(array(0, 5, 9, 8, 6, 2, 1), array('in' => range(0, 10), 'max' => 5)));
+ $this->assertFalse(Validation::multiple(array(0, 5, 9, 8, 11), array('in' => range(0, 10), 'max' => 5)));
+
+ $this->assertFalse(Validation::multiple(array(0, 5, 9), array('in' => range(0, 10), 'max' => 5, 'min' => 3)));
+ $this->assertFalse(Validation::multiple(array(0, 5, 9, 8, 6, 2, 1), array('in' => range(0, 10), 'max' => 5, 'min' => 2)));
+ $this->assertFalse(Validation::multiple(array(0, 5, 9, 8, 11), array('in' => range(0, 10), 'max' => 5, 'min' => 2)));
+ }
+
+/**
+ * testNumeric method
+ *
+ * @access public
+ * @return void
+ */
+ function testNumeric() {
+ $this->assertFalse(Validation::numeric('teststring'));
+ $this->assertFalse(Validation::numeric('1.1test'));
+ $this->assertFalse(Validation::numeric('2test'));
+
+ $this->assertTrue(Validation::numeric('2'));
+ $this->assertTrue(Validation::numeric(2));
+ $this->assertTrue(Validation::numeric(2.2));
+ $this->assertTrue(Validation::numeric('2.2'));
+ }
+
+/**
+ * testPhone method
+ *
+ * @access public
+ * @return void
+ */
+ function testPhone() {
+ $this->assertFalse(Validation::phone('teststring'));
+ $this->assertFalse(Validation::phone('1-(33)-(333)-(4444)'));
+ $this->assertFalse(Validation::phone('1-(33)-3333-4444'));
+ $this->assertFalse(Validation::phone('1-(33)-33-4444'));
+ $this->assertFalse(Validation::phone('1-(33)-3-44444'));
+ $this->assertFalse(Validation::phone('1-(33)-3-444'));
+ $this->assertFalse(Validation::phone('1-(33)-3-44'));
+
+ $this->assertFalse(Validation::phone('(055) 999-9999'));
+ $this->assertFalse(Validation::phone('(155) 999-9999'));
+ $this->assertFalse(Validation::phone('(595) 999-9999'));
+ $this->assertFalse(Validation::phone('(555) 099-9999'));
+ $this->assertFalse(Validation::phone('(555) 199-9999'));
+
+ $this->assertTrue(Validation::phone('1 (222) 333 4444'));
+ $this->assertTrue(Validation::phone('+1 (222) 333 4444'));
+ $this->assertTrue(Validation::phone('(222) 333 4444'));
+
+ $this->assertTrue(Validation::phone('1-(333)-333-4444'));
+ $this->assertTrue(Validation::phone('1.(333)-333-4444'));
+ $this->assertTrue(Validation::phone('1.(333).333-4444'));
+ $this->assertTrue(Validation::phone('1.(333).333.4444'));
+ $this->assertTrue(Validation::phone('1-333-333-4444'));
+ }
+
+/**
+ * testPostal method
+ *
+ * @access public
+ * @return void
+ */
+ function testPostal() {
+ $this->assertFalse(Validation::postal('111', null, 'de'));
+ $this->assertFalse(Validation::postal('1111', null, 'de'));
+ $this->assertTrue(Validation::postal('13089', null, 'de'));
+
+ $this->assertFalse(Validation::postal('111', null, 'be'));
+ $this->assertFalse(Validation::postal('0123', null, 'be'));
+ $this->assertTrue(Validation::postal('1204', null, 'be'));
+
+ $this->assertFalse(Validation::postal('111', null, 'it'));
+ $this->assertFalse(Validation::postal('1111', null, 'it'));
+ $this->assertTrue(Validation::postal('13089', null, 'it'));
+
+ $this->assertFalse(Validation::postal('111', null, 'uk'));
+ $this->assertFalse(Validation::postal('1111', null, 'uk'));
+ $this->assertFalse(Validation::postal('AZA 0AB', null, 'uk'));
+ $this->assertFalse(Validation::postal('X0A 0ABC', null, 'uk'));
+ $this->assertTrue(Validation::postal('X0A 0AB', null, 'uk'));
+ $this->assertTrue(Validation::postal('AZ0A 0AA', null, 'uk'));
+ $this->assertTrue(Validation::postal('A89 2DD', null, 'uk'));
+
+ $this->assertFalse(Validation::postal('111', null, 'ca'));
+ $this->assertFalse(Validation::postal('1111', null, 'ca'));
+ $this->assertFalse(Validation::postal('D2A 0A0', null, 'ca'));
+ $this->assertFalse(Validation::postal('BAA 0ABC', null, 'ca'));
+ $this->assertFalse(Validation::postal('B2A AABC', null, 'ca'));
+ $this->assertFalse(Validation::postal('B2A 2AB', null, 'ca'));
+ $this->assertTrue(Validation::postal('X0A 0A2', null, 'ca'));
+ $this->assertTrue(Validation::postal('G4V 4C3', null, 'ca'));
+ $this->assertTrue(Validation::postal('L4J8D6', null, 'ca'));
+
+ $this->assertFalse(Validation::postal('111', null, 'us'));
+ $this->assertFalse(Validation::postal('1111', null, 'us'));
+ $this->assertFalse(Validation::postal('130896', null, 'us'));
+ $this->assertFalse(Validation::postal('13089-33333', null, 'us'));
+ $this->assertFalse(Validation::postal('13089-333', null, 'us'));
+ $this->assertFalse(Validation::postal('13A89-4333', null, 'us'));
+ $this->assertTrue(Validation::postal('13089-3333', null, 'us'));
+
+ $this->assertFalse(Validation::postal('111'));
+ $this->assertFalse(Validation::postal('1111'));
+ $this->assertFalse(Validation::postal('130896'));
+ $this->assertFalse(Validation::postal('13089-33333'));
+ $this->assertFalse(Validation::postal('13089-333'));
+ $this->assertFalse(Validation::postal('13A89-4333'));
+ $this->assertTrue(Validation::postal('13089-3333'));
+ }
+
+/**
+ * test that phone and postal pass to other classes.
+ *
+ * @return void
+ */
+ function testPhonePostalSsnPass() {
+ $this->assertTrue(Validation::postal('text', null, 'testNl'));
+ $this->assertTrue(Validation::phone('text', null, 'testDe'));
+ $this->assertTrue(Validation::ssn('text', null, 'testNl'));
+ }
+
+/**
+ * test the pass through calling of an alternate locale with postal()
+ *
+ * @return void
+ **/
+ function testPassThroughMethod() {
+ $this->assertTrue(Validation::postal('text', null, 'testNl'));
+
+ $this->expectError('Could not find AUTOFAILValidation class, unable to complete validation.');
+ Validation::postal('text', null, 'AUTOFAIL');
+
+ $this->expectError('Method phone does not exist on TestNlValidation unable to complete validation.');
+ Validation::phone('text', null, 'testNl');
+ }
+
+/**
+ * testSsn method
+ *
+ * @access public
+ * @return void
+ */
+ function testSsn() {
+ $this->assertFalse(Validation::ssn('111-333', null, 'dk'));
+ $this->assertFalse(Validation::ssn('111111-333', null, 'dk'));
+ $this->assertTrue(Validation::ssn('111111-3334', null, 'dk'));
+
+ $this->assertFalse(Validation::ssn('1118333', null, 'nl'));
+ $this->assertFalse(Validation::ssn('1234567890', null, 'nl'));
+ $this->assertFalse(Validation::ssn('12345A789', null, 'nl'));
+ $this->assertTrue(Validation::ssn('123456789', null, 'nl'));
+
+ $this->assertFalse(Validation::ssn('11-33-4333', null, 'us'));
+ $this->assertFalse(Validation::ssn('113-3-4333', null, 'us'));
+ $this->assertFalse(Validation::ssn('111-33-333', null, 'us'));
+ $this->assertTrue(Validation::ssn('111-33-4333', null, 'us'));
+ }
+
+/**
+ * testUserDefined method
+ *
+ * @access public
+ * @return void
+ */
+ function testUserDefined() {
+ $validator = new CustomValidator;
+ $this->assertFalse(Validation::userDefined('33', $validator, 'customValidate'));
+ $this->assertFalse(Validation::userDefined('3333', $validator, 'customValidate'));
+ $this->assertTrue(Validation::userDefined('333', $validator, 'customValidate'));
+ }
+
+}
diff --git a/code/ryzom/tools/server/www/webtt/cake/tests/cases/libs/view/helper.test.php b/code/ryzom/tools/server/www/webtt/cake/tests/cases/libs/view/helper.test.php
new file mode 100644
index 000000000..75d644d7d
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/cake/tests/cases/libs/view/helper.test.php
@@ -0,0 +1,804 @@
+
+ * Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
+ *
+ * Licensed under The Open Group Test Suite License
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
+ * @link http://book.cakephp.org/view/1196/Testing CakePHP(tm) Tests
+ * @package cake
+ * @subpackage cake.tests.cases.libs
+ * @since CakePHP(tm) v 1.2.0.4206
+ * @license http://www.opensource.org/licenses/opengroup.php The Open Group Test Suite License
+ */
+App::import('Core', array('View', 'Helper'));
+
+/**
+ * HelperTestPost class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.view
+ */
+class HelperTestPost extends Model {
+
+/**
+ * useTable property
+ *
+ * @var bool false
+ * @access public
+ */
+ var $useTable = false;
+
+/**
+ * schema method
+ *
+ * @access public
+ * @return void
+ */
+ function schema() {
+ $this->_schema = array(
+ 'id' => array('type' => 'integer', 'null' => false, 'default' => '', 'length' => '8'),
+ 'title' => array('type' => 'string', 'null' => false, 'default' => '', 'length' => '255'),
+ 'body' => array('type' => 'string', 'null' => true, 'default' => '', 'length' => ''),
+ 'number' => array('type' => 'integer', 'null' => false, 'default' => '', 'length' => '8'),
+ 'date' => array('type' => 'date', 'null' => true, 'default' => '', 'length' => ''),
+ 'created' => array('type' => 'date', 'null' => true, 'default' => '', 'length' => ''),
+ 'modified' => array('type' => 'datetime', 'null' => true, 'default' => '', 'length' => null)
+ );
+ return $this->_schema;
+ }
+
+/**
+ * hasAndBelongsToMany property
+ *
+ * @var array
+ * @access public
+ */
+ var $hasAndBelongsToMany = array('HelperTestTag'=> array('with' => 'HelperTestPostsTag'));
+}
+
+/**
+ * HelperTestComment class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.view
+ */
+class HelperTestComment extends Model {
+
+/**
+ * useTable property
+ *
+ * @var bool false
+ * @access public
+ */
+ var $useTable = false;
+
+/**
+ * schema method
+ *
+ * @access public
+ * @return void
+ */
+ function schema() {
+ $this->_schema = array(
+ 'id' => array('type' => 'integer', 'null' => false, 'default' => '', 'length' => '8'),
+ 'author_id' => array('type' => 'integer', 'null' => false, 'default' => '', 'length' => '8'),
+ 'title' => array('type' => 'string', 'null' => false, 'default' => '', 'length' => '255'),
+ 'body' => array('type' => 'string', 'null' => true, 'default' => '', 'length' => ''),
+ 'created' => array('type' => 'date', 'null' => true, 'default' => '', 'length' => ''),
+ 'modified' => array('type' => 'datetime', 'null' => true, 'default' => '', 'length' => null)
+ );
+ return $this->_schema;
+ }
+}
+
+/**
+ * HelperTestTag class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.view
+ */
+class HelperTestTag extends Model {
+
+/**
+ * useTable property
+ *
+ * @var bool false
+ * @access public
+ */
+ var $useTable = false;
+
+/**
+ * schema method
+ *
+ * @access public
+ * @return void
+ */
+ function schema() {
+ $this->_schema = array(
+ 'id' => array('type' => 'integer', 'null' => false, 'default' => '', 'length' => '8'),
+ 'name' => array('type' => 'string', 'null' => false, 'default' => '', 'length' => '255'),
+ 'created' => array('type' => 'date', 'null' => true, 'default' => '', 'length' => ''),
+ 'modified' => array('type' => 'datetime', 'null' => true, 'default' => '', 'length' => null)
+ );
+ return $this->_schema;
+ }
+}
+
+/**
+ * HelperTestPostsTag class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.view
+ */
+class HelperTestPostsTag extends Model {
+
+/**
+ * useTable property
+ *
+ * @var bool false
+ * @access public
+ */
+ var $useTable = false;
+
+/**
+ * schema method
+ *
+ * @access public
+ * @return void
+ */
+ function schema() {
+ $this->_schema = array(
+ 'helper_test_post_id' => array('type' => 'integer', 'null' => false, 'default' => '', 'length' => '8'),
+ 'helper_test_tag_id' => array('type' => 'integer', 'null' => false, 'default' => '', 'length' => '8'),
+ );
+ return $this->_schema;
+ }
+}
+
+class TestHelper extends Helper {
+/**
+ * expose a method as public
+ *
+ * @param string $options
+ * @param string $exclude
+ * @param string $insertBefore
+ * @param string $insertAfter
+ * @return void
+ */
+ function parseAttributes($options, $exclude = null, $insertBefore = ' ', $insertAfter = null) {
+ return $this->_parseAttributes($options, $exclude, $insertBefore, $insertAfter);
+ }
+}
+
+/**
+ * HelperTest class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs
+ */
+class HelperTest extends CakeTestCase {
+
+/**
+ * setUp method
+ *
+ * @access public
+ * @return void
+ */
+ function setUp() {
+ ClassRegistry::flush();
+ Router::reload();
+ $null = null;
+ $this->View = new View($null);
+ $this->Helper = new Helper();
+ ClassRegistry::addObject('HelperTestPost', new HelperTestPost());
+ ClassRegistry::addObject('HelperTestComment', new HelperTestComment());
+ ClassRegistry::addObject('HelperTestTag', new HelperTestTag());
+ }
+
+/**
+ * tearDown method
+ *
+ * @access public
+ * @return void
+ */
+ function tearDown() {
+ unset($this->Helper, $this->View);
+ ClassRegistry::flush();
+ }
+
+/**
+ * testFormFieldNameParsing method
+ *
+ * @access public
+ * @return void
+ */
+ function testSetEntity() {
+ // PHP4 reference hack
+ ClassRegistry::removeObject('view');
+ ClassRegistry::addObject('view', $this->View);
+
+ $this->Helper->setEntity('HelperTestPost.id');
+ $this->assertFalse($this->View->modelScope);
+ $this->assertEqual($this->View->model, 'HelperTestPost');
+ $this->assertEqual($this->View->field, 'id');
+ $this->assertEqual($this->View->modelId, null);
+ $this->assertEqual($this->View->association, null);
+
+ $this->Helper->setEntity('HelperTestComment.body');
+ $this->assertFalse($this->View->modelScope);
+ $this->assertEqual($this->View->model, 'HelperTestComment');
+ $this->assertEqual($this->View->field, 'body');
+ $this->assertEqual($this->View->modelId, null);
+ $this->assertEqual($this->View->association, null);
+ $this->assertEqual($this->View->fieldSuffix, null);
+
+ $this->Helper->setEntity('HelperTestPost', true);
+ $this->assertTrue($this->View->modelScope);
+ $this->assertEqual($this->View->model, 'HelperTestPost');
+ $this->assertEqual($this->View->field, null);
+ $this->assertEqual($this->View->modelId, null);
+ $this->assertEqual($this->View->association, null);
+ $this->assertEqual($this->View->fieldSuffix, null);
+
+ $this->Helper->setEntity('_Token.fields');
+ $this->assertTrue($this->View->modelScope);
+ $this->assertEqual($this->View->model, 'HelperTestPost');
+ $this->assertEqual($this->View->field, 'fields');
+ $this->assertEqual($this->View->modelId, null);
+ $this->assertEqual($this->View->association, '_Token');
+ $this->assertEqual($this->View->fieldSuffix, null);
+
+
+ $this->Helper->setEntity('id');
+ $this->assertTrue($this->View->modelScope);
+ $this->assertEqual($this->View->model, 'HelperTestPost');
+ $this->assertEqual($this->View->field, 'id');
+ $this->assertEqual($this->View->modelId, null);
+ $this->assertEqual($this->View->association, null);
+ $this->assertEqual($this->View->fieldSuffix, null);
+
+ $this->Helper->setEntity('HelperTestComment.body');
+ $this->assertTrue($this->View->modelScope);
+ $this->assertEqual($this->View->model, 'HelperTestPost');
+ $this->assertEqual($this->View->field, 'body');
+ $this->assertEqual($this->View->modelId, null);
+ $this->assertEqual($this->View->association, 'HelperTestComment');
+ $this->assertEqual($this->View->fieldSuffix, null);
+
+ $this->Helper->setEntity('body');
+ $this->assertTrue($this->View->modelScope);
+ $this->assertEqual($this->View->model, 'HelperTestPost');
+ $this->assertEqual($this->View->field, 'body');
+ $this->assertEqual($this->View->modelId, null);
+ $this->assertEqual($this->View->association, null);
+ $this->assertEqual($this->View->fieldSuffix, null);
+
+ $this->Helper->setEntity('Something.else');
+ $this->assertTrue($this->View->modelScope);
+ $this->assertEqual($this->View->model, 'HelperTestPost');
+ $this->assertEqual($this->View->field, 'else');
+ $this->assertEqual($this->View->modelId, false);
+ $this->assertEqual($this->View->association, 'Something');
+ $this->assertEqual($this->View->fieldSuffix, '');
+
+ $this->Helper->setEntity('5.id');
+ $this->assertTrue($this->View->modelScope);
+ $this->assertEqual($this->View->model, 'HelperTestPost');
+ $this->assertEqual($this->View->field, 'id');
+ $this->assertEqual($this->View->modelId, '5');
+ $this->assertEqual($this->View->association, null);
+ $this->assertEqual($this->View->fieldSuffix, null);
+
+ $this->assertEqual($this->View->entity(), array('HelperTestPost', 5, 'id'));
+
+ $this->Helper->setEntity('0.id');
+ $this->assertTrue($this->View->modelScope);
+ $this->assertEqual($this->View->model, 'HelperTestPost');
+ $this->assertEqual($this->View->field, 'id');
+ $this->assertEqual($this->View->modelId, '0');
+ $this->assertEqual($this->View->association, null);
+ $this->assertEqual($this->View->fieldSuffix, null);
+
+ $this->assertEqual($this->View->entity(), array('HelperTestPost', 0, 'id'));
+
+ $this->Helper->setEntity('5.created.month');
+ $this->assertTrue($this->View->modelScope);
+ $this->assertEqual($this->View->model, 'HelperTestPost');
+ $this->assertEqual($this->View->field, 'created');
+ $this->assertEqual($this->View->modelId, '5');
+ $this->assertEqual($this->View->association, null);
+ $this->assertEqual($this->View->fieldSuffix, 'month');
+
+ $this->Helper->setEntity('HelperTestComment.5.id');
+ $this->assertTrue($this->View->modelScope);
+ $this->assertEqual($this->View->model, 'HelperTestPost');
+ $this->assertEqual($this->View->field, 'id');
+ $this->assertEqual($this->View->modelId, '5');
+ $this->assertEqual($this->View->association, 'HelperTestComment');
+ $this->assertEqual($this->View->fieldSuffix, null);
+
+ $this->Helper->setEntity('HelperTestComment.id.time');
+ $this->assertTrue($this->View->modelScope);
+ $this->assertEqual($this->View->model, 'HelperTestPost');
+ $this->assertEqual($this->View->field, 'id');
+ $this->assertEqual($this->View->modelId, null);
+ $this->assertEqual($this->View->association, 'HelperTestComment');
+ $this->assertEqual($this->View->fieldSuffix, 'time');
+
+ $this->Helper->setEntity('HelperTestTag');
+ $this->assertTrue($this->View->modelScope);
+ $this->assertEqual($this->View->model, 'HelperTestPost');
+ $this->assertEqual($this->View->field, 'HelperTestTag');
+ $this->assertEqual($this->View->modelId, '');
+ $this->assertEqual($this->View->association, 'HelperTestTag');
+ $this->assertEqual($this->View->fieldSuffix, '');
+
+ $this->Helper->setEntity(null);
+ $this->Helper->setEntity('ModelThatDoesntExist.field_that_doesnt_exist');
+ $this->assertFalse($this->View->modelScope);
+ $this->assertEqual($this->View->model, 'ModelThatDoesntExist');
+ $this->assertEqual($this->View->field, 'field_that_doesnt_exist');
+ $this->assertEqual($this->View->modelId, null);
+ $this->assertEqual($this->View->association, null);
+ $this->assertEqual($this->View->fieldSuffix, null);
+ }
+
+/**
+ * test that 'view' doesn't break things.
+ *
+ * @return void
+ */
+ function testSetEntityWithView() {
+ $this->assertNull($this->Helper->setEntity('Allow.view.group_id'));
+ $this->assertNull($this->Helper->setEntity('Allow.view'));
+ $this->assertNull($this->Helper->setEntity('View.view'));
+ }
+
+/**
+ * test getting values from Helper
+ *
+ * @return void
+ */
+ function testValue() {
+ $this->Helper->data = array('fullname' => 'This is me');
+ $this->Helper->setEntity('fullname');
+ $result = $this->Helper->value('fullname');
+ $this->assertEqual($result, 'This is me');
+
+ $this->Helper->data = array('Post' => array('name' => 'First Post'));
+ $this->Helper->setEntity('Post.name');
+ $result = $this->Helper->value('Post.name');
+ $this->assertEqual($result, 'First Post');
+
+ $this->Helper->data = array('Post' => array(2 => array('name' => 'First Post')));
+ $this->Helper->setEntity('Post.2.name');
+ $result = $this->Helper->value('Post.2.name');
+ $this->assertEqual($result, 'First Post');
+
+ $this->Helper->data = array('Post' => array(2 => array('created' => array('year' => '2008'))));
+ $this->Helper->setEntity('Post.2.created');
+ $result = $this->Helper->value('Post.2.created');
+ $this->assertEqual($result, array('year' => '2008'));
+
+ $this->Helper->data = array('Post' => array(2 => array('created' => array('year' => '2008'))));
+ $this->Helper->setEntity('Post.2.created.year');
+ $result = $this->Helper->value('Post.2.created.year');
+ $this->assertEqual($result, '2008');
+
+ $this->Helper->data = array('HelperTestTag' => array('HelperTestTag' => ''));
+ $this->Helper->setEntity('HelperTestTag.HelperTestTag');
+ $result = $this->Helper->value('HelperTestTag.HelperTestTag');
+ $this->assertEqual($result, '');
+
+ $this->Helper->data = array('HelperTestTag' => array('HelperTestTag' => array(2, 3, 4)));
+ $this->Helper->setEntity('HelperTestTag.HelperTestTag');
+ $result = $this->Helper->value('HelperTestTag.HelperTestTag');
+ $this->assertEqual($result, array(2, 3, 4));
+
+ $this->Helper->data = array(
+ 'HelperTestTag' => array(
+ array('id' => 3),
+ array('id' => 5)
+ )
+ );
+ $this->Helper->setEntity('HelperTestTag.HelperTestTag');
+ $result = $this->Helper->value('HelperTestTag.HelperTestTag');
+ $this->assertEqual($result, array(3 => 3, 5 => 5));
+
+ $this->Helper->data = array('zero' => 0);
+ $this->Helper->setEntity('zero');
+ $result = $this->Helper->value(array('default' => 'something'), 'zero');
+ $this->assertEqual($result, array('value' => 0));
+
+ $this->Helper->data = array('zero' => '0');
+ $result = $this->Helper->value(array('default' => 'something'), 'zero');
+ $this->assertEqual($result, array('value' => '0'));
+
+ $this->Helper->setEntity('inexistent');
+ $result = $this->Helper->value(array('default' => 'something'), 'inexistent');
+ $this->assertEqual($result, array('value' => 'something'));
+ }
+
+/**
+ * Ensure HTML escaping of url params. So link addresses are valid and not exploited
+ *
+ * @return void
+ */
+ function testUrlConversion() {
+ $result = $this->Helper->url('/controller/action/1');
+ $this->assertEqual($result, '/controller/action/1');
+
+ $result = $this->Helper->url('/controller/action/1?one=1&two=2');
+ $this->assertEqual($result, '/controller/action/1?one=1&two=2');
+
+ $result = $this->Helper->url(array('controller' => 'posts', 'action' => 'index', 'page' => '1" onclick="alert(\'XSS\');"'));
+ $this->assertEqual($result, "/posts/index/page:1" onclick="alert('XSS');"");
+
+ $result = $this->Helper->url('/controller/action/1/param:this+one+more');
+ $this->assertEqual($result, '/controller/action/1/param:this+one+more');
+
+ $result = $this->Helper->url('/controller/action/1/param:this%20one%20more');
+ $this->assertEqual($result, '/controller/action/1/param:this%20one%20more');
+
+ $result = $this->Helper->url('/controller/action/1/param:%7Baround%20here%7D%5Bthings%5D%5Bare%5D%24%24');
+ $this->assertEqual($result, '/controller/action/1/param:%7Baround%20here%7D%5Bthings%5D%5Bare%5D%24%24');
+
+ $result = $this->Helper->url(array(
+ 'controller' => 'posts', 'action' => 'index', 'param' => '%7Baround%20here%7D%5Bthings%5D%5Bare%5D%24%24'
+ ));
+ $this->assertEqual($result, "/posts/index/param:%7Baround%20here%7D%5Bthings%5D%5Bare%5D%24%24");
+
+ $result = $this->Helper->url(array(
+ 'controller' => 'posts', 'action' => 'index', 'page' => '1',
+ '?' => array('one' => 'value', 'two' => 'value', 'three' => 'purple')
+ ));
+ $this->assertEqual($result, "/posts/index/page:1?one=value&two=value&three=purple");
+ }
+
+/**
+ * test assetTimestamp application
+ *
+ * @return void
+ */
+ function testAssetTimestamp() {
+ $_timestamp = Configure::read('Asset.timestamp');
+ $_debug = Configure::read('debug');
+
+ Configure::write('Asset.timestamp', false);
+ $result = $this->Helper->assetTimestamp(CSS_URL . 'cake.generic.css');
+ $this->assertEqual($result, CSS_URL . 'cake.generic.css');
+
+ Configure::write('Asset.timestamp', true);
+ Configure::write('debug', 0);
+ $result = $this->Helper->assetTimestamp(CSS_URL . 'cake.generic.css');
+ $this->assertEqual($result, CSS_URL . 'cake.generic.css');
+
+ Configure::write('Asset.timestamp', true);
+ Configure::write('debug', 2);
+ $result = $this->Helper->assetTimestamp(CSS_URL . 'cake.generic.css');
+ $this->assertPattern('/' . preg_quote(CSS_URL . 'cake.generic.css?', '/') . '[0-9]+/', $result);
+
+ Configure::write('Asset.timestamp', 'force');
+ Configure::write('debug', 0);
+ $result = $this->Helper->assetTimestamp(CSS_URL . 'cake.generic.css');
+ $this->assertPattern('/' . preg_quote(CSS_URL . 'cake.generic.css?', '/') . '[0-9]+/', $result);
+
+ $result = $this->Helper->assetTimestamp(CSS_URL . 'cake.generic.css?someparam');
+ $this->assertEqual($result, CSS_URL . 'cake.generic.css?someparam');
+
+ $this->Helper->webroot = '/some/dir/';
+ $result = $this->Helper->assetTimestamp('/some/dir/' . CSS_URL . 'cake.generic.css');
+ $this->assertPattern('/' . preg_quote(CSS_URL . 'cake.generic.css?', '/') . '[0-9]+/', $result);
+
+ Configure::write('debug', $_debug);
+ Configure::write('Asset.timestamp', $_timestamp);
+ }
+
+/**
+ * test assetTimestamp with plugins and themes
+ *
+ * @return void
+ */
+ function testAssetTimestampPluginsAndThemes() {
+ $_timestamp = Configure::read('Asset.timestamp');
+ Configure::write('Asset.timestamp', 'force');
+ App::build(array(
+ 'plugins' => array(TEST_CAKE_CORE_INCLUDE_PATH . 'tests' . DS . 'test_app' . DS . 'plugins' . DS),
+ 'views' => array(TEST_CAKE_CORE_INCLUDE_PATH . 'tests' . DS . 'test_app' . DS . 'views' . DS),
+ ));
+
+ $result = $this->Helper->assetTimestamp('/test_plugin/css/test_plugin_asset.css');
+ $this->assertPattern('#/test_plugin/css/test_plugin_asset.css\?[0-9]+$#', $result, 'Missing timestamp plugin');
+
+ $result = $this->Helper->assetTimestamp('/test_plugin/css/i_dont_exist.css');
+ $this->assertPattern('#/test_plugin/css/i_dont_exist.css\?$#', $result, 'No error on missing file');
+
+ $result = $this->Helper->assetTimestamp('/theme/test_theme/js/theme.js');
+ $this->assertPattern('#/theme/test_theme/js/theme.js\?[0-9]+$#', $result, 'Missing timestamp theme');
+
+ $result = $this->Helper->assetTimestamp('/theme/test_theme/js/non_existant.js');
+ $this->assertPattern('#/theme/test_theme/js/non_existant.js\?$#', $result, 'No error on missing file');
+
+ App::build();
+ Configure::write('Asset.timestamp', $_timestamp);
+ }
+
+/**
+ * testFieldsWithSameName method
+ *
+ * @access public
+ * @return void
+ */
+ function testFieldsWithSameName() {
+ // PHP4 reference hack
+ ClassRegistry::removeObject('view');
+ ClassRegistry::addObject('view', $this->View);
+
+ $this->Helper->setEntity('HelperTestTag', true);
+
+ $this->Helper->setEntity('HelperTestTag.id');
+ $this->assertEqual($this->View->model, 'HelperTestTag');
+ $this->assertEqual($this->View->field, 'id');
+ $this->assertEqual($this->View->modelId, null);
+ $this->assertEqual($this->View->association, null);
+ $this->assertEqual($this->View->fieldSuffix, null);
+
+ $this->Helper->setEntity('My.id');
+ $this->assertEqual($this->View->model, 'HelperTestTag');
+ $this->assertEqual($this->View->field, 'id');
+ $this->assertEqual($this->View->modelId, null);
+ $this->assertEqual($this->View->association, 'My');
+ $this->assertEqual($this->View->fieldSuffix, null);
+
+ $this->Helper->setEntity('MyOther.id');
+ $this->assertEqual($this->View->model, 'HelperTestTag');
+ $this->assertEqual($this->View->field, 'id');
+ $this->assertEqual($this->View->modelId, null);
+ $this->assertEqual($this->View->association, 'MyOther');
+ $this->assertEqual($this->View->fieldSuffix, null);
+
+ }
+
+/**
+ * testFieldSameAsModel method
+ *
+ * @access public
+ * @return void
+ */
+ function testFieldSameAsModel() {
+ // PHP4 reference hack
+ ClassRegistry::removeObject('view');
+ ClassRegistry::addObject('view', $this->View);
+
+ $this->Helper->setEntity('HelperTestTag', true);
+
+ $this->Helper->setEntity('helper_test_post');
+ $this->assertEqual($this->View->model, 'HelperTestTag');
+ $this->assertEqual($this->View->field, 'helper_test_post');
+ $this->assertEqual($this->View->modelId, null);
+ $this->assertEqual($this->View->association, null);
+ $this->assertEqual($this->View->fieldSuffix, null);
+
+ $this->Helper->setEntity('HelperTestTag');
+ $this->assertEqual($this->View->model, 'HelperTestTag');
+ $this->assertEqual($this->View->field, 'HelperTestTag');
+ $this->assertEqual($this->View->modelId, null);
+ $this->assertEqual($this->View->association, null);
+ $this->assertEqual($this->View->fieldSuffix, null);
+ $this->assertEqual($this->View->entityPath, 'HelperTestTag');
+ }
+
+/**
+ * testFieldSuffixForDate method
+ *
+ * @access public
+ * @return void
+ */
+ function testFieldSuffixForDate() {
+ // PHP4 reference hack
+ ClassRegistry::removeObject('view');
+ ClassRegistry::addObject('view', $this->View);
+
+ $this->Helper->setEntity('HelperTestPost', true);
+ $this->assertEqual($this->View->model, 'HelperTestPost');
+ $this->assertEqual($this->View->field, null);
+ $this->assertEqual($this->View->modelId, null);
+ $this->assertEqual($this->View->association, null);
+ $this->assertEqual($this->View->fieldSuffix, null);
+
+ $this->Helper->setEntity('date.month');
+ $this->assertEqual($this->View->model, 'HelperTestPost');
+ $this->assertEqual($this->View->field, 'date');
+ $this->assertEqual($this->View->modelId, null);
+ $this->assertEqual($this->View->association, null);
+ $this->assertEqual($this->View->fieldSuffix, 'month');
+ }
+
+/**
+ * testMulitDimensionValue method
+ *
+ * @access public
+ * @return void
+ */
+ function testMulitDimensionValue() {
+ $this->Helper->data = array();
+ for ($i = 0; $i < 2; $i++) {
+ $this->Helper->data['Model'][$i] = 'what';
+ $result[] = $this->Helper->value("Model.{$i}");
+ $this->Helper->data['Model'][$i] = array();
+ for ($j = 0; $j < 2; $j++) {
+ $this->Helper->data['Model'][$i][$j] = 'how';
+ $result[] = $this->Helper->value("Model.{$i}.{$j}");
+ }
+ }
+ $expected = array('what', 'how', 'how', 'what', 'how', 'how');
+ $this->assertEqual($result, $expected);
+
+ $this->Helper->data['HelperTestComment']['5']['id'] = 'ok';
+ $result = $this->Helper->value('HelperTestComment.5.id');
+ $this->assertEqual($result, 'ok');
+
+ $this->Helper->setEntity('HelperTestPost', true);
+ $this->Helper->data['HelperTestPost']['5']['created']['month'] = '10';
+ $result = $this->Helper->value('5.created.month');
+ $this->assertEqual($result, 10);
+
+ $this->Helper->data['HelperTestPost']['0']['id'] = 100;
+ $result = $this->Helper->value('0.id');
+ $this->assertEqual($result, 100);
+ }
+
+/**
+ * testClean method
+ *
+ * @access public
+ * @return void
+ */
+ function testClean() {
+ $result = $this->Helper->clean(array());
+ $this->assertEqual($result, null);
+
+ $result = $this->Helper->clean(array('', 'something else '));
+ $this->assertEqual($result, array('with something', 'something else'));
+
+ $result = $this->Helper->clean('');
+ $this->assertEqual($result, 'with something');
+
+ $result = $this->Helper->clean('');
+ $this->assertNoPattern('#*script#', $result);
+
+ $result = $this->Helper->clean("");
+ $this->assertNoPattern('#*script#', $result);
+
+ $result = $this->Helper->clean('');
+ $this->assertEqual($result, ' ');
+
+ $result = $this->Helper->clean('<script>alert(document.cookie)</script>');
+ $this->assertEqual($result, '<script>alert(document.cookie)</script>');
+ }
+
+/**
+ * testMultiDimensionalField method
+ *
+ * @access public
+ * @return void
+ */
+ function testMultiDimensionalField() {
+ // PHP4 reference hack
+ ClassRegistry::removeObject('view');
+ ClassRegistry::addObject('view', $this->View);
+
+ $this->Helper->setEntity('HelperTestPost', true);
+
+ $this->Helper->setEntity('HelperTestPost.2.HelperTestComment.1.title');
+ $this->assertEqual($this->View->model, 'HelperTestPost');
+ $this->assertEqual($this->View->association, 'HelperTestComment');
+ $this->assertEqual($this->View->modelId,2);
+ $this->assertEqual($this->View->field, 'title');
+
+ $this->Helper->setEntity('HelperTestPost.1.HelperTestComment.1.HelperTestTag.1.created');
+ $this->assertEqual($this->View->field,'created');
+ $this->assertEqual($this->View->association,'HelperTestTag');
+ $this->assertEqual($this->View->modelId,1);
+
+ $this->Helper->setEntity('HelperTestPost.0.HelperTestComment.1.HelperTestTag.1.fake');
+ $this->assertEqual($this->View->model,'HelperTestPost');
+ $this->assertEqual($this->View->association,'HelperTestTag');
+ $this->assertEqual($this->View->field,null);
+
+ $this->Helper->setEntity('1.HelperTestComment.1.HelperTestTag.created.year');
+ $this->assertEqual($this->View->model,'HelperTestPost');
+ $this->assertEqual($this->View->association,'HelperTestTag');
+ $this->assertEqual($this->View->field,'created');
+ $this->assertEqual($this->View->modelId,1);
+ $this->assertEqual($this->View->fieldSuffix,'year');
+
+ $this->Helper->data['HelperTestPost'][2]['HelperTestComment'][1]['title'] = 'My Title';
+ $result = $this->Helper->value('HelperTestPost.2.HelperTestComment.1.title');
+ $this->assertEqual($result,'My Title');
+
+ $this->Helper->data['HelperTestPost'][2]['HelperTestComment'][1]['created']['year'] = 2008;
+ $result = $this->Helper->value('HelperTestPost.2.HelperTestComment.1.created.year');
+ $this->assertEqual($result,2008);
+
+ $this->Helper->data[2]['HelperTestComment'][1]['created']['year'] = 2008;
+ $result = $this->Helper->value('HelperTestPost.2.HelperTestComment.1.created.year');
+ $this->assertEqual($result,2008);
+
+ $this->Helper->data['HelperTestPost']['title'] = 'My Title';
+ $result = $this->Helper->value('title');
+ $this->assertEqual($result,'My Title');
+
+ $this->Helper->data['My']['title'] = 'My Title';
+ $result = $this->Helper->value('My.title');
+ $this->assertEqual($result,'My Title');
+ }
+
+ function testWebrootPaths() {
+ $this->Helper->webroot = '/';
+ $result = $this->Helper->webroot('/img/cake.power.gif');
+ $expected = '/img/cake.power.gif';
+ $this->assertEqual($result, $expected);
+
+ $this->Helper->theme = 'test_theme';
+
+ App::build(array(
+ 'views' => array(TEST_CAKE_CORE_INCLUDE_PATH . 'tests' . DS . 'test_app' . DS . 'views'. DS)
+ ));
+
+ $result = $this->Helper->webroot('/img/cake.power.gif');
+ $expected = '/theme/test_theme/img/cake.power.gif';
+ $this->assertEqual($result, $expected);
+
+ $result = $this->Helper->webroot('/img/test.jpg');
+ $expected = '/theme/test_theme/img/test.jpg';
+ $this->assertEqual($result, $expected);
+
+ $webRoot = Configure::read('App.www_root');
+ Configure::write('App.www_root', TEST_CAKE_CORE_INCLUDE_PATH . 'tests' . DS . 'test_app' . DS . 'webroot' . DS);
+
+ $result = $this->Helper->webroot('/img/cake.power.gif');
+ $expected = '/theme/test_theme/img/cake.power.gif';
+ $this->assertEqual($result, $expected);
+
+ $result = $this->Helper->webroot('/img/test.jpg');
+ $expected = '/theme/test_theme/img/test.jpg';
+ $this->assertEqual($result, $expected);
+
+ $result = $this->Helper->webroot('/img/cake.icon.gif');
+ $expected = '/img/cake.icon.gif';
+ $this->assertEqual($result, $expected);
+
+ $result = $this->Helper->webroot('/img/cake.icon.gif?some=param');
+ $expected = '/img/cake.icon.gif?some=param';
+ $this->assertEqual($result, $expected);
+
+ Configure::write('App.www_root', $webRoot);
+ }
+
+/**
+ * test parsing attributes.
+ *
+ * @return void
+ */
+ function testParseAttributeCompact() {
+ $helper =& new TestHelper();
+ $compact = array('compact', 'checked', 'declare', 'readonly', 'disabled',
+ 'selected', 'defer', 'ismap', 'nohref', 'noshade', 'nowrap', 'multiple', 'noresize');
+
+ foreach ($compact as $attribute) {
+ foreach (array('true', true, 1, '1', $attribute) as $value) {
+ $attrs = array($attribute => $value);
+ $expected = ' ' . $attribute . '="' . $attribute . '"';
+ $this->assertEqual($helper->parseAttributes($attrs), $expected, '%s Failed on ' . $value);
+ }
+ }
+ }
+}
diff --git a/code/ryzom/tools/server/www/webtt/cake/tests/cases/libs/view/helpers/ajax.test.php b/code/ryzom/tools/server/www/webtt/cake/tests/cases/libs/view/helpers/ajax.test.php
new file mode 100644
index 000000000..d06bf4a71
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/cake/tests/cases/libs/view/helpers/ajax.test.php
@@ -0,0 +1,910 @@
+
+ * Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
+ *
+ * Licensed under The Open Group Test Suite License
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
+ * @link http://book.cakephp.org/view/1196/Testing CakePHP(tm) Tests
+ * @package cake
+ * @subpackage cake.tests.cases.libs.view.helpers
+ * @since CakePHP(tm) v 1.2.0.4206
+ * @license http://www.opensource.org/licenses/opengroup.php The Open Group Test Suite License
+ */
+if (!defined('CAKEPHP_UNIT_TEST_EXECUTION')) {
+ define('CAKEPHP_UNIT_TEST_EXECUTION', 1);
+}
+App::import('Helper', array('Html', 'Form', 'Javascript', 'Ajax'));
+/**
+ * AjaxTestController class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.view.helpers
+ */
+class AjaxTestController extends Controller {
+/**
+ * name property
+ *
+ * @var string 'AjaxTest'
+ * @access public
+ */
+ var $name = 'AjaxTest';
+/**
+ * uses property
+ *
+ * @var mixed null
+ * @access public
+ */
+ var $uses = null;
+}
+/**
+ * PostAjaxTest class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.view.helpers
+ */
+class PostAjaxTest extends Model {
+/**
+ * primaryKey property
+ *
+ * @var string 'id'
+ * @access public
+ */
+ var $primaryKey = 'id';
+/**
+ * useTable property
+ *
+ * @var bool false
+ * @access public
+ */
+ var $useTable = false;
+/**
+ * schema method
+ *
+ * @access public
+ * @return void
+ */
+ function schema() {
+ return array(
+ 'id' => array('type' => 'integer', 'null' => '', 'default' => '', 'length' => '8'),
+ 'name' => array('type' => 'string', 'null' => '', 'default' => '', 'length' => '255'),
+ 'created' => array('type' => 'date', 'null' => '1', 'default' => '', 'length' => ''),
+ 'updated' => array('type' => 'datetime', 'null' => '1', 'default' => '', 'length' => null)
+ );
+ }
+}
+/**
+ * TestAjaxHelper class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.view.helpers
+ */
+class TestAjaxHelper extends AjaxHelper {
+/**
+ * stop method
+ *
+ * @access public
+ * @return void
+ */
+ function _stop() {
+ }
+}
+/**
+ * TestJavascriptHelper class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.view.helpers
+ */
+class TestJavascriptHelper extends JavascriptHelper {
+/**
+ * codeBlocks property
+ *
+ * @var mixed
+ * @access public
+ */
+ var $codeBlocks;
+/**
+ * codeBlock method
+ *
+ * @param mixed $parameter
+ * @access public
+ * @return void
+ */
+ function codeBlock($parameter) {
+ if (empty($this->codeBlocks)) {
+ $this->codeBlocks = array();
+ }
+ $this->codeBlocks[] = $parameter;
+ }
+}
+/**
+ * AjaxTest class
+ *
+ * @package cake
+ * @subpackage cake.tests.cases.libs.view.helpers
+ */
+class AjaxHelperTest extends CakeTestCase {
+/**
+ * Regexp for CDATA start block
+ *
+ * @var string
+ */
+ var $cDataStart = 'preg:/^\/\/[\s\r\n]*/';
+/**
+ * setUp method
+ *
+ * @access public
+ * @return void
+ */
+ function setUp() {
+ Router::reload();
+ $this->Ajax =& new TestAjaxHelper();
+ $this->Ajax->Html =& new HtmlHelper();
+ $this->Ajax->Form =& new FormHelper();
+ $this->Ajax->Javascript =& new JavascriptHelper();
+ $this->Ajax->Form->Html =& $this->Ajax->Html;
+ $view =& new View(new AjaxTestController());
+ ClassRegistry::addObject('view', $view);
+ ClassRegistry::addObject('PostAjaxTest', new PostAjaxTest());
+
+ $this->Ajax->Form->params = array(
+ 'plugin' => null,
+ 'action' => 'view',
+ 'controller' => 'users'
+ );
+ }
+/**
+ * tearDown method
+ *
+ * @access public
+ * @return void
+ */
+ function tearDown() {
+ unset($this->Ajax);
+ ClassRegistry::flush();
+ }
+/**
+ * testEvalScripts method
+ *
+ * @access public
+ * @return void
+ */
+ function testEvalScripts() {
+ $result = $this->Ajax->link('Test Link', 'http://www.cakephp.org', array('id' => 'link1', 'update' => 'content', 'evalScripts' => false));
+ $expected = array(
+ 'a' => array('id' => 'link1', 'onclick' => ' event.returnValue = false; return false;', 'href' => 'http://www.cakephp.org'),
+ 'Test Link',
+ '/a',
+ array('script' => array('type' => 'text/javascript')),
+ $this->cDataStart,
+ "Event.observe('link1', 'click', function(event) { new Ajax.Updater('content','http://www.cakephp.org', {asynchronous:true, evalScripts:false, requestHeaders:['X-Update', 'content']}) }, false);",
+ $this->cDataEnd,
+ '/script'
+ );
+ $this->assertTags($result, $expected);
+
+ $result = $this->Ajax->link('Test Link', 'http://www.cakephp.org', array('id' => 'link1', 'update' => 'content'));
+ $expected = array(
+ 'a' => array('id' => 'link1', 'onclick' => ' event.returnValue = false; return false;', 'href' => 'http://www.cakephp.org'),
+ 'Test Link',
+ '/a',
+ array('script' => array('type' => 'text/javascript')),
+ $this->cDataStart,
+ "Event.observe('link1', 'click', function(event) { new Ajax.Updater('content','http://www.cakephp.org', {asynchronous:true, evalScripts:true, requestHeaders:['X-Update', 'content']}) }, false);",
+ $this->cDataEnd,
+ '/script'
+ );
+ $this->assertTags($result, $expected);
+ }
+/**
+ * testAutoComplete method
+ *
+ * @access public
+ * @return void
+ */
+ function testAutoComplete() {
+ $result = $this->Ajax->autoComplete('PostAjaxTest.title' , '/posts', array('minChars' => 2));
+ $this->assertPattern('/^ ]+name="data\[PostAjaxTest\]\[title\]"[^<>]+autocomplete="off"[^<>]+\/>/', $result);
+ $this->assertPattern('/]+id="PostAjaxTestTitle_autoComplete"[^<>]*><\/div>/', $result);
+ $this->assertPattern('/
]+class="auto_complete"[^<>]*><\/div>/', $result);
+ $this->assertPattern('/<\/div>\s+';
+ $this->assertEqual($result, $expected);
+
+ $result = $this->Javascript->link('script');
+ $expected = '';
+ $this->assertEqual($result, $expected);
+
+ $result = $this->Javascript->link('scriptaculous.js?load=effects');
+ $expected = '';
+ $this->assertEqual($result, $expected);
+
+ $result = $this->Javascript->link('some.json.libary');
+ $expected = '';
+ $this->assertEqual($result, $expected);
+
+ $result = $this->Javascript->link('jquery-1.1.2');
+ $expected = '';
+ $this->assertEqual($result, $expected);
+
+ $result = $this->Javascript->link('jquery-1.1.2');
+ $expected = '';
+ $this->assertEqual($result, $expected);
+
+ $result = $this->Javascript->link('/plugin/js/jquery-1.1.2');
+ $expected = '';
+ $this->assertEqual($result, $expected);
+
+ $result = $this->Javascript->link('/some_other_path/myfile.1.2.2.min.js');
+ $expected = '';
+ $this->assertEqual($result, $expected);
+
+ $result = $this->Javascript->link('some_other_path/myfile.1.2.2.min.js');
+ $expected = '';
+ $this->assertEqual($result, $expected);
+
+ $result = $this->Javascript->link('some_other_path/myfile.1.2.2.min');
+ $expected = '';
+ $this->assertEqual($result, $expected);
+
+ $result = $this->Javascript->link('http://example.com/jquery.js');
+ $expected = '';
+ $this->assertEqual($result, $expected);
+
+ $result = $this->Javascript->link(array('prototype.js', 'scriptaculous.js'));
+ $this->assertPattern('/^\s*';
+ $this->assertNull($result);
+ $this->assertEqual(count($resultScripts), 1);
+ $this->assertEqual(current($resultScripts), $expected);
+ }
+
+/**
+ * testFilteringAndTimestamping method
+ *
+ * @access public
+ * @return void
+ */
+ function testFilteringAndTimestamping() {
+ if ($this->skipIf(!is_writable(JS), 'JavaScript directory not writable, skipping JS asset timestamp tests. %s')) {
+ return;
+ }
+
+ cache(str_replace(WWW_ROOT, '', JS) . '__cake_js_test.js', 'alert("test")', '+999 days', 'public');
+ $timestamp = substr(strtotime('now'), 0, 8);
+
+ Configure::write('Asset.timestamp', true);
+ $result = $this->Javascript->link('__cake_js_test');
+ $this->assertPattern('/^';
+ $this->assertEqual($result, $expected);
+
+ Configure::write('Asset.timestamp', 'force');
+ $result = $this->Javascript->link('__cake_js_test');
+ $this->assertPattern('/^';
+ $this->assertEqual($result, $expected);
+
+ $result = $this->Javascript->link('folderjs/jquery-1.1.2');
+ $expected = '';
+ $this->assertEqual($result, $expected);
+
+ if ($old === null) {
+ Configure::delete('Asset.filter.js');
+ }
+
+ $debug = Configure::read('debug');
+ $webroot = $this->Javascript->webroot;
+
+ Configure::write('debug', 0);
+ Configure::write('Asset.timestamp', 'force');
+
+ $this->Javascript->webroot = '/testing/';
+ $result = $this->Javascript->link('__cake_js_test');
+ $this->assertPattern('/^
\ No newline at end of file
diff --git a/code/ryzom/tools/server/www/webtt/cake/tests/test_app/views/layouts/multi_cache.ctp b/code/ryzom/tools/server/www/webtt/cake/tests/test_app/views/layouts/multi_cache.ctp
new file mode 100644
index 000000000..86bc4d3ae
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/cake/tests/test_app/views/layouts/multi_cache.ctp
@@ -0,0 +1,40 @@
+
+
This is regular text
+
+ A. Layout Before Content
+ log('1. layout before content') ?>
+
+
element('nocache/plain'); ?>
+
+ C. Layout After Test Element But Before Content
+ log('3. layout after test element but before content') ?>
+
+
+
+ E. Layout After Content
+ log('5. layout after content') ?>
+
+
Additional regular text.
+element('nocache/contains_nocache'); stub?>
+
+ G. Layout After Content And After Element With No Cache Tags
+ log('7. layout after content and after element with no cache tags') ?>
+
\ No newline at end of file
diff --git a/code/ryzom/tools/server/www/webtt/cake/tests/test_app/views/layouts/rss/default.ctp b/code/ryzom/tools/server/www/webtt/cake/tests/test_app/views/layouts/rss/default.ctp
new file mode 100644
index 000000000..94067f2bf
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/cake/tests/test_app/views/layouts/rss/default.ctp
@@ -0,0 +1,17 @@
+header();
+
+if (!isset($channel)) {
+ $channel = array();
+}
+if (!isset($channel['title'])) {
+ $channel['title'] = $title_for_layout;
+}
+
+echo $rss->document(
+ $rss->channel(
+ array(), $channel, $content_for_layout
+ )
+);
+
+?>
\ No newline at end of file
diff --git a/code/ryzom/tools/server/www/webtt/cake/tests/test_app/views/layouts/xml/default.ctp b/code/ryzom/tools/server/www/webtt/cake/tests/test_app/views/layouts/xml/default.ctp
new file mode 100644
index 000000000..566ca2158
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/cake/tests/test_app/views/layouts/xml/default.ctp
@@ -0,0 +1,2 @@
+header(); ?>
+
\ No newline at end of file
diff --git a/code/ryzom/tools/server/www/webtt/cake/tests/test_app/views/pages/empty b/code/ryzom/tools/server/www/webtt/cake/tests/test_app/views/pages/empty
new file mode 100644
index 000000000..e69de29bb
diff --git a/code/ryzom/tools/server/www/webtt/cake/tests/test_app/views/pages/extract.ctp b/code/ryzom/tools/server/www/webtt/cake/tests/test_app/views/pages/extract.ctp
new file mode 100644
index 000000000..e3eede1c1
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/cake/tests/test_app/views/pages/extract.ctp
@@ -0,0 +1,14 @@
+ 10);
+
+// Plural
+__n('You have %d new message.', 'You have %d new messages.', $count);
+__n('You deleted %d message.', 'You deleted %d messages.', $messages['count']);
+
+// Domain Plural
+__dn('domain', 'You have %d new message (domain).', 'You have %d new messages (domain).', '10');
+__dn('domain', 'You deleted %d message (domain).', 'You deleted %d messages (domain).', $messages['count']);
+
+// Duplicated Message
+__('Editing this Page');
\ No newline at end of file
diff --git a/code/ryzom/tools/server/www/webtt/cake/tests/test_app/views/pages/home.ctp b/code/ryzom/tools/server/www/webtt/cake/tests/test_app/views/pages/home.ctp
new file mode 100644
index 000000000..830a21fae
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/cake/tests/test_app/views/pages/home.ctp
@@ -0,0 +1,82 @@
+
Sweet, "Test App" got Baked by CakePHP!
+
+ 0):
+ Debugger::checkSecurityKeys();
+endif;
+?>
+
+';
+ __('Your tmp directory is writable.');
+ echo '';
+ else:
+ echo '';
+ __('Your tmp directory is NOT writable.');
+ echo ' ';
+ endif;
+?>
+
+
+';
+ printf(__('The %s is being used for caching. To change the config edit APP/config/core.php ', true), ''. $settings['engine'] . 'Engine ');
+ echo '';
+ else:
+ echo '';
+ __('Your cache is NOT working. Please check the settings in APP/config/core.php');
+ echo ' ';
+ endif;
+?>
+
+
+';
+ __('Your database configuration file is present.');
+ $filePresent = true;
+ echo '';
+ else:
+ echo '';
+ __('Your database configuration file is NOT present.');
+ echo ' ';
+ __('Rename config/database.php.default to config/database.php');
+ echo ' ';
+ endif;
+?>
+
+getDataSource('default');
+?>
+
+isConnected()):
+ echo '';
+ __('Cake is able to connect to the database.');
+ echo ' ';
+ else:
+ echo '';
+ __('Cake is NOT able to connect to the database.');
+ echo ' ';
+ endif;
+?>
+
+
+
+
+', APP . 'views' . DS . 'layouts' . DS . 'default.ctp. ', APP . 'webroot' . DS . 'css');
+?>
+
\ No newline at end of file
diff --git a/code/ryzom/tools/server/www/webtt/cake/tests/test_app/views/posts/cache_empty_sections.ctp b/code/ryzom/tools/server/www/webtt/cake/tests/test_app/views/posts/cache_empty_sections.ctp
new file mode 100644
index 000000000..ab6fb3ae9
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/cake/tests/test_app/views/posts/cache_empty_sections.ctp
@@ -0,0 +1,2 @@
+View Content
+
diff --git a/code/ryzom/tools/server/www/webtt/cake/tests/test_app/views/posts/cache_form.ctp b/code/ryzom/tools/server/www/webtt/cake/tests/test_app/views/posts/cache_form.ctp
new file mode 100644
index 000000000..87ec9cf5b
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/cake/tests/test_app/views/posts/cache_form.ctp
@@ -0,0 +1,14 @@
+
+
+ create('User');?>
+
+
+ input('username');
+ echo $form->input('email');
+ echo $form->input('password');
+ ?>
+
+ end('Submit');?>
+
+
\ No newline at end of file
diff --git a/code/ryzom/tools/server/www/webtt/cake/tests/test_app/views/posts/helper_overwrite.ctp b/code/ryzom/tools/server/www/webtt/cake/tests/test_app/views/posts/helper_overwrite.ctp
new file mode 100644
index 000000000..a3b6928fb
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/cake/tests/test_app/views/posts/helper_overwrite.ctp
@@ -0,0 +1,4 @@
+Html->link('Test link', '#');
+?>
\ No newline at end of file
diff --git a/code/ryzom/tools/server/www/webtt/cake/tests/test_app/views/posts/index.ctp b/code/ryzom/tools/server/www/webtt/cake/tests/test_app/views/posts/index.ctp
new file mode 100644
index 000000000..ff145eeed
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/cake/tests/test_app/views/posts/index.ctp
@@ -0,0 +1 @@
+posts index
\ No newline at end of file
diff --git a/code/ryzom/tools/server/www/webtt/cake/tests/test_app/views/posts/multiple_nocache.ctp b/code/ryzom/tools/server/www/webtt/cake/tests/test_app/views/posts/multiple_nocache.ctp
new file mode 100644
index 000000000..eb397e492
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/cake/tests/test_app/views/posts/multiple_nocache.ctp
@@ -0,0 +1,15 @@
+--view start--
+
+
+
+
+this view has 3 nocache blocks
+
+
+
+
+
+
+
+
+--view end--
\ No newline at end of file
diff --git a/code/ryzom/tools/server/www/webtt/cake/tests/test_app/views/posts/nocache_multiple_element.ctp b/code/ryzom/tools/server/www/webtt/cake/tests/test_app/views/posts/nocache_multiple_element.ctp
new file mode 100644
index 000000000..a72788305
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/cake/tests/test_app/views/posts/nocache_multiple_element.ctp
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+element('nocache/sub1'); ?>
\ No newline at end of file
diff --git a/code/ryzom/tools/server/www/webtt/cake/tests/test_app/views/posts/scaffold.edit.ctp b/code/ryzom/tools/server/www/webtt/cake/tests/test_app/views/posts/scaffold.edit.ctp
new file mode 100644
index 000000000..ff8239012
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/cake/tests/test_app/views/posts/scaffold.edit.ctp
@@ -0,0 +1 @@
+test_app posts add/edit scaffold view
\ No newline at end of file
diff --git a/code/ryzom/tools/server/www/webtt/cake/tests/test_app/views/posts/sequencial_nocache.ctp b/code/ryzom/tools/server/www/webtt/cake/tests/test_app/views/posts/sequencial_nocache.ctp
new file mode 100644
index 000000000..27dd47fd2
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/cake/tests/test_app/views/posts/sequencial_nocache.ctp
@@ -0,0 +1,24 @@
+
+
Content
+
+ D. In View File
+ log('4. in view file') ?>
+
\ No newline at end of file
diff --git a/code/ryzom/tools/server/www/webtt/cake/tests/test_app/views/posts/test_nocache_tags.ctp b/code/ryzom/tools/server/www/webtt/cake/tests/test_app/views/posts/test_nocache_tags.ctp
new file mode 100644
index 000000000..d1bf80e72
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/cake/tests/test_app/views/posts/test_nocache_tags.ctp
@@ -0,0 +1,144 @@
+
+
+
+
+
+
+
+
+
+
+ ' . $settings['engine'];
+ __(' is being used to cache, to change this edit config/core.php ');
+ echo '
';
+
+ echo 'Settings:
';
+ foreach ($settings as $name => $value):
+ echo '' . $name . ': ' . $value . ' ';
+ endforeach;
+ echo ' ';
+
+ else:
+ __('NOT working.');
+ echo '
';
+ if (is_writable(TMP)):
+ __('Edit: config/core.php to insure you have the newset version of this file and the variable $cakeCache set properly');
+ endif;
+ endif;
+ ?>
+
+
+
+
+ ';
+ __('Rename config/database.php.default to config/database.php');
+ endif;
+ ?>
+
+
+getDataSource('default');
+?>
+
+
+ isConnected()):
+ __(' is able to ');
+ else:
+ __(' is NOT able to ');
+ endif;
+ __('connect to the database.');
+ ?>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/code/ryzom/tools/server/www/webtt/cake/tests/test_app/views/scaffolds/empty b/code/ryzom/tools/server/www/webtt/cake/tests/test_app/views/scaffolds/empty
new file mode 100644
index 000000000..e69de29bb
diff --git a/code/ryzom/tools/server/www/webtt/cake/tests/test_app/views/tests_apps/index.ctp b/code/ryzom/tools/server/www/webtt/cake/tests/test_app/views/tests_apps/index.ctp
new file mode 100644
index 000000000..36aecfa1d
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/cake/tests/test_app/views/tests_apps/index.ctp
@@ -0,0 +1 @@
+This is the TestsAppsController index view
\ No newline at end of file
diff --git a/code/ryzom/tools/server/www/webtt/cake/tests/test_app/views/themed/test_theme/elements/test_element.ctp b/code/ryzom/tools/server/www/webtt/cake/tests/test_app/views/themed/test_theme/elements/test_element.ctp
new file mode 100644
index 000000000..745dddbf2
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/cake/tests/test_app/views/themed/test_theme/elements/test_element.ctp
@@ -0,0 +1 @@
+Hi, I'm the test element.
\ No newline at end of file
diff --git a/code/ryzom/tools/server/www/webtt/cake/tests/test_app/views/themed/test_theme/layouts/default.ctp b/code/ryzom/tools/server/www/webtt/cake/tests/test_app/views/themed/test_theme/layouts/default.ctp
new file mode 100644
index 000000000..89107d393
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/cake/tests/test_app/views/themed/test_theme/layouts/default.ctp
@@ -0,0 +1 @@
+default test_theme layout
\ No newline at end of file
diff --git a/code/ryzom/tools/server/www/webtt/cake/tests/test_app/views/themed/test_theme/plugins/test_plugin/layouts/plugin_default.ctp b/code/ryzom/tools/server/www/webtt/cake/tests/test_app/views/themed/test_theme/plugins/test_plugin/layouts/plugin_default.ctp
new file mode 100644
index 000000000..9e1e449c2
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/cake/tests/test_app/views/themed/test_theme/plugins/test_plugin/layouts/plugin_default.ctp
@@ -0,0 +1 @@
+test_plugin test_plugin_theme default layout
\ No newline at end of file
diff --git a/code/ryzom/tools/server/www/webtt/cake/tests/test_app/views/themed/test_theme/plugins/test_plugin/tests/index.ctp b/code/ryzom/tools/server/www/webtt/cake/tests/test_app/views/themed/test_theme/plugins/test_plugin/tests/index.ctp
new file mode 100644
index 000000000..edf7ab4b2
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/cake/tests/test_app/views/themed/test_theme/plugins/test_plugin/tests/index.ctp
@@ -0,0 +1 @@
+test plugin index theme view
\ No newline at end of file
diff --git a/code/ryzom/tools/server/www/webtt/cake/tests/test_app/views/themed/test_theme/posts/index.ctp b/code/ryzom/tools/server/www/webtt/cake/tests/test_app/views/themed/test_theme/posts/index.ctp
new file mode 100644
index 000000000..3ec978c95
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/cake/tests/test_app/views/themed/test_theme/posts/index.ctp
@@ -0,0 +1 @@
+posts index themed view
\ No newline at end of file
diff --git a/code/ryzom/tools/server/www/webtt/cake/tests/test_app/views/themed/test_theme/posts/scaffold.index.ctp b/code/ryzom/tools/server/www/webtt/cake/tests/test_app/views/themed/test_theme/posts/scaffold.index.ctp
new file mode 100644
index 000000000..a7829877c
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/cake/tests/test_app/views/themed/test_theme/posts/scaffold.index.ctp
@@ -0,0 +1 @@
+I'm a themed scaffold file.
\ No newline at end of file
diff --git a/code/ryzom/tools/server/www/webtt/cake/tests/test_app/views/themed/test_theme/webroot/css/test_asset.css b/code/ryzom/tools/server/www/webtt/cake/tests/test_app/views/themed/test_theme/webroot/css/test_asset.css
new file mode 100644
index 000000000..e8b09dd29
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/cake/tests/test_app/views/themed/test_theme/webroot/css/test_asset.css
@@ -0,0 +1 @@
+this is the test asset css file
\ No newline at end of file
diff --git a/code/ryzom/tools/server/www/webtt/cake/tests/test_app/views/themed/test_theme/webroot/css/theme_webroot.css b/code/ryzom/tools/server/www/webtt/cake/tests/test_app/views/themed/test_theme/webroot/css/theme_webroot.css
new file mode 100644
index 000000000..12e29a565
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/cake/tests/test_app/views/themed/test_theme/webroot/css/theme_webroot.css
@@ -0,0 +1 @@
+theme webroot css file
\ No newline at end of file
diff --git a/code/ryzom/tools/server/www/webtt/cake/tests/test_app/views/themed/test_theme/webroot/flash/theme_test.swf b/code/ryzom/tools/server/www/webtt/cake/tests/test_app/views/themed/test_theme/webroot/flash/theme_test.swf
new file mode 100644
index 000000000..cfe782b7a
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/cake/tests/test_app/views/themed/test_theme/webroot/flash/theme_test.swf
@@ -0,0 +1 @@
+this is just a test to load swf file from the theme.
\ No newline at end of file
diff --git a/code/ryzom/tools/server/www/webtt/cake/tests/test_app/views/themed/test_theme/webroot/img/cake.power.gif b/code/ryzom/tools/server/www/webtt/cake/tests/test_app/views/themed/test_theme/webroot/img/cake.power.gif
new file mode 100644
index 000000000..8f8d570a2
Binary files /dev/null and b/code/ryzom/tools/server/www/webtt/cake/tests/test_app/views/themed/test_theme/webroot/img/cake.power.gif differ
diff --git a/code/ryzom/tools/server/www/webtt/cake/tests/test_app/views/themed/test_theme/webroot/img/test.jpg b/code/ryzom/tools/server/www/webtt/cake/tests/test_app/views/themed/test_theme/webroot/img/test.jpg
new file mode 100644
index 000000000..ca5197ae8
Binary files /dev/null and b/code/ryzom/tools/server/www/webtt/cake/tests/test_app/views/themed/test_theme/webroot/img/test.jpg differ
diff --git a/code/ryzom/tools/server/www/webtt/cake/tests/test_app/views/themed/test_theme/webroot/js/one/theme_one.js b/code/ryzom/tools/server/www/webtt/cake/tests/test_app/views/themed/test_theme/webroot/js/one/theme_one.js
new file mode 100644
index 000000000..d29bcbc94
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/cake/tests/test_app/views/themed/test_theme/webroot/js/one/theme_one.js
@@ -0,0 +1 @@
+nested theme js file
\ No newline at end of file
diff --git a/code/ryzom/tools/server/www/webtt/cake/tests/test_app/views/themed/test_theme/webroot/js/theme.js b/code/ryzom/tools/server/www/webtt/cake/tests/test_app/views/themed/test_theme/webroot/js/theme.js
new file mode 100644
index 000000000..ec17940de
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/cake/tests/test_app/views/themed/test_theme/webroot/js/theme.js
@@ -0,0 +1 @@
+root theme js file
\ No newline at end of file
diff --git a/code/ryzom/tools/server/www/webtt/cake/tests/test_app/views/themed/test_theme/webroot/pdfs/theme_test.pdf b/code/ryzom/tools/server/www/webtt/cake/tests/test_app/views/themed/test_theme/webroot/pdfs/theme_test.pdf
new file mode 100644
index 000000000..9c1dcbcc4
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/cake/tests/test_app/views/themed/test_theme/webroot/pdfs/theme_test.pdf
@@ -0,0 +1 @@
+this is just a test to load pdf file from the theme.
\ No newline at end of file
diff --git a/code/ryzom/tools/server/www/webtt/cake/tests/test_app/webroot/theme/test_theme/css/theme_webroot.css b/code/ryzom/tools/server/www/webtt/cake/tests/test_app/webroot/theme/test_theme/css/theme_webroot.css
new file mode 100644
index 000000000..f65d3e08a
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/cake/tests/test_app/webroot/theme/test_theme/css/theme_webroot.css
@@ -0,0 +1 @@
+override the theme webroot css file
\ No newline at end of file
diff --git a/code/ryzom/tools/server/www/webtt/cake/tests/test_app/webroot/theme/test_theme/css/webroot_test.css b/code/ryzom/tools/server/www/webtt/cake/tests/test_app/webroot/theme/test_theme/css/webroot_test.css
new file mode 100644
index 000000000..83c3bc4d7
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/cake/tests/test_app/webroot/theme/test_theme/css/webroot_test.css
@@ -0,0 +1 @@
+this is the webroot test asset css file
\ No newline at end of file
diff --git a/code/ryzom/tools/server/www/webtt/cake/tests/test_app/webroot/theme/test_theme/img/cake.power.gif b/code/ryzom/tools/server/www/webtt/cake/tests/test_app/webroot/theme/test_theme/img/cake.power.gif
new file mode 100644
index 000000000..8f8d570a2
Binary files /dev/null and b/code/ryzom/tools/server/www/webtt/cake/tests/test_app/webroot/theme/test_theme/img/cake.power.gif differ
diff --git a/code/ryzom/tools/server/www/webtt/cake/tests/test_app/webroot/theme/test_theme/img/test.jpg b/code/ryzom/tools/server/www/webtt/cake/tests/test_app/webroot/theme/test_theme/img/test.jpg
new file mode 100644
index 000000000..ca5197ae8
Binary files /dev/null and b/code/ryzom/tools/server/www/webtt/cake/tests/test_app/webroot/theme/test_theme/img/test.jpg differ
diff --git a/code/ryzom/tools/server/www/webtt/index.php b/code/ryzom/tools/server/www/webtt/index.php
new file mode 100644
index 000000000..9fd58145e
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/index.php
@@ -0,0 +1,55 @@
+ 1.2` are compatible with CakePHP 1.2.x. These releases of DebugKit will not work with CakePHP 1.3.
+* `1.3` is compatible with CakePHP 1.3.x only. It will not work with CakePHP 1.2.
+
diff --git a/code/ryzom/tools/server/www/webtt/plugins/debug_kit/build.py b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/build.py
new file mode 100755
index 000000000..ba75dcf62
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/build.py
@@ -0,0 +1,130 @@
+#! /usr/bin/env python
+
+import sys, os
+import tarfile, zipfile, gzip, bz2
+from optparse import OptionParser
+
+"""
+Builds packaged releases of DebugKit so I don't have to do things manually.
+
+Excludes itself (build.py), .gitignore, .DS_Store and the .git folder from the archives.
+"""
+def main():
+ parser = OptionParser();
+ parser.add_option('-o', '--output-dir', dest="output_dir",
+ help="write the packages to DIR", metavar="DIR")
+ parser.add_option('-p', '--prefix-name', dest="prefix",
+ help="prefix used for the generated files")
+ parser.add_option('-k', '--skip', dest="skip", default="",
+ help="A comma separated list of files to skip")
+ parser.add_option('-s', '--source-dir', dest="source", default=".",
+ help="The source directory for the build process")
+
+ (options, args) = parser.parse_args()
+
+ if options.output_dir == '' or options.output_dir == options.source:
+ print 'Requires an output dir, and that output dir cannot be the same as the source one!'
+ exit()
+
+ # append .git and build.py to the skip files
+ skip = options.skip.split(',')
+ skip.extend(['.git', '.gitignore', '.DS_Store', 'build.py'])
+
+ # get list of files in top level dir.
+ files = os.listdir(options.source)
+
+ os.chdir(options.source)
+
+ # filter the files, I couldn't figure out how to do it in a more concise way.
+ for f in files[:]:
+ try:
+ skip.index(f)
+ files.remove(f)
+ except ValueError:
+ pass
+
+ # make a boring tar file
+ destfile = ''.join([options.output_dir, options.prefix])
+ tar_file_name = destfile + '.tar'
+ tar = tarfile.open(tar_file_name, 'w');
+ for f in files:
+ tar.add(f)
+ tar.close()
+ print "Generated tar file"
+
+ # make the gzip
+ if make_gzip(tar_file_name, destfile):
+ print "Generated gzip file"
+ else:
+ print "Could not generate gzip file"
+
+ # make the bz2
+ if make_bz2(tar_file_name, destfile):
+ print "Generated bz2 file"
+ else:
+ print "Could not generate bz2 file"
+
+ # make the zip file
+ zip_recursive(destfile + '.zip', options.source, files)
+ print "Generated zip file\n"
+
+def make_gzip(tar_file, destination):
+ """
+ Takes a tar_file and destination. Compressess the tar file and creates
+ a .tar.gzip
+ """
+ tar_contents = open(tar_file, 'rb')
+ gzipfile = gzip.open(destination + '.tar.gz', 'wb')
+ gzipfile.writelines(tar_contents)
+ gzipfile.close()
+ tar_contents.close()
+ return True
+
+def make_bz2(tar_file, destination):
+ """
+ Takes a tar_file and destination. Compressess the tar file and creates
+ a .tar.bz2
+ """
+ tar_contents = open(tar_file, 'rb')
+ bz2file = bz2.BZ2File(destination + '.tar.bz2', 'wb')
+ bz2file.writelines(tar_contents)
+ bz2file.close()
+ tar_contents.close()
+ return True
+
+def zip_recursive(destination, source_dir, rootfiles):
+ """
+ Recursively zips source_dir into destination.
+ rootfiles should contain a list of files in the top level directory that
+ are to be included. Any top level files not in rootfiles will be omitted
+ from the zip file.
+ """
+ zipped = zipfile.ZipFile(destination, 'w', zipfile.ZIP_DEFLATED)
+
+ for root, dirs, files in os.walk(source_dir):
+ inRoot = False
+ if root == source_dir:
+ inRoot = True
+
+ if inRoot:
+ for d in dirs:
+ try:
+ rootfiles.index(d)
+ except ValueError:
+ dirs.remove(d)
+
+ for f in files[:]:
+ if inRoot:
+ try:
+ rootfiles.index(f)
+ except ValueError:
+ continue
+
+ fullpath = os.path.join(root, f)
+ zipped.write(fullpath)
+ zipped.close()
+ return destination
+
+
+if __name__ == '__main__':
+ main()
\ No newline at end of file
diff --git a/code/ryzom/tools/server/www/webtt/plugins/debug_kit/controllers/components/toolbar.php b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/controllers/components/toolbar.php
new file mode 100644
index 000000000..1066cf75f
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/controllers/components/toolbar.php
@@ -0,0 +1,700 @@
+ false,
+ 'autoRun' => true
+ );
+
+/**
+ * Controller instance reference
+ *
+ * @var object
+ */
+ var $controller;
+
+/**
+ * Components used by DebugToolbar
+ *
+ * @var array
+ */
+ var $components = array('RequestHandler', 'Session');
+
+/**
+ * The default panels the toolbar uses.
+ * which panels are used can be configured when attaching the component
+ *
+ * @var array
+ */
+ var $_defaultPanels = array('history', 'session', 'request', 'sqlLog', 'timer', 'log', 'variables');
+
+/**
+ * Loaded panel objects.
+ *
+ * @var array
+ */
+ var $panels = array();
+
+/**
+ * javascript files component will be using
+ *
+ * @var array
+ **/
+ var $javascript = array(
+ 'behavior' => '/debug_kit/js/js_debug_toolbar'
+ );
+
+/**
+ * CacheKey used for the cache file.
+ *
+ * @var string
+ **/
+ var $cacheKey = 'toolbar_cache';
+
+/**
+ * Duration of the debug kit history cache
+ *
+ * @var string
+ **/
+ var $cacheDuration = '+4 hours';
+
+/**
+ * initialize
+ *
+ * If debug is off the component will be disabled and not do any further time tracking
+ * or load the toolbar helper.
+ *
+ * @return bool
+ **/
+ function initialize(&$controller, $settings) {
+ $this->settings = am($this->settings, $settings);
+ if (!Configure::read('debug') && empty($this->settings['forceEnable'])) {
+ $this->enabled = false;
+ return false;
+ }
+ if ($this->settings['autoRun'] == false && !isset($controller->params['url']['debug'])) {
+ $this->enabled = false;
+ return false;
+ }
+ App::import('Vendor', 'DebugKit.DebugKitDebugger');
+
+ DebugKitDebugger::setMemoryPoint(__d('debug_kit', 'Component initialization', true));
+ DebugKitDebugger::startTimer('componentInit', __d('debug_kit', 'Component initialization and startup', true));
+
+ $panels = $this->_defaultPanels;
+ if (isset($settings['panels'])) {
+ $panels = $this->_makePanelList($settings['panels']);
+ unset($settings['panels']);
+ }
+
+ $this->cacheKey .= $this->Session->read('Config.userAgent');
+ if (in_array('history', $panels) || (isset($settings['history']) && $settings['history'] !== false)) {
+ $this->_createCacheConfig();
+ }
+
+ $this->_loadPanels($panels, $settings);
+
+ $this->_set($settings);
+ $this->controller =& $controller;
+ return false;
+ }
+
+/**
+ * Go through user panels and remove default panels as indicated.
+ *
+ * @param array $userPanels The list of panels ther user has added removed.
+ * @return array Array of panels to use.
+ **/
+ function _makePanelList($userPanels) {
+ $panels = $this->_defaultPanels;
+ foreach ($userPanels as $key => $value) {
+ if (is_numeric($key)) {
+ $panels[] = $value;
+ }
+ if (is_string($key) && $value === false) {
+ $index = array_search($key, $panels);
+ if ($index !== false) {
+ unset($panels[$index]);
+ }
+ }
+ }
+ return $panels;
+ }
+
+/**
+ * Component Startup
+ *
+ * @return bool
+ **/
+ function startup(&$controller) {
+ $currentViewClass = $controller->view;
+ $this->_makeViewClass($currentViewClass);
+ $controller->view = 'DebugKit.Debug';
+ $isHtml = (
+ !isset($controller->params['url']['ext']) ||
+ (isset($controller->params['url']['ext']) && $controller->params['url']['ext'] == 'html')
+ );
+
+ if (!$this->RequestHandler->isAjax() && $isHtml) {
+ $format = 'Html';
+ } else {
+ $format = 'FirePhp';
+ }
+ $controller->helpers['DebugKit.Toolbar'] = array(
+ 'output' => sprintf('DebugKit.%sToolbar', $format),
+ 'cacheKey' => $this->cacheKey,
+ 'cacheConfig' => 'debug_kit',
+ 'forceEnable' => $this->settings['forceEnable'],
+ );
+ $panels = array_keys($this->panels);
+ foreach ($panels as $panelName) {
+ $this->panels[$panelName]->startup($controller);
+ }
+ DebugKitDebugger::stopTimer('componentInit');
+ DebugKitDebugger::startTimer('controllerAction', __d('debug_kit', 'Controller action', true));
+ DebugKitDebugger::setMemoryPoint(__d('debug_kit', 'Controller action start', true));
+ }
+
+/**
+ * beforeRedirect callback
+ *
+ * @return void
+ **/
+ function beforeRedirect(&$controller) {
+ if (!class_exists('DebugKitDebugger')) {
+ return null;
+ }
+ DebugKitDebugger::stopTimer('controllerAction');
+ $vars = $this->_gatherVars($controller);
+ $this->_saveState($controller, $vars);
+ }
+
+/**
+ * beforeRender callback
+ *
+ * Calls beforeRender on all the panels and set the aggregate to the controller.
+ *
+ * @return void
+ **/
+ function beforeRender(&$controller) {
+ if (!class_exists('DebugKitDebugger')) {
+ return null;
+ }
+ DebugKitDebugger::stopTimer('controllerAction');
+ $vars = $this->_gatherVars($controller);
+ $this->_saveState($controller, $vars);
+
+ $controller->set(array('debugToolbarPanels' => $vars, 'debugToolbarJavascript' => $this->javascript));
+ DebugKitDebugger::startTimer('controllerRender', __d('debug_kit', 'Render Controller Action', true));
+ DebugKitDebugger::setMemoryPoint(__d('debug_kit', 'Controller render start', true));
+ }
+
+/**
+ * Load a toolbar state from cache
+ *
+ * @param int $key
+ * @return array
+ **/
+ function loadState($key) {
+ $history = Cache::read($this->cacheKey, 'debug_kit');
+ if (isset($history[$key])) {
+ return $history[$key];
+ }
+ return array();
+ }
+
+/**
+ * Create the cache config for the history
+ *
+ * @return void
+ * @access protected
+ **/
+ function _createCacheConfig() {
+ if (Configure::read('Cache.disable') !== true) {
+ Cache::config('debug_kit', array(
+ 'duration' => $this->cacheDuration,
+ 'engine' => 'File',
+ 'path' => CACHE
+ ));
+ Cache::config('default');
+ }
+ }
+
+/**
+ * collects the panel contents
+ *
+ * @return array Array of all panel beforeRender()
+ * @access protected
+ **/
+ function _gatherVars(&$controller) {
+ $vars = array();
+ $panels = array_keys($this->panels);
+
+ foreach ($panels as $panelName) {
+ $panel =& $this->panels[$panelName];
+ $panelName = Inflector::underscore($panelName);
+ $vars[$panelName]['content'] = $panel->beforeRender($controller);
+ $elementName = Inflector::underscore($panelName) . '_panel';
+ if (isset($panel->elementName)) {
+ $elementName = $panel->elementName;
+ }
+ $vars[$panelName]['elementName'] = $elementName;
+ $vars[$panelName]['plugin'] = $panel->plugin;
+ $vars[$panelName]['title'] = $panel->title;
+ $vars[$panelName]['disableTimer'] = true;
+ }
+ return $vars;
+ }
+
+/**
+ * Load Panels used in the debug toolbar
+ *
+ * @return void
+ * @access protected
+ **/
+ function _loadPanels($panels, $settings) {
+ foreach ($panels as $panel) {
+ $className = $panel . 'Panel';
+ if (!class_exists($className) && !App::import('Vendor', $className)) {
+ trigger_error(sprintf(__d('debug_kit', 'Could not load DebugToolbar panel %s', true), $panel), E_USER_WARNING);
+ continue;
+ }
+ list($plugin, $className) = pluginSplit($className);
+ $panelObj =& new $className($settings);
+ if (is_subclass_of($panelObj, 'DebugPanel') || is_subclass_of($panelObj, 'debugpanel')) {
+ list(, $panel) = pluginSplit($panel);
+ $this->panels[$panel] =& $panelObj;
+ }
+ }
+ }
+/**
+ * Makes the DoppleGangerView class if it doesn't already exist.
+ * This allows DebugView to be compatible with all view classes.
+ *
+ * @param string $baseClassName
+ * @access protected
+ * @return void
+ */
+ function _makeViewClass($baseClassName) {
+ if (!class_exists('DoppelGangerView')) {
+ $parent = strtolower($baseClassName) === 'view' ? false : true;
+ App::import('View', $baseClassName, $parent);
+ if (strpos($baseClassName, '.') !== false) {
+ list($plugin, $baseClassName) = explode('.', $baseClassName);
+ }
+ if (strpos($baseClassName, 'View') === false) {
+ $baseClassName .= 'View';
+ }
+ $class = "class DoppelGangerView extends $baseClassName {}";
+ $this->_eval($class);
+ }
+ }
+
+/**
+ * Method wrapper for eval() for testing uses.
+ *
+ * @return void
+ **/
+ function _eval($code) {
+ eval($code);
+ }
+
+/**
+ * Save the current state of the toolbar varibles to the cache file.
+ *
+ * @param object $controller Controller instance
+ * @param array $vars Vars to save.
+ * @access protected
+ * @return void
+ **/
+ function _saveState(&$controller, $vars) {
+ $config = Cache::config('debug_kit');
+ if (empty($config) || !isset($this->panels['history'])) {
+ return;
+ }
+ $history = Cache::read($this->cacheKey, 'debug_kit');
+ if (empty($history)) {
+ $history = array();
+ }
+ if (count($history) == $this->panels['history']->history) {
+ array_pop($history);
+ }
+ unset($vars['history']);
+ array_unshift($history, $vars);
+ Cache::write($this->cacheKey, $history, 'debug_kit');
+ }
+}
+
+/**
+ * Debug Panel
+ *
+ * Abstract class for debug panels.
+ *
+ * @package cake.debug_kit
+ */
+class DebugPanel extends Object {
+/**
+ * Defines which plugin this panel is from so the element can be located.
+ *
+ * @var string
+ */
+ var $plugin = null;
+
+/**
+ * Defines the title for displaying on the toolbar. If null, the class name will be used.
+ * Overriding this allows you to define a custom name in the toolbar.
+ *
+ * @var string
+ */
+ var $title = null;
+
+/**
+ * Provide a custom element name for this panel. If null, the underscored version of the class
+ * name will be used.
+ *
+ * @var string
+ */
+ var $elementName = null;
+
+/**
+ * startup the panel
+ *
+ * Pull information from the controller / request
+ *
+ * @param object $controller Controller reference.
+ * @return void
+ **/
+ function startup(&$controller) { }
+
+/**
+ * Prepare output vars before Controller Rendering.
+ *
+ * @param object $controller Controller reference.
+ * @return void
+ **/
+ function beforeRender(&$controller) { }
+}
+
+/**
+ * History Panel
+ *
+ * Provides debug information on previous requests.
+ *
+ * @package cake.debug_kit.panels
+ **/
+class HistoryPanel extends DebugPanel {
+
+ var $plugin = 'debug_kit';
+
+/**
+ * Number of history elements to keep
+ *
+ * @var string
+ **/
+ var $history = 5;
+
+/**
+ * Constructor
+ *
+ * @param array $settings Array of settings.
+ * @return void
+ **/
+ function __construct($settings) {
+ if (isset($settings['history'])) {
+ $this->history = $settings['history'];
+ }
+ }
+
+/**
+ * beforeRender callback function
+ *
+ * @return array contents for panel
+ **/
+ function beforeRender(&$controller) {
+ $cacheKey = $controller->Toolbar->cacheKey;
+ $toolbarHistory = Cache::read($cacheKey, 'debug_kit');
+ $historyStates = array();
+ if (is_array($toolbarHistory) && !empty($toolbarHistory)) {
+ $prefix = array();
+ if (!empty($controller->params['prefix'])) {
+ $prefix[$controller->params['prefix']] = false;
+ }
+ foreach ($toolbarHistory as $i => $state) {
+ if (!isset($state['request']['content']['params']['url']['url'])) {
+ continue;
+ }
+ $historyStates[] = array(
+ 'title' => $state['request']['content']['params']['url']['url'],
+ 'url' => array_merge($prefix, array(
+ 'plugin' => 'debug_kit',
+ 'controller' => 'toolbar_access',
+ 'action' => 'history_state',
+ $i + 1))
+ );
+ }
+ }
+ if (count($historyStates) >= $this->history) {
+ array_pop($historyStates);
+ }
+ return $historyStates;
+ }
+}
+
+/**
+ * Variables Panel
+ *
+ * Provides debug information on the View variables.
+ *
+ * @package cake.debug_kit.panels
+ **/
+class VariablesPanel extends DebugPanel {
+
+ var $plugin = 'debug_kit';
+
+/**
+ * beforeRender callback
+ *
+ * @return array
+ **/
+ function beforeRender(&$controller) {
+ return array_merge($controller->viewVars, array('$this->data' => $controller->data));
+ }
+}
+
+/**
+ * Session Panel
+ *
+ * Provides debug information on the Session contents.
+ *
+ * @package cake.debug_kit.panels
+ **/
+class SessionPanel extends DebugPanel {
+
+ var $plugin = 'debug_kit';
+
+/**
+ * beforeRender callback
+ *
+ * @param object $controller
+ * @access public
+ * @return array
+ */
+ function beforeRender(&$controller) {
+ $sessions = $controller->Toolbar->Session->read();
+ return $sessions;
+ }
+}
+
+/**
+ * Request Panel
+ *
+ * Provides debug information on the Current request params.
+ *
+ * @package cake.debug_kit.panels
+ **/
+class RequestPanel extends DebugPanel {
+
+ var $plugin = 'debug_kit';
+
+/**
+ * beforeRender callback - grabs request params
+ *
+ * @return array
+ **/
+ function beforeRender(&$controller) {
+ $out = array();
+ $out['params'] = $controller->params;
+ if (isset($controller->Cookie)) {
+ $out['cookie'] = $controller->Cookie->read();
+ }
+ $out['get'] = $_GET;
+ $out['currentRoute'] = Router::currentRoute();
+ return $out;
+ }
+}
+
+/**
+ * Timer Panel
+ *
+ * Provides debug information on all timers used in a request.
+ *
+ * @package cake.debug_kit.panels
+ **/
+class TimerPanel extends DebugPanel {
+
+ var $plugin = 'debug_kit';
+
+/**
+ * startup - add in necessary helpers
+ *
+ * @return void
+ **/
+ function startup(&$controller) {
+ if (!in_array('Number', $controller->helpers)) {
+ $controller->helpers[] = 'Number';
+ }
+ if (!in_array('SimpleGraph', $controller->helpers)) {
+ $controller->helpers[] = 'DebugKit.SimpleGraph';
+ }
+ }
+}
+
+/**
+ * SqlLog Panel
+ *
+ * Provides debug information on the SQL logs and provides links to an ajax explain interface.
+ *
+ * @package cake.debug_kit.panels
+ **/
+class SqlLogPanel extends DebugPanel {
+
+ var $plugin = 'debug_kit';
+
+/**
+ * Minimum number of Rows Per Millisecond that must be returned by a query before an explain
+ * is done.
+ *
+ * @var int
+ **/
+ var $slowRate = 20;
+
+/**
+ * Gets the connection names that should have logs + dumps generated.
+ *
+ * @param string $controller
+ * @access public
+ * @return void
+ */
+ function beforeRender(&$controller) {
+ if (!class_exists('ConnectionManager')) {
+ return array();
+ }
+ $connections = array();
+
+ $dbConfigs = ConnectionManager::sourceList();
+ foreach ($dbConfigs as $configName) {
+ $driver = null;
+ $db =& ConnectionManager::getDataSource($configName);
+ if (
+ (empty($db->config['driver']) && empty($db->config['datasource'])) ||
+ !$db->isInterfaceSupported('getLog')
+ ) {
+ continue;
+ }
+
+ if (isset($db->config['driver'])) {
+ $driver = $db->config['driver'];
+ }
+ if (empty($driver) && isset($db->config['datasource'])) {
+ $driver = $db->config['datasource'];
+ }
+ $explain = false;
+ $isExplainable = ($driver === 'mysql' || $driver === 'mysqli' || $driver === 'postgres');
+ if ($isExplainable) {
+ $explain = true;
+ }
+ $connections[$configName] = $explain;
+ }
+ return array('connections' => $connections, 'threshold' => $this->slowRate);
+ }
+}
+
+/**
+ * Log Panel - Reads log entries made this request.
+ *
+ * @package cake.debug_kit.panels
+ */
+class LogPanel extends DebugPanel {
+
+ var $plugin = 'debug_kit';
+
+/**
+ * Constructor - sets up the log listener.
+ *
+ * @return void
+ */
+ function __construct($settings) {
+ parent::__construct();
+ if (!class_exists('CakeLog')) {
+ App::import('Core', 'CakeLog');
+ }
+ $existing = CakeLog::configured();
+ if (empty($existing)) {
+ CakeLog::config('default', array(
+ 'engine' => 'FileLog'
+ ));
+ }
+ CakeLog::config('debug_kit_log_panel', array(
+ 'engine' => 'DebugKitLogListener',
+ 'panel' => $this
+ ));
+ }
+
+/**
+ * beforeRender Callback
+ *
+ * @return array
+ **/
+ function beforeRender(&$controller) {
+ $logs = $this->logger->logs;
+ return $logs;
+ }
+}
+
+/**
+ * A CakeLog listener which saves having to munge files or other configured loggers.
+ *
+ * @package debug_kit.components
+ */
+class DebugKitLogListener {
+
+ var $logs = array();
+
+/**
+ * Makes the reverse link needed to get the logs later.
+ *
+ * @return void
+ */
+ function DebugKitLogListener($options) {
+ $options['panel']->logger =& $this;
+ }
+
+/**
+ * Captures log messages in memory
+ *
+ * @return void
+ */
+ function write($type, $message) {
+ if (!isset($this->logs[$type])) {
+ $this->logs[$type] = array();
+ }
+ $this->logs[$type][] = array(date('Y-m-d H:i:s'), $message);
+ }
+}
+
diff --git a/code/ryzom/tools/server/www/webtt/plugins/debug_kit/controllers/toolbar_access_controller.php b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/controllers/toolbar_access_controller.php
new file mode 100644
index 000000000..5e6afdf31
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/controllers/toolbar_access_controller.php
@@ -0,0 +1,111 @@
+ array('output' => 'DebugKit.HtmlToolbar'),
+ 'Javascript', 'Number', 'DebugKit.SimpleGraph'
+ );
+
+/**
+ * Components
+ *
+ * @var array
+ **/
+ var $components = array('RequestHandler', 'DebugKit.Toolbar');
+
+/**
+ * Uses
+ *
+ * @var array
+ **/
+ var $uses = array('DebugKit.ToolbarAccess');
+
+/**
+ * beforeFilter callback
+ *
+ * @return void
+ **/
+ function beforeFilter() {
+ parent::beforeFilter();
+ if (isset($this->Toolbar)) {
+ $this->Toolbar->enabled = false;
+ }
+ $this->helpers['DebugKit.Toolbar']['cacheKey'] = $this->Toolbar->cacheKey;
+ $this->helpers['DebugKit.Toolbar']['cacheConfig'] = 'debug_kit';
+ }
+
+/**
+ * Get a stored history state from the toolbar cache.
+ *
+ * @return void
+ **/
+ function history_state($key = null) {
+ if (Configure::read('debug') == 0) {
+ return $this->redirect($this->referer());
+ }
+ $oldState = $this->Toolbar->loadState($key);
+ $this->set('toolbarState', $oldState);
+ $this->set('debugKitInHistoryMode', true);
+ }
+
+/**
+ * Run SQL explain/profiling on queries. Checks the hash + the hashed queries,
+ * if there is mismatch a 404 will be rendered. If debug == 0 a 404 will also be
+ * rendered. No explain will be run if a 404 is made.
+ *
+ * @return void
+ */
+ function sql_explain() {
+ if (
+ !$this->RequestHandler->isPost() ||
+ empty($this->data['log']['sql']) ||
+ empty($this->data['log']['ds']) ||
+ empty($this->data['log']['hash']) ||
+ Configure::read('debug') == 0
+ ) {
+ $this->cakeError('error404', array(array(
+ 'message' => 'Invalid parameters'
+ )));
+ }
+ App::import('Core', 'Security');
+ $hash = Security::hash($this->data['log']['sql'] . $this->data['log']['ds'], null, true);
+ if ($hash !== $this->data['log']['hash']) {
+ $this->cakeError('error404', array(array(
+ 'message' => 'Invalid parameters'
+ )));
+ }
+ $result = $this->ToolbarAccess->explainQuery($this->data['log']['ds'], $this->data['log']['sql']);
+ $this->set(compact('result'));
+ }
+}
\ No newline at end of file
diff --git a/code/ryzom/tools/server/www/webtt/plugins/debug_kit/debug_kit_app_controller.php b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/debug_kit_app_controller.php
new file mode 100644
index 000000000..3592cb5ed
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/debug_kit_app_controller.php
@@ -0,0 +1,22 @@
+
+# No version information was available in the source files.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: debug_kit-\n"
+"POT-Creation-Date: 2009-05-27 09:47+0200\n"
+"PO-Revision-Date: YYYY-mm-DD HH:MM+ZZZZ\n"
+"Last-Translator: Andy Dawson
\n"
+"Language-Team:\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Poedit-Basepath: ../../../\n"
+
+#: controllers/components/toolbar.php:91
+msgid "Component initialization and startup"
+msgstr ""
+
+#: controllers/components/toolbar.php:140
+msgid "Controller Action"
+msgstr ""
+
+#: controllers/components/toolbar.php:167
+msgid "Render Controller Action"
+msgstr ""
+
+#: controllers/components/toolbar.php:231
+msgid "Could not load DebugToolbar panel %s"
+msgstr ""
+
+#: views/elements/debug_toolbar.ctp:25
+msgid "There are no active panels. You must enable a panel to see its output."
+msgstr ""
+
+#: views/elements/history_panel.ctp:21
+msgid "Request History"
+msgstr ""
+
+#: views/elements/history_panel.ctp:23
+msgid "No previous requests logged."
+msgstr ""
+
+#: views/elements/history_panel.ctp:25
+msgid "previous requests available"
+msgstr ""
+
+#: views/elements/history_panel.ctp:27
+msgid "Restore to current request"
+msgstr ""
+
+#: views/elements/log_panel.ctp:21
+msgid "Logs"
+msgstr ""
+
+#: views/elements/log_panel.ctp:28
+msgid "Time"
+msgstr ""
+
+#: views/elements/log_panel.ctp:28
+#: views/elements/timer_panel.ctp:54
+msgid "Message"
+msgstr ""
+
+#: views/elements/log_panel.ctp:37
+msgid "There were no log entries made this request"
+msgstr ""
+
+#: views/elements/request_panel.ctp:21
+msgid "Request"
+msgstr ""
+
+#: views/elements/request_panel.ctp:35
+msgid "Current Route"
+msgstr ""
+
+#: views/elements/session_panel.ctp:21
+msgid "Session"
+msgstr ""
+
+#: views/elements/sql_log_panel.ctp:21
+msgid "Sql Logs"
+msgstr ""
+
+#: views/elements/sql_log_panel.ctp:31
+msgid "toggle (%s) query explains for %s"
+msgstr ""
+
+#: views/elements/sql_log_panel.ctp:39
+msgid "No slow queries!, or your database does not support EXPLAIN"
+msgstr ""
+
+#: views/elements/sql_log_panel.ctp:44
+msgid "No active database connections"
+msgstr ""
+
+#: views/elements/timer_panel.ctp:33
+msgid "Memory"
+msgstr ""
+
+#: views/elements/timer_panel.ctp:35
+msgid "Current Memory Use"
+msgstr ""
+
+#: views/elements/timer_panel.ctp:39
+msgid "Peak Memory Use"
+msgstr ""
+
+#: views/elements/timer_panel.ctp:43
+msgid "Timers"
+msgstr ""
+
+#: views/elements/timer_panel.ctp:45
+msgid "%s (ms)"
+msgstr ""
+
+#: views/elements/timer_panel.ctp:46
+msgid "Total Request Time:"
+msgstr ""
+
+#: views/elements/timer_panel.ctp:54
+msgid "Time in ms"
+msgstr ""
+
+#: views/elements/timer_panel.ctp:54
+msgid "Graph"
+msgstr ""
+
+#: views/elements/variables_panel.ctp:21
+msgid "View Variables"
+msgstr ""
+
+#: views/helpers/simple_graph.php:79
+msgid "Starting %sms into the request, taking %sms"
+msgstr ""
+
diff --git a/code/ryzom/tools/server/www/webtt/plugins/debug_kit/locale/eng/LC_MESSAGES/debug_kit.po b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/locale/eng/LC_MESSAGES/debug_kit.po
new file mode 100644
index 000000000..9aec83297
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/locale/eng/LC_MESSAGES/debug_kit.po
@@ -0,0 +1,135 @@
+# LANGUAGE translation of CakePHP Application
+# Copyright YEAR NAME
+# No version information was available in the source files.
+#
+#, fuzzy
+msgid ""
+msgstr "Project-Id-Version: PROJECT VERSION\n"
+ "POT-Creation-Date: 2009-05-27 09:47+0200\n"
+ "PO-Revision-Date: YYYY-mm-DD HH:MM+ZZZZ\n"
+ "Last-Translator: NAME \n"
+ "Language-Team: LANGUAGE \n"
+ "MIME-Version: 1.0\n"
+ "Content-Type: text/plain; charset=UTF-8\n"
+ "Content-Transfer-Encoding: 8bit\n"
+ "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"
+
+#: controllers/components/toolbar.php:91
+msgid "Component initialization and startup"
+msgstr ""
+
+#: controllers/components/toolbar.php:140
+msgid "Controller Action"
+msgstr ""
+
+#: controllers/components/toolbar.php:167
+msgid "Render Controller Action"
+msgstr ""
+
+#: controllers/components/toolbar.php:231
+msgid "Could not load DebugToolbar panel %s"
+msgstr ""
+
+#: views/elements/debug_toolbar.ctp:25
+msgid "There are no active panels. You must enable a panel to see its output."
+msgstr ""
+
+#: views/elements/history_panel.ctp:21
+msgid "Request History"
+msgstr ""
+
+#: views/elements/history_panel.ctp:23
+msgid "No previous requests logged."
+msgstr ""
+
+#: views/elements/history_panel.ctp:25
+msgid "previous requests available"
+msgstr ""
+
+#: views/elements/history_panel.ctp:27
+msgid "Restore to current request"
+msgstr ""
+
+#: views/elements/log_panel.ctp:21
+msgid "Logs"
+msgstr ""
+
+#: views/elements/log_panel.ctp:28
+msgid "Time"
+msgstr ""
+
+#: views/elements/log_panel.ctp:28 views/elements/timer_panel.ctp:54
+msgid "Message"
+msgstr ""
+
+#: views/elements/log_panel.ctp:37
+msgid "There were no log entries made this request"
+msgstr ""
+
+#: views/elements/request_panel.ctp:21
+msgid "Request"
+msgstr ""
+
+#: views/elements/request_panel.ctp:35
+msgid "Current Route"
+msgstr ""
+
+#: views/elements/session_panel.ctp:21
+msgid "Session"
+msgstr ""
+
+#: views/elements/sql_log_panel.ctp:21
+msgid "Sql Logs"
+msgstr ""
+
+#: views/elements/sql_log_panel.ctp:31
+msgid "toggle (%s) query explains for %s"
+msgstr ""
+
+#: views/elements/sql_log_panel.ctp:39
+msgid "No slow queries!, or your database does not support EXPLAIN"
+msgstr ""
+
+#: views/elements/sql_log_panel.ctp:44
+msgid "No active database connections"
+msgstr ""
+
+#: views/elements/timer_panel.ctp:33
+msgid "Memory"
+msgstr ""
+
+#: views/elements/timer_panel.ctp:35
+msgid "Current Memory Use"
+msgstr ""
+
+#: views/elements/timer_panel.ctp:39
+msgid "Peak Memory Use"
+msgstr ""
+
+#: views/elements/timer_panel.ctp:43
+msgid "Timers"
+msgstr ""
+
+#: views/elements/timer_panel.ctp:45
+msgid "%s (ms)"
+msgstr ""
+
+#: views/elements/timer_panel.ctp:46
+msgid "Total Request Time:"
+msgstr ""
+
+#: views/elements/timer_panel.ctp:54
+msgid "Time in ms"
+msgstr ""
+
+#: views/elements/timer_panel.ctp:54
+msgid "Graph"
+msgstr ""
+
+#: views/elements/variables_panel.ctp:21
+msgid "View Variables"
+msgstr ""
+
+#: views/helpers/simple_graph.php:79
+msgid "Starting %sms into the request, taking %sms"
+msgstr ""
diff --git a/code/ryzom/tools/server/www/webtt/plugins/debug_kit/locale/spa/LC_MESSAGES/debug_kit.po b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/locale/spa/LC_MESSAGES/debug_kit.po
new file mode 100644
index 000000000..0833a4942
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/locale/spa/LC_MESSAGES/debug_kit.po
@@ -0,0 +1,135 @@
+# LANGUAGE translation of CakePHP Application
+# Copyright YEAR NAME
+# No version information was available in the source files.
+#
+#, fuzzy
+msgid ""
+msgstr "Project-Id-Version: PROJECT VERSION\n"
+ "POT-Creation-Date: 2009-05-27 09:47+0200\n"
+ "PO-Revision-Date: YYYY-mm-DD HH:MM+ZZZZ\n"
+ "Last-Translator: NAME \n"
+ "Language-Team: LANGUAGE \n"
+ "MIME-Version: 1.0\n"
+ "Content-Type: text/plain; charset=UTF-8\n"
+ "Content-Transfer-Encoding: 8bit\n"
+ "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"
+
+#: controllers/components/toolbar.php:91
+msgid "Component initialization and startup"
+msgstr ""
+
+#: controllers/components/toolbar.php:140
+msgid "Controller Action"
+msgstr ""
+
+#: controllers/components/toolbar.php:167
+msgid "Render Controller Action"
+msgstr ""
+
+#: controllers/components/toolbar.php:231
+msgid "Could not load DebugToolbar panel %s"
+msgstr ""
+
+#: views/elements/debug_toolbar.ctp:25
+msgid "There are no active panels. You must enable a panel to see its output."
+msgstr ""
+
+#: views/elements/history_panel.ctp:21
+msgid "Request History"
+msgstr ""
+
+#: views/elements/history_panel.ctp:23
+msgid "No previous requests logged."
+msgstr ""
+
+#: views/elements/history_panel.ctp:25
+msgid "previous requests available"
+msgstr ""
+
+#: views/elements/history_panel.ctp:27
+msgid "Restore to current request"
+msgstr ""
+
+#: views/elements/log_panel.ctp:21
+msgid "Logs"
+msgstr ""
+
+#: views/elements/log_panel.ctp:28
+msgid "Time"
+msgstr ""
+
+#: views/elements/log_panel.ctp:28 views/elements/timer_panel.ctp:54
+msgid "Message"
+msgstr ""
+
+#: views/elements/log_panel.ctp:37
+msgid "There were no log entries made this request"
+msgstr ""
+
+#: views/elements/request_panel.ctp:21
+msgid "Request"
+msgstr ""
+
+#: views/elements/request_panel.ctp:35
+msgid "Current Route"
+msgstr ""
+
+#: views/elements/session_panel.ctp:21
+msgid "Session"
+msgstr ""
+
+#: views/elements/sql_log_panel.ctp:21
+msgid "Sql Logs"
+msgstr ""
+
+#: views/elements/sql_log_panel.ctp:31
+msgid "toggle (%s) query explains for %s"
+msgstr ""
+
+#: views/elements/sql_log_panel.ctp:39
+msgid "No slow queries!, or your database does not support EXPLAIN"
+msgstr ""
+
+#: views/elements/sql_log_panel.ctp:44
+msgid "No active database connections"
+msgstr ""
+
+#: views/elements/timer_panel.ctp:33
+msgid "Memory"
+msgstr ""
+
+#: views/elements/timer_panel.ctp:35
+msgid "Current Memory Use"
+msgstr ""
+
+#: views/elements/timer_panel.ctp:39
+msgid "Peak Memory Use"
+msgstr ""
+
+#: views/elements/timer_panel.ctp:43
+msgid "Timers"
+msgstr ""
+
+#: views/elements/timer_panel.ctp:45
+msgid "%s (ms)"
+msgstr ""
+
+#: views/elements/timer_panel.ctp:46
+msgid "Total Request Time:"
+msgstr ""
+
+#: views/elements/timer_panel.ctp:54
+msgid "Time in ms"
+msgstr ""
+
+#: views/elements/timer_panel.ctp:54
+msgid "Graph"
+msgstr ""
+
+#: views/elements/variables_panel.ctp:21
+msgid "View Variables"
+msgstr ""
+
+#: views/helpers/simple_graph.php:79
+msgid "Starting %sms into the request, taking %sms"
+msgstr ""
\ No newline at end of file
diff --git a/code/ryzom/tools/server/www/webtt/plugins/debug_kit/models/behaviors/timed.php b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/models/behaviors/timed.php
new file mode 100644
index 000000000..28eadec74
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/models/behaviors/timed.php
@@ -0,0 +1,105 @@
+settings[$Model->alias] = array_merge($this->_defaults, $settings);
+ } else {
+ $this->settings[$Model->alias] = $this->_defaults;
+ }
+ }
+
+/**
+ * beforeFind, starts a timer for a find operation.
+ *
+ * @param Model $Model
+ * @param array $queryData Array of query data (not modified)
+ * @return boolean true
+ */
+ function beforeFind(&$Model, $queryData){
+ DebugKitDebugger::startTimer($Model->alias . '_find', $Model->alias . '->find()');
+ return true;
+ }
+
+/**
+ * afterFind, stops a timer for a find operation.
+ *
+ * @param Model $Model
+ * @param array $results Array of results
+ * @return boolean true.
+ */
+ function afterFind(&$Model, $results){
+ DebugKitDebugger::stopTimer($Model->alias . '_find');
+ return true;
+ }
+
+/**
+ * beforeSave, starts a time before a save is initiated.
+ *
+ * @param Model $Model
+ * @return boolean true
+ */
+ function beforeSave(&$Model){
+ DebugKitDebugger::startTimer($Model->alias . '_save', $Model->alias . '->save()');
+ return true;
+ }
+
+/**
+ * afterSave, stop the timer started from a save.
+ *
+ * @param string $Model
+ * @param string $created
+ * @return void
+ */
+ function afterSave(&$Model, $created) {
+ DebugKitDebugger::stopTimer($Model->alias . '_save');
+ return true;
+ }
+ }
+
diff --git a/code/ryzom/tools/server/www/webtt/plugins/debug_kit/models/toolbar_access.php b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/models/toolbar_access.php
new file mode 100644
index 000000000..ab1fea99b
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/models/toolbar_access.php
@@ -0,0 +1,56 @@
+config['driver'];
+
+ $return = array();
+ if ($driver === 'mysqli' || $driver === 'mysql' || $driver === 'postgres') {
+ $explained = $db->query('EXPLAIN ' . $query);
+ if ($driver === 'postgres') {
+ $queryPlan = array();
+ foreach ($explained as $postgreValue) {
+ $queryPlan[] = array($postgreValue[0]['QUERY PLAN']);
+ }
+ $return = array_merge(array(array('')), $queryPlan);
+ } else {
+ $keys = array_keys($explained[0][0]);
+ foreach ($explained as $mysqlValue) {
+ $queryPlan[] = array_values($mysqlValue[0]);
+ }
+ $return = array_merge(array($keys), $queryPlan);
+ }
+ }
+ return $return;
+ }
+}
\ No newline at end of file
diff --git a/code/ryzom/tools/server/www/webtt/plugins/debug_kit/tests/cases/behaviors/timed.test.php b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/tests/cases/behaviors/timed.test.php
new file mode 100644
index 000000000..3fbbd614b
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/tests/cases/behaviors/timed.test.php
@@ -0,0 +1,77 @@
+Article =& new Model(array('ds' => 'test_suite', 'table' => 'articles', 'name' => 'Article'));
+ $this->Article->Behaviors->attach('DebugKit.Timed');
+ }
+
+/**
+ * end a test
+ *
+ * @return void
+ */
+ function endTest() {
+ unset($this->Article);
+ ClassRegistry::flush();
+ DebugKitDebugger::clearTimers();
+ }
+
+/**
+ * test find timers
+ *
+ * @return void
+ */
+ function testFindTimers() {
+ $timers = DebugKitDebugger::getTimers(false);
+ $this->assertEqual(count($timers), 1);
+
+ $this->Article->find('all');
+ $result = DebugKitDebugger::getTimers(false);
+ $this->assertEqual(count($result), 2);
+
+ $this->Article->find('all');
+ $result = DebugKitDebugger::getTimers(false);
+ $this->assertEqual(count($result), 3);
+ }
+
+/**
+ * test save timers
+ *
+ * @return void
+ */
+ function testSaveTimers() {
+ $timers = DebugKitDebugger::getTimers(false);
+ $this->assertEqual(count($timers), 1);
+
+ $this->Article->save(array('user_id' => 1, 'title' => 'test', 'body' => 'test'));
+ $result = DebugKitDebugger::getTimers(false);
+ $this->assertEqual(count($result), 2);
+ }
+}
\ No newline at end of file
diff --git a/code/ryzom/tools/server/www/webtt/plugins/debug_kit/tests/cases/controllers/components/toolbar.test.php b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/tests/cases/controllers/components/toolbar.test.php
new file mode 100644
index 000000000..05f464ed6
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/tests/cases/controllers/components/toolbar.test.php
@@ -0,0 +1,580 @@
+_loadPanels($panels, $settings);
+ }
+
+ function _eval($code) {
+ if ($this->evalTest) {
+ $this->evalCode = $code;
+ return;
+ }
+ eval($code);
+ }
+}
+
+Mock::generate('DebugPanel');
+
+if (!class_exists('AppController')) {
+ class AppController extends Controller {
+
+ }
+}
+
+class TestPanel extends DebugPanel {
+
+}
+
+/**
+* DebugToolbar Test case
+*/
+class DebugToolbarTestCase extends CakeTestCase {
+/**
+ * fixtures.
+ *
+ * @var array
+ **/
+ var $fixtures = array('core.article');
+/**
+ * Start test callback
+ *
+ * @access public
+ * @return void
+ **/
+ function startTest() {
+ Router::connect('/', array('controller' => 'pages', 'action' => 'display', 'home'));
+ $this->Controller =& new Controller();
+ $this->Controller->params = Router::parse('/');
+ $this->Controller->params['url']['url'] = '/';
+ $this->Controller->uses = array();
+ $this->Controller->components = array('TestToolBar');
+ $this->Controller->constructClasses();
+ $this->Controller->Toolbar =& $this->Controller->TestToolBar;
+
+ $this->_server = $_SERVER;
+ $this->_paths = array();
+ $this->_paths['plugins'] = App::path('plugins');
+ $this->_paths['views'] = App::path('views');
+ $this->_paths['vendors'] = App::path('vendors');
+ $this->_paths['controllers'] = App::path('controllers');
+ Configure::write('Cache.disable', false);
+ }
+/**
+ * endTest
+ *
+ * @return void
+ **/
+ function endTest() {
+ $_SERVER = $this->_server;
+ App::build(array(
+ 'plugins' => $this->_paths['plugins'],
+ 'views' => $this->_paths['views'],
+ 'controllers' => $this->_paths['controllers'],
+ 'vendors' => $this->_paths['vendors']
+ ), true);
+ Configure::write('Cache.disable', true);
+
+ unset($this->Controller);
+ if (class_exists('DebugKitDebugger')) {
+ DebugKitDebugger::clearTimers();
+ DebugKitDebugger::clearMemoryPoints();
+ }
+ }
+/**
+ * test Loading of panel classes
+ *
+ * @return void
+ **/
+ function testLoadPanels() {
+ $this->Controller->Toolbar->loadPanels(array('session', 'request'));
+ $this->assertTrue(is_a($this->Controller->Toolbar->panels['session'], 'SessionPanel'));
+ $this->assertTrue(is_a($this->Controller->Toolbar->panels['request'], 'RequestPanel'));
+
+ $this->Controller->Toolbar->loadPanels(array('history'), array('history' => 10));
+ $this->assertEqual($this->Controller->Toolbar->panels['history']->history, 10);
+
+ $this->expectError();
+ $this->Controller->Toolbar->loadPanels(array('randomNonExisting', 'request'));
+ }
+/**
+ * test Loading of panel classes from a plugin
+ *
+ * @return void
+ **/
+ function testLoadPluginPanels() {
+ $this->Controller->Toolbar->loadPanels(array('plugin.test'));
+ $this->assertTrue(is_a($this->Controller->Toolbar->panels['test'], 'TestPanel'));
+ }
+/**
+ * test generating a DoppelGangerView with a pluginView.
+ *
+ * If $this->Controller->Toolbar->startup() has been previously called,
+ * DoppelGangerView class has already been defined.
+ *
+ * @return void
+ **/
+ function testPluginViewParsing() {
+ if (class_exists('DoppelGangerView')) {
+ $this->skipIf(true, 'Class DoppelGangerView already defined, skipping %s');
+ return;
+ }
+ App::import('Vendor', 'DebugKit.DebugKitDebugger');
+ $this->Controller->Toolbar->evalTest = true;
+ $this->Controller->view = 'Plugin.OtherView';
+ $this->Controller->Toolbar->startup($this->Controller);
+ $this->assertPattern('/class DoppelGangerView extends OtherView/', $this->Controller->Toolbar->evalCode);
+ }
+/**
+ * test loading of vendor panels from test_app folder
+ *
+ * @access public
+ * @return void
+ */
+ function testVendorPanels() {
+ $debugKitPath = App::pluginPath('DebugKit');
+ $noDir = (empty($debugKitPath) || !file_exists($debugKitPath));
+ $skip = $this->skipIf($noDir, 'Could not find debug_kit in plugin paths, skipping %s');
+ if ($skip) {
+ return;
+ }
+
+ App::build(array(
+ 'vendors' => array($debugKitPath . 'tests' . DS . 'test_app' . DS . 'vendors' . DS)
+ ));
+ $this->Controller->components = array(
+ 'DebugKit.Toolbar' => array(
+ 'panels' => array('test'),
+ )
+ );
+ $this->Controller->Component->init($this->Controller);
+ $this->Controller->Component->initialize($this->Controller);
+ $this->Controller->Component->startup($this->Controller);
+ $this->assertTrue(isset($this->Controller->Toolbar->panels['test']));
+ $this->assertTrue(is_a($this->Controller->Toolbar->panels['test'], 'TestPanel'));
+ }
+/**
+ * test initialize
+ *
+ * @return void
+ * @access public
+ **/
+ function testInitialize() {
+ $this->Controller->components = array('DebugKit.Toolbar');
+ $this->Controller->Component->init($this->Controller);
+ $this->Controller->Component->initialize($this->Controller);
+
+ $this->assertFalse(empty($this->Controller->Toolbar->panels));
+
+ $timers = DebugKitDebugger::getTimers();
+ $this->assertTrue(isset($timers['componentInit']));
+ $memory = DebugKitDebugger::getMemoryPoints();
+ $this->assertTrue(isset($memory['Component initialization']));
+ }
+/**
+ * test initialize w/ custom panels and defaults
+ *
+ * @return void
+ * @access public
+ **/
+ function testInitializeCustomPanelsWithDefaults() {
+ $this->Controller->components = array(
+ 'DebugKit.Toolbar' => array('panels' => array('test'))
+ );
+ $this->Controller->Component->init($this->Controller);
+ $this->Controller->Component->initialize($this->Controller);
+
+ $expected = array('history', 'session', 'request', 'sqlLog', 'timer', 'log', 'variables', 'test');
+ $this->assertEqual($expected, array_keys($this->Controller->Toolbar->panels));
+ }
+
+/**
+ * test syntax for removing panels
+ *
+ * @return void
+ **/
+ function testInitializeRemovingPanels() {
+ unset($this->Controller->Toolbar);
+ $this->Controller->components = array(
+ 'DebugKit.Toolbar' => array('panels' => array('session' => false, 'history' => false, 'test'))
+ );
+ $this->Controller->Component->init($this->Controller);
+ $this->Controller->Component->initialize($this->Controller);
+
+ $expected = array('request', 'sqlLog', 'timer', 'log', 'variables', 'test');
+ $this->assertEqual($expected, array_keys($this->Controller->Toolbar->panels));
+ }
+/**
+ * ensure that enabled = false when debug == 0 on initialize
+ *
+ * @return void
+ **/
+ function testDebugDisableOnInitialize() {
+ $_debug = Configure::read('debug');
+ Configure::write('debug', 0);
+ $this->Controller->components = array('DebugKit.Toolbar');
+ $this->Controller->Component->init($this->Controller);
+ $this->Controller->Component->initialize($this->Controller);
+ $this->assertFalse($this->Controller->Toolbar->enabled);
+
+ Configure::write('debug', $_debug);
+ }
+/**
+ * test that passing in forceEnable will enable the toolbar even if debug = 0
+ *
+ * @return void
+ **/
+ function testForceEnable() {
+ unset($this->Controller->Toolbar);
+ $_debug = Configure::read('debug');
+ Configure::write('debug', 0);
+ $this->Controller->components = array('DebugKit.Toolbar' => array('forceEnable' => true));
+ $this->Controller->Component->init($this->Controller);
+ $this->Controller->Component->initialize($this->Controller);
+ $this->assertTrue($this->Controller->Toolbar->enabled);
+
+ Configure::write('debug', $_debug);
+ }
+/**
+ * Test disabling autoRunning of toolbar
+ *
+ * @return void
+ **/
+ function testAutoRunSettingFalse() {
+ $this->Controller->components = array('DebugKit.Toolbar' => array('autoRun' => false));
+ $this->Controller->Component->init($this->Controller);
+ $this->Controller->Component->initialize($this->Controller);
+ $this->assertFalse($this->Controller->Toolbar->enabled);
+ }
+/**
+ * test autorun = false with query string param
+ *
+ * @return void
+ **/
+ function testAutoRunSettingWithQueryString() {
+ $this->Controller->params['url']['debug'] = true;
+ $this->Controller->components = array('DebugKit.Toolbar' => array('autoRun' => false));
+ $this->Controller->Component->init($this->Controller);
+ $this->Controller->Component->initialize($this->Controller);
+ $this->assertTrue($this->Controller->Toolbar->enabled);
+ }
+/**
+ * test startup
+ *
+ * @return void
+ **/
+ function testStartup() {
+ $this->Controller->components = array(
+ 'DebugKit.Toolbar' => array(
+ 'panels' => array('MockDebug')
+ )
+ );
+ $this->Controller->Component->init($this->Controller);
+ $this->Controller->Component->initialize($this->Controller);
+ $this->Controller->Toolbar->panels['MockDebug']->expectOnce('startup');
+ $this->Controller->Toolbar->startup($this->Controller);
+
+ $this->assertEqual($this->Controller->view, 'DebugKit.Debug');
+ $this->assertTrue(isset($this->Controller->helpers['DebugKit.Toolbar']));
+
+ $this->assertEqual($this->Controller->helpers['DebugKit.Toolbar']['output'], 'DebugKit.HtmlToolbar');
+ $this->assertEqual($this->Controller->helpers['DebugKit.Toolbar']['cacheConfig'], 'debug_kit');
+ $this->assertTrue(isset($this->Controller->helpers['DebugKit.Toolbar']['cacheKey']));
+
+ $timers = DebugKitDebugger::getTimers();
+ $this->assertTrue(isset($timers['controllerAction']));
+ $memory = DebugKitDebugger::getMemoryPoints();
+ $this->assertTrue(isset($memory['Controller action start']));
+ }
+/**
+ * Test that cache config generation works.
+ *
+ * @return void
+ **/
+ function testCacheConfigGeneration() {
+ $this->Controller->components = array('DebugKit.Toolbar');
+ $this->Controller->Component->init($this->Controller);
+ $this->Controller->Component->initialize($this->Controller);
+ $this->Controller->Component->startup($this->Controller);
+
+ $results = Cache::config('debug_kit');
+ $this->assertTrue(is_array($results));
+ }
+/**
+ * test state saving of toolbar
+ *
+ * @return void
+ **/
+ function testStateSaving() {
+ $this->Controller->components = array('DebugKit.Toolbar');
+ $this->Controller->Component->init($this->Controller);
+ $this->Controller->Component->initialize($this->Controller);
+ $configName = 'debug_kit';
+ $this->Controller->Toolbar->cacheKey = 'toolbar_history';
+
+ $this->Controller->Component->startup($this->Controller);
+ $this->Controller->set('test', 'testing');
+ $this->Controller->Component->beforeRender($this->Controller);
+
+ $result = Cache::read('toolbar_history', $configName);
+ $this->assertEqual($result[0]['variables']['content']['test'], 'testing');
+ Cache::delete('toolbar_history', $configName);
+ }
+/**
+ * Test Before Render callback
+ *
+ * @return void
+ **/
+ function testBeforeRender() {
+ $this->Controller->components = array(
+ 'DebugKit.Toolbar' => array(
+ 'panels' => array('MockDebug', 'session')
+ )
+ );
+ $this->Controller->Component->init($this->Controller);
+ $this->Controller->Component->initialize($this->Controller);
+ $this->Controller->Toolbar->panels['MockDebug']->expectOnce('beforeRender');
+ $this->Controller->Toolbar->beforeRender($this->Controller);
+
+ $this->assertTrue(isset($this->Controller->viewVars['debugToolbarPanels']));
+ $vars = $this->Controller->viewVars['debugToolbarPanels'];
+
+ $expected = array(
+ 'plugin' => 'debug_kit',
+ 'elementName' => 'session_panel',
+ 'content' => $this->Controller->Toolbar->Session->read(),
+ 'disableTimer' => true,
+ 'title' => ''
+ );
+ $this->assertEqual($expected, $vars['session']);
+
+ $memory = DebugKitDebugger::getMemoryPoints();
+ $this->assertTrue(isset($memory['Controller render start']));
+ }
+/**
+ * test that vars are gathered and state is saved on beforeRedirect
+ *
+ * @return void
+ **/
+ function testBeforeRedirect() {
+ $this->Controller->components = array(
+ 'DebugKit.Toolbar' => array(
+ 'panels' => array('MockDebug', 'session', 'history')
+ )
+ );
+ $this->Controller->Component->init($this->Controller);
+ $this->Controller->Component->initialize($this->Controller);
+
+ $configName = 'debug_kit';
+ $this->Controller->Toolbar->cacheKey = 'toolbar_history';
+ Cache::delete('toolbar_history', $configName);
+
+ DebugKitDebugger::startTimer('controllerAction', 'testing beforeRedirect');
+ $this->Controller->Toolbar->panels['MockDebug']->expectOnce('beforeRender');
+ $this->Controller->Toolbar->beforeRedirect($this->Controller);
+
+ $result = Cache::read('toolbar_history', $configName);
+ $this->assertTrue(isset($result[0]['session']));
+ $this->assertTrue(isset($result[0]['mock_debug']));
+
+ $timers = DebugKitDebugger::getTimers();
+ $this->assertTrue(isset($timers['controllerAction']));
+ }
+/**
+ * test that loading state (accessing cache) works.
+ *
+ * @return void
+ **/
+ function testLoadState() {
+ $this->Controller->Toolbar->cacheKey = 'toolbar_history';
+
+ $data = array(0 => array('my data'));
+ Cache::write('toolbar_history', $data, 'debug_kit');
+ $result = $this->Controller->Toolbar->loadState(0);
+ $this->assertEqual($result, $data[0]);
+ }
+/**
+ * test the Log panel log reading.
+ *
+ * @return void
+ **/
+ function testLogPanel() {
+ $this->Controller->components = array(
+ 'DebugKit.Toolbar' => array(
+ 'panels' => array('log', 'session', 'history' => false, 'variables' => false, 'sqlLog' => false,
+ 'timer' => false)
+ )
+ );
+ $this->Controller->Component->init($this->Controller);
+ $this->Controller->Component->initialize($this->Controller);
+
+ sleep(1);
+ $this->Controller->log('This is a log I made this request');
+ $this->Controller->log('This is the second log I made this request');
+ $this->Controller->log('This time in the debug log!', LOG_DEBUG);
+
+ $this->Controller->Component->startup($this->Controller);
+ $this->Controller->Component->beforeRender($this->Controller);
+ $result = $this->Controller->viewVars['debugToolbarPanels']['log'];
+
+ $this->assertEqual(count($result['content']), 2);
+ $this->assertEqual(count($result['content']['error']), 2);
+ $this->assertEqual(count($result['content']['debug']), 1);
+
+ $this->assertEqual(trim($result['content']['debug'][0][1]), 'This time in the debug log!');
+ $this->assertEqual(trim($result['content']['error'][0][1]), 'This is a log I made this request');
+
+ $data = array(
+ 'Post' => array(
+ 'id' => 1,
+ 'title' => 'post!',
+ 'body' => 'some text here',
+ 'created' => '2009-11-07 23:23:23'
+ ),
+ 'Comment' => array(
+ 'id' => 23
+ )
+ );
+ $this->Controller->log($data);
+ $this->Controller->Component->beforeRender($this->Controller);
+ $result = $this->Controller->viewVars['debugToolbarPanels']['log'];
+ $this->assertPattern('/\[created\] => 2009-11-07 23:23:23/', $result['content']['error'][2][1]);
+ $this->assertPattern('/\[Comment\] => Array/', $result['content']['error'][2][1]);
+ }
+
+/**
+ * test that creating the log panel creates the default file logger if none
+ * are configured. This stops DebugKit from mucking with the default auto-magic log config
+ *
+ * @return void
+ */
+ function testLogPanelConstructCreatingDefaultLogConfiguration() {
+ CakeLog::drop('default');
+ CakeLog::drop('debug_kit_log_panel');
+
+ $panel =& new LogPanel(array());
+ $configured = CakeLog::configured();
+
+ $this->assertTrue(in_array('default', $configured));
+ $this->assertTrue(in_array('debug_kit_log_panel', $configured));
+ }
+
+/**
+ * Test that history state urls set prefix = null and admin = null so generated urls do not
+ * adopt these params.
+ *
+ * @return void
+ **/
+ function testHistoryUrlGenerationWithPrefixes() {
+ $configName = 'debug_kit';
+ $this->Controller->params = array(
+ 'controller' => 'posts',
+ 'action' => 'edit',
+ 'admin' => 1,
+ 'prefix' => 'admin',
+ 'plugin' => 'cms',
+ 'url' => array(
+ 'url' => '/admin/cms/posts/edit/'
+ )
+ );
+ $this->Controller->Component->initialize($this->Controller);
+ $this->Controller->Toolbar->cacheKey = 'url_test';
+ $this->Controller->Component->beforeRender($this->Controller);
+
+ $result = $this->Controller->Toolbar->panels['history']->beforeRender($this->Controller);
+ $expected = array(
+ 'plugin' => 'debug_kit', 'controller' => 'toolbar_access', 'action' => 'history_state',
+ 0 => 1, 'admin' => false
+ );
+ $this->assertEqual($result[0]['url'], $expected);
+ Cache::delete('url_test', $configName);
+ }
+/**
+ * Test that the FireCake toolbar is used on AJAX requests
+ *
+ * @return void
+ **/
+ function testAjaxToolbar() {
+ $_SERVER['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest';
+ $this->Controller->components = array('DebugKit.Toolbar');
+ $this->Controller->Component->init($this->Controller);
+ $this->Controller->Component->initialize($this->Controller);
+ $this->Controller->Component->startup($this->Controller);
+ $this->assertEqual($this->Controller->helpers['DebugKit.Toolbar']['output'], 'DebugKit.FirePhpToolbar');
+ }
+/**
+ * Test that the toolbar does not interfere with requestAction
+ *
+ * @return void
+ **/
+ function testNoRequestActionInterference() {
+ $debugKitPath = App::pluginPath('DebugKit');
+ $noDir = (empty($debugKitPath) || !file_exists($debugKitPath));
+ $skip = $this->skipIf($noDir, 'Could not find debug_kit in plugin paths, skipping %s');
+ if ($skip) {
+ return;
+ }
+
+ App::build(array(
+ 'controllers' => $debugKitPath . 'tests' . DS . 'test_app' . DS . 'controllers' . DS,
+ 'views' => array(
+ $debugKitPath . 'tests' . DS . 'test_app' . DS . 'views' . DS,
+ CAKE_CORE_INCLUDE_PATH . DS . 'cake' . DS . 'libs' . DS . 'view' . DS
+ ),
+ 'plugins' => $this->_paths['plugins']
+ ));
+ Router::reload();
+
+ $result = $this->Controller->requestAction('/debug_kit_test/request_action_return', array('return'));
+ $this->assertEqual($result, 'I am some value from requestAction.');
+
+ $result = $this->Controller->requestAction('/debug_kit_test/request_action_render', array('return'));
+ $this->assertEqual($result, 'I have been rendered.');
+ }
+/**
+ * test the sqlLog panel parsing of db->showLog
+ *
+ * @return void
+ **/
+ function testSqlLogPanel() {
+ App::import('Core', 'Model');
+ $Article =& new Model(array('ds' => 'test_suite', 'name' => 'Article'));
+ $Article->find('first', array('conditions' => array('Article.id' => 1)));
+
+ $this->Controller->components = array(
+ 'DebugKit.Toolbar' => array(
+ 'panels' => array('SqlLog')
+ )
+ );
+ $this->Controller->Component->init($this->Controller);
+ $this->Controller->Component->initialize($this->Controller);
+ $this->Controller->Component->startup($this->Controller);
+ $this->Controller->Component->beforeRender($this->Controller);
+ $result = $this->Controller->viewVars['debugToolbarPanels']['sql_log'];
+
+ $this->assertTrue(isset($result['content']['connections']['test_suite']));
+ $this->assertTrue(isset($result['content']['threshold']));
+ }
+}
diff --git a/code/ryzom/tools/server/www/webtt/plugins/debug_kit/tests/cases/models/toolbar_access.test.php b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/tests/cases/models/toolbar_access.test.php
new file mode 100644
index 000000000..008f4fe10
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/tests/cases/models/toolbar_access.test.php
@@ -0,0 +1,65 @@
+Model =& new ToolbarAccess();
+ }
+
+/**
+ * endTest
+ *
+ * @return void
+ */
+ function endTest() {
+ unset($this->Model);
+ }
+
+/**
+ * test that explain query returns arrays of query information.
+ *
+ * @return void
+ */
+ function testExplainQuery() {
+ $db =& ConnectionManager::getDataSource('test_suite');
+ $sql = 'SELECT * FROM ' . $db->fullTableName('posts') . ';';
+ $result = $this->Model->explainQuery('test_suite', $sql);
+
+ $this->assertTrue(is_array($result));
+ $this->assertFalse(empty($result));
+ }
+}
diff --git a/code/ryzom/tools/server/www/webtt/plugins/debug_kit/tests/cases/test_objects.php b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/tests/cases/test_objects.php
new file mode 100644
index 000000000..67b01a7df
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/tests/cases/test_objects.php
@@ -0,0 +1,53 @@
+sentHeaders[$name] = $value;
+ }
+/**
+ * skip client detection as headers are not being sent.
+ *
+ * @access public
+ * @return void
+ */
+ function detectClientExtension() {
+ return true;
+ }
+/**
+ * Reset the fireCake
+ *
+ * @return void
+ **/
+ function reset() {
+ $_this =& FireCake::getInstance();
+ $_this->sentHeaders = array();
+ $_this->_messageIndex = 1;
+ }
+}
+
+
diff --git a/code/ryzom/tools/server/www/webtt/plugins/debug_kit/tests/cases/vendors/debug_kit_debugger.test.php b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/tests/cases/vendors/debug_kit_debugger.test.php
new file mode 100644
index 000000000..536e89922
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/tests/cases/vendors/debug_kit_debugger.test.php
@@ -0,0 +1,232 @@
+assertTrue(DebugKitDebugger::startTimer('test1', 'this is my first test'));
+ usleep(5000);
+ $this->assertTrue(DebugKitDebugger::stopTimer('test1'));
+ $elapsed = DebugKitDebugger::elapsedTime('test1');
+ $this->assertTrue($elapsed > 0.0050);
+
+ $this->assertTrue(DebugKitDebugger::startTimer('test2', 'this is my second test'));
+ sleep(1);
+ $this->assertTrue(DebugKitDebugger::stopTimer('test2'));
+ $elapsed = DebugKitDebugger::elapsedTime('test2');
+ $this->assertTrue($elapsed > 1);
+
+ DebugKitDebugger::startTimer('test3');
+ $this->assertFalse(DebugKitDebugger::elapsedTime('test3'));
+ $this->assertFalse(DebugKitDebugger::stopTimer('wrong'));
+ }
+/**
+ * test timers with no names.
+ *
+ * @return void
+ **/
+ function testAnonymousTimers() {
+ $this->assertTrue(DebugKitDebugger::startTimer());
+ usleep(2000);
+ $this->assertTrue(DebugKitDebugger::stopTimer());
+ $timers = DebugKitDebugger::getTimers();
+
+ $this->assertEqual(count($timers), 2);
+ end($timers);
+ $key = key($timers);
+ $lineNo = __LINE__ - 8;
+
+ $file = Debugger::trimPath(__FILE__);
+ $expected = $file . ' line ' . $lineNo;
+ $this->assertEqual($key, $expected);
+
+ $timer = $timers[$expected];
+ $this->assertTrue($timer['time'] > 0.0020);
+ $this->assertEqual($timers[$expected]['message'], $expected);
+ }
+/**
+ * Assert that nested anonymous timers don't get mixed up.
+ *
+ * @return void
+ **/
+ function testNestedAnonymousTimers() {
+ $this->assertTrue(DebugKitDebugger::startTimer());
+ usleep(100);
+ $this->assertTrue(DebugKitDebugger::startTimer());
+ usleep(100);
+ $this->assertTrue(DebugKitDebugger::stopTimer());
+ $this->assertTrue(DebugKitDebugger::stopTimer());
+
+ $timers = DebugKitDebugger::getTimers();
+ $this->assertEqual(count($timers), 3, 'incorrect number of timers %s');
+ $firstTimerLine = __LINE__ -9;
+ $secondTimerLine = __LINE__ -8;
+ $file = Debugger::trimPath(__FILE__);
+
+ $this->assertTrue(isset($timers[$file . ' line ' . $firstTimerLine]), 'first timer is not set %s');
+ $this->assertTrue(isset($timers[$file . ' line ' . $secondTimerLine]), 'second timer is not set %s');
+
+ $firstTimer = $timers[$file . ' line ' . $firstTimerLine];
+ $secondTimer = $timers[$file . ' line ' . $secondTimerLine];
+ $this->assertTrue($firstTimer['time'] > $secondTimer['time']);
+ }
+/**
+ * test that calling startTimer with the same name does not overwrite previous timers
+ * and instead adds new ones.
+ *
+ * @return void
+ **/
+ function testRepeatTimers() {
+ DebugKitDebugger::startTimer('my timer', 'This is the first call');
+ usleep(100);
+ DebugKitDebugger::startTimer('my timer', 'This is the second call');
+ usleep(100);
+
+ DebugKitDebugger::stopTimer('my timer');
+ DebugKitDebugger::stopTimer('my timer');
+
+ $timers = DebugKitDebugger::getTimers();
+ $this->assertEqual(count($timers), 3, 'wrong timer count %s');
+
+ $this->assertTrue(isset($timers['my timer']));
+ $this->assertTrue(isset($timers['my timer #2']));
+
+ $this->assertTrue($timers['my timer']['time'] > $timers['my timer #2']['time'], 'timer 2 is longer? %s');
+ $this->assertEqual($timers['my timer']['message'], 'This is the first call');
+ $this->assertEqual($timers['my timer #2']['message'], 'This is the second call #2');
+ }
+/**
+ * testRequestTime
+ *
+ * @access public
+ * @return void
+ */
+ function testRequestTime() {
+ $result1 = DebugKitDebugger::requestTime();
+ usleep(50);
+ $result2 = DebugKitDebugger::requestTime();
+ $this->assertTrue($result1 < $result2);
+ }
+/**
+ * test getting all the set timers.
+ *
+ * @return void
+ **/
+ function testGetTimers() {
+ DebugKitDebugger::startTimer('test1', 'this is my first test');
+ DebugKitDebugger::stopTimer('test1');
+ usleep(50);
+ DebugKitDebugger::startTimer('test2');
+ DebugKitDebugger::stopTimer('test2');
+ $timers = DebugKitDebugger::getTimers();
+
+ $this->assertEqual(count($timers), 3);
+ $this->assertTrue(is_float($timers['test1']['time']));
+ $this->assertTrue(isset($timers['test1']['message']));
+ $this->assertTrue(isset($timers['test2']['message']));
+ }
+/**
+ * test memory usage
+ *
+ * @return void
+ **/
+ function testMemoryUsage() {
+ $result = DebugKitDebugger::getMemoryUse();
+ $this->assertTrue(is_int($result));
+
+ $result = DebugKitDebugger::getPeakMemoryUse();
+ $this->assertTrue(is_int($result));
+ }
+/**
+ * test _output switch to firePHP
+ *
+ * @return void
+ */
+ function testOutput() {
+ $firecake =& FireCake::getInstance('TestFireCake');
+ Debugger::invoke(DebugKitDebugger::getInstance('DebugKitDebugger'));
+ Debugger::output('fb');
+ $foo .= '';
+ $result = $firecake->sentHeaders;
+
+ $this->assertPattern('/GROUP_START/', $result['X-Wf-1-1-1-1']);
+ $this->assertPattern('/ERROR/', $result['X-Wf-1-1-1-2']);
+ $this->assertPattern('/GROUP_END/', $result['X-Wf-1-1-1-5']);
+
+ Debugger::invoke(Debugger::getInstance('Debugger'));
+ Debugger::output();
+ }
+/**
+ * test making memory use markers.
+ *
+ * @return void
+ **/
+ function testMemorySettingAndGetting() {
+ $result = DebugKitDebugger::setMemoryPoint('test marker');
+ $this->assertTrue($result);
+
+ $result = DebugKitDebugger::getMemoryPoints(true);
+ $this->assertEqual(count($result), 1);
+ $this->assertTrue(isset($result['test marker']));
+ $this->assertTrue(is_numeric($result['test marker']));
+
+ $result = DebugKitDebugger::getMemoryPoints();
+ $this->assertTrue(empty($result));
+
+ DebugKitDebugger::setMemoryPoint('test marker');
+ DebugKitDebugger::setMemoryPoint('test marker');
+ $result = DebugKitDebugger::getMemoryPoints();
+ $this->assertEqual(count($result), 2);
+ $this->assertTrue(isset($result['test marker']));
+ $this->assertTrue(isset($result['test marker #2']));
+ }
+
+}
diff --git a/code/ryzom/tools/server/www/webtt/plugins/debug_kit/tests/cases/vendors/fire_cake.test.php b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/tests/cases/vendors/fire_cake.test.php
new file mode 100644
index 000000000..80abdfc73
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/tests/cases/vendors/fire_cake.test.php
@@ -0,0 +1,340 @@
+firecake =& FireCake::getInstance('TestFireCake');
+ }
+/**
+ * test getInstance cheat.
+ *
+ * If this fails the rest of the test is going to fail too.
+ *
+ * @return void
+ **/
+ function testGetInstanceOverride() {
+ $instance =& FireCake::getInstance();
+ $instance2 =& FireCake::getInstance();
+ $this->assertReference($instance, $instance2);
+ $this->assertIsA($instance, 'FireCake');
+ $this->assertIsA($instance, 'TestFireCake', 'Stored instance is not a copy of TestFireCake, test case is broken.');
+ }
+/**
+ * testsetoption
+ *
+ * @return void
+ **/
+ function testSetOptions() {
+ FireCake::setOptions(array('includeLineNumbers' => false));
+ $this->assertEqual($this->firecake->options['includeLineNumbers'], false);
+ }
+/**
+ * test Log()
+ *
+ * @access public
+ * @return void
+ */
+ function testLog() {
+ FireCake::setOptions(array('includeLineNumbers' => false));
+ FireCake::log('Testing');
+ $this->assertTrue(isset($this->firecake->sentHeaders['X-Wf-Protocol-1']));
+ $this->assertTrue(isset($this->firecake->sentHeaders['X-Wf-1-Plugin-1']));
+ $this->assertTrue(isset($this->firecake->sentHeaders['X-Wf-1-Structure-1']));
+ $this->assertEqual($this->firecake->sentHeaders['X-Wf-1-Index'], 1);
+ $this->assertEqual($this->firecake->sentHeaders['X-Wf-1-1-1-1'], '26|[{"Type":"LOG"},"Testing"]|');
+
+ FireCake::log('Testing', 'log-info');
+ $this->assertEqual($this->firecake->sentHeaders['X-Wf-1-1-1-2'], '45|[{"Type":"LOG","Label":"log-info"},"Testing"]|');
+ }
+/**
+ * test info()
+ *
+ * @access public
+ * @return void
+ */
+ function testInfo() {
+ FireCake::setOptions(array('includeLineNumbers' => false));
+ FireCake::info('I have information');
+ $this->assertTrue(isset($this->firecake->sentHeaders['X-Wf-Protocol-1']));
+ $this->assertTrue(isset($this->firecake->sentHeaders['X-Wf-1-Plugin-1']));
+ $this->assertTrue(isset($this->firecake->sentHeaders['X-Wf-1-Structure-1']));
+ $this->assertEqual($this->firecake->sentHeaders['X-Wf-1-Index'], 1);
+ $this->assertEqual($this->firecake->sentHeaders['X-Wf-1-1-1-1'], '38|[{"Type":"INFO"},"I have information"]|');
+
+ FireCake::info('I have information', 'info-label');
+ $this->assertEqual($this->firecake->sentHeaders['X-Wf-1-1-1-2'], '59|[{"Type":"INFO","Label":"info-label"},"I have information"]|');
+ }
+/**
+ * test info()
+ *
+ * @access public
+ * @return void
+ */
+ function testWarn() {
+ FireCake::setOptions(array('includeLineNumbers' => false));
+ FireCake::warn('A Warning');
+ $this->assertTrue(isset($this->firecake->sentHeaders['X-Wf-Protocol-1']));
+ $this->assertTrue(isset($this->firecake->sentHeaders['X-Wf-1-Plugin-1']));
+ $this->assertTrue(isset($this->firecake->sentHeaders['X-Wf-1-Structure-1']));
+ $this->assertEqual($this->firecake->sentHeaders['X-Wf-1-Index'], 1);
+ $this->assertEqual($this->firecake->sentHeaders['X-Wf-1-1-1-1'], '29|[{"Type":"WARN"},"A Warning"]|');
+
+ FireCake::warn('A Warning', 'Bzzz');
+ $this->assertEqual($this->firecake->sentHeaders['X-Wf-1-1-1-2'], '44|[{"Type":"WARN","Label":"Bzzz"},"A Warning"]|');
+ }
+/**
+ * test error()
+ *
+ * @access public
+ * @return void
+ **/
+ function testError() {
+ FireCake::setOptions(array('includeLineNumbers' => false));
+ FireCake::error('An error');
+ $this->assertTrue(isset($this->firecake->sentHeaders['X-Wf-Protocol-1']));
+ $this->assertTrue(isset($this->firecake->sentHeaders['X-Wf-1-Plugin-1']));
+ $this->assertTrue(isset($this->firecake->sentHeaders['X-Wf-1-Structure-1']));
+ $this->assertEqual($this->firecake->sentHeaders['X-Wf-1-Index'], 1);
+ $this->assertEqual($this->firecake->sentHeaders['X-Wf-1-1-1-1'], '29|[{"Type":"ERROR"},"An error"]|');
+
+ FireCake::error('An error', 'wonky');
+ $this->assertEqual($this->firecake->sentHeaders['X-Wf-1-1-1-2'], '45|[{"Type":"ERROR","Label":"wonky"},"An error"]|');
+ }
+/**
+ * test dump()
+ *
+ * @return void
+ **/
+ function testDump() {
+ FireCake::dump('mydump', array('one' => 1, 'two' => 2));
+ $this->assertEqual($this->firecake->sentHeaders['X-Wf-1-2-1-1'], '28|{"mydump":{"one":1,"two":2}}|');
+ $this->assertTrue(isset($this->firecake->sentHeaders['X-Wf-1-Structure-2']));
+ }
+/**
+ * test table() generation
+ *
+ * @return void
+ **/
+ function testTable() {
+ $table[] = array('Col 1 Heading','Col 2 Heading');
+ $table[] = array('Row 1 Col 1','Row 1 Col 2');
+ $table[] = array('Row 2 Col 1','Row 2 Col 2');
+ $table[] = array('Row 3 Col 1','Row 3 Col 2');
+ FireCake::table('myTrace', $table);
+ $expected = '162|[{"Type":"TABLE","Label":"myTrace"},[["Col 1 Heading","Col 2 Heading"],["Row 1 Col 1","Row 1 Col 2"],["Row 2 Col 1","Row 2 Col 2"],["Row 3 Col 1","Row 3 Col 2"]]]|';
+ $this->assertEqual($this->firecake->sentHeaders['X-Wf-1-1-1-1'], $expected);
+ }
+/**
+ * testStringEncoding
+ *
+ * @return void
+ **/
+ function testStringEncode() {
+ $vars = array(1,2,3);
+ $result = $this->firecake->stringEncode($vars);
+ $this->assertEqual($result, array(1,2,3));
+
+ $this->firecake->setOptions(array('maxArrayDepth' => 3));
+ $deep = array(1 => array(2 => array(3)));
+ $result = $this->firecake->stringEncode($deep);
+ $this->assertEqual($result, array(1 => array(2 => '** Max Array Depth (3) **')));
+ }
+/**
+ * test object encoding
+ *
+ * @return void
+ **/
+ function testStringEncodeObjects() {
+ $obj =& FireCake::getInstance();
+ $result = $this->firecake->stringEncode($obj);
+
+ $this->assertTrue(is_array($result));
+ $this->assertEqual($result['_defaultOptions']['useNativeJsonEncode'], true);
+ $this->assertEqual($result['_encodedObjects'][0], '** Recursion (TestFireCake) **');
+ }
+/**
+ * test trace()
+ *
+ * @return void
+ **/
+ function testTrace() {
+ FireCake::trace('myTrace');
+ $this->assertTrue(isset($this->firecake->sentHeaders['X-Wf-Protocol-1']));
+ $this->assertTrue(isset($this->firecake->sentHeaders['X-Wf-1-Plugin-1']));
+ $this->assertTrue(isset($this->firecake->sentHeaders['X-Wf-1-Structure-1']));
+ $dump = $this->firecake->sentHeaders['X-Wf-1-1-1-1'];
+ $this->assertPattern('/"Message":"myTrace"/', $dump);
+ $this->assertPattern('/"Trace":\[/', $dump);
+ }
+/**
+ * test enabling and disabling of FireCake output
+ *
+ * @return void
+ **/
+ function testEnableDisable() {
+ FireCake::disable();
+ FireCake::trace('myTrace');
+ $this->assertTrue(empty($this->firecake->sentHeaders));
+
+ FireCake::enable();
+ FireCake::trace('myTrace');
+ $this->assertFalse(empty($this->firecake->sentHeaders));
+ }
+
+/**
+ * test correct line continuation markers on multi line headers.
+ *
+ * @access public
+ * @return void
+ */
+ function testMultiLineOutput() {
+ $skip = $this->skipIf(!PHP5, 'Output is not long enough with PHP4');
+ if ($skip) {
+ return;
+ }
+ FireCake::trace('myTrace');
+ $this->assertEqual($this->firecake->sentHeaders['X-Wf-1-Index'], 4);
+ $header = $this->firecake->sentHeaders['X-Wf-1-1-1-1'];
+ $this->assertEqual(substr($header, -2), '|\\');
+
+ $header = $this->firecake->sentHeaders['X-Wf-1-1-1-2'];
+ $this->assertEqual(substr($header, -2), '|\\');
+
+ $header = $this->firecake->sentHeaders['X-Wf-1-1-1-3'];
+ $this->assertEqual(substr($header, -2), '|\\');
+
+ $header = $this->firecake->sentHeaders['X-Wf-1-1-1-4'];
+ $this->assertEqual(substr($header, -1), '|');
+ }
+/**
+ * test inclusion of line numbers
+ *
+ * @return void
+ **/
+ function testIncludeLineNumbers() {
+ FireCake::setOptions(array('includeLineNumbers' => true));
+ FireCake::info('Testing');
+ $result = $this->firecake->sentHeaders['X-Wf-1-1-1-1'];
+ $this->assertPattern('/"File"\:".*fire_cake.test.php/', $result);
+ $this->assertPattern('/"Line"\:\d+/', $result);
+ }
+/**
+ * test Group messages
+ *
+ * @return void
+ **/
+ function testGroup() {
+ FireCake::setOptions(array('includeLineNumbers' => false));
+ FireCake::group('test');
+ FireCake::info('my info');
+ FireCake::groupEnd();
+ $this->assertEqual($this->firecake->sentHeaders['X-Wf-1-1-1-1'], '63|[{"Collapsed":"true","Type":"GROUP_START","Label":"test"},null]|');
+ $this->assertEqual($this->firecake->sentHeaders['X-Wf-1-1-1-3'], '27|[{"Type":"GROUP_END"},null]|');
+ $this->assertEqual($this->firecake->sentHeaders['X-Wf-1-Index'], 3);
+ }
+/**
+ * test fb() parameter parsing
+ *
+ * @return void
+ **/
+ function testFbParameterParsing() {
+ FireCake::setOptions(array('includeLineNumbers' => false));
+ FireCake::fb('Test');
+ $this->assertEqual($this->firecake->sentHeaders['X-Wf-1-1-1-1'], '23|[{"Type":"LOG"},"Test"]|');
+
+ FireCake::fb('Test', 'warn');
+ $this->assertEqual($this->firecake->sentHeaders['X-Wf-1-1-1-2'], '24|[{"Type":"WARN"},"Test"]|');
+
+ FireCake::fb('Test', 'Custom label', 'warn');
+ $this->assertEqual($this->firecake->sentHeaders['X-Wf-1-1-1-3'], '47|[{"Type":"WARN","Label":"Custom label"},"Test"]|');
+
+ $this->expectError();
+ $this->assertFalse(FireCake::fb('Test', 'Custom label', 'warn', 'more parameters'));
+
+ $this->assertEqual($this->firecake->sentHeaders['X-Wf-1-Index'], 3);
+ }
+/**
+ * Test defaulting to log if incorrect message type is used
+ *
+ * @return void
+ **/
+ function testIncorrectMessageType() {
+ FireCake::setOptions(array('includeLineNumbers' => false));
+ FireCake::fb('Hello World', 'foobared');
+ $this->assertEqual($this->firecake->sentHeaders['X-Wf-1-1-1-1'], '30|[{"Type":"LOG"},"Hello World"]|');
+ }
+/**
+ * testClientExtensionDetection.
+ *
+ * @return void
+ **/
+ function testDetectClientExtension() {
+ $back = env('HTTP_USER_AGENT');
+ $_SERVER['HTTP_USER_AGENT'] = 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.0.4) Gecko/2008102920 Firefox/3.0.4 FirePHP/0.2.1';
+ $this->assertTrue(FireCake::detectClientExtension());
+
+ $_SERVER['HTTP_USER_AGENT'] = 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.0.4) Gecko/2008102920 Firefox/3.0.4 FirePHP/0.0.4';
+ $this->assertFalse(FireCake::detectClientExtension());
+
+ $_SERVER['HTTP_USER_AGENT'] = 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.0.4) Gecko/2008102920 Firefox/3.0.4';
+ $this->assertFalse(FireCake::detectClientExtension());
+ $_SERVER['HTTP_USER_AGENT'] = $back;
+ }
+/**
+ * test of Non Native JSON encoding.
+ *
+ * @return void
+ **/
+ function testNonNativeEncoding() {
+ FireCake::setOptions(array('useNativeJsonEncode' => false));
+ $json = FireCake::jsonEncode(array('one' => 1, 'two' => 2));
+ $this->assertEqual($json, '{"one":1,"two":2}');
+
+ $json = FireCake::jsonEncode(array(1,2,3));
+ $this->assertEqual($json, '[1,2,3]');
+
+ $json = FireCake::jsonEncode(FireCake::getInstance());
+ $this->assertPattern('/"options"\:\{"maxObjectDepth"\:\d*,/', $json);
+ }
+/**
+ * reset the FireCake counters and headers.
+ *
+ * @access public
+ * @return void
+ */
+ function tearDown() {
+ TestFireCake::reset();
+ }
+}
diff --git a/code/ryzom/tools/server/www/webtt/plugins/debug_kit/tests/cases/views/debug.test.php b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/tests/cases/views/debug.test.php
new file mode 100644
index 000000000..606ab0630
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/tests/cases/views/debug.test.php
@@ -0,0 +1,161 @@
+ 'pages', 'action' => 'display', 'home'));
+ Router::parse('/');
+ $this->Controller =& new Controller();
+ $this->View =& new DebugView($this->Controller, false);
+ $this->_debug = Configure::read('debug');
+ $this->_paths = array();
+ $this->_paths['plugins'] = App::path('plugins');
+ $this->_paths['views'] = App::path('views');
+ $this->_paths['vendors'] = App::path('vendors');
+ $this->_paths['controllers'] = App::path('controllers');
+ }
+/**
+ * tear down function
+ *
+ * @return void
+ **/
+ function endTest() {
+ App::build(array(
+ 'plugins' => $this->_paths['plugins'],
+ 'views' => $this->_paths['views'],
+ 'vendors' => $this->_paths['vendors'],
+ 'controllers' => $this->_paths['controllers']
+ ));
+
+ unset($this->View, $this->Controller);
+ DebugKitDebugger::clearTimers();
+ Configure::write('debug', $this->_debug);
+ }
+/**
+ * start Case - switch view paths
+ *
+ * @return void
+ **/
+ function startCase() {
+ App::build(array(
+ 'views' => array(
+ TEST_CAKE_CORE_INCLUDE_PATH . 'tests' . DS . 'test_app' . DS . 'views'. DS,
+ APP . 'plugins' . DS . 'debug_kit' . DS . 'views'. DS,
+ ROOT . DS . LIBS . 'view' . DS
+ )
+ ), true);
+ }
+/**
+ * test that element timers are working
+ *
+ * @return void
+ **/
+ function testElementTimers() {
+ $result = $this->View->element('test_element');
+ $expected = <<
+this is the test element
+
+
+TEXT;
+ $this->assertEqual($result, $expected);
+
+ $result = DebugKitDebugger::getTimers();
+ $this->assertTrue(isset($result['render_test_element.ctp']));
+ }
+/**
+ * test rendering and ensure that timers are being set.
+ *
+ * @access public
+ * @return void
+ */
+ function testRenderTimers() {
+ $this->Controller->viewPath = 'posts';
+ $this->Controller->action = 'index';
+ $this->Controller->params = array(
+ 'action' => 'index',
+ 'controller' => 'posts',
+ 'plugin' => null,
+ 'url' => array('url' => 'posts/index'),
+ 'base' => null,
+ 'here' => '/posts/index',
+ );
+ $this->Controller->layout = 'default';
+ $View =& new DebugView($this->Controller, false);
+ $View->render('index');
+
+ $result = DebugKitDebugger::getTimers();
+ $this->assertEqual(count($result), 4);
+ $this->assertTrue(isset($result['viewRender']));
+ $this->assertTrue(isset($result['render_default.ctp']));
+ $this->assertTrue(isset($result['render_index.ctp']));
+
+ $result = DebugKitDebugger::getMemoryPoints();
+ $this->assertTrue(isset($result['View render complete']));
+ }
+/**
+ * Test for correct loading of helpers into custom view
+ *
+ * @return void
+ */
+ function testLoadHelpers() {
+ $loaded = array();
+ $result = $this->View->_loadHelpers($loaded, array('Html', 'Javascript', 'Number'));
+ $this->assertTrue(is_object($result['Html']));
+ $this->assertTrue(is_object($result['Javascript']));
+ $this->assertTrue(is_object($result['Number']));
+ }
+/**
+ * test that $out is returned when a layout is rendered instead of the empty
+ * $this->output. As this causes issues with requestAction()
+ *
+ * @return void
+ **/
+ function testProperReturnUnderRequestAction() {
+ $testapp = App::pluginPath('DebugKit') . 'tests' . DS . 'test_app' . DS . 'views' . DS;
+ App::build(array('views' => array($testapp)));
+
+ $this->View->set('test', 'I have been rendered.');
+ $this->View->action = 'request_action_render';
+ $this->View->name = 'DebugKitTest';
+ $this->View->viewPath = 'debug_kit_test';
+ $this->View->layout = false;
+ $result = $this->View->render('request_action_render');
+
+ $this->assertEqual($result, 'I have been rendered.');
+ }
+}
diff --git a/code/ryzom/tools/server/www/webtt/plugins/debug_kit/tests/cases/views/helpers/fire_php_toolbar.test.php b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/tests/cases/views/helpers/fire_php_toolbar.test.php
new file mode 100644
index 000000000..dd269483b
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/tests/cases/views/helpers/fire_php_toolbar.test.php
@@ -0,0 +1,149 @@
+ 'pages', 'action' => 'display', 'home'));
+ Router::parse('/');
+
+ $this->Toolbar =& new ToolbarHelper(array('output' => 'DebugKit.FirePhpToolbar'));
+ $this->Toolbar->FirePhpToolbar =& new FirePhpToolbarHelper();
+
+ $this->Controller =& new Controller();
+ if (isset($this->_debug)) {
+ Configure::write('debug', $this->_debug);
+ }
+ }
+/**
+ * start Case - switch view paths
+ *
+ * @return void
+ **/
+ function startCase() {
+ $this->_viewPaths = App::build('views');
+ App::build(array(
+ 'views' => array(
+ TEST_CAKE_CORE_INCLUDE_PATH . 'tests' . DS . 'test_app' . DS . 'views'. DS,
+ APP . 'plugins' . DS . 'debug_kit' . DS . 'views'. DS,
+ ROOT . DS . LIBS . 'view' . DS
+ )), true);
+ $this->_debug = Configure::read('debug');
+ $this->firecake =& FireCake::getInstance();
+ }
+/**
+ * test neat array (dump)creation
+ *
+ * @return void
+ */
+ function testMakeNeatArray() {
+ $this->Toolbar->makeNeatArray(array(1,2,3));
+ $result = $this->firecake->sentHeaders;
+ $this->assertTrue(isset($result['X-Wf-1-1-1-1']));
+ $this->assertPattern('/\[1,2,3\]/', $result['X-Wf-1-1-1-1']);
+ }
+/**
+ * testAfterlayout element rendering
+ *
+ * @return void
+ */
+ function testAfterLayout(){
+ $this->Controller->viewPath = 'posts';
+ $this->Controller->action = 'index';
+ $this->Controller->params = array(
+ 'action' => 'index',
+ 'controller' => 'posts',
+ 'plugin' => null,
+ 'url' => array('url' => 'posts/index', 'ext' => 'xml'),
+ 'base' => null,
+ 'here' => '/posts/index',
+ );
+ $this->Controller->layout = 'default';
+ $this->Controller->uses = null;
+ $this->Controller->components = array('DebugKit.Toolbar');
+ $this->Controller->constructClasses();
+ $this->Controller->Component->initialize($this->Controller);
+ $this->Controller->Component->startup($this->Controller);
+ $this->Controller->Component->beforeRender($this->Controller);
+ $result = $this->Controller->render();
+ $this->assertNoPattern('/debug-toolbar/', $result);
+ $result = $this->firecake->sentHeaders;
+ $this->assertTrue(is_array($result));
+ }
+/**
+ * test starting a panel
+ *
+ * @return void
+ **/
+ function testPanelStart() {
+ $this->Toolbar->panelStart('My Panel', 'my_panel');
+ $result = $this->firecake->sentHeaders;
+ $this->assertPattern('/GROUP_START.+My Panel/', $result['X-Wf-1-1-1-1']);
+ }
+/**
+ * test ending a panel
+ *
+ * @return void
+ **/
+ function testPanelEnd() {
+ $this->Toolbar->panelEnd();
+ $result = $this->firecake->sentHeaders;
+ $this->assertPattern('/GROUP_END/', $result['X-Wf-1-1-1-1']);
+ }
+/**
+ * endTest()
+ *
+ * @return void
+ */
+ function endTest() {
+ TestFireCake::reset();
+ }
+/**
+ * reset the view paths
+ *
+ * @return void
+ **/
+ function endCase() {
+ Configure::write('viewPaths', $this->_viewPaths);
+ }
+/**
+ * tearDown
+ *
+ * @access public
+ * @return void
+ */
+ function tearDown() {
+ unset($this->Toolbar, $this->Controller);
+ ClassRegistry::removeObject('view');
+ ClassRegistry::flush();
+ Router::reload();
+ }
+}
diff --git a/code/ryzom/tools/server/www/webtt/plugins/debug_kit/tests/cases/views/helpers/html_toolbar.test.php b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/tests/cases/views/helpers/html_toolbar.test.php
new file mode 100644
index 000000000..766edd621
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/tests/cases/views/helpers/html_toolbar.test.php
@@ -0,0 +1,352 @@
+ 'pages', 'action' => 'display', 'home'));
+ Router::parse('/');
+
+ $this->Toolbar =& new ToolbarHelper(array('output' => 'DebugKit.HtmlToolbar'));
+ $this->Toolbar->HtmlToolbar =& new HtmlToolbarHelper();
+ $this->Toolbar->HtmlToolbar->Html =& new HtmlHelper();
+ $this->Toolbar->HtmlToolbar->Form =& new FormHelper();
+
+ $this->Controller =& new Controller();
+ if (isset($this->_debug)) {
+ Configure::write('debug', $this->_debug);
+ }
+ }
+/**
+ * start Case - switch view paths
+ *
+ * @return void
+ **/
+ function startCase() {
+ $this->_viewPaths = App::path('views');
+ App::build(array(
+ 'views' => array(
+ TEST_CAKE_CORE_INCLUDE_PATH . 'tests' . DS . 'test_app' . DS . 'views'. DS,
+ APP . 'plugins' . DS . 'debug_kit' . DS . 'views'. DS,
+ ROOT . DS . LIBS . 'view' . DS
+ )), true);
+ $this->_debug = Configure::read('debug');
+ }
+/**
+ * test Neat Array formatting
+ *
+ * @return void
+ **/
+ function testMakeNeatArray() {
+ $in = false;
+ $result = $this->Toolbar->makeNeatArray($in);
+ $expected = array(
+ 'ul' => array('class' => 'neat-array depth-0'),
+ 'assertTags($result, $expected);
+
+ $in = null;
+ $result = $this->Toolbar->makeNeatArray($in);
+ $expected = array(
+ 'ul' => array('class' => 'neat-array depth-0'),
+ ' assertTags($result, $expected);
+
+ $in = true;
+ $result = $this->Toolbar->makeNeatArray($in);
+ $expected = array(
+ 'ul' => array('class' => 'neat-array depth-0'),
+ ' assertTags($result, $expected);
+
+ $in = array();
+ $result = $this->Toolbar->makeNeatArray($in);
+ $expected = array(
+ 'ul' => array('class' => 'neat-array depth-0'),
+ ' assertTags($result, $expected);
+
+ $in = array('key' => 'value');
+ $result = $this->Toolbar->makeNeatArray($in);
+ $expected = array(
+ 'ul' => array('class' => 'neat-array depth-0'),
+ ' assertTags($result, $expected);
+
+ $in = array('key' => null);
+ $result = $this->Toolbar->makeNeatArray($in);
+ $expected = array(
+ 'ul' => array('class' => 'neat-array depth-0'),
+ ' assertTags($result, $expected);
+
+ $in = array('key' => 'value', 'foo' => 'bar');
+ $result = $this->Toolbar->makeNeatArray($in);
+ $expected = array(
+ 'ul' => array('class' => 'neat-array depth-0'),
+ ' assertTags($result, $expected);
+
+ $in = array(
+ 'key' => 'value',
+ 'foo' => array(
+ 'this' => 'deep',
+ 'another' => 'value'
+ )
+ );
+ $result = $this->Toolbar->makeNeatArray($in);
+ $expected = array(
+ 'ul' => array('class' => 'neat-array depth-0'),
+ ' array('class' => 'neat-array depth-1')),
+ ' assertTags($result, $expected);
+
+ $in = array(
+ 'key' => 'value',
+ 'foo' => array(
+ 'this' => 'deep',
+ 'another' => 'value'
+ ),
+ 'lotr' => array(
+ 'gandalf' => 'wizard',
+ 'bilbo' => 'hobbit'
+ )
+ );
+ $result = $this->Toolbar->makeNeatArray($in, 1);
+ $expected = array(
+ 'ul' => array('class' => 'neat-array depth-0 expanded'),
+ ' array('class' => 'neat-array depth-1')),
+ ' array('class' => 'neat-array depth-1')),
+ ' assertTags($result, $expected);
+
+ $result = $this->Toolbar->makeNeatArray($in, 2);
+ $expected = array(
+ 'ul' => array('class' => 'neat-array depth-0 expanded'),
+ ' array('class' => 'neat-array depth-1 expanded')),
+ ' array('class' => 'neat-array depth-1 expanded')),
+ ' assertTags($result, $expected);
+
+ $in = array('key' => 'value', 'array' => array());
+ $result = $this->Toolbar->makeNeatArray($in);
+ $expected = array(
+ 'ul' => array('class' => 'neat-array depth-0'),
+ ' assertTags($result, $expected);
+ }
+
+/**
+ * Test injection of toolbar
+ *
+ * @return void
+ **/
+ function testInjectToolbar() {
+ $this->Controller->viewPath = 'posts';
+ $this->Controller->action = 'index';
+ $this->Controller->params = array(
+ 'action' => 'index',
+ 'controller' => 'posts',
+ 'plugin' => null,
+ 'url' => array('url' => 'posts/index'),
+ 'base' => null,
+ 'here' => '/posts/index',
+ );
+ $this->Controller->helpers = array('Html', 'Javascript', 'Session', 'DebugKit.Toolbar');
+ $this->Controller->layout = 'default';
+ $this->Controller->uses = null;
+ $this->Controller->components = array('DebugKit.Toolbar');
+ $this->Controller->constructClasses();
+ $this->Controller->Component->initialize($this->Controller);
+ $this->Controller->Component->startup($this->Controller);
+ $this->Controller->Component->beforeRender($this->Controller);
+ $result = $this->Controller->render();
+ $result = str_replace(array("\n", "\r"), '', $result);
+ $this->assertPattern('#.+
.*#', $result);
+ }
+
+/**
+ * test injection of javascript
+ *
+ * @return void
+ **/
+ function testJavascriptInjection() {
+ $this->Controller->viewPath = 'posts';
+ $this->Controller->uses = null;
+ $this->Controller->action = 'index';
+ $this->Controller->params = array(
+ 'action' => 'index',
+ 'controller' => 'posts',
+ 'plugin' => null,
+ 'url' => array('url' => 'posts/index'),
+ 'base' => '/',
+ 'here' => '/posts/index',
+ );
+ $this->Controller->helpers = array('Javascript', 'Html', 'Session');
+ $this->Controller->components = array('DebugKit.Toolbar');
+ $this->Controller->layout = 'default';
+ $this->Controller->constructClasses();
+ $this->Controller->Component->initialize($this->Controller);
+ $this->Controller->Component->startup($this->Controller);
+ $this->Controller->Component->beforeRender($this->Controller);
+ $result = $this->Controller->render();
+ $result = str_replace(array("\n", "\r"), '', $result);
+ $this->assertPattern('##', $result);
+ }
+
+/**
+ * test message creation
+ *
+ * @return void
+ */
+ function testMessage() {
+ $result = $this->Toolbar->message('test', 'one, two');
+ $expected = array(
+ 'assertTags($result, $expected);
+ }
+/**
+ * Test Table generation
+ *
+ * @return void
+ */
+ function testTable() {
+ $rows = array(
+ array(1,2),
+ array(3,4),
+ );
+ $result = $this->Toolbar->table($rows);
+ $expected = array(
+ 'table' => array('class' =>'debug-table'),
+ array('tr' => array('class' => 'odd')),
+ '
array('class' => 'even')),
+ ' assertTags($result, $expected);
+ }
+/**
+ * test starting a panel
+ *
+ * @return void
+ **/
+ function testStartPanel() {
+ $result = $this->Toolbar->panelStart('My Panel', 'my_panel');
+ $expected = array(
+ 'a' => array('href' => '#my_panel'),
+ 'My Panel',
+ '/a'
+ );
+ $this->assertTags($result, $expected);
+ }
+/**
+ * test ending a panel
+ *
+ * @return void
+ **/
+ function testPanelEnd() {
+ $result = $this->Toolbar->panelEnd();
+ $this->assertNull($result);
+ }
+/**
+ * reset the view paths
+ *
+ * @return void
+ **/
+ function endCase() {
+ App::build();
+ }
+
+/**
+ * tearDown
+ *
+ * @access public
+ * @return void
+ */
+ function tearDown() {
+ unset($this->Toolbar, $this->Controller);
+ ClassRegistry::removeObject('view');
+ ClassRegistry::flush();
+ }
+}
diff --git a/code/ryzom/tools/server/www/webtt/plugins/debug_kit/tests/cases/views/helpers/toolbar.test.php b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/tests/cases/views/helpers/toolbar.test.php
new file mode 100644
index 000000000..81c914e73
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/tests/cases/views/helpers/toolbar.test.php
@@ -0,0 +1,170 @@
+ 'pages', 'action' => 'display', 'home'));
+ Router::parse('/');
+
+ $this->Toolbar =& new ToolbarHelper(array(
+ 'output' => 'MockBackendHelper',
+ 'cacheKey' => 'debug_kit_toolbar_test_case',
+ 'cacheConfig' => 'default'
+ ));
+ $this->Toolbar->MockBackend = new MockBackendHelper();
+
+ $this->Controller =& ClassRegistry::init('Controller');
+ if (isset($this->_debug)) {
+ Configure::write('debug', $this->_debug);
+ }
+ }
+/**
+ * start Case - switch view paths
+ *
+ * @return void
+ **/
+ function startCase() {
+ $this->_viewPaths = App::path('views');
+ App::build(array(
+ 'views' => array(
+ TEST_CAKE_CORE_INCLUDE_PATH . 'tests' . DS . 'test_app' . DS . 'views'. DS,
+ APP . 'plugins' . DS . 'debug_kit' . DS . 'views'. DS,
+ ROOT . DS . LIBS . 'view' . DS
+ )), true);
+ $this->_debug = Configure::read('debug');
+ }
+/**
+ * test cache writing for views.
+ *
+ * @return void
+ **/
+ function testCacheWrite() {
+ $result = $this->Toolbar->writeCache('test', array('stuff', 'to', 'cache'));
+ $this->assertTrue($result);
+ }
+/**
+ * Ensure that the cache writing only affects the
+ * top most level of the history stack. As this is where the current request is stored.
+ *
+ * @return void
+ **/
+ function testOnlyWritingToFirstElement() {
+ $values = array(
+ array('test' => array('content' => array('first', 'values'))),
+ array('test' => array('content' => array('second', 'values'))),
+ );
+ Cache::write('debug_kit_toolbar_test_case', $values, 'default');
+ $this->Toolbar->writeCache('test', array('new', 'values'));
+
+ $result = $this->Toolbar->readCache('test');
+ $this->assertEqual($result, array('new', 'values'));
+
+ $result = $this->Toolbar->readCache('test', 1);
+ $this->assertEqual($result, array('second', 'values'));
+ }
+/**
+ * test cache reading for views
+ *
+ * @return void
+ **/
+ function testCacheRead() {
+ $result = $this->Toolbar->writeCache('test', array('stuff', 'to', 'cache'));
+ $this->assertTrue($result, 'Cache write failed %s');
+
+ $result = $this->Toolbar->readCache('test');
+ $this->assertEqual($result, array('stuff', 'to', 'cache'), 'Cache value is wrong %s');
+
+ $result = $this->Toolbar->writeCache('test', array('new', 'stuff'));
+ $this->assertTrue($result, 'Cache write failed %s');
+
+ $result = $this->Toolbar->readCache('test');
+ $this->assertEqual($result, array('new', 'stuff'), 'Cache value is wrong %s');
+ }
+/**
+ * Test that reading/writing doesn't work with no cache config.
+ *
+ * @return void
+ **/
+ function testNoCacheConfigPresent() {
+ $this->Toolbar = new ToolbarHelper(array('output' => 'MockBackendHelper'));
+
+ $result = $this->Toolbar->writeCache('test', array('stuff', 'to', 'cache'));
+ $this->assertFalse($result, 'Writing to cache succeeded with no cache config %s');
+
+ $result = $this->Toolbar->readCache('test');
+ $this->assertFalse($result, 'Reading cache succeeded with no cache config %s');
+ }
+/**
+ * ensure that getQueryLogs works and writes to the cache so the history panel will
+ * work.
+ *
+ * @return void
+ */
+ function testGetQueryLogs() {
+ $model =& new Model(array('ds' => 'test_suite', 'table' => 'posts', 'name' => 'Post'));
+ $model->find('all');
+ $model->find('first');
+
+ $result = $this->Toolbar->getQueryLogs('test_suite', array('cache' => false));
+ $this->assertTrue(is_array($result));
+ $this->assertTrue(count($result) >= 2, 'Should be more than 2 queries in the log %s');
+ $this->assertTrue(isset($result[0]['actions']));
+
+ $model->find('first');
+ Cache::delete('debug_kit_toolbar_test_case', 'default');
+ $result = $this->Toolbar->getQueryLogs('test_suite', array('cache' => true));
+
+ $cached = $this->Toolbar->readCache('sql_log');
+ $this->assertTrue(isset($cached['test_suite']));
+ $this->assertEqual($cached['test_suite'][0], $result[0]);
+ }
+/**
+ * reset the view paths
+ *
+ * @return void
+ **/
+ function endCase() {
+ App::build(array('views' => $this->_viewPaths), true);
+ Cache::delete('debug_kit_toolbar_test_case', 'default');
+ }
+/**
+ * endTest
+ *
+ * @access public
+ * @return void
+ */
+ function endTest() {
+ unset($this->Toolbar, $this->Controller);
+ ClassRegistry::removeObject('view');
+ ClassRegistry::flush();
+ }
+}
diff --git a/code/ryzom/tools/server/www/webtt/plugins/debug_kit/tests/groups/view_group.group.php b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/tests/groups/view_group.group.php
new file mode 100644
index 000000000..4f5625545
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/tests/groups/view_group.group.php
@@ -0,0 +1,44 @@
+autoRender = false;
+ return 'I am some value from requestAction.';
+ }
+
+ function request_action_render() {
+ $this->set('test', 'I have been rendered.');
+ }
+
+}
\ No newline at end of file
diff --git a/code/ryzom/tools/server/www/webtt/plugins/debug_kit/tests/test_app/vendors/test_panel.php b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/tests/test_app/vendors/test_panel.php
new file mode 100644
index 000000000..3b004d3f7
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/tests/test_app/vendors/test_panel.php
@@ -0,0 +1,24 @@
+testPanel = true;
+ }
+}
diff --git a/code/ryzom/tools/server/www/webtt/plugins/debug_kit/tests/test_app/views/debug_kit_test/request_action_render.ctp b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/tests/test_app/views/debug_kit_test/request_action_render.ctp
new file mode 100644
index 000000000..172d541d7
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/tests/test_app/views/debug_kit_test/request_action_render.ctp
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/code/ryzom/tools/server/www/webtt/plugins/debug_kit/vendors/debug_kit_debugger.php b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/vendors/debug_kit_debugger.php
new file mode 100644
index 000000000..862ce627d
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/vendors/debug_kit_debugger.php
@@ -0,0 +1,400 @@
+__benchmarks) {
+ return;
+ }
+ $timers = array_values(DebugKitDebugger::getTimers());
+ $end = end($timers);
+ echo '';
+ echo 'Debug timer info ';
+ echo 'Message Start Time (ms) End Time (ms) Duration (ms) ';
+ $i = 0;
+ foreach ($timers as $timer) {
+ $indent = 0;
+ for ($j = 0; $j < $i; $j++) {
+ if (($timers[$j]['end']) > ($timer['start']) && ($timers[$j]['end']) > ($timer['end'])) {
+ $indent++;
+ }
+ }
+ $indent = str_repeat(' » ', $indent);
+
+ extract($timer);
+ $start = round($start * 1000, 0);
+ $end = round($end * 1000, 0);
+ $time = round($time * 1000, 0);
+ echo "{$indent}$message $start $end $time ";
+ $i++;
+ }
+ echo '
';
+ }
+/**
+ * Start an benchmarking timer.
+ *
+ * @param string $name The name of the timer to start.
+ * @param string $message A message for your timer
+ * @return bool true
+ * @static
+ **/
+ function startTimer($name = null, $message = null) {
+ $start = getMicrotime();
+ $_this =& DebugKitDebugger::getInstance();
+
+ if (!$name) {
+ $named = false;
+ $calledFrom = debug_backtrace();
+ $_name = $name = Debugger::trimpath($calledFrom[0]['file']) . ' line ' . $calledFrom[0]['line'];
+ } else {
+ $named = true;
+ }
+
+ if (!$message) {
+ $message = $name;
+ }
+
+ $_name = $name;
+ $i = 1;
+ while (isset($_this->__benchmarks[$name])) {
+ $i++;
+ $name = $_name . ' #' . $i;
+ }
+
+ if ($i > 1) {
+ $message .= ' #' . $i;
+ }
+
+ $_this->__benchmarks[$name] = array(
+ 'start' => $start,
+ 'message' => $message,
+ 'named' => $named
+ );
+ return true;
+ }
+/**
+ * Stop a benchmarking timer.
+ *
+ * $name should be the same as the $name used in startTimer().
+ *
+ * @param string $name The name of the timer to end.
+ * @access public
+ * @return boolean true if timer was ended, false if timer was not started.
+ * @static
+ */
+ function stopTimer($name = null) {
+ $end = getMicrotime();
+ $_this =& DebugKitDebugger::getInstance();
+ if (!$name) {
+ $names = array_reverse(array_keys($_this->__benchmarks));
+ foreach($names as $name) {
+ if (!empty($_this->__benchmarks[$name]['end'])) {
+ continue;
+ }
+ if (empty($_this->__benchmarks[$name]['named'])) {
+ break;
+ }
+ }
+ } else {
+ $i = 1;
+ $_name = $name;
+ while (isset($_this->__benchmarks[$name])) {
+ if (empty($_this->__benchmarks[$name]['end'])) {
+ break;
+ }
+ $i++;
+ $name = $_name . ' #' . $i;
+ }
+ }
+ if (!isset($_this->__benchmarks[$name])) {
+ return false;
+ }
+ $_this->__benchmarks[$name]['end'] = $end;
+ return true;
+ }
+/**
+ * Get all timers that have been started and stopped.
+ * Calculates elapsed time for each timer. If clear is true, will delete existing timers
+ *
+ * @param bool $clear false
+ * @return array
+ * @access public
+ **/
+ function getTimers($clear = false) {
+ $_this =& DebugKitDebugger::getInstance();
+ $start = DebugKitDebugger::requestStartTime();
+ $now = getMicrotime();
+
+ $times = array();
+ if (!empty($_this->__benchmarks)) {
+ $firstTimer = current($_this->__benchmarks);
+ $_end = $firstTimer['start'];
+ } else {
+ $_end = $now;
+ }
+ $times['Core Processing (Derived)'] = array(
+ 'message' => __d('debug_kit', 'Core Processing (Derived)', true),
+ 'start' => 0,
+ 'end' => $_end - $start,
+ 'time' => round($_end - $start, 6),
+ 'named' => null
+ );
+ foreach ($_this->__benchmarks as $name => $timer) {
+ if (!isset($timer['end'])) {
+ $timer['end'] = $now;
+ }
+ $times[$name] = array_merge($timer, array(
+ 'start' => $timer['start'] - $start,
+ 'end' => $timer['end'] - $start,
+ 'time' => DebugKitDebugger::elapsedTime($name)
+ ));
+ }
+ if ($clear) {
+ $_this->__benchmarks = array();
+ }
+ return $times;
+ }
+/**
+ * Clear all existing timers
+ *
+ * @return bool true
+ **/
+ function clearTimers() {
+ $_this =& DebugKitDebugger::getInstance();
+ $_this->__benchmarks = array();
+ return true;
+ }
+/**
+ * Get the difference in time between the timer start and timer end.
+ *
+ * @param $name string the name of the timer you want elapsed time for.
+ * @param $precision int the number of decimal places to return, defaults to 5.
+ * @return float number of seconds elapsed for timer name, 0 on missing key
+ * @static
+ **/
+ function elapsedTime($name = 'default', $precision = 5) {
+ $_this =& DebugKitDebugger::getInstance();
+ if (!isset($_this->__benchmarks[$name]['start']) || !isset($_this->__benchmarks[$name]['end'])) {
+ return 0;
+ }
+ return round($_this->__benchmarks[$name]['end'] - $_this->__benchmarks[$name]['start'], $precision);
+ }
+/**
+ * Get the total execution time until this point
+ *
+ * @access public
+ * @return float elapsed time in seconds since script start.
+ * @static
+ */
+ function requestTime() {
+ $start = DebugKitDebugger::requestStartTime();
+ $now = getMicroTime();
+ return ($now - $start);
+ }
+/**
+ * get the time the current request started.
+ *
+ * @access public
+ * @return float time of request start
+ * @static
+ */
+ function requestStartTime() {
+ if (defined('TIME_START')) {
+ $startTime = TIME_START;
+ } else if (isset($GLOBALS['TIME_START'])) {
+ $startTime = $GLOBALS['TIME_START'];
+ } else {
+ $startTime = env('REQUEST_TIME');
+ }
+ return $startTime;
+ }
+/**
+ * get current memory usage
+ *
+ * @return integer number of bytes ram currently in use. 0 if memory_get_usage() is not available.
+ * @static
+ **/
+ function getMemoryUse() {
+ if (!function_exists('memory_get_usage')) {
+ return 0;
+ }
+ return memory_get_usage();
+ }
+/**
+ * Get peak memory use
+ *
+ * @return integer peak memory use (in bytes). Returns 0 if memory_get_peak_usage() is not available
+ * @static
+ **/
+ function getPeakMemoryUse() {
+ if (!function_exists('memory_get_peak_usage')) {
+ return 0;
+ }
+ return memory_get_peak_usage();
+ }
+/**
+ * Stores a memory point in the internal tracker.
+ * Takes a optional message name which can be used to identify the memory point.
+ * If no message is supplied a debug_backtrace will be done to identifty the memory point.
+ * If you don't have memory_get_xx methods this will not work.
+ *
+ * @param string $message Message to identify this memory point.
+ * @return boolean
+ **/
+ function setMemoryPoint($message = null) {
+ $memoryUse = DebugKitDebugger::getMemoryUse();
+ if (!$message) {
+ $named = false;
+ $trace = debug_backtrace();
+ $message = Debugger::trimpath($trace[0]['file']) . ' line ' . $trace[0]['line'];
+ }
+ $self =& DebugKitDebugger::getInstance();
+ if (isset($self->__memoryPoints[$message])) {
+ $originalMessage = $message;
+ $i = 1;
+ while (isset($self->__memoryPoints[$message])) {
+ $i++;
+ $message = $originalMessage . ' #' . $i;
+ }
+ }
+ $self->__memoryPoints[$message] = $memoryUse;
+ return true;
+ }
+/**
+ * Get all the stored memory points
+ *
+ * @param boolean $clear Whether you want to clear the memory points as well. Defaults to false.
+ * @return array Array of memory marks stored so far.
+ **/
+ function getMemoryPoints($clear = false) {
+ $self =& DebugKitDebugger::getInstance();
+ $marks = $self->__memoryPoints;
+ if ($clear) {
+ $self->__memoryPoints = array();
+ }
+ return $marks;
+ }
+/**
+ * Clear out any existing memory points
+ *
+ * @return void
+ **/
+ function clearMemoryPoints() {
+ $self =& DebugKitDebugger::getInstance();
+ $self->__memoryPoints = array();
+ }
+/**
+ * Handles object conversion to debug string.
+ *
+ * @param string $var Object to convert
+ * @access protected
+ */
+ function _output($data = array()) {
+ extract($data);
+ if (is_array($level)) {
+ $error = $level['error'];
+ $code = $level['code'];
+ if (isset($level['helpID'])) {
+ $helpID = $level['helpID'];
+ } else {
+ $helpID = '';
+ }
+ $description = $level['description'];
+ $file = $level['file'];
+ $line = $level['line'];
+ $context = $level['context'];
+ $level = $level['level'];
+ }
+ $files = $this->trace(array('start' => 2, 'format' => 'points'));
+ $listing = $this->excerpt($files[0]['file'], $files[0]['line'] - 1, 1);
+ $trace = $this->trace(array('start' => 2, 'depth' => '20'));
+
+ if ($this->_outputFormat == 'fb') {
+ $kontext = array();
+ foreach ((array)$context as $var => $value) {
+ $kontext[] = "\${$var}\t=\t" . $this->exportVar($value, 1);
+ }
+ $this->_fireError($error, $code, $description, $file, $line, $trace, $kontext);
+ } else {
+ $data = compact(
+ 'level', 'error', 'code', 'helpID', 'description', 'file', 'path', 'line', 'context'
+ );
+ echo parent::_output($data);
+ }
+ }
+/**
+ * Create a FirePHP error message
+ *
+ * @param string $error Name of error
+ * @param string $code Code of error
+ * @param string $description Description of error
+ * @param string $file File error occured in
+ * @param string $line Line error occured on
+ * @param string $trace Stack trace at time of error
+ * @param string $context context of error
+ * @return void
+ * @access protected
+ */
+ function _fireError($error, $code, $description, $file, $line, $trace, $context) {
+ $name = $error . ' - ' . $description;
+ $message = "$error $code $description on line: $line in file: $file";
+ FireCake::group($name);
+ FireCake::error($message, $name);
+ FireCake::log($context, 'Context');
+ FireCake::log($trace, 'Trace');
+ FireCake::groupEnd();
+ }
+}
+
+
+Debugger::invoke(DebugKitDebugger::getInstance('DebugKitDebugger'));
+Debugger::getInstance('DebugKitDebugger');
diff --git a/code/ryzom/tools/server/www/webtt/plugins/debug_kit/vendors/fire_cake.php b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/vendors/fire_cake.php
new file mode 100644
index 000000000..1b7835ccb
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/vendors/fire_cake.php
@@ -0,0 +1,546 @@
+ 10,
+ 'maxArrayDepth' => 20,
+ 'useNativeJsonEncode' => true,
+ 'includeLineNumbers' => true,
+ );
+/**
+ * Message Levels for messages sent via FirePHP
+ *
+ * @var array
+ */
+ var $_levels = array(
+ 'log' => 'LOG',
+ 'info' => 'INFO',
+ 'warn' => 'WARN',
+ 'error' => 'ERROR',
+ 'dump' => 'DUMP',
+ 'trace' => 'TRACE',
+ 'exception' => 'EXCEPTION',
+ 'table' => 'TABLE',
+ 'groupStart' => 'GROUP_START',
+ 'groupEnd' => 'GROUP_END',
+ );
+
+ var $_version = '0.2.1';
+/**
+ * internal messageIndex counter
+ *
+ * @var int
+ * @access protected
+ */
+ var $_messageIndex = 1;
+/**
+ * stack of objects encoded by stringEncode()
+ *
+ * @var array
+ **/
+ var $_encodedObjects = array();
+/**
+ * methodIndex to include in tracebacks when using includeLineNumbers
+ *
+ * @var array
+ **/
+ var $_methodIndex = array('info', 'log', 'warn', 'error', 'table', 'trace');
+/**
+ * FireCake output status
+ *
+ * @var bool
+ **/
+ var $_enabled = true;
+/**
+ * get Instance of the singleton
+ *
+ * @param string $class Class instance to store in the singleton. Used with subclasses and Tests.
+ * @access public
+ * @static
+ * @return void
+ */
+ function &getInstance($class = null) {
+ static $instance = array();
+ if (!empty($class)) {
+ if (!$instance || strtolower($class) != strtolower(get_class($instance[0]))) {
+ $instance[0] =& new $class();
+ $instance[0]->setOptions();
+ }
+ }
+ if (!isset($instance[0]) || !$instance[0]) {
+ $instance[0] =& new FireCake();
+ $instance[0]->setOptions();
+ }
+ return $instance[0];
+ }
+/**
+ * setOptions
+ *
+ * @param array $options Array of options to set.
+ * @access public
+ * @static
+ * @return void
+ */
+ function setOptions($options = array()) {
+ $_this =& FireCake::getInstance();
+ if (empty($_this->options)) {
+ $_this->options = array_merge($_this->_defaultOptions, $options);
+ } else {
+ $_this->options = array_merge($_this->options, $options);
+ }
+ }
+/**
+ * Return boolean based on presence of FirePHP extension
+ *
+ * @access public
+ * @return boolean
+ **/
+ function detectClientExtension() {
+ $ua = FireCake::getUserAgent();
+ if (!preg_match('/\sFirePHP\/([\.|\d]*)\s?/si', $ua, $match) || !version_compare($match[1], '0.0.6', '>=')) {
+ return false;
+ }
+ return true;
+ }
+/**
+ * Get the Current UserAgent
+ *
+ * @access public
+ * @static
+ * @return string UserAgent string of active client connection
+ **/
+ function getUserAgent() {
+ return env('HTTP_USER_AGENT');
+ }
+/**
+ * Disable FireCake output
+ * All subsequent output calls will not be run.
+ *
+ * @return void
+ **/
+ function disable() {
+ $_this =& FireCake::getInstance();
+ $_this->_enabled = false;
+ }
+/**
+ * Enable FireCake output
+ *
+ * @return void
+ **/
+ function enable() {
+ $_this =& FireCake::getInstance();
+ $_this->_enabled = true;
+ }
+/**
+ * Convenience wrapper for LOG messages
+ *
+ * @param string $message Message to log
+ * @param string $label Label for message (optional)
+ * @access public
+ * @static
+ * @return void
+ */
+ function log($message, $label = null) {
+ FireCake::fb($message, $label, 'log');
+ }
+/**
+ * Convenience wrapper for WARN messages
+ *
+ * @param string $message Message to log
+ * @param string $label Label for message (optional)
+ * @access public
+ * @static
+ * @return void
+ */
+ function warn($message, $label = null) {
+ FireCake::fb($message, $label, 'warn');
+ }
+/**
+ * Convenience wrapper for INFO messages
+ *
+ * @param string $message Message to log
+ * @param string $label Label for message (optional)
+ * @access public
+ * @static
+ * @return void
+ */
+ function info($message, $label = null) {
+ FireCake::fb($message, $label, 'info');
+ }
+/**
+ * Convenience wrapper for ERROR messages
+ *
+ * @param string $message Message to log
+ * @param string $label Label for message (optional)
+ * @access public
+ * @static
+ * @return void
+ */
+ function error($message, $label = null) {
+ FireCake::fb($message, $label, 'error');
+ }
+/**
+ * Convenience wrapper for TABLE messages
+ *
+ * @param string $message Message to log
+ * @param string $label Label for message (optional)
+ * @access public
+ * @static
+ * @return void
+ */
+ function table($label, $message) {
+ FireCake::fb($message, $label, 'table');
+ }
+/**
+ * Convenience wrapper for DUMP messages
+ *
+ * @param string $message Message to log
+ * @param string $label Unique label for message
+ * @access public
+ * @static
+ * @return void
+ */
+ function dump($label, $message) {
+ FireCake::fb($message, $label, 'dump');
+ }
+/**
+ * Convenience wrapper for TRACE messages
+ *
+ * @param string $label Label for message (optional)
+ * @access public
+ * @return void
+ */
+ function trace($label) {
+ FireCake::fb($label, 'trace');
+ }
+/**
+ * Convenience wrapper for GROUP messages
+ * Messages following the group call will be nested in a group block
+ *
+ * @param string $label Label for group (optional)
+ * @access public
+ * @return void
+ */
+ function group($label) {
+ FireCake::fb(null, $label, 'groupStart');
+ }
+/**
+ * Convenience wrapper for GROUPEND messages
+ * Closes a group block
+ *
+ * @param string $label Label for group (optional)
+ * @access public
+ * @return void
+ */
+ function groupEnd() {
+ FireCake::fb(null, null, 'groupEnd');
+ }
+/**
+ * fb - Send messages with FireCake to FirePHP
+ *
+ * Much like FirePHP's fb() this method can be called with various parameter counts
+ * fb($message) - Just send a message defaults to LOG type
+ * fb($message, $type) - Send a message with a specific type
+ * fb($message, $label, $type) - Send a message with a custom label and type.
+ *
+ * @param mixed $message Message to output. For other parameters see usage above.
+ * @static
+ * @return void
+ **/
+ function fb($message) {
+ $_this =& FireCake::getInstance();
+
+ if (headers_sent($filename, $linenum)) {
+ trigger_error(sprintf(__d('debug_kit', 'Headers already sent in %s on line %s. Cannot send log data to FirePHP.', true), $filename, $linenum), E_USER_WARNING);
+ return false;
+ }
+ if (!$_this->_enabled || !$_this->detectClientExtension()) {
+ return false;
+ }
+
+ $args = func_get_args();
+ $type = $label = null;
+ switch (count($args)) {
+ case 1:
+ $type = $_this->_levels['log'];
+ break;
+ case 2:
+ $type = $args[1];
+ break;
+ case 3:
+ $type = $args[2];
+ $label = $args[1];
+ break;
+ default:
+ trigger_error(__d('debug_kit', 'Incorrect parameter count for FireCake::fb()', true), E_USER_WARNING);
+ return false;
+ }
+ if (isset($_this->_levels[$type])) {
+ $type = $_this->_levels[$type];
+ } else {
+ $type = $_this->_levels['log'];
+ }
+
+ $meta = array();
+ $skipFinalObjectEncode = false;
+ if ($type == $_this->_levels['trace']) {
+ $trace = debug_backtrace();
+ if (!$trace) {
+ return false;
+ }
+ $message = $_this->_parseTrace($trace, $args[0]);
+ $skipFinalObjectEncode = true;
+ }
+
+ if ($_this->options['includeLineNumbers']) {
+ if (!isset($meta['file']) || !isset($meta['line'])) {
+ $trace = debug_backtrace();
+ for ($i = 0, $len = count($trace); $i < $len ; $i++) {
+ $keySet = (isset($trace[$i]['class']) && isset($trace[$i]['function']));
+ $selfCall = ($keySet &&
+ strtolower($trace[$i]['class']) == 'firecake' &&
+ in_array($trace[$i]['function'], $_this->_methodIndex)
+ );
+ if ($selfCall) {
+ $meta['File'] = isset($trace[$i]['file']) ? Debugger::trimPath($trace[$i]['file']) : '';
+ $meta['Line'] = isset($trace[$i]['line']) ? $trace[$i]['line'] : '';
+ break;
+ }
+ }
+ }
+ }
+
+ $structureIndex = 1;
+ if ($type == $_this->_levels['dump']) {
+ $structureIndex = 2;
+ $_this->_sendHeader('X-Wf-1-Structure-2','http://meta.firephp.org/Wildfire/Structure/FirePHP/Dump/0.1');
+ } else {
+ $_this->_sendHeader('X-Wf-1-Structure-1','http://meta.firephp.org/Wildfire/Structure/FirePHP/FirebugConsole/0.1');
+ }
+
+ $_this->_sendHeader('X-Wf-Protocol-1', 'http://meta.wildfirehq.org/Protocol/JsonStream/0.2');
+ $_this->_sendHeader('X-Wf-1-Plugin-1', 'http://meta.firephp.org/Wildfire/Plugin/FirePHP/Library-FirePHPCore/'. $_this->_version);
+ if ($type == $_this->_levels['groupStart']) {
+ $meta['Collapsed'] = 'true';
+ }
+ if ($type == $_this->_levels['dump']) {
+ $dump = $_this->jsonEncode($message);
+ $msg = '{"' . $label .'":' . $dump .'}';
+ } else {
+ $meta['Type'] = $type;
+ if ($label !== null) {
+ $meta['Label'] = $label;
+ }
+ $msg = '[' . $_this->jsonEncode($meta) . ',' . $_this->jsonEncode($message, $skipFinalObjectEncode).']';
+ }
+
+ $lines = explode("\n", chunk_split($msg, 5000, "\n"));
+
+ foreach ($lines as $i => $line) {
+ if (empty($line)) {
+ continue;
+ }
+ $header = 'X-Wf-1-' . $structureIndex . '-1-' . $_this->_messageIndex;
+ if (count($lines) > 2) {
+ $first = ($i == 0) ? strlen($msg) : '';
+ $end = ($i < count($lines) - 2) ? '\\' : '';
+ $message = $first . '|' . $line . '|' . $end;
+ $_this->_sendHeader($header, $message);
+ } else {
+ $_this->_sendHeader($header, strlen($line) . '|' . $line . '|');
+ }
+ $_this->_messageIndex++;
+ if ($_this->_messageIndex > 99999) {
+ trigger_error(__d('debug_kit', 'Maximum number (99,999) of messages reached!', true), E_USER_WARNING);
+ }
+ }
+ $_this->_sendHeader('X-Wf-1-Index', $_this->_messageIndex - 1);
+ return true;
+ }
+/**
+ * Parse a debug backtrace
+ *
+ * @param array $trace Debug backtrace output
+ * @access protected
+ * @return array
+ **/
+ function _parseTrace($trace, $messageName) {
+ $message = array();
+ for ($i = 0, $len = count($trace); $i < $len ; $i++) {
+ $keySet = (isset($trace[$i]['class']) && isset($trace[$i]['function']));
+ $selfCall = ($keySet && $trace[$i]['class'] == 'FireCake');
+ if (!$selfCall) {
+ $message = array(
+ 'Class' => isset($trace[$i]['class']) ? $trace[$i]['class'] : '',
+ 'Type' => isset($trace[$i]['type']) ? $trace[$i]['type'] : '',
+ 'Function' => isset($trace[$i]['function']) ? $trace[$i]['function'] : '',
+ 'Message' => $messageName,
+ 'File' => isset($trace[$i]['file']) ? Debugger::trimPath($trace[$i]['file']) : '',
+ 'Line' => isset($trace[$i]['line']) ? $trace[$i]['line'] : '',
+ 'Args' => isset($trace[$i]['args']) ? $this->stringEncode($trace[$i]['args']) : '',
+ 'Trace' => $this->_escapeTrace(array_splice($trace, $i + 1))
+ );
+ break;
+ }
+ }
+ return $message;
+ }
+/**
+ * Fix a trace for use in output
+ *
+ * @param mixed $trace Trace to fix
+ * @access protected
+ * @static
+ * @return string
+ **/
+ function _escapeTrace($trace) {
+ for ($i = 0, $len = count($trace); $i < $len; $i++) {
+ if (isset($trace[$i]['file'])) {
+ $trace[$i]['file'] = Debugger::trimPath($trace[$i]['file']);
+ }
+ if (isset($trace[$i]['args'])) {
+ $trace[$i]['args'] = $this->stringEncode($trace[$i]['args']);
+ }
+ }
+ return $trace;
+ }
+/**
+ * Encode non string objects to string.
+ * Filter out recursion, so no errors are raised by json_encode or $javascript->object()
+ *
+ * @param mixed $object Object or variable to encode to string.
+ * @param int $objectDepth Current Depth in object chains.
+ * @param int $arrayDepth Current Depth in array chains.
+ * @static
+ * @return void
+ **/
+ function stringEncode($object, $objectDepth = 1, $arrayDepth = 1) {
+ $_this =& FireCake::getInstance();
+ $return = array();
+ if (is_resource($object)) {
+ return '** ' . (string)$object . '**';
+ }
+ if (is_object($object)) {
+ if ($objectDepth == $_this->options['maxObjectDepth']) {
+ return '** Max Object Depth (' . $_this->options['maxObjectDepth'] . ') **';
+ }
+ foreach ($_this->_encodedObjects as $encoded) {
+ if ($encoded === $object) {
+ return '** Recursion (' . get_class($object) . ') **';
+ }
+ }
+ $_this->_encodedObjects[] =& $object;
+
+ $return['__className'] = $class = get_class($object);
+ $properties = (array)$object;
+ foreach ($properties as $name => $property) {
+ $return[$name] = FireCake::stringEncode($property, 1, $objectDepth + 1);
+ }
+ array_pop($_this->_encodedObjects);
+ }
+ if (is_array($object)) {
+ if ($arrayDepth == $_this->options['maxArrayDepth']) {
+ return '** Max Array Depth ('. $_this->options['maxArrayDepth'] . ') **';
+ }
+ foreach ($object as $key => $value) {
+ $return[$key] = FireCake::stringEncode($value, 1, $arrayDepth + 1);
+ }
+ }
+ if (is_string($object) || is_numeric($object) || is_bool($object) || is_null($object)) {
+ return $object;
+ }
+ return $return;
+ }
+/**
+ * Encode an object into JSON
+ *
+ * @param mixed $object Object or array to json encode
+ * @param boolean $doIt
+ * @access public
+ * @static
+ * @return string
+ **/
+ function jsonEncode($object, $skipEncode = false) {
+ $_this =& FireCake::getInstance();
+ if (!$skipEncode) {
+ $object = FireCake::stringEncode($object);
+ }
+
+ if (function_exists('json_encode') && $_this->options['useNativeJsonEncode']) {
+ return json_encode($object);
+ } else {
+ return FireCake::_jsonEncode($object);
+ }
+ }
+/**
+ * jsonEncode Helper method for PHP4 compatibility
+ *
+ * @param mixed $object Something to encode
+ * @access protected
+ * @static
+ * @return string
+ **/
+ function _jsonEncode($object) {
+ if (!class_exists('JavascriptHelper')) {
+ App::import('Helper', 'Javascript');
+ }
+ $javascript =& new JavascriptHelper();
+ $javascript->useNative = false;
+ if (is_string($object)) {
+ return '"' . $javascript->escapeString($object) . '"';
+ }
+ return $javascript->object($object);
+ }
+/**
+ * Send Headers - write headers.
+ *
+ * @access protected
+ * @return void
+ **/
+ function _sendHeader($name, $value) {
+ header($name . ': ' . $value);
+ }
+}
diff --git a/code/ryzom/tools/server/www/webtt/plugins/debug_kit/vendors/shells/benchmark.php b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/vendors/shells/benchmark.php
new file mode 100644
index 000000000..eb2a3dcc4
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/vendors/shells/benchmark.php
@@ -0,0 +1,167 @@
+args) || count($this->args) > 1) {
+ return $this->help();
+ }
+
+ $url = $this->args[0];
+ $defaults = array('t' => 100, 'n' => 10);
+ $options = array_merge($defaults, $this->params);
+ $times = array();
+
+ $this->out(String::insert(__d('debug_kit', '-> Testing :url', true), compact('url')));
+ $this->out("");
+ for ($i = 0; $i < $options['n']; $i++) {
+ if (floor($options['t'] - array_sum($times)) <= 0 || $options['n'] <= 1) {
+ break;
+ }
+
+ $start = microtime(true);
+ file_get_contents($url);
+ $stop = microtime(true);
+
+ $times[] = $stop - $start;
+ }
+ $this->_results($times);
+ }
+/**
+ * Prints calculated results
+ *
+ * @param array $times Array of time values
+ * @return void
+ * @access protected
+ */
+ function _results($times) {
+ $duration = array_sum($times);
+ $requests = count($times);
+
+ $this->out(String::insert(__d('debug_kit', 'Total Requests made: :requests', true), compact('requests')));
+ $this->out(String::insert(__d('debug_kit', 'Total Time elapsed: :duration (seconds)', true), compact('duration')));
+
+ $this->out("");
+
+ $this->out(String::insert(__d('debug_kit', 'Requests/Second: :rps req/sec', true), array(
+ 'rps' => round($requests / $duration, 3)
+ )));
+
+ $this->out(String::insert(__d('debug_kit', 'Average request time: :average-time seconds', true), array(
+ 'average-time' => round($duration / $requests, 3)
+ )));
+
+ $this->out(String::insert(__d('debug_kit', 'Standard deviation of average request time: :std-dev', true), array(
+ 'std-dev' => round($this->_deviation($times, true), 3)
+ )));
+
+ $this->out(String::insert(__d('debug_kit', 'Longest/shortest request: :longest sec/:shortest sec', true), array(
+ 'longest' => round(max($times), 3),
+ 'shortest' => round(min($times), 3)
+ )));
+
+ $this->out("");
+
+ }
+/**
+ * One-pass, numerically stable calculation of population variance.
+ *
+ * Donald E. Knuth (1998).
+ * The Art of Computer Programming, volume 2: Seminumerical Algorithms, 3rd edn.,
+ * p. 232. Boston: Addison-Wesley.
+ *
+ * @param array $times Array of values
+ * @param boolean $sample If true, calculates an unbiased estimate of the population
+ * variance from a finite sample.
+ * @return float Variance
+ * @access protected
+ */
+ function _variance($times, $sample = true) {
+ $n = $mean = $M2 = 0;
+
+ foreach($times as $time){
+ $n += 1;
+ $delta = $time - $mean;
+ $mean = $mean + $delta/$n;
+ $M2 = $M2 + $delta*($time - $mean);
+ }
+
+ if ($sample) $n -= 1;
+
+ return $M2/$n;
+ }
+/**
+ * Calculate the standard deviation.
+ *
+ * @param array $times Array of values
+ * @return float Standard deviation
+ * @access protected
+ */
+ function _deviation($times, $sample = true) {
+ return sqrt($this->_variance($times, $sample));
+ }
+/**
+ * Help for Benchmark shell
+ *
+ * @return void
+ * @access public
+ */
+ function help() {
+ $this->out(__d('debug_kit', "DebugKit Benchmark Shell", true));
+ $this->out("");
+ $this->out(__d('debug_kit', "\tAllows you to obtain some rough benchmarking statistics \n\tabout a fully qualified URL.", true));
+ $this->out("");
+ $this->out(__d('debug_kit', "\tUse:", true));
+ $this->out(__d('debug_kit', "\t\tcake benchmark [-n iterations] [-t timeout] url", true));
+ $this->out("");
+ $this->out(__d('debug_kit', "\tParams:", true));
+ $this->out(__d('debug_kit', "\t\t-n Number of iterations to perform. Defaults to 10. \n\t\t Must be an integer.", true));
+ $this->out(__d('debug_kit', "\t\t-t Maximum total time for all iterations, in seconds. \n\t\t Defaults to 100. Must be an integer.", true));
+ $this->out("");
+ $this->out(__d('debug_kit', "\tIf a single iteration takes more than the \n\ttimeout specified, only one request will be made.", true));
+ $this->out("");
+ $this->out(__d('debug_kit', "\tExample Use:", true));
+ $this->out(__d('debug_kit', "\t\tcake benchmark -n 10 -t 100 http://localhost/testsite", true));
+ $this->out("");
+ $this->out(__d('debug_kit', "\tNote that this benchmark does not include browser render time", true));
+ $this->out("");
+ $this->hr();
+ $this->out("");
+ }
+}
+
diff --git a/code/ryzom/tools/server/www/webtt/plugins/debug_kit/vendors/shells/whitespace.php b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/vendors/shells/whitespace.php
new file mode 100644
index 000000000..d5185d454
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/vendors/shells/whitespace.php
@@ -0,0 +1,69 @@
+findRecursive('.*\.php');
+ $this->out("Checking *.php in ".ROOT);
+ foreach($r as $file) {
+ $c = file_get_contents($file);
+ if (preg_match('/^[\n\r|\n\r|\n|\r|\s]+\<\?php/',$c)) {
+ $this->out('!!!contains leading whitespaces: '.$this->shortPath($file));
+ }
+ if (preg_match('/\?\>[\n\r|\n\r|\n|\r|\s]+$/',$c)) {
+ $this->out('!!!contains trailing whitespaces: '.$this->shortPath($file));
+ }
+ }
+ }
+
+/**
+ * Much like main() except files are modified. Be sure to have
+ * backups or use version control.
+ *
+ * @return void
+ */
+ function trim() {
+ $siteRoot = new Folder(ROOT);
+
+ $r = $siteRoot->findRecursive('.*\.php');
+ $this->out("Checking *.php in ".ROOT);
+ foreach($r as $file) {
+ $c = file_get_contents($file);
+ if (preg_match('/^[\n\r|\n\r|\n|\r|\s]+\<\?php/', $c) || preg_match('/\?\>[\n\r|\n\r|\n|\r|\s]+$/', $c)) {
+ $this->out('trimming' . $this->shortPath($file));
+ $c = preg_replace('/^[\n\r|\n\r|\n|\r|\s]+\<\?php/', '[\n\r|\n\r|\n|\r|\s]+$/', '?>', $c);
+ file_put_contents($file, $c);
+ }
+ }
+ }
+}
diff --git a/code/ryzom/tools/server/www/webtt/plugins/debug_kit/views/debug.php b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/views/debug.php
new file mode 100644
index 000000000..43601e72d
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/views/debug.php
@@ -0,0 +1,100 @@
+params['url']['ext']) && $this->params['url']['ext'] === 'html') ||
+ !isset($this->params['url']['ext'])
+ );
+ if ($isHtml) {
+ $out .= sprintf("\n", __d('debug_kit', 'Starting to render', true), $name);
+ }
+ $out .= parent::element($name, $params, $loadHelpers);
+ if ($isHtml) {
+ $out .= sprintf("\n\n", __d('debug_kit', 'Finished', true), $name);
+ }
+ return $out;
+ }
+
+/**
+ * Renders view for given action and layout. If $file is given, that is used
+ * for a view filename (e.g. customFunkyView.ctp).
+ * Adds timers, for all subsequent rendering, and injects the debugKit toolbar.
+ *
+ * @param string $action Name of action to render for
+ * @param string $layout Layout to use
+ * @param string $file Custom filename for view
+ * @return string Rendered Element
+ */
+ function render($action = null, $layout = null, $file = null) {
+ DebugKitDebugger::startTimer('viewRender', __d('debug_kit', 'Rendering View', true));
+
+ $out = parent::render($action, $layout, $file);
+
+ DebugKitDebugger::stopTimer('viewRender');
+ DebugKitDebugger::stopTimer('controllerRender');
+ DebugKitDebugger::setMemoryPoint(__d('debug_kit', 'View render complete', true));
+
+ if (empty($this->params['requested']) && isset($this->loaded['toolbar'])) {
+ $backend = $this->loaded['toolbar']->getName();
+ $this->loaded['toolbar']->{$backend}->send();
+ }
+ if (empty($this->output)) {
+ return $out;
+ }
+ return $this->output;
+ }
+}
diff --git a/code/ryzom/tools/server/www/webtt/plugins/debug_kit/views/elements/debug_toolbar.ctp b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/views/elements/debug_toolbar.ctp
new file mode 100644
index 000000000..327f0eb85
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/views/elements/debug_toolbar.ctp
@@ -0,0 +1,58 @@
+
+
diff --git a/code/ryzom/tools/server/www/webtt/plugins/debug_kit/views/elements/history_panel.ctp b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/views/elements/history_panel.ctp
new file mode 100644
index 000000000..8f4cdab4d
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/views/elements/history_panel.ctp
@@ -0,0 +1,195 @@
+
+
+
+
+
+
+
+ link(__d('debug_kit', 'Restore to current request', true),
+ '#', array('class' => 'history-link', 'id' => 'history-restore-current')); ?>
+
+
+ link($previous['title'], $previous['url'], array('class' => 'history-link')); ?>
+
+
+
+
+
\ No newline at end of file
diff --git a/code/ryzom/tools/server/www/webtt/plugins/debug_kit/views/elements/log_panel.ctp b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/views/elements/log_panel.ctp
new file mode 100644
index 000000000..1751df991
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/views/elements/log_panel.ctp
@@ -0,0 +1,40 @@
+
+
+
+ $logs): ?>
+
+ 0):
+ $headers = array(__d('debug_kit', 'Time', true), __d('debug_kit', 'Message', true));
+ $rows = array();
+ for ($i = 0; $i < $len; $i += 1):
+ $rows[] = array(
+ $logs[$i][0], h($logs[$i][1])
+ );
+ endfor;
+ echo $toolbar->table($rows, $headers, array('title' => $logName));
+ else: ?>
+
+
+
+
\ No newline at end of file
diff --git a/code/ryzom/tools/server/www/webtt/plugins/debug_kit/views/elements/request_panel.ctp b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/views/elements/request_panel.ctp
new file mode 100644
index 000000000..310090ea9
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/views/elements/request_panel.ctp
@@ -0,0 +1,36 @@
+
+
+Cake Params
+makeNeatArray($content['params']); ?>
+
+$_GET
+makeNeatArray($content['get']); ?>
+
+Cookie
+
+ makeNeatArray($content['cookie']); ?>
+
+ To view Cookies, add CookieComponent to Controller
+
+
+
+makeNeatArray($content['currentRoute']); ?>
\ No newline at end of file
diff --git a/code/ryzom/tools/server/www/webtt/plugins/debug_kit/views/elements/session_panel.ctp b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/views/elements/session_panel.ctp
new file mode 100644
index 000000000..c729a8273
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/views/elements/session_panel.ctp
@@ -0,0 +1,22 @@
+
+
+makeNeatArray($content); ?>
\ No newline at end of file
diff --git a/code/ryzom/tools/server/www/webtt/plugins/debug_kit/views/elements/sql_log_panel.ctp b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/views/elements/sql_log_panel.ctp
new file mode 100755
index 000000000..148c694dc
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/views/elements/sql_log_panel.ctp
@@ -0,0 +1,105 @@
+readCache('sql_log', $this->params['pass'][0]);
+}
+?>
+
+
+ $explain): ?>
+
+
+ getQueryLogs($dbName, array(
+ 'explain' => $explain, 'threshold' => $content['threshold']
+ ));
+ else:
+ $queryLog = $content[$dbName];
+ endif;
+ echo $toolbar->table($queryLog, $headers, array('title' => 'SQL Log ' . $dbName));
+ ?>
+
+
+
+
+message('Warning', __d('debug_kit', 'No active database connections', true));
+endif; ?>
+
+
\ No newline at end of file
diff --git a/code/ryzom/tools/server/www/webtt/plugins/debug_kit/views/elements/timer_panel.ctp b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/views/elements/timer_panel.ctp
new file mode 100644
index 000000000..c5c010937
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/views/elements/timer_panel.ctp
@@ -0,0 +1,108 @@
+readCache('timer', $this->params['pass'][0]);
+ if (is_array($content)):
+ extract($content);
+ endif;
+endif;
+?>
+
+
+
+ message(__d('debug_kit', 'Peak Memory Use', true), $number->toReadableSize($peakMemory)); ?>
+
+
+ $value):
+ $rows[] = array($key, $number->toReadableSize($value));
+ endforeach;
+
+ echo $toolbar->table($rows, $headers);
+ ?>
+
+
+
+
+
+ precision($requestTime * 1000, 0)); ?>
+ message(__d('debug_kit', 'Total Request Time:', true), $totalTime)?>
+
+ $timeInfo):
+ $indent = 0;
+ for ($j = 0; $j < $i; $j++) {
+ if (($values[$j]['end'] > $timeInfo['start']) && ($values[$j]['end']) > ($timeInfo['end'])) {
+ $indent++;
+ }
+ }
+ $indent = str_repeat(' » ', $indent);
+ $rows[] = array(
+ $indent . $timeInfo['message'],
+ $number->precision($timeInfo['time'] * 1000, 2),
+ $simpleGraph->bar(
+ $number->precision($timeInfo['time'] * 1000, 2),
+ $number->precision($timeInfo['start'] * 1000, 2),
+ array(
+ 'max' => $maxTime * 1000,
+ 'requestTime' => $requestTime * 1000,
+ )
+ )
+ );
+ $i++;
+endforeach;
+
+if (strtolower($toolbar->getName()) == 'firephptoolbar'):
+ for ($i = 0, $len = count($rows); $i < $len; $i++):
+ unset($rows[$i][2]);
+ endfor;
+ unset($headers[2]);
+endif;
+
+echo $toolbar->table($rows, $headers, array('title' => 'Timers'));
+
+if (!isset($debugKitInHistoryMode)):
+ $toolbar->writeCache('timer', compact('timers', 'currentMemory', 'peakMemory', 'requestTime'));
+endif;
+?>
+
\ No newline at end of file
diff --git a/code/ryzom/tools/server/www/webtt/plugins/debug_kit/views/elements/variables_panel.ctp b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/views/elements/variables_panel.ctp
new file mode 100644
index 000000000..3be537d6a
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/views/elements/variables_panel.ctp
@@ -0,0 +1,25 @@
+
+
+validationErrors'] = $this->validationErrors;
+$content['Loaded Helpers'] = array_keys($this->loaded);
+echo $toolbar->makeNeatArray($content); ?>
\ No newline at end of file
diff --git a/code/ryzom/tools/server/www/webtt/plugins/debug_kit/views/helpers/fire_php_toolbar.php b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/views/helpers/fire_php_toolbar.php
new file mode 100644
index 000000000..e8bb814af
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/views/helpers/fire_php_toolbar.php
@@ -0,0 +1,99 @@
+ 'firePHP', 'forceEnable' => false);
+/**
+ * send method
+ *
+ * @return void
+ * @access protected
+ */
+ function send() {
+ $view =& ClassRegistry::getObject('view');
+ $view->element('debug_toolbar', array('plugin' => 'debug_kit', 'disableTimer' => true));
+ }
+/**
+ * makeNeatArray.
+ *
+ * wraps FireCake::dump() allowing panel elements to continue functioning
+ *
+ * @param string $values
+ * @return void
+ */
+ function makeNeatArray($values) {
+ FireCake::info($values);
+ }
+/**
+ * Create a simple message
+ *
+ * @param string $label Label of message
+ * @param string $message Message content
+ * @return void
+ */
+ function message($label, $message) {
+ FireCake::log($message, $label);
+ }
+/**
+ * Generate a table with FireCake
+ *
+ * @param array $rows Rows to print
+ * @param array $headers Headers for table
+ * @param array $options Additional options and params
+ * @return void
+ */
+ function table($rows, $headers, $options = array()) {
+ $title = $headers[0];
+ if (isset($options['title'])) {
+ $title = $options['title'];
+ }
+ foreach ($rows as $i => $row) {
+ $rows[$i] = array_values($row);
+ }
+ array_unshift($rows, $headers);
+ FireCake::table($title, $rows);
+ }
+/**
+ * Start a panel which is a 'Group' in FirePHP
+ *
+ * @return void
+ **/
+ function panelStart($title, $anchor) {
+ FireCake::group($title);
+ }
+/**
+ * End a panel (Group)
+ *
+ * @return void
+ **/
+ function panelEnd() {
+ FireCake::groupEnd();
+ }
+}
diff --git a/code/ryzom/tools/server/www/webtt/plugins/debug_kit/views/helpers/html_toolbar.php b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/views/helpers/html_toolbar.php
new file mode 100755
index 000000000..f772870ce
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/views/helpers/html_toolbar.php
@@ -0,0 +1,191 @@
+ 'html', 'forceEnable' => false);
+/**
+ * Recursively goes through an array and makes neat HTML out of it.
+ *
+ * @param mixed $values Array to make pretty.
+ * @param int $openDepth Depth to add open class
+ * @param int $currentDepth current depth.
+ * @return string
+ **/
+ function makeNeatArray($values, $openDepth = 0, $currentDepth = 0) {
+ $className ="neat-array depth-$currentDepth";
+ if ($openDepth > $currentDepth) {
+ $className .= ' expanded';
+ }
+ $nextDepth = $currentDepth + 1;
+ $out = "";
+ if (!is_array($values)) {
+ if (is_bool($values)) {
+ $values = array($values);
+ }
+ if (is_null($values)) {
+ $values = array(null);
+ }
+ }
+ if (empty($values)) {
+ $values[] = '(empty)';
+ }
+ foreach ($values as $key => $value) {
+ $out .= '' . $key . ' ';
+ if ($value === null) {
+ $value = '(null)';
+ }
+ if ($value === false) {
+ $value = '(false)';
+ }
+ if ($value === true) {
+ $value = '(true)';
+ }
+ if (empty($value) && $value != 0) {
+ $value = '(empty)';
+ }
+
+ if (is_object($value)) {
+ $value = Set::reverse($value, true);
+ }
+
+ if (is_array($value) && !empty($value)) {
+ $out .= $this->makeNeatArray($value, $openDepth, $nextDepth);
+ } else {
+ $out .= h($value);
+ }
+ $out .= ' ';
+ }
+ $out .= ' ';
+ return $out;
+ }
+/**
+ * Create an HTML message
+ *
+ * @param string $label label content
+ * @param string $message message content
+ * @return string
+ */
+ function message($label, $message) {
+ return sprintf('%s %s
', $label, $message);
+ }
+/**
+ * Start a panel.
+ * make a link and anchor.
+ *
+ * @return void
+ **/
+ function panelStart($title, $anchor) {
+ $link = $this->Html->link($title, '#' . $anchor);
+ return $link;
+ }
+/**
+ * Create a table.
+ *
+ * @param array $rows Rows to make.
+ * @param array $headers Optional header row.
+ * @return string
+ */
+ function table($rows, $headers = array()) {
+ $out = '';
+ if (!empty($headers)) {
+ $out .= $this->Html->tableHeaders($headers);
+ }
+ $out .= $this->Html->tableCells($rows, array('class' => 'odd'), array('class' => 'even'), false, false);
+ $out .= '
';
+ return $out;
+ }
+/**
+ * send method
+ *
+ * @return void
+ * @access public
+ */
+ function send() {
+ if (!$this->settings['forceEnable'] && Configure::read('debug') == 0) {
+ return;
+ }
+ $view =& ClassRegistry::getObject('view');
+ $head = $this->Html->css('/debug_kit/css/debug_toolbar');
+ if (isset($view->viewVars['debugToolbarJavascript'])) {
+ foreach ($view->viewVars['debugToolbarJavascript'] as $script) {
+ if ($script) {
+ $head .= $this->Html->script($script);
+ }
+ }
+ }
+ if (preg_match('##', $view->output)) {
+ $view->output = preg_replace('##', $head . "\n", $view->output, 1);
+ }
+ $toolbar = $view->element('debug_toolbar', array('plugin' => 'debug_kit', 'disableTimer' => true));
+ if (preg_match('##', $view->output)) {
+ $view->output = preg_replace('##', $toolbar . "\n", $view->output, 1);
+ }
+ }
+/**
+ * Generates a SQL explain link for a given query
+ *
+ * @param string $sql SQL query string you want an explain link for.
+ * @return string Rendered Html link or '' if the query is not a select/describe
+ */
+ function explainLink($sql, $connection) {
+ if (!preg_match('/^(SELECT)/i', $sql)) {
+ return '';
+ }
+ App::import('Core', 'Security');
+ $hash = Security::hash($sql . $connection, null, true);
+ $url = array(
+ 'plugin' => 'debug_kit',
+ 'controller' => 'toolbar_access',
+ 'action' => 'sql_explain'
+ );
+ foreach (Router::prefixes() as $prefix) {
+ $url[$prefix] = false;
+ }
+ $this->explainLinkUid = (isset($this->explainLinkUid) ? $this->explainLinkUid + 1 : 0);
+ $uid = $this->explainLinkUid . '_' . rand(0, 10000);
+ $form = $this->Form->create('log', array('url' => $url, 'id' => "logForm{$uid}"));
+ $form .= $this->Form->hidden('log.ds', array('id' => "logDs{$uid}", 'value' => $connection));
+ $form .= $this->Form->hidden('log.sql', array('id' => "logSql{$uid}", 'value' => $sql));
+ $form .= $this->Form->hidden('log.hash', array('id' => "logHash{$uid}", 'value' => $hash));
+ $form .= $this->Form->submit(__d('debug_kit', 'Explain', true), array(
+ 'div' => false,
+ 'class' => 'sql-explain-link'
+ ));
+ $form .= $this->Form->end();
+ return $form;
+ }
+}
diff --git a/code/ryzom/tools/server/www/webtt/plugins/debug_kit/views/helpers/simple_graph.php b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/views/helpers/simple_graph.php
new file mode 100644
index 000000000..22c17865c
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/views/helpers/simple_graph.php
@@ -0,0 +1,84 @@
+ (int) Maximum value in the graphs
+ * - width => (int)
+ * - valueType => string (value, percentage)
+ * - style => array
+ *
+ * @var array
+ */
+ var $__defaultSettings = array(
+ 'max' => 100,
+ 'width' => 350,
+ 'valueType' => 'value',
+ );
+/**
+ * bar method
+ *
+ * @param $value Value to be graphed
+ * @param $offset how much indentation
+ * @param $options Graph options
+ * @return string Html graph
+ * @access public
+ */
+ function bar($value, $offset, $options = array()) {
+ $settings = array_merge($this->__defaultSettings, $options);
+ extract($settings);
+
+ $graphValue = ($value / $max) * $width;
+ $graphValue = max(round($graphValue), 1);
+
+ if ($valueType == 'percentage') {
+ $graphOffset = 0;
+ } else {
+ $graphOffset = ($offset / $max) * $width;
+ $graphOffset = round($graphOffset);
+ }
+ return $this->Html->div(
+ 'debug-kit-graph-bar',
+ $this->Html->div(
+ 'debug-kit-graph-bar-value',
+ ' ',
+ array(
+ 'style' => "margin-left: {$graphOffset}px; width: {$graphValue}px",
+ 'title' => sprintf(__d('debug_kit', "Starting %sms into the request, taking %sms", true), $offset, $value),
+ )
+ ),
+ array('style' => "width: {$width}px;"),
+ false
+ );
+ }
+}
diff --git a/code/ryzom/tools/server/www/webtt/plugins/debug_kit/views/helpers/toolbar.php b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/views/helpers/toolbar.php
new file mode 100644
index 000000000..1ae3a9734
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/views/helpers/toolbar.php
@@ -0,0 +1,182 @@
+_myName = strtolower(get_class($this));
+ $this->settings = am($this->settings, $options);
+
+ if ($this->_myName !== 'toolbarhelper') {
+ return;
+ }
+
+ if (!isset($options['output'])) {
+ $options['output'] = 'DebugKit.HtmlToolbar';
+ }
+ App::import('Helper', $options['output']);
+ $className = $options['output'];
+ if (strpos($options['output'], '.') !== false) {
+ list($plugin, $className) = explode('.', $options['output']);
+ }
+ $this->_backEndClassName = $className;
+ $this->helpers[$options['output']] = $options;
+ if (isset($options['cacheKey']) && isset($options['cacheConfig'])) {
+ $this->_cacheKey = $options['cacheKey'];
+ $this->_cacheConfig = $options['cacheConfig'];
+ $this->_cacheEnabled = true;
+ }
+ }
+/**
+ * Get the name of the backend Helper
+ * used to conditionally trigger toolbar output
+ *
+ * @return string
+ **/
+ function getName() {
+ return $this->_backEndClassName;
+ }
+/**
+ * call__
+ *
+ * Allows method calls on backend helper
+ *
+ * @param string $method
+ * @param mixed $params
+ * @access public
+ * @return void
+ */
+ function call__($method, $params) {
+ if (method_exists($this->{$this->_backEndClassName}, $method)) {
+ return $this->{$this->_backEndClassName}->dispatchMethod($method, $params);
+ }
+ }
+/**
+ * Allows for writing to panel cache from view.
+ * Some panels generate all variables in the view by
+ * necessity ie. Timer. Using this method, will allow you to replace in full
+ * the content for a panel.
+ *
+ * @param string $name Name of the panel you are replacing.
+ * @param string $content Content to write to the panel.
+ * @return boolean Sucess of write.
+ **/
+ function writeCache($name, $content) {
+ if (!$this->_cacheEnabled) {
+ return false;
+ }
+ $existing = (array)Cache::read($this->_cacheKey, $this->_cacheConfig);
+ $existing[0][$name]['content'] = $content;
+ return Cache::write($this->_cacheKey, $existing, $this->_cacheConfig);
+ }
+/**
+ * Read the toolbar
+ *
+ * @param string $name Name of the panel you want cached data for
+ * @return mixed Boolean false on failure, array of data otherwise.
+ **/
+ function readCache($name, $index = 0) {
+ if (!$this->_cacheEnabled) {
+ return false;
+ }
+ $existing = (array)Cache::read($this->_cacheKey, $this->_cacheConfig);
+ if (!isset($existing[$index][$name]['content'])) {
+ return false;
+ }
+ return $existing[$index][$name]['content'];
+ }
+/**
+ * Gets the query logs for the given connection names.
+ *
+ * ### Options
+ *
+ * - explain - Whether explain links should be generated for this connection.
+ * - cache - Whether the toolbar_state Cache should be updated.
+ * - threshold - The threshold at which a visual 'maybe slow' flag should be added.
+ * results with rows/ms lower than $threshold will be marked.
+ *
+ * @param string $connection Connection name to get logs for.
+ * @param array $options Options for the query log retrieval.
+ * @return array Array of data to be converted into a table.
+ */
+ function getQueryLogs($connection, $options = array()) {
+ $options += array('explain' => false, 'cache' => true, 'threshold' => 20);
+ App::import('Model', 'ConnectionManager');
+ $db =& ConnectionManager::getDataSource($connection);
+
+ if (!$db->isInterfaceSupported('getLog')) {
+ return array();
+ }
+
+ $out = array();
+ $log = $db->getLog();
+ foreach ($log['log'] as $i => $query) {
+ $isSlow = (
+ $query['took'] > 0 &&
+ $query['numRows'] / $query['took'] != 1 &&
+ $query['numRows'] / $query['took'] <= $options['threshold']
+ );
+ $query['actions'] = '';
+ $isHtml = ($this->getName() == 'HtmlToolbar');
+ if ($isSlow && $isHtml) {
+ $query['actions'] = sprintf(
+ '%s ',
+ __d('debug_kit', 'maybe slow', true)
+ );
+ } elseif ($isSlow) {
+ $query['actions'] = '*';
+ }
+ if ($options['explain'] && $isHtml) {
+ $query['actions'] .= $this->explainLink($query['query'], $connection);
+ }
+ if ($isHtml) {
+ $query['query'] = h($query['query']);
+ }
+ $out[] = $query;
+ }
+ if ($options['cache']) {
+ $existing = $this->readCache('sql_log');
+ $existing[$connection] = $out;
+ $this->writeCache('sql_log', $existing);
+ }
+ return $out;
+ }
+}
diff --git a/code/ryzom/tools/server/www/webtt/plugins/debug_kit/views/toolbar_access/history_state.ctp b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/views/toolbar_access/history_state.ctp
new file mode 100644
index 000000000..21a1dcfef
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/views/toolbar_access/history_state.ctp
@@ -0,0 +1,29 @@
+ $panel) {
+ $panels[$panelName] = $this->element($panel['elementName'], array(
+ 'content' => $panel['content'],
+ 'plugin' => $panel['plugin']
+ ));
+}
+echo $javascript->object($panels);
+Configure::write('debug', 0);
+?>
\ No newline at end of file
diff --git a/code/ryzom/tools/server/www/webtt/plugins/debug_kit/views/toolbar_access/sql_explain.ctp b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/views/toolbar_access/sql_explain.ctp
new file mode 100644
index 000000000..a38939005
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/views/toolbar_access/sql_explain.ctp
@@ -0,0 +1,12 @@
+
+tableHeaders($headers);
+echo $html->tableCells($result);
+?>
+
+
\ No newline at end of file
diff --git a/code/ryzom/tools/server/www/webtt/plugins/debug_kit/webroot/css/debug_toolbar.css b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/webroot/css/debug_toolbar.css
new file mode 100644
index 000000000..46939561a
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/webroot/css/debug_toolbar.css
@@ -0,0 +1,377 @@
+/* @override http://localhost/mark_story/site/debug_kit/css/debug_toolbar.css */
+#debug-kit-toolbar {
+ position: fixed;
+ top: 0px;
+ right:0px;
+ width: 100%;
+ height: 1%;
+ overflow: visible;
+ z-index:10000;
+ font-family: helvetica, arial, sans-serif;
+ font-size: 12px;
+ direction: ltr;
+}
+#debug-kit-toolbar img {
+ border:0;
+ outline:0;
+}
+
+/* panel tabs */
+#debug-kit-toolbar #panel-tabs {
+ float: right;
+ list-style: none;
+ margin: 0;
+}
+#debug-kit-toolbar .panel-tab {
+ clear: none;
+ float: left;
+ margin: 0;
+ padding: 0;
+ list-style: none;
+}
+#debug-kit-toolbar .panel-tab > a {
+ float: left;
+ clear: none;
+ background: #efefef;
+ background: -webkit-gradient(linear, left top, left bottom, from(#efefef), to(#cacaca));
+ background: -moz-linear-gradient(top, #efefef, #cacaca);
+ color: #222;
+ padding: 6px;
+ border-right: 1px solid #ccc;
+ border-bottom: 1px solid #aaa;
+ font-size: 12px;
+ line-height: 16px;
+ margin: 0;
+ display: block;
+ text-decoration:none;
+ text-shadow:1px 1px #eee;
+ -moz-text-shadow:1px 1px #eee;
+ -webkit-text-shadow:1px 1px #eee;
+}
+#debug-kit-toolbar .panel-tab .active {
+ background: #fff;
+ background: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#fff));
+ background: -moz-linear-gradient(top, #f5f5f5, #fff);
+}
+#debug-kit-toolbar .panel-tab > a:hover {
+ background: #fff;
+ background: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#fff));
+ background: -moz-linear-gradient(top, #f5f5f5, #fff);
+ text-decoration:underline;
+}
+#debug-kit-toolbar .panel-tab.icon a {
+ padding: 4px;
+}
+#debug-kit-toolbar .panel-tab a.edit-value {
+ float: none;
+ display: inline;
+}
+
+/* Hovering over link shows tab, useful for no js */
+#debug-kit-toolbar .panel-tab a:hover + .panel-content,
+#debug-kit-toolbar .panel-tab a + .panel-content:hover {
+ display: block;
+}
+#debug-kit-toolbar .panel-tab.icon a {
+ -webkit-border-top-left-radius: 8px 8px;
+ -webkit-border-bottom-left-radius: 8px 8px;
+ -moz-border-radius-topleft: 8px;
+ -moz-border-radius-bottomleft: 8px
+}
+#debug-kit-toolbar .panel-tab.icon img {
+ display:block;
+}
+
+/* panel content */
+#debug-kit-toolbar .panel-content {
+ position: absolute;
+ text-align: left;
+ width: auto;
+ top:28px;
+ right:0px;
+ background: #fff;
+ color: #000;
+ width:100%;
+ box-shadow:0px 5px 6px #ccc;
+ height: 200px;
+ overflow: hidden;
+}
+
+#debug-kit-toolbar .panel-resize-region {
+ padding:15px;
+ position: absolute;
+ top: 0px;
+ bottom: 14px;
+ left: 0px;
+ right: 0px;
+ overflow: auto;
+}
+
+#debug-kit-toolbar .ui-control {
+ background:#ccc;
+ background: -webkit-gradient(linear, left top, left bottom, from(#d6d6d6), to(#c2c2c2));
+ background: -moz-linear-gradient(top, #d6d6d6, #c2c2c2);
+ text-align:center;
+ border-top:1px solid #afafaf;
+ border-bottom:1px solid #7c7c7c;
+ color:#666;
+ text-shadow: 1px 1px #eee;
+ -webkit-text-shadow: 1px 1px #eee;
+ -moz-text-shadow: 1px 1px #eee;
+}
+#debug-kit-toolbar .ui-button {
+ -webkit-border-radius: 5px;
+ -moz-border-radius: 5px;
+ border-radius: 5px;
+}
+#debug-kit-toolbar .ui-button:hover {
+ text-decoration: none;
+ background:#ccc;
+ background: -webkit-gradient(linear, left top, left bottom, from(#c2c2c2), to(#d6d6d6));
+ background: -moz-linear-gradient(top, #c2c2c2, #d6d6d6);
+}
+#debug-kit-toolbar .panel-resize-handle {
+ cursor: row-resize;
+ height:14px;
+ line-height: 14px;
+ position: absolute;
+ bottom: 0px;
+ left: 0px;
+ right: 0px;
+}
+#debug-kit-toolbar .panel-maximize,
+#debug-kit-toolbar .panel-minimize {
+ float: right;
+ display: block;
+ width: 12px;
+ height: 12px;
+ line-height: 12px;
+ border-left: 1px solid #afafaf;
+ border-right: 1px solid #7c7c7c;
+}
+#debug-kit-toolbar .panel-maximize {
+ float: right;
+ margin: 10px 20px 0 0;
+ z-index: 999;
+ position: relative;
+}
+#debug-kit-toolbar .panel-minimize {
+ float: right;
+ margin: 10px 10px 0 0;
+ z-index: 999;
+ position: relative;
+}
+
+/* Hide panel content by default */
+#debug-kit-toolbar .panel-content {
+ display: none;
+}
+.panel-content p {
+ margin: 1em 0;
+}
+.panel-content h2 {
+ padding: 0;
+ margin-top:0;
+}
+.panel-content h3 {
+ padding: 0;
+ margin-top: 1em;
+}
+.panel-content .info {
+ padding: 4px;
+ border-top: 1px dashed #6c6cff;
+ border-bottom: 1px dashed #6c6cff;
+}
+#debug-kit-toolbar h1,
+#debug-kit-toolbar h2,
+#debug-kit-toolbar h3,
+#debug-kit-toolbar h4,
+#debug-kit-toolbar h5,
+#debug-kit-toolbar th {
+ color: #5d1717;
+ font-family: "Trebuchet MS", trebuchet, helvetica, arial, sans-serif;
+ margin-bottom:0.6em;
+ background:none;
+}
+#debug-kit-toolbar h1 {
+ font-size: 18px;
+}
+#debug-kit-toolbar h2 {
+ font-size: 16px;
+}
+#debug-kit-toolbar h4 {
+ font-size: 14px;
+}
+
+
+/* panel tables */
+#debug-kit-toolbar table.debug-table {
+ width: 100%;
+ border: 0;
+ clear:both;
+ margin-bottom: 20px;
+}
+#debug-kit-toolbar table.debug-table td,
+#debug-kit-toolbar table.debug-table th {
+ text-align: left;
+ border: 0;
+ padding: 3px;
+}
+#debug-kit-toolbar table.debug-table th {
+ border-bottom: 1px solid #222;
+ background: 0;
+ color: #252525;
+}
+#debug-kit-toolbar table.debug-table tr:nth-child(2n+1) td {
+ background:#f6f6f6;
+}
+#debug-kit-toolbar table.debug-table tr.even td {
+ background:#f7f7f7;
+}
+#debug-kit-toolbar .debug-timers .debug-table td:nth-child(2),
+#debug-kit-toolbar .debug-timers .debug-table th:nth-child(2) {
+ text-align:right;
+}
+
+/** code tables **/
+#debug-kit-toolbar .code-table td {
+ white-space: pre;
+ font-family: monaco, Consolas, "courier new", courier, monospaced;
+}
+#debug-kit-toolbar .code-table td:first-child {
+ width: 15%;
+}
+#debug-kit-toolbar .code-table td:last-child {
+ width: 80%;
+}
+
+#debug-kit-toolbar .panel-content.request {
+ display: block;
+}
+
+/** Neat Array styles **/
+#debug-kit-toolbar .neat-array,
+#debug-kit-toolbar .neat-array li {
+ list-style:none;
+ list-style-image:none;
+}
+.neat-array {
+ padding: 1px 2px 1px 20px;
+ background: #CE9E23;
+ list-style: none;
+ margin: 0 0 1em 0;
+}
+.neat-array .neat-array {
+ padding: 0 0 0 20px;
+ margin:0;
+ border-top:1px solid #CE9E23;
+}
+.neat-array li {
+ background: #FEF6E5;
+ border-top: 1px solid #CE9E23;
+ border-bottom: 1px solid #CE9E23;
+ margin: 0;
+ line-height: 1.5em;
+}
+.neat-array li:hover {
+ background: #fff;
+}
+.neat-array li strong {
+ padding: 0 8px;
+ font-weight: bold;
+}
+
+
+/* expandable sections */
+.neat-array li.expandable {
+ cursor: pointer;
+}
+.neat-array .expanded {
+ border-bottom:0;
+}
+.neat-array li.expandable.expanded > strong:before {
+ content: 'v ';
+}
+.neat-array li.expandable.collapsed > strong:before,
+.neat-array li.expandable.expanded .expandable.collapsed > strong:before {
+ content: '> ';
+}
+.neat-array li {
+ cursor: default;
+}
+
+#debug-kit-toolbar .debug-kit-graph-bar,
+#debug-kit-toolbar .debug-kit-graph-bar-value {
+ margin: 0;
+ padding: 0px;
+ border: none;
+ overflow: hidden;
+ height: 10px;
+}
+#debug-kit-toolbar .debug-kit-graph-bar {
+ background-color: #ddd;
+ padding:2px;
+}
+#debug-kit-toolbar .debug-kit-graph-bar-value {
+ background-color: #CE9E23;
+}
+
+/* Sql Log */
+#sql_log-tab td,
+#sql_log-tab .slow-query-container p {
+ font-family: Monaco, 'Consolas', "Courier New", Courier, monospaced;
+}
+#debug-kit-toolbar #sql_log-tab a.show-slow {
+ display:block;
+ margin: 3px;
+ float:none;
+}
+#sql_log-tab .slow-query-container p {
+ display:block;
+ clear:both;
+ margin: 20px 0 5px;
+}
+#debug-kit-toolbar #sql_log-tab .panel-content-data a {
+ background: none;
+ border:none;
+}
+#sql_log-tab .slow-query {
+ background:#e79302;
+ font-size:9px;
+ color:#fff;
+ padding: 2px;
+ white-space:nowrap;
+}
+#sql_log-tab input[type=submit] {
+ border: 0;
+ background: transparent;
+ cursor: pointer;
+ font-size: 12px;
+ font-family: Monaco, 'Consolas', "Courier New", Courier, monospaced;
+}
+#sql_log-tab input[type=submit]:hover {
+ color: darkred;
+}
+
+/* previous panels */
+#debug-kit-toolbar .panel-history {
+ display: none;
+ background:#eeffff;
+}
+#debug-kit-toolbar #history-tab ul {
+ margin: 20px 0 0 20px;
+}
+#debug-kit-toolbar #history-tab li {
+ margin: 0 0 5px 0;
+}
+#debug-kit-toolbar #history-tab .panel-content-data a {
+ float: none;
+ display:block;
+}
+#debug-kit-toolbar #history-tab a.active {
+ background: #FEF6E5;
+}
+#debug-kit-toolbar #history-tab a.loading:after {
+ content : ' Loading...';
+ font-style:italic;
+}
diff --git a/code/ryzom/tools/server/www/webtt/plugins/debug_kit/webroot/img/cake.icon.png b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/webroot/img/cake.icon.png
new file mode 100644
index 000000000..394fa42d5
Binary files /dev/null and b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/webroot/img/cake.icon.png differ
diff --git a/code/ryzom/tools/server/www/webtt/plugins/debug_kit/webroot/js/js_debug_toolbar.js b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/webroot/js/js_debug_toolbar.js
new file mode 100644
index 000000000..57cc1cc08
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/plugins/debug_kit/webroot/js/js_debug_toolbar.js
@@ -0,0 +1,767 @@
+/**
+ * Debug Toolbar Javascript.
+ *
+ * Creates the DEBUGKIT namespace and provides methods for extending
+ * and enhancing the Html toolbar. Includes library agnostic Event, Element,
+ * Cookie and Request wrappers.
+ *
+ *
+ * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
+ * Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
+ *
+ * Licensed under The MIT License
+ * Redistributions of files must retain the above copyright notice.
+ *
+ * @copyright Copyright 2005-2010, Cake Software Foundation, Inc. (http://cakefoundation.org)
+ * @link http://cakephp.org
+ * @package debug_kit
+ * @subpackage debug_kit.views.helpers
+ * @since DebugKit 0.1
+ * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
+ */
+var DEBUGKIT = function () {
+ var undef;
+ return {
+ module: function (newmodule) {
+ if (this[newmodule] === undef) {
+ this[newmodule] = {};
+ return this[newmodule];
+ }
+ return this[newmodule];
+ }
+ };
+}() ;
+
+DEBUGKIT.loader = function () {
+ return {
+ //list of methods to run on startup.
+ _startup: [],
+
+ //register a new method to be run on dom ready.
+ register: function (method) {
+ this._startup.push(method);
+ },
+
+ init: function () {
+ for (var i = 0, callback; callback = this._startup[i]; i++) {
+ callback.init();
+ }
+ }
+ };
+}();
+
+//Util module and Element utility class.
+DEBUGKIT.module('Util');
+DEBUGKIT.Util.Element = {
+
+ //test if an element is a name node.
+ nodeName: function (element, name) {
+ return element.nodeName && element.nodeName.toLowerCase() == name.toLowerCase();
+ },
+
+ //return a boolean if the element has the classname
+ hasClass: function (element, className) {
+ if (!element.className) {
+ return false;
+ }
+ return element.className.indexOf(className) > -1;
+ },
+
+ addClass: function (element, className) {
+ if (!element.className) {
+ element.className = className;
+ return;
+ }
+ element.className = element.className.replace(/^(.*)$/, '$1 ' + className);
+ },
+
+ removeClass: function (element, className) {
+ if (DEBUGKIT.Util.isArray(element)) {
+ DEBUGKIT.Util.Collection.apply(element, function (element) {
+ DEBUGKIT.Util.Element.removeClass(element, className);
+ });
+ }
+ if (!element.className) {
+ return false;
+ }
+ element.className = element.className.replace(new RegExp(' ?(' + className +') ?'), '');
+ },
+
+ swapClass: function (element, removeClass, addClass) {
+ if (!element.className) {
+ return false;
+ }
+ element.className = element.className.replace(removeClass, addClass);
+ },
+
+ show: function (element) {
+ element.style.display = 'block';
+ },
+
+ hide: function (element) {
+ element.style.display = 'none';
+ },
+
+ //go between hide() and show() depending on element.style.display
+ toggle: function (element) {
+ if (element.style.display == 'none') {
+ this.show(element);
+ return;
+ }
+ this.hide(element);
+ },
+
+ _walk: function (element, walk) {
+ var sibling = element[walk];
+ while (true) {
+ if (sibling.nodeType == 1) {
+ break;
+ }
+ sibling = sibling[walk];
+ }
+ return sibling;
+ },
+
+ getNext: function (element) {
+ return this._walk(element, 'nextSibling');
+ },
+
+ getPrevious: function (element) {
+ return this._walk(element, 'previousSibling');
+ },
+
+ //get or set an element's height, omit value to get, add value (integer) to set.
+ height: function (element, value) {
+ //get value
+ if (value === undefined) {
+ return parseInt(this.getStyle(element, 'height'));
+ }
+ element.style.height = value + 'px';
+ },
+
+ //gets the style in css format for property
+ getStyle: function (element, property) {
+ if (element.currentStyle) {
+ property = property.replace(/-[a-z]/g, function (match) {
+ return match.charAt(1).toUpperCase();
+ });
+ return element.currentStyle[property];
+ }
+ if (window.getComputedStyle) {
+ return document.defaultView.getComputedStyle(element, null).getPropertyValue(property);
+ }
+ }
+};
+
+DEBUGKIT.Util.Collection = {
+ /*
+ Apply the passed function to each item in the collection.
+ The current element in the collection will be `this` in the callback
+ The callback is also passed the element and the index as arguments.
+ Optionally you can supply a binding parameter to change `this` in the callback.
+ */
+ apply: function (collection, callback, binding) {
+ var name, thisVar, i = 0, len = collection.length;
+
+ if (len === undefined) {
+ for (name in collection) {
+ thisVar = (binding === undefined) ? collection[name] : binding;
+ callback.apply(thisVar, [collection[name], name]);
+ }
+ } else {
+ for (; i < len; i++) {
+ thisVar = (binding === undefined) ? collection[i] : binding;
+ callback.apply(thisVar, [collection[i], i]);
+ }
+ }
+ }
+}
+
+
+//Event binding
+DEBUGKIT.Util.Event = function () {
+ var _listeners = {},
+ _eventId = 0;
+
+ var preventDefault = function () {
+ this.returnValue = false;
+ }
+
+ var stopPropagation = function () {
+ this.cancelBubble = true;
+ }
+
+ // Fixes IE's broken event object, adds in common methods + properties.
+ var fixEvent = function (event) {
+ if (!event.preventDefault) {
+ event.preventDefault = preventDefault;
+ }
+ if (!event.stopPropagation) {
+ event.stopPropagation = stopPropagation;
+ }
+ if (!event.target) {
+ event.target = event.srcElement || document;
+ }
+ if (event.pageX == null && event.clientX != null) {
+ var doc = document.body;
+ event.pageX = event.clientX + (doc.scrollLeft || 0) - (doc.clientLeft || 0);
+ event.pageY = event.clientY + (doc.scrollTop || 0) - (doc.clientTop || 0);
+ }
+ return event;
+ }
+
+ return {
+ // bind an event listener of type to element, handler is your method.
+ addEvent: function(element, type, handler, capture) {
+ capture = (capture === undefined) ? false : capture;
+
+ var callback = function (event) {
+ event = fixEvent(event || window.event);
+ handler.apply(element, [event]);
+ };
+
+ if (element.addEventListener) {
+ element.addEventListener(type, callback, capture);
+ } else if (element.attachEvent) {
+ type = 'on' + type;
+ element.attachEvent(type, callback);
+ } else {
+ type = 'on' + type;
+ element[type] = callback;
+ }
+ _listeners[++_eventId] = {element: element, type: type, handler: callback};
+ },
+
+ // destroy an event listener. requires the exact same function as was used for attaching
+ // the event.
+ removeEvent: function (element, type, handler) {
+ if (element.removeEventListener) {
+ element.removeEventListener(type, handler, false);
+ } else if (element.detachEvent) {
+ type = 'on' + type;
+ element.detachEvent(type, handler);
+ } else {
+ type = 'on' + type;
+ element[type] = null;
+ }
+ },
+
+ // bind an event to the DOMContentLoaded or other similar event.
+ domready: function(callback) {
+ if (document.addEventListener) {
+ return document.addEventListener("DOMContentLoaded", callback, false);
+ }
+
+ if (document.all && !window.opera) {
+ //Define a "blank" external JavaScript tag
+ document.write('', 'js');
+ $this->mapHandler('comment', 'ignore');
+ $this->addEntryPattern('', 'comment');
+ }
+
+ /**
+ * Pattern matches to start and end a tag.
+ * @param string $tag Name of tag to scan for.
+ * @access private
+ */
+ protected function addTag($tag) {
+ $this->addSpecialPattern("$tag>", 'text', 'acceptEndToken');
+ $this->addEntryPattern("<$tag", 'text', 'tag');
+ }
+
+ /**
+ * Pattern matches to parse the inside of a tag
+ * including the attributes and their quoting.
+ * @access private
+ */
+ protected function addInTagTokens() {
+ $this->mapHandler('tag', 'acceptStartToken');
+ $this->addSpecialPattern('\s+', 'tag', 'ignore');
+ $this->addAttributeTokens();
+ $this->addExitPattern('/>', 'tag');
+ $this->addExitPattern('>', 'tag');
+ }
+
+ /**
+ * Matches attributes that are either single quoted,
+ * double quoted or unquoted.
+ * @access private
+ */
+ protected function addAttributeTokens() {
+ $this->mapHandler('dq_attribute', 'acceptAttributeToken');
+ $this->addEntryPattern('=\s*"', 'tag', 'dq_attribute');
+ $this->addPattern("\\\\\"", 'dq_attribute');
+ $this->addExitPattern('"', 'dq_attribute');
+ $this->mapHandler('sq_attribute', 'acceptAttributeToken');
+ $this->addEntryPattern("=\s*'", 'tag', 'sq_attribute');
+ $this->addPattern("\\\\'", 'sq_attribute');
+ $this->addExitPattern("'", 'sq_attribute');
+ $this->mapHandler('uq_attribute', 'acceptAttributeToken');
+ $this->addSpecialPattern('=\s*[^>\s]*', 'tag', 'uq_attribute');
+ }
+}
+
+/**
+ * Converts HTML tokens into selected SAX events.
+ * @package SimpleTest
+ * @subpackage WebTester
+ */
+class SimpleHtmlSaxParser {
+ private $lexer;
+ private $listener;
+ private $tag;
+ private $attributes;
+ private $current_attribute;
+
+ /**
+ * Sets the listener.
+ * @param SimplePhpPageBuilder $listener SAX event handler.
+ * @access public
+ */
+ function __construct($listener) {
+ $this->listener = $listener;
+ $this->lexer = $this->createLexer($this);
+ $this->tag = '';
+ $this->attributes = array();
+ $this->current_attribute = '';
+ }
+
+ /**
+ * Runs the content through the lexer which
+ * should call back to the acceptors.
+ * @param string $raw Page text to parse.
+ * @return boolean False if parse error.
+ * @access public
+ */
+ function parse($raw) {
+ return $this->lexer->parse($raw);
+ }
+
+ /**
+ * Sets up the matching lexer. Starts in 'text' mode.
+ * @param SimpleSaxParser $parser Event generator, usually $self.
+ * @return SimpleLexer Lexer suitable for this parser.
+ * @access public
+ */
+ static function createLexer(&$parser) {
+ return new SimpleHtmlLexer($parser);
+ }
+
+ /**
+ * Accepts a token from the tag mode. If the
+ * starting element completes then the element
+ * is dispatched and the current attributes
+ * set back to empty. The element or attribute
+ * name is converted to lower case.
+ * @param string $token Incoming characters.
+ * @param integer $event Lexer event type.
+ * @return boolean False if parse error.
+ * @access public
+ */
+ function acceptStartToken($token, $event) {
+ if ($event == LEXER_ENTER) {
+ $this->tag = strtolower(substr($token, 1));
+ return true;
+ }
+ if ($event == LEXER_EXIT) {
+ $success = $this->listener->startElement(
+ $this->tag,
+ $this->attributes);
+ $this->tag = '';
+ $this->attributes = array();
+ return $success;
+ }
+ if ($token != '=') {
+ $this->current_attribute = strtolower(html_entity_decode($token, ENT_QUOTES));
+ $this->attributes[$this->current_attribute] = '';
+ }
+ return true;
+ }
+
+ /**
+ * Accepts a token from the end tag mode.
+ * The element name is converted to lower case.
+ * @param string $token Incoming characters.
+ * @param integer $event Lexer event type.
+ * @return boolean False if parse error.
+ * @access public
+ */
+ function acceptEndToken($token, $event) {
+ if (! preg_match('/<\/(.*)>/', $token, $matches)) {
+ return false;
+ }
+ return $this->listener->endElement(strtolower($matches[1]));
+ }
+
+ /**
+ * Part of the tag data.
+ * @param string $token Incoming characters.
+ * @param integer $event Lexer event type.
+ * @return boolean False if parse error.
+ * @access public
+ */
+ function acceptAttributeToken($token, $event) {
+ if ($this->current_attribute) {
+ if ($event == LEXER_UNMATCHED) {
+ $this->attributes[$this->current_attribute] .=
+ html_entity_decode($token, ENT_QUOTES);
+ }
+ if ($event == LEXER_SPECIAL) {
+ $this->attributes[$this->current_attribute] .=
+ preg_replace('/^=\s*/' , '', html_entity_decode($token, ENT_QUOTES));
+ }
+ }
+ return true;
+ }
+
+ /**
+ * A character entity.
+ * @param string $token Incoming characters.
+ * @param integer $event Lexer event type.
+ * @return boolean False if parse error.
+ * @access public
+ */
+ function acceptEntityToken($token, $event) {
+ }
+
+ /**
+ * Character data between tags regarded as
+ * important.
+ * @param string $token Incoming characters.
+ * @param integer $event Lexer event type.
+ * @return boolean False if parse error.
+ * @access public
+ */
+ function acceptTextToken($token, $event) {
+ return $this->listener->addContent($token);
+ }
+
+ /**
+ * Incoming data to be ignored.
+ * @param string $token Incoming characters.
+ * @param integer $event Lexer event type.
+ * @return boolean False if parse error.
+ * @access public
+ */
+ function ignore($token, $event) {
+ return true;
+ }
+}
+
+/**
+ * SAX event handler. Maintains a list of
+ * open tags and dispatches them as they close.
+ * @package SimpleTest
+ * @subpackage WebTester
+ */
+class SimplePhpPageBuilder {
+ private $tags;
+ private $page;
+ private $private_content_tag;
+ private $open_forms = array();
+ private $complete_forms = array();
+ private $frameset = false;
+ private $loading_frames = array();
+ private $frameset_nesting_level = 0;
+ private $left_over_labels = array();
+
+ /**
+ * Frees up any references so as to allow the PHP garbage
+ * collection from unset() to work.
+ * @access public
+ */
+ function free() {
+ unset($this->tags);
+ unset($this->page);
+ unset($this->private_content_tags);
+ $this->open_forms = array();
+ $this->complete_forms = array();
+ $this->frameset = false;
+ $this->loading_frames = array();
+ $this->frameset_nesting_level = 0;
+ $this->left_over_labels = array();
+ }
+
+ /**
+ * This builder is always available.
+ * @return boolean Always true.
+ */
+ function can() {
+ return true;
+ }
+
+ /**
+ * Reads the raw content and send events
+ * into the page to be built.
+ * @param $response SimpleHttpResponse Fetched response.
+ * @return SimplePage Newly parsed page.
+ * @access public
+ */
+ function parse($response) {
+ $this->tags = array();
+ $this->page = $this->createPage($response);
+ $parser = $this->createParser($this);
+ $parser->parse($response->getContent());
+ $this->acceptPageEnd();
+ $page = $this->page;
+ $this->free();
+ return $page;
+ }
+
+ /**
+ * Creates an empty page.
+ * @return SimplePage New unparsed page.
+ * @access protected
+ */
+ protected function createPage($response) {
+ return new SimplePage($response);
+ }
+
+ /**
+ * Creates the parser used with the builder.
+ * @param SimplePhpPageBuilder $listener Target of parser.
+ * @return SimpleSaxParser Parser to generate
+ * events for the builder.
+ * @access protected
+ */
+ protected function createParser(&$listener) {
+ return new SimpleHtmlSaxParser($listener);
+ }
+
+ /**
+ * Start of element event. Opens a new tag.
+ * @param string $name Element name.
+ * @param hash $attributes Attributes without content
+ * are marked as true.
+ * @return boolean False on parse error.
+ * @access public
+ */
+ function startElement($name, $attributes) {
+ $factory = new SimpleTagBuilder();
+ $tag = $factory->createTag($name, $attributes);
+ if (! $tag) {
+ return true;
+ }
+ if ($tag->getTagName() == 'label') {
+ $this->acceptLabelStart($tag);
+ $this->openTag($tag);
+ return true;
+ }
+ if ($tag->getTagName() == 'form') {
+ $this->acceptFormStart($tag);
+ return true;
+ }
+ if ($tag->getTagName() == 'frameset') {
+ $this->acceptFramesetStart($tag);
+ return true;
+ }
+ if ($tag->getTagName() == 'frame') {
+ $this->acceptFrame($tag);
+ return true;
+ }
+ if ($tag->isPrivateContent() && ! isset($this->private_content_tag)) {
+ $this->private_content_tag = &$tag;
+ }
+ if ($tag->expectEndTag()) {
+ $this->openTag($tag);
+ return true;
+ }
+ $this->acceptTag($tag);
+ return true;
+ }
+
+ /**
+ * End of element event.
+ * @param string $name Element name.
+ * @return boolean False on parse error.
+ * @access public
+ */
+ function endElement($name) {
+ if ($name == 'label') {
+ $this->acceptLabelEnd();
+ return true;
+ }
+ if ($name == 'form') {
+ $this->acceptFormEnd();
+ return true;
+ }
+ if ($name == 'frameset') {
+ $this->acceptFramesetEnd();
+ return true;
+ }
+ if ($this->hasNamedTagOnOpenTagStack($name)) {
+ $tag = array_pop($this->tags[$name]);
+ if ($tag->isPrivateContent() && $this->private_content_tag->getTagName() == $name) {
+ unset($this->private_content_tag);
+ }
+ $this->addContentTagToOpenTags($tag);
+ $this->acceptTag($tag);
+ return true;
+ }
+ return true;
+ }
+
+ /**
+ * Test to see if there are any open tags awaiting
+ * closure that match the tag name.
+ * @param string $name Element name.
+ * @return boolean True if any are still open.
+ * @access private
+ */
+ protected function hasNamedTagOnOpenTagStack($name) {
+ return isset($this->tags[$name]) && (count($this->tags[$name]) > 0);
+ }
+
+ /**
+ * Unparsed, but relevant data. The data is added
+ * to every open tag.
+ * @param string $text May include unparsed tags.
+ * @return boolean False on parse error.
+ * @access public
+ */
+ function addContent($text) {
+ if (isset($this->private_content_tag)) {
+ $this->private_content_tag->addContent($text);
+ } else {
+ $this->addContentToAllOpenTags($text);
+ }
+ return true;
+ }
+
+ /**
+ * Any content fills all currently open tags unless it
+ * is part of an option tag.
+ * @param string $text May include unparsed tags.
+ * @access private
+ */
+ protected function addContentToAllOpenTags($text) {
+ foreach (array_keys($this->tags) as $name) {
+ for ($i = 0, $count = count($this->tags[$name]); $i < $count; $i++) {
+ $this->tags[$name][$i]->addContent($text);
+ }
+ }
+ }
+
+ /**
+ * Parsed data in tag form. The parsed tag is added
+ * to every open tag. Used for adding options to select
+ * fields only.
+ * @param SimpleTag $tag Option tags only.
+ * @access private
+ */
+ protected function addContentTagToOpenTags(&$tag) {
+ if ($tag->getTagName() != 'option') {
+ return;
+ }
+ foreach (array_keys($this->tags) as $name) {
+ for ($i = 0, $count = count($this->tags[$name]); $i < $count; $i++) {
+ $this->tags[$name][$i]->addTag($tag);
+ }
+ }
+ }
+
+ /**
+ * Opens a tag for receiving content. Multiple tags
+ * will be receiving input at the same time.
+ * @param SimpleTag $tag New content tag.
+ * @access private
+ */
+ protected function openTag($tag) {
+ $name = $tag->getTagName();
+ if (! in_array($name, array_keys($this->tags))) {
+ $this->tags[$name] = array();
+ }
+ $this->tags[$name][] = $tag;
+ }
+
+ /**
+ * Adds a tag to the page.
+ * @param SimpleTag $tag Tag to accept.
+ * @access public
+ */
+ protected function acceptTag($tag) {
+ if ($tag->getTagName() == "a") {
+ $this->page->addLink($tag);
+ } elseif ($tag->getTagName() == "base") {
+ $this->page->setBase($tag->getAttribute('href'));
+ } elseif ($tag->getTagName() == "title") {
+ $this->page->setTitle($tag);
+ } elseif ($this->isFormElement($tag->getTagName())) {
+ for ($i = 0; $i < count($this->open_forms); $i++) {
+ $this->open_forms[$i]->addWidget($tag);
+ }
+ $this->last_widget = $tag;
+ }
+ }
+
+ /**
+ * Opens a label for a described widget.
+ * @param SimpleFormTag $tag Tag to accept.
+ * @access public
+ */
+ protected function acceptLabelStart($tag) {
+ $this->label = $tag;
+ unset($this->last_widget);
+ }
+
+ /**
+ * Closes the most recently opened label.
+ * @access public
+ */
+ protected function acceptLabelEnd() {
+ if (isset($this->label)) {
+ if (isset($this->last_widget)) {
+ $this->last_widget->setLabel($this->label->getText());
+ unset($this->last_widget);
+ } else {
+ $this->left_over_labels[] = SimpleTestCompatibility::copy($this->label);
+ }
+ unset($this->label);
+ }
+ }
+
+ /**
+ * Tests to see if a tag is a possible form
+ * element.
+ * @param string $name HTML element name.
+ * @return boolean True if form element.
+ * @access private
+ */
+ protected function isFormElement($name) {
+ return in_array($name, array('input', 'button', 'textarea', 'select'));
+ }
+
+ /**
+ * Opens a form. New widgets go here.
+ * @param SimpleFormTag $tag Tag to accept.
+ * @access public
+ */
+ protected function acceptFormStart($tag) {
+ $this->open_forms[] = new SimpleForm($tag, $this->page);
+ }
+
+ /**
+ * Closes the most recently opened form.
+ * @access public
+ */
+ protected function acceptFormEnd() {
+ if (count($this->open_forms)) {
+ $this->complete_forms[] = array_pop($this->open_forms);
+ }
+ }
+
+ /**
+ * Opens a frameset. A frameset may contain nested
+ * frameset tags.
+ * @param SimpleFramesetTag $tag Tag to accept.
+ * @access public
+ */
+ protected function acceptFramesetStart($tag) {
+ if (! $this->isLoadingFrames()) {
+ $this->frameset = $tag;
+ }
+ $this->frameset_nesting_level++;
+ }
+
+ /**
+ * Closes the most recently opened frameset.
+ * @access public
+ */
+ protected function acceptFramesetEnd() {
+ if ($this->isLoadingFrames()) {
+ $this->frameset_nesting_level--;
+ }
+ }
+
+ /**
+ * Takes a single frame tag and stashes it in
+ * the current frame set.
+ * @param SimpleFrameTag $tag Tag to accept.
+ * @access public
+ */
+ protected function acceptFrame($tag) {
+ if ($this->isLoadingFrames()) {
+ if ($tag->getAttribute('src')) {
+ $this->loading_frames[] = $tag;
+ }
+ }
+ }
+
+ /**
+ * Test to see if in the middle of reading
+ * a frameset.
+ * @return boolean True if inframeset.
+ * @access private
+ */
+ protected function isLoadingFrames() {
+ return $this->frameset and $this->frameset_nesting_level > 0;
+ }
+
+ /**
+ * Marker for end of complete page. Any work in
+ * progress can now be closed.
+ * @access public
+ */
+ protected function acceptPageEnd() {
+ while (count($this->open_forms)) {
+ $this->complete_forms[] = array_pop($this->open_forms);
+ }
+ foreach ($this->left_over_labels as $label) {
+ for ($i = 0, $count = count($this->complete_forms); $i < $count; $i++) {
+ $this->complete_forms[$i]->attachLabelBySelector(
+ new SimpleById($label->getFor()),
+ $label->getText());
+ }
+ }
+ $this->page->setForms($this->complete_forms);
+ $this->page->setFrames($this->loading_frames);
+ }
+}
+?>
\ No newline at end of file
diff --git a/code/ryzom/tools/server/www/webtt/vendors/simpletest/reflection_php4.php b/code/ryzom/tools/server/www/webtt/vendors/simpletest/reflection_php4.php
new file mode 100644
index 000000000..39801ea1b
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/vendors/simpletest/reflection_php4.php
@@ -0,0 +1,136 @@
+_interface = $interface;
+ }
+
+ /**
+ * Checks that a class has been declared.
+ * @return boolean True if defined.
+ * @access public
+ */
+ function classExists() {
+ return class_exists($this->_interface);
+ }
+
+ /**
+ * Needed to kill the autoload feature in PHP5
+ * for classes created dynamically.
+ * @return boolean True if defined.
+ * @access public
+ */
+ function classExistsSansAutoload() {
+ return class_exists($this->_interface);
+ }
+
+ /**
+ * Checks that a class or interface has been
+ * declared.
+ * @return boolean True if defined.
+ * @access public
+ */
+ function classOrInterfaceExists() {
+ return class_exists($this->_interface);
+ }
+
+ /**
+ * Needed to kill the autoload feature in PHP5
+ * for classes created dynamically.
+ * @return boolean True if defined.
+ * @access public
+ */
+ function classOrInterfaceExistsSansAutoload() {
+ return class_exists($this->_interface);
+ }
+
+ /**
+ * Gets the list of methods on a class or
+ * interface.
+ * @returns array List of method names.
+ * @access public
+ */
+ function getMethods() {
+ return get_class_methods($this->_interface);
+ }
+
+ /**
+ * Gets the list of interfaces from a class. If the
+ * class name is actually an interface then just that
+ * interface is returned.
+ * @returns array List of interfaces.
+ * @access public
+ */
+ function getInterfaces() {
+ return array();
+ }
+
+ /**
+ * Finds the parent class name.
+ * @returns string Parent class name.
+ * @access public
+ */
+ function getParent() {
+ return strtolower(get_parent_class($this->_interface));
+ }
+
+ /**
+ * Determines if the class is abstract, which for PHP 4
+ * will never be the case.
+ * @returns boolean True if abstract.
+ * @access public
+ */
+ function isAbstract() {
+ return false;
+ }
+
+ /**
+ * Determines if the the entity is an interface, which for PHP 4
+ * will never be the case.
+ * @returns boolean True if interface.
+ * @access public
+ */
+ function isInterface() {
+ return false;
+ }
+
+ /**
+ * Scans for final methods, but as it's PHP 4 there
+ * aren't any.
+ * @returns boolean True if the class has a final method.
+ * @access public
+ */
+ function hasFinal() {
+ return false;
+ }
+
+ /**
+ * Gets the source code matching the declaration
+ * of a method.
+ * @param string $method Method name.
+ * @access public
+ */
+ function getSignature($method) {
+ return "function &$method()";
+ }
+}
+?>
\ No newline at end of file
diff --git a/code/ryzom/tools/server/www/webtt/vendors/simpletest/reflection_php5.php b/code/ryzom/tools/server/www/webtt/vendors/simpletest/reflection_php5.php
new file mode 100644
index 000000000..43d8a7b28
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/vendors/simpletest/reflection_php5.php
@@ -0,0 +1,386 @@
+interface = $interface;
+ }
+
+ /**
+ * Checks that a class has been declared. Versions
+ * before PHP5.0.2 need a check that it's not really
+ * an interface.
+ * @return boolean True if defined.
+ * @access public
+ */
+ function classExists() {
+ if (! class_exists($this->interface)) {
+ return false;
+ }
+ $reflection = new ReflectionClass($this->interface);
+ return ! $reflection->isInterface();
+ }
+
+ /**
+ * Needed to kill the autoload feature in PHP5
+ * for classes created dynamically.
+ * @return boolean True if defined.
+ * @access public
+ */
+ function classExistsSansAutoload() {
+ return class_exists($this->interface, false);
+ }
+
+ /**
+ * Checks that a class or interface has been
+ * declared.
+ * @return boolean True if defined.
+ * @access public
+ */
+ function classOrInterfaceExists() {
+ return $this->classOrInterfaceExistsWithAutoload($this->interface, true);
+ }
+
+ /**
+ * Needed to kill the autoload feature in PHP5
+ * for classes created dynamically.
+ * @return boolean True if defined.
+ * @access public
+ */
+ function classOrInterfaceExistsSansAutoload() {
+ return $this->classOrInterfaceExistsWithAutoload($this->interface, false);
+ }
+
+ /**
+ * Needed to select the autoload feature in PHP5
+ * for classes created dynamically.
+ * @param string $interface Class or interface name.
+ * @param boolean $autoload True totriggerautoload.
+ * @return boolean True if interface defined.
+ * @access private
+ */
+ protected function classOrInterfaceExistsWithAutoload($interface, $autoload) {
+ if (function_exists('interface_exists')) {
+ if (interface_exists($this->interface, $autoload)) {
+ return true;
+ }
+ }
+ return class_exists($this->interface, $autoload);
+ }
+
+ /**
+ * Gets the list of methods on a class or
+ * interface.
+ * @returns array List of method names.
+ * @access public
+ */
+ function getMethods() {
+ return array_unique(get_class_methods($this->interface));
+ }
+
+ /**
+ * Gets the list of interfaces from a class. If the
+ * class name is actually an interface then just that
+ * interface is returned.
+ * @returns array List of interfaces.
+ * @access public
+ */
+ function getInterfaces() {
+ $reflection = new ReflectionClass($this->interface);
+ if ($reflection->isInterface()) {
+ return array($this->interface);
+ }
+ return $this->onlyParents($reflection->getInterfaces());
+ }
+
+ /**
+ * Gets the list of methods for the implemented
+ * interfaces only.
+ * @returns array List of enforced method signatures.
+ * @access public
+ */
+ function getInterfaceMethods() {
+ $methods = array();
+ foreach ($this->getInterfaces() as $interface) {
+ $methods = array_merge($methods, get_class_methods($interface));
+ }
+ return array_unique($methods);
+ }
+
+ /**
+ * Checks to see if the method signature has to be tightly
+ * specified.
+ * @param string $method Method name.
+ * @returns boolean True if enforced.
+ * @access private
+ */
+ protected function isInterfaceMethod($method) {
+ return in_array($method, $this->getInterfaceMethods());
+ }
+
+ /**
+ * Finds the parent class name.
+ * @returns string Parent class name.
+ * @access public
+ */
+ function getParent() {
+ $reflection = new ReflectionClass($this->interface);
+ $parent = $reflection->getParentClass();
+ if ($parent) {
+ return $parent->getName();
+ }
+ return false;
+ }
+
+ /**
+ * Trivially determines if the class is abstract.
+ * @returns boolean True if abstract.
+ * @access public
+ */
+ function isAbstract() {
+ $reflection = new ReflectionClass($this->interface);
+ return $reflection->isAbstract();
+ }
+
+ /**
+ * Trivially determines if the class is an interface.
+ * @returns boolean True if interface.
+ * @access public
+ */
+ function isInterface() {
+ $reflection = new ReflectionClass($this->interface);
+ return $reflection->isInterface();
+ }
+
+ /**
+ * Scans for final methods, as they screw up inherited
+ * mocks by not allowing you to override them.
+ * @returns boolean True if the class has a final method.
+ * @access public
+ */
+ function hasFinal() {
+ $reflection = new ReflectionClass($this->interface);
+ foreach ($reflection->getMethods() as $method) {
+ if ($method->isFinal()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Whittles a list of interfaces down to only the
+ * necessary top level parents.
+ * @param array $interfaces Reflection API interfaces
+ * to reduce.
+ * @returns array List of parent interface names.
+ * @access private
+ */
+ protected function onlyParents($interfaces) {
+ $parents = array();
+ $blacklist = array();
+ foreach ($interfaces as $interface) {
+ foreach($interfaces as $possible_parent) {
+ if ($interface->getName() == $possible_parent->getName()) {
+ continue;
+ }
+ if ($interface->isSubClassOf($possible_parent)) {
+ $blacklist[$possible_parent->getName()] = true;
+ }
+ }
+ if (!isset($blacklist[$interface->getName()])) {
+ $parents[] = $interface->getName();
+ }
+ }
+ return $parents;
+ }
+
+ /**
+ * Checks whether a method is abstract or not.
+ * @param string $name Method name.
+ * @return bool true if method is abstract, else false
+ * @access private
+ */
+ protected function isAbstractMethod($name) {
+ $interface = new ReflectionClass($this->interface);
+ if (! $interface->hasMethod($name)) {
+ return false;
+ }
+ return $interface->getMethod($name)->isAbstract();
+ }
+
+ /**
+ * Checks whether a method is the constructor.
+ * @param string $name Method name.
+ * @return bool true if method is the constructor
+ * @access private
+ */
+ protected function isConstructor($name) {
+ return ($name == '__construct') || ($name == $this->interface);
+ }
+
+ /**
+ * Checks whether a method is abstract in all parents or not.
+ * @param string $name Method name.
+ * @return bool true if method is abstract in parent, else false
+ * @access private
+ */
+ protected function isAbstractMethodInParents($name) {
+ $interface = new ReflectionClass($this->interface);
+ $parent = $interface->getParentClass();
+ while($parent) {
+ if (! $parent->hasMethod($name)) {
+ return false;
+ }
+ if ($parent->getMethod($name)->isAbstract()) {
+ return true;
+ }
+ $parent = $parent->getParentClass();
+ }
+ return false;
+ }
+
+ /**
+ * Checks whether a method is static or not.
+ * @param string $name Method name
+ * @return bool true if method is static, else false
+ * @access private
+ */
+ protected function isStaticMethod($name) {
+ $interface = new ReflectionClass($this->interface);
+ if (! $interface->hasMethod($name)) {
+ return false;
+ }
+ return $interface->getMethod($name)->isStatic();
+ }
+
+ /**
+ * Writes the source code matching the declaration
+ * of a method.
+ * @param string $name Method name.
+ * @return string Method signature up to last
+ * bracket.
+ * @access public
+ */
+ function getSignature($name) {
+ if ($name == '__set') {
+ return 'function __set($key, $value)';
+ }
+ if ($name == '__call') {
+ return 'function __call($method, $arguments)';
+ }
+ if (version_compare(phpversion(), '5.1.0', '>=')) {
+ if (in_array($name, array('__get', '__isset', $name == '__unset'))) {
+ return "function {$name}(\$key)";
+ }
+ }
+ if ($name == '__toString') {
+ return "function $name()";
+ }
+
+ // This wonky try-catch is a work around for a faulty method_exists()
+ // in early versions of PHP 5 which would return false for static
+ // methods. The Reflection classes work fine, but hasMethod()
+ // doesn't exist prior to PHP 5.1.0, so we need to use a more crude
+ // detection method.
+ try {
+ $interface = new ReflectionClass($this->interface);
+ $interface->getMethod($name);
+ } catch (ReflectionException $e) {
+ return "function $name()";
+ }
+ return $this->getFullSignature($name);
+ }
+
+ /**
+ * For a signature specified in an interface, full
+ * details must be replicated to be a valid implementation.
+ * @param string $name Method name.
+ * @return string Method signature up to last
+ * bracket.
+ * @access private
+ */
+ protected function getFullSignature($name) {
+ $interface = new ReflectionClass($this->interface);
+ $method = $interface->getMethod($name);
+ $reference = $method->returnsReference() ? '&' : '';
+ $static = $method->isStatic() ? 'static ' : '';
+ return "{$static}function $reference$name(" .
+ implode(', ', $this->getParameterSignatures($method)) .
+ ")";
+ }
+
+ /**
+ * Gets the source code for each parameter.
+ * @param ReflectionMethod $method Method object from
+ * reflection API
+ * @return array List of strings, each
+ * a snippet of code.
+ * @access private
+ */
+ protected function getParameterSignatures($method) {
+ $signatures = array();
+ foreach ($method->getParameters() as $parameter) {
+ $signature = '';
+ $type = $parameter->getClass();
+ if (is_null($type) && version_compare(phpversion(), '5.1.0', '>=') && $parameter->isArray()) {
+ $signature .= 'array ';
+ } elseif (!is_null($type)) {
+ $signature .= $type->getName() . ' ';
+ }
+ if ($parameter->isPassedByReference()) {
+ $signature .= '&';
+ }
+ $signature .= '$' . $this->suppressSpurious($parameter->getName());
+ if ($this->isOptional($parameter)) {
+ $signature .= ' = null';
+ }
+ $signatures[] = $signature;
+ }
+ return $signatures;
+ }
+
+ /**
+ * The SPL library has problems with the
+ * Reflection library. In particular, you can
+ * get extra characters in parameter names :(.
+ * @param string $name Parameter name.
+ * @return string Cleaner name.
+ * @access private
+ */
+ protected function suppressSpurious($name) {
+ return str_replace(array('[', ']', ' '), '', $name);
+ }
+
+ /**
+ * Test of a reflection parameter being optional
+ * that works with early versions of PHP5.
+ * @param reflectionParameter $parameter Is this optional.
+ * @return boolean True if optional.
+ * @access private
+ */
+ protected function isOptional($parameter) {
+ if (method_exists($parameter, 'isOptional')) {
+ return $parameter->isOptional();
+ }
+ return false;
+ }
+}
+?>
\ No newline at end of file
diff --git a/code/ryzom/tools/server/www/webtt/vendors/simpletest/remote.php b/code/ryzom/tools/server/www/webtt/vendors/simpletest/remote.php
new file mode 100644
index 000000000..4bb37b7c5
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/vendors/simpletest/remote.php
@@ -0,0 +1,115 @@
+url = $url;
+ $this->dry_url = $dry_url ? $dry_url : $url;
+ $this->size = false;
+ }
+
+ /**
+ * Accessor for the test name for subclasses.
+ * @return string Name of the test.
+ * @access public
+ */
+ function getLabel() {
+ return $this->url;
+ }
+
+ /**
+ * Runs the top level test for this class. Currently
+ * reads the data as a single chunk. I'll fix this
+ * once I have added iteration to the browser.
+ * @param SimpleReporter $reporter Target of test results.
+ * @returns boolean True if no failures.
+ * @access public
+ */
+ function run($reporter) {
+ $browser = $this->createBrowser();
+ $xml = $browser->get($this->url);
+ if (! $xml) {
+ trigger_error('Cannot read remote test URL [' . $this->url . ']');
+ return false;
+ }
+ $parser = $this->createParser($reporter);
+ if (! $parser->parse($xml)) {
+ trigger_error('Cannot parse incoming XML from [' . $this->url . ']');
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Creates a new web browser object for fetching
+ * the XML report.
+ * @return SimpleBrowser New browser.
+ * @access protected
+ */
+ protected function createBrowser() {
+ return new SimpleBrowser();
+ }
+
+ /**
+ * Creates the XML parser.
+ * @param SimpleReporter $reporter Target of test results.
+ * @return SimpleTestXmlListener XML reader.
+ * @access protected
+ */
+ protected function createParser($reporter) {
+ return new SimpleTestXmlParser($reporter);
+ }
+
+ /**
+ * Accessor for the number of subtests.
+ * @return integer Number of test cases.
+ * @access public
+ */
+ function getSize() {
+ if ($this->size === false) {
+ $browser = $this->createBrowser();
+ $xml = $browser->get($this->dry_url);
+ if (! $xml) {
+ trigger_error('Cannot read remote test URL [' . $this->dry_url . ']');
+ return false;
+ }
+ $reporter = new SimpleReporter();
+ $parser = $this->createParser($reporter);
+ if (! $parser->parse($xml)) {
+ trigger_error('Cannot parse incoming XML from [' . $this->dry_url . ']');
+ return false;
+ }
+ $this->size = $reporter->getTestCaseCount();
+ }
+ return $this->size;
+ }
+}
+?>
\ No newline at end of file
diff --git a/code/ryzom/tools/server/www/webtt/vendors/simpletest/reporter.php b/code/ryzom/tools/server/www/webtt/vendors/simpletest/reporter.php
new file mode 100644
index 000000000..bf8d2ac11
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/vendors/simpletest/reporter.php
@@ -0,0 +1,445 @@
+character_set = $character_set;
+ }
+
+ /**
+ * Paints the top of the web page setting the
+ * title to the name of the starting test.
+ * @param string $test_name Name class of test.
+ * @access public
+ */
+ function paintHeader($test_name) {
+ $this->sendNoCacheHeaders();
+ print "";
+ print "\n\n$test_name \n";
+ print " \n";
+ print "\n";
+ print "\n\n";
+ print "$test_name \n";
+ flush();
+ }
+
+ /**
+ * Send the headers necessary to ensure the page is
+ * reloaded on every request. Otherwise you could be
+ * scratching your head over out of date test data.
+ * @access public
+ */
+ static function sendNoCacheHeaders() {
+ if (! headers_sent()) {
+ header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
+ header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
+ header("Cache-Control: no-store, no-cache, must-revalidate");
+ header("Cache-Control: post-check=0, pre-check=0", false);
+ header("Pragma: no-cache");
+ }
+ }
+
+ /**
+ * Paints the CSS. Add additional styles here.
+ * @return string CSS code as text.
+ * @access protected
+ */
+ protected function getCss() {
+ return ".fail { background-color: inherit; color: red; }" .
+ ".pass { background-color: inherit; color: green; }" .
+ " pre { background-color: lightgray; color: inherit; }";
+ }
+
+ /**
+ * Paints the end of the test with a summary of
+ * the passes and failures.
+ * @param string $test_name Name class of test.
+ * @access public
+ */
+ function paintFooter($test_name) {
+ $colour = ($this->getFailCount() + $this->getExceptionCount() > 0 ? "red" : "green");
+ print "";
+ print $this->getTestCaseProgress() . "/" . $this->getTestCaseCount();
+ print " test cases complete:\n";
+ print "" . $this->getPassCount() . " passes, ";
+ print "" . $this->getFailCount() . " fails and ";
+ print "" . $this->getExceptionCount() . " exceptions.";
+ print "
\n";
+ print "\n\n";
+ }
+
+ /**
+ * Paints the test failure with a breadcrumbs
+ * trail of the nesting test suites below the
+ * top level test.
+ * @param string $message Failure message displayed in
+ * the context of the other tests.
+ */
+ function paintFail($message) {
+ parent::paintFail($message);
+ print "Fail : ";
+ $breadcrumb = $this->getTestList();
+ array_shift($breadcrumb);
+ print implode(" -> ", $breadcrumb);
+ print " -> " . $this->htmlEntities($message) . " \n";
+ }
+
+ /**
+ * Paints a PHP error.
+ * @param string $message Message is ignored.
+ * @access public
+ */
+ function paintError($message) {
+ parent::paintError($message);
+ print "Exception : ";
+ $breadcrumb = $this->getTestList();
+ array_shift($breadcrumb);
+ print implode(" -> ", $breadcrumb);
+ print " -> " . $this->htmlEntities($message) . " \n";
+ }
+
+ /**
+ * Paints a PHP exception.
+ * @param Exception $exception Exception to display.
+ * @access public
+ */
+ function paintException($exception) {
+ parent::paintException($exception);
+ print "Exception : ";
+ $breadcrumb = $this->getTestList();
+ array_shift($breadcrumb);
+ print implode(" -> ", $breadcrumb);
+ $message = 'Unexpected exception of type [' . get_class($exception) .
+ '] with message ['. $exception->getMessage() .
+ '] in ['. $exception->getFile() .
+ ' line ' . $exception->getLine() . ']';
+ print " -> " . $this->htmlEntities($message) . " \n";
+ }
+
+ /**
+ * Prints the message for skipping tests.
+ * @param string $message Text of skip condition.
+ * @access public
+ */
+ function paintSkip($message) {
+ parent::paintSkip($message);
+ print "Skipped : ";
+ $breadcrumb = $this->getTestList();
+ array_shift($breadcrumb);
+ print implode(" -> ", $breadcrumb);
+ print " -> " . $this->htmlEntities($message) . " \n";
+ }
+
+ /**
+ * Paints formatted text such as dumped privateiables.
+ * @param string $message Text to show.
+ * @access public
+ */
+ function paintFormattedMessage($message) {
+ print '' . $this->htmlEntities($message) . ' ';
+ }
+
+ /**
+ * Character set adjusted entity conversion.
+ * @param string $message Plain text or Unicode message.
+ * @return string Browser readable message.
+ * @access protected
+ */
+ protected function htmlEntities($message) {
+ return htmlentities($message, ENT_COMPAT, $this->character_set);
+ }
+}
+
+/**
+ * Sample minimal test displayer. Generates only
+ * failure messages and a pass count. For command
+ * line use. I've tried to make it look like JUnit,
+ * but I wanted to output the errors as they arrived
+ * which meant dropping the dots.
+ * @package SimpleTest
+ * @subpackage UnitTester
+ */
+class TextReporter extends SimpleReporter {
+
+ /**
+ * Does nothing yet. The first output will
+ * be sent on the first test start.
+ */
+ function __construct() {
+ parent::__construct();
+ }
+
+ /**
+ * Paints the title only.
+ * @param string $test_name Name class of test.
+ * @access public
+ */
+ function paintHeader($test_name) {
+ if (! SimpleReporter::inCli()) {
+ header('Content-type: text/plain');
+ }
+ print "$test_name\n";
+ flush();
+ }
+
+ /**
+ * Paints the end of the test with a summary of
+ * the passes and failures.
+ * @param string $test_name Name class of test.
+ * @access public
+ */
+ function paintFooter($test_name) {
+ if ($this->getFailCount() + $this->getExceptionCount() == 0) {
+ print "OK\n";
+ } else {
+ print "FAILURES!!!\n";
+ }
+ print "Test cases run: " . $this->getTestCaseProgress() .
+ "/" . $this->getTestCaseCount() .
+ ", Passes: " . $this->getPassCount() .
+ ", Failures: " . $this->getFailCount() .
+ ", Exceptions: " . $this->getExceptionCount() . "\n";
+ }
+
+ /**
+ * Paints the test failure as a stack trace.
+ * @param string $message Failure message displayed in
+ * the context of the other tests.
+ * @access public
+ */
+ function paintFail($message) {
+ parent::paintFail($message);
+ print $this->getFailCount() . ") $message\n";
+ $breadcrumb = $this->getTestList();
+ array_shift($breadcrumb);
+ print "\tin " . implode("\n\tin ", array_reverse($breadcrumb));
+ print "\n";
+ }
+
+ /**
+ * Paints a PHP error or exception.
+ * @param string $message Message to be shown.
+ * @access public
+ * @abstract
+ */
+ function paintError($message) {
+ parent::paintError($message);
+ print "Exception " . $this->getExceptionCount() . "!\n$message\n";
+ $breadcrumb = $this->getTestList();
+ array_shift($breadcrumb);
+ print "\tin " . implode("\n\tin ", array_reverse($breadcrumb));
+ print "\n";
+ }
+
+ /**
+ * Paints a PHP error or exception.
+ * @param Exception $exception Exception to describe.
+ * @access public
+ * @abstract
+ */
+ function paintException($exception) {
+ parent::paintException($exception);
+ $message = 'Unexpected exception of type [' . get_class($exception) .
+ '] with message ['. $exception->getMessage() .
+ '] in ['. $exception->getFile() .
+ ' line ' . $exception->getLine() . ']';
+ print "Exception " . $this->getExceptionCount() . "!\n$message\n";
+ $breadcrumb = $this->getTestList();
+ array_shift($breadcrumb);
+ print "\tin " . implode("\n\tin ", array_reverse($breadcrumb));
+ print "\n";
+ }
+
+ /**
+ * Prints the message for skipping tests.
+ * @param string $message Text of skip condition.
+ * @access public
+ */
+ function paintSkip($message) {
+ parent::paintSkip($message);
+ print "Skip: $message\n";
+ }
+
+ /**
+ * Paints formatted text such as dumped privateiables.
+ * @param string $message Text to show.
+ * @access public
+ */
+ function paintFormattedMessage($message) {
+ print "$message\n";
+ flush();
+ }
+}
+
+/**
+ * Runs just a single test group, a single case or
+ * even a single test within that case.
+ * @package SimpleTest
+ * @subpackage UnitTester
+ */
+class SelectiveReporter extends SimpleReporterDecorator {
+ private $just_this_case = false;
+ private $just_this_test = false;
+ private $on;
+
+ /**
+ * Selects the test case or group to be run,
+ * and optionally a specific test.
+ * @param SimpleScorer $reporter Reporter to receive events.
+ * @param string $just_this_case Only this case or group will run.
+ * @param string $just_this_test Only this test method will run.
+ */
+ function __construct($reporter, $just_this_case = false, $just_this_test = false) {
+ if (isset($just_this_case) && $just_this_case) {
+ $this->just_this_case = strtolower($just_this_case);
+ $this->off();
+ } else {
+ $this->on();
+ }
+ if (isset($just_this_test) && $just_this_test) {
+ $this->just_this_test = strtolower($just_this_test);
+ }
+ parent::__construct($reporter);
+ }
+
+ /**
+ * Compares criteria to actual the case/group name.
+ * @param string $test_case The incoming test.
+ * @return boolean True if matched.
+ * @access protected
+ */
+ protected function matchesTestCase($test_case) {
+ return $this->just_this_case == strtolower($test_case);
+ }
+
+ /**
+ * Compares criteria to actual the test name. If no
+ * name was specified at the beginning, then all tests
+ * can run.
+ * @param string $method The incoming test method.
+ * @return boolean True if matched.
+ * @access protected
+ */
+ protected function shouldRunTest($test_case, $method) {
+ if ($this->isOn() || $this->matchesTestCase($test_case)) {
+ if ($this->just_this_test) {
+ return $this->just_this_test == strtolower($method);
+ } else {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Switch on testing for the group or subgroup.
+ * @access private
+ */
+ protected function on() {
+ $this->on = true;
+ }
+
+ /**
+ * Switch off testing for the group or subgroup.
+ * @access private
+ */
+ protected function off() {
+ $this->on = false;
+ }
+
+ /**
+ * Is this group actually being tested?
+ * @return boolean True if the current test group is active.
+ * @access private
+ */
+ protected function isOn() {
+ return $this->on;
+ }
+
+ /**
+ * Veto everything that doesn't match the method wanted.
+ * @param string $test_case Name of test case.
+ * @param string $method Name of test method.
+ * @return boolean True if test should be run.
+ * @access public
+ */
+ function shouldInvoke($test_case, $method) {
+ if ($this->shouldRunTest($test_case, $method)) {
+ return $this->reporter->shouldInvoke($test_case, $method);
+ }
+ return false;
+ }
+
+ /**
+ * Paints the start of a group test.
+ * @param string $test_case Name of test or other label.
+ * @param integer $size Number of test cases starting.
+ * @access public
+ */
+ function paintGroupStart($test_case, $size) {
+ if ($this->just_this_case && $this->matchesTestCase($test_case)) {
+ $this->on();
+ }
+ $this->reporter->paintGroupStart($test_case, $size);
+ }
+
+ /**
+ * Paints the end of a group test.
+ * @param string $test_case Name of test or other label.
+ * @access public
+ */
+ function paintGroupEnd($test_case) {
+ $this->reporter->paintGroupEnd($test_case);
+ if ($this->just_this_case && $this->matchesTestCase($test_case)) {
+ $this->off();
+ }
+ }
+}
+
+/**
+ * Suppresses skip messages.
+ * @package SimpleTest
+ * @subpackage UnitTester
+ */
+class NoSkipsReporter extends SimpleReporterDecorator {
+
+ /**
+ * Does nothing.
+ * @param string $message Text of skip condition.
+ * @access public
+ */
+ function paintSkip($message) { }
+}
+?>
\ No newline at end of file
diff --git a/code/ryzom/tools/server/www/webtt/vendors/simpletest/scorer.php b/code/ryzom/tools/server/www/webtt/vendors/simpletest/scorer.php
new file mode 100644
index 000000000..27776f4b6
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/vendors/simpletest/scorer.php
@@ -0,0 +1,875 @@
+passes = 0;
+ $this->fails = 0;
+ $this->exceptions = 0;
+ $this->is_dry_run = false;
+ }
+
+ /**
+ * Signals that the next evaluation will be a dry
+ * run. That is, the structure events will be
+ * recorded, but no tests will be run.
+ * @param boolean $is_dry Dry run if true.
+ * @access public
+ */
+ function makeDry($is_dry = true) {
+ $this->is_dry_run = $is_dry;
+ }
+
+ /**
+ * The reporter has a veto on what should be run.
+ * @param string $test_case_name name of test case.
+ * @param string $method Name of test method.
+ * @access public
+ */
+ function shouldInvoke($test_case_name, $method) {
+ return ! $this->is_dry_run;
+ }
+
+ /**
+ * Can wrap the invoker in preperation for running
+ * a test.
+ * @param SimpleInvoker $invoker Individual test runner.
+ * @return SimpleInvoker Wrapped test runner.
+ * @access public
+ */
+ function createInvoker($invoker) {
+ return $invoker;
+ }
+
+ /**
+ * Accessor for current status. Will be false
+ * if there have been any failures or exceptions.
+ * Used for command line tools.
+ * @return boolean True if no failures.
+ * @access public
+ */
+ function getStatus() {
+ if ($this->exceptions + $this->fails > 0) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Paints the start of a group test.
+ * @param string $test_name Name of test or other label.
+ * @param integer $size Number of test cases starting.
+ * @access public
+ */
+ function paintGroupStart($test_name, $size) {
+ }
+
+ /**
+ * Paints the end of a group test.
+ * @param string $test_name Name of test or other label.
+ * @access public
+ */
+ function paintGroupEnd($test_name) {
+ }
+
+ /**
+ * Paints the start of a test case.
+ * @param string $test_name Name of test or other label.
+ * @access public
+ */
+ function paintCaseStart($test_name) {
+ }
+
+ /**
+ * Paints the end of a test case.
+ * @param string $test_name Name of test or other label.
+ * @access public
+ */
+ function paintCaseEnd($test_name) {
+ }
+
+ /**
+ * Paints the start of a test method.
+ * @param string $test_name Name of test or other label.
+ * @access public
+ */
+ function paintMethodStart($test_name) {
+ }
+
+ /**
+ * Paints the end of a test method.
+ * @param string $test_name Name of test or other label.
+ * @access public
+ */
+ function paintMethodEnd($test_name) {
+ }
+
+ /**
+ * Increments the pass count.
+ * @param string $message Message is ignored.
+ * @access public
+ */
+ function paintPass($message) {
+ $this->passes++;
+ }
+
+ /**
+ * Increments the fail count.
+ * @param string $message Message is ignored.
+ * @access public
+ */
+ function paintFail($message) {
+ $this->fails++;
+ }
+
+ /**
+ * Deals with PHP 4 throwing an error.
+ * @param string $message Text of error formatted by
+ * the test case.
+ * @access public
+ */
+ function paintError($message) {
+ $this->exceptions++;
+ }
+
+ /**
+ * Deals with PHP 5 throwing an exception.
+ * @param Exception $exception The actual exception thrown.
+ * @access public
+ */
+ function paintException($exception) {
+ $this->exceptions++;
+ }
+
+ /**
+ * Prints the message for skipping tests.
+ * @param string $message Text of skip condition.
+ * @access public
+ */
+ function paintSkip($message) {
+ }
+
+ /**
+ * Accessor for the number of passes so far.
+ * @return integer Number of passes.
+ * @access public
+ */
+ function getPassCount() {
+ return $this->passes;
+ }
+
+ /**
+ * Accessor for the number of fails so far.
+ * @return integer Number of fails.
+ * @access public
+ */
+ function getFailCount() {
+ return $this->fails;
+ }
+
+ /**
+ * Accessor for the number of untrapped errors
+ * so far.
+ * @return integer Number of exceptions.
+ * @access public
+ */
+ function getExceptionCount() {
+ return $this->exceptions;
+ }
+
+ /**
+ * Paints a simple supplementary message.
+ * @param string $message Text to display.
+ * @access public
+ */
+ function paintMessage($message) {
+ }
+
+ /**
+ * Paints a formatted ASCII message such as a
+ * privateiable dump.
+ * @param string $message Text to display.
+ * @access public
+ */
+ function paintFormattedMessage($message) {
+ }
+
+ /**
+ * By default just ignores user generated events.
+ * @param string $type Event type as text.
+ * @param mixed $payload Message or object.
+ * @access public
+ */
+ function paintSignal($type, $payload) {
+ }
+}
+
+/**
+ * Recipient of generated test messages that can display
+ * page footers and headers. Also keeps track of the
+ * test nesting. This is the main base class on which
+ * to build the finished test (page based) displays.
+ * @package SimpleTest
+ * @subpackage UnitTester
+ */
+class SimpleReporter extends SimpleScorer {
+ private $test_stack;
+ private $size;
+ private $progress;
+
+ /**
+ * Starts the display with no results in.
+ * @access public
+ */
+ function __construct() {
+ parent::__construct();
+ $this->test_stack = array();
+ $this->size = null;
+ $this->progress = 0;
+ }
+
+ /**
+ * Gets the formatter for small generic data items.
+ * @return SimpleDumper Formatter.
+ * @access public
+ */
+ function getDumper() {
+ return new SimpleDumper();
+ }
+
+ /**
+ * Paints the start of a group test. Will also paint
+ * the page header and footer if this is the
+ * first test. Will stash the size if the first
+ * start.
+ * @param string $test_name Name of test that is starting.
+ * @param integer $size Number of test cases starting.
+ * @access public
+ */
+ function paintGroupStart($test_name, $size) {
+ if (! isset($this->size)) {
+ $this->size = $size;
+ }
+ if (count($this->test_stack) == 0) {
+ $this->paintHeader($test_name);
+ }
+ $this->test_stack[] = $test_name;
+ }
+
+ /**
+ * Paints the end of a group test. Will paint the page
+ * footer if the stack of tests has unwound.
+ * @param string $test_name Name of test that is ending.
+ * @param integer $progress Number of test cases ending.
+ * @access public
+ */
+ function paintGroupEnd($test_name) {
+ array_pop($this->test_stack);
+ if (count($this->test_stack) == 0) {
+ $this->paintFooter($test_name);
+ }
+ }
+
+ /**
+ * Paints the start of a test case. Will also paint
+ * the page header and footer if this is the
+ * first test. Will stash the size if the first
+ * start.
+ * @param string $test_name Name of test that is starting.
+ * @access public
+ */
+ function paintCaseStart($test_name) {
+ if (! isset($this->size)) {
+ $this->size = 1;
+ }
+ if (count($this->test_stack) == 0) {
+ $this->paintHeader($test_name);
+ }
+ $this->test_stack[] = $test_name;
+ }
+
+ /**
+ * Paints the end of a test case. Will paint the page
+ * footer if the stack of tests has unwound.
+ * @param string $test_name Name of test that is ending.
+ * @access public
+ */
+ function paintCaseEnd($test_name) {
+ $this->progress++;
+ array_pop($this->test_stack);
+ if (count($this->test_stack) == 0) {
+ $this->paintFooter($test_name);
+ }
+ }
+
+ /**
+ * Paints the start of a test method.
+ * @param string $test_name Name of test that is starting.
+ * @access public
+ */
+ function paintMethodStart($test_name) {
+ $this->test_stack[] = $test_name;
+ }
+
+ /**
+ * Paints the end of a test method. Will paint the page
+ * footer if the stack of tests has unwound.
+ * @param string $test_name Name of test that is ending.
+ * @access public
+ */
+ function paintMethodEnd($test_name) {
+ array_pop($this->test_stack);
+ }
+
+ /**
+ * Paints the test document header.
+ * @param string $test_name First test top level
+ * to start.
+ * @access public
+ * @abstract
+ */
+ function paintHeader($test_name) {
+ }
+
+ /**
+ * Paints the test document footer.
+ * @param string $test_name The top level test.
+ * @access public
+ * @abstract
+ */
+ function paintFooter($test_name) {
+ }
+
+ /**
+ * Accessor for internal test stack. For
+ * subclasses that need to see the whole test
+ * history for display purposes.
+ * @return array List of methods in nesting order.
+ * @access public
+ */
+ function getTestList() {
+ return $this->test_stack;
+ }
+
+ /**
+ * Accessor for total test size in number
+ * of test cases. Null until the first
+ * test is started.
+ * @return integer Total number of cases at start.
+ * @access public
+ */
+ function getTestCaseCount() {
+ return $this->size;
+ }
+
+ /**
+ * Accessor for the number of test cases
+ * completed so far.
+ * @return integer Number of ended cases.
+ * @access public
+ */
+ function getTestCaseProgress() {
+ return $this->progress;
+ }
+
+ /**
+ * Static check for running in the comand line.
+ * @return boolean True if CLI.
+ * @access public
+ */
+ static function inCli() {
+ return php_sapi_name() == 'cli';
+ }
+}
+
+/**
+ * For modifying the behaviour of the visual reporters.
+ * @package SimpleTest
+ * @subpackage UnitTester
+ */
+class SimpleReporterDecorator {
+ protected $reporter;
+
+ /**
+ * Mediates between the reporter and the test case.
+ * @param SimpleScorer $reporter Reporter to receive events.
+ */
+ function __construct($reporter) {
+ $this->reporter = $reporter;
+ }
+
+ /**
+ * Signals that the next evaluation will be a dry
+ * run. That is, the structure events will be
+ * recorded, but no tests will be run.
+ * @param boolean $is_dry Dry run if true.
+ * @access public
+ */
+ function makeDry($is_dry = true) {
+ $this->reporter->makeDry($is_dry);
+ }
+
+ /**
+ * Accessor for current status. Will be false
+ * if there have been any failures or exceptions.
+ * Used for command line tools.
+ * @return boolean True if no failures.
+ * @access public
+ */
+ function getStatus() {
+ return $this->reporter->getStatus();
+ }
+
+ /**
+ * The nesting of the test cases so far. Not
+ * all reporters have this facility.
+ * @return array Test list if accessible.
+ * @access public
+ */
+ function getTestList() {
+ if (method_exists($this->reporter, 'getTestList')) {
+ return $this->reporter->getTestList();
+ } else {
+ return array();
+ }
+ }
+
+ /**
+ * The reporter has a veto on what should be run.
+ * @param string $test_case_name Name of test case.
+ * @param string $method Name of test method.
+ * @return boolean True if test should be run.
+ * @access public
+ */
+ function shouldInvoke($test_case_name, $method) {
+ return $this->reporter->shouldInvoke($test_case_name, $method);
+ }
+
+ /**
+ * Can wrap the invoker in preparation for running
+ * a test.
+ * @param SimpleInvoker $invoker Individual test runner.
+ * @return SimpleInvoker Wrapped test runner.
+ * @access public
+ */
+ function createInvoker($invoker) {
+ return $this->reporter->createInvoker($invoker);
+ }
+
+ /**
+ * Gets the formatter for privateiables and other small
+ * generic data items.
+ * @return SimpleDumper Formatter.
+ * @access public
+ */
+ function getDumper() {
+ return $this->reporter->getDumper();
+ }
+
+ /**
+ * Paints the start of a group test.
+ * @param string $test_name Name of test or other label.
+ * @param integer $size Number of test cases starting.
+ * @access public
+ */
+ function paintGroupStart($test_name, $size) {
+ $this->reporter->paintGroupStart($test_name, $size);
+ }
+
+ /**
+ * Paints the end of a group test.
+ * @param string $test_name Name of test or other label.
+ * @access public
+ */
+ function paintGroupEnd($test_name) {
+ $this->reporter->paintGroupEnd($test_name);
+ }
+
+ /**
+ * Paints the start of a test case.
+ * @param string $test_name Name of test or other label.
+ * @access public
+ */
+ function paintCaseStart($test_name) {
+ $this->reporter->paintCaseStart($test_name);
+ }
+
+ /**
+ * Paints the end of a test case.
+ * @param string $test_name Name of test or other label.
+ * @access public
+ */
+ function paintCaseEnd($test_name) {
+ $this->reporter->paintCaseEnd($test_name);
+ }
+
+ /**
+ * Paints the start of a test method.
+ * @param string $test_name Name of test or other label.
+ * @access public
+ */
+ function paintMethodStart($test_name) {
+ $this->reporter->paintMethodStart($test_name);
+ }
+
+ /**
+ * Paints the end of a test method.
+ * @param string $test_name Name of test or other label.
+ * @access public
+ */
+ function paintMethodEnd($test_name) {
+ $this->reporter->paintMethodEnd($test_name);
+ }
+
+ /**
+ * Chains to the wrapped reporter.
+ * @param string $message Message is ignored.
+ * @access public
+ */
+ function paintPass($message) {
+ $this->reporter->paintPass($message);
+ }
+
+ /**
+ * Chains to the wrapped reporter.
+ * @param string $message Message is ignored.
+ * @access public
+ */
+ function paintFail($message) {
+ $this->reporter->paintFail($message);
+ }
+
+ /**
+ * Chains to the wrapped reporter.
+ * @param string $message Text of error formatted by
+ * the test case.
+ * @access public
+ */
+ function paintError($message) {
+ $this->reporter->paintError($message);
+ }
+
+ /**
+ * Chains to the wrapped reporter.
+ * @param Exception $exception Exception to show.
+ * @access public
+ */
+ function paintException($exception) {
+ $this->reporter->paintException($exception);
+ }
+
+ /**
+ * Prints the message for skipping tests.
+ * @param string $message Text of skip condition.
+ * @access public
+ */
+ function paintSkip($message) {
+ $this->reporter->paintSkip($message);
+ }
+
+ /**
+ * Chains to the wrapped reporter.
+ * @param string $message Text to display.
+ * @access public
+ */
+ function paintMessage($message) {
+ $this->reporter->paintMessage($message);
+ }
+
+ /**
+ * Chains to the wrapped reporter.
+ * @param string $message Text to display.
+ * @access public
+ */
+ function paintFormattedMessage($message) {
+ $this->reporter->paintFormattedMessage($message);
+ }
+
+ /**
+ * Chains to the wrapped reporter.
+ * @param string $type Event type as text.
+ * @param mixed $payload Message or object.
+ * @return boolean Should return false if this
+ * type of signal should fail the
+ * test suite.
+ * @access public
+ */
+ function paintSignal($type, $payload) {
+ $this->reporter->paintSignal($type, $payload);
+ }
+}
+
+/**
+ * For sending messages to multiple reporters at
+ * the same time.
+ * @package SimpleTest
+ * @subpackage UnitTester
+ */
+class MultipleReporter {
+ private $reporters = array();
+
+ /**
+ * Adds a reporter to the subscriber list.
+ * @param SimpleScorer $reporter Reporter to receive events.
+ * @access public
+ */
+ function attachReporter($reporter) {
+ $this->reporters[] = $reporter;
+ }
+
+ /**
+ * Signals that the next evaluation will be a dry
+ * run. That is, the structure events will be
+ * recorded, but no tests will be run.
+ * @param boolean $is_dry Dry run if true.
+ * @access public
+ */
+ function makeDry($is_dry = true) {
+ for ($i = 0; $i < count($this->reporters); $i++) {
+ $this->reporters[$i]->makeDry($is_dry);
+ }
+ }
+
+ /**
+ * Accessor for current status. Will be false
+ * if there have been any failures or exceptions.
+ * If any reporter reports a failure, the whole
+ * suite fails.
+ * @return boolean True if no failures.
+ * @access public
+ */
+ function getStatus() {
+ for ($i = 0; $i < count($this->reporters); $i++) {
+ if (! $this->reporters[$i]->getStatus()) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * The reporter has a veto on what should be run.
+ * It requires all reporters to want to run the method.
+ * @param string $test_case_name name of test case.
+ * @param string $method Name of test method.
+ * @access public
+ */
+ function shouldInvoke($test_case_name, $method) {
+ for ($i = 0; $i < count($this->reporters); $i++) {
+ if (! $this->reporters[$i]->shouldInvoke($test_case_name, $method)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Every reporter gets a chance to wrap the invoker.
+ * @param SimpleInvoker $invoker Individual test runner.
+ * @return SimpleInvoker Wrapped test runner.
+ * @access public
+ */
+ function createInvoker($invoker) {
+ for ($i = 0; $i < count($this->reporters); $i++) {
+ $invoker = $this->reporters[$i]->createInvoker($invoker);
+ }
+ return $invoker;
+ }
+
+ /**
+ * Gets the formatter for privateiables and other small
+ * generic data items.
+ * @return SimpleDumper Formatter.
+ * @access public
+ */
+ function getDumper() {
+ return new SimpleDumper();
+ }
+
+ /**
+ * Paints the start of a group test.
+ * @param string $test_name Name of test or other label.
+ * @param integer $size Number of test cases starting.
+ * @access public
+ */
+ function paintGroupStart($test_name, $size) {
+ for ($i = 0; $i < count($this->reporters); $i++) {
+ $this->reporters[$i]->paintGroupStart($test_name, $size);
+ }
+ }
+
+ /**
+ * Paints the end of a group test.
+ * @param string $test_name Name of test or other label.
+ * @access public
+ */
+ function paintGroupEnd($test_name) {
+ for ($i = 0; $i < count($this->reporters); $i++) {
+ $this->reporters[$i]->paintGroupEnd($test_name);
+ }
+ }
+
+ /**
+ * Paints the start of a test case.
+ * @param string $test_name Name of test or other label.
+ * @access public
+ */
+ function paintCaseStart($test_name) {
+ for ($i = 0; $i < count($this->reporters); $i++) {
+ $this->reporters[$i]->paintCaseStart($test_name);
+ }
+ }
+
+ /**
+ * Paints the end of a test case.
+ * @param string $test_name Name of test or other label.
+ * @access public
+ */
+ function paintCaseEnd($test_name) {
+ for ($i = 0; $i < count($this->reporters); $i++) {
+ $this->reporters[$i]->paintCaseEnd($test_name);
+ }
+ }
+
+ /**
+ * Paints the start of a test method.
+ * @param string $test_name Name of test or other label.
+ * @access public
+ */
+ function paintMethodStart($test_name) {
+ for ($i = 0; $i < count($this->reporters); $i++) {
+ $this->reporters[$i]->paintMethodStart($test_name);
+ }
+ }
+
+ /**
+ * Paints the end of a test method.
+ * @param string $test_name Name of test or other label.
+ * @access public
+ */
+ function paintMethodEnd($test_name) {
+ for ($i = 0; $i < count($this->reporters); $i++) {
+ $this->reporters[$i]->paintMethodEnd($test_name);
+ }
+ }
+
+ /**
+ * Chains to the wrapped reporter.
+ * @param string $message Message is ignored.
+ * @access public
+ */
+ function paintPass($message) {
+ for ($i = 0; $i < count($this->reporters); $i++) {
+ $this->reporters[$i]->paintPass($message);
+ }
+ }
+
+ /**
+ * Chains to the wrapped reporter.
+ * @param string $message Message is ignored.
+ * @access public
+ */
+ function paintFail($message) {
+ for ($i = 0; $i < count($this->reporters); $i++) {
+ $this->reporters[$i]->paintFail($message);
+ }
+ }
+
+ /**
+ * Chains to the wrapped reporter.
+ * @param string $message Text of error formatted by
+ * the test case.
+ * @access public
+ */
+ function paintError($message) {
+ for ($i = 0; $i < count($this->reporters); $i++) {
+ $this->reporters[$i]->paintError($message);
+ }
+ }
+
+ /**
+ * Chains to the wrapped reporter.
+ * @param Exception $exception Exception to display.
+ * @access public
+ */
+ function paintException($exception) {
+ for ($i = 0; $i < count($this->reporters); $i++) {
+ $this->reporters[$i]->paintException($exception);
+ }
+ }
+
+ /**
+ * Prints the message for skipping tests.
+ * @param string $message Text of skip condition.
+ * @access public
+ */
+ function paintSkip($message) {
+ for ($i = 0; $i < count($this->reporters); $i++) {
+ $this->reporters[$i]->paintSkip($message);
+ }
+ }
+
+ /**
+ * Chains to the wrapped reporter.
+ * @param string $message Text to display.
+ * @access public
+ */
+ function paintMessage($message) {
+ for ($i = 0; $i < count($this->reporters); $i++) {
+ $this->reporters[$i]->paintMessage($message);
+ }
+ }
+
+ /**
+ * Chains to the wrapped reporter.
+ * @param string $message Text to display.
+ * @access public
+ */
+ function paintFormattedMessage($message) {
+ for ($i = 0; $i < count($this->reporters); $i++) {
+ $this->reporters[$i]->paintFormattedMessage($message);
+ }
+ }
+
+ /**
+ * Chains to the wrapped reporter.
+ * @param string $type Event type as text.
+ * @param mixed $payload Message or object.
+ * @return boolean Should return false if this
+ * type of signal should fail the
+ * test suite.
+ * @access public
+ */
+ function paintSignal($type, $payload) {
+ for ($i = 0; $i < count($this->reporters); $i++) {
+ $this->reporters[$i]->paintSignal($type, $payload);
+ }
+ }
+}
+?>
\ No newline at end of file
diff --git a/code/ryzom/tools/server/www/webtt/vendors/simpletest/selector.php b/code/ryzom/tools/server/www/webtt/vendors/simpletest/selector.php
new file mode 100644
index 000000000..ba2fed312
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/vendors/simpletest/selector.php
@@ -0,0 +1,141 @@
+name = $name;
+ }
+
+ /**
+ * Accessor for name.
+ * @returns string $name Name to match.
+ */
+ function getName() {
+ return $this->name;
+ }
+
+ /**
+ * Compares with name attribute of widget.
+ * @param SimpleWidget $widget Control to compare.
+ * @access public
+ */
+ function isMatch($widget) {
+ return ($widget->getName() == $this->name);
+ }
+}
+
+/**
+ * Used to extract form elements for testing against.
+ * Searches by visible label or alt text.
+ * @package SimpleTest
+ * @subpackage WebTester
+ */
+class SimpleByLabel {
+ private $label;
+
+ /**
+ * Stashes the name for later comparison.
+ * @param string $label Visible text to match.
+ */
+ function __construct($label) {
+ $this->label = $label;
+ }
+
+ /**
+ * Comparison. Compares visible text of widget or
+ * related label.
+ * @param SimpleWidget $widget Control to compare.
+ * @access public
+ */
+ function isMatch($widget) {
+ if (! method_exists($widget, 'isLabel')) {
+ return false;
+ }
+ return $widget->isLabel($this->label);
+ }
+}
+
+/**
+ * Used to extract form elements for testing against.
+ * Searches dy id attribute.
+ * @package SimpleTest
+ * @subpackage WebTester
+ */
+class SimpleById {
+ private $id;
+
+ /**
+ * Stashes the name for later comparison.
+ * @param string $id ID atribute to match.
+ */
+ function __construct($id) {
+ $this->id = $id;
+ }
+
+ /**
+ * Comparison. Compares id attribute of widget.
+ * @param SimpleWidget $widget Control to compare.
+ * @access public
+ */
+ function isMatch($widget) {
+ return $widget->isId($this->id);
+ }
+}
+
+/**
+ * Used to extract form elements for testing against.
+ * Searches by visible label, name or alt text.
+ * @package SimpleTest
+ * @subpackage WebTester
+ */
+class SimpleByLabelOrName {
+ private $label;
+
+ /**
+ * Stashes the name/label for later comparison.
+ * @param string $label Visible text to match.
+ */
+ function __construct($label) {
+ $this->label = $label;
+ }
+
+ /**
+ * Comparison. Compares visible text of widget or
+ * related label or name.
+ * @param SimpleWidget $widget Control to compare.
+ * @access public
+ */
+ function isMatch($widget) {
+ if (method_exists($widget, 'isLabel')) {
+ if ($widget->isLabel($this->label)) {
+ return true;
+ }
+ }
+ return ($widget->getName() == $this->label);
+ }
+}
+?>
\ No newline at end of file
diff --git a/code/ryzom/tools/server/www/webtt/vendors/simpletest/shell_tester.php b/code/ryzom/tools/server/www/webtt/vendors/simpletest/shell_tester.php
new file mode 100644
index 000000000..9a3bd389e
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/vendors/simpletest/shell_tester.php
@@ -0,0 +1,330 @@
+output = false;
+ }
+
+ /**
+ * Actually runs the command. Does not trap the
+ * error stream output as this need PHP 4.3+.
+ * @param string $command The actual command line
+ * to run.
+ * @return integer Exit code.
+ * @access public
+ */
+ function execute($command) {
+ $this->output = false;
+ exec($command, $this->output, $ret);
+ return $ret;
+ }
+
+ /**
+ * Accessor for the last output.
+ * @return string Output as text.
+ * @access public
+ */
+ function getOutput() {
+ return implode("\n", $this->output);
+ }
+
+ /**
+ * Accessor for the last output.
+ * @return array Output as array of lines.
+ * @access public
+ */
+ function getOutputAsList() {
+ return $this->output;
+ }
+}
+
+/**
+ * Test case for testing of command line scripts and
+ * utilities. Usually scripts that are external to the
+ * PHP code, but support it in some way.
+ * @package SimpleTest
+ * @subpackage UnitTester
+ */
+class ShellTestCase extends SimpleTestCase {
+ private $current_shell;
+ private $last_status;
+ private $last_command;
+
+ /**
+ * Creates an empty test case. Should be subclassed
+ * with test methods for a functional test case.
+ * @param string $label Name of test case. Will use
+ * the class name if none specified.
+ * @access public
+ */
+ function __construct($label = false) {
+ parent::__construct($label);
+ $this->current_shell = $this->createShell();
+ $this->last_status = false;
+ $this->last_command = '';
+ }
+
+ /**
+ * Executes a command and buffers the results.
+ * @param string $command Command to run.
+ * @return boolean True if zero exit code.
+ * @access public
+ */
+ function execute($command) {
+ $shell = $this->getShell();
+ $this->last_status = $shell->execute($command);
+ $this->last_command = $command;
+ return ($this->last_status === 0);
+ }
+
+ /**
+ * Dumps the output of the last command.
+ * @access public
+ */
+ function dumpOutput() {
+ $this->dump($this->getOutput());
+ }
+
+ /**
+ * Accessor for the last output.
+ * @return string Output as text.
+ * @access public
+ */
+ function getOutput() {
+ $shell = $this->getShell();
+ return $shell->getOutput();
+ }
+
+ /**
+ * Accessor for the last output.
+ * @return array Output as array of lines.
+ * @access public
+ */
+ function getOutputAsList() {
+ $shell = $this->getShell();
+ return $shell->getOutputAsList();
+ }
+
+ /**
+ * Called from within the test methods to register
+ * passes and failures.
+ * @param boolean $result Pass on true.
+ * @param string $message Message to display describing
+ * the test state.
+ * @return boolean True on pass
+ * @access public
+ */
+ function assertTrue($result, $message = false) {
+ return $this->assert(new TrueExpectation(), $result, $message);
+ }
+
+ /**
+ * Will be true on false and vice versa. False
+ * is the PHP definition of false, so that null,
+ * empty strings, zero and an empty array all count
+ * as false.
+ * @param boolean $result Pass on false.
+ * @param string $message Message to display.
+ * @return boolean True on pass
+ * @access public
+ */
+ function assertFalse($result, $message = '%s') {
+ return $this->assert(new FalseExpectation(), $result, $message);
+ }
+
+ /**
+ * Will trigger a pass if the two parameters have
+ * the same value only. Otherwise a fail. This
+ * is for testing hand extracted text, etc.
+ * @param mixed $first Value to compare.
+ * @param mixed $second Value to compare.
+ * @param string $message Message to display.
+ * @return boolean True on pass
+ * @access public
+ */
+ function assertEqual($first, $second, $message = "%s") {
+ return $this->assert(
+ new EqualExpectation($first),
+ $second,
+ $message);
+ }
+
+ /**
+ * Will trigger a pass if the two parameters have
+ * a different value. Otherwise a fail. This
+ * is for testing hand extracted text, etc.
+ * @param mixed $first Value to compare.
+ * @param mixed $second Value to compare.
+ * @param string $message Message to display.
+ * @return boolean True on pass
+ * @access public
+ */
+ function assertNotEqual($first, $second, $message = "%s") {
+ return $this->assert(
+ new NotEqualExpectation($first),
+ $second,
+ $message);
+ }
+
+ /**
+ * Tests the last status code from the shell.
+ * @param integer $status Expected status of last
+ * command.
+ * @param string $message Message to display.
+ * @return boolean True if pass.
+ * @access public
+ */
+ function assertExitCode($status, $message = "%s") {
+ $message = sprintf($message, "Expected status code of [$status] from [" .
+ $this->last_command . "], but got [" .
+ $this->last_status . "]");
+ return $this->assertTrue($status === $this->last_status, $message);
+ }
+
+ /**
+ * Attempt to exactly match the combined STDERR and
+ * STDOUT output.
+ * @param string $expected Expected output.
+ * @param string $message Message to display.
+ * @return boolean True if pass.
+ * @access public
+ */
+ function assertOutput($expected, $message = "%s") {
+ $shell = $this->getShell();
+ return $this->assert(
+ new EqualExpectation($expected),
+ $shell->getOutput(),
+ $message);
+ }
+
+ /**
+ * Scans the output for a Perl regex. If found
+ * anywhere it passes, else it fails.
+ * @param string $pattern Regex to search for.
+ * @param string $message Message to display.
+ * @return boolean True if pass.
+ * @access public
+ */
+ function assertOutputPattern($pattern, $message = "%s") {
+ $shell = $this->getShell();
+ return $this->assert(
+ new PatternExpectation($pattern),
+ $shell->getOutput(),
+ $message);
+ }
+
+ /**
+ * If a Perl regex is found anywhere in the current
+ * output then a failure is generated, else a pass.
+ * @param string $pattern Regex to search for.
+ * @param $message Message to display.
+ * @return boolean True if pass.
+ * @access public
+ */
+ function assertNoOutputPattern($pattern, $message = "%s") {
+ $shell = $this->getShell();
+ return $this->assert(
+ new NoPatternExpectation($pattern),
+ $shell->getOutput(),
+ $message);
+ }
+
+ /**
+ * File existence check.
+ * @param string $path Full filename and path.
+ * @param string $message Message to display.
+ * @return boolean True if pass.
+ * @access public
+ */
+ function assertFileExists($path, $message = "%s") {
+ $message = sprintf($message, "File [$path] should exist");
+ return $this->assertTrue(file_exists($path), $message);
+ }
+
+ /**
+ * File non-existence check.
+ * @param string $path Full filename and path.
+ * @param string $message Message to display.
+ * @return boolean True if pass.
+ * @access public
+ */
+ function assertFileNotExists($path, $message = "%s") {
+ $message = sprintf($message, "File [$path] should not exist");
+ return $this->assertFalse(file_exists($path), $message);
+ }
+
+ /**
+ * Scans a file for a Perl regex. If found
+ * anywhere it passes, else it fails.
+ * @param string $pattern Regex to search for.
+ * @param string $path Full filename and path.
+ * @param string $message Message to display.
+ * @return boolean True if pass.
+ * @access public
+ */
+ function assertFilePattern($pattern, $path, $message = "%s") {
+ return $this->assert(
+ new PatternExpectation($pattern),
+ implode('', file($path)),
+ $message);
+ }
+
+ /**
+ * If a Perl regex is found anywhere in the named
+ * file then a failure is generated, else a pass.
+ * @param string $pattern Regex to search for.
+ * @param string $path Full filename and path.
+ * @param string $message Message to display.
+ * @return boolean True if pass.
+ * @access public
+ */
+ function assertNoFilePattern($pattern, $path, $message = "%s") {
+ return $this->assert(
+ new NoPatternExpectation($pattern),
+ implode('', file($path)),
+ $message);
+ }
+
+ /**
+ * Accessor for current shell. Used for testing the
+ * the tester itself.
+ * @return Shell Current shell.
+ * @access protected
+ */
+ protected function getShell() {
+ return $this->current_shell;
+ }
+
+ /**
+ * Factory for the shell to run the command on.
+ * @return Shell New shell object.
+ * @access protected
+ */
+ protected function createShell() {
+ return new SimpleShell();
+ }
+}
+?>
\ No newline at end of file
diff --git a/code/ryzom/tools/server/www/webtt/vendors/simpletest/simpletest.php b/code/ryzom/tools/server/www/webtt/vendors/simpletest/simpletest.php
new file mode 100644
index 000000000..425c869a8
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/vendors/simpletest/simpletest.php
@@ -0,0 +1,391 @@
+getParent()) {
+ SimpleTest::ignore($parent);
+ }
+ }
+ }
+ }
+
+ /**
+ * Puts the object to the global pool of 'preferred' objects
+ * which can be retrieved with SimpleTest :: preferred() method.
+ * Instances of the same class are overwritten.
+ * @param object $object Preferred object
+ * @see preferred()
+ */
+ static function prefer($object) {
+ $registry = &SimpleTest::getRegistry();
+ $registry['Preferred'][] = $object;
+ }
+
+ /**
+ * Retrieves 'preferred' objects from global pool. Class filter
+ * can be applied in order to retrieve the object of the specific
+ * class
+ * @param array|string $classes Allowed classes or interfaces.
+ * @return array|object|null
+ * @see prefer()
+ */
+ static function preferred($classes) {
+ if (! is_array($classes)) {
+ $classes = array($classes);
+ }
+ $registry = &SimpleTest::getRegistry();
+ for ($i = count($registry['Preferred']) - 1; $i >= 0; $i--) {
+ foreach ($classes as $class) {
+ if (SimpleTestCompatibility::isA($registry['Preferred'][$i], $class)) {
+ return $registry['Preferred'][$i];
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Test to see if a test case is in the ignore
+ * list. Quite obviously the ignore list should
+ * be a separate object and will be one day.
+ * This method is internal to SimpleTest. Don't
+ * use it.
+ * @param string $class Class name to test.
+ * @return boolean True if should not be run.
+ */
+ static function isIgnored($class) {
+ $registry = &SimpleTest::getRegistry();
+ return isset($registry['IgnoreList'][strtolower($class)]);
+ }
+
+ /**
+ * Sets proxy to use on all requests for when
+ * testing from behind a firewall. Set host
+ * to false to disable. This will take effect
+ * if there are no other proxy settings.
+ * @param string $proxy Proxy host as URL.
+ * @param string $username Proxy username for authentication.
+ * @param string $password Proxy password for authentication.
+ */
+ static function useProxy($proxy, $username = false, $password = false) {
+ $registry = &SimpleTest::getRegistry();
+ $registry['DefaultProxy'] = $proxy;
+ $registry['DefaultProxyUsername'] = $username;
+ $registry['DefaultProxyPassword'] = $password;
+ }
+
+ /**
+ * Accessor for default proxy host.
+ * @return string Proxy URL.
+ */
+ static function getDefaultProxy() {
+ $registry = &SimpleTest::getRegistry();
+ return $registry['DefaultProxy'];
+ }
+
+ /**
+ * Accessor for default proxy username.
+ * @return string Proxy username for authentication.
+ */
+ static function getDefaultProxyUsername() {
+ $registry = &SimpleTest::getRegistry();
+ return $registry['DefaultProxyUsername'];
+ }
+
+ /**
+ * Accessor for default proxy password.
+ * @return string Proxy password for authentication.
+ */
+ static function getDefaultProxyPassword() {
+ $registry = &SimpleTest::getRegistry();
+ return $registry['DefaultProxyPassword'];
+ }
+
+ /**
+ * Accessor for default HTML parsers.
+ * @return array List of parsers to try in
+ * order until one responds true
+ * to can().
+ */
+ static function getParsers() {
+ $registry = &SimpleTest::getRegistry();
+ return $registry['Parsers'];
+ }
+
+ /**
+ * Set the list of HTML parsers to attempt to use by default.
+ * @param array $parsers List of parsers to try in
+ * order until one responds true
+ * to can().
+ */
+ static function setParsers($parsers) {
+ $registry = &SimpleTest::getRegistry();
+ $registry['Parsers'] = $parsers;
+ }
+
+ /**
+ * Accessor for global registry of options.
+ * @return hash All stored values.
+ */
+ protected static function &getRegistry() {
+ static $registry = false;
+ if (! $registry) {
+ $registry = SimpleTest::getDefaults();
+ }
+ return $registry;
+ }
+
+ /**
+ * Accessor for the context of the current
+ * test run.
+ * @return SimpleTestContext Current test run.
+ */
+ static function getContext() {
+ static $context = false;
+ if (! $context) {
+ $context = new SimpleTestContext();
+ }
+ return $context;
+ }
+
+ /**
+ * Constant default values.
+ * @return hash All registry defaults.
+ */
+ protected static function getDefaults() {
+ return array(
+ 'Parsers' => false,
+ 'MockBaseClass' => 'SimpleMock',
+ 'IgnoreList' => array(),
+ 'DefaultProxy' => false,
+ 'DefaultProxyUsername' => false,
+ 'DefaultProxyPassword' => false,
+ 'Preferred' => array(new HtmlReporter(), new TextReporter(), new XmlReporter()));
+ }
+
+ /**
+ * @deprecated
+ */
+ static function setMockBaseClass($mock_base) {
+ $registry = &SimpleTest::getRegistry();
+ $registry['MockBaseClass'] = $mock_base;
+ }
+
+ /**
+ * @deprecated
+ */
+ static function getMockBaseClass() {
+ $registry = &SimpleTest::getRegistry();
+ return $registry['MockBaseClass'];
+ }
+}
+
+/**
+ * Container for all components for a specific
+ * test run. Makes things like error queues
+ * available to PHP event handlers, and also
+ * gets around some nasty reference issues in
+ * the mocks.
+ * @package SimpleTest
+ */
+class SimpleTestContext {
+ private $test;
+ private $reporter;
+ private $resources;
+
+ /**
+ * Clears down the current context.
+ * @access public
+ */
+ function clear() {
+ $this->resources = array();
+ }
+
+ /**
+ * Sets the current test case instance. This
+ * global instance can be used by the mock objects
+ * to send message to the test cases.
+ * @param SimpleTestCase $test Test case to register.
+ */
+ function setTest($test) {
+ $this->clear();
+ $this->test = $test;
+ }
+
+ /**
+ * Accessor for currently running test case.
+ * @return SimpleTestCase Current test.
+ */
+ function getTest() {
+ return $this->test;
+ }
+
+ /**
+ * Sets the current reporter. This
+ * global instance can be used by the mock objects
+ * to send messages.
+ * @param SimpleReporter $reporter Reporter to register.
+ */
+ function setReporter($reporter) {
+ $this->clear();
+ $this->reporter = $reporter;
+ }
+
+ /**
+ * Accessor for current reporter.
+ * @return SimpleReporter Current reporter.
+ */
+ function getReporter() {
+ return $this->reporter;
+ }
+
+ /**
+ * Accessor for the Singleton resource.
+ * @return object Global resource.
+ */
+ function get($resource) {
+ if (! isset($this->resources[$resource])) {
+ $this->resources[$resource] = new $resource();
+ }
+ return $this->resources[$resource];
+ }
+}
+
+/**
+ * Interrogates the stack trace to recover the
+ * failure point.
+ * @package SimpleTest
+ * @subpackage UnitTester
+ */
+class SimpleStackTrace {
+ private $prefixes;
+
+ /**
+ * Stashes the list of target prefixes.
+ * @param array $prefixes List of method prefixes
+ * to search for.
+ */
+ function __construct($prefixes) {
+ $this->prefixes = $prefixes;
+ }
+
+ /**
+ * Extracts the last method name that was not within
+ * Simpletest itself. Captures a stack trace if none given.
+ * @param array $stack List of stack frames.
+ * @return string Snippet of test report with line
+ * number and file.
+ */
+ function traceMethod($stack = false) {
+ $stack = $stack ? $stack : $this->captureTrace();
+ foreach ($stack as $frame) {
+ if ($this->frameLiesWithinSimpleTestFolder($frame)) {
+ continue;
+ }
+ if ($this->frameMatchesPrefix($frame)) {
+ return ' at [' . $frame['file'] . ' line ' . $frame['line'] . ']';
+ }
+ }
+ return '';
+ }
+
+ /**
+ * Test to see if error is generated by SimpleTest itself.
+ * @param array $frame PHP stack frame.
+ * @return boolean True if a SimpleTest file.
+ */
+ protected function frameLiesWithinSimpleTestFolder($frame) {
+ if (isset($frame['file'])) {
+ $path = substr(SIMPLE_TEST, 0, -1);
+ if (strpos($frame['file'], $path) === 0) {
+ if (dirname($frame['file']) == $path) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Tries to determine if the method call is an assert, etc.
+ * @param array $frame PHP stack frame.
+ * @return boolean True if matches a target.
+ */
+ protected function frameMatchesPrefix($frame) {
+ foreach ($this->prefixes as $prefix) {
+ if (strncmp($frame['function'], $prefix, strlen($prefix)) == 0) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Grabs a current stack trace.
+ * @return array Fulle trace.
+ */
+ protected function captureTrace() {
+ if (function_exists('debug_backtrace')) {
+ return array_reverse(debug_backtrace());
+ }
+ return array();
+ }
+}
+?>
\ No newline at end of file
diff --git a/code/ryzom/tools/server/www/webtt/vendors/simpletest/socket.php b/code/ryzom/tools/server/www/webtt/vendors/simpletest/socket.php
new file mode 100644
index 000000000..06e8ca62d
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/vendors/simpletest/socket.php
@@ -0,0 +1,312 @@
+clearError();
+ }
+
+ /**
+ * Test for an outstanding error.
+ * @return boolean True if there is an error.
+ * @access public
+ */
+ function isError() {
+ return ($this->error != '');
+ }
+
+ /**
+ * Accessor for an outstanding error.
+ * @return string Empty string if no error otherwise
+ * the error message.
+ * @access public
+ */
+ function getError() {
+ return $this->error;
+ }
+
+ /**
+ * Sets the internal error.
+ * @param string Error message to stash.
+ * @access protected
+ */
+ function setError($error) {
+ $this->error = $error;
+ }
+
+ /**
+ * Resets the error state to no error.
+ * @access protected
+ */
+ function clearError() {
+ $this->setError('');
+ }
+}
+
+/**
+ * @package SimpleTest
+ * @subpackage WebTester
+ */
+class SimpleFileSocket extends SimpleStickyError {
+ private $handle;
+ private $is_open = false;
+ private $sent = '';
+ private $block_size;
+
+ /**
+ * Opens a socket for reading and writing.
+ * @param SimpleUrl $file Target URI to fetch.
+ * @param integer $block_size Size of chunk to read.
+ * @access public
+ */
+ function __construct($file, $block_size = 1024) {
+ parent::__construct();
+ if (! ($this->handle = $this->openFile($file, $error))) {
+ $file_string = $file->asString();
+ $this->setError("Cannot open [$file_string] with [$error]");
+ return;
+ }
+ $this->is_open = true;
+ $this->block_size = $block_size;
+ }
+
+ /**
+ * Writes some data to the socket and saves alocal copy.
+ * @param string $message String to send to socket.
+ * @return boolean True if successful.
+ * @access public
+ */
+ function write($message) {
+ return true;
+ }
+
+ /**
+ * Reads data from the socket. The error suppresion
+ * is a workaround for PHP4 always throwing a warning
+ * with a secure socket.
+ * @return integer/boolean Incoming bytes. False
+ * on error.
+ * @access public
+ */
+ function read() {
+ $raw = @fread($this->handle, $this->block_size);
+ if ($raw === false) {
+ $this->setError('Cannot read from socket');
+ $this->close();
+ }
+ return $raw;
+ }
+
+ /**
+ * Accessor for socket open state.
+ * @return boolean True if open.
+ * @access public
+ */
+ function isOpen() {
+ return $this->is_open;
+ }
+
+ /**
+ * Closes the socket preventing further reads.
+ * Cannot be reopened once closed.
+ * @return boolean True if successful.
+ * @access public
+ */
+ function close() {
+ if (!$this->is_open) return false;
+ $this->is_open = false;
+ return fclose($this->handle);
+ }
+
+ /**
+ * Accessor for content so far.
+ * @return string Bytes sent only.
+ * @access public
+ */
+ function getSent() {
+ return $this->sent;
+ }
+
+ /**
+ * Actually opens the low level socket.
+ * @param SimpleUrl $file SimpleUrl file target.
+ * @param string $error Recipient of error message.
+ * @param integer $timeout Maximum time to wait for connection.
+ * @access protected
+ */
+ protected function openFile($file, &$error) {
+ return @fopen($file->asString(), 'r');
+ }
+}
+
+/**
+ * Wrapper for TCP/IP socket.
+ * @package SimpleTest
+ * @subpackage WebTester
+ */
+class SimpleSocket extends SimpleStickyError {
+ private $handle;
+ private $is_open = false;
+ private $sent = '';
+ private $lock_size;
+
+ /**
+ * Opens a socket for reading and writing.
+ * @param string $host Hostname to send request to.
+ * @param integer $port Port on remote machine to open.
+ * @param integer $timeout Connection timeout in seconds.
+ * @param integer $block_size Size of chunk to read.
+ * @access public
+ */
+ function __construct($host, $port, $timeout, $block_size = 255) {
+ parent::__construct();
+ if (! ($this->handle = $this->openSocket($host, $port, $error_number, $error, $timeout))) {
+ $this->setError("Cannot open [$host:$port] with [$error] within [$timeout] seconds");
+ return;
+ }
+ $this->is_open = true;
+ $this->block_size = $block_size;
+ SimpleTestCompatibility::setTimeout($this->handle, $timeout);
+ }
+
+ /**
+ * Writes some data to the socket and saves alocal copy.
+ * @param string $message String to send to socket.
+ * @return boolean True if successful.
+ * @access public
+ */
+ function write($message) {
+ if ($this->isError() || ! $this->isOpen()) {
+ return false;
+ }
+ $count = fwrite($this->handle, $message);
+ if (! $count) {
+ if ($count === false) {
+ $this->setError('Cannot write to socket');
+ $this->close();
+ }
+ return false;
+ }
+ fflush($this->handle);
+ $this->sent .= $message;
+ return true;
+ }
+
+ /**
+ * Reads data from the socket. The error suppresion
+ * is a workaround for PHP4 always throwing a warning
+ * with a secure socket.
+ * @return integer/boolean Incoming bytes. False
+ * on error.
+ * @access public
+ */
+ function read() {
+ if ($this->isError() || ! $this->isOpen()) {
+ return false;
+ }
+ $raw = @fread($this->handle, $this->block_size);
+ if ($raw === false) {
+ $this->setError('Cannot read from socket');
+ $this->close();
+ }
+ return $raw;
+ }
+
+ /**
+ * Accessor for socket open state.
+ * @return boolean True if open.
+ * @access public
+ */
+ function isOpen() {
+ return $this->is_open;
+ }
+
+ /**
+ * Closes the socket preventing further reads.
+ * Cannot be reopened once closed.
+ * @return boolean True if successful.
+ * @access public
+ */
+ function close() {
+ $this->is_open = false;
+ return fclose($this->handle);
+ }
+
+ /**
+ * Accessor for content so far.
+ * @return string Bytes sent only.
+ * @access public
+ */
+ function getSent() {
+ return $this->sent;
+ }
+
+ /**
+ * Actually opens the low level socket.
+ * @param string $host Host to connect to.
+ * @param integer $port Port on host.
+ * @param integer $error_number Recipient of error code.
+ * @param string $error Recipoent of error message.
+ * @param integer $timeout Maximum time to wait for connection.
+ * @access protected
+ */
+ protected function openSocket($host, $port, &$error_number, &$error, $timeout) {
+ return @fsockopen($host, $port, $error_number, $error, $timeout);
+ }
+}
+
+/**
+ * Wrapper for TCP/IP socket over TLS.
+ * @package SimpleTest
+ * @subpackage WebTester
+ */
+class SimpleSecureSocket extends SimpleSocket {
+
+ /**
+ * Opens a secure socket for reading and writing.
+ * @param string $host Hostname to send request to.
+ * @param integer $port Port on remote machine to open.
+ * @param integer $timeout Connection timeout in seconds.
+ * @access public
+ */
+ function __construct($host, $port, $timeout) {
+ parent::__construct($host, $port, $timeout);
+ }
+
+ /**
+ * Actually opens the low level socket.
+ * @param string $host Host to connect to.
+ * @param integer $port Port on host.
+ * @param integer $error_number Recipient of error code.
+ * @param string $error Recipient of error message.
+ * @param integer $timeout Maximum time to wait for connection.
+ * @access protected
+ */
+ function openSocket($host, $port, &$error_number, &$error, $timeout) {
+ return parent::openSocket("tls://$host", $port, $error_number, $error, $timeout);
+ }
+}
+?>
\ No newline at end of file
diff --git a/code/ryzom/tools/server/www/webtt/vendors/simpletest/tag.php b/code/ryzom/tools/server/www/webtt/vendors/simpletest/tag.php
new file mode 100644
index 000000000..afe649ec5
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/vendors/simpletest/tag.php
@@ -0,0 +1,1527 @@
+ 'SimpleAnchorTag',
+ 'title' => 'SimpleTitleTag',
+ 'base' => 'SimpleBaseTag',
+ 'button' => 'SimpleButtonTag',
+ 'textarea' => 'SimpleTextAreaTag',
+ 'option' => 'SimpleOptionTag',
+ 'label' => 'SimpleLabelTag',
+ 'form' => 'SimpleFormTag',
+ 'frame' => 'SimpleFrameTag');
+ $attributes = $this->keysToLowerCase($attributes);
+ if (array_key_exists($name, $map)) {
+ $tag_class = $map[$name];
+ return new $tag_class($attributes);
+ } elseif ($name == 'select') {
+ return $this->createSelectionTag($attributes);
+ } elseif ($name == 'input') {
+ return $this->createInputTag($attributes);
+ }
+ return new SimpleTag($name, $attributes);
+ }
+
+ /**
+ * Factory for selection fields.
+ * @param hash $attributes Element attributes.
+ * @return SimpleTag Tag object.
+ * @access protected
+ */
+ protected function createSelectionTag($attributes) {
+ if (isset($attributes['multiple'])) {
+ return new MultipleSelectionTag($attributes);
+ }
+ return new SimpleSelectionTag($attributes);
+ }
+
+ /**
+ * Factory for input tags.
+ * @param hash $attributes Element attributes.
+ * @return SimpleTag Tag object.
+ * @access protected
+ */
+ protected function createInputTag($attributes) {
+ if (! isset($attributes['type'])) {
+ return new SimpleTextTag($attributes);
+ }
+ $type = strtolower(trim($attributes['type']));
+ $map = array(
+ 'submit' => 'SimpleSubmitTag',
+ 'image' => 'SimpleImageSubmitTag',
+ 'checkbox' => 'SimpleCheckboxTag',
+ 'radio' => 'SimpleRadioButtonTag',
+ 'text' => 'SimpleTextTag',
+ 'hidden' => 'SimpleTextTag',
+ 'password' => 'SimpleTextTag',
+ 'file' => 'SimpleUploadTag');
+ if (array_key_exists($type, $map)) {
+ $tag_class = $map[$type];
+ return new $tag_class($attributes);
+ }
+ return false;
+ }
+
+ /**
+ * Make the keys lower case for case insensitive look-ups.
+ * @param hash $map Hash to convert.
+ * @return hash Unchanged values, but keys lower case.
+ * @access private
+ */
+ protected function keysToLowerCase($map) {
+ $lower = array();
+ foreach ($map as $key => $value) {
+ $lower[strtolower($key)] = $value;
+ }
+ return $lower;
+ }
+}
+
+/**
+ * HTML or XML tag.
+ * @package SimpleTest
+ * @subpackage WebTester
+ */
+class SimpleTag {
+ private $name;
+ private $attributes;
+ private $content;
+
+ /**
+ * Starts with a named tag with attributes only.
+ * @param string $name Tag name.
+ * @param hash $attributes Attribute names and
+ * string values. Note that
+ * the keys must have been
+ * converted to lower case.
+ */
+ function __construct($name, $attributes) {
+ $this->name = strtolower(trim($name));
+ $this->attributes = $attributes;
+ $this->content = '';
+ }
+
+ /**
+ * Check to see if the tag can have both start and
+ * end tags with content in between.
+ * @return boolean True if content allowed.
+ * @access public
+ */
+ function expectEndTag() {
+ return true;
+ }
+
+ /**
+ * The current tag should not swallow all content for
+ * itself as it's searchable page content. Private
+ * content tags are usually widgets that contain default
+ * values.
+ * @return boolean False as content is available
+ * to other tags by default.
+ * @access public
+ */
+ function isPrivateContent() {
+ return false;
+ }
+
+ /**
+ * Appends string content to the current content.
+ * @param string $content Additional text.
+ * @access public
+ */
+ function addContent($content) {
+ $this->content .= (string)$content;
+ return $this;
+ }
+
+ /**
+ * Adds an enclosed tag to the content.
+ * @param SimpleTag $tag New tag.
+ * @access public
+ */
+ function addTag($tag) {
+ }
+
+ /**
+ * Adds multiple enclosed tags to the content.
+ * @param array List of SimpleTag objects to be added.
+ */
+ function addTags($tags) {
+ foreach ($tags as $tag) {
+ $this->addTag($tag);
+ }
+ }
+
+ /**
+ * Accessor for tag name.
+ * @return string Name of tag.
+ * @access public
+ */
+ function getTagName() {
+ return $this->name;
+ }
+
+ /**
+ * List of legal child elements.
+ * @return array List of element names.
+ * @access public
+ */
+ function getChildElements() {
+ return array();
+ }
+
+ /**
+ * Accessor for an attribute.
+ * @param string $label Attribute name.
+ * @return string Attribute value.
+ * @access public
+ */
+ function getAttribute($label) {
+ $label = strtolower($label);
+ if (! isset($this->attributes[$label])) {
+ return false;
+ }
+ return (string)$this->attributes[$label];
+ }
+
+ /**
+ * Sets an attribute.
+ * @param string $label Attribute name.
+ * @return string $value New attribute value.
+ * @access protected
+ */
+ protected function setAttribute($label, $value) {
+ $this->attributes[strtolower($label)] = $value;
+ }
+
+ /**
+ * Accessor for the whole content so far.
+ * @return string Content as big raw string.
+ * @access public
+ */
+ function getContent() {
+ return $this->content;
+ }
+
+ /**
+ * Accessor for content reduced to visible text. Acts
+ * like a text mode browser, normalising space and
+ * reducing images to their alt text.
+ * @return string Content as plain text.
+ * @access public
+ */
+ function getText() {
+ return SimplePage::normalise($this->content);
+ }
+
+ /**
+ * Test to see if id attribute matches.
+ * @param string $id ID to test against.
+ * @return boolean True on match.
+ * @access public
+ */
+ function isId($id) {
+ return ($this->getAttribute('id') == $id);
+ }
+}
+
+/**
+ * Base url.
+ * @package SimpleTest
+ * @subpackage WebTester
+ */
+class SimpleBaseTag extends SimpleTag {
+
+ /**
+ * Starts with a named tag with attributes only.
+ * @param hash $attributes Attribute names and
+ * string values.
+ */
+ function __construct($attributes) {
+ parent::__construct('base', $attributes);
+ }
+
+ /**
+ * Base tag is not a block tag.
+ * @return boolean false
+ * @access public
+ */
+ function expectEndTag() {
+ return false;
+ }
+}
+
+/**
+ * Page title.
+ * @package SimpleTest
+ * @subpackage WebTester
+ */
+class SimpleTitleTag extends SimpleTag {
+
+ /**
+ * Starts with a named tag with attributes only.
+ * @param hash $attributes Attribute names and
+ * string values.
+ */
+ function __construct($attributes) {
+ parent::__construct('title', $attributes);
+ }
+}
+
+/**
+ * Link.
+ * @package SimpleTest
+ * @subpackage WebTester
+ */
+class SimpleAnchorTag extends SimpleTag {
+
+ /**
+ * Starts with a named tag with attributes only.
+ * @param hash $attributes Attribute names and
+ * string values.
+ */
+ function __construct($attributes) {
+ parent::__construct('a', $attributes);
+ }
+
+ /**
+ * Accessor for URL as string.
+ * @return string Coerced as string.
+ * @access public
+ */
+ function getHref() {
+ $url = $this->getAttribute('href');
+ if (is_bool($url)) {
+ $url = '';
+ }
+ return $url;
+ }
+}
+
+/**
+ * Form element.
+ * @package SimpleTest
+ * @subpackage WebTester
+ */
+class SimpleWidget extends SimpleTag {
+ private $value;
+ private $label;
+ private $is_set;
+
+ /**
+ * Starts with a named tag with attributes only.
+ * @param string $name Tag name.
+ * @param hash $attributes Attribute names and
+ * string values.
+ */
+ function __construct($name, $attributes) {
+ parent::__construct($name, $attributes);
+ $this->value = false;
+ $this->label = false;
+ $this->is_set = false;
+ }
+
+ /**
+ * Accessor for name submitted as the key in
+ * GET/POST privateiables hash.
+ * @return string Parsed value.
+ * @access public
+ */
+ function getName() {
+ return $this->getAttribute('name');
+ }
+
+ /**
+ * Accessor for default value parsed with the tag.
+ * @return string Parsed value.
+ * @access public
+ */
+ function getDefault() {
+ return $this->getAttribute('value');
+ }
+
+ /**
+ * Accessor for currently set value or default if
+ * none.
+ * @return string Value set by form or default
+ * if none.
+ * @access public
+ */
+ function getValue() {
+ if (! $this->is_set) {
+ return $this->getDefault();
+ }
+ return $this->value;
+ }
+
+ /**
+ * Sets the current form element value.
+ * @param string $value New value.
+ * @return boolean True if allowed.
+ * @access public
+ */
+ function setValue($value) {
+ $this->value = $value;
+ $this->is_set = true;
+ return true;
+ }
+
+ /**
+ * Resets the form element value back to the
+ * default.
+ * @access public
+ */
+ function resetValue() {
+ $this->is_set = false;
+ }
+
+ /**
+ * Allows setting of a label externally, say by a
+ * label tag.
+ * @param string $label Label to attach.
+ * @access public
+ */
+ function setLabel($label) {
+ $this->label = trim($label);
+ return $this;
+ }
+
+ /**
+ * Reads external or internal label.
+ * @param string $label Label to test.
+ * @return boolean True is match.
+ * @access public
+ */
+ function isLabel($label) {
+ return $this->label == trim($label);
+ }
+
+ /**
+ * Dispatches the value into the form encoded packet.
+ * @param SimpleEncoding $encoding Form packet.
+ * @access public
+ */
+ function write($encoding) {
+ if ($this->getName()) {
+ $encoding->add($this->getName(), $this->getValue());
+ }
+ }
+}
+
+/**
+ * Text, password and hidden field.
+ * @package SimpleTest
+ * @subpackage WebTester
+ */
+class SimpleTextTag extends SimpleWidget {
+
+ /**
+ * Starts with a named tag with attributes only.
+ * @param hash $attributes Attribute names and
+ * string values.
+ */
+ function __construct($attributes) {
+ parent::__construct('input', $attributes);
+ if ($this->getAttribute('value') === false) {
+ $this->setAttribute('value', '');
+ }
+ }
+
+ /**
+ * Tag contains no content.
+ * @return boolean False.
+ * @access public
+ */
+ function expectEndTag() {
+ return false;
+ }
+
+ /**
+ * Sets the current form element value. Cannot
+ * change the value of a hidden field.
+ * @param string $value New value.
+ * @return boolean True if allowed.
+ * @access public
+ */
+ function setValue($value) {
+ if ($this->getAttribute('type') == 'hidden') {
+ return false;
+ }
+ return parent::setValue($value);
+ }
+}
+
+/**
+ * Submit button as input tag.
+ * @package SimpleTest
+ * @subpackage WebTester
+ */
+class SimpleSubmitTag extends SimpleWidget {
+
+ /**
+ * Starts with a named tag with attributes only.
+ * @param hash $attributes Attribute names and
+ * string values.
+ */
+ function __construct($attributes) {
+ parent::__construct('input', $attributes);
+ if ($this->getAttribute('value') === false) {
+ $this->setAttribute('value', 'Submit');
+ }
+ }
+
+ /**
+ * Tag contains no end element.
+ * @return boolean False.
+ * @access public
+ */
+ function expectEndTag() {
+ return false;
+ }
+
+ /**
+ * Disables the setting of the button value.
+ * @param string $value Ignored.
+ * @return boolean True if allowed.
+ * @access public
+ */
+ function setValue($value) {
+ return false;
+ }
+
+ /**
+ * Value of browser visible text.
+ * @return string Visible label.
+ * @access public
+ */
+ function getLabel() {
+ return $this->getValue();
+ }
+
+ /**
+ * Test for a label match when searching.
+ * @param string $label Label to test.
+ * @return boolean True on match.
+ * @access public
+ */
+ function isLabel($label) {
+ return trim($label) == trim($this->getLabel());
+ }
+}
+
+/**
+ * Image button as input tag.
+ * @package SimpleTest
+ * @subpackage WebTester
+ */
+class SimpleImageSubmitTag extends SimpleWidget {
+
+ /**
+ * Starts with a named tag with attributes only.
+ * @param hash $attributes Attribute names and
+ * string values.
+ */
+ function __construct($attributes) {
+ parent::__construct('input', $attributes);
+ }
+
+ /**
+ * Tag contains no end element.
+ * @return boolean False.
+ * @access public
+ */
+ function expectEndTag() {
+ return false;
+ }
+
+ /**
+ * Disables the setting of the button value.
+ * @param string $value Ignored.
+ * @return boolean True if allowed.
+ * @access public
+ */
+ function setValue($value) {
+ return false;
+ }
+
+ /**
+ * Value of browser visible text.
+ * @return string Visible label.
+ * @access public
+ */
+ function getLabel() {
+ if ($this->getAttribute('title')) {
+ return $this->getAttribute('title');
+ }
+ return $this->getAttribute('alt');
+ }
+
+ /**
+ * Test for a label match when searching.
+ * @param string $label Label to test.
+ * @return boolean True on match.
+ * @access public
+ */
+ function isLabel($label) {
+ return trim($label) == trim($this->getLabel());
+ }
+
+ /**
+ * Dispatches the value into the form encoded packet.
+ * @param SimpleEncoding $encoding Form packet.
+ * @param integer $x X coordinate of click.
+ * @param integer $y Y coordinate of click.
+ * @access public
+ */
+ function write($encoding, $x = 1, $y = 1) {
+ if ($this->getName()) {
+ $encoding->add($this->getName() . '.x', $x);
+ $encoding->add($this->getName() . '.y', $y);
+ } else {
+ $encoding->add('x', $x);
+ $encoding->add('y', $y);
+ }
+ }
+}
+
+/**
+ * Submit button as button tag.
+ * @package SimpleTest
+ * @subpackage WebTester
+ */
+class SimpleButtonTag extends SimpleWidget {
+
+ /**
+ * Starts with a named tag with attributes only.
+ * Defaults are very browser dependent.
+ * @param hash $attributes Attribute names and
+ * string values.
+ */
+ function __construct($attributes) {
+ parent::__construct('button', $attributes);
+ }
+
+ /**
+ * Check to see if the tag can have both start and
+ * end tags with content in between.
+ * @return boolean True if content allowed.
+ * @access public
+ */
+ function expectEndTag() {
+ return true;
+ }
+
+ /**
+ * Disables the setting of the button value.
+ * @param string $value Ignored.
+ * @return boolean True if allowed.
+ * @access public
+ */
+ function setValue($value) {
+ return false;
+ }
+
+ /**
+ * Value of browser visible text.
+ * @return string Visible label.
+ * @access public
+ */
+ function getLabel() {
+ return $this->getContent();
+ }
+
+ /**
+ * Test for a label match when searching.
+ * @param string $label Label to test.
+ * @return boolean True on match.
+ * @access public
+ */
+ function isLabel($label) {
+ return trim($label) == trim($this->getLabel());
+ }
+}
+
+/**
+ * Content tag for text area.
+ * @package SimpleTest
+ * @subpackage WebTester
+ */
+class SimpleTextAreaTag extends SimpleWidget {
+
+ /**
+ * Starts with a named tag with attributes only.
+ * @param hash $attributes Attribute names and
+ * string values.
+ */
+ function __construct($attributes) {
+ parent::__construct('textarea', $attributes);
+ }
+
+ /**
+ * Accessor for starting value.
+ * @return string Parsed value.
+ * @access public
+ */
+ function getDefault() {
+ return $this->wrap(html_entity_decode($this->getContent(), ENT_QUOTES));
+ }
+
+ /**
+ * Applies word wrapping if needed.
+ * @param string $value New value.
+ * @return boolean True if allowed.
+ * @access public
+ */
+ function setValue($value) {
+ return parent::setValue($this->wrap($value));
+ }
+
+ /**
+ * Test to see if text should be wrapped.
+ * @return boolean True if wrapping on.
+ * @access private
+ */
+ function wrapIsEnabled() {
+ if ($this->getAttribute('cols')) {
+ $wrap = $this->getAttribute('wrap');
+ if (($wrap == 'physical') || ($wrap == 'hard')) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Performs the formatting that is peculiar to
+ * this tag. There is strange behaviour in this
+ * one, including stripping a leading new line.
+ * Go figure. I am using Firefox as a guide.
+ * @param string $text Text to wrap.
+ * @return string Text wrapped with carriage
+ * returns and line feeds
+ * @access private
+ */
+ protected function wrap($text) {
+ $text = str_replace("\r\r\n", "\r\n", str_replace("\n", "\r\n", $text));
+ $text = str_replace("\r\n\n", "\r\n", str_replace("\r", "\r\n", $text));
+ if (strncmp($text, "\r\n", strlen("\r\n")) == 0) {
+ $text = substr($text, strlen("\r\n"));
+ }
+ if ($this->wrapIsEnabled()) {
+ return wordwrap(
+ $text,
+ (integer)$this->getAttribute('cols'),
+ "\r\n");
+ }
+ return $text;
+ }
+
+ /**
+ * The content of textarea is not part of the page.
+ * @return boolean True.
+ * @access public
+ */
+ function isPrivateContent() {
+ return true;
+ }
+}
+
+/**
+ * File upload widget.
+ * @package SimpleTest
+ * @subpackage WebTester
+ */
+class SimpleUploadTag extends SimpleWidget {
+
+ /**
+ * Starts with attributes only.
+ * @param hash $attributes Attribute names and
+ * string values.
+ */
+ function __construct($attributes) {
+ parent::__construct('input', $attributes);
+ }
+
+ /**
+ * Tag contains no content.
+ * @return boolean False.
+ * @access public
+ */
+ function expectEndTag() {
+ return false;
+ }
+
+ /**
+ * Dispatches the value into the form encoded packet.
+ * @param SimpleEncoding $encoding Form packet.
+ * @access public
+ */
+ function write($encoding) {
+ if (! file_exists($this->getValue())) {
+ return;
+ }
+ $encoding->attach(
+ $this->getName(),
+ implode('', file($this->getValue())),
+ basename($this->getValue()));
+ }
+}
+
+/**
+ * Drop down widget.
+ * @package SimpleTest
+ * @subpackage WebTester
+ */
+class SimpleSelectionTag extends SimpleWidget {
+ private $options;
+ private $choice;
+
+ /**
+ * Starts with attributes only.
+ * @param hash $attributes Attribute names and
+ * string values.
+ */
+ function __construct($attributes) {
+ parent::__construct('select', $attributes);
+ $this->options = array();
+ $this->choice = false;
+ }
+
+ /**
+ * Adds an option tag to a selection field.
+ * @param SimpleOptionTag $tag New option.
+ * @access public
+ */
+ function addTag($tag) {
+ if ($tag->getTagName() == 'option') {
+ $this->options[] = $tag;
+ }
+ }
+
+ /**
+ * Text within the selection element is ignored.
+ * @param string $content Ignored.
+ * @access public
+ */
+ function addContent($content) {
+ return $this;
+ }
+
+ /**
+ * Scans options for defaults. If none, then
+ * the first option is selected.
+ * @return string Selected field.
+ * @access public
+ */
+ function getDefault() {
+ for ($i = 0, $count = count($this->options); $i < $count; $i++) {
+ if ($this->options[$i]->getAttribute('selected') !== false) {
+ return $this->options[$i]->getDefault();
+ }
+ }
+ if ($count > 0) {
+ return $this->options[0]->getDefault();
+ }
+ return '';
+ }
+
+ /**
+ * Can only set allowed values.
+ * @param string $value New choice.
+ * @return boolean True if allowed.
+ * @access public
+ */
+ function setValue($value) {
+ for ($i = 0, $count = count($this->options); $i < $count; $i++) {
+ if ($this->options[$i]->isValue($value)) {
+ $this->choice = $i;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Accessor for current selection value.
+ * @return string Value attribute or
+ * content of opton.
+ * @access public
+ */
+ function getValue() {
+ if ($this->choice === false) {
+ return $this->getDefault();
+ }
+ return $this->options[$this->choice]->getValue();
+ }
+}
+
+/**
+ * Drop down widget.
+ * @package SimpleTest
+ * @subpackage WebTester
+ */
+class MultipleSelectionTag extends SimpleWidget {
+ private $options;
+ private $values;
+
+ /**
+ * Starts with attributes only.
+ * @param hash $attributes Attribute names and
+ * string values.
+ */
+ function __construct($attributes) {
+ parent::__construct('select', $attributes);
+ $this->options = array();
+ $this->values = false;
+ }
+
+ /**
+ * Adds an option tag to a selection field.
+ * @param SimpleOptionTag $tag New option.
+ * @access public
+ */
+ function addTag($tag) {
+ if ($tag->getTagName() == 'option') {
+ $this->options[] = &$tag;
+ }
+ }
+
+ /**
+ * Text within the selection element is ignored.
+ * @param string $content Ignored.
+ * @access public
+ */
+ function addContent($content) {
+ return $this;
+ }
+
+ /**
+ * Scans options for defaults to populate the
+ * value array().
+ * @return array Selected fields.
+ * @access public
+ */
+ function getDefault() {
+ $default = array();
+ for ($i = 0, $count = count($this->options); $i < $count; $i++) {
+ if ($this->options[$i]->getAttribute('selected') !== false) {
+ $default[] = $this->options[$i]->getDefault();
+ }
+ }
+ return $default;
+ }
+
+ /**
+ * Can only set allowed values. Any illegal value
+ * will result in a failure, but all correct values
+ * will be set.
+ * @param array $desired New choices.
+ * @return boolean True if all allowed.
+ * @access public
+ */
+ function setValue($desired) {
+ $achieved = array();
+ foreach ($desired as $value) {
+ $success = false;
+ for ($i = 0, $count = count($this->options); $i < $count; $i++) {
+ if ($this->options[$i]->isValue($value)) {
+ $achieved[] = $this->options[$i]->getValue();
+ $success = true;
+ break;
+ }
+ }
+ if (! $success) {
+ return false;
+ }
+ }
+ $this->values = $achieved;
+ return true;
+ }
+
+ /**
+ * Accessor for current selection value.
+ * @return array List of currently set options.
+ * @access public
+ */
+ function getValue() {
+ if ($this->values === false) {
+ return $this->getDefault();
+ }
+ return $this->values;
+ }
+}
+
+/**
+ * Option for selection field.
+ * @package SimpleTest
+ * @subpackage WebTester
+ */
+class SimpleOptionTag extends SimpleWidget {
+
+ /**
+ * Stashes the attributes.
+ */
+ function __construct($attributes) {
+ parent::__construct('option', $attributes);
+ }
+
+ /**
+ * Does nothing.
+ * @param string $value Ignored.
+ * @return boolean Not allowed.
+ * @access public
+ */
+ function setValue($value) {
+ return false;
+ }
+
+ /**
+ * Test to see if a value matches the option.
+ * @param string $compare Value to compare with.
+ * @return boolean True if possible match.
+ * @access public
+ */
+ function isValue($compare) {
+ $compare = trim($compare);
+ if (trim($this->getValue()) == $compare) {
+ return true;
+ }
+ return trim(strip_tags($this->getContent())) == $compare;
+ }
+
+ /**
+ * Accessor for starting value. Will be set to
+ * the option label if no value exists.
+ * @return string Parsed value.
+ * @access public
+ */
+ function getDefault() {
+ if ($this->getAttribute('value') === false) {
+ return strip_tags($this->getContent());
+ }
+ return $this->getAttribute('value');
+ }
+
+ /**
+ * The content of options is not part of the page.
+ * @return boolean True.
+ * @access public
+ */
+ function isPrivateContent() {
+ return true;
+ }
+}
+
+/**
+ * Radio button.
+ * @package SimpleTest
+ * @subpackage WebTester
+ */
+class SimpleRadioButtonTag extends SimpleWidget {
+
+ /**
+ * Stashes the attributes.
+ * @param array $attributes Hash of attributes.
+ */
+ function __construct($attributes) {
+ parent::__construct('input', $attributes);
+ if ($this->getAttribute('value') === false) {
+ $this->setAttribute('value', 'on');
+ }
+ }
+
+ /**
+ * Tag contains no content.
+ * @return boolean False.
+ * @access public
+ */
+ function expectEndTag() {
+ return false;
+ }
+
+ /**
+ * The only allowed value sn the one in the
+ * "value" attribute.
+ * @param string $value New value.
+ * @return boolean True if allowed.
+ * @access public
+ */
+ function setValue($value) {
+ if ($value === false) {
+ return parent::setValue($value);
+ }
+ if ($value != $this->getAttribute('value')) {
+ return false;
+ }
+ return parent::setValue($value);
+ }
+
+ /**
+ * Accessor for starting value.
+ * @return string Parsed value.
+ * @access public
+ */
+ function getDefault() {
+ if ($this->getAttribute('checked') !== false) {
+ return $this->getAttribute('value');
+ }
+ return false;
+ }
+}
+
+/**
+ * Checkbox widget.
+ * @package SimpleTest
+ * @subpackage WebTester
+ */
+class SimpleCheckboxTag extends SimpleWidget {
+
+ /**
+ * Starts with attributes only.
+ * @param hash $attributes Attribute names and
+ * string values.
+ */
+ function __construct($attributes) {
+ parent::__construct('input', $attributes);
+ if ($this->getAttribute('value') === false) {
+ $this->setAttribute('value', 'on');
+ }
+ }
+
+ /**
+ * Tag contains no content.
+ * @return boolean False.
+ * @access public
+ */
+ function expectEndTag() {
+ return false;
+ }
+
+ /**
+ * The only allowed value in the one in the
+ * "value" attribute. The default for this
+ * attribute is "on". If this widget is set to
+ * true, then the usual value will be taken.
+ * @param string $value New value.
+ * @return boolean True if allowed.
+ * @access public
+ */
+ function setValue($value) {
+ if ($value === false) {
+ return parent::setValue($value);
+ }
+ if ($value === true) {
+ return parent::setValue($this->getAttribute('value'));
+ }
+ if ($value != $this->getAttribute('value')) {
+ return false;
+ }
+ return parent::setValue($value);
+ }
+
+ /**
+ * Accessor for starting value. The default
+ * value is "on".
+ * @return string Parsed value.
+ * @access public
+ */
+ function getDefault() {
+ if ($this->getAttribute('checked') !== false) {
+ return $this->getAttribute('value');
+ }
+ return false;
+ }
+}
+
+/**
+ * A group of multiple widgets with some shared behaviour.
+ * @package SimpleTest
+ * @subpackage WebTester
+ */
+class SimpleTagGroup {
+ private $widgets = array();
+
+ /**
+ * Adds a tag to the group.
+ * @param SimpleWidget $widget
+ * @access public
+ */
+ function addWidget($widget) {
+ $this->widgets[] = $widget;
+ }
+
+ /**
+ * Accessor to widget set.
+ * @return array All widgets.
+ * @access protected
+ */
+ protected function &getWidgets() {
+ return $this->widgets;
+ }
+
+ /**
+ * Accessor for an attribute.
+ * @param string $label Attribute name.
+ * @return boolean Always false.
+ * @access public
+ */
+ function getAttribute($label) {
+ return false;
+ }
+
+ /**
+ * Fetches the name for the widget from the first
+ * member.
+ * @return string Name of widget.
+ * @access public
+ */
+ function getName() {
+ if (count($this->widgets) > 0) {
+ return $this->widgets[0]->getName();
+ }
+ }
+
+ /**
+ * Scans the widgets for one with the appropriate
+ * ID field.
+ * @param string $id ID value to try.
+ * @return boolean True if matched.
+ * @access public
+ */
+ function isId($id) {
+ for ($i = 0, $count = count($this->widgets); $i < $count; $i++) {
+ if ($this->widgets[$i]->isId($id)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Scans the widgets for one with the appropriate
+ * attached label.
+ * @param string $label Attached label to try.
+ * @return boolean True if matched.
+ * @access public
+ */
+ function isLabel($label) {
+ for ($i = 0, $count = count($this->widgets); $i < $count; $i++) {
+ if ($this->widgets[$i]->isLabel($label)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Dispatches the value into the form encoded packet.
+ * @param SimpleEncoding $encoding Form packet.
+ * @access public
+ */
+ function write($encoding) {
+ $encoding->add($this->getName(), $this->getValue());
+ }
+}
+
+/**
+ * A group of tags with the same name within a form.
+ * @package SimpleTest
+ * @subpackage WebTester
+ */
+class SimpleCheckboxGroup extends SimpleTagGroup {
+
+ /**
+ * Accessor for current selected widget or false
+ * if none.
+ * @return string/array Widget values or false if none.
+ * @access public
+ */
+ function getValue() {
+ $values = array();
+ $widgets = $this->getWidgets();
+ for ($i = 0, $count = count($widgets); $i < $count; $i++) {
+ if ($widgets[$i]->getValue() !== false) {
+ $values[] = $widgets[$i]->getValue();
+ }
+ }
+ return $this->coerceValues($values);
+ }
+
+ /**
+ * Accessor for starting value that is active.
+ * @return string/array Widget values or false if none.
+ * @access public
+ */
+ function getDefault() {
+ $values = array();
+ $widgets = $this->getWidgets();
+ for ($i = 0, $count = count($widgets); $i < $count; $i++) {
+ if ($widgets[$i]->getDefault() !== false) {
+ $values[] = $widgets[$i]->getDefault();
+ }
+ }
+ return $this->coerceValues($values);
+ }
+
+ /**
+ * Accessor for current set values.
+ * @param string/array/boolean $values Either a single string, a
+ * hash or false for nothing set.
+ * @return boolean True if all values can be set.
+ * @access public
+ */
+ function setValue($values) {
+ $values = $this->makeArray($values);
+ if (! $this->valuesArePossible($values)) {
+ return false;
+ }
+ $widgets = $this->getWidgets();
+ for ($i = 0, $count = count($widgets); $i < $count; $i++) {
+ $possible = $widgets[$i]->getAttribute('value');
+ if (in_array($widgets[$i]->getAttribute('value'), $values)) {
+ $widgets[$i]->setValue($possible);
+ } else {
+ $widgets[$i]->setValue(false);
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Tests to see if a possible value set is legal.
+ * @param string/array/boolean $values Either a single string, a
+ * hash or false for nothing set.
+ * @return boolean False if trying to set a
+ * missing value.
+ * @access private
+ */
+ protected function valuesArePossible($values) {
+ $matches = array();
+ $widgets = &$this->getWidgets();
+ for ($i = 0, $count = count($widgets); $i < $count; $i++) {
+ $possible = $widgets[$i]->getAttribute('value');
+ if (in_array($possible, $values)) {
+ $matches[] = $possible;
+ }
+ }
+ return ($values == $matches);
+ }
+
+ /**
+ * Converts the output to an appropriate format. This means
+ * that no values is false, a single value is just that
+ * value and only two or more are contained in an array.
+ * @param array $values List of values of widgets.
+ * @return string/array/boolean Expected format for a tag.
+ * @access private
+ */
+ protected function coerceValues($values) {
+ if (count($values) == 0) {
+ return false;
+ } elseif (count($values) == 1) {
+ return $values[0];
+ } else {
+ return $values;
+ }
+ }
+
+ /**
+ * Converts false or string into array. The opposite of
+ * the coercian method.
+ * @param string/array/boolean $value A single item is converted
+ * to a one item list. False
+ * gives an empty list.
+ * @return array List of values, possibly empty.
+ * @access private
+ */
+ protected function makeArray($value) {
+ if ($value === false) {
+ return array();
+ }
+ if (is_string($value)) {
+ return array($value);
+ }
+ return $value;
+ }
+}
+
+/**
+ * A group of tags with the same name within a form.
+ * Used for radio buttons.
+ * @package SimpleTest
+ * @subpackage WebTester
+ */
+class SimpleRadioGroup extends SimpleTagGroup {
+
+ /**
+ * Each tag is tried in turn until one is
+ * successfully set. The others will be
+ * unchecked if successful.
+ * @param string $value New value.
+ * @return boolean True if any allowed.
+ * @access public
+ */
+ function setValue($value) {
+ if (! $this->valueIsPossible($value)) {
+ return false;
+ }
+ $index = false;
+ $widgets = $this->getWidgets();
+ for ($i = 0, $count = count($widgets); $i < $count; $i++) {
+ if (! $widgets[$i]->setValue($value)) {
+ $widgets[$i]->setValue(false);
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Tests to see if a value is allowed.
+ * @param string Attempted value.
+ * @return boolean True if a valid value.
+ * @access private
+ */
+ protected function valueIsPossible($value) {
+ $widgets = $this->getWidgets();
+ for ($i = 0, $count = count($widgets); $i < $count; $i++) {
+ if ($widgets[$i]->getAttribute('value') == $value) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Accessor for current selected widget or false
+ * if none.
+ * @return string/boolean Value attribute or
+ * content of opton.
+ * @access public
+ */
+ function getValue() {
+ $widgets = $this->getWidgets();
+ for ($i = 0, $count = count($widgets); $i < $count; $i++) {
+ if ($widgets[$i]->getValue() !== false) {
+ return $widgets[$i]->getValue();
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Accessor for starting value that is active.
+ * @return string/boolean Value of first checked
+ * widget or false if none.
+ * @access public
+ */
+ function getDefault() {
+ $widgets = $this->getWidgets();
+ for ($i = 0, $count = count($widgets); $i < $count; $i++) {
+ if ($widgets[$i]->getDefault() !== false) {
+ return $widgets[$i]->getDefault();
+ }
+ }
+ return false;
+ }
+}
+
+/**
+ * Tag to keep track of labels.
+ * @package SimpleTest
+ * @subpackage WebTester
+ */
+class SimpleLabelTag extends SimpleTag {
+
+ /**
+ * Starts with a named tag with attributes only.
+ * @param hash $attributes Attribute names and
+ * string values.
+ */
+ function __construct($attributes) {
+ parent::__construct('label', $attributes);
+ }
+
+ /**
+ * Access for the ID to attach the label to.
+ * @return string For attribute.
+ * @access public
+ */
+ function getFor() {
+ return $this->getAttribute('for');
+ }
+}
+
+/**
+ * Tag to aid parsing the form.
+ * @package SimpleTest
+ * @subpackage WebTester
+ */
+class SimpleFormTag extends SimpleTag {
+
+ /**
+ * Starts with a named tag with attributes only.
+ * @param hash $attributes Attribute names and
+ * string values.
+ */
+ function __construct($attributes) {
+ parent::__construct('form', $attributes);
+ }
+}
+
+/**
+ * Tag to aid parsing the frames in a page.
+ * @package SimpleTest
+ * @subpackage WebTester
+ */
+class SimpleFrameTag extends SimpleTag {
+
+ /**
+ * Starts with a named tag with attributes only.
+ * @param hash $attributes Attribute names and
+ * string values.
+ */
+ function __construct($attributes) {
+ parent::__construct('frame', $attributes);
+ }
+
+ /**
+ * Tag contains no content.
+ * @return boolean False.
+ * @access public
+ */
+ function expectEndTag() {
+ return false;
+ }
+}
+?>
\ No newline at end of file
diff --git a/code/ryzom/tools/server/www/webtt/vendors/simpletest/test_case.php b/code/ryzom/tools/server/www/webtt/vendors/simpletest/test_case.php
new file mode 100644
index 000000000..ba023c3b2
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/vendors/simpletest/test_case.php
@@ -0,0 +1,658 @@
+label = $label;
+ }
+ }
+
+ /**
+ * Accessor for the test name for subclasses.
+ * @return string Name of the test.
+ * @access public
+ */
+ function getLabel() {
+ return $this->label ? $this->label : get_class($this);
+ }
+
+ /**
+ * This is a placeholder for skipping tests. In this
+ * method you place skipIf() and skipUnless() calls to
+ * set the skipping state.
+ * @access public
+ */
+ function skip() {
+ }
+
+ /**
+ * Will issue a message to the reporter and tell the test
+ * case to skip if the incoming flag is true.
+ * @param string $should_skip Condition causing the tests to be skipped.
+ * @param string $message Text of skip condition.
+ * @access public
+ */
+ function skipIf($should_skip, $message = '%s') {
+ if ($should_skip && ! $this->should_skip) {
+ $this->should_skip = true;
+ $message = sprintf($message, 'Skipping [' . get_class($this) . ']');
+ $this->reporter->paintSkip($message . $this->getAssertionLine());
+ }
+ }
+
+ /**
+ * Accessor for the private variable $_shoud_skip
+ * @access public
+ */
+ function shouldSkip() {
+ return $this->should_skip;
+ }
+
+ /**
+ * Will issue a message to the reporter and tell the test
+ * case to skip if the incoming flag is false.
+ * @param string $shouldnt_skip Condition causing the tests to be run.
+ * @param string $message Text of skip condition.
+ * @access public
+ */
+ function skipUnless($shouldnt_skip, $message = false) {
+ $this->skipIf(! $shouldnt_skip, $message);
+ }
+
+ /**
+ * Used to invoke the single tests.
+ * @return SimpleInvoker Individual test runner.
+ * @access public
+ */
+ function createInvoker() {
+ return new SimpleErrorTrappingInvoker(
+ new SimpleExceptionTrappingInvoker(new SimpleInvoker($this)));
+ }
+
+ /**
+ * Uses reflection to run every method within itself
+ * starting with the string "test" unless a method
+ * is specified.
+ * @param SimpleReporter $reporter Current test reporter.
+ * @return boolean True if all tests passed.
+ * @access public
+ */
+ function run($reporter) {
+ $context = SimpleTest::getContext();
+ $context->setTest($this);
+ $context->setReporter($reporter);
+ $this->reporter = $reporter;
+ $started = false;
+ foreach ($this->getTests() as $method) {
+ if ($reporter->shouldInvoke($this->getLabel(), $method)) {
+ $this->skip();
+ if ($this->should_skip) {
+ break;
+ }
+ if (! $started) {
+ $reporter->paintCaseStart($this->getLabel());
+ $started = true;
+ }
+ $invoker = $this->reporter->createInvoker($this->createInvoker());
+ $invoker->before($method);
+ $invoker->invoke($method);
+ $invoker->after($method);
+ }
+ }
+ if ($started) {
+ $reporter->paintCaseEnd($this->getLabel());
+ }
+ unset($this->reporter);
+ $context->setTest(null);
+ return $reporter->getStatus();
+ }
+
+ /**
+ * Gets a list of test names. Normally that will
+ * be all internal methods that start with the
+ * name "test". This method should be overridden
+ * if you want a different rule.
+ * @return array List of test names.
+ * @access public
+ */
+ function getTests() {
+ $methods = array();
+ foreach (get_class_methods(get_class($this)) as $method) {
+ if ($this->isTest($method)) {
+ $methods[] = $method;
+ }
+ }
+ return $methods;
+ }
+
+ /**
+ * Tests to see if the method is a test that should
+ * be run. Currently any method that starts with 'test'
+ * is a candidate unless it is the constructor.
+ * @param string $method Method name to try.
+ * @return boolean True if test method.
+ * @access protected
+ */
+ protected function isTest($method) {
+ if (strtolower(substr($method, 0, 4)) == 'test') {
+ return ! SimpleTestCompatibility::isA($this, strtolower($method));
+ }
+ return false;
+ }
+
+ /**
+ * Announces the start of the test.
+ * @param string $method Test method just started.
+ * @access public
+ */
+ function before($method) {
+ $this->reporter->paintMethodStart($method);
+ $this->observers = array();
+ }
+
+ /**
+ * Sets up unit test wide variables at the start
+ * of each test method. To be overridden in
+ * actual user test cases.
+ * @access public
+ */
+ function setUp() {
+ }
+
+ /**
+ * Clears the data set in the setUp() method call.
+ * To be overridden by the user in actual user test cases.
+ * @access public
+ */
+ function tearDown() {
+ }
+
+ /**
+ * Announces the end of the test. Includes private clean up.
+ * @param string $method Test method just finished.
+ * @access public
+ */
+ function after($method) {
+ for ($i = 0; $i < count($this->observers); $i++) {
+ $this->observers[$i]->atTestEnd($method, $this);
+ }
+ $this->reporter->paintMethodEnd($method);
+ }
+
+ /**
+ * Sets up an observer for the test end.
+ * @param object $observer Must have atTestEnd()
+ * method.
+ * @access public
+ */
+ function tell($observer) {
+ $this->observers[] = &$observer;
+ }
+
+ /**
+ * @deprecated
+ */
+ function pass($message = "Pass") {
+ if (! isset($this->reporter)) {
+ trigger_error('Can only make assertions within test methods');
+ }
+ $this->reporter->paintPass(
+ $message . $this->getAssertionLine());
+ return true;
+ }
+
+ /**
+ * Sends a fail event with a message.
+ * @param string $message Message to send.
+ * @access public
+ */
+ function fail($message = "Fail") {
+ if (! isset($this->reporter)) {
+ trigger_error('Can only make assertions within test methods');
+ }
+ $this->reporter->paintFail(
+ $message . $this->getAssertionLine());
+ return false;
+ }
+
+ /**
+ * Formats a PHP error and dispatches it to the
+ * reporter.
+ * @param integer $severity PHP error code.
+ * @param string $message Text of error.
+ * @param string $file File error occoured in.
+ * @param integer $line Line number of error.
+ * @access public
+ */
+ function error($severity, $message, $file, $line) {
+ if (! isset($this->reporter)) {
+ trigger_error('Can only make assertions within test methods');
+ }
+ $this->reporter->paintError(
+ "Unexpected PHP error [$message] severity [$severity] in [$file line $line]");
+ }
+
+ /**
+ * Formats an exception and dispatches it to the
+ * reporter.
+ * @param Exception $exception Object thrown.
+ * @access public
+ */
+ function exception($exception) {
+ $this->reporter->paintException($exception);
+ }
+
+ /**
+ * For user defined expansion of the available messages.
+ * @param string $type Tag for sorting the signals.
+ * @param mixed $payload Extra user specific information.
+ */
+ function signal($type, $payload) {
+ if (! isset($this->reporter)) {
+ trigger_error('Can only make assertions within test methods');
+ }
+ $this->reporter->paintSignal($type, $payload);
+ }
+
+ /**
+ * Runs an expectation directly, for extending the
+ * tests with new expectation classes.
+ * @param SimpleExpectation $expectation Expectation subclass.
+ * @param mixed $compare Value to compare.
+ * @param string $message Message to display.
+ * @return boolean True on pass
+ * @access public
+ */
+ function assert($expectation, $compare, $message = '%s') {
+ if ($expectation->test($compare)) {
+ return $this->pass(sprintf(
+ $message,
+ $expectation->overlayMessage($compare, $this->reporter->getDumper())));
+ } else {
+ return $this->fail(sprintf(
+ $message,
+ $expectation->overlayMessage($compare, $this->reporter->getDumper())));
+ }
+ }
+
+ /**
+ * Uses a stack trace to find the line of an assertion.
+ * @return string Line number of first assert*
+ * method embedded in format string.
+ * @access public
+ */
+ function getAssertionLine() {
+ $trace = new SimpleStackTrace(array('assert', 'expect', 'pass', 'fail', 'skip'));
+ return $trace->traceMethod();
+ }
+
+ /**
+ * Sends a formatted dump of a variable to the
+ * test suite for those emergency debugging
+ * situations.
+ * @param mixed $variable Variable to display.
+ * @param string $message Message to display.
+ * @return mixed The original variable.
+ * @access public
+ */
+ function dump($variable, $message = false) {
+ $dumper = $this->reporter->getDumper();
+ $formatted = $dumper->dump($variable);
+ if ($message) {
+ $formatted = $message . "\n" . $formatted;
+ }
+ $this->reporter->paintFormattedMessage($formatted);
+ return $variable;
+ }
+
+ /**
+ * Accessor for the number of subtests including myelf.
+ * @return integer Number of test cases.
+ * @access public
+ */
+ function getSize() {
+ return 1;
+ }
+}
+
+/**
+ * Helps to extract test cases automatically from a file.
+ * @package SimpleTest
+ * @subpackage UnitTester
+ */
+class SimpleFileLoader {
+
+ /**
+ * Builds a test suite from a library of test cases.
+ * The new suite is composed into this one.
+ * @param string $test_file File name of library with
+ * test case classes.
+ * @return TestSuite The new test suite.
+ * @access public
+ */
+ function load($test_file) {
+ $existing_classes = get_declared_classes();
+ $existing_globals = get_defined_vars();
+ include_once($test_file);
+ $new_globals = get_defined_vars();
+ $this->makeFileVariablesGlobal($existing_globals, $new_globals);
+ $new_classes = array_diff(get_declared_classes(), $existing_classes);
+ if (empty($new_classes)) {
+ $new_classes = $this->scrapeClassesFromFile($test_file);
+ }
+ $classes = $this->selectRunnableTests($new_classes);
+ return $this->createSuiteFromClasses($test_file, $classes);
+ }
+
+ /**
+ * Imports new variables into the global namespace.
+ * @param hash $existing Variables before the file was loaded.
+ * @param hash $new Variables after the file was loaded.
+ * @access private
+ */
+ protected function makeFileVariablesGlobal($existing, $new) {
+ $globals = array_diff(array_keys($new), array_keys($existing));
+ foreach ($globals as $global) {
+ $GLOBALS[$global] = $new[$global];
+ }
+ }
+
+ /**
+ * Lookup classnames from file contents, in case the
+ * file may have been included before.
+ * Note: This is probably too clever by half. Figuring this
+ * out after a failed test case is going to be tricky for us,
+ * never mind the user. A test case should not be included
+ * twice anyway.
+ * @param string $test_file File name with classes.
+ * @access private
+ */
+ protected function scrapeClassesFromFile($test_file) {
+ preg_match_all('~^\s*class\s+(\w+)(\s+(extends|implements)\s+\w+)*\s*\{~mi',
+ file_get_contents($test_file),
+ $matches );
+ return $matches[1];
+ }
+
+ /**
+ * Calculates the incoming test cases. Skips abstract
+ * and ignored classes.
+ * @param array $candidates Candidate classes.
+ * @return array New classes which are test
+ * cases that shouldn't be ignored.
+ * @access public
+ */
+ function selectRunnableTests($candidates) {
+ $classes = array();
+ foreach ($candidates as $class) {
+ if (TestSuite::getBaseTestCase($class)) {
+ $reflection = new SimpleReflection($class);
+ if ($reflection->isAbstract()) {
+ SimpleTest::ignore($class);
+ } else {
+ $classes[] = $class;
+ }
+ }
+ }
+ return $classes;
+ }
+
+ /**
+ * Builds a test suite from a class list.
+ * @param string $title Title of new group.
+ * @param array $classes Test classes.
+ * @return TestSuite Group loaded with the new
+ * test cases.
+ * @access public
+ */
+ function createSuiteFromClasses($title, $classes) {
+ if (count($classes) == 0) {
+ $suite = new BadTestSuite($title, "No runnable test cases in [$title]");
+ return $suite;
+ }
+ SimpleTest::ignoreParentsIfIgnored($classes);
+ $suite = new TestSuite($title);
+ foreach ($classes as $class) {
+ if (! SimpleTest::isIgnored($class)) {
+ $suite->add($class);
+ }
+ }
+ return $suite;
+ }
+}
+
+/**
+ * This is a composite test class for combining
+ * test cases and other RunnableTest classes into
+ * a group test.
+ * @package SimpleTest
+ * @subpackage UnitTester
+ */
+class TestSuite {
+ private $label;
+ private $test_cases;
+
+ /**
+ * Sets the name of the test suite.
+ * @param string $label Name sent at the start and end
+ * of the test.
+ * @access public
+ */
+ function TestSuite($label = false) {
+ $this->label = $label;
+ $this->test_cases = array();
+ }
+
+ /**
+ * Accessor for the test name for subclasses. If the suite
+ * wraps a single test case the label defaults to the name of that test.
+ * @return string Name of the test.
+ * @access public
+ */
+ function getLabel() {
+ if (! $this->label) {
+ return ($this->getSize() == 1) ?
+ get_class($this->test_cases[0]) : get_class($this);
+ } else {
+ return $this->label;
+ }
+ }
+
+ /**
+ * Adds a test into the suite by instance or class. The class will
+ * be instantiated if it's a test suite.
+ * @param SimpleTestCase $test_case Suite or individual test
+ * case implementing the
+ * runnable test interface.
+ * @access public
+ */
+ function add($test_case) {
+ if (! is_string($test_case)) {
+ $this->test_cases[] = $test_case;
+ } elseif (TestSuite::getBaseTestCase($test_case) == 'testsuite') {
+ $this->test_cases[] = new $test_case();
+ } else {
+ $this->test_cases[] = $test_case;
+ }
+ }
+
+ /**
+ * Builds a test suite from a library of test cases.
+ * The new suite is composed into this one.
+ * @param string $test_file File name of library with
+ * test case classes.
+ * @access public
+ */
+ function addFile($test_file) {
+ $extractor = new SimpleFileLoader();
+ $this->add($extractor->load($test_file));
+ }
+
+ /**
+ * Delegates to a visiting collector to add test
+ * files.
+ * @param string $path Path to scan from.
+ * @param SimpleCollector $collector Directory scanner.
+ * @access public
+ */
+ function collect($path, $collector) {
+ $collector->collect($this, $path);
+ }
+
+ /**
+ * Invokes run() on all of the held test cases, instantiating
+ * them if necessary.
+ * @param SimpleReporter $reporter Current test reporter.
+ * @access public
+ */
+ function run($reporter) {
+ $reporter->paintGroupStart($this->getLabel(), $this->getSize());
+ for ($i = 0, $count = count($this->test_cases); $i < $count; $i++) {
+ if (is_string($this->test_cases[$i])) {
+ $class = $this->test_cases[$i];
+ $test = new $class();
+ $test->run($reporter);
+ unset($test);
+ } else {
+ $this->test_cases[$i]->run($reporter);
+ }
+ }
+ $reporter->paintGroupEnd($this->getLabel());
+ return $reporter->getStatus();
+ }
+
+ /**
+ * Number of contained test cases.
+ * @return integer Total count of cases in the group.
+ * @access public
+ */
+ function getSize() {
+ $count = 0;
+ foreach ($this->test_cases as $case) {
+ if (is_string($case)) {
+ if (! SimpleTest::isIgnored($case)) {
+ $count++;
+ }
+ } else {
+ $count += $case->getSize();
+ }
+ }
+ return $count;
+ }
+
+ /**
+ * Test to see if a class is derived from the
+ * SimpleTestCase class.
+ * @param string $class Class name.
+ * @access public
+ */
+ static function getBaseTestCase($class) {
+ while ($class = get_parent_class($class)) {
+ $class = strtolower($class);
+ if ($class == 'simpletestcase' || $class == 'testsuite') {
+ return $class;
+ }
+ }
+ return false;
+ }
+}
+
+/**
+ * This is a failing group test for when a test suite hasn't
+ * loaded properly.
+ * @package SimpleTest
+ * @subpackage UnitTester
+ */
+class BadTestSuite {
+ private $label;
+ private $error;
+
+ /**
+ * Sets the name of the test suite and error message.
+ * @param string $label Name sent at the start and end
+ * of the test.
+ * @access public
+ */
+ function BadTestSuite($label, $error) {
+ $this->label = $label;
+ $this->error = $error;
+ }
+
+ /**
+ * Accessor for the test name for subclasses.
+ * @return string Name of the test.
+ * @access public
+ */
+ function getLabel() {
+ return $this->label;
+ }
+
+ /**
+ * Sends a single error to the reporter.
+ * @param SimpleReporter $reporter Current test reporter.
+ * @access public
+ */
+ function run($reporter) {
+ $reporter->paintGroupStart($this->getLabel(), $this->getSize());
+ $reporter->paintFail('Bad TestSuite [' . $this->getLabel() .
+ '] with error [' . $this->error . ']');
+ $reporter->paintGroupEnd($this->getLabel());
+ return $reporter->getStatus();
+ }
+
+ /**
+ * Number of contained test cases. Always zero.
+ * @return integer Total count of cases in the group.
+ * @access public
+ */
+ function getSize() {
+ return 0;
+ }
+}
+?>
diff --git a/code/ryzom/tools/server/www/webtt/vendors/simpletest/tidy_parser.php b/code/ryzom/tools/server/www/webtt/vendors/simpletest/tidy_parser.php
new file mode 100644
index 000000000..3d8b4b2ac
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/vendors/simpletest/tidy_parser.php
@@ -0,0 +1,382 @@
+free();
+ }
+
+ /**
+ * Frees up any references so as to allow the PHP garbage
+ * collection from unset() to work.
+ */
+ private function free() {
+ unset($this->page);
+ $this->forms = array();
+ $this->labels = array();
+ }
+
+ /**
+ * This builder is only available if the 'tidy' extension is loaded.
+ * @return boolean True if available.
+ */
+ function can() {
+ return extension_loaded('tidy');
+ }
+
+ /**
+ * Reads the raw content the page using HTML Tidy.
+ * @param $response SimpleHttpResponse Fetched response.
+ * @return SimplePage Newly parsed page.
+ */
+ function parse($response) {
+ $this->page = new SimplePage($response);
+ $tidied = tidy_parse_string($input = $this->insertGuards($response->getContent()),
+ array('output-xml' => false, 'wrap' => '0', 'indent' => 'no'),
+ 'latin1');
+ $this->walkTree($tidied->html());
+ $this->attachLabels($this->widgets_by_id, $this->labels);
+ $this->page->setForms($this->forms);
+ $page = $this->page;
+ $this->free();
+ return $page;
+ }
+
+ /**
+ * Stops HTMLTidy stripping content that we wish to preserve.
+ * @param string The raw html.
+ * @return string The html with guard tags inserted.
+ */
+ private function insertGuards($html) {
+ return $this->insertEmptyTagGuards($this->insertTextareaSimpleWhitespaceGuards($html));
+ }
+
+ /**
+ * Removes the extra content added during the parse stage
+ * in order to preserve content we don't want stripped
+ * out by HTMLTidy.
+ * @param string The raw html.
+ * @return string The html with guard tags removed.
+ */
+ private function stripGuards($html) {
+ return $this->stripTextareaWhitespaceGuards($this->stripEmptyTagGuards($html));
+ }
+
+ /**
+ * HTML tidy strips out empty tags such as which we
+ * need to preserve. This method inserts an additional marker.
+ * @param string The raw html.
+ * @return string The html with guards inserted.
+ */
+ private function insertEmptyTagGuards($html) {
+ return preg_replace('#<(option|textarea)([^>]*)>(\s*)(option|textarea)>#is',
+ '<\1\2>___EMPTY___\3\4>',
+ $html);
+ }
+
+ /**
+ * HTML tidy strips out empty tags such as which we
+ * need to preserve. This method strips additional markers
+ * inserted by SimpleTest to the tidy output used to make the
+ * tags non-empty. This ensures their preservation.
+ * @param string The raw html.
+ * @return string The html with guards removed.
+ */
+ private function stripEmptyTagGuards($html) {
+ return preg_replace('#(^|>)(\s*)___EMPTY___(\s*)(|$)#i', '\2\3', $html);
+ }
+
+ /**
+ * By parsing the XML output of tidy, we lose some whitespace
+ * information in textarea tags. We temporarily recode this
+ * data ourselves so as not to lose it.
+ * @param string The raw html.
+ * @return string The html with guards inserted.
+ */
+ private function insertTextareaSimpleWhitespaceGuards($html) {
+ return preg_replace_callback('##is',
+ array($this, 'insertWhitespaceGuards'),
+ $html);
+ }
+
+ /**
+ * Callback for insertTextareaSimpleWhitespaceGuards().
+ * @param array $matches Result of preg_replace_callback().
+ * @return string Guard tags now replace whitespace.
+ */
+ private function insertWhitespaceGuards($matches) {
+ return '';
+ }
+
+ /**
+ * Removes the whitespace preserving guards we added
+ * before parsing.
+ * @param string The raw html.
+ * @return string The html with guards removed.
+ */
+ private function stripTextareaWhitespaceGuards($html) {
+ return str_replace(array('___NEWLINE___', '___CR___', '___TAB___', '___SPACE___'),
+ array("\n", "\r", "\t", ' '),
+ $html);
+ }
+
+ /**
+ * Visits the given node and all children
+ * @param object $node Tidy XML node.
+ */
+ private function walkTree($node) {
+ if ($node->name == 'a') {
+ $this->page->addLink($this->tags()->createTag($node->name, (array)$node->attribute)
+ ->addContent($this->innerHtml($node)));
+ } elseif ($node->name == 'base' and isset($node->attribute['href'])) {
+ $this->page->setBase($node->attribute['href']);
+ } elseif ($node->name == 'title') {
+ $this->page->setTitle($this->tags()->createTag($node->name, (array)$node->attribute)
+ ->addContent($this->innerHtml($node)));
+ } elseif ($node->name == 'frameset') {
+ $this->page->setFrames($this->collectFrames($node));
+ } elseif ($node->name == 'form') {
+ $this->forms[] = $this->walkForm($node, $this->createEmptyForm($node));
+ } elseif ($node->name == 'label') {
+ $this->labels[] = $this->tags()->createTag($node->name, (array)$node->attribute)
+ ->addContent($this->innerHtml($node));
+ } else {
+ $this->walkChildren($node);
+ }
+ }
+
+ /**
+ * Helper method for traversing the XML tree.
+ * @param object $node Tidy XML node.
+ */
+ private function walkChildren($node) {
+ if ($node->hasChildren()) {
+ foreach ($node->child as $child) {
+ $this->walkTree($child);
+ }
+ }
+ }
+
+ /**
+ * Facade for forms containing preparsed widgets.
+ * @param object $node Tidy XML node.
+ * @return SimpleForm Facade for SimpleBrowser.
+ */
+ private function createEmptyForm($node) {
+ return new SimpleForm($this->tags()->createTag($node->name, (array)$node->attribute), $this->page);
+ }
+
+ /**
+ * Visits the given node and all children
+ * @param object $node Tidy XML node.
+ */
+ private function walkForm($node, $form, $enclosing_label = '') {
+ if ($node->name == 'a') {
+ $this->page->addLink($this->tags()->createTag($node->name, (array)$node->attribute)
+ ->addContent($this->innerHtml($node)));
+ } elseif (in_array($node->name, array('input', 'button', 'textarea', 'select'))) {
+ $this->addWidgetToForm($node, $form, $enclosing_label);
+ } elseif ($node->name == 'label') {
+ $this->labels[] = $this->tags()->createTag($node->name, (array)$node->attribute)
+ ->addContent($this->innerHtml($node));
+ if ($node->hasChildren()) {
+ foreach ($node->child as $child) {
+ $this->walkForm($child, $form, SimplePage::normalise($this->innerHtml($node)));
+ }
+ }
+ } elseif ($node->hasChildren()) {
+ foreach ($node->child as $child) {
+ $this->walkForm($child, $form);
+ }
+ }
+ return $form;
+ }
+
+ /**
+ * Tests a node for a "for" atribute. Used for
+ * attaching labels.
+ * @param object $node Tidy XML node.
+ * @return boolean True if the "for" attribute exists.
+ */
+ private function hasFor($node) {
+ return isset($node->attribute) and $node->attribute['for'];
+ }
+
+ /**
+ * Adds the widget into the form container.
+ * @param object $node Tidy XML node of widget.
+ * @param SimpleForm $form Form to add it to.
+ * @param string $enclosing_label The label of any label
+ * tag we might be in.
+ */
+ private function addWidgetToForm($node, $form, $enclosing_label) {
+ $widget = $this->tags()->createTag($node->name, $this->attributes($node));
+ if (! $widget) {
+ return;
+ }
+ $widget->setLabel($enclosing_label)
+ ->addContent($this->innerHtml($node));
+ if ($node->name == 'select') {
+ $widget->addTags($this->collectSelectOptions($node));
+ }
+ $form->addWidget($widget);
+ $this->indexWidgetById($widget);
+ }
+
+ /**
+ * Fills the widget cache to speed up searching.
+ * @param SimpleTag $widget Parsed widget to cache.
+ */
+ private function indexWidgetById($widget) {
+ $id = $widget->getAttribute('id');
+ if (! $id) {
+ return;
+ }
+ if (! isset($this->widgets_by_id[$id])) {
+ $this->widgets_by_id[$id] = array();
+ }
+ $this->widgets_by_id[$id][] = $widget;
+ }
+
+ /**
+ * Parses the options from inside an XML select node.
+ * @param object $node Tidy XML node.
+ * @return array List of SimpleTag options.
+ */
+ private function collectSelectOptions($node) {
+ $options = array();
+ if ($node->name == 'option') {
+ $options[] = $this->tags()->createTag($node->name, $this->attributes($node))
+ ->addContent($this->innerHtml($node));
+ }
+ if ($node->hasChildren()) {
+ foreach ($node->child as $child) {
+ $options = array_merge($options, $this->collectSelectOptions($child));
+ }
+ }
+ return $options;
+ }
+
+ /**
+ * Convenience method for collecting all the attributes
+ * of a tag. Not sure why Tidy does not have this.
+ * @param object $node Tidy XML node.
+ * @return array Hash of attribute strings.
+ */
+ private function attributes($node) {
+ if (! preg_match('|<[^ ]+\s(.*?)/?>|s', $node->value, $first_tag_contents)) {
+ return array();
+ }
+ $attributes = array();
+ preg_match_all('/\S+\s*=\s*\'[^\']*\'|(\S+\s*=\s*"[^"]*")|([^ =]+\s*=\s*[^ "\']+?)|[^ "\']+/', $first_tag_contents[1], $matches);
+ foreach($matches[0] as $unparsed) {
+ $attributes = $this->mergeAttribute($attributes, $unparsed);
+ }
+ return $attributes;
+ }
+
+ /**
+ * Overlay an attribute into the attributes hash.
+ * @param array $attributes Current attribute list.
+ * @param string $raw Raw attribute string with
+ * both key and value.
+ * @return array New attribute hash.
+ */
+ private function mergeAttribute($attributes, $raw) {
+ $parts = explode('=', $raw);
+ list($name, $value) = count($parts) == 1 ? array($parts[0], $parts[0]) : $parts;
+ $attributes[trim($name)] = html_entity_decode($this->dequote(trim($value)), ENT_QUOTES);
+ return $attributes;
+ }
+
+ /**
+ * Remove start and end quotes.
+ * @param string $quoted A quoted string.
+ * @return string Quotes are gone.
+ */
+ private function dequote($quoted) {
+ if (preg_match('/^(\'([^\']*)\'|"([^"]*)")$/', $quoted, $matches)) {
+ return isset($matches[3]) ? $matches[3] : $matches[2];
+ }
+ return $quoted;
+ }
+
+ /**
+ * Collects frame information inside a frameset tag.
+ * @param object $node Tidy XML node.
+ * @return array List of SimpleTag frame descriptions.
+ */
+ private function collectFrames($node) {
+ $frames = array();
+ if ($node->name == 'frame') {
+ $frames = array($this->tags()->createTag($node->name, (array)$node->attribute));
+ } else if ($node->hasChildren()) {
+ $frames = array();
+ foreach ($node->child as $child) {
+ $frames = array_merge($frames, $this->collectFrames($child));
+ }
+ }
+ return $frames;
+ }
+
+ /**
+ * Extracts the XML node text.
+ * @param object $node Tidy XML node.
+ * @return string The text only.
+ */
+ private function innerHtml($node) {
+ $raw = '';
+ if ($node->hasChildren()) {
+ foreach ($node->child as $child) {
+ $raw .= $child->value;
+ }
+ }
+ return $this->stripGuards($raw);
+ }
+
+ /**
+ * Factory for parsed content holders.
+ * @return SimpleTagBuilder Factory.
+ */
+ private function tags() {
+ return new SimpleTagBuilder();
+ }
+
+ /**
+ * Called at the end of a parse run. Attaches any
+ * non-wrapping labels to their form elements.
+ * @param array $widgets_by_id Cached SimpleTag hash.
+ * @param array $labels SimpleTag label elements.
+ */
+ private function attachLabels($widgets_by_id, $labels) {
+ foreach ($labels as $label) {
+ $for = $label->getFor();
+ if ($for and isset($widgets_by_id[$for])) {
+ $text = $label->getText();
+ foreach ($widgets_by_id[$for] as $widget) {
+ $widget->setLabel($text);
+ }
+ }
+ }
+ }
+}
+?>
\ No newline at end of file
diff --git a/code/ryzom/tools/server/www/webtt/vendors/simpletest/unit_tester.php b/code/ryzom/tools/server/www/webtt/vendors/simpletest/unit_tester.php
new file mode 100644
index 000000000..ce82660af
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/vendors/simpletest/unit_tester.php
@@ -0,0 +1,413 @@
+assert(new TrueExpectation(), $result, $message);
+ }
+
+ /**
+ * Will be true on false and vice versa. False
+ * is the PHP definition of false, so that null,
+ * empty strings, zero and an empty array all count
+ * as false.
+ * @param boolean $result Pass on false.
+ * @param string $message Message to display.
+ * @return boolean True on pass
+ * @access public
+ */
+ function assertFalse($result, $message = '%s') {
+ return $this->assert(new FalseExpectation(), $result, $message);
+ }
+
+ /**
+ * Will be true if the value is null.
+ * @param null $value Supposedly null value.
+ * @param string $message Message to display.
+ * @return boolean True on pass
+ * @access public
+ */
+ function assertNull($value, $message = '%s') {
+ $dumper = new SimpleDumper();
+ $message = sprintf(
+ $message,
+ '[' . $dumper->describeValue($value) . '] should be null');
+ return $this->assertTrue(! isset($value), $message);
+ }
+
+ /**
+ * Will be true if the value is set.
+ * @param mixed $value Supposedly set value.
+ * @param string $message Message to display.
+ * @return boolean True on pass.
+ * @access public
+ */
+ function assertNotNull($value, $message = '%s') {
+ $dumper = new SimpleDumper();
+ $message = sprintf(
+ $message,
+ '[' . $dumper->describeValue($value) . '] should not be null');
+ return $this->assertTrue(isset($value), $message);
+ }
+
+ /**
+ * Type and class test. Will pass if class
+ * matches the type name or is a subclass or
+ * if not an object, but the type is correct.
+ * @param mixed $object Object to test.
+ * @param string $type Type name as string.
+ * @param string $message Message to display.
+ * @return boolean True on pass.
+ * @access public
+ */
+ function assertIsA($object, $type, $message = '%s') {
+ return $this->assert(
+ new IsAExpectation($type),
+ $object,
+ $message);
+ }
+
+ /**
+ * Type and class mismatch test. Will pass if class
+ * name or underling type does not match the one
+ * specified.
+ * @param mixed $object Object to test.
+ * @param string $type Type name as string.
+ * @param string $message Message to display.
+ * @return boolean True on pass.
+ * @access public
+ */
+ function assertNotA($object, $type, $message = '%s') {
+ return $this->assert(
+ new NotAExpectation($type),
+ $object,
+ $message);
+ }
+
+ /**
+ * Will trigger a pass if the two parameters have
+ * the same value only. Otherwise a fail.
+ * @param mixed $first Value to compare.
+ * @param mixed $second Value to compare.
+ * @param string $message Message to display.
+ * @return boolean True on pass
+ * @access public
+ */
+ function assertEqual($first, $second, $message = '%s') {
+ return $this->assert(
+ new EqualExpectation($first),
+ $second,
+ $message);
+ }
+
+ /**
+ * Will trigger a pass if the two parameters have
+ * a different value. Otherwise a fail.
+ * @param mixed $first Value to compare.
+ * @param mixed $second Value to compare.
+ * @param string $message Message to display.
+ * @return boolean True on pass
+ * @access public
+ */
+ function assertNotEqual($first, $second, $message = '%s') {
+ return $this->assert(
+ new NotEqualExpectation($first),
+ $second,
+ $message);
+ }
+
+ /**
+ * Will trigger a pass if the if the first parameter
+ * is near enough to the second by the margin.
+ * @param mixed $first Value to compare.
+ * @param mixed $second Value to compare.
+ * @param mixed $margin Fuzziness of match.
+ * @param string $message Message to display.
+ * @return boolean True on pass
+ * @access public
+ */
+ function assertWithinMargin($first, $second, $margin, $message = '%s') {
+ return $this->assert(
+ new WithinMarginExpectation($first, $margin),
+ $second,
+ $message);
+ }
+
+ /**
+ * Will trigger a pass if the two parameters differ
+ * by more than the margin.
+ * @param mixed $first Value to compare.
+ * @param mixed $second Value to compare.
+ * @param mixed $margin Fuzziness of match.
+ * @param string $message Message to display.
+ * @return boolean True on pass
+ * @access public
+ */
+ function assertOutsideMargin($first, $second, $margin, $message = '%s') {
+ return $this->assert(
+ new OutsideMarginExpectation($first, $margin),
+ $second,
+ $message);
+ }
+
+ /**
+ * Will trigger a pass if the two parameters have
+ * the same value and same type. Otherwise a fail.
+ * @param mixed $first Value to compare.
+ * @param mixed $second Value to compare.
+ * @param string $message Message to display.
+ * @return boolean True on pass
+ * @access public
+ */
+ function assertIdentical($first, $second, $message = '%s') {
+ return $this->assert(
+ new IdenticalExpectation($first),
+ $second,
+ $message);
+ }
+
+ /**
+ * Will trigger a pass if the two parameters have
+ * the different value or different type.
+ * @param mixed $first Value to compare.
+ * @param mixed $second Value to compare.
+ * @param string $message Message to display.
+ * @return boolean True on pass
+ * @access public
+ */
+ function assertNotIdentical($first, $second, $message = '%s') {
+ return $this->assert(
+ new NotIdenticalExpectation($first),
+ $second,
+ $message);
+ }
+
+ /**
+ * Will trigger a pass if both parameters refer
+ * to the same object or value. Fail otherwise.
+ * This will cause problems testing objects under
+ * E_STRICT.
+ * TODO: Replace with expectation.
+ * @param mixed $first Reference to check.
+ * @param mixed $second Hopefully the same variable.
+ * @param string $message Message to display.
+ * @return boolean True on pass
+ * @access public
+ */
+ function assertReference(&$first, &$second, $message = '%s') {
+ $dumper = new SimpleDumper();
+ $message = sprintf(
+ $message,
+ '[' . $dumper->describeValue($first) .
+ '] and [' . $dumper->describeValue($second) .
+ '] should reference the same object');
+ return $this->assertTrue(
+ SimpleTestCompatibility::isReference($first, $second),
+ $message);
+ }
+
+ /**
+ * Will trigger a pass if both parameters refer
+ * to the same object. Fail otherwise. This has
+ * the same semantics at the PHPUnit assertSame.
+ * That is, if values are passed in it has roughly
+ * the same affect as assertIdentical.
+ * TODO: Replace with expectation.
+ * @param mixed $first Object reference to check.
+ * @param mixed $second Hopefully the same object.
+ * @param string $message Message to display.
+ * @return boolean True on pass
+ * @access public
+ */
+ function assertSame($first, $second, $message = '%s') {
+ $dumper = new SimpleDumper();
+ $message = sprintf(
+ $message,
+ '[' . $dumper->describeValue($first) .
+ '] and [' . $dumper->describeValue($second) .
+ '] should reference the same object');
+ return $this->assertTrue($first === $second, $message);
+ }
+
+ /**
+ * Will trigger a pass if both parameters refer
+ * to different objects. Fail otherwise. The objects
+ * have to be identical though.
+ * @param mixed $first Object reference to check.
+ * @param mixed $second Hopefully not the same object.
+ * @param string $message Message to display.
+ * @return boolean True on pass
+ * @access public
+ */
+ function assertClone($first, $second, $message = '%s') {
+ $dumper = new SimpleDumper();
+ $message = sprintf(
+ $message,
+ '[' . $dumper->describeValue($first) .
+ '] and [' . $dumper->describeValue($second) .
+ '] should not be the same object');
+ $identical = new IdenticalExpectation($first);
+ return $this->assertTrue(
+ $identical->test($second) && ! ($first === $second),
+ $message);
+ }
+
+ /**
+ * Will trigger a pass if both parameters refer
+ * to different variables. Fail otherwise. The objects
+ * have to be identical references though.
+ * This will fail under E_STRICT with objects. Use
+ * assertClone() for this.
+ * @param mixed $first Object reference to check.
+ * @param mixed $second Hopefully not the same object.
+ * @param string $message Message to display.
+ * @return boolean True on pass
+ * @access public
+ */
+ function assertCopy(&$first, &$second, $message = "%s") {
+ $dumper = new SimpleDumper();
+ $message = sprintf(
+ $message,
+ "[" . $dumper->describeValue($first) .
+ "] and [" . $dumper->describeValue($second) .
+ "] should not be the same object");
+ return $this->assertFalse(
+ SimpleTestCompatibility::isReference($first, $second),
+ $message);
+ }
+
+ /**
+ * Will trigger a pass if the Perl regex pattern
+ * is found in the subject. Fail otherwise.
+ * @param string $pattern Perl regex to look for including
+ * the regex delimiters.
+ * @param string $subject String to search in.
+ * @param string $message Message to display.
+ * @return boolean True on pass
+ * @access public
+ */
+ function assertPattern($pattern, $subject, $message = '%s') {
+ return $this->assert(
+ new PatternExpectation($pattern),
+ $subject,
+ $message);
+ }
+
+ /**
+ * Will trigger a pass if the perl regex pattern
+ * is not present in subject. Fail if found.
+ * @param string $pattern Perl regex to look for including
+ * the regex delimiters.
+ * @param string $subject String to search in.
+ * @param string $message Message to display.
+ * @return boolean True on pass
+ * @access public
+ */
+ function assertNoPattern($pattern, $subject, $message = '%s') {
+ return $this->assert(
+ new NoPatternExpectation($pattern),
+ $subject,
+ $message);
+ }
+
+ /**
+ * Prepares for an error. If the error mismatches it
+ * passes through, otherwise it is swallowed. Any
+ * left over errors trigger failures.
+ * @param SimpleExpectation/string $expected The error to match.
+ * @param string $message Message on failure.
+ * @access public
+ */
+ function expectError($expected = false, $message = '%s') {
+ $queue = SimpleTest::getContext()->get('SimpleErrorQueue');
+ $queue->expectError($this->coerceExpectation($expected), $message);
+ }
+
+ /**
+ * Prepares for an exception. If the error mismatches it
+ * passes through, otherwise it is swallowed. Any
+ * left over errors trigger failures.
+ * @param SimpleExpectation/Exception $expected The error to match.
+ * @param string $message Message on failure.
+ * @access public
+ */
+ function expectException($expected = false, $message = '%s') {
+ $queue = SimpleTest::getContext()->get('SimpleExceptionTrap');
+ $line = $this->getAssertionLine();
+ $queue->expectException($expected, $message . $line);
+ }
+
+ /**
+ * Tells SimpleTest to ignore an upcoming exception as not relevant
+ * to the current test. It doesn't affect the test, whether thrown or
+ * not.
+ * @param SimpleExpectation/Exception $ignored The error to ignore.
+ * @access public
+ */
+ function ignoreException($ignored = false) {
+ SimpleTest::getContext()->get('SimpleExceptionTrap')->ignoreException($ignored);
+ }
+
+ /**
+ * Creates an equality expectation if the
+ * object/value is not already some type
+ * of expectation.
+ * @param mixed $expected Expected value.
+ * @return SimpleExpectation Expectation object.
+ * @access private
+ */
+ protected function coerceExpectation($expected) {
+ if ($expected == false) {
+ return new TrueExpectation();
+ }
+ if (SimpleTestCompatibility::isA($expected, 'SimpleExpectation')) {
+ return $expected;
+ }
+ return new EqualExpectation(
+ is_string($expected) ? str_replace('%', '%%', $expected) : $expected);
+ }
+}
+?>
\ No newline at end of file
diff --git a/code/ryzom/tools/server/www/webtt/vendors/simpletest/url.php b/code/ryzom/tools/server/www/webtt/vendors/simpletest/url.php
new file mode 100644
index 000000000..11d70e745
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/vendors/simpletest/url.php
@@ -0,0 +1,550 @@
+chompCoordinates($url);
+ $this->setCoordinates($x, $y);
+ $this->scheme = $this->chompScheme($url);
+ if ($this->scheme === 'file') {
+ // Unescaped backslashes not used in directory separator context
+ // will get caught by this, but they should have been urlencoded
+ // anyway so we don't care. If this ends up being a problem, the
+ // host regexp must be modified to match for backslashes when
+ // the scheme is file.
+ $url = str_replace('\\', '/', $url);
+ }
+ list($this->username, $this->password) = $this->chompLogin($url);
+ $this->host = $this->chompHost($url);
+ $this->port = false;
+ if (preg_match('/(.*?):(.*)/', $this->host, $host_parts)) {
+ if ($this->scheme === 'file' && strlen($this->host) === 2) {
+ // DOS drive was placed in authority; promote it to path.
+ $url = '/' . $this->host . $url;
+ $this->host = false;
+ } else {
+ $this->host = $host_parts[1];
+ $this->port = (integer)$host_parts[2];
+ }
+ }
+ $this->path = $this->chompPath($url);
+ $this->request = $this->parseRequest($this->chompRequest($url));
+ $this->fragment = (strncmp($url, "#", 1) == 0 ? substr($url, 1) : false);
+ $this->target = false;
+ }
+
+ /**
+ * Extracts the X, Y coordinate pair from an image map.
+ * @param string $url URL so far. The coordinates will be
+ * removed.
+ * @return array X, Y as a pair of integers.
+ * @access private
+ */
+ protected function chompCoordinates(&$url) {
+ if (preg_match('/(.*)\?(\d+),(\d+)$/', $url, $matches)) {
+ $url = $matches[1];
+ return array((integer)$matches[2], (integer)$matches[3]);
+ }
+ return array(false, false);
+ }
+
+ /**
+ * Extracts the scheme part of an incoming URL.
+ * @param string $url URL so far. The scheme will be
+ * removed.
+ * @return string Scheme part or false.
+ * @access private
+ */
+ protected function chompScheme(&$url) {
+ if (preg_match('#^([^/:]*):(//)(.*)#', $url, $matches)) {
+ $url = $matches[2] . $matches[3];
+ return $matches[1];
+ }
+ return false;
+ }
+
+ /**
+ * Extracts the username and password from the
+ * incoming URL. The // prefix will be reattached
+ * to the URL after the doublet is extracted.
+ * @param string $url URL so far. The username and
+ * password are removed.
+ * @return array Two item list of username and
+ * password. Will urldecode() them.
+ * @access private
+ */
+ protected function chompLogin(&$url) {
+ $prefix = '';
+ if (preg_match('#^(//)(.*)#', $url, $matches)) {
+ $prefix = $matches[1];
+ $url = $matches[2];
+ }
+ if (preg_match('#^([^/]*)@(.*)#', $url, $matches)) {
+ $url = $prefix . $matches[2];
+ $parts = explode(":", $matches[1]);
+ return array(
+ urldecode($parts[0]),
+ isset($parts[1]) ? urldecode($parts[1]) : false);
+ }
+ $url = $prefix . $url;
+ return array(false, false);
+ }
+
+ /**
+ * Extracts the host part of an incoming URL.
+ * Includes the port number part. Will extract
+ * the host if it starts with // or it has
+ * a top level domain or it has at least two
+ * dots.
+ * @param string $url URL so far. The host will be
+ * removed.
+ * @return string Host part guess or false.
+ * @access private
+ */
+ protected function chompHost(&$url) {
+ if (preg_match('!^(//)(.*?)(/.*|\?.*|#.*|$)!', $url, $matches)) {
+ $url = $matches[3];
+ return $matches[2];
+ }
+ if (preg_match('!(.*?)(\.\./|\./|/|\?|#|$)(.*)!', $url, $matches)) {
+ $tlds = SimpleUrl::getAllTopLevelDomains();
+ if (preg_match('/[a-z0-9\-]+\.(' . $tlds . ')/i', $matches[1])) {
+ $url = $matches[2] . $matches[3];
+ return $matches[1];
+ } elseif (preg_match('/[a-z0-9\-]+\.[a-z0-9\-]+\.[a-z0-9\-]+/i', $matches[1])) {
+ $url = $matches[2] . $matches[3];
+ return $matches[1];
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Extracts the path information from the incoming
+ * URL. Strips this path from the URL.
+ * @param string $url URL so far. The host will be
+ * removed.
+ * @return string Path part or '/'.
+ * @access private
+ */
+ protected function chompPath(&$url) {
+ if (preg_match('/(.*?)(\?|#|$)(.*)/', $url, $matches)) {
+ $url = $matches[2] . $matches[3];
+ return ($matches[1] ? $matches[1] : '');
+ }
+ return '';
+ }
+
+ /**
+ * Strips off the request data.
+ * @param string $url URL so far. The request will be
+ * removed.
+ * @return string Raw request part.
+ * @access private
+ */
+ protected function chompRequest(&$url) {
+ if (preg_match('/\?(.*?)(#|$)(.*)/', $url, $matches)) {
+ $url = $matches[2] . $matches[3];
+ return $matches[1];
+ }
+ return '';
+ }
+
+ /**
+ * Breaks the request down into an object.
+ * @param string $raw Raw request.
+ * @return SimpleFormEncoding Parsed data.
+ * @access private
+ */
+ protected function parseRequest($raw) {
+ $this->raw = $raw;
+ $request = new SimpleGetEncoding();
+ foreach (explode("&", $raw) as $pair) {
+ if (preg_match('/(.*?)=(.*)/', $pair, $matches)) {
+ $request->add(urldecode($matches[1]), urldecode($matches[2]));
+ } elseif ($pair) {
+ $request->add(urldecode($pair), '');
+ }
+ }
+ return $request;
+ }
+
+ /**
+ * Accessor for protocol part.
+ * @param string $default Value to use if not present.
+ * @return string Scheme name, e.g "http".
+ * @access public
+ */
+ function getScheme($default = false) {
+ return $this->scheme ? $this->scheme : $default;
+ }
+
+ /**
+ * Accessor for user name.
+ * @return string Username preceding host.
+ * @access public
+ */
+ function getUsername() {
+ return $this->username;
+ }
+
+ /**
+ * Accessor for password.
+ * @return string Password preceding host.
+ * @access public
+ */
+ function getPassword() {
+ return $this->password;
+ }
+
+ /**
+ * Accessor for hostname and port.
+ * @param string $default Value to use if not present.
+ * @return string Hostname only.
+ * @access public
+ */
+ function getHost($default = false) {
+ return $this->host ? $this->host : $default;
+ }
+
+ /**
+ * Accessor for top level domain.
+ * @return string Last part of host.
+ * @access public
+ */
+ function getTld() {
+ $path_parts = pathinfo($this->getHost());
+ return (isset($path_parts['extension']) ? $path_parts['extension'] : false);
+ }
+
+ /**
+ * Accessor for port number.
+ * @return integer TCP/IP port number.
+ * @access public
+ */
+ function getPort() {
+ return $this->port;
+ }
+
+ /**
+ * Accessor for path.
+ * @return string Full path including leading slash if implied.
+ * @access public
+ */
+ function getPath() {
+ if (! $this->path && $this->host) {
+ return '/';
+ }
+ return $this->path;
+ }
+
+ /**
+ * Accessor for page if any. This may be a
+ * directory name if ambiguious.
+ * @return Page name.
+ * @access public
+ */
+ function getPage() {
+ if (! preg_match('/([^\/]*?)$/', $this->getPath(), $matches)) {
+ return false;
+ }
+ return $matches[1];
+ }
+
+ /**
+ * Gets the path to the page.
+ * @return string Path less the page.
+ * @access public
+ */
+ function getBasePath() {
+ if (! preg_match('/(.*\/)[^\/]*?$/', $this->getPath(), $matches)) {
+ return false;
+ }
+ return $matches[1];
+ }
+
+ /**
+ * Accessor for fragment at end of URL after the "#".
+ * @return string Part after "#".
+ * @access public
+ */
+ function getFragment() {
+ return $this->fragment;
+ }
+
+ /**
+ * Sets image coordinates. Set to false to clear
+ * them.
+ * @param integer $x Horizontal position.
+ * @param integer $y Vertical position.
+ * @access public
+ */
+ function setCoordinates($x = false, $y = false) {
+ if (($x === false) || ($y === false)) {
+ $this->x = $this->y = false;
+ return;
+ }
+ $this->x = (integer)$x;
+ $this->y = (integer)$y;
+ }
+
+ /**
+ * Accessor for horizontal image coordinate.
+ * @return integer X value.
+ * @access public
+ */
+ function getX() {
+ return $this->x;
+ }
+
+ /**
+ * Accessor for vertical image coordinate.
+ * @return integer Y value.
+ * @access public
+ */
+ function getY() {
+ return $this->y;
+ }
+
+ /**
+ * Accessor for current request parameters
+ * in URL string form. Will return teh original request
+ * if at all possible even if it doesn't make much
+ * sense.
+ * @return string Form is string "?a=1&b=2", etc.
+ * @access public
+ */
+ function getEncodedRequest() {
+ if ($this->raw) {
+ $encoded = $this->raw;
+ } else {
+ $encoded = $this->request->asUrlRequest();
+ }
+ if ($encoded) {
+ return '?' . preg_replace('/^\?/', '', $encoded);
+ }
+ return '';
+ }
+
+ /**
+ * Adds an additional parameter to the request.
+ * @param string $key Name of parameter.
+ * @param string $value Value as string.
+ * @access public
+ */
+ function addRequestParameter($key, $value) {
+ $this->raw = false;
+ $this->request->add($key, $value);
+ }
+
+ /**
+ * Adds additional parameters to the request.
+ * @param hash/SimpleFormEncoding $parameters Additional
+ * parameters.
+ * @access public
+ */
+ function addRequestParameters($parameters) {
+ $this->raw = false;
+ $this->request->merge($parameters);
+ }
+
+ /**
+ * Clears down all parameters.
+ * @access public
+ */
+ function clearRequest() {
+ $this->raw = false;
+ $this->request = new SimpleGetEncoding();
+ }
+
+ /**
+ * Gets the frame target if present. Although
+ * not strictly part of the URL specification it
+ * acts as similarily to the browser.
+ * @return boolean/string Frame name or false if none.
+ * @access public
+ */
+ function getTarget() {
+ return $this->target;
+ }
+
+ /**
+ * Attaches a frame target.
+ * @param string $frame Name of frame.
+ * @access public
+ */
+ function setTarget($frame) {
+ $this->raw = false;
+ $this->target = $frame;
+ }
+
+ /**
+ * Renders the URL back into a string.
+ * @return string URL in canonical form.
+ * @access public
+ */
+ function asString() {
+ $path = $this->path;
+ $scheme = $identity = $host = $port = $encoded = $fragment = '';
+ if ($this->username && $this->password) {
+ $identity = $this->username . ':' . $this->password . '@';
+ }
+ if ($this->getHost()) {
+ $scheme = $this->getScheme() ? $this->getScheme() : 'http';
+ $scheme .= '://';
+ $host = $this->getHost();
+ } elseif ($this->getScheme() === 'file') {
+ // Safest way; otherwise, file URLs on Windows have an extra
+ // leading slash. It might be possible to convert file://
+ // URIs to local file paths, but that requires more research.
+ $scheme = 'file://';
+ }
+ if ($this->getPort() && $this->getPort() != 80 ) {
+ $port = ':'.$this->getPort();
+ }
+
+ if (substr($this->path, 0, 1) == '/') {
+ $path = $this->normalisePath($this->path);
+ }
+ $encoded = $this->getEncodedRequest();
+ $fragment = $this->getFragment() ? '#'. $this->getFragment() : '';
+ $coords = $this->getX() === false ? '' : '?' . $this->getX() . ',' . $this->getY();
+ return "$scheme$identity$host$port$path$encoded$fragment$coords";
+ }
+
+ /**
+ * Replaces unknown sections to turn a relative
+ * URL into an absolute one. The base URL can
+ * be either a string or a SimpleUrl object.
+ * @param string/SimpleUrl $base Base URL.
+ * @access public
+ */
+ function makeAbsolute($base) {
+ if (! is_object($base)) {
+ $base = new SimpleUrl($base);
+ }
+ if ($this->getHost()) {
+ $scheme = $this->getScheme();
+ $host = $this->getHost();
+ $port = $this->getPort() ? ':' . $this->getPort() : '';
+ $identity = $this->getIdentity() ? $this->getIdentity() . '@' : '';
+ if (! $identity) {
+ $identity = $base->getIdentity() ? $base->getIdentity() . '@' : '';
+ }
+ } else {
+ $scheme = $base->getScheme();
+ $host = $base->getHost();
+ $port = $base->getPort() ? ':' . $base->getPort() : '';
+ $identity = $base->getIdentity() ? $base->getIdentity() . '@' : '';
+ }
+ $path = $this->normalisePath($this->extractAbsolutePath($base));
+ $encoded = $this->getEncodedRequest();
+ $fragment = $this->getFragment() ? '#'. $this->getFragment() : '';
+ $coords = $this->getX() === false ? '' : '?' . $this->getX() . ',' . $this->getY();
+ return new SimpleUrl("$scheme://$identity$host$port$path$encoded$fragment$coords");
+ }
+
+ /**
+ * Replaces unknown sections of the path with base parts
+ * to return a complete absolute one.
+ * @param string/SimpleUrl $base Base URL.
+ * @param string Absolute path.
+ * @access private
+ */
+ protected function extractAbsolutePath($base) {
+ if ($this->getHost()) {
+ return $this->path;
+ }
+ if (! $this->isRelativePath($this->path)) {
+ return $this->path;
+ }
+ if ($this->path) {
+ return $base->getBasePath() . $this->path;
+ }
+ return $base->getPath();
+ }
+
+ /**
+ * Simple test to see if a path part is relative.
+ * @param string $path Path to test.
+ * @return boolean True if starts with a "/".
+ * @access private
+ */
+ protected function isRelativePath($path) {
+ return (substr($path, 0, 1) != '/');
+ }
+
+ /**
+ * Extracts the username and password for use in rendering
+ * a URL.
+ * @return string/boolean Form of username:password or false.
+ * @access public
+ */
+ function getIdentity() {
+ if ($this->username && $this->password) {
+ return $this->username . ':' . $this->password;
+ }
+ return false;
+ }
+
+ /**
+ * Replaces . and .. sections of the path.
+ * @param string $path Unoptimised path.
+ * @return string Path with dots removed if possible.
+ * @access public
+ */
+ function normalisePath($path) {
+ $path = preg_replace('|/\./|', '/', $path);
+ return preg_replace('|/[^/]+/\.\./|', '/', $path);
+ }
+
+ /**
+ * A pipe seperated list of all TLDs that result in two part
+ * domain names.
+ * @return string Pipe separated list.
+ * @access public
+ */
+ static function getAllTopLevelDomains() {
+ return 'com|edu|net|org|gov|mil|int|biz|info|name|pro|aero|coop|museum';
+ }
+}
+?>
\ No newline at end of file
diff --git a/code/ryzom/tools/server/www/webtt/vendors/simpletest/user_agent.php b/code/ryzom/tools/server/www/webtt/vendors/simpletest/user_agent.php
new file mode 100644
index 000000000..aff7ee6e6
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/vendors/simpletest/user_agent.php
@@ -0,0 +1,328 @@
+cookie_jar = new SimpleCookieJar();
+ $this->authenticator = new SimpleAuthenticator();
+ }
+
+ /**
+ * Removes expired and temporary cookies as if
+ * the browser was closed and re-opened. Authorisation
+ * has to be obtained again as well.
+ * @param string/integer $date Time when session restarted.
+ * If omitted then all persistent
+ * cookies are kept.
+ * @access public
+ */
+ function restart($date = false) {
+ $this->cookie_jar->restartSession($date);
+ $this->authenticator->restartSession();
+ }
+
+ /**
+ * Adds a header to every fetch.
+ * @param string $header Header line to add to every
+ * request until cleared.
+ * @access public
+ */
+ function addHeader($header) {
+ $this->additional_headers[] = $header;
+ }
+
+ /**
+ * Ages the cookies by the specified time.
+ * @param integer $interval Amount in seconds.
+ * @access public
+ */
+ function ageCookies($interval) {
+ $this->cookie_jar->agePrematurely($interval);
+ }
+
+ /**
+ * Sets an additional cookie. If a cookie has
+ * the same name and path it is replaced.
+ * @param string $name Cookie key.
+ * @param string $value Value of cookie.
+ * @param string $host Host upon which the cookie is valid.
+ * @param string $path Cookie path if not host wide.
+ * @param string $expiry Expiry date.
+ * @access public
+ */
+ function setCookie($name, $value, $host = false, $path = '/', $expiry = false) {
+ $this->cookie_jar->setCookie($name, $value, $host, $path, $expiry);
+ }
+
+ /**
+ * Reads the most specific cookie value from the
+ * browser cookies.
+ * @param string $host Host to search.
+ * @param string $path Applicable path.
+ * @param string $name Name of cookie to read.
+ * @return string False if not present, else the
+ * value as a string.
+ * @access public
+ */
+ function getCookieValue($host, $path, $name) {
+ return $this->cookie_jar->getCookieValue($host, $path, $name);
+ }
+
+ /**
+ * Reads the current cookies within the base URL.
+ * @param string $name Key of cookie to find.
+ * @param SimpleUrl $base Base URL to search from.
+ * @return string/boolean Null if there is no base URL, false
+ * if the cookie is not set.
+ * @access public
+ */
+ function getBaseCookieValue($name, $base) {
+ if (! $base) {
+ return null;
+ }
+ return $this->getCookieValue($base->getHost(), $base->getPath(), $name);
+ }
+
+ /**
+ * Switches off cookie sending and recieving.
+ * @access public
+ */
+ function ignoreCookies() {
+ $this->cookies_enabled = false;
+ }
+
+ /**
+ * Switches back on the cookie sending and recieving.
+ * @access public
+ */
+ function useCookies() {
+ $this->cookies_enabled = true;
+ }
+
+ /**
+ * Sets the socket timeout for opening a connection.
+ * @param integer $timeout Maximum time in seconds.
+ * @access public
+ */
+ function setConnectionTimeout($timeout) {
+ $this->connection_timeout = $timeout;
+ }
+
+ /**
+ * Sets the maximum number of redirects before
+ * a page will be loaded anyway.
+ * @param integer $max Most hops allowed.
+ * @access public
+ */
+ function setMaximumRedirects($max) {
+ $this->max_redirects = $max;
+ }
+
+ /**
+ * Sets proxy to use on all requests for when
+ * testing from behind a firewall. Set URL
+ * to false to disable.
+ * @param string $proxy Proxy URL.
+ * @param string $username Proxy username for authentication.
+ * @param string $password Proxy password for authentication.
+ * @access public
+ */
+ function useProxy($proxy, $username, $password) {
+ if (! $proxy) {
+ $this->proxy = false;
+ return;
+ }
+ if ((strncmp($proxy, 'http://', 7) != 0) && (strncmp($proxy, 'https://', 8) != 0)) {
+ $proxy = 'http://'. $proxy;
+ }
+ $this->proxy = new SimpleUrl($proxy);
+ $this->proxy_username = $username;
+ $this->proxy_password = $password;
+ }
+
+ /**
+ * Test to see if the redirect limit is passed.
+ * @param integer $redirects Count so far.
+ * @return boolean True if over.
+ * @access private
+ */
+ protected function isTooManyRedirects($redirects) {
+ return ($redirects > $this->max_redirects);
+ }
+
+ /**
+ * Sets the identity for the current realm.
+ * @param string $host Host to which realm applies.
+ * @param string $realm Full name of realm.
+ * @param string $username Username for realm.
+ * @param string $password Password for realm.
+ * @access public
+ */
+ function setIdentity($host, $realm, $username, $password) {
+ $this->authenticator->setIdentityForRealm($host, $realm, $username, $password);
+ }
+
+ /**
+ * Fetches a URL as a response object. Will keep trying if redirected.
+ * It will also collect authentication realm information.
+ * @param string/SimpleUrl $url Target to fetch.
+ * @param SimpleEncoding $encoding Additional parameters for request.
+ * @return SimpleHttpResponse Hopefully the target page.
+ * @access public
+ */
+ function fetchResponse($url, $encoding) {
+ if ($encoding->getMethod() != 'POST') {
+ $url->addRequestParameters($encoding);
+ $encoding->clear();
+ }
+ $response = $this->fetchWhileRedirected($url, $encoding);
+ if ($headers = $response->getHeaders()) {
+ if ($headers->isChallenge()) {
+ $this->authenticator->addRealm(
+ $url,
+ $headers->getAuthentication(),
+ $headers->getRealm());
+ }
+ }
+ return $response;
+ }
+
+ /**
+ * Fetches the page until no longer redirected or
+ * until the redirect limit runs out.
+ * @param SimpleUrl $url Target to fetch.
+ * @param SimpelFormEncoding $encoding Additional parameters for request.
+ * @return SimpleHttpResponse Hopefully the target page.
+ * @access private
+ */
+ protected function fetchWhileRedirected($url, $encoding) {
+ $redirects = 0;
+ do {
+ $response = $this->fetch($url, $encoding);
+ if ($response->isError()) {
+ return $response;
+ }
+ $headers = $response->getHeaders();
+ $location = new SimpleUrl($headers->getLocation());
+ $url = $location->makeAbsolute($url);
+ if ($this->cookies_enabled) {
+ $headers->writeCookiesToJar($this->cookie_jar, $url);
+ }
+ if (! $headers->isRedirect()) {
+ break;
+ }
+ $encoding = new SimpleGetEncoding();
+ } while (! $this->isTooManyRedirects(++$redirects));
+ return $response;
+ }
+
+ /**
+ * Actually make the web request.
+ * @param SimpleUrl $url Target to fetch.
+ * @param SimpleFormEncoding $encoding Additional parameters for request.
+ * @return SimpleHttpResponse Headers and hopefully content.
+ * @access protected
+ */
+ protected function fetch($url, $encoding) {
+ $request = $this->createRequest($url, $encoding);
+ return $request->fetch($this->connection_timeout);
+ }
+
+ /**
+ * Creates a full page request.
+ * @param SimpleUrl $url Target to fetch as url object.
+ * @param SimpleFormEncoding $encoding POST/GET parameters.
+ * @return SimpleHttpRequest New request.
+ * @access private
+ */
+ protected function createRequest($url, $encoding) {
+ $request = $this->createHttpRequest($url, $encoding);
+ $this->addAdditionalHeaders($request);
+ if ($this->cookies_enabled) {
+ $request->readCookiesFromJar($this->cookie_jar, $url);
+ }
+ $this->authenticator->addHeaders($request, $url);
+ return $request;
+ }
+
+ /**
+ * Builds the appropriate HTTP request object.
+ * @param SimpleUrl $url Target to fetch as url object.
+ * @param SimpleFormEncoding $parameters POST/GET parameters.
+ * @return SimpleHttpRequest New request object.
+ * @access protected
+ */
+ protected function createHttpRequest($url, $encoding) {
+ return new SimpleHttpRequest($this->createRoute($url), $encoding);
+ }
+
+ /**
+ * Sets up either a direct route or via a proxy.
+ * @param SimpleUrl $url Target to fetch as url object.
+ * @return SimpleRoute Route to take to fetch URL.
+ * @access protected
+ */
+ protected function createRoute($url) {
+ if ($this->proxy) {
+ return new SimpleProxyRoute(
+ $url,
+ $this->proxy,
+ $this->proxy_username,
+ $this->proxy_password);
+ }
+ return new SimpleRoute($url);
+ }
+
+ /**
+ * Adds additional manual headers.
+ * @param SimpleHttpRequest $request Outgoing request.
+ * @access private
+ */
+ protected function addAdditionalHeaders(&$request) {
+ foreach ($this->additional_headers as $header) {
+ $request->addHeaderLine($header);
+ }
+ }
+}
+?>
\ No newline at end of file
diff --git a/code/ryzom/tools/server/www/webtt/vendors/simpletest/web_tester.php b/code/ryzom/tools/server/www/webtt/vendors/simpletest/web_tester.php
new file mode 100644
index 000000000..a17230e7b
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/vendors/simpletest/web_tester.php
@@ -0,0 +1,1532 @@
+value = $value;
+ }
+
+ /**
+ * Tests the expectation. True if it matches
+ * a string value or an array value in any order.
+ * @param mixed $compare Comparison value. False for
+ * an unset field.
+ * @return boolean True if correct.
+ * @access public
+ */
+ function test($compare) {
+ if ($this->value === false) {
+ return ($compare === false);
+ }
+ if ($this->isSingle($this->value)) {
+ return $this->testSingle($compare);
+ }
+ if (is_array($this->value)) {
+ return $this->testMultiple($compare);
+ }
+ return false;
+ }
+
+ /**
+ * Tests for valid field comparisons with a single option.
+ * @param mixed $value Value to type check.
+ * @return boolean True if integer, string or float.
+ * @access private
+ */
+ protected function isSingle($value) {
+ return is_string($value) || is_integer($value) || is_float($value);
+ }
+
+ /**
+ * String comparison for simple field with a single option.
+ * @param mixed $compare String to test against.
+ * @returns boolean True if matching.
+ * @access private
+ */
+ protected function testSingle($compare) {
+ if (is_array($compare) && count($compare) == 1) {
+ $compare = $compare[0];
+ }
+ if (! $this->isSingle($compare)) {
+ return false;
+ }
+ return ($this->value == $compare);
+ }
+
+ /**
+ * List comparison for multivalue field.
+ * @param mixed $compare List in any order to test against.
+ * @returns boolean True if matching.
+ * @access private
+ */
+ protected function testMultiple($compare) {
+ if (is_string($compare)) {
+ $compare = array($compare);
+ }
+ if (! is_array($compare)) {
+ return false;
+ }
+ sort($compare);
+ return ($this->value === $compare);
+ }
+
+ /**
+ * Returns a human readable test message.
+ * @param mixed $compare Comparison value.
+ * @return string Description of success
+ * or failure.
+ * @access public
+ */
+ function testMessage($compare) {
+ $dumper = $this->getDumper();
+ if (is_array($compare)) {
+ sort($compare);
+ }
+ if ($this->test($compare)) {
+ return "Field expectation [" . $dumper->describeValue($this->value) . "]";
+ } else {
+ return "Field expectation [" . $dumper->describeValue($this->value) .
+ "] fails with [" .
+ $dumper->describeValue($compare) . "] " .
+ $dumper->describeDifference($this->value, $compare);
+ }
+ }
+}
+
+/**
+ * Test for a specific HTTP header within a header block.
+ * @package SimpleTest
+ * @subpackage WebTester
+ */
+class HttpHeaderExpectation extends SimpleExpectation {
+ private $expected_header;
+ private $expected_value;
+
+ /**
+ * Sets the field and value to compare against.
+ * @param string $header Case insenstive trimmed header name.
+ * @param mixed $value Optional value to compare. If not
+ * given then any value will match. If
+ * an expectation object then that will
+ * be used instead.
+ * @param string $message Optiona message override. Can use %s as
+ * a placeholder for the original message.
+ */
+ function __construct($header, $value = false, $message = '%s') {
+ parent::__construct($message);
+ $this->expected_header = $this->normaliseHeader($header);
+ $this->expected_value = $value;
+ }
+
+ /**
+ * Accessor for aggregated object.
+ * @return mixed Expectation set in constructor.
+ * @access protected
+ */
+ protected function getExpectation() {
+ return $this->expected_value;
+ }
+
+ /**
+ * Removes whitespace at ends and case variations.
+ * @param string $header Name of header.
+ * @param string Trimmed and lowecased header
+ * name.
+ * @access private
+ */
+ protected function normaliseHeader($header) {
+ return strtolower(trim($header));
+ }
+
+ /**
+ * Tests the expectation. True if it matches
+ * a string value or an array value in any order.
+ * @param mixed $compare Raw header block to search.
+ * @return boolean True if header present.
+ * @access public
+ */
+ function test($compare) {
+ return is_string($this->findHeader($compare));
+ }
+
+ /**
+ * Searches the incoming result. Will extract the matching
+ * line as text.
+ * @param mixed $compare Raw header block to search.
+ * @return string Matching header line.
+ * @access protected
+ */
+ protected function findHeader($compare) {
+ $lines = explode("\r\n", $compare);
+ foreach ($lines as $line) {
+ if ($this->testHeaderLine($line)) {
+ return $line;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Compares a single header line against the expectation.
+ * @param string $line A single line to compare.
+ * @return boolean True if matched.
+ * @access private
+ */
+ protected function testHeaderLine($line) {
+ if (count($parsed = explode(':', $line, 2)) < 2) {
+ return false;
+ }
+ list($header, $value) = $parsed;
+ if ($this->normaliseHeader($header) != $this->expected_header) {
+ return false;
+ }
+ return $this->testHeaderValue($value, $this->expected_value);
+ }
+
+ /**
+ * Tests the value part of the header.
+ * @param string $value Value to test.
+ * @param mixed $expected Value to test against.
+ * @return boolean True if matched.
+ * @access protected
+ */
+ protected function testHeaderValue($value, $expected) {
+ if ($expected === false) {
+ return true;
+ }
+ if (SimpleExpectation::isExpectation($expected)) {
+ return $expected->test(trim($value));
+ }
+ return (trim($value) == trim($expected));
+ }
+
+ /**
+ * Returns a human readable test message.
+ * @param mixed $compare Raw header block to search.
+ * @return string Description of success
+ * or failure.
+ * @access public
+ */
+ function testMessage($compare) {
+ if (SimpleExpectation::isExpectation($this->expected_value)) {
+ $message = $this->expected_value->overlayMessage($compare, $this->getDumper());
+ } else {
+ $message = $this->expected_header .
+ ($this->expected_value ? ': ' . $this->expected_value : '');
+ }
+ if (is_string($line = $this->findHeader($compare))) {
+ return "Searching for header [$message] found [$line]";
+ } else {
+ return "Failed to find header [$message]";
+ }
+ }
+}
+
+/**
+ * Test for a specific HTTP header within a header block that
+ * should not be found.
+ * @package SimpleTest
+ * @subpackage WebTester
+ */
+class NoHttpHeaderExpectation extends HttpHeaderExpectation {
+ private $expected_header;
+ private $expected_value;
+
+ /**
+ * Sets the field and value to compare against.
+ * @param string $unwanted Case insenstive trimmed header name.
+ * @param string $message Optiona message override. Can use %s as
+ * a placeholder for the original message.
+ */
+ function __construct($unwanted, $message = '%s') {
+ parent::__construct($unwanted, false, $message);
+ }
+
+ /**
+ * Tests that the unwanted header is not found.
+ * @param mixed $compare Raw header block to search.
+ * @return boolean True if header present.
+ * @access public
+ */
+ function test($compare) {
+ return ($this->findHeader($compare) === false);
+ }
+
+ /**
+ * Returns a human readable test message.
+ * @param mixed $compare Raw header block to search.
+ * @return string Description of success
+ * or failure.
+ * @access public
+ */
+ function testMessage($compare) {
+ $expectation = $this->getExpectation();
+ if (is_string($line = $this->findHeader($compare))) {
+ return "Found unwanted header [$expectation] with [$line]";
+ } else {
+ return "Did not find unwanted header [$expectation]";
+ }
+ }
+}
+
+/**
+ * Test for a text substring.
+ * @package SimpleTest
+ * @subpackage UnitTester
+ */
+class TextExpectation extends SimpleExpectation {
+ private $substring;
+
+ /**
+ * Sets the value to compare against.
+ * @param string $substring Text to search for.
+ * @param string $message Customised message on failure.
+ * @access public
+ */
+ function __construct($substring, $message = '%s') {
+ parent::__construct($message);
+ $this->substring = $substring;
+ }
+
+ /**
+ * Accessor for the substring.
+ * @return string Text to match.
+ * @access protected
+ */
+ protected function getSubstring() {
+ return $this->substring;
+ }
+
+ /**
+ * Tests the expectation. True if the text contains the
+ * substring.
+ * @param string $compare Comparison value.
+ * @return boolean True if correct.
+ * @access public
+ */
+ function test($compare) {
+ return (strpos($compare, $this->substring) !== false);
+ }
+
+ /**
+ * Returns a human readable test message.
+ * @param mixed $compare Comparison value.
+ * @return string Description of success
+ * or failure.
+ * @access public
+ */
+ function testMessage($compare) {
+ if ($this->test($compare)) {
+ return $this->describeTextMatch($this->getSubstring(), $compare);
+ } else {
+ $dumper = $this->getDumper();
+ return "Text [" . $this->getSubstring() .
+ "] not detected in [" .
+ $dumper->describeValue($compare) . "]";
+ }
+ }
+
+ /**
+ * Describes a pattern match including the string
+ * found and it's position.
+ * @param string $substring Text to search for.
+ * @param string $subject Subject to search.
+ * @access protected
+ */
+ protected function describeTextMatch($substring, $subject) {
+ $position = strpos($subject, $substring);
+ $dumper = $this->getDumper();
+ return "Text [$substring] detected at character [$position] in [" .
+ $dumper->describeValue($subject) . "] in region [" .
+ $dumper->clipString($subject, 100, $position) . "]";
+ }
+}
+
+/**
+ * Fail if a substring is detected within the
+ * comparison text.
+ * @package SimpleTest
+ * @subpackage UnitTester
+ */
+class NoTextExpectation extends TextExpectation {
+
+ /**
+ * Sets the reject pattern
+ * @param string $substring Text to search for.
+ * @param string $message Customised message on failure.
+ * @access public
+ */
+ function __construct($substring, $message = '%s') {
+ parent::__construct($substring, $message);
+ }
+
+ /**
+ * Tests the expectation. False if the substring appears
+ * in the text.
+ * @param string $compare Comparison value.
+ * @return boolean True if correct.
+ * @access public
+ */
+ function test($compare) {
+ return ! parent::test($compare);
+ }
+
+ /**
+ * Returns a human readable test message.
+ * @param string $compare Comparison value.
+ * @return string Description of success
+ * or failure.
+ * @access public
+ */
+ function testMessage($compare) {
+ if ($this->test($compare)) {
+ $dumper = $this->getDumper();
+ return "Text [" . $this->getSubstring() .
+ "] not detected in [" .
+ $dumper->describeValue($compare) . "]";
+ } else {
+ return $this->describeTextMatch($this->getSubstring(), $compare);
+ }
+ }
+}
+
+/**
+ * Test case for testing of web pages. Allows
+ * fetching of pages, parsing of HTML and
+ * submitting forms.
+ * @package SimpleTest
+ * @subpackage WebTester
+ */
+class WebTestCase extends SimpleTestCase {
+ private $browser;
+ private $ignore_errors = false;
+
+ /**
+ * Creates an empty test case. Should be subclassed
+ * with test methods for a functional test case.
+ * @param string $label Name of test case. Will use
+ * the class name if none specified.
+ * @access public
+ */
+ function __construct($label = false) {
+ parent::__construct($label);
+ }
+
+ /**
+ * Announces the start of the test.
+ * @param string $method Test method just started.
+ * @access public
+ */
+ function before($method) {
+ parent::before($method);
+ $this->setBrowser($this->createBrowser());
+ }
+
+ /**
+ * Announces the end of the test. Includes private clean up.
+ * @param string $method Test method just finished.
+ * @access public
+ */
+ function after($method) {
+ $this->unsetBrowser();
+ parent::after($method);
+ }
+
+ /**
+ * Gets a current browser reference for setting
+ * special expectations or for detailed
+ * examination of page fetches.
+ * @return SimpleBrowser Current test browser object.
+ * @access public
+ */
+ function getBrowser() {
+ return $this->browser;
+ }
+
+ /**
+ * Gets a current browser reference for setting
+ * special expectations or for detailed
+ * examination of page fetches.
+ * @param SimpleBrowser $browser New test browser object.
+ * @access public
+ */
+ function setBrowser($browser) {
+ return $this->browser = $browser;
+ }
+
+ /**
+ * Sets the HTML parser to use within this browser.
+ * @param object The parser, one of SimplePHPPageBuilder or
+ * SimpleTidyPageBuilder.
+ */
+ function setParser($parser) {
+ $this->browser->setParser($parser);
+ }
+
+ /**
+ * Clears the current browser reference to help the
+ * PHP garbage collector.
+ * @access public
+ */
+ function unsetBrowser() {
+ unset($this->browser);
+ }
+
+ /**
+ * Creates a new default web browser object.
+ * Will be cleared at the end of the test method.
+ * @return TestBrowser New browser.
+ * @access public
+ */
+ function createBrowser() {
+ return new SimpleBrowser();
+ }
+
+ /**
+ * Gets the last response error.
+ * @return string Last low level HTTP error.
+ * @access public
+ */
+ function getTransportError() {
+ return $this->browser->getTransportError();
+ }
+
+ /**
+ * Accessor for the currently selected URL.
+ * @return string Current location or false if
+ * no page yet fetched.
+ * @access public
+ */
+ function getUrl() {
+ return $this->browser->getUrl();
+ }
+
+ /**
+ * Dumps the current request for debugging.
+ * @access public
+ */
+ function showRequest() {
+ $this->dump($this->browser->getRequest());
+ }
+
+ /**
+ * Dumps the current HTTP headers for debugging.
+ * @access public
+ */
+ function showHeaders() {
+ $this->dump($this->browser->getHeaders());
+ }
+
+ /**
+ * Dumps the current HTML source for debugging.
+ * @access public
+ */
+ function showSource() {
+ $this->dump($this->browser->getContent());
+ }
+
+ /**
+ * Dumps the visible text only for debugging.
+ * @access public
+ */
+ function showText() {
+ $this->dump(wordwrap($this->browser->getContentAsText(), 80));
+ }
+
+ /**
+ * Simulates the closing and reopening of the browser.
+ * Temporary cookies will be discarded and timed
+ * cookies will be expired if later than the
+ * specified time.
+ * @param string/integer $date Time when session restarted.
+ * If ommitted then all persistent
+ * cookies are kept. Time is either
+ * Cookie format string or timestamp.
+ * @access public
+ */
+ function restart($date = false) {
+ if ($date === false) {
+ $date = time();
+ }
+ $this->browser->restart($date);
+ }
+
+ /**
+ * Moves cookie expiry times back into the past.
+ * Useful for testing timeouts and expiries.
+ * @param integer $interval Amount to age in seconds.
+ * @access public
+ */
+ function ageCookies($interval) {
+ $this->browser->ageCookies($interval);
+ }
+
+ /**
+ * Disables frames support. Frames will not be fetched
+ * and the frameset page will be used instead.
+ * @access public
+ */
+ function ignoreFrames() {
+ $this->browser->ignoreFrames();
+ }
+
+ /**
+ * Switches off cookie sending and recieving.
+ * @access public
+ */
+ function ignoreCookies() {
+ $this->browser->ignoreCookies();
+ }
+
+ /**
+ * Skips errors for the next request only. You might
+ * want to confirm that a page is unreachable for
+ * example.
+ * @access public
+ */
+ function ignoreErrors() {
+ $this->ignore_errors = true;
+ }
+
+ /**
+ * Issues a fail if there is a transport error anywhere
+ * in the current frameset. Only one such error is
+ * reported.
+ * @param string/boolean $result HTML or failure.
+ * @return string/boolean $result Passes through result.
+ * @access private
+ */
+ protected function failOnError($result) {
+ if (! $this->ignore_errors) {
+ if ($error = $this->browser->getTransportError()) {
+ $this->fail($error);
+ }
+ }
+ $this->ignore_errors = false;
+ return $result;
+ }
+
+ /**
+ * Adds a header to every fetch.
+ * @param string $header Header line to add to every
+ * request until cleared.
+ * @access public
+ */
+ function addHeader($header) {
+ $this->browser->addHeader($header);
+ }
+
+ /**
+ * Sets the maximum number of redirects before
+ * the web page is loaded regardless.
+ * @param integer $max Maximum hops.
+ * @access public
+ */
+ function setMaximumRedirects($max) {
+ if (! $this->browser) {
+ trigger_error(
+ 'Can only set maximum redirects in a test method, setUp() or tearDown()');
+ }
+ $this->browser->setMaximumRedirects($max);
+ }
+
+ /**
+ * Sets the socket timeout for opening a connection and
+ * receiving at least one byte of information.
+ * @param integer $timeout Maximum time in seconds.
+ * @access public
+ */
+ function setConnectionTimeout($timeout) {
+ $this->browser->setConnectionTimeout($timeout);
+ }
+
+ /**
+ * Sets proxy to use on all requests for when
+ * testing from behind a firewall. Set URL
+ * to false to disable.
+ * @param string $proxy Proxy URL.
+ * @param string $username Proxy username for authentication.
+ * @param string $password Proxy password for authentication.
+ * @access public
+ */
+ function useProxy($proxy, $username = false, $password = false) {
+ $this->browser->useProxy($proxy, $username, $password);
+ }
+
+ /**
+ * Fetches a page into the page buffer. If
+ * there is no base for the URL then the
+ * current base URL is used. After the fetch
+ * the base URL reflects the new location.
+ * @param string $url URL to fetch.
+ * @param hash $parameters Optional additional GET data.
+ * @return boolean/string Raw page on success.
+ * @access public
+ */
+ function get($url, $parameters = false) {
+ return $this->failOnError($this->browser->get($url, $parameters));
+ }
+
+ /**
+ * Fetches a page by POST into the page buffer.
+ * If there is no base for the URL then the
+ * current base URL is used. After the fetch
+ * the base URL reflects the new location.
+ * @param string $url URL to fetch.
+ * @param mixed $parameters Optional POST parameters or content body to send
+ * @param string $content_type Content type of provided body
+ * @return boolean/string Raw page on success.
+ * @access public
+ */
+ function post($url, $parameters = false, $content_type = false) {
+ return $this->failOnError($this->browser->post($url, $parameters, $content_type));
+ }
+
+ /**
+ * Fetches a page by PUT into the page buffer.
+ * If there is no base for the URL then the
+ * current base URL is used. After the fetch
+ * the base URL reflects the new location.
+ * @param string $url URL to fetch.
+ * @param mixed $body Optional content body to send
+ * @param string $content_type Content type of provided body
+ * @return boolean/string Raw page on success.
+ * @access public
+ */
+ function put($url, $body = false, $content_type = false) {
+ return $this->failOnError($this->browser->put($url, $body, $content_type));
+ }
+
+ /**
+ * Fetches a page by a DELETE request
+ * @param string $url URL to fetch.
+ * @param hash $parameters Optional additional parameters.
+ * @return boolean/string Raw page on success.
+ * @access public
+ */
+ function delete($url, $parameters = false) {
+ return $this->failOnError($this->browser->delete($url, $parameters));
+ }
+
+
+ /**
+ * Does a HTTP HEAD fetch, fetching only the page
+ * headers. The current base URL is unchanged by this.
+ * @param string $url URL to fetch.
+ * @param hash $parameters Optional additional GET data.
+ * @return boolean True on success.
+ * @access public
+ */
+ function head($url, $parameters = false) {
+ return $this->failOnError($this->browser->head($url, $parameters));
+ }
+
+ /**
+ * Equivalent to hitting the retry button on the
+ * browser. Will attempt to repeat the page fetch.
+ * @return boolean True if fetch succeeded.
+ * @access public
+ */
+ function retry() {
+ return $this->failOnError($this->browser->retry());
+ }
+
+ /**
+ * Equivalent to hitting the back button on the
+ * browser.
+ * @return boolean True if history entry and
+ * fetch succeeded.
+ * @access public
+ */
+ function back() {
+ return $this->failOnError($this->browser->back());
+ }
+
+ /**
+ * Equivalent to hitting the forward button on the
+ * browser.
+ * @return boolean True if history entry and
+ * fetch succeeded.
+ * @access public
+ */
+ function forward() {
+ return $this->failOnError($this->browser->forward());
+ }
+
+ /**
+ * Retries a request after setting the authentication
+ * for the current realm.
+ * @param string $username Username for realm.
+ * @param string $password Password for realm.
+ * @return boolean/string HTML on successful fetch. Note
+ * that authentication may still have
+ * failed.
+ * @access public
+ */
+ function authenticate($username, $password) {
+ return $this->failOnError(
+ $this->browser->authenticate($username, $password));
+ }
+
+ /**
+ * Gets the cookie value for the current browser context.
+ * @param string $name Name of cookie.
+ * @return string Value of cookie or false if unset.
+ * @access public
+ */
+ function getCookie($name) {
+ return $this->browser->getCurrentCookieValue($name);
+ }
+
+ /**
+ * Sets a cookie in the current browser.
+ * @param string $name Name of cookie.
+ * @param string $value Cookie value.
+ * @param string $host Host upon which the cookie is valid.
+ * @param string $path Cookie path if not host wide.
+ * @param string $expiry Expiry date.
+ * @access public
+ */
+ function setCookie($name, $value, $host = false, $path = '/', $expiry = false) {
+ $this->browser->setCookie($name, $value, $host, $path, $expiry);
+ }
+
+ /**
+ * Accessor for current frame focus. Will be
+ * false if no frame has focus.
+ * @return integer/string/boolean Label if any, otherwise
+ * the position in the frameset
+ * or false if none.
+ * @access public
+ */
+ function getFrameFocus() {
+ return $this->browser->getFrameFocus();
+ }
+
+ /**
+ * Sets the focus by index. The integer index starts from 1.
+ * @param integer $choice Chosen frame.
+ * @return boolean True if frame exists.
+ * @access public
+ */
+ function setFrameFocusByIndex($choice) {
+ return $this->browser->setFrameFocusByIndex($choice);
+ }
+
+ /**
+ * Sets the focus by name.
+ * @param string $name Chosen frame.
+ * @return boolean True if frame exists.
+ * @access public
+ */
+ function setFrameFocus($name) {
+ return $this->browser->setFrameFocus($name);
+ }
+
+ /**
+ * Clears the frame focus. All frames will be searched
+ * for content.
+ * @access public
+ */
+ function clearFrameFocus() {
+ return $this->browser->clearFrameFocus();
+ }
+
+ /**
+ * Clicks a visible text item. Will first try buttons,
+ * then links and then images.
+ * @param string $label Visible text or alt text.
+ * @return string/boolean Raw page or false.
+ * @access public
+ */
+ function click($label) {
+ return $this->failOnError($this->browser->click($label));
+ }
+
+ /**
+ * Checks for a click target.
+ * @param string $label Visible text or alt text.
+ * @return boolean True if click target.
+ * @access public
+ */
+ function assertClickable($label, $message = '%s') {
+ return $this->assertTrue(
+ $this->browser->isClickable($label),
+ sprintf($message, "Click target [$label] should exist"));
+ }
+
+ /**
+ * Clicks the submit button by label. The owning
+ * form will be submitted by this.
+ * @param string $label Button label. An unlabeled
+ * button can be triggered by 'Submit'.
+ * @param hash $additional Additional form values.
+ * @return boolean/string Page on success, else false.
+ * @access public
+ */
+ function clickSubmit($label = 'Submit', $additional = false) {
+ return $this->failOnError(
+ $this->browser->clickSubmit($label, $additional));
+ }
+
+ /**
+ * Clicks the submit button by name attribute. The owning
+ * form will be submitted by this.
+ * @param string $name Name attribute of button.
+ * @param hash $additional Additional form values.
+ * @return boolean/string Page on success.
+ * @access public
+ */
+ function clickSubmitByName($name, $additional = false) {
+ return $this->failOnError(
+ $this->browser->clickSubmitByName($name, $additional));
+ }
+
+ /**
+ * Clicks the submit button by ID attribute. The owning
+ * form will be submitted by this.
+ * @param string $id ID attribute of button.
+ * @param hash $additional Additional form values.
+ * @return boolean/string Page on success.
+ * @access public
+ */
+ function clickSubmitById($id, $additional = false) {
+ return $this->failOnError(
+ $this->browser->clickSubmitById($id, $additional));
+ }
+
+ /**
+ * Checks for a valid button label.
+ * @param string $label Visible text.
+ * @return boolean True if click target.
+ * @access public
+ */
+ function assertSubmit($label, $message = '%s') {
+ return $this->assertTrue(
+ $this->browser->isSubmit($label),
+ sprintf($message, "Submit button [$label] should exist"));
+ }
+
+ /**
+ * Clicks the submit image by some kind of label. Usually
+ * the alt tag or the nearest equivalent. The owning
+ * form will be submitted by this. Clicking outside of
+ * the boundary of the coordinates will result in
+ * a failure.
+ * @param string $label Alt attribute of button.
+ * @param integer $x X-coordinate of imaginary click.
+ * @param integer $y Y-coordinate of imaginary click.
+ * @param hash $additional Additional form values.
+ * @return boolean/string Page on success.
+ * @access public
+ */
+ function clickImage($label, $x = 1, $y = 1, $additional = false) {
+ return $this->failOnError(
+ $this->browser->clickImage($label, $x, $y, $additional));
+ }
+
+ /**
+ * Clicks the submit image by the name. Usually
+ * the alt tag or the nearest equivalent. The owning
+ * form will be submitted by this. Clicking outside of
+ * the boundary of the coordinates will result in
+ * a failure.
+ * @param string $name Name attribute of button.
+ * @param integer $x X-coordinate of imaginary click.
+ * @param integer $y Y-coordinate of imaginary click.
+ * @param hash $additional Additional form values.
+ * @return boolean/string Page on success.
+ * @access public
+ */
+ function clickImageByName($name, $x = 1, $y = 1, $additional = false) {
+ return $this->failOnError(
+ $this->browser->clickImageByName($name, $x, $y, $additional));
+ }
+
+ /**
+ * Clicks the submit image by ID attribute. The owning
+ * form will be submitted by this. Clicking outside of
+ * the boundary of the coordinates will result in
+ * a failure.
+ * @param integer/string $id ID attribute of button.
+ * @param integer $x X-coordinate of imaginary click.
+ * @param integer $y Y-coordinate of imaginary click.
+ * @param hash $additional Additional form values.
+ * @return boolean/string Page on success.
+ * @access public
+ */
+ function clickImageById($id, $x = 1, $y = 1, $additional = false) {
+ return $this->failOnError(
+ $this->browser->clickImageById($id, $x, $y, $additional));
+ }
+
+ /**
+ * Checks for a valid image with atht alt text or title.
+ * @param string $label Visible text.
+ * @return boolean True if click target.
+ * @access public
+ */
+ function assertImage($label, $message = '%s') {
+ return $this->assertTrue(
+ $this->browser->isImage($label),
+ sprintf($message, "Image with text [$label] should exist"));
+ }
+
+ /**
+ * Submits a form by the ID.
+ * @param string $id Form ID. No button information
+ * is submitted this way.
+ * @return boolean/string Page on success.
+ * @access public
+ */
+ function submitFormById($id, $additional = false) {
+ return $this->failOnError($this->browser->submitFormById($id, $additional));
+ }
+
+ /**
+ * Follows a link by name. Will click the first link
+ * found with this link text by default, or a later
+ * one if an index is given. Match is case insensitive
+ * with normalised space.
+ * @param string $label Text between the anchor tags.
+ * @param integer $index Link position counting from zero.
+ * @return boolean/string Page on success.
+ * @access public
+ */
+ function clickLink($label, $index = 0) {
+ return $this->failOnError($this->browser->clickLink($label, $index));
+ }
+
+ /**
+ * Follows a link by id attribute.
+ * @param string $id ID attribute value.
+ * @return boolean/string Page on success.
+ * @access public
+ */
+ function clickLinkById($id) {
+ return $this->failOnError($this->browser->clickLinkById($id));
+ }
+
+ /**
+ * Tests for the presence of a link label. Match is
+ * case insensitive with normalised space.
+ * @param string $label Text between the anchor tags.
+ * @param mixed $expected Expected URL or expectation object.
+ * @param string $message Message to display. Default
+ * can be embedded with %s.
+ * @return boolean True if link present.
+ * @access public
+ */
+ function assertLink($label, $expected = true, $message = '%s') {
+ $url = $this->browser->getLink($label);
+ if ($expected === true || ($expected !== true && $url === false)) {
+ return $this->assertTrue($url !== false, sprintf($message, "Link [$label] should exist"));
+ }
+ if (! SimpleExpectation::isExpectation($expected)) {
+ $expected = new IdenticalExpectation($expected);
+ }
+ return $this->assert($expected, $url->asString(), sprintf($message, "Link [$label] should match"));
+ }
+
+ /**
+ * Tests for the non-presence of a link label. Match is
+ * case insensitive with normalised space.
+ * @param string/integer $label Text between the anchor tags
+ * or ID attribute.
+ * @param string $message Message to display. Default
+ * can be embedded with %s.
+ * @return boolean True if link missing.
+ * @access public
+ */
+ function assertNoLink($label, $message = '%s') {
+ return $this->assertTrue(
+ $this->browser->getLink($label) === false,
+ sprintf($message, "Link [$label] should not exist"));
+ }
+
+ /**
+ * Tests for the presence of a link id attribute.
+ * @param string $id Id attribute value.
+ * @param mixed $expected Expected URL or expectation object.
+ * @param string $message Message to display. Default
+ * can be embedded with %s.
+ * @return boolean True if link present.
+ * @access public
+ */
+ function assertLinkById($id, $expected = true, $message = '%s') {
+ $url = $this->browser->getLinkById($id);
+ if ($expected === true) {
+ return $this->assertTrue($url !== false, sprintf($message, "Link ID [$id] should exist"));
+ }
+ if (! SimpleExpectation::isExpectation($expected)) {
+ $expected = new IdenticalExpectation($expected);
+ }
+ return $this->assert($expected, $url->asString(), sprintf($message, "Link ID [$id] should match"));
+ }
+
+ /**
+ * Tests for the non-presence of a link label. Match is
+ * case insensitive with normalised space.
+ * @param string $id Id attribute value.
+ * @param string $message Message to display. Default
+ * can be embedded with %s.
+ * @return boolean True if link missing.
+ * @access public
+ */
+ function assertNoLinkById($id, $message = '%s') {
+ return $this->assertTrue(
+ $this->browser->getLinkById($id) === false,
+ sprintf($message, "Link ID [$id] should not exist"));
+ }
+
+ /**
+ * Sets all form fields with that label, or name if there
+ * is no label attached.
+ * @param string $name Name of field in forms.
+ * @param string $value New value of field.
+ * @return boolean True if field exists, otherwise false.
+ * @access public
+ */
+ function setField($label, $value, $position=false) {
+ return $this->browser->setField($label, $value, $position);
+ }
+
+ /**
+ * Sets all form fields with that name.
+ * @param string $name Name of field in forms.
+ * @param string $value New value of field.
+ * @return boolean True if field exists, otherwise false.
+ * @access public
+ */
+ function setFieldByName($name, $value, $position=false) {
+ return $this->browser->setFieldByName($name, $value, $position);
+ }
+
+ /**
+ * Sets all form fields with that id.
+ * @param string/integer $id Id of field in forms.
+ * @param string $value New value of field.
+ * @return boolean True if field exists, otherwise false.
+ * @access public
+ */
+ function setFieldById($id, $value) {
+ return $this->browser->setFieldById($id, $value);
+ }
+
+ /**
+ * Confirms that the form element is currently set
+ * to the expected value. A missing form will always
+ * fail. If no value is given then only the existence
+ * of the field is checked.
+ * @param string $name Name of field in forms.
+ * @param mixed $expected Expected string/array value or
+ * false for unset fields.
+ * @param string $message Message to display. Default
+ * can be embedded with %s.
+ * @return boolean True if pass.
+ * @access public
+ */
+ function assertField($label, $expected = true, $message = '%s') {
+ $value = $this->browser->getField($label);
+ return $this->assertFieldValue($label, $value, $expected, $message);
+ }
+
+ /**
+ * Confirms that the form element is currently set
+ * to the expected value. A missing form element will always
+ * fail. If no value is given then only the existence
+ * of the field is checked.
+ * @param string $name Name of field in forms.
+ * @param mixed $expected Expected string/array value or
+ * false for unset fields.
+ * @param string $message Message to display. Default
+ * can be embedded with %s.
+ * @return boolean True if pass.
+ * @access public
+ */
+ function assertFieldByName($name, $expected = true, $message = '%s') {
+ $value = $this->browser->getFieldByName($name);
+ return $this->assertFieldValue($name, $value, $expected, $message);
+ }
+
+ /**
+ * Confirms that the form element is currently set
+ * to the expected value. A missing form will always
+ * fail. If no ID is given then only the existence
+ * of the field is checked.
+ * @param string/integer $id Name of field in forms.
+ * @param mixed $expected Expected string/array value or
+ * false for unset fields.
+ * @param string $message Message to display. Default
+ * can be embedded with %s.
+ * @return boolean True if pass.
+ * @access public
+ */
+ function assertFieldById($id, $expected = true, $message = '%s') {
+ $value = $this->browser->getFieldById($id);
+ return $this->assertFieldValue($id, $value, $expected, $message);
+ }
+
+ /**
+ * Tests the field value against the expectation.
+ * @param string $identifier Name, ID or label.
+ * @param mixed $value Current field value.
+ * @param mixed $expected Expected value to match.
+ * @param string $message Failure message.
+ * @return boolean True if pass
+ * @access protected
+ */
+ protected function assertFieldValue($identifier, $value, $expected, $message) {
+ if ($expected === true) {
+ return $this->assertTrue(
+ isset($value),
+ sprintf($message, "Field [$identifier] should exist"));
+ }
+ if (! SimpleExpectation::isExpectation($expected)) {
+ $identifier = str_replace('%', '%%', $identifier);
+ $expected = new FieldExpectation(
+ $expected,
+ "Field [$identifier] should match with [%s]");
+ }
+ return $this->assert($expected, $value, $message);
+ }
+
+ /**
+ * Checks the response code against a list
+ * of possible values.
+ * @param array $responses Possible responses for a pass.
+ * @param string $message Message to display. Default
+ * can be embedded with %s.
+ * @return boolean True if pass.
+ * @access public
+ */
+ function assertResponse($responses, $message = '%s') {
+ $responses = (is_array($responses) ? $responses : array($responses));
+ $code = $this->browser->getResponseCode();
+ $message = sprintf($message, "Expecting response in [" .
+ implode(", ", $responses) . "] got [$code]");
+ return $this->assertTrue(in_array($code, $responses), $message);
+ }
+
+ /**
+ * Checks the mime type against a list
+ * of possible values.
+ * @param array $types Possible mime types for a pass.
+ * @param string $message Message to display.
+ * @return boolean True if pass.
+ * @access public
+ */
+ function assertMime($types, $message = '%s') {
+ $types = (is_array($types) ? $types : array($types));
+ $type = $this->browser->getMimeType();
+ $message = sprintf($message, "Expecting mime type in [" .
+ implode(", ", $types) . "] got [$type]");
+ return $this->assertTrue(in_array($type, $types), $message);
+ }
+
+ /**
+ * Attempt to match the authentication type within
+ * the security realm we are currently matching.
+ * @param string $authentication Usually basic.
+ * @param string $message Message to display.
+ * @return boolean True if pass.
+ * @access public
+ */
+ function assertAuthentication($authentication = false, $message = '%s') {
+ if (! $authentication) {
+ $message = sprintf($message, "Expected any authentication type, got [" .
+ $this->browser->getAuthentication() . "]");
+ return $this->assertTrue(
+ $this->browser->getAuthentication(),
+ $message);
+ } else {
+ $message = sprintf($message, "Expected authentication [$authentication] got [" .
+ $this->browser->getAuthentication() . "]");
+ return $this->assertTrue(
+ strtolower($this->browser->getAuthentication()) == strtolower($authentication),
+ $message);
+ }
+ }
+
+ /**
+ * Checks that no authentication is necessary to view
+ * the desired page.
+ * @param string $message Message to display.
+ * @return boolean True if pass.
+ * @access public
+ */
+ function assertNoAuthentication($message = '%s') {
+ $message = sprintf($message, "Expected no authentication type, got [" .
+ $this->browser->getAuthentication() . "]");
+ return $this->assertFalse($this->browser->getAuthentication(), $message);
+ }
+
+ /**
+ * Attempts to match the current security realm.
+ * @param string $realm Name of security realm.
+ * @param string $message Message to display.
+ * @return boolean True if pass.
+ * @access public
+ */
+ function assertRealm($realm, $message = '%s') {
+ if (! SimpleExpectation::isExpectation($realm)) {
+ $realm = new EqualExpectation($realm);
+ }
+ return $this->assert(
+ $realm,
+ $this->browser->getRealm(),
+ "Expected realm -> $message");
+ }
+
+ /**
+ * Checks each header line for the required value. If no
+ * value is given then only an existence check is made.
+ * @param string $header Case insensitive header name.
+ * @param mixed $value Case sensitive trimmed string to
+ * match against. An expectation object
+ * can be used for pattern matching.
+ * @return boolean True if pass.
+ * @access public
+ */
+ function assertHeader($header, $value = false, $message = '%s') {
+ return $this->assert(
+ new HttpHeaderExpectation($header, $value),
+ $this->browser->getHeaders(),
+ $message);
+ }
+
+ /**
+ * Confirms that the header type has not been received.
+ * Only the landing page is checked. If you want to check
+ * redirect pages, then you should limit redirects so
+ * as to capture the page you want.
+ * @param string $header Case insensitive header name.
+ * @return boolean True if pass.
+ * @access public
+ */
+ function assertNoHeader($header, $message = '%s') {
+ return $this->assert(
+ new NoHttpHeaderExpectation($header),
+ $this->browser->getHeaders(),
+ $message);
+ }
+
+ /**
+ * Tests the text between the title tags.
+ * @param string/SimpleExpectation $title Expected title.
+ * @param string $message Message to display.
+ * @return boolean True if pass.
+ * @access public
+ */
+ function assertTitle($title = false, $message = '%s') {
+ if (! SimpleExpectation::isExpectation($title)) {
+ $title = new EqualExpectation($title);
+ }
+ return $this->assert($title, $this->browser->getTitle(), $message);
+ }
+
+ /**
+ * Will trigger a pass if the text is found in the plain
+ * text form of the page.
+ * @param string $text Text to look for.
+ * @param string $message Message to display.
+ * @return boolean True if pass.
+ * @access public
+ */
+ function assertText($text, $message = '%s') {
+ return $this->assert(
+ new TextExpectation($text),
+ $this->browser->getContentAsText(),
+ $message);
+ }
+
+ /**
+ * Will trigger a pass if the text is not found in the plain
+ * text form of the page.
+ * @param string $text Text to look for.
+ * @param string $message Message to display.
+ * @return boolean True if pass.
+ * @access public
+ */
+ function assertNoText($text, $message = '%s') {
+ return $this->assert(
+ new NoTextExpectation($text),
+ $this->browser->getContentAsText(),
+ $message);
+ }
+
+ /**
+ * Will trigger a pass if the Perl regex pattern
+ * is found in the raw content.
+ * @param string $pattern Perl regex to look for including
+ * the regex delimiters.
+ * @param string $message Message to display.
+ * @return boolean True if pass.
+ * @access public
+ */
+ function assertPattern($pattern, $message = '%s') {
+ return $this->assert(
+ new PatternExpectation($pattern),
+ $this->browser->getContent(),
+ $message);
+ }
+
+ /**
+ * Will trigger a pass if the perl regex pattern
+ * is not present in raw content.
+ * @param string $pattern Perl regex to look for including
+ * the regex delimiters.
+ * @param string $message Message to display.
+ * @return boolean True if pass.
+ * @access public
+ */
+ function assertNoPattern($pattern, $message = '%s') {
+ return $this->assert(
+ new NoPatternExpectation($pattern),
+ $this->browser->getContent(),
+ $message);
+ }
+
+ /**
+ * Checks that a cookie is set for the current page
+ * and optionally checks the value.
+ * @param string $name Name of cookie to test.
+ * @param string $expected Expected value as a string or
+ * false if any value will do.
+ * @param string $message Message to display.
+ * @return boolean True if pass.
+ * @access public
+ */
+ function assertCookie($name, $expected = false, $message = '%s') {
+ $value = $this->getCookie($name);
+ if (! $expected) {
+ return $this->assertTrue(
+ $value,
+ sprintf($message, "Expecting cookie [$name]"));
+ }
+ if (! SimpleExpectation::isExpectation($expected)) {
+ $expected = new EqualExpectation($expected);
+ }
+ return $this->assert($expected, $value, "Expecting cookie [$name] -> $message");
+ }
+
+ /**
+ * Checks that no cookie is present or that it has
+ * been successfully cleared.
+ * @param string $name Name of cookie to test.
+ * @param string $message Message to display.
+ * @return boolean True if pass.
+ * @access public
+ */
+ function assertNoCookie($name, $message = '%s') {
+ return $this->assertTrue(
+ $this->getCookie($name) === null or $this->getCookie($name) === false,
+ sprintf($message, "Not expecting cookie [$name]"));
+ }
+
+ /**
+ * Called from within the test methods to register
+ * passes and failures.
+ * @param boolean $result Pass on true.
+ * @param string $message Message to display describing
+ * the test state.
+ * @return boolean True on pass
+ * @access public
+ */
+ function assertTrue($result, $message = '%s') {
+ return $this->assert(new TrueExpectation(), $result, $message);
+ }
+
+ /**
+ * Will be true on false and vice versa. False
+ * is the PHP definition of false, so that null,
+ * empty strings, zero and an empty array all count
+ * as false.
+ * @param boolean $result Pass on false.
+ * @param string $message Message to display.
+ * @return boolean True on pass
+ * @access public
+ */
+ function assertFalse($result, $message = '%s') {
+ return $this->assert(new FalseExpectation(), $result, $message);
+ }
+
+ /**
+ * Will trigger a pass if the two parameters have
+ * the same value only. Otherwise a fail. This
+ * is for testing hand extracted text, etc.
+ * @param mixed $first Value to compare.
+ * @param mixed $second Value to compare.
+ * @param string $message Message to display.
+ * @return boolean True on pass
+ * @access public
+ */
+ function assertEqual($first, $second, $message = '%s') {
+ return $this->assert(
+ new EqualExpectation($first),
+ $second,
+ $message);
+ }
+
+ /**
+ * Will trigger a pass if the two parameters have
+ * a different value. Otherwise a fail. This
+ * is for testing hand extracted text, etc.
+ * @param mixed $first Value to compare.
+ * @param mixed $second Value to compare.
+ * @param string $message Message to display.
+ * @return boolean True on pass
+ * @access public
+ */
+ function assertNotEqual($first, $second, $message = '%s') {
+ return $this->assert(
+ new NotEqualExpectation($first),
+ $second,
+ $message);
+ }
+
+ /**
+ * Uses a stack trace to find the line of an assertion.
+ * @return string Line number of first assert*
+ * method embedded in format string.
+ * @access public
+ */
+ function getAssertionLine() {
+ $trace = new SimpleStackTrace(array('assert', 'click', 'pass', 'fail'));
+ return $trace->traceMethod();
+ }
+}
+?>
\ No newline at end of file
diff --git a/code/ryzom/tools/server/www/webtt/vendors/simpletest/xml.php b/code/ryzom/tools/server/www/webtt/vendors/simpletest/xml.php
new file mode 100644
index 000000000..54fb6f5b1
--- /dev/null
+++ b/code/ryzom/tools/server/www/webtt/vendors/simpletest/xml.php
@@ -0,0 +1,647 @@
+namespace = ($namespace ? $namespace . ':' : '');
+ $this->indent = $indent;
+ }
+
+ /**
+ * Calculates the pretty printing indent level
+ * from the current level of nesting.
+ * @param integer $offset Extra indenting level.
+ * @return string Leading space.
+ * @access protected
+ */
+ protected function getIndent($offset = 0) {
+ return str_repeat(
+ $this->indent,
+ count($this->getTestList()) + $offset);
+ }
+
+ /**
+ * Converts character string to parsed XML
+ * entities string.
+ * @param string text Unparsed character data.
+ * @return string Parsed character data.
+ * @access public
+ */
+ function toParsedXml($text) {
+ return str_replace(
+ array('&', '<', '>', '"', '\''),
+ array('&', '<', '>', '"', '''),
+ $text);
+ }
+
+ /**
+ * Paints the start of a group test.
+ * @param string $test_name Name of test that is starting.
+ * @param integer $size Number of test cases starting.
+ * @access public
+ */
+ function paintGroupStart($test_name, $size) {
+ parent::paintGroupStart($test_name, $size);
+ print $this->getIndent();
+ print "<" . $this->namespace . "group size=\"$size\">\n";
+ print $this->getIndent(1);
+ print "<" . $this->namespace . "name>" .
+ $this->toParsedXml($test_name) .
+ "" . $this->namespace . "name>\n";
+ }
+
+ /**
+ * Paints the end of a group test.
+ * @param string $test_name Name of test that is ending.
+ * @access public
+ */
+ function paintGroupEnd($test_name) {
+ print $this->getIndent();
+ print "" . $this->namespace . "group>\n";
+ parent::paintGroupEnd($test_name);
+ }
+
+ /**
+ * Paints the start of a test case.
+ * @param string $test_name Name of test that is starting.
+ * @access public
+ */
+ function paintCaseStart($test_name) {
+ parent::paintCaseStart($test_name);
+ print $this->getIndent();
+ print "<" . $this->namespace . "case>\n";
+ print $this->getIndent(1);
+ print "<" . $this->namespace . "name>" .
+ $this->toParsedXml($test_name) .
+ "" . $this->namespace . "name>\n";
+ }
+
+ /**
+ * Paints the end of a test case.
+ * @param string $test_name Name of test that is ending.
+ * @access public
+ */
+ function paintCaseEnd($test_name) {
+ print $this->getIndent();
+ print "" . $this->namespace . "case>\n";
+ parent::paintCaseEnd($test_name);
+ }
+
+ /**
+ * Paints the start of a test method.
+ * @param string $test_name Name of test that is starting.
+ * @access public
+ */
+ function paintMethodStart($test_name) {
+ parent::paintMethodStart($test_name);
+ print $this->getIndent();
+ print "<" . $this->namespace . "test>\n";
+ print $this->getIndent(1);
+ print "<" . $this->namespace . "name>" .
+ $this->toParsedXml($test_name) .
+ "" . $this->namespace . "name>\n";
+ }
+
+ /**
+ * Paints the end of a test method.
+ * @param string $test_name Name of test that is ending.
+ * @param integer $progress Number of test cases ending.
+ * @access public
+ */
+ function paintMethodEnd($test_name) {
+ print $this->getIndent();
+ print "" . $this->namespace . "test>\n";
+ parent::paintMethodEnd($test_name);
+ }
+
+ /**
+ * Paints pass as XML.
+ * @param string $message Message to encode.
+ * @access public
+ */
+ function paintPass($message) {
+ parent::paintPass($message);
+ print $this->getIndent(1);
+ print "<" . $this->namespace . "pass>";
+ print $this->toParsedXml($message);
+ print "" . $this->namespace . "pass>\n";
+ }
+
+ /**
+ * Paints failure as XML.
+ * @param string $message Message to encode.
+ * @access public
+ */
+ function paintFail($message) {
+ parent::paintFail($message);
+ print $this->getIndent(1);
+ print "<" . $this->namespace . "fail>";
+ print $this->toParsedXml($message);
+ print "" . $this->namespace . "fail>\n";
+ }
+
+ /**
+ * Paints error as XML.
+ * @param string $message Message to encode.
+ * @access public
+ */
+ function paintError($message) {
+ parent::paintError($message);
+ print $this->getIndent(1);
+ print "<" . $this->namespace . "exception>";
+ print $this->toParsedXml($message);
+ print "" . $this->namespace . "exception>\n";
+ }
+
+ /**
+ * Paints exception as XML.
+ * @param Exception $exception Exception to encode.
+ * @access public
+ */
+ function paintException($exception) {
+ parent::paintException($exception);
+ print $this->getIndent(1);
+ print "<" . $this->namespace . "exception>";
+ $message = 'Unexpected exception of type [' . get_class($exception) .
+ '] with message ['. $exception->getMessage() .
+ '] in ['. $exception->getFile() .
+ ' line ' . $exception->getLine() . ']';
+ print $this->toParsedXml($message);
+ print "" . $this->namespace . "exception>\n";
+ }
+
+ /**
+ * Paints the skipping message and tag.
+ * @param string $message Text to display in skip tag.
+ * @access public
+ */
+ function paintSkip($message) {
+ parent::paintSkip($message);
+ print $this->getIndent(1);
+ print "<" . $this->namespace . "skip>";
+ print $this->toParsedXml($message);
+ print "" . $this->namespace . "skip>\n";
+ }
+
+ /**
+ * Paints a simple supplementary message.
+ * @param string $message Text to display.
+ * @access public
+ */
+ function paintMessage($message) {
+ parent::paintMessage($message);
+ print $this->getIndent(1);
+ print "<" . $this->namespace . "message>";
+ print $this->toParsedXml($message);
+ print "" . $this->namespace . "message>\n";
+ }
+
+ /**
+ * Paints a formatted ASCII message such as a
+ * privateiable dump.
+ * @param string $message Text to display.
+ * @access public
+ */
+ function paintFormattedMessage($message) {
+ parent::paintFormattedMessage($message);
+ print $this->getIndent(1);
+ print "<" . $this->namespace . "formatted>";
+ print "";
+ print "" . $this->namespace . "formatted>\n";
+ }
+
+ /**
+ * Serialises the event object.
+ * @param string $type Event type as text.
+ * @param mixed $payload Message or object.
+ * @access public
+ */
+ function paintSignal($type, $payload) {
+ parent::paintSignal($type, $payload);
+ print $this->getIndent(1);
+ print "<" . $this->namespace . "signal type=\"$type\">";
+ print "";
+ print "" . $this->namespace . "signal>\n";
+ }
+
+ /**
+ * Paints the test document header.
+ * @param string $test_name First test top level
+ * to start.
+ * @access public
+ * @abstract
+ */
+ function paintHeader($test_name) {
+ if (! SimpleReporter::inCli()) {
+ header('Content-type: text/xml');
+ }
+ print "namespace) {
+ print " xmlns:" . $this->namespace .
+ "=\"www.lastcraft.com/SimpleTest/Beta3/Report\"";
+ }
+ print "?>\n";
+ print "<" . $this->namespace . "run>\n";
+ }
+
+ /**
+ * Paints the test document footer.
+ * @param string $test_name The top level test.
+ * @access public
+ * @abstract
+ */
+ function paintFooter($test_name) {
+ print "" . $this->namespace . "run>\n";
+ }
+}
+
+/**
+ * Accumulator for incoming tag. Holds the
+ * incoming test structure information for
+ * later dispatch to the reporter.
+ * @package SimpleTest
+ * @subpackage UnitTester
+ */
+class NestingXmlTag {
+ private $name;
+ private $attributes;
+
+ /**
+ * Sets the basic test information except
+ * the name.
+ * @param hash $attributes Name value pairs.
+ * @access public
+ */
+ function NestingXmlTag($attributes) {
+ $this->name = false;
+ $this->attributes = $attributes;
+ }
+
+ /**
+ * Sets the test case/method name.
+ * @param string $name Name of test.
+ * @access public
+ */
+ function setName($name) {
+ $this->name = $name;
+ }
+
+ /**
+ * Accessor for name.
+ * @return string Name of test.
+ * @access public
+ */
+ function getName() {
+ return $this->name;
+ }
+
+ /**
+ * Accessor for attributes.
+ * @return hash All attributes.
+ * @access protected
+ */
+ protected function getAttributes() {
+ return $this->attributes;
+ }
+}
+
+/**
+ * Accumulator for incoming method tag. Holds the
+ * incoming test structure information for
+ * later dispatch to the reporter.
+ * @package SimpleTest
+ * @subpackage UnitTester
+ */
+class NestingMethodTag extends NestingXmlTag {
+
+ /**
+ * Sets the basic test information except
+ * the name.
+ * @param hash $attributes Name value pairs.
+ * @access public
+ */
+ function NestingMethodTag($attributes) {
+ $this->NestingXmlTag($attributes);
+ }
+
+ /**
+ * Signals the appropriate start event on the
+ * listener.
+ * @param SimpleReporter $listener Target for events.
+ * @access public
+ */
+ function paintStart(&$listener) {
+ $listener->paintMethodStart($this->getName());
+ }
+
+ /**
+ * Signals the appropriate end event on the
+ * listener.
+ * @param SimpleReporter $listener Target for events.
+ * @access public
+ */
+ function paintEnd(&$listener) {
+ $listener->paintMethodEnd($this->getName());
+ }
+}
+
+/**
+ * Accumulator for incoming case tag. Holds the
+ * incoming test structure information for
+ * later dispatch to the reporter.
+ * @package SimpleTest
+ * @subpackage UnitTester
+ */
+class NestingCaseTag extends NestingXmlTag {
+
+ /**
+ * Sets the basic test information except
+ * the name.
+ * @param hash $attributes Name value pairs.
+ * @access public
+ */
+ function NestingCaseTag($attributes) {
+ $this->NestingXmlTag($attributes);
+ }
+
+ /**
+ * Signals the appropriate start event on the
+ * listener.
+ * @param SimpleReporter $listener Target for events.
+ * @access public
+ */
+ function paintStart(&$listener) {
+ $listener->paintCaseStart($this->getName());
+ }
+
+ /**
+ * Signals the appropriate end event on the
+ * listener.
+ * @param SimpleReporter $listener Target for events.
+ * @access public
+ */
+ function paintEnd(&$listener) {
+ $listener->paintCaseEnd($this->getName());
+ }
+}
+
+/**
+ * Accumulator for incoming group tag. Holds the
+ * incoming test structure information for
+ * later dispatch to the reporter.
+ * @package SimpleTest
+ * @subpackage UnitTester
+ */
+class NestingGroupTag extends NestingXmlTag {
+
+ /**
+ * Sets the basic test information except
+ * the name.
+ * @param hash $attributes Name value pairs.
+ * @access public
+ */
+ function NestingGroupTag($attributes) {
+ $this->NestingXmlTag($attributes);
+ }
+
+ /**
+ * Signals the appropriate start event on the
+ * listener.
+ * @param SimpleReporter $listener Target for events.
+ * @access public
+ */
+ function paintStart(&$listener) {
+ $listener->paintGroupStart($this->getName(), $this->getSize());
+ }
+
+ /**
+ * Signals the appropriate end event on the
+ * listener.
+ * @param SimpleReporter $listener Target for events.
+ * @access public
+ */
+ function paintEnd(&$listener) {
+ $listener->paintGroupEnd($this->getName());
+ }
+
+ /**
+ * The size in the attributes.
+ * @return integer Value of size attribute or zero.
+ * @access public
+ */
+ function getSize() {
+ $attributes = $this->getAttributes();
+ if (isset($attributes['SIZE'])) {
+ return (integer)$attributes['SIZE'];
+ }
+ return 0;
+ }
+}
+
+/**
+ * Parser for importing the output of the XmlReporter.
+ * Dispatches that output to another reporter.
+ * @package SimpleTest
+ * @subpackage UnitTester
+ */
+class SimpleTestXmlParser {
+ private $listener;
+ private $expat;
+ private $tag_stack;
+ private $in_content_tag;
+ private $content;
+ private $attributes;
+
+ /**
+ * Loads a listener with the SimpleReporter
+ * interface.
+ * @param SimpleReporter $listener Listener of tag events.
+ * @access public
+ */
+ function SimpleTestXmlParser(&$listener) {
+ $this->listener = &$listener;
+ $this->expat = &$this->createParser();
+ $this->tag_stack = array();
+ $this->in_content_tag = false;
+ $this->content = '';
+ $this->attributes = array();
+ }
+
+ /**
+ * Parses a block of XML sending the results to
+ * the listener.
+ * @param string $chunk Block of text to read.
+ * @return boolean True if valid XML.
+ * @access public
+ */
+ function parse($chunk) {
+ if (! xml_parse($this->expat, $chunk)) {
+ trigger_error('XML parse error with ' .
+ xml_error_string(xml_get_error_code($this->expat)));
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Sets up expat as the XML parser.
+ * @return resource Expat handle.
+ * @access protected
+ */
+ protected function &createParser() {
+ $expat = xml_parser_create();
+ xml_set_object($expat, $this);
+ xml_set_element_handler($expat, 'startElement', 'endElement');
+ xml_set_character_data_handler($expat, 'addContent');
+ xml_set_default_handler($expat, 'defaultContent');
+ return $expat;
+ }
+
+ /**
+ * Opens a new test nesting level.
+ * @return NestedXmlTag The group, case or method tag
+ * to start.
+ * @access private
+ */
+ protected function pushNestingTag($nested) {
+ array_unshift($this->tag_stack, $nested);
+ }
+
+ /**
+ * Accessor for current test structure tag.
+ * @return NestedXmlTag The group, case or method tag
+ * being parsed.
+ * @access private
+ */
+ protected function &getCurrentNestingTag() {
+ return $this->tag_stack[0];
+ }
+
+ /**
+ * Ends a nesting tag.
+ * @return NestedXmlTag The group, case or method tag
+ * just finished.
+ * @access private
+ */
+ protected function popNestingTag() {
+ return array_shift($this->tag_stack);
+ }
+
+ /**
+ * Test if tag is a leaf node with only text content.
+ * @param string $tag XML tag name.
+ * @return @boolean True if leaf, false if nesting.
+ * @private
+ */
+ protected function isLeaf($tag) {
+ return in_array($tag, array(
+ 'NAME', 'PASS', 'FAIL', 'EXCEPTION', 'SKIP', 'MESSAGE', 'FORMATTED', 'SIGNAL'));
+ }
+
+ /**
+ * Handler for start of event element.
+ * @param resource $expat Parser handle.
+ * @param string $tag Element name.
+ * @param hash $attributes Name value pairs.
+ * Attributes without content
+ * are marked as true.
+ * @access protected
+ */
+ protected function startElement($expat, $tag, $attributes) {
+ $this->attributes = $attributes;
+ if ($tag == 'GROUP') {
+ $this->pushNestingTag(new NestingGroupTag($attributes));
+ } elseif ($tag == 'CASE') {
+ $this->pushNestingTag(new NestingCaseTag($attributes));
+ } elseif ($tag == 'TEST') {
+ $this->pushNestingTag(new NestingMethodTag($attributes));
+ } elseif ($this->isLeaf($tag)) {
+ $this->in_content_tag = true;
+ $this->content = '';
+ }
+ }
+
+ /**
+ * End of element event.
+ * @param resource $expat Parser handle.
+ * @param string $tag Element name.
+ * @access protected
+ */
+ protected function endElement($expat, $tag) {
+ $this->in_content_tag = false;
+ if (in_array($tag, array('GROUP', 'CASE', 'TEST'))) {
+ $nesting_tag = $this->popNestingTag();
+ $nesting_tag->paintEnd($this->listener);
+ } elseif ($tag == 'NAME') {
+ $nesting_tag = &$this->getCurrentNestingTag();
+ $nesting_tag->setName($this->content);
+ $nesting_tag->paintStart($this->listener);
+ } elseif ($tag == 'PASS') {
+ $this->listener->paintPass($this->content);
+ } elseif ($tag == 'FAIL') {
+ $this->listener->paintFail($this->content);
+ } elseif ($tag == 'EXCEPTION') {
+ $this->listener->paintError($this->content);
+ } elseif ($tag == 'SKIP') {
+ $this->listener->paintSkip($this->content);
+ } elseif ($tag == 'SIGNAL') {
+ $this->listener->paintSignal(
+ $this->attributes['TYPE'],
+ unserialize($this->content));
+ } elseif ($tag == 'MESSAGE') {
+ $this->listener->paintMessage($this->content);
+ } elseif ($tag == 'FORMATTED') {
+ $this->listener->paintFormattedMessage($this->content);
+ }
+ }
+
+ /**
+ * Content between start and end elements.
+ * @param resource $expat Parser handle.
+ * @param string $text Usually output messages.
+ * @access protected
+ */
+ protected function addContent($expat, $text) {
+ if ($this->in_content_tag) {
+ $this->content .= $text;
+ }
+ return true;
+ }
+
+ /**
+ * XML and Doctype handler. Discards all such content.
+ * @param resource $expat Parser handle.
+ * @param string $default Text of default content.
+ * @access protected
+ */
+ protected function defaultContent($expat, $default) {
+ }
+}
+?>