<?php
/**
* Test methods for the P4 Client class.
*
* @copyright 2011 Perforce Software. All rights reserved.
* @license Please see LICENSE.txt in top-level folder of this distribution.
* @version <release>/<patch>
*/
class P4_ClientTest extends TestCase
{
/**
* Test initial conditions.
*/
public function testInitialConditions()
{
$clients = P4_Client::fetchAll();
$this->assertSame(1, count($clients), 'Expected clients at start.');
$client = $clients[0];
$this->assertSame($this->utility->getP4Params('client'), $client->getId(), 'Expected client name.');
$this->assertSame(
$this->utility->getP4Params('user'),
$client->getOwner(),
'Expected client owner.'
);
$this->assertSame(
$this->utility->getP4Params('clientRoot') .'/superuser',
$client->getRoot(),
'Expected client root.'
);
$this->assertSame('', $client->getHost(), 'Expected client host.');
$this->assertSame('', $client->getDescription(), 'Expected client description.');
$this->assertSame('local', $client->getLineEnd(), 'Expected client line ending.');
$this->assertSame(
array(
'noallwrite', 'noclobber', 'nocompress', 'unlocked',
'nomodtime', 'normdir',
),
$client->getOptions(),
'Expected options'
);
$this->assertSame(
array(
array(
'depot' => '//depot/...',
'client' => '//'. $this->utility->getP4Params('client') .'/...',
),
),
$client->getView(),
'Expected client view.'
);
$this->assertTrue(
P4_Client::exists($this->utility->getP4Params('client')),
'Expect configured client to exist.'
);
$this->assertFalse(
P4_Client::exists('foobar'),
'Expect bogus client to not exist.'
);
$this->assertFalse(
P4_Client::exists(123),
'Expect invalid client to not exist.'
);
}
/**
* Test a fresh in-memory Client object.
*/
public function testFreshObject()
{
$client = new P4_Client;
$this->assertSame(
null,
$client->getUpdateDateTime(),
'Expected update datetime'
);
$this->assertSame(
null,
$client->getAccessDateTime(),
'Expected access datetime'
);
$this->assertSame(
null,
$client->getRoot(),
'Expected null client root'
);
}
/**
* Test accessors/mutators.
*/
public function testAccessorsMutators()
{
$client = new P4_Client;
$tests = array(
'Client' => 'zclient',
'Description' => 'zdesc',
'Host' => 'zhost',
'LineEnd' => 'zle',
'Owner' => 'bob',
'Root' => 'zroot',
);
foreach ($tests as $key => $value) {
$client->setValue($key, $value);
$this->assertSame($value, $client->getValue($key), "Expected value for $key");
}
$client->setValue('View', array('a view'));
$this->assertSame(
array(array('depot' => 'a', 'client' => 'view')),
$client->getValue('View'),
'Expected view.'
);
}
/**
* Test setView.
*/
public function testSetView()
{
$badTypeError = "Each view entry must be a 'depot' and 'client' array or a string.";
$badFormatError = "Each view entry must contain two paths, no more, no less.";
$tests = array(
array(
'label' => __LINE__ .': null',
'view' => null,
'expect' => false,
'error' => 'View must be passed as array.',
),
array(
'label' => __LINE__ .': empty array',
'view' => array(),
'expect' => array(),
'error' => false,
),
array(
'label' => __LINE__ .': array containing int',
'view' => array(12),
'expect' => false,
'error' => $badTypeError,
),
array(
'label' => __LINE__ .': array with empty string',
'view' => array(''),
'expect' => false,
'error' => $badFormatError,
),
array(
'label' => __LINE__ .': array with bogus string',
'view' => array('qstring'),
'expect' => false,
'error' => $badFormatError,
),
array(
'label' => __LINE__ .': array with string, integer',
'view' => array('a string', 12),
'expect' => false,
'error' => $badTypeError,
),
array(
'label' => __LINE__ .': array with string, bogus string',
'view' => array('a string', 'bogus'),
'expect' => false,
'error' => $badFormatError,
),
array(
'label' => __LINE__ .': array with string',
'view' => array('a string'),
'expect' => array(
array('depot' => 'a', 'client' => 'string'),
),
'error' => false,
),
array(
'label' => __LINE__ .': array with strings',
'view' => array('a string', '"another" string', "third 'entry'"),
'expect' => array(
array('depot' => 'a', 'client' => 'string'),
array('depot' => 'another', 'client' => 'string'),
array('depot' => 'third', 'client' => "'entry'"),
),
'error' => false,
),
array(
'label' => __LINE__ .': array with empty array',
'view' => array(array()),
'expect' => false,
'error' => $badTypeError,
),
array(
'label' => __LINE__ .': array with good array + bad array',
'view' => array(
array('depot' => 'depot', 'client' => 'client'),
array(),
),
'expect' => false,
'error' => $badTypeError,
),
array(
'label' => __LINE__ .': array with array, no client',
'view' => array(array('depot' => 'a')),
'expect' => false,
'error' => $badTypeError,
),
array(
'label' => __LINE__ .': array with array, no depot',
'view' => array(array('client' => 'a')),
'expect' => false,
'error' => $badTypeError,
),
array(
'label' => __LINE__ .': array with array + extra',
'view' => array(
array('depot' => 'depot', 'client' => 'client', 'a' => 'b')
),
'expect' => array(
array('depot' => 'depot', 'client' => 'client'),
),
'error' => false,
),
array(
'label' => __LINE__ .': array with good array + string',
'view' => array(
array('depot' => 'depot', 'client' => 'client'),
'another client',
),
'expect' => array(
array('depot' => 'depot', 'client' => 'client'),
array('depot' => 'another', 'client' => 'client'),
),
'error' => false,
),
array(
'label' => __LINE__ .': array with good arrays',
'view' => array(
array('depot' => 'depot', 'client' => 'client'),
array('depot' => 'builds', 'client' => 'buildClient'),
array('depot' => 'cms', 'client' => 'cmsClient'),
),
'expect' => array(
array('depot' => 'depot', 'client' => 'client'),
array('depot' => 'builds', 'client' => 'buildClient'),
array('depot' => 'cms', 'client' => 'cmsClient'),
),
'error' => false,
),
);
foreach ($tests as $test) {
$label = $test['label'];
$client = new P4_Client;
try {
$client->setView($test['view']);
if ($test['error']) {
$this->fail("$label - unexpected success");
}
} catch (InvalidArgumentException $e) {
if ($test['error']) {
$this->assertSame(
$test['error'],
$e->getMessage(),
'Expected error message.'
);
} else {
$this->fail("$label - unexpected argument exception.");
}
} catch (PHPUnit_Framework_AssertionFailedError $e) {
$this->fail($e->getMessage());
} catch (Exception $e) {
$this->fail(
"$label - Unexpected exception (". get_class($e)
.") - ". $e->getMessage()
);
}
if (!$test['error']) {
$this->assertSame(
$test['expect'],
$client->getView(),
"$label - expected view after set"
);
}
}
}
/**
* Test addView.
*/
public function testAddView()
{
$error = "Each view entry must be a 'depot' and 'client' array or a string.";
$tests = array(
array(
'label' => __LINE__ .': null, null',
'depot' => null,
'client' => null,
'error' => $error,
'expect' => array(),
),
array(
'label' => __LINE__ .': numeric, numeric',
'depot' => 1,
'client' => 2,
'error' => $error,
'expect' => array(),
),
array(
'label' => __LINE__ .': null, string',
'depot' => null,
'client' => 'string',
'error' => $error,
'expect' => array(),
),
array(
'label' => __LINE__ .': string, null',
'depot' => 'string',
'client' => null,
'error' => $error,
'expect' => array(),
),
array(
'label' => __LINE__ .': numeric, string',
'depot' => 1,
'client' => 'string',
'error' => $error,
'expect' => array(),
),
array(
'label' => __LINE__ .': string, numeric',
'depot' => 'string',
'client' => 1,
'error' => $error,
'expect' => array(),
),
array(
'label' => __LINE__ .': empty, empty',
'depot' => 'depot',
'client' => 'client',
'error' => false,
'expect' => array(
array(
'depot' => 'depot',
'client' => 'client',
),
),
),
);
foreach ($tests as $test) {
$label = $test['label'];
$client = new P4_Client;
try {
$client->addView($test['depot'], $test['client']);
if ($test['error']) {
$this->fail("$label - unexpected success");
}
} catch (InvalidArgumentException $e) {
if ($test['error']) {
$this->assertSame(
$test['error'],
$e->getMessage(),
'Expected error message.'
);
} else {
$this->fail("$label - unexpected argument exception.");
}
} catch (PHPUnit_Framework_AssertionFailedError $e) {
$this->fail($e->getMessage());
} catch (Exception $e) {
$this->fail(
"$label - Unexpected exception (". get_class($e)
.") - ". $e->getMessage()
);
}
if (!$test['error']) {
$this->assertSame(
$test['expect'],
$client->getView(),
"$label - expected view after set"
);
}
}
}
/**
* test the touchup view function
*/
public function testTouchUpView()
{
$expected = array(
array(
'depot' => '//depot/foo/...',
'client' => '//newclient/foo/...',
),
array(
'depot' => '//depot/foo/...',
'client' => '//newclient/foo/...',
),
array(
'depot' => '//depot/foo/...',
'client' => '//newclient/foo/...',
)
);
$client = new P4_Client;
$client->setView(
array(
'//depot/foo/... //oldclient-1/foo/...',
'//depot/foo/... //oldClient2/foo/...',
'//depot/foo/... //newclient/foo/...'
)
);
$client->setId('newclient')->touchUpView();
$this->assertSame($expected, $client->getView());
}
/**
* Test setOptionsSubmitOptions.
*/
public function testSetOptionsSubmitOptions()
{
$tests = array(
array(
'label' => __LINE__ .': null',
'options' => null,
'expect' => false,
'error' => true,
),
array(
'label' => __LINE__ .': empty string',
'options' => '',
'expect' => array(),
'error' => false,
),
array(
'label' => __LINE__ .': string',
'options' => 'bob',
'expect' => array('bob'),
'error' => false,
),
array(
'label' => __LINE__ .': integer',
'options' => 3,
'expect' => false,
'error' => true,
),
array(
'label' => __LINE__ .': array',
'options' => array(),
'expect' => array(),
'error' => false,
),
);
$types = array ('Options', 'SubmitOptions');
foreach ($types as $type) {
$typeLabel = ($type == 'SubmitOptions') ? 'Submit Options' : $type;
$setMethod = "set$type";
$getMethod = "get$type";
foreach ($tests as $test) {
$label = $test['label'];
$client = new P4_Client;
try {
$client->$setMethod($test['options']);
if ($test['error']) {
$this->fail("$label - unexpected success");
}
} catch (InvalidArgumentException $e) {
if ($test['error']) {
$this->assertSame(
"$typeLabel must be an array or string",
$e->getMessage(),
'Expected error message.'
);
} else {
$this->fail("$label - unexpected argument exception.");
}
} catch (PHPUnit_Framework_AssertionFailedError $e) {
$this->fail($e->getMessage());
} catch (Exception $e) {
$this->fail(
"$label - Unexpected exception (". get_class($e)
.") - ". $e->getMessage()
);
}
if (!$test['error']) {
$this->assertSame(
$test['expect'],
$client->$getMethod(),
"$label - expected $type after set"
);
}
}
}
}
/**
* Test setId, setDescription, setHost, setLineEnd, setOwner, setRoot.
*/
public function testSetIdDescriptionHostLineEndOwnerRoot()
{
$tests = array(
array(
'label' => __LINE__ .': null',
'value' => null,
'error' => false,
),
array(
'label' => __LINE__ .': empty string',
'value' => '',
'error' => false,
),
array(
'label' => __LINE__ .': string',
'value' => 'bob',
'error' => false,
),
array(
'label' => __LINE__ .': integer',
'value' => 3,
'error' => true,
),
);
$types = array('Id', 'Description', 'Host', 'LineEnd', 'Owner', 'Root');
foreach ($types as $type) {
$typeLabel = ($type == 'LineEnd') ? 'Line End' : $type;
$setMethod = "set$type";
$getMethod = "get$type";
foreach ($tests as $test) {
$label = $test['label'] ." ($type)";
$client = new P4_Client;
// setup the expected error message
$expectedError = "$typeLabel must be a string or null.";
// Client id validation fails on empty string now, which
// is the only exception (so far), so we special case it here.
if ($type == 'Id') {
$expectedError = 'Cannot set id. Id is invalid.';
if (preg_match('/empty string/', $label)) {
$test['error'] = true;
}
}
try {
$client->$setMethod($test['value']);
if ($test['error']) {
$this->fail("$label - unexpected success");
}
} catch (InvalidArgumentException $e) {
if ($test['error']) {
$this->assertSame(
$expectedError,
$e->getMessage(),
"$label - Expected error message."
);
} else {
$this->fail("$label - unexpected argument exception.");
}
} catch (PHPUnit_Framework_AssertionFailedError $e) {
$this->fail($e->getMessage());
} catch (Exception $e) {
$this->fail(
"$label - Unexpected exception (". get_class($e)
.") - ". $e->getMessage()
);
}
if (!$test['error']) {
$this->assertSame(
$test['value'],
$client->$getMethod(),
"$label - expected $type after set"
);
}
}
}
}
/**
* Test fetchAll filtered by Owner
*/
public function testFetchAllByOwner()
{
// 'test-client' will exist out of the gate; add a couple more to make it a real test.
$this->_createClients();
$byOwner = P4_Client::fetchAll(array(P4_Client::FETCH_BY_OWNER => 'user1'));
$this->assertSame(
2,
count($byOwner),
'Expected matching number of results'
);
$this->assertSame(
'test2-client',
$byOwner[0]->getId(),
'Expected first result client to match'
);
$this->assertSame(
'user1',
$byOwner[0]->getOwner(),
'Expected first result user to match'
);
$this->assertSame(
'test3-client',
$byOwner[1]->getId(),
'Expected second result client to match'
);
$this->assertSame(
'user1',
$byOwner[1]->getOwner(),
'Expected second result user to match'
);
// Verify invalid names causes error
$tests = array(
__LINE__ .' int' => 10,
__LINE__ .' bool' => false
);
foreach ($tests as $label => $value) {
try {
P4_Client::fetchAll(array(P4_Client::FETCH_BY_OWNER => $value));
$this->fail($label.': Expected filter to fail');
} catch (PHPUnit_Framework_AssertionFailedError $e) {
throw $e;
} catch (InvalidArgumentException $e) {
$this->assertSame(
'Filter by Owner expects a non-empty string as input',
$e->getMessage(),
$label.':Unexpected Exception message'
);
} catch (Exception $e) {
$this->fail(
$label.':Unexpected Exception ('. get_class($e) .'): '. $e->getMessage()
);
}
}
}
/**
* Test fetchAll filtered by Name
*/
public function testFetchAllByName()
{
// 'test-client' will exist out of the gate; add a couple more to make it a real test.
$this->_createClients();
$byOwner = P4_Client::fetchAll(array(P4_Client::FETCH_BY_NAME => 'test3-*'));
$this->assertSame(
2,
count($byOwner),
'Expected matching number of results'
);
$this->assertSame(
'test3-client',
$byOwner[0]->getId(),
'Expected first result client to match'
);
$this->assertSame(
'test3-clientb',
$byOwner[1]->getId(),
'Expected second result client to match'
);
// Verify invalid names causes error
$tests = array(
__LINE__ .' empty string' => "",
__LINE__ .' bool' => false
);
foreach ($tests as $label => $value) {
try {
P4_Client::fetchAll(array(P4_Client::FETCH_BY_NAME => $value));
$this->fail($label.': Expected filter to fail');
} catch (PHPUnit_Framework_AssertionFailedError $e) {
throw $e;
} catch (InvalidArgumentException $e) {
$this->assertSame(
'Filter by Name expects a non-empty string as input',
$e->getMessage(),
$label.':Unexpected Exception message'
);
} catch (Exception $e) {
$this->fail(
$label.':Unexpected Exception ('. get_class($e) .'): '. $e->getMessage()
);
}
}
}
/**
* Test fetchAll filtered by Owner and filtered by Name
*/
public function testFetchAllByOwnerAndName()
{
// 'test-client' will exist out of the gate; add a couple more to make it a real test.
$this->_createClients();
$byOwner = P4_Client::fetchAll(
array(
P4_Client::FETCH_BY_NAME => 'test3-*',
P4_Client::FETCH_BY_OWNER => 'user1'
)
);
$this->assertSame(
1,
count($byOwner),
'Expected matching number of results'
);
$this->assertSame(
'test3-client',
$byOwner[0]->getId(),
'Expected first result client to match'
);
}
/**
* Make some clients for testing fetch all.
*/
protected function _createClients()
{
$client = new P4_Client;
$client->setId('test2-client')
->setOwner('user1')
->setRoot(DATA_PATH . '/clients/test2-client')
->save();
$client->setId('test3-client')
->setOwner('user1')
->setRoot(DATA_PATH . '/clients/test3-client')
->save();
$client->setId('test3-clientb')
->setOwner('user2')
->setRoot(DATA_PATH . '/clients/test3-clientb')
->save();
}
/**
* Test creation of temp objects.
*/
public function testMakeTemp()
{
// ensure we only have one client at start
$this->assertSame(
array('test-client'),
P4_Client::fetchAll()->invoke('getId')
);
$client = P4_Client::makeTemp(array('Root' => DATA_PATH));
$callbackCount = 0;
$client2 = P4_Client::makeTemp(
array('Root' => DATA_PATH),
function($client, $defaultCallback) use (&$callbackCount)
{
$callbackCount++;
$defaultCallback($client);
}
);
$this->assertSame(
3,
count(P4_Client::fetchAll()),
'expected matching number of clients after our adds'
);
$client->getConnection()->disconnect();
$this->assertSame(
array('test-client'),
P4_Client::fetchAll()->invoke('getId'),
'expected matching number of clients after disconnect'
);
$this->assertSame(
1,
$callbackCount,
'expected our callback count to have incremented'
);
}
}