Skip to content
Browse files

Initial commit

  • Loading branch information...
0 parents commit e02f83d20f40c0a8fe4777f902442bbd3b67e5f3 @jails jails committed Dec 14, 2012
25 LICENSE.txt
@@ -0,0 +1,25 @@
+Copyright (c) 2012, Union of RAD http://union-of-rad.org
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of Lithium, Union of Rad, nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
185 README.md
@@ -0,0 +1,185 @@
+# Database schema managment
+
+## Requirement
+
+PHP 5.4
+
+## Installation
+
+Checkout the code to either of your library directories:
+
+ cd libraries
+ git clone git@github.com:UnionOfRAD/li3_fixtures.git
+
+Include the library in in your `/app/config/bootstrap/libraries.php`
+
+ Libraries::add('li3_fixtures');
+
+## Presentation
+
+Thin plugin provide fixtures managment over connections. Should work with any kind of `Source` adapaters.
+
+## Dependencies
+
+This plugin needs [li3_sqltools](https://github.com/UnionOfRAD/li3_sqltools) if you want to make it work with li3's `Database` adapters. For schema less datasources, adapters must return false on `::enabled('schema')` call.
+
+## API
+
+### The Fixture class
+
+Methods:
+--------
+
+- Fixture::create($safe); //Create the source only
+- Fixture::save($safe); //Create the source + save the fixture's records in.
+- Fixture::drop($safe); //Drop the source.
+- Fixture::populate($records); //Insert a record in the database
+- Fixture::alter($mode, $fieldname, $value); //Altering the schema before `::create()/::save()`.
+
+Simple example of unit test:
+
+ //app/tests/cases/models/SampleTest.php
+ namespace app\tests\cases\models;
+
+ use li3_fixtures\test\Fixture;
+
+ class SampleTest extends \lithium\test\Unit {
+
+ public function testFixture() {
+ $fixture = new Fixture(array(
+ 'connection' => 'lithium_mysql_test',
+ 'source' => 'contacts',
+ 'fields' => array(
+ 'id' => array('type' => 'id'),
+ 'name' => array('type' => 'string')
+ ),
+ 'records' => array(
+ array('id' => 1, 'name' => 'Nate'),
+ array('id' => 2, 'name' => 'Gwoo')
+ )
+ ));
+
+ $fixture->save();
+
+ $fixture->populate(array('id' => 3, 'name' => 'Mehlah'));
+
+ $fixture->drop();
+ }
+ }
+
+### The Fixtures class
+
+`Fixture` is a kind of `Schema` which contain records and a source name or a reference to a model.
+So let save the above fixture in a class.
+
+ //app/tests/fixture/ContactsFixture.php
+ namespace app\tests\fixture;
+
+ class ContactsFixture extends \li3_fixtures\test\Fixture {
+
+ protected $_model = 'app\models\Contacts';
+
+ protected $_fields = array(
+ 'id' => array('type' => 'id'),
+ 'name' => array('type' => 'string')
+ );
+
+ protected $_records = array(
+ array('id' => 1, 'name' => 'Nate'),
+ array('id' => 2, 'name' => 'Gwoo')
+ );
+ }
+
+ //app/models/Contact.php
+ namespace app\models;
+
+ class Contacts extends \lithium\data\Model {
+ }
+
+If you have numbers of fixtures, it will be interesting to use the `Fixtures` class.
+
+Example of use case:
+
+ //app/tests/integration/Sample2Test.php
+ namespace app\tests\integration;
+
+ use li3_fixtures\test\Fixtures;
+ use app\models\Contacts;
+ use app\models\Images;
+ // and so on...
+
+ class Sample2Test extends \lithium\test\Unit {
+
+ public function setUp() {
+ Fixtures::config(array(
+ 'db' => array(
+ 'adapter' => 'Connection',
+ 'connection' => 'lithium_mysql_test',
+ 'fixtures' => array(
+ 'contacts' => 'app\tests\fixture\ContactsFixture',
+ 'images' => 'app\tests\fixture\ImagesFixture'
+ // and so on...
+ )
+ )
+ ));
+ Fixtures::save('db');
+ }
+
+ public function tearDown() {
+ Fixtures::reset('db');
+ }
+
+ public function testFixture() {
+ var_export(Contacts::find('all')->data());
+ var_export(Images::find('all')->data());
+ }
+ }
+
+Ok so why it's better to set the `Fixture::_model` instead of `Fixture::_source` ? Long story short,
+models had their own meta `'connection'` value. If a fixture is "linked" with a model, it will
+automagically configure its meta `'connection'` to the fixture's connection when is created or saved.
+
+Example:
+
+ Fixtures::save('db', array('contacts'));
+ Contacts::config(array('meta' => array('connection' => 'test'))); //This is not needed
+
+### Advanced use case
+
+For interoperability, sometimes it's usefull to adjust fixtures according a datasources.
+
+You can alter `Fixture`'s instance before creating it like the following use case:
+
+ $fixture->alter('add', array(
+ 'name' => 'enabled',
+ 'type' => 'boolean'
+ ); //Add a field
+
+ $fixture->alter('change', array(
+ 'name' => 'published',
+ 'value' => function ($val) {
+ return new MongoDate(strtotime($val));
+ }
+ ); //Simple cast for fixture's values according the closure
+
+ $fixture->alter('change', array(
+ 'name' => 'id',
+ 'to' => '_id',
+ 'value' => function ($val) {
+ return new MongoId('4c3628558ead0e594' . (string) ($val + 1000000));
+ }
+ ); //Renaming the field 'id' to '_id' + cast fixture's values according the closure
+
+ $fixture->alter('change', array(
+ 'name' => 'bigintger',
+ 'type' => 'integer',
+ 'use' => 'bigint' //use db specific type
+ ); //Modifing a field type
+
+ $fixture->alter('drop', 'bigintger'); //Simply dropping a field
+
+Note :
+
+You can recover a specific fixture's instance from `Fixtures` using:
+
+ $fixture = Fixtures::get('db', 'contacts');
184 extensions/adapter/test/fixtures/Connection.php
@@ -0,0 +1,184 @@
+<?php
+/**
+ * Lithium: the most rad php framework
+ *
+ * @copyright Copyright 2012, Union of RAD (http://union-of-rad.org)
+ * @license http://opensource.org/licenses/bsd-license.php The BSD License
+ */
+
+namespace li3_fixtures\extensions\adapter\test\fixtures;
+
+use lithium\core\ConfigException;
+use UnexpectedValueException;
+
+class Connection extends \lithium\core\Object {
+
+ /**
+ * Auto configuration properties.
+ *
+ * @var array
+ */
+ protected $_autoConfig = array('connection', 'fixtures');
+
+ /**
+ * Connection name to use.
+ *
+ * @var string
+ */
+ protected $_connection = null;
+
+ /**
+ * Holds the fixture classes that where instantiated.
+ *
+ * @var array
+ */
+ protected $_loaded = array();
+
+ /**
+ * Holds the fixture classes to be instantiated indexed by a name.
+ *
+ * @var array
+ */
+ protected $_fixtures = array();
+
+ /**
+ * Initializes class configuration (`$_config`), and assigns object properties using the
+ * `_init()` method, unless otherwise specified by configuration. See below for details.
+ *
+ * @see lithium\core\Object::__construct()
+ * @param array $config The configuration options
+ */
+ public function __construct(array $config = array()) {
+ $defaults = array('alters' => array());
+ parent::__construct($config + $defaults);
+ }
+
+ /**
+ * Initializer function called by the constructor unless the constructor
+ *
+ * @see lithium\core\Object::_init()
+ * @throws ConfigException
+ */
+ protected function _init() {
+ parent::_init();
+
+ if (!$this->_connection) {
+ throw new ConfigException("The `'connection'` option must be set.");
+ }
+ }
+
+ /**
+ * Instantiate a fixture
+ *
+ * @param array $name The fixture name to instanciate
+ * @return boolean Returns `true` on success
+ */
+ protected function _instantiate($name) {
+ if (isset($this->_fixtures[$name])) {
+ $options = array(
+ 'connection' => $this->_connection,
+ 'alters' => $this->_config['alters']
+ );
+ $this->_loaded[$name] = new $this->_fixtures[$name]($options);
+ return true;
+ } else {
+ throw new UnexpectedValueException("Undefined fixture named: `{$name}`.");
+ }
+ }
+
+ /**
+ * Getting a fixture.
+ *
+ * @param mixed $name The fixture name to get.
+ * @return mixed Returns a fixture object or `null` if doesn't exists.
+ */
+ public function get($name) {
+ if (isset($this->_loaded[$name]) || $this->_instantiate($name)) {
+ return $this->_loaded[$name];
+ }
+ }
+
+ /**
+ * Creates the schema of fixtures
+ *
+ * @param mixed $names An array of fixture name.
+ * @param boolean $drop If `true` drop the fixture before creating it
+ */
+ public function create(array $names = array(), $drop = true) {
+ $this->_create($names, $drop, false);
+ }
+
+ /**
+ * Creates the fixtures tables and inserts data on them
+ *
+ * @param mixed $names An array of fixture name.
+ * @param boolean $drop If `true` drop the fixture before loading it
+ */
+ public function save(array $names = array(), $drop = true) {
+ $this->_create($names, $drop, true);
+ }
+
+ /**
+ * Build fixtures
+ *
+ * @param mixed $names An array of fixture name.
+ * @param boolean $drop If `true` drop the fixture before creating it
+ * @param boolean $save If `true` save fixture's records in the database
+ */
+ protected function _create($names = array(), $drop = true, $save = true) {
+ $names = $names ?: array_keys($this->_fixtures);
+
+ foreach ((array) $names as $name) {
+ if (isset($this->_loaded[$name]) || $this->_instantiate($name)) {
+ $fixture = $this->_loaded[$name];
+ if ($save) {
+ $fixture->save($drop);
+ } else {
+ $fixture->create($drop);
+ }
+ }
+ }
+ }
+
+ /**
+ * Trucantes the fixtures tables
+ *
+ * @param mixed $names The fixtures name to truncate.
+ */
+ public function truncate(array $names = array()) {
+ $names = $names ?: array_keys($this->_loaded);
+ foreach ($names as $name) {
+ $fixture = $this->get($name);
+ $fixture->truncate();
+ }
+ }
+
+ /**
+ * Drop all fixture tables loaded by this class.
+ *
+ * @param array $names The fixtures name to drop.
+ * @param boolean $safe If `true` drop the fixture only if exists
+ */
+ public function drop(array $names = array(), $safe = true) {
+ $names = $names ?: array_keys($this->_loaded);
+ foreach ($names as $name) {
+ $fixture = $this->get($name);
+ $fixture->drop($safe);
+ }
+ }
+
+ /**
+ * Drop all fixture tables loaded by this class.
+ *
+ * @param array $names The fixtures name to drop.
+ */
+ public function reset() {
+ foreach ($this->_loaded as $name => $fixture) {
+ $fixture->drop();
+ }
+ $this->_loaded = array();
+ $this->_config = array();
+ }
+}
+
+?>
338 test/Fixture.php
@@ -0,0 +1,338 @@
+<?php
+/**
+ * Lithium: the most rad php framework
+ *
+ * @copyright Copyright 2012, Union of RAD (http://union-of-rad.org)
+ * @license http://opensource.org/licenses/bsd-license.php The BSD License
+ */
+
+namespace li3_fixtures\test;
+
+use lithium\core\ConfigException;
+
+class Fixture extends \lithium\data\Schema {
+
+ /**
+ * Classes used by `Fixture`.
+ *
+ * @var array
+ */
+ protected $_classes = array(
+ 'connections' => 'lithium\data\Connections',
+ 'schema' => 'lithium\data\Schema',
+ 'query' => 'lithium\data\model\Query'
+ );
+ /**
+ * Auto configuration properties.
+ *
+ * @var array
+ */
+ protected $_autoConfig = array(
+ 'connection', 'source', 'locked', 'model', 'fields' => 'merge', 'meta', 'records'
+ );
+
+ /**
+ * The connection name
+ *
+ * @var string
+ */
+ protected $_connection = null;
+
+ /**
+ * The name of the source. Used if `Fixture::_model` is not set (i.e. `null`).
+ *
+ * @var string
+ */
+ protected $_source = null;
+
+ /**
+ * The fully-namespaced attached model class name
+ *
+ * @var string
+ */
+ protected $_model = null;
+
+ /**
+ * Fields definition
+ *
+ * Example:
+ * {{{
+ * protected $_fields = array(
+ * 'id' => array('type' => 'id'),
+ * 'firstname' => array('type' => 'string', 'default' => 'foo', 'null' => false),
+ * 'lastname' => array('type' => 'string', 'default' => 'bar', 'null' => false)
+ * );
+ * }}}
+ *
+ * @var array
+ */
+ protected $_fields = array();
+
+ /**
+ * Alteres dields definition
+ *
+ * @var array
+ */
+ protected $_alteredFields = array();
+
+ /**
+ * Metas for the fixture.
+ *
+ * Example:
+ * {{{
+ * protected $_meta = array(
+ * 'constraints' => array(
+ * array(
+ * 'type' => 'foreign_key',
+ * 'column' => 'id',
+ * 'toColumn' => 'id',
+ * 'to' => 'other_table'
+ * )
+ * ),
+ * 'table' => array('charset' => 'utf8', 'engine' => 'InnoDB')
+ * );
+ * }}}
+ *
+ * @var array
+ */
+ protected $_meta = array();
+
+ /**
+ * The records should be an array of rows. Each row should have values keyed by
+ * the column name.
+ *
+ * Example:
+ * {{{
+ * protected $_records = array(
+ * array('id' => 1, 'firstname' => 'John', 'lastname' => 'Doe'),
+ * array('id' => 2, 'firstname' => 'Pamela', 'lastname' => 'A.'),
+ * array('id' => 6, 'firstname' => 'Jay', 'lastname' => 'Miner'),
+ * array('id' => 9, 'firstname' => 'Obi-Wan', 'lastname' => 'Kenobi')
+ * );
+ * }}}
+ *
+ * @var array
+ */
+ protected $_records = array();
+
+ /**
+ * Initializes class configuration (`$_config`), and assigns object properties using the
+ * `_init()` method, unless otherwise specified by configuration. See below for details.
+ *
+ * @see lithium\core\Object::__construct()
+ * @param array $config The configuration options
+ */
+ public function __construct($config = array()) {
+ parent::__construct($config + array('alters' => array()));
+ }
+
+ /**
+ * Initializer function called by the constructor unless the constructor
+ *
+ * @see lithium\core\Object::_init()
+ * @throws ConfigException
+ */
+ protected function _init() {
+ parent::_init();
+
+ if (!$this->_connection) {
+ throw new ConfigException("The `'connection'` option must be set.");
+ }
+
+ if (!$this->_source && !$this->_model) {
+ throw new ConfigException("The `'model'` or `'source'` option must be set.");
+ }
+
+ if ($model = $this->_model) {
+ $model::config(array('meta' => array('connection' => $this->_connection)));
+ $this->_source = $this->_source ? : $model::meta('source');
+ }
+
+ foreach ($this->_config['alters'] as $mode => $values) {
+ foreach ($values as $key => $value) {
+ $this->alter($mode, $key, $value);
+ }
+ }
+ }
+
+ /**
+ * Create the fixture's schema.
+ *
+ * @return boolean Returns `true` on success or if there are no records to import,
+ * return `false` on failure.
+ */
+ public function create($drop = true) {
+ return $this->_create($drop, false);
+ }
+
+ /**
+ * Create the fixture's schema and import records.
+ *
+ * @return boolean Returns `true` on success or if there are no records to import,
+ * return `false` on failure.
+ */
+ public function save($drop = true) {
+ return $this->_create($drop, true);
+ }
+
+ /**
+ * Create the fixture's schema and import records.
+ *
+ * @param boolean $drop If `true` drop the fixture before creating it
+ * @param boolean $load If `true` load fixture's records
+ * @return boolean True on success, false on failure
+ */
+ public function _create($drop = true, $save = true) {
+ $connections = $this->_classes['connections'];
+ $db = $connections::get($this->_connection);
+
+ if (!$db::enabled('schema')) {
+ return true;
+ }
+
+ if ($drop && !$this->drop()) {
+ return false;
+ }
+
+ $this->_alteredFields = $this->_alterFields($this->_fields);
+
+ $schema = $this->_instance('schema', array(
+ 'fields' => $this->_alteredFields,
+ 'meta' => $this->_meta,
+ 'locked' => $this->_locked
+ ));
+
+ $return = $db->createSchema($this->_source, $schema);
+
+ if ($return && $save) {
+ foreach ($this->_records as $record) {
+ if (!$this->populate($record, true)) {
+ return false;
+ }
+ }
+ }
+ return $return;
+ }
+
+ /**
+ * Drop table for this fixture.
+ *
+ * @param boolean $soft If `true` and there's not existing schema, no drop query is generated.
+ * @return boolean True on success, false on failure
+ */
+ public function drop($soft = true) {
+ $connections = $this->_classes['connections'];
+ $db = $connections::get($this->_connection);
+ if (!$db::enabled('schema')) {
+ return $this->truncate();
+ }
+ if ($soft) {
+ $sources = $db->sources();
+ if(!in_array($this->_source, $sources)) {
+ return true;
+ }
+ }
+ return $db->dropSchema($this->_source);
+ }
+
+ /**
+ * Populate a custom records in the database.
+ *
+ * @param array $record The data of the record
+ * @param boolean $alter If true, the `$record` will be altered according the alter rules.
+ * @return boolean Returns `true` on success `false` otherwise.
+ */
+ public function populate(array $record = array(), $alter = true) {
+ if (!$record) {
+ return true;
+ }
+ $connections = $this->_classes['connections'];
+ $db = $connections::get($this->_connection);
+ $data = $alter ? $this->_alterRecord($record) : $record;
+ $data = array_intersect_key($data, $this->_alteredFields);
+ $options = array('type' => 'create', 'source' => $this->_source, 'data' => $data);
+ $query = $this->_instance('query', $options);
+ return $db->create($query, $record, $this);
+ }
+
+ /**
+ * Truncates the current fixture.
+ *
+ * @return boolean
+ */
+ public function truncate() {
+ $connections = $this->_classes['connections'];
+ $db = $connections::get($this->_connection);
+ return $db->truncate($this->_source);
+ }
+
+ public function alter($mode = null, $key = null, $value = array()) {
+ if ($mode === null) {
+ return $this->_config['alters'];
+ }
+ if ($key && $mode === 'drop') {
+ $this->_config['alters']['drop'][] = $key;
+ return;
+ }
+ if ($key && $value) {
+ $this->_config['alters'][$mode][$key] = $value;
+ }
+ }
+
+ /**
+ * Apply the configured value mapping.
+ *
+ * @param array $record The record array.
+ * @return array Returns the modified record.
+ */
+ public function _alterRecord(array $record = array()) {
+ $result = array();
+ foreach ($record as $name => $value) {
+ if (isset($this->_config['alters']['change'][$name])) {
+ $alter = $this->_config['alters']['change'][$name];
+ if (isset($alter['value'])) {
+ $function = $alter['value'];
+ $value = $function($record[$name]);
+ } else {
+ $value = $record[$name];
+ }
+ if (isset($alter['to'])) {
+ $result[$alter['to']] = $value;
+ } else {
+ $result[$name] = $value;
+ }
+ } else {
+ $result[$name] = $value;
+ }
+ }
+ return $result;
+ }
+
+ public function _alterFields(array $fields = array()) {
+ foreach ($this->_config['alters'] as $mode => $values) {
+ foreach ($values as $key => $value) {
+ switch($mode) {
+ case 'add':
+ $fields[$key] = $value;
+ break;
+ case 'change':
+ if (isset($fields[$key]) && isset($value['to'])) {
+ $field = $fields[$key];
+ unset($fields[$key]);
+ $to = $value['to'];
+ unset($value['to']);
+ unset($value['value']);
+ $fields[$to] = $value + $field;
+ }
+ break;
+ case 'drop':
+ unset($fields[$value]);
+ break;
+ }
+ }
+ }
+ return $fields;
+ }
+}
+
+?>
50 test/Fixtures.php
@@ -0,0 +1,50 @@
+<?php
+/**
+ * Lithium: the most rad php framework
+ *
+ * @copyright Copyright 2012, Union of RAD (http://union-of-rad.org)
+ * @license http://opensource.org/licenses/bsd-license.php The BSD License
+ */
+
+namespace li3_fixtures\test;
+
+use lithium\core\ConfigException;
+
+class Fixtures extends \lithium\core\Adaptable {
+
+ /**
+ * Stores configurations arrays for session adapters, keyed by configuration name.
+ *
+ * @var array
+ */
+ protected static $_configurations = array();
+
+ /**
+ * Libraries::locate() compatible path to adapters for this class.
+ *
+ * @see lithium\core\Libraries::locate()
+ * @var string Dot-delimited path.
+ */
+ protected static $_adapters = 'adapter.test.fixtures';
+
+ /**
+ * Delegate calls to adapters
+ *
+ * @param string $method The called method name.
+ * @param array $params The parameters array.
+ * @return mixed
+ */
+
+ public static function __callStatic($method, $params) {
+ $name = array_shift($params);
+ if (($config = static::_config($name)) === null) {
+ throw new ConfigException("Configuration `{$name}` has not been defined.");
+ }
+ $filter = function($self, $params) use ($name, $method) {
+ return call_user_func_array(array($self::adapter($name), $method), $params);
+ };
+ return static::_filter(__FUNCTION__, $params, $filter, (array) $config['filters']);
+ }
+}
+
+?>
301 tests/cases/test/FixtureTest.php
@@ -0,0 +1,301 @@
+<?php
+/**
+ * Lithium: the most rad php framework
+ *
+ * @copyright Copyright 2012, Union of RAD (http://union-of-rad.org)
+ * @license http://opensource.org/licenses/bsd-license.php The BSD License
+ */
+
+namespace li3_fixtures\tests\cases\test;
+
+use MongoId;
+use lithium\data\Connections;
+use li3_fixtures\tests\mocks\core\MockLogCall;
+use li3_fixtures\test\Fixture;
+
+class FixtureTest extends \lithium\test\Unit {
+
+ protected $_connection = 'fixture_test';
+
+ protected $_callable = null;
+
+ public function skip() {
+ $this->_callable = new MockLogCall();
+ Connections::add($this->_connection, array(
+ 'object' => $this->_callable
+ ));
+ }
+
+ public function tearDown() {
+ $this->_callable->__clear();
+ }
+
+ public function testInitMissingConnection() {
+ $this->expectException("The `'connection'` option must be set.");
+ new Fixture();
+ }
+
+ public function testInitMissingModelAndSource() {
+ $this->expectException("The `'model'` or `'source'` option must be set.");
+ new Fixture(array('connection' => $this->_connection));
+ }
+
+ public function testCreate() {
+ $fields = array(
+ 'id' => array('type' => 'id'),
+ 'name' => array('type' => 'string')
+ );
+
+ $fixture = new Fixture(array(
+ 'connection' => $this->_connection,
+ 'source' => 'contacts',
+ 'fields' => $fields,
+ 'records' => array(
+ array('id' => 1, 'name' => 'Nate'),
+ array('id' => 2, 'name' => 'Gwoo')
+ )
+ ));
+
+ $fixture->create(false);
+ $this->assertEqual(1, count($this->_callable->call));
+ $call = $this->_callable->call[0];
+ $this->assertEqual('createSchema', $call['method']);
+ $this->assertEqual('contacts', $call['params'][0]);
+ $this->assertEqual($fields, $call['params'][1]->fields());
+
+ $fixture->create();
+ $call = $this->_callable->call[1];
+ $this->assertEqual('sources', $call['method']);
+ }
+
+ public function testDrop() {
+ $fixture = new Fixture(array(
+ 'connection' => $this->_connection,
+ 'source' => 'contacts'
+ ));
+
+ $fixture->drop(false);
+ $call = $this->_callable->call[0];
+ $this->assertEqual('dropSchema', $call['method']);
+ $this->assertEqual('contacts', $call['params'][0]);
+
+ $fixture->drop();
+ $call = $this->_callable->call[1];
+ $this->assertEqual('sources', $call['method']);
+ }
+
+ public function testTruncate() {
+ $fixture = new Fixture(array(
+ 'connection' => $this->_connection,
+ 'source' => 'contacts'
+ ));
+
+ $fixture->truncate();
+ $call = $this->_callable->call[0];
+ $this->assertEqual('truncate', $call['method']);
+ }
+
+ public function testSave() {
+ $fields = array(
+ 'id' => array('type' => 'id'),
+ 'name' => array('type' => 'string')
+ );
+
+ $records = array(
+ array('id' => 1, 'name' => 'Nate'),
+ array('id' => 2, 'name' => 'Gwoo')
+ );
+
+ $fixture = new Fixture(array(
+ 'connection' => $this->_connection,
+ 'source' => 'contacts',
+ 'fields' => $fields,
+ 'records' => $records
+ ));
+
+ $fixture->save(false);
+ $this->assertEqual(3, count($this->_callable->call));
+ $call = $this->_callable->call[0];
+ $this->assertEqual('createSchema', $call['method']);
+ $this->assertEqual('contacts', $call['params'][0]);
+ $this->assertEqual($fields, $call['params'][1]->fields());
+
+ $call = $this->_callable->call[1];
+ $this->assertEqual('create', $call['method']);
+ $query = $call['params'][0];
+ $this->assertEqual('create', $query->type());
+ $this->assertEqual($records[0], $query->data());
+
+ $call = $this->_callable->call[2];
+ $this->assertEqual('create', $call['method']);
+ $query = $call['params'][0];
+ $this->assertEqual('create', $query->type());
+ $this->assertEqual($records[1], $query->data());
+ }
+
+ public function testAlter() {
+ $fields = array(
+ 'id' => array('type' => 'id'),
+ 'name' => array('type' => 'string'),
+ 'useless' => array('type' => 'string')
+ );
+
+ $records = array(
+ array('id' => 1, 'name' => 'Nate', 'useless' => 'a'),
+ array('id' => 2, 'name' => 'Gwoo', 'useless' => 'b')
+ );
+
+ $alters = array(
+ 'add' => array(
+ 'lastname' => array('type' => 'string', 'default' => 'li3')
+ ),
+ 'change' => array(
+ 'id' => array(
+ 'type' => 'string',
+ 'length' => '24',
+ 'to' => '_id',
+ 'value' => function ($val) {
+ return new MongoId('4c3628558ead0e594' . (string) ($val + 1000000));
+ }
+ ),
+ 'name' => array(
+ 'to' => 'firstname'
+ )
+ ),
+ 'drop' => array(
+ 'useless'
+ )
+ );
+
+ $fixture = new Fixture(array(
+ 'connection' => $this->_connection,
+ 'source' => 'contacts',
+ 'fields' => $fields,
+ 'records' => $records,
+ 'alters' => $alters
+ ));
+
+ $this->assertEqual($alters, $fixture->alter());
+
+ $fixture->save(false);
+ $this->assertEqual(3, count($this->_callable->call));
+ $call = $this->_callable->call[0];
+ $this->assertEqual('createSchema', $call['method']);
+ $this->assertEqual('contacts', $call['params'][0]);
+
+ $expected = array(
+ '_id' => array('type' => 'string', 'length' => 24),
+ 'firstname' => array('type' => 'string'),
+ 'lastname' => array('type' => 'string', 'default' => 'li3')
+ );
+ $this->assertEqual($expected, $call['params'][1]->fields());
+
+ $expected = array(
+ array('_id' => new MongoId('4c3628558ead0e5941000001'), 'firstname' => 'Nate'),
+ array('_id' => new MongoId('4c3628558ead0e5941000002'), 'firstname' => 'Gwoo')
+ );
+ $call = $this->_callable->call[1];
+ $this->assertEqual('create', $call['method']);
+ $query = $call['params'][0];
+ $this->assertEqual('create', $query->type());
+ $this->assertEqual($expected[0], $query->data());
+
+ $call = $this->_callable->call[2];
+ $this->assertEqual('create', $call['method']);
+ $query = $call['params'][0];
+ $this->assertEqual('create', $query->type());
+ $this->assertEqual($expected[1], $query->data());
+ }
+
+ public function testPopulate() {
+ $fields = array(
+ 'id' => array('type' => 'id'),
+ 'name' => array('type' => 'string'),
+ 'useless' => array('type' => 'string')
+ );
+
+ $fixture = new Fixture(array(
+ 'connection' => $this->_connection,
+ 'source' => 'contacts',
+ 'fields' => $fields
+ ));
+
+ $fixture->create(false);
+ $this->assertEqual(1, count($this->_callable->call));
+ $call = $this->_callable->call[0];
+ $this->assertEqual('createSchema', $call['method']);
+ $this->assertEqual('contacts', $call['params'][0]);
+
+ $record = array('id' => 1, 'name' => 'Nate', 'useless' => 'a');
+ $fixture->populate($record);
+ $call = $this->_callable->call[1];
+ $this->assertEqual('create', $call['method']);
+ $query = $call['params'][0];
+ $this->assertEqual('create', $query->type());
+ $this->assertEqual($record, $query->data());
+ }
+
+ public function testLiveAlter() {
+ $fields = array(
+ 'id' => array('type' => 'id'),
+ 'name' => array('type' => 'string'),
+ 'useless' => array('type' => 'string')
+ );
+
+ $fixture = new Fixture(array(
+ 'connection' => $this->_connection,
+ 'source' => 'contacts',
+ 'fields' => $fields
+ ));
+
+ $fixture->alter('change', 'id', array(
+ 'type' => 'string',
+ 'length' => '24',
+ 'to' => '_id',
+ 'value' => function ($val) {
+ return new MongoId('4c3628558ead0e594' . (string) ($val + 1000000));
+ }
+ ));
+ $fixture->alter('change', 'name', array('to' => 'firstname'));
+ $fixture->alter('drop', 'useless');
+ $fixture->alter('add', 'lastname', array('type' => 'string', 'default' => 'li3'));
+
+ $fixture->create(false);
+ $this->assertEqual(1, count($this->_callable->call));
+ $call = $this->_callable->call[0];
+ $this->assertEqual('createSchema', $call['method']);
+ $this->assertEqual('contacts', $call['params'][0]);
+
+ $record = array('id' => 1, 'name' => 'Nate', 'useless' => 'a');
+ $fixture->populate($record);
+ $call = $this->_callable->call[1];
+ $this->assertEqual('create', $call['method']);
+ $query = $call['params'][0];
+ $this->assertEqual('create', $query->type());
+ $expected = array('_id' => new MongoId('4c3628558ead0e5941000001'), 'firstname' => 'Nate');
+ $this->assertEqual($expected, $query->data());
+
+ $record = array('id' => 1, 'name' => 'Nate', 'useless' => 'a');
+ $fixture->populate($record, false);
+ $call = $this->_callable->call[2];
+ $this->assertEqual('create', $call['method']);
+ $query = $call['params'][0];
+ $this->assertEqual('create', $query->type());
+ $expected = array('id' => 1, 'name' => 'Nate');
+ $this->assertEqual(array(), $query->data());
+ }
+
+ public function testSchemaLess() {
+ $fixture = new Fixture(array(
+ 'connection' => $this->_connection,
+ 'source' => 'contacts',
+ 'fields' => array()
+ ));
+
+ MockLogCall::$returnStatic = array('enabled' => false);
+ $fixture->create(false);
+ $this->assertEqual(0, count($this->_callable->call));
+ }
+}
+
+?>
69 tests/cases/test/FixturesTest.php
@@ -0,0 +1,69 @@
+<?php
+/**
+ * Lithium: the most rad php framework
+ *
+ * @copyright Copyright 2012, Union of RAD (http://union-of-rad.org)
+ * @license http://opensource.org/licenses/bsd-license.php The BSD License
+ */
+
+namespace li3_fixtures\tests\cases\test;
+
+use li3_fixtures\tests\mocks\core\MockLogCall;
+use li3_fixtures\test\Fixtures;
+
+class FixturesTest extends \lithium\test\Unit {
+
+ protected $_callable;
+
+ public function setUp() {
+ Fixtures::reset();
+ $this->_callable = new MockLogCall();
+ Fixtures::config(array(
+ 'fixture_test' => array(
+ 'object' => $this->_callable,
+ 'fixtures' => array(
+ 'image' => 'name\spa\ce',
+ 'gallery' => 'na\mespac\e',
+ )
+ )
+ ));
+ }
+
+ public function tearDown() {
+ $this->_callable->__clear();
+ Fixtures::reset();
+ }
+
+ public function testConstructPassedParams() {
+ Fixtures::reset();
+ $config = array(
+ 'adapter' => 'li3_fixtures\tests\mocks\core\MockLogCall',
+ 'fixtures' => array(
+ 'image' => 'name\spa\ce',
+ 'gallery' => 'na\mespac\e',
+ )
+ );
+ Fixtures::config(array(
+ 'fixture_test' => $config
+ ));
+ $callable = Fixtures::adapter('fixture_test');
+ $expected = $config + array('filters' => array());
+ $this->assertEqual($expected, $callable->construct[0]);
+ }
+
+ public function testCallStatic() {
+ $result = Fixtures::methodName('fixture_test', array('parameter' => 'value'), 'param');
+ $expected = array(
+ 'method' => 'methodName',
+ 'params' => array(
+ array(
+ 'parameter' => 'value',
+ ),
+ 'param'
+ )
+ );
+ $this->assertEqual($expected, $this->_callable->call[0]);
+ }
+}
+
+?>
149 tests/cases/test/fixtures/adapter/ConnectionTest.php
@@ -0,0 +1,149 @@
+<?php
+/**
+ * Lithium: the most rad php framework
+ *
+ * @copyright Copyright 2012, Union of RAD (http://union-of-rad.org)
+ * @license http://opensource.org/licenses/bsd-license.php The BSD License
+ */
+
+namespace li3_fixtures\tests\cases\test\fixtures\adapter;
+
+use li3_fixtures\extensions\adapter\test\fixtures\Connection;
+
+class ConnectionTest extends \lithium\test\Unit {
+
+ protected $_connection = 'fixture_test';
+
+ protected $_adapter;
+
+ public function setUp() {
+ $this->_adapter = new Connection(array(
+ 'connection' => $this->_connection,
+ 'alters' => array(
+ 'add' => array('custom' => array('type' => 'string'))
+ ),
+ 'fixtures' => array(
+ 'gallery' => 'li3_fixtures\tests\mocks\core\MockLogCall',
+ 'image' => 'li3_fixtures\tests\mocks\core\MockLogCall'
+ )
+ ));
+ }
+
+ public function testInitMissingConnection() {
+ $this->expectException("The `'connection'` option must be set.");
+ new Connection();
+ }
+
+ public function testInstantiateFixture() {
+ $callable = $this->_adapter->get('gallery');
+ $expected = array(
+ 'connection' => $this->_connection,
+ 'alters' => array('add' => array('custom' => array('type' => 'string')))
+ );
+ $this->assertEqual($expected, $callable->construct[0]);
+ }
+
+ public function testMissingFixture() {
+ $this->expectException("Undefined fixture named: `foo`.");
+ $this->_adapter->get('foo');
+ }
+
+ public function testCreate() {
+ $this->_adapter->create();
+
+ $callable = $this->_adapter->get('image');
+ $expected = array('method' => 'create', 'params' => array(true));
+ $this->assertEqual($expected, $callable->call[0]);
+
+ $callable = $this->_adapter->get('gallery');
+ $expected = array('method' => 'create', 'params' => array(true));
+ $this->assertEqual($expected, $callable->call[0]);
+ }
+
+ public function testCreateSingle() {
+ $this->_adapter->create(array('gallery'));
+
+ $callable = $this->_adapter->get('image');
+ $expected = array('method' => 'create', 'params' => array(true));
+ $this->assertEqual(0, count($callable->call));
+
+ $callable = $this->_adapter->get('gallery');
+ $expected = array('method' => 'create', 'params' => array(true));
+ $this->assertEqual($expected, $callable->call[0]);
+ }
+
+ public function testDrop() {
+ $this->_adapter->create();
+ $this->_adapter->drop();
+
+ $callable = $this->_adapter->get('image');
+ $expected = array('method' => 'create', 'params' => array(true));
+ $this->assertEqual($expected, $callable->call[0]);
+
+ $callable = $this->_adapter->get('image');
+ $expected = array('method' => 'drop', 'params' => array(true));
+ $this->assertEqual($expected, $callable->call[1]);
+
+ $callable = $this->_adapter->get('gallery');
+ $expected = array('method' => 'create', 'params' => array(true));
+ $this->assertEqual($expected, $callable->call[0]);
+
+ $callable = $this->_adapter->get('gallery');
+ $expected = array('method' => 'drop', 'params' => array(true));
+ $this->assertEqual($expected, $callable->call[1]);
+ }
+
+ public function testDropLoadedFixtureOnly() {
+ $this->_adapter->create(array('gallery'));
+ $this->_adapter->drop();
+
+ $callable = $this->_adapter->get('image');
+ $this->assertEqual(0, count($callable->call));
+
+ $callable = $this->_adapter->get('gallery');
+ $expected = array('method' => 'create', 'params' => array(true));
+ $this->assertEqual($expected, $callable->call[0]);
+
+ $callable = $this->_adapter->get('gallery');
+ $expected = array('method' => 'drop', 'params' => array(true));
+ $this->assertEqual($expected, $callable->call[1]);
+ }
+
+ public function testTruncate() {
+ $this->_adapter->create();
+ $this->_adapter->truncate();
+
+ $callable = $this->_adapter->get('image');
+ $expected = array('method' => 'create', 'params' => array(true));
+ $this->assertEqual($expected, $callable->call[0]);
+
+ $callable = $this->_adapter->get('image');
+ $expected = array('method' => 'truncate', 'params' => array());
+ $this->assertEqual($expected, $callable->call[1]);
+
+ $callable = $this->_adapter->get('gallery');
+ $expected = array('method' => 'create', 'params' => array(true));
+ $this->assertEqual($expected, $callable->call[0]);
+
+ $callable = $this->_adapter->get('gallery');
+ $expected = array('method' => 'truncate', 'params' => array());
+ $this->assertEqual($expected, $callable->call[1]);
+ }
+
+ public function testTruncateLoadedFixtureOnly() {
+ $this->_adapter->create(array('gallery'));
+ $this->_adapter->truncate();
+
+ $callable = $this->_adapter->get('image');
+ $this->assertEqual(0, count($callable->call));
+
+ $callable = $this->_adapter->get('gallery');
+ $expected = array('method' => 'create', 'params' => array(true));
+ $this->assertEqual($expected, $callable->call[0]);
+
+ $callable = $this->_adapter->get('gallery');
+ $expected = array('method' => 'truncate', 'params' => array());
+ $this->assertEqual($expected, $callable->call[1]);
+ }
+}
+?>
53 tests/mocks/core/MockLogCall.php
@@ -0,0 +1,53 @@
+<?php
+/**
+ * Lithium: the most rad php framework
+ *
+ * @copyright Copyright 2012, Union of RAD (http://union-of-rad.org)
+ * @license http://opensource.org/licenses/bsd-license.php The BSD License
+ */
+
+namespace li3_fixtures\tests\mocks\core;
+
+class MockLogCall extends \lithium\core\Object {
+
+ public $construct = array();
+
+ public $get = array();
+
+ public $return = array();
+
+ public static $returnStatic = array();
+
+ public $call = array();
+
+ public static $callStatic = array();
+
+ public function __construct() {
+ $this->construct = func_get_args();
+ }
+
+ public function __clear() {
+ $this->call = array();
+ $this->return = array();
+ $this->get = array();
+ static::$callStatic = array();
+ }
+
+ public function __call($method, $params = array()) {
+ $call = compact('method', 'params');
+ $this->call[] = $call;
+ return isset($this->return[$method]) ? $this->return[$method]: $call;
+ }
+
+ public static function __callStatic($method, $params) {
+ $callStatic = compact('method', 'params');
+ static::$callStatic[] = $callStatic;
+ return isset(static::$returnStatic[$method]) ? static::$returnStatic[$method]: $callStatic;
+ }
+
+ public function __get($value) {
+ return $this->get[] = $value;
+ }
+}
+
+?>

0 comments on commit e02f83d

Please sign in to comment.
Something went wrong with that request. Please try again.