/ */ class P4Cms_Record_QueryTest extends TestCase { /** * Test setup. */ public function setUp() { parent::setUp(); $adapter = new P4Cms_Record_Adapter; $adapter->setBasePath('//depot') ->setConnection($this->p4); P4Cms_Record::setDefaultAdapter($adapter); } /** * Test teardown. */ public function tearDown() { P4Cms_Record::clearDefaultAdapter(); parent::tearDown(); } /** * Provide test array runner, as most of the included test methods * require almost identical infrastructure for checking success/failure. * * @param array $tests The array of tests to run. * @param array $method The P4Cms_Record_Query method suffix, after 'get' and 'set'. */ protected function _runTests($tests, $method) { $setMethod = "set$method"; $getMethod = "get$method"; foreach ($tests as $test) { $label = $test['label']; $query = new P4Cms_Record_Query; try { $query->$setMethod($test['argument']); if (isset($test['addFilter'])) { foreach ((array) $test['addFilter'] as $filter) { $query->addFilter($filter); } } if ($test['error']) { $this->fail("$label - unexpected success"); } else { $this->assertEquals( $test['expected'], $query->$getMethod(), "$label - expected value" ); } } catch (PHPUnit_Framework_AssertionFailedError $e) { $this->fail($e->getMessage()); } catch (PHPUnit_Framework_ExpectationFailedError $e) { $this->fail($e->getMessage()); } catch (Exception $e) { if (!$test['error']) { $this->fail("$label - Unexpected exception (". get_class($e) .') :'. $e->getMessage()); } else { list($class, $error) = each($test['error']); $this->assertEquals( $class, get_class($e), "$label - expected exception class: ". $e->getMessage() ); $this->assertEquals( $error, $e->getMessage(), "$label - expected exception message" ); } } } } /** * Test the out-of-the-box query behaviour. */ public function testInitialConditions() { $query = new P4Cms_Record_Query; $this->assertTrue($query instanceof P4Cms_Record_Query, 'Expected class.'); $array = $query->toArray(); $this->assertEquals( array( P4_File_Query::QUERY_FILTER => null, P4_File_Query::QUERY_SORT_BY => null, P4_File_Query::QUERY_SORT_REVERSE => false, P4_File_Query::QUERY_LIMIT_FIELDS => null, P4_File_Query::QUERY_LIMIT_TO_CHANGELIST => null, P4_File_Query::QUERY_LIMIT_TO_NEEDS_RESOLVE => false, P4_File_Query::QUERY_LIMIT_TO_OPENED => false, P4_File_Query::QUERY_START_ROW => null, P4Cms_Record_Query::QUERY_MAX_ROWS => null, P4Cms_Record_Query::QUERY_INCLUDE_DELETED => false, P4Cms_Record_Query::QUERY_MAX_DEPTH => null, P4Cms_Record_Query::QUERY_PATHS => null, P4Cms_Record_Query::QUERY_IDS => null, P4Cms_Record_Query::QUERY_RECORD_CLASS => null, ), $query->toArray(), 'Expected options from constructor as array' ); $query = P4Cms_Record_Query::create(); $this->assertTrue($query instanceof P4Cms_Record_Query, 'Expected class.'); $array = $query->toArray(); $this->assertEquals( array( P4_File_Query::QUERY_FILTER => null, P4_File_Query::QUERY_SORT_BY => null, P4_File_Query::QUERY_SORT_REVERSE => false, P4_File_Query::QUERY_LIMIT_FIELDS => null, P4_File_Query::QUERY_LIMIT_TO_CHANGELIST => null, P4_File_Query::QUERY_LIMIT_TO_NEEDS_RESOLVE => false, P4_File_Query::QUERY_LIMIT_TO_OPENED => false, P4_File_Query::QUERY_START_ROW => null, P4Cms_Record_Query::QUERY_MAX_ROWS => null, P4Cms_Record_Query::QUERY_INCLUDE_DELETED => false, P4Cms_Record_Query::QUERY_MAX_DEPTH => null, P4Cms_Record_Query::QUERY_PATHS => null, P4Cms_Record_Query::QUERY_IDS => null, P4Cms_Record_Query::QUERY_RECORD_CLASS => null ), $query->toArray(), 'Expected options from create as array' ); } /** * Test passing options to the query constructors. */ public function testConstructorOptions() { $badOptions = array( P4_File_Query::QUERY_FILTER => -1, P4_File_Query::QUERY_SORT_BY => -1, P4_File_Query::QUERY_SORT_REVERSE => -1, P4_File_Query::QUERY_LIMIT_FIELDS => -1, P4_File_Query::QUERY_LIMIT_TO_CHANGELIST => -1, P4_File_Query::QUERY_LIMIT_TO_NEEDS_RESOLVE => -1, P4_File_Query::QUERY_LIMIT_TO_OPENED => -1, P4_File_Query::QUERY_START_ROW => -1, P4Cms_Record_Query::QUERY_MAX_ROWS => -1, P4Cms_Record_Query::QUERY_INCLUDE_DELETED => -1, P4Cms_Record_Query::QUERY_MAX_DEPTH => -1, P4Cms_Record_Query::QUERY_PATHS => array('filespec'), P4Cms_Record_Query::QUERY_IDS => -1, ); try { $query = new P4Cms_Record_Query($badOptions); $this->fail('Unexpected success with bad options.'); } catch (PHPUnit_Framework_AssertionFailedError $e) { $this->fail($e->getMessage()); } catch (InvalidArgumentException $e) { $this->assertEquals( 'Cannot set filter; argument must be a P4_File_Filter, a string, or null.', $e->getMessage(), 'Expected exception' ); } catch (Exception $e) { $this->fail('Unexpected exception ('. get_class($e) .') :'. $e->getMessage()); } $goodOptions = array( P4_File_Query::QUERY_FILTER => new P4_File_Filter('filter'), P4_File_Query::QUERY_SORT_BY => 'column', P4_File_Query::QUERY_SORT_REVERSE => true, P4_File_Query::QUERY_LIMIT_FIELDS => array('d'), P4_File_Query::QUERY_LIMIT_TO_CHANGELIST => 5, P4_File_Query::QUERY_LIMIT_TO_NEEDS_RESOLVE => true, P4_File_Query::QUERY_LIMIT_TO_OPENED => true, P4_File_Query::QUERY_START_ROW => 5, P4Cms_Record_Query::QUERY_MAX_ROWS => 10, P4Cms_Record_Query::QUERY_INCLUDE_DELETED => true, P4Cms_Record_Query::QUERY_MAX_DEPTH => 3, P4Cms_Record_Query::QUERY_PATHS => array('filespec'), P4Cms_Record_Query::QUERY_IDS => array('1', '2'), P4Cms_Record_Query::QUERY_RECORD_CLASS => null ); $query = new P4Cms_Record_Query($goodOptions); $expected = $goodOptions; $expected[P4_File_Query::QUERY_SORT_BY] = array('column' => null); $this->assertEquals( $expected, $query->toArray(), 'Expected options' ); $query = P4Cms_Record_Query::create($goodOptions); $this->assertEquals( $expected, $query->toArray(), 'Expected options' ); } /** * Test get/set a query's Filter attribute. */ public function testGetSetFilter() { $tests = array( array( 'label' => __LINE__ .': null', 'argument' => null, 'error' => null, 'expected' => null, ), array( 'label' => __LINE__ .': bool', 'argument' => true, 'error' => array( 'InvalidArgumentException' => 'Cannot set filter; argument must be a P4Cms_Record_Filter, an array, a string, or null.' ), 'expected' => null, ), array( 'label' => __LINE__ .': numeric', 'argument' => 1, 'error' => array( 'InvalidArgumentException' => 'Cannot set filter; argument must be a P4Cms_Record_Filter, an array, a string, or null.' ), 'expected' => null, ), array( 'label' => __LINE__ .': string', 'argument' => 'foobar', 'error' => null, 'expected' => 'foobar' ), array( 'label' => __LINE__ .': array', 'argument' => array('fields' => array('foobar' => '')), 'error' => null, 'expected' => P4Cms_Record_Filter::create(array('fields' => array('foobar' => '')))->getExpression() ), array( 'label' => __LINE__ .': some object', 'argument' => new stdClass, 'error' => array( 'InvalidArgumentException' => 'Cannot set filter; argument must be a P4Cms_Record_Filter, an array, a string, or null.' ), 'expected' => null, ), array( 'label' => __LINE__ .': P4Cms_Record_Filter', 'argument' => P4Cms_Record_Filter::create(), 'error' => null, 'expected' => '', ), array( 'label' => __LINE__ .': P4Cms_Record_Filter', 'argument' => P4Cms_Record_Filter::create()->add('field', 'value'), 'error' => null, 'expected' => 'attr-field~=\\^value\\$', ), array( 'label' => __LINE__ .': P4Cms_Record_Filter', 'argument' => P4Cms_Record_Filter::create()->add('field', 'value'), 'addFilter' => array( new P4Cms_Record_Filter ), 'error' => null, 'expected' => 'attr-field~=\\^value\\$', ), array( 'label' => __LINE__ .': P4Cms_Record_Filter', 'argument' => new P4Cms_Record_Filter, 'addFilter' => array( P4Cms_Record_Filter::create()->add('field', 'value') ), 'error' => null, 'expected' => '(attr-field~=\\^value\\$)', ), array( 'label' => __LINE__ .': P4Cms_Record_Filter', 'argument' => P4Cms_Record_Filter::create()->add('field', 'value'), 'addFilter' => array( new P4Cms_Record_Filter, P4Cms_Record_Filter::create()->add('field2', 'value2') ), 'error' => null, 'expected' => 'attr-field~=\^value\$ & (attr-field2~=\^value2\$)' ) ); // This block is needed here because _runTests does not support non P4Cms_Record_Filter // objects for the argument. foreach ($tests as $test) { $label = $test['label']; $query = new P4Cms_Record_Query; try { $query->setFilter($test['argument']); if (isset($test['addFilter'])) { foreach ((array) $test['addFilter'] as $filter) { $query->addFilter($filter); } } $expr = $query->getFilter() instanceof P4Cms_Record_Filter ? $query->getFilter()->getExpression() : $query->getFilter(); $this->assertEquals( $test['expected'], $expr, "$label - expected value" ); } catch (Exception $e) { if ($test['error']) { $this->assertEquals( 'Cannot set filter; argument must be a P4Cms_Record_Filter, an array, a string, or null.', $test['error']['InvalidArgumentException'], "$label - expected InvalidArgumentException" ); } else { $this->fail($e->getMessage()); } } } } /** * Test get/set a query's SortBy attribute. */ public function testGetSetSortBy() { $tests = array( array( 'label' => __LINE__ .': null', 'argument' => null, 'error' => null, 'expected' => null, ), array( 'label' => __LINE__ .': bool', 'argument' => true, 'error' => array( 'InvalidArgumentException' => 'Cannot set sort by; argument must be an array, string, or null.' ), 'expected' => null, ), array( 'label' => __LINE__ .': numeric', 'argument' => 1, 'error' => array( 'InvalidArgumentException' => 'Cannot set sort by; argument must be an array, string, or null.' ), 'expected' => null, ), array( 'label' => __LINE__ .': string', 'argument' => 'foobar', 'error' => null, 'expected' => array('foobar' => null), ), array( 'label' => __LINE__ .': array', 'argument' => array('foobar'), 'error' => null, 'expected' => array('foobar' => null), ), array( 'label' => __LINE__ .': object', 'argument' => new stdClass, 'error' => array( 'InvalidArgumentException' => 'Cannot set sort by; argument must be an array, string, or null.' ), 'expected' => null, ) ); $this->_runTests($tests, 'SortBy'); } /** * Test get/set a query's ReverseOrder attribute. */ public function testGetSetReverseOrder() { $tests = array( array( 'label' => __LINE__ .': null', 'argument' => null, 'error' => null, 'expected' => null, ), array( 'label' => __LINE__ .': boolean', 'argument' => true, 'error' => null, 'expected' => true, ), array( 'label' => __LINE__ .': numeric non-zero', 'argument' => 1, 'error' => null, 'expected' => true, ), array( 'label' => __LINE__ .': numeric zero', 'argument' => 0, 'error' => null, 'expected' => false, ), array( 'label' => __LINE__ .': string', 'argument' => 'foobar', 'error' => null, 'expected' => true, ), array( 'label' => __LINE__ .': string numeric', 'argument' => '1', 'error' => null, 'expected' => true, ), array( 'label' => __LINE__ .': array', 'argument' => array('foobar'), 'error' => null, 'expected' => true, ), array( 'label' => __LINE__ .': object', 'argument' => new stdClass, 'error' => null, 'expected' => true, ), ); $this->_runTests($tests, 'ReverseOrder'); } /** * Test get/set a query's StartRow attribute. */ public function testGetSetStartRow() { $tests = array( array( 'label' => __LINE__ .': null', 'argument' => null, 'error' => null, 'expected' => null, ), array( 'label' => __LINE__ .': boolean', 'argument' => true, 'error' => array( 'InvalidArgumentException' => 'Cannot set start row; argument must be a positive integer or null.' ), 'expected' => true, ), array( 'label' => __LINE__ .': positive numeric', 'argument' => 1, 'error' => null, 'expected' => 1, ), array( 'label' => __LINE__ .': negative numeric', 'argument' => -1, 'error' => array( 'InvalidArgumentException' => 'Cannot set start row; argument must be a positive integer or null.' ), 'expected' => false, ), array( 'label' => __LINE__ .': zero', 'argument' => 0, 'error' => null, 'expected' => null, ), array( 'label' => __LINE__ .': string', 'argument' => 'foobar', 'error' => null, 'expected' => null, ), array( 'label' => __LINE__ .': string numeric', 'argument' => '1', 'error' => null, 'expected' => 1, ), array( 'label' => __LINE__ .': array', 'argument' => array('foobar'), 'error' => array( 'InvalidArgumentException' => 'Cannot set start row; argument must be a positive integer or null.' ), 'expected' => null, ), array( 'label' => __LINE__ .': object', 'argument' => new stdClass, 'error' => array( 'InvalidArgumentException' => 'Cannot set start row; argument must be a positive integer or null.' ), 'expected' => null, ), ); $this->_runTests($tests, 'StartRow'); } /** * Test get/set a query's IncludeDeleted attribute. */ public function testGetSetIncludeDeleted() { $tests = array( array( 'label' => __LINE__ .': null', 'argument' => null, 'error' => null, 'expected' => false, ), array( 'label' => __LINE__ .': boolean', 'argument' => true, 'error' => null, 'expected' => true, ), array( 'label' => __LINE__ .': positive numeric', 'argument' => 1, 'error' => null, 'expected' => true, ), array( 'label' => __LINE__ .': negative numeric', 'argument' => -1, 'error' => null, 'expected' => true, ), array( 'label' => __LINE__ .': zero', 'argument' => 0, 'error' => null, 'expected' => false, ), array( 'label' => __LINE__ .': string', 'argument' => 'foobar', 'error' => null, 'expected' => true, ), array( 'label' => __LINE__ .': string numeric', 'argument' => '1', 'error' => null, 'expected' => true, ), array( 'label' => __LINE__ .': array', 'argument' => array('foobar'), 'error' => null, 'expected' => true, ), array( 'label' => __LINE__ .': object', 'argument' => new stdClass, 'error' => null, 'expected' => true, ), ); $this->_runTests($tests, 'IncludeDeleted'); } /** * Test get/set a query's MaxDepth attribute. */ public function testGetSetMaxDepth() { $tests = array( array( 'label' => __LINE__ .': null', 'argument' => null, 'error' => null, 'expected' => null, ), array( 'label' => __LINE__ .': boolean', 'argument' => true, 'error' => array( 'InvalidArgumentException' => 'Cannot set maximum depth; argument must be a non-negative integer or null.' ), 'expected' => true, ), array( 'label' => __LINE__ .': positive numeric', 'argument' => 1, 'error' => null, 'expected' => 1, ), array( 'label' => __LINE__ .': negative numeric', 'argument' => -1, 'error' => array( 'InvalidArgumentException' => 'Cannot set maximum depth; argument must be a non-negative integer or null.' ), 'expected' => false, ), array( 'label' => __LINE__ .': zero', 'argument' => 0, 'error' => null, 'expected' => 0, ), array( 'label' => __LINE__ .': string', 'argument' => 'foobar', 'error' => null, 'expected' => 0, ), array( 'label' => __LINE__ .': string numeric', 'argument' => '1', 'error' => null, 'expected' => 1, ), array( 'label' => __LINE__ .': array', 'argument' => array('foobar'), 'error' => array( 'InvalidArgumentException' => 'Cannot set maximum depth; argument must be a non-negative integer or null.' ), 'expected' => null, ), array( 'label' => __LINE__ .': object', 'argument' => new stdClass, 'error' => array( 'InvalidArgumentException' => 'Cannot set maximum depth; argument must be a non-negative integer or null.' ), 'expected' => null, ), ); $this->_runTests($tests, 'MaxDepth'); } /** * Test get/set a query's MaxRows attribute. */ public function testGetSetMaxRows() { $tests = array( array( 'label' => __LINE__ .': null', 'argument' => null, 'error' => null, 'expected' => null, ), array( 'label' => __LINE__ .': boolean', 'argument' => true, 'error' => array( 'InvalidArgumentException' => 'Cannot set max files; argument must be a positive integer or null.' ), 'expected' => true, ), array( 'label' => __LINE__ .': positive numeric', 'argument' => 1, 'error' => null, 'expected' => 1, ), array( 'label' => __LINE__ .': negative numeric', 'argument' => -1, 'error' => array( 'InvalidArgumentException' => 'Cannot set max files; argument must be a positive integer or null.' ), 'expected' => false, ), array( 'label' => __LINE__ .': zero', 'argument' => 0, 'error' => null, 'expected' => null, ), array( 'label' => __LINE__ .': string', 'argument' => 'foobar', 'error' => null, 'expected' => null, ), array( 'label' => __LINE__ .': string numeric', 'argument' => '1', 'error' => null, 'expected' => 1, ), array( 'label' => __LINE__ .': array', 'argument' => array('foobar'), 'error' => array( 'InvalidArgumentException' => 'Cannot set max files; argument must be a positive integer or null.' ), 'expected' => null, ), array( 'label' => __LINE__ .': object', 'argument' => new stdClass, 'error' => array( 'InvalidArgumentException' => 'Cannot set max files; argument must be a positive integer or null.' ), 'expected' => null, ), ); $this->_runTests($tests, 'MaxRows'); } /** * Test get/set query paths. */ public function testGetSetPaths() { $tests = array( array( 'label' => __LINE__ .': null', 'argument' => null, 'error' => null, 'expected' => null, ), array( 'label' => __LINE__ .': boolean', 'argument' => true, 'error' => array( 'InvalidArgumentException' => 'Cannot set filespecs; argument must be a string, an array, or null.' ), 'expected' => true, ), array( 'label' => __LINE__ .': numeric', 'argument' => 1, 'error' => array( 'InvalidArgumentException' => 'Cannot set filespecs; argument must be a string, an array, or null.' ), 'expected' => 1, ), array( 'label' => __LINE__ .': string', 'argument' => 'foobar', 'error' => null, 'expected' => array('foobar'), ), array( 'label' => __LINE__ .': array', 'argument' => array('foobar'), 'error' => null, 'expected' => array('foobar'), ), array( 'label' => __LINE__ .': hash', 'argument' => array('foobar' => 'testing'), 'error' => null, 'expected' => array('testing'), ), array( 'label' => __LINE__ .': object', 'argument' => new stdClass, 'error' => array( 'InvalidArgumentException' => 'Cannot set filespecs; argument must be a string, an array, or null.' ), 'expected' => null, ), ); $this->_runTests($tests, 'Paths'); } /** * Test adding a path to a query. */ public function testAddPath() { $tests = array( array( 'label' => __LINE__ .': null', 'argument' => null, 'error' => array('InvalidArgumentException' => 'Cannot add path; argument must be a string.'), 'expected' => null, ), array( 'label' => __LINE__ .': numeric', 'argument' => 1, 'error' => array('InvalidArgumentException' => 'Cannot add path; argument must be a string.'), 'expected' => null, ), array( 'label' => __LINE__ .': string', 'argument' => 'string', 'error' => null, 'expected' => array('string'), ), array( 'label' => __LINE__ .': array', 'argument' => array('string'), 'error' => array('InvalidArgumentException' => 'Cannot add path; argument must be a string.'), 'expected' => null, ), array( 'label' => __LINE__ .': object', 'argument' => new stdClass, 'error' => array('InvalidArgumentException' => 'Cannot add path; argument must be a string.'), 'expected' => null, ), ); foreach ($tests as $test) { $label = $test['label']; $query = new P4Cms_Record_Query; try { $query->addPath($test['argument']); if ($test['error']) { $this->fail("$label - unexpected success"); } else { $this->assertEquals( $test['expected'], $query->getPaths(), "$label - expected value" ); } } catch (PHPUnit_Framework_AssertionFailedError $e) { $this->fail($e->getMessage()); } catch (PHPUnit_Framework_ExpectationFailedError $e) { $this->fail($e->getMessage()); } catch (Exception $e) { if (!$test['error']) { $this->fail("$label - Unexpected exception (". get_class($e) .') :'. $e->getMessage()); } else { list($class, $error) = each($test['error']); $this->assertEquals( $class, get_class($e), "$label - expected exception class: ". $e->getMessage() ); $this->assertEquals( $error, $e->getMessage(), "$label - expected exception message" ); } } } $query = P4Cms_Record_Query::create()->addPath('one')->addPath('two')->addPath('three'); $this->assertEquals( array('one', 'two', 'three'), $query->getPaths(), 'Expected filespecs after add chain' ); } /** * Test adding multiple paths to a query. */ public function testAddPaths() { $tests = array( array( 'label' => __LINE__ .': null', 'argument' => null, 'error' => array('InvalidArgumentException' => 'Cannot add paths; argument must be an array.'), 'expected' => null, ), array( 'label' => __LINE__ .': numeric', 'argument' => 1, 'error' => array('InvalidArgumentException' => 'Cannot add paths; argument must be an array.'), 'expected' => null, ), array( 'label' => __LINE__ .': string', 'argument' => 'string', 'error' => array('InvalidArgumentException' => 'Cannot add paths; argument must be an array.'), 'expected' => null, ), array( 'label' => __LINE__ .': array', 'argument' => array('string'), 'error' => null, 'expected' => array('string'), ), array( 'label' => __LINE__ .': object', 'argument' => new stdClass, 'error' => array('InvalidArgumentException' => 'Cannot add paths; argument must be an array.'), 'expected' => null, ), ); foreach ($tests as $test) { $label = $test['label']; $query = new P4Cms_Record_Query; try { $query->addPaths($test['argument']); if ($test['error']) { $this->fail("$label - unexpected success"); } else { $this->assertEquals( $test['expected'], $query->getPaths(), "$label - expected value" ); } } catch (PHPUnit_Framework_AssertionFailedError $e) { $this->fail($e->getMessage()); } catch (PHPUnit_Framework_ExpectationFailedError $e) { $this->fail($e->getMessage()); } catch (Exception $e) { if (!$test['error']) { $this->fail("$label - Unexpected exception (". get_class($e) .') :'. $e->getMessage()); } else { list($class, $error) = each($test['error']); $this->assertEquals( $class, get_class($e), "$label - expected exception class: ". $e->getMessage() ); $this->assertEquals( $error, $e->getMessage(), "$label - expected exception message" ); } } } $query = new P4Cms_Record_Query; $query->addPaths(array('one', 'two', 'three')); $this->assertEquals( array('one', 'two', 'three'), $query->getPaths(), 'Expected filespecs after initial add' ); // add array containing a dupe $query->addPaths(array('two', 'four', 'five')); $this->assertEquals( array('one', 'two', 'three', 'two', 'four', 'five'), $query->getPaths(), 'Expected filespecs after 2nd add' ); } /** * Test query fstat flag generation. */ public function testGetFstatFlags() { $tests = array( array( 'label' => __LINE__ .': fresh query', 'query' => new P4Cms_Record_Query, 'expected' => array('-F', '^headAction=...delete', '-Oal'), ), array( 'label' => __LINE__ .': with paths', 'query' => P4Cms_Record_Query::create()->addPath('one')->addPath('two'), 'expected' => array('-F', '^headAction=...delete', '-Oal'), ), array( 'label' => __LINE__ .': reversed order', 'query' => P4Cms_Record_Query::create()->setReverseOrder(true), 'expected' => array('-F', '^headAction=...delete', '-r', '-Oal'), ), array( 'label' => __LINE__ .': sort by fileSize', 'query' => P4Cms_Record_Query::create()->setSortBy(P4Cms_Record_Query::SORT_FILE_SIZE), 'expected' => array('-F', '^headAction=...delete', '-Ss', '-Oal'), ), array( 'label' => __LINE__ .': sort by fileType', 'query' => P4Cms_Record_Query::create()->setSortBy(P4Cms_Record_Query::SORT_FILE_TYPE), 'expected' => array('-F', '^headAction=...delete', '-St', '-Oal'), ), array( 'label' => __LINE__ .': sort by date', 'query' => P4Cms_Record_Query::create()->setSortBy(P4Cms_Record_Query::SORT_DATE), 'expected' => array('-F', '^headAction=...delete', '-Sd', '-Oal'), ), array( 'label' => __LINE__ .': sort by head rev', 'query' => P4Cms_Record_Query::create()->setSortBy(P4Cms_Record_Query::SORT_HEAD_REV), 'expected' => array('-F', '^headAction=...delete', '-Sr', '-Oal'), ), array( 'label' => __LINE__ .': sort by have rev', 'query' => P4Cms_Record_Query::create()->setSortBy(P4Cms_Record_Query::SORT_HAVE_REV), 'expected' => array('-F', '^headAction=...delete', '-Sh', '-Oal'), ), array( 'label' => __LINE__ .': max files', 'query' => P4Cms_Record_Query::create()->setMaxRows(7), 'expected' => array('-F', '^headAction=...delete', '-m', 7, '-Oal'), ), array( 'label' => __LINE__ .': max depth', 'query' => P4Cms_Record_Query::create()->setMaxDepth(4), 'expected' => array('-F', '(^headAction=...delete) & ^depotFile=//depot/*/*/*/*/*/...', '-Oal'), ), array( 'label' => __LINE__ .': filter', 'query' => P4Cms_Record_Query::create()->setFilter('attr-title=test') ->setMaxRows(7) ->setMaxDepth(4) ->setSortBy(P4Cms_Record_Query::SORT_HAVE_REV) ->setReverseOrder(true), 'expected' => array( '-F', '((attr-title=test) & ^headAction=...delete) & ^depotFile=//depot/*/*/*/*/*/...', '-m', 7, '-Sh', '-r', '-Oal' ), ), array( 'label' => __LINE__ .': all', 'query' => P4Cms_Record_Query::create()->setFilter('attr-title=test'), 'expected' => array('-F', '(attr-title=test) & ^headAction=...delete', '-Oal'), ), ); foreach ($tests as $test) { $label = $test['label']; $this->assertEquals( $test['expected'], $test['query']->toFileQuery()->getFstatFlags(), "$label - expected flags" ); } } /** * Test variations of adding paths to a query. */ public function testAddModes() { $query = new P4Cms_Record_Query; $this->assertEquals(null, $query->getPaths(), 'Expected paths after new object.'); $query->addPath('one'); $query->addPaths(array('two', 'three')); $this->assertEquals( array('one', 'two', 'three'), $query->getPaths(), 'Expected paths after add without intersect (1).' ); $query->addPaths(array('two', 'three', 'four'), true); $this->assertEquals( array('two', 'three'), $query->getPaths(), 'Expected paths after add with intersect (1).' ); $query->addPath('two', true); $this->assertEquals( array('two'), $query->getPaths(), 'Expected paths after add with intersect (2).' ); $query->addPath('one'); $query->addPaths(array('two', 'three')); $this->assertEquals( array('two', 'one', 'two', 'three'), $query->getPaths(), 'Expected paths after add without intersect (2).' ); $query->addPath('five', true); $this->assertEquals( array(), $query->getPaths(), 'Expected paths after add with intersect (3).' ); } /** * Test conversion of query paths to filespecs. */ public function testToFileQueryPathToFilespec() { $query = P4Cms_Record_Query::create()->addPath('one')->addPath('two'); $this->assertSame( array('one', 'two'), $query->getPaths(), 'Expected paths' ); // should result in tmp label. $filespecs = $query->toFileQuery()->getFilespecs(); $this->assertSame(1, count($filespecs)); $this->assertRegExp("://depot/\.\.\.@~tmp.[0-9]+:", $filespecs[0]); } /** * Test removing a path from a query. */ public function testRemovePath() { $tests = array( array( 'label' => __LINE__ .': null', 'argument' => null, 'error' => array('InvalidArgumentException' => 'Cannot remove path; argument must be a string.'), 'expected' => null, ), array( 'label' => __LINE__ .': numeric', 'argument' => 1, 'error' => array('InvalidArgumentException' => 'Cannot remove path; argument must be a string.'), 'expected' => null, ), array( 'label' => __LINE__ .': string', 'argument' => 'string', 'error' => null, 'expected' => array(), ), array( 'label' => __LINE__ .': array', 'argument' => array('string'), 'error' => array('InvalidArgumentException' => 'Cannot remove path; argument must be a string.'), 'expected' => array('string'), ), array( 'label' => __LINE__ .': object', 'argument' => new stdClass, 'error' => array('InvalidArgumentException' => 'Cannot remove path; argument must be a string.'), 'expected' => null, ), ); foreach ($tests as $test) { $label = $test['label']; $query = new P4Cms_Record_Query; try { $query->removePath($test['argument']); if ($test['error']) { $this->fail("$label - unexpected success"); } else { $this->assertEquals( $test['expected'], $query->getPaths(), "$label - expected value" ); } } catch (PHPUnit_Framework_AssertionFailedError $e) { $this->fail($e->getMessage()); } catch (PHPUnit_Framework_ExpectationFailedError $e) { $this->fail($e->getMessage()); } catch (Exception $e) { if (!$test['error']) { $this->fail("$label - Unexpected exception (". get_class($e) .') :'. $e->getMessage()); } else { list($class, $error) = each($test['error']); $this->assertEquals( $class, get_class($e), "$label - expected exception class: ". $e->getMessage() ); $this->assertEquals( $error, $e->getMessage(), "$label - expected exception message" ); } } } $query = P4Cms_Record_Query::create()->addPaths(array('one', 'two', 'three', 'two', 'four')); $this->assertEquals( array('one', 'two', 'three', 'two', 'four'), $query->getPaths(), 'Expected paths after add' ); $query->removePath('two'); $this->assertEquals( array('one', 'three', 'two', 'four'), $query->getPaths(), 'Expected paths after remove' ); } /** * Test removing multiple paths from a query. */ public function testRemovePaths() { $tests = array( array( 'label' => __LINE__ .': null', 'argument' => null, 'error' => array('InvalidArgumentException' => 'Cannot remove paths; argument must be an array.'), 'expected' => null, ), array( 'label' => __LINE__ .': numeric', 'argument' => 1, 'error' => array('InvalidArgumentException' => 'Cannot remove paths; argument must be an array.'), 'expected' => null, ), array( 'label' => __LINE__ .': string', 'argument' => 'string', 'error' => array('InvalidArgumentException' => 'Cannot remove paths; argument must be an array.'), 'expected' => null, ), array( 'label' => __LINE__ .': array', 'argument' => array('string'), 'error' => null, 'expected' => array(), ), array( 'label' => __LINE__ .': object', 'argument' => new stdClass, 'error' => array('InvalidArgumentException' => 'Cannot remove paths; argument must be an array.'), 'expected' => null, ), ); foreach ($tests as $test) { $label = $test['label']; $query = new P4Cms_Record_Query; try { $query->removePaths($test['argument']); if ($test['error']) { $this->fail("$label - unexpected success"); } else { $this->assertEquals( $test['expected'], $query->getPaths(), "$label - expected value" ); } } catch (PHPUnit_Framework_AssertionFailedError $e) { $this->fail($e->getMessage()); } catch (PHPUnit_Framework_ExpectationFailedError $e) { $this->fail($e->getMessage()); } catch (Exception $e) { if (!$test['error']) { $this->fail("$label - Unexpected exception (". get_class($e) .') :'. $e->getMessage()); } else { list($class, $error) = each($test['error']); $this->assertEquals( $class, get_class($e), "$label - expected exception class: ". $e->getMessage() ); $this->assertEquals( $error, $e->getMessage(), "$label - expected exception message" ); } } } $query = P4Cms_Record_Query::create()->addPaths(array('one', 'two', 'three', 'two', 'four')); $this->assertEquals( array('one', 'two', 'three', 'two', 'four'), $query->getPaths(), 'Expected paths after add' ); $query->removePaths(array('two', 'four')); $this->assertEquals( array('one', 'three', 'two'), $query->getPaths(), 'Expected paths after remove #1' ); } /** * Test (set/get)LimitField() methods. */ public function testGetSetLimitFields() { $record = P4Cms_Record::store( array( 'id' => 'test', 'field1' => 'a', 'field2' => 'b', 'field3' => 'c' ) ); $query = P4Cms_Record_Query::create()->setLimitFields(array('field2')); $this->assertSame( array('field2'), $query->getLimitFields(), "Expected limit fields." ); $entry = P4Cms_Record::fetch('test', $query); $this->assertSame( array('id', 'field2'), $entry->getFields(), 'Expected only selected fields are returned.' ); $this->assertSame( array('id' => 'test', 'field2' => 'b'), $entry->getValues(), 'Expected only values for selected fields are returned.' ); $this->assertSame( null, $entry->getValue('field3'), "Expected return default value for field not set in limti fields." ); // verify that limitFields option is not directly applied to the file query $options = array('limitFields' => 'field1'); $query = new P4Cms_Record_Query($options); $this->assertSame( 'field1', $query->getLimitFields(), "Expected limitFields value set on record query." ); // verify that record fields are converted to the file fields (depotFile field is always present) $fileQuery = $query->toFileQuery(); $this->assertSame( array('depotFile', 'attr-field1'), $fileQuery->getLimitFields(), "Expected limitFields value set on file query." ); // verify that id and file content fields are not converted to the fiel fields $limitFields = array('field3', P4Cms_Content::getIdField(), P4Cms_Content::getFileContentField()); $query = new P4Cms_Record_Query(array('limitFields' => $limitFields)); $this->assertSame( $limitFields, $query->getLimitFields(), "Expected limitFields value set on record query #2." ); $fileQuery = $query->toFileQuery('P4Cms_Content'); $this->assertSame( array('depotFile', 'attr-field3'), $fileQuery->getLimitFields(), "Expected limitFields value set on file query #2." ); } }