- <?php
- /**
- * Test methods for the P4 fielded model iterator.
- *
- * @copyright 2012 Perforce Software. All rights reserved.
- * @license Please see LICENSE.txt in top-level folder of this distribution.
- * @version <release>/<patch>
- */
-
- namespace P4Test\File;
-
- use P4Test\TestCase;
- use P4\File\File;
- use P4\Spec\User;
- use P4\Spec\Client;
- use P4\Spec\Change;
- use P4\File\Query as FileQuery;
- use P4\File\Exception\NotFoundException;
- use P4\File\Exception\Exception as FileException;
- use P4\Connection\Exception\CommandException;
-
- class Test extends TestCase
- {
- /**
- * Test fetchAll filespec handling.
- */
- public function testFetchAllSingular()
- {
- $tests = array(
- array(
- 'label' => __LINE__ .': null query',
- 'query' => FileQuery::create(),
- 'error' => 'Cannot fetch files. No filespecs provided in query.',
- ),
- array(
- 'label' => __LINE__ .': valid, but nonexistant filespec',
- 'query' => FileQuery::create()->addFilespec('//depot/foobartesting'),
- 'error' => '',
- ),
- array(
- 'label' => __LINE__ .': valid, but nonexistant depot filespec',
- 'query' => FileQuery::create()->addFilespec('//depotadsadsa/foobartesting'),
- 'error' => '',
- )
- );
-
- foreach ($tests as $test) {
- try {
- $files = File::fetchAll($test['query']);
- if ($test['error']) {
- $this->fail($test['label'] .' - unexpected success');
- }
- } catch (\InvalidArgumentException $e) {
- if ($test['error']) {
- $this->assertSame(
- $test['error'],
- $e->getMessage(),
- $test['label'] .' - Expected error'
- );
- } else {
- $this->fail($test['error'] .' - unexpected failure: '. $e->getMessage());
- }
- } catch (\Exception $e) {
- $this->fail($test['label'] .' - Unexpected exception: '. $e->getMessage());
- }
-
- }
- }
-
- /**
- * Test fetchAll with multiple filespecs.
- */
- public function testFetchAllMultiple()
- {
- $basePath = '//depot/';
- $testFiles = $this->prepareFetchAllTests($basePath, false);
-
- $query = FileQuery::create()->addFilespecs(array($basePath .'*small.txt', $basePath .'medium.jpg'));
- $files = File::fetchAll($query);
-
- $filenames = array();
- foreach ($files as $file) {
- $filenames[] = $file->getFilespec();
- }
- $this->assertSame(
- array(
- '//depot/another_small.txt',
- '//depot/small.txt',
- '//depot/medium.jpg',
- ),
- $filenames,
- "Expected matching filenames when using multiple filespecs."
- );
- }
-
- /**
- * Test sync and flush.
- */
- public function testSyncFlush()
- {
- // ensure sync of non-existent file throws exception.
- $file = new File;
- $file->setFilespec('//depot/non-existent-file');
- try {
- $file->sync();
- $this->fail("Excepted exception syncing non-existent file.");
- } catch (FileException $e) {
- $this->assertTrue(true);
- }
-
- // ensure flush of non-existent file throws exception.
- try {
- $file->flush();
- $this->fail("Excepted exception syncing non-existent file.");
- } catch (FileException $e) {
- $this->assertTrue(true);
- }
-
- // create a file
- $file = new File;
- $content = 'Content.';
- $file->setFilespec('//depot/file.txt')
- ->add()
- ->setLocalContents($content)
- ->submit('Add file.');
- $this->assertTrue(
- is_file($file->getLocalFilename()),
- 'Expect file to exist after create/submit.'
- );
-
- // delete client file
- $file->deleteLocalFile();
- $this->assertFalse(
- is_file($file->getLocalFilename()),
- 'Expect file to no longer exist after delete.'
- );
-
- // sync the file; should fail as server thinks we have the file.
- $file->sync();
- $this->assertFalse(
- is_file($file->getLocalFilename()),
- 'Expect file to still exist after sync without force.'
- );
-
- // sync again, with force.
- $file->sync(true);
- $this->assertTrue(
- is_file($file->getLocalFilename()),
- 'Expect file to now exist after sync with force.'
- );
-
- // verify content
- $this->assertSame(
- $content,
- $file->getLocalContents(),
- 'Expected content after sync.'
- );
-
- // revise content and flush; sync should not affect client file.
- $newContent = 'Some new content.';
- $file->setLocalContents($newContent)
- ->flush()
- ->sync();
- $this->assertSame(
- $newContent,
- $file->getLocalContents(),
- 'Expected content after flush/sync'
- );
-
- // force sync again, content should revert to original.
- $file->sync(true);
- $this->assertSame(
- $content,
- $file->getLocalContents(),
- 'Expected content after force sync'
- );
- }
-
- /**
- * Test getBasename.
- */
- public function testGetBasename()
- {
- $file = new File;
- $path = 'a/path/to/a/file.txt';
- $root = $this->p4->getClientRoot();
- $filespec = "$root/$path";
- $file->setFilespec($filespec);
-
- $this->assertEquals(
- 'file.txt',
- $file->getBasename(),
- 'Expected basename'
- );
- }
-
- /**
- * Test getExtension.
- */
- public function testGetExtension()
- {
- $file = new File;
- $path = 'a/path/to/a/file.txt';
- $root = $this->p4->getClientRoot();
- $filespec = "$root/$path";
- $file->setFilespec($filespec);
-
- $this->assertEquals(
- 'txt',
- $file->getExtension(),
- 'Expected extension'
- );
- }
-
- /**
- * Test getFileSize and getLocalFileSize.
- */
- public function testGetFileSizeAndGetLocalFileSize()
- {
-
- $basePath = '//depot/testFileSize/';
- $files = $this->prepareFetchAllTests($basePath);
-
- $expectedSizes = array(
- 'small.txt' => 13,
- 'another_small.txt' => 13,
- 'medium.jpg' => 40,
- 'ze_medium_2.jpg' => 40,
- 'large.txt' => 3599,
- 'opened.txt' => 7,
- );
-
- foreach ($files as $file) {
- $filename = basename($file->getFilespec());
- if ($filename === 'opened.txt') {
- $this->assertSame(
- $expectedSizes[$filename],
- $file->getLocalFileSize(),
- "Expected filesize for '$filename'"
- );
- } else {
- $this->assertSame(
- $expectedSizes[$filename],
- $file->getFilesize(),
- "Expected filesize for '$filename'"
- );
- }
- }
-
- // test getting sizes for non-existant files.
- $file = new File;
- $file->setFilespec('//depot/does_not_exist.txt');
-
- try {
- $size = $file->getFileSize();
- $this->fail("Unexpected success for getFileSize().");
- } catch (FileException $e) {
- $this->assertSame(
- 'The file does not have a fileSize attribute.',
- $e->getMessage(),
- 'Expected error for getFileSize().'
- );
- } catch (\Exception $e) {
- $this->fail(
- "Unexpected exception for getFileSize() ("
- . get_class($e) .') :'. $e->getMessage()
- );
- }
-
- try {
- $size = $file->getLocalFileSize();
- $this->fail("Unexpected success for getLocalFileSize().");
- } catch (FileException $e) {
- $this->assertSame(
- 'The local file does not exist.',
- $e->getMessage(),
- 'Expected error for getLocalFileSize().'
- );
- } catch (\Exception $e) {
- $this->fail(
- "Unexpected exception for getLocalFileSize() ("
- . get_class($e) .') :'. $e->getMessage()
- );
- }
- }
-
- /**
- * Test filename in local-file syntax.
- */
- public function testFilenameInLocalSyntax()
- {
- $file = new File;
- $path = 'a/path/to/a/file.txt';
- $root = $this->p4->getClientRoot();
- $filespec = "$root/$path";
- $file->setFilespec($filespec);
-
- $this->assertSame(
- $filespec,
- $file->getLocalFilename(),
- 'Expected local filename.'
- );
-
- $this->assertSame(
- "//depot/$path",
- $file->getDepotFilename(),
- 'Expected depot filename.'
- );
-
- // test file object with no filespec set
- $file = new File;
- try {
- $file->getLocalFilename();
- $this->fail('Unexpected success for getLocalFilename with no filespec');
- } catch (FileException $e) {
- $this->assertSame(
- 'Cannot complete operation, no filespec has been specified',
- $e->getMessage(),
- 'Expected error for getLocalFilename with no filespec.'
- );
- } catch (\Exception $e) {
- $this->fail(
- 'Unexpected exception for getLocalFilename with no filespec ('
- . get_class($e) .') :'. $e->getMessage()
- );
- }
- try {
- $file->getDepotFilename();
- $this->fail('Unexpected success for getDepotFilename with no filespec');
- } catch (FileException $e) {
- $this->assertSame(
- 'Cannot complete operation, no filespec has been specified',
- $e->getMessage(),
- 'Expected error for getDepotFilename with no filespec.'
- );
- } catch (\Exception $e) {
- $this->fail(
- 'Unexpected exception for getDepotFilename with no filespec ('
- . get_class($e) .') :'. $e->getMessage()
- );
- }
- }
-
- /**
- * Test count method.
- */
- public function testCount()
- {
- if (getenv('SKIP_LONG_TESTS')) {
- $this->markTestSkipped('long fetchAll test skipped, because asked');
- return;
- }
-
- $basePath = '//depot/testFetchOptions/';
- $testFiles = $this->prepareFetchAllTests($basePath, true);
-
- $tests = array(
- // sorting tests
- array(
- 'label' => __LINE__ .': defaults',
- 'query' => FileQuery::create(),
- 'expected' => 6,
- ),
- array(
- 'label' => __LINE__ .': reversed default sort',
- 'query' => FileQuery::create()->setReverseOrder(true),
- 'expected' => 6,
- ),
- array(
- 'label' => __LINE__ .': sort',
- 'query' => FileQuery::create()->setSortBy('fileSize'),
- 'expected' => 6,
- ),
- array(
- 'label' => __LINE__ .': reversed sort',
- 'query' => FileQuery::create()->setReverseOrder(true)->setSortBy('fileSize'),
- 'expected' => 6,
- ),
-
- // limit results tests (limits should have no effect)
- array(
- 'label' => __LINE__ .': limit',
- 'query' => FileQuery::create()->setMaxFiles(1),
- 'expected' => 1,
- ),
- array(
- 'label' => __LINE__ .': reversed limit',
- 'query' => FileQuery::create()->setMaxFiles(1)->setReverseOrder(true),
- 'expected' => 1,
- ),
-
- // filtering tests
- array(
- 'label' => __LINE__ .': filter fileSize > 1000',
- 'query' => FileQuery::create()->setFilter('fileSize > 1000'),
- 'expected' => 1,
- ),
- array(
- 'label' => __LINE__ .': filter fileSize <= 1000',
- 'query' => FileQuery::create()->setFilter('fileSize <= 1000'),
- 'expected' => 4,
- ),
- array(
- 'label' => __LINE__ .': filter scrunchy',
- 'query' => FileQuery::create()->setFilter('scrunchy'),
- 'expected' => 0,
- ),
- array(
- 'label' => __LINE__ .': filter with existing rowNumber',
- 'query' => FileQuery::create()->setFilter('fileSize <= 1000 & rowNumber >= 4'),
- 'expected' => 1,
- ),
- array(
- 'label' => __LINE__ .': filter with rowNumber existing',
- 'query' => FileQuery::create()->setFilter('rowNumber >= 5 & fileSize <= 1000'),
- 'expected' => 0,
- ),
- array(
- 'label' => __LINE__ .': filter with existing rowNumber existing',
- 'query' => FileQuery::create()->setFilter('fileSize <= 1000 rowNumber >= 2 & fileSize <= 1000'),
- 'expected' => 3,
- ),
-
- // change and content tests
- array(
- 'label' => __LINE__ .': change 1',
- 'query' => FileQuery::create()->setLimitToChangelist(1),
- 'expected' => 1,
- ),
-
- // opened tests
- array(
- 'label' => __LINE__ .': opened',
- 'query' => FileQuery::create()->setLimitToOpened(true),
- 'expected' => 1,
- ),
- );
-
- foreach ($tests as $test) {
- $label = $test['label'];
- $file = new File;
- $count = null;
-
- $test['query']->addFilespec($basePath .'...');
- try {
- $count = File::count($test['query']);
- } catch (\Exception $e) {
- $this->fail("$label - unexpected failure (". get_class($e) .': '. $e->getMessage());
- }
-
- if (array_key_exists('dump', $test)) {
- var_dump($file->getConnection()->run('fstat', array('-Ol', '//...')));
- exit;
- }
-
- $this->assertEquals(
- $test['expected'],
- $count,
- "$label - expected count"
- );
- }
- }
-
- /**
- * Test count with no filespec.
- */
- public function testCountWithoutFilespec()
- {
- try {
- $count = File::count(new FileQuery);
- $this->fail('Unexpected success');
- } catch (\PHPUnit\Framework\AssertionFailedError $e) {
- $this->fail($e->getMessage());
- } catch (\InvalidArgumentException $e) {
- $this->assertSame(
- 'Cannot count files. No filespecs provided in query.',
- $e->getMessage(),
- 'Expected exception'
- );
- } catch (\Exception $e) {
- $this->fail('Unexpected exception ('. get_class($e) .') :'. $e->getMessage());
- }
- }
-
- /**
- * Test fetchAll options.
- *
- * @todo fixup and remove skip for sorting tests when/if server sorts
- * by size/data properly.
- */
- public function testFetchAllOptions()
- {
- if (getenv('SKIP_LONG_TESTS')) {
- $this->markTestSkipped('long fetchAll test skipped, because asked');
- return;
- }
-
- $basePath = '//depot/testFetchOptions/';
- $testFiles = $this->prepareFetchAllTests($basePath, true);
-
- $tests = array(
- // sorting tests
- array(
- 'label' => __LINE__ .': defaults',
- 'query' => FileQuery::create()->addFilespec($basePath .'...'),
- 'expected' => array(
- 'another_small.txt',
- 'large.txt',
- 'medium.jpg',
- 'opened.txt',
- 'small.txt',
- 'ze_medium_2.jpg',
- ),
- 'content' => false,
- ),
- array(
- 'label' => __LINE__ .': reversed default sort',
- 'query' => FileQuery::create()->addFilespec($basePath .'...')
- ->setReverseOrder(true),
- 'expected' => array(
- 'ze_medium_2.jpg',
- 'small.txt',
- 'opened.txt',
- 'medium.jpg',
- 'large.txt',
- 'another_small.txt',
- ),
- 'content' => false,
- ),
- array(
- 'label' => __LINE__ .': filesize sort',
- 'query' => FileQuery::create()->addFilespec($basePath .'...')
- ->setSortBy(FileQuery::SORT_FILE_SIZE),
- 'expected' => array(
- 'opened.txt',
- 'another_small.txt',
- 'small.txt',
- 'medium.jpg',
- 'ze_medium_2.jpg',
- 'large.txt',
- ),
- 'content' => false,
- ),
-
- array(
- 'label' => __LINE__ .': reversed filesize sort',
- 'query' => FileQuery::create()->addFilespec($basePath .'...')
- ->setSortBy(FileQuery::SORT_FILE_SIZE)
- ->setReverseOrder(true),
- 'expected' => array(
- 'large.txt',
- 'medium.jpg',
- 'ze_medium_2.jpg',
- 'another_small.txt',
- 'small.txt',
- 'opened.txt',
- ),
- 'content' => false,
- ),
- array(
- 'label' => __LINE__ .': date sort',
- 'query' => FileQuery::create()->addFilespec($basePath .'...')
- ->setSortBy(FileQuery::SORT_DATE),
- 'expected' => array(
- 'opened.txt',
- 'small.txt',
- 'medium.jpg',
- 'large.txt',
- 'another_small.txt',
- 'ze_medium_2.jpg',
- ),
- 'content' => false,
- ),
- array(
- 'label' => __LINE__ .': reversed date sort',
- 'query' => FileQuery::create()->addFilespec($basePath .'...')
- ->setSortBy(FileQuery::SORT_DATE)
- ->setReverseOrder(true),
- 'expected' => array(
- 'ze_medium_2.jpg',
- 'another_small.txt',
- 'large.txt',
- 'medium.jpg',
- 'small.txt',
- 'opened.txt',
- ),
- 'content' => false,
- ),
- array(
- 'label' => __LINE__ .': filetype sort',
- 'query' => FileQuery::create()->addFilespec($basePath .'...')
- ->setSortBy(FileQuery::SORT_FILE_TYPE),
- 'expected' => array(
- 'medium.jpg',
- 'ze_medium_2.jpg',
- 'another_small.txt',
- 'large.txt',
- 'opened.txt',
- 'small.txt',
- ),
- 'content' => false,
- ),
- array(
- 'label' => __LINE__ .': reversed filetype sort',
- 'query' => FileQuery::create()->addFilespec($basePath .'...')
- ->setSortBy(FileQuery::SORT_FILE_TYPE)
- ->setReverseOrder(true),
- 'expected' => array(
- 'another_small.txt',
- 'large.txt',
- 'opened.txt',
- 'small.txt',
- 'medium.jpg',
- 'ze_medium_2.jpg',
- ),
- 'content' => false,
- ),
- array(
- 'label' => __LINE__ .': attribute sort',
- 'query' => FileQuery::create()->addFilespec($basePath .'...')
- ->setSortBy('foo'),
- 'expected' => array(
- 'opened.txt',
- 'ze_medium_2.jpg',
- 'large.txt',
- 'medium.jpg',
- 'another_small.txt',
- 'small.txt',
- ),
- 'content' => false,
- ),
- array(
- 'label' => __LINE__ .': reversed attribute sort',
- 'query' => FileQuery::create()->addFilespec($basePath .'...')
- ->setSortBy('foo', array(FileQuery::SORT_DESCENDING)),
- 'expected' => array(
- 'another_small.txt',
- 'small.txt',
- 'medium.jpg',
- 'large.txt',
- 'ze_medium_2.jpg',
- 'opened.txt',
- ),
- 'content' => false,
- ),
- array(
- 'label' => __LINE__ .': attribute + date sort',
- 'query' => FileQuery::create()->addFilespec($basePath .'...')
- ->setSortBy(array('foo', FileQuery::SORT_DATE)),
- 'expected' => array(
- 'opened.txt',
- 'ze_medium_2.jpg',
- 'large.txt',
- 'medium.jpg',
- 'small.txt',
- 'another_small.txt',
- ),
- 'content' => false,
- ),
-
- // limit results tests
- array(
- 'label' => __LINE__ .': limit 1',
- 'query' => FileQuery::create()->addFilespec($basePath .'...')
- ->setMaxFiles(1),
- 'expected' => array(
- 'another_small.txt',
- ),
- 'content' => false,
- ),
- array(
- 'label' => __LINE__ .': reversed limit 1',
- 'query' => FileQuery::create()->addFilespec($basePath .'...')
- ->setMaxFiles(1)
- ->setReverseOrder(true),
- 'expected' => array(
- 'ze_medium_2.jpg',
- ),
- 'content' => false,
- ),
- array(
- 'label' => __LINE__ .': limit 2',
- 'query' => FileQuery::create()->addFilespec($basePath .'...')
- ->setMaxFiles(2),
- 'expected' => array(
- 'another_small.txt',
- 'large.txt',
- ),
- 'content' => false,
- ),
- array(
- 'label' => __LINE__ .': reversed limit 2',
- 'query' => FileQuery::create()->addFilespec($basePath .'...')
- ->setMaxFiles(2)
- ->setReverseOrder(true),
- 'expected' => array(
- 'ze_medium_2.jpg',
- 'small.txt',
- ),
- 'content' => false,
- ),
-
- // filtering tests
- array(
- 'label' => __LINE__ .': filter fileSize > 1000',
- 'query' => FileQuery::create()->addFilespec($basePath .'...')
- ->setFilter('fileSize > 1000'),
- 'expected' => array(
- 'large.txt',
- ),
- 'content' => false,
- ),
- array(
- 'label' => __LINE__ .': filter fileSize <= 1000',
- 'query' => FileQuery::create()->addFilespec($basePath .'...')
- ->setFilter('fileSize <= 1000'),
- 'expected' => array(
- 'another_small.txt',
- 'medium.jpg',
- 'small.txt',
- 'ze_medium_2.jpg',
- ),
- 'content' => false,
- ),
-
- // change and content tests
- array(
- 'label' => __LINE__ .': change 1',
- 'query' => FileQuery::create()->addFilespec($basePath .'...')
- ->setLimitToChangelist(1),
- 'expected' => array(
- basename($testFiles[0]->getFilespec()),
- ),
- 'content' => false,
- ),
- array(
- 'label' => __LINE__ .': change 2',
- 'query' => FileQuery::create()->addFilespec($basePath .'...')
- ->setLimitToChangelist(2),
- 'expected' => array(
- basename($testFiles[1]->getFilespec()),
- ),
- 'content' => true,
- ),
- array(
- 'label' => __LINE__ .': change 3',
- 'query' => FileQuery::create()->addFilespec($basePath .'...')
- ->setLimitToChangelist(3),
- 'expected' => array(
- basename($testFiles[2]->getFilespec()),
- ),
- 'content' => true,
- ),
- array(
- 'label' => __LINE__ .': change 4',
- 'query' => FileQuery::create()->addFilespec($basePath .'...')
- ->setLimitToChangelist(4),
- 'expected' => array(
- basename($testFiles[3]->getFilespec()),
- ),
- 'content' => true,
- ),
- array(
- 'label' => __LINE__ .': change 5',
- 'query' => FileQuery::create()->addFilespec($basePath .'...')
- ->setLimitToChangelist(5),
- 'expected' => array(
- basename($testFiles[4]->getFilespec()),
- ),
- 'content' => true,
- ),
- array(
- 'label' => __LINE__ .': change default',
- 'query' => FileQuery::create()->addFilespec($basePath .'...')
- ->setLimitToChangelist('default'),
- 'expected' => array(
- basename($testFiles[5]->getFilespec()),
- ),
- 'content' => true,
- ),
-
- // opened tests
- array(
- 'label' => __LINE__ .': opened',
- 'query' => FileQuery::create()->addFilespec($basePath .'...')
- ->setLimitToOpened(true),
- 'expected' => array(
- basename($testFiles[5]->getFilespec()),
- ),
- 'content' => true,
- ),
- );
-
- $showSizes = 0;
- foreach ($tests as $test) {
- $label = $test['label'];
- $file = new File;
-
- if (array_key_exists('dumpQuery', $test) and $test['dumpQuery']) {
- print var_export($test['query']->toArray(), true);
- }
- try {
- $files = File::fetchAll($test['query']);
- } catch (\Exception $e) {
- // ignore exception if we detect an attribute sort for server version < 2011.1
- if ($e instanceof \P4\File\Exception\Exception
- && in_array('-S', $test['query']->getFstatFlags())
- && !$this->p4->isServerMinVersion('2011.1')
- ) {
- continue;
- }
- $this->fail("$label - unexpected failure: ". $e->getMessage());
- }
-
- if (array_key_exists('dump', $test)) {
- var_dump($file->getConnection()->run('info'));
- var_dump($file->getConnection()->run('fstat', array('-Oal', '//depot/testFetchOptions/...')));
- exit;
- }
-
- $this->assertEquals(
- count($test['expected']),
- count($files),
- "$label - expected file count"
- );
- $fileNames = array();
- foreach ($files as $file) {
- $filename = $file->getFilespec();
- $filesize = $file->getLocalFileSize();
- $fileNames[] = basename($file->getFilespec());
- if ($showSizes) {
- print "'$filename' is '$filesize' bytes.\n";
- }
- }
- $showSizes = 0;
-
- $this->assertSame(
- $test['expected'],
- $fileNames,
- "$label - expected file list"
- );
-
- if ($test['content']) {
- for ($i = 0; $i < count($test['expected']); $i++) {
- $method = ($testFiles[$test['expected'][$i]]->isOpened()) ? 'getLocalContents' : 'getDepotContents';
- $this->assertSame(
- $testFiles[$test['expected'][$i]]->$method(),
- $files[$i]->$method(),
- "$label - Expected content for file #$i"
- );
- }
- }
- }
- }
-
- /**
- * Verify we are doing a proper natural order sort on attributes
- */
- public function testNaturalSort()
- {
- $basePath = "//depot/test/";
- $file = new File;
- $file->setFilespec($basePath .'10.txt')
- ->open()
- ->setLocalContents('i am a file')
- ->setAttribute('foo', 'give-me-a-10')
- ->submit('10');
- $file->setFilespec($basePath .'2.txt')
- ->open()
- ->setLocalContents('i am a file')
- ->setAttribute('foo', 'give-me-a-2')
- ->submit('2');
- $file->setFilespec($basePath .'1.txt')
- ->open()
- ->setLocalContents('i am a file')
- ->setAttribute('foo', 'give-me-a-1')
- ->submit('1');
- $file->setFilespec($basePath .'just1.txt')
- ->open()
- ->setLocalContents('i am a file')
- ->setAttribute('foo', '1')
- ->submit('just digit 1');
- $file->setFilespec($basePath .'a.txt')
- ->open()
- ->setLocalContents('i am a file')
- ->setAttribute('foo', 'a')
- ->submit('a');
- $file->setFilespec($basePath .'Aa.txt')
- ->open()
- ->setLocalContents('i am a file')
- ->setAttribute('foo', 'Aa')
- ->submit('A');
- $file->setFilespec($basePath .'z.txt')
- ->open()
- ->setLocalContents('i am a file')
- ->setAttribute('foo', 'z')
- ->submit('z');
- $file->setFilespec($basePath .'Zz.txt')
- ->open()
- ->setLocalContents('i am a file')
- ->setAttribute('foo', 'Zz')
- ->submit('Zz');
-
- try {
- $foos = File::fetchAll(
- FileQuery::create()->setFilespecs($basePath . "...")->setSortBy('foo')
- );
- } catch (\P4\File\Exception\Exception $e) {
- if (!$this->p4->isServerMinVersion('2011.1')) {
- $this->markTestSkipped('Skipping attribute sort for server versions < 2011.1');
- return;
- }
- throw $e;
- }
-
- $this->assertSame(
- array(
- '1',
- 'a',
- 'Aa',
- 'give-me-a-1',
- 'give-me-a-2',
- 'give-me-a-10',
- 'z',
- 'Zz'
- ),
- $foos->invoke('getAttribute', array('foo')),
- 'Expecting sorted attributes'
- );
- }
-
- /**
- * Test an already opened file.
- */
- public function testAlreadyOpened()
- {
- $file = new File;
- $file->setFilespec('//depot/notAlreadyOpened.txt');
- $this->assertFalse($file->exists($file->getFilespec()), 'Expect file to not exist #1.');
- $this->assertFalse($file->isOpened(), 'Expect file to not be opened #1.');
-
- $file->open()->setLocalContents('Some content.');
- $this->assertFalse($file->exists($file->getFilespec()), 'Still expect file to not exist #1.');
- $this->assertTrue($file->isOpened(), 'Expect file to be opened #1.');
-
- $file->open();
- $this->assertFalse($file->exists($file->getFilespec()), 'Still expect file to not exist #1.');
- $this->assertTrue($file->isOpened(), 'Expect file to still be opened #1.');
- $file->revert();
-
- // once again, with initial add instead of open
- $file = new File;
- $file->setFilespec('//depot/notAlreadyOpened.txt');
- $this->assertFalse($file->exists($file->getFilespec()), 'Expect file to not exist #2.');
- $this->assertFalse($file->isOpened(), 'Expect file to not be opened. #2');
-
- $file->add(null, 'binary')->setLocalContents('Some content.');
- $this->assertFalse($file->exists($file->getFilespec()), 'Still expect file to not exist #2.');
- $this->assertTrue($file->isOpened(), 'Expect file to be opened. #2');
-
- $file->open();
- $this->assertFalse($file->exists($file->getFilespec()), 'Still expect file to not exist #2.');
- $this->assertTrue($file->isOpened(), 'Expect file to still be opened #2.');
- }
-
- /**
- * Test file deletion.
- *
- * @todo enable when appropriate error handling exists
- */
- public function testFileDeletion()
- {
- // first, create a file to delete.
- $file = new File;
- $file->setFilespec('//depot/a_file_to_delete.txt');
- $this->assertFalse($file->exists($file->getFilespec()), 'Expect file to not exist.');
- $file->open()
- ->setLocalContents('Some content to delete.')
- ->submit('Adding a file to delete.');
- $this->assertTrue((bool)$file->exists($file->getFilespec()), 'Expect file to exist.');
- $this->assertFalse($file->isDeleted(), 'Expect file to not have deleted status after create');
-
- // expect file to still exist if exclude deleted is true.
- $this->assertTrue(
- (bool)File::exists($file->getFilespec(), null, true),
- "Expected file to exist with excluded deleted = true."
- );
-
- // test deleting the opened file.
- $file->open();
- $this->assertTrue($file->isOpened(), 'Expect file to be opened.');
-
- // first, with force set to false
- try {
- $file->delete(null, false);
- $this->fail('Unexpected success deleting an opened file without force.');
- } catch (FileException $e) {
- $this->assertSame(
- "Failed to open file for delete: //depot/a_file_to_delete.txt"
- . " - can't delete (already opened for edit)",
- $e->getMessage(),
- 'Expected error message deleting an opened file without force.'
- );
- } catch (\PHPUnit\Framework\AssertionFailedError $e) {
- $this->fail($e->getMessage());
- } catch (\Exception $e) {
- $this->fail('Unexpected exception on delete opened file: '. $e->getMessage());
- }
-
- // again with force defaulting to true
- try {
- $file->delete();
- } catch (\Exception $e) {
- $this->fail('Unexpected exception on delete opened file: '. $e->getMessage());
- }
-
- // test deleting the file again.
- try {
- $file->delete();
- } catch (\Exception $e) {
- $this->fail('Unexpected exception on delete opened file again: '. $e->getMessage());
- }
-
- // now submit the deletion.
- $file->submit('Delete the file.');
- $this->assertTrue((bool)$file->exists($file->getFilespec()), 'Expect file to still exist.');
- $this->assertTrue(
- $file->hasStatusField('headAction')
- && $file->getStatus('headAction') == 'delete',
- 'Expect file to be deleted'
- );
- $this->assertTrue($file->isDeleted(), 'Expect file to have deleted status after delete.');
-
- // expect file to not exist if exclude deleted is true.
- $this->assertFalse(
- File::exists($file->getFilespec(), null, true),
- "Expected file to not exist with excluded deleted = true."
- );
-
- // test deleting the file again after submission.
- try {
- $file->delete();
- $this->fail('Unexpected success deleting an already deleted file');
- } catch (FileException $e) {
- $this->assertSame(
- "Failed to open file for delete: //depot/a_file_to_delete.txt - file(s) not on client.",
- $e->getMessage(),
- 'Expected error message deleting an already deleted file.'
- );
- } catch (\Exception $e) {
- $this->fail('Unexpected exception on delete deleted file: '. $e->getMessage());
- }
- }
-
- /**
- * Test edit after delete.
- */
- public function testEditAfterDelete()
- {
- $file = new File;
- $file->setFilespec('//depot/file.txt')
- ->add()
- ->setLocalContents('Some content.')
- ->submit('Created it.');
-
- // delete the file, and then attempt to edit it with force=false.
- $file->delete();
- try {
- $file->edit(null, null, false);
- $this->fail('Unexpected success editing a file opened for delete');
- } catch (FileException $e) {
- $this->assertSame(
- "Failed to open file for edit: //depot/file.txt - can't edit (already opened for delete)",
- $e->getMessage(),
- 'Expected error editing a file opened for delete.'
- );
- } catch (\PHPUnit\Framework\AssertionFailedError $e) {
- $this->fail($e->getMessage());
- } catch (\Exception $e) {
- $this->fail(
- 'Unexpected exception editing a file opened for delete ('
- . get_class($e) .'): '. $e->getMessage()
- );
- }
-
- // try to edit again, with force set. Should succeed.
- $file->edit(null, null, true)
- ->setLocalContents('New text.')
- ->submit('Update after delete.');
- }
-
- /**
- * Test invalid submit description.
- */
- public function testInvalidSubmitDescription()
- {
- $tests = array(
- array(
- 'label' => __LINE__ .': null description',
- 'description' => null,
- 'error' => new \InvalidArgumentException(
- 'Cannot submit. Description must be a non-empty string.'
- ),
- ),
- array(
- 'label' => __LINE__ .': empty description',
- 'description' => '',
- 'error' => new \InvalidArgumentException(
- 'Cannot submit. Description must be a non-empty string.'
- ),
- ),
- array(
- 'label' => __LINE__ .': array description',
- 'description' => array('1', '2'),
- 'error' => new \InvalidArgumentException(
- 'Cannot submit. Description must be a non-empty string.'
- ),
- ),
- array(
- 'label' => __LINE__ .': 0 description',
- 'description' => 0,
- 'error' => new \InvalidArgumentException(
- 'Cannot submit. Description must be a non-empty string.'
- ),
- ),
- array(
- 'label' => __LINE__ .': 1 description',
- 'description' => 1,
- 'error' => new \InvalidArgumentException(
- 'Cannot submit. Description must be a non-empty string.'
- ),
- ),
- array(
- 'label' => __LINE__ .': string description',
- 'description' => 'abcde',
- 'error' => false,
- ),
- );
-
- $counter = 0;
- foreach ($tests as $test) {
- $label = $test['label'];
- $file = new File;
- $file->setFilespec('//depot/file'. $counter++ .'.txt')
- ->add()
- ->setLocalContents('Content');
- try {
- $file->submit($test['description']);
- if ($test['error']) {
- $this->fail("$label - unexpected success");
- }
- } catch (\PHPUnit\Framework\AssertionFailedError $e) {
- $this->fail($e->getMessage());
- } catch (\Exception $e) {
- if ($test['error']) {
- $this->assertSame(
- get_class($test['error']),
- get_class($e),
- "$label - expected exception class: ". $e->getMessage()
- );
- $this->assertSame(
- $test['error']->getMessage(),
- $e->getMessage(),
- "$label - expected error message."
- );
- } else {
- $this->fail(
- "$label - unexpected exception ("
- . get_class($e) .') :'. $e->getMessage()
- );
- }
- }
- }
- }
-
- /**
- * Test setStatusCache.
- */
- public function testSetStatusCache()
- {
- $file = new File;
- $file->setFilespec('//depot/file')->add()->setLocalContents('A')->submit('A');
- $originalStatus = $modifiedStatus = $file->getStatus();
- foreach ($modifiedStatus as $key => $value) {
- $modifiedStatus[$key] = 'head';
- }
- $file->setStatusCache($modifiedStatus);
- $this->assertSame(
- $modifiedStatus,
- $file->getStatus(),
- 'Expected modified status'
- );
-
- $file->clearStatusCache();
- $this->assertSame(
- $originalStatus,
- $file->getStatus(),
- 'Expected original status'
- );
-
- try {
- $file->setStatusCache(1);
- $this->fail('Unexpected success setting numeric status');
- } catch (\InvalidArgumentException $e) {
- $this->assertSame(
- 'Cannot set status cache. Status must be an array.',
- $e->getMessage(),
- 'Expected error setting numeric status'
- );
- } catch (\Exception $e) {
- $this->fail(
- 'Unexpected exception setting numeric status ('
- . get_class($e) .') '. $e->getMessage()
- );
- }
- }
-
- /**
- * Test open attributes.
- */
- public function testOpenAttributes()
- {
- // setup a file
- $file = new File;
- $file->setFilespec('//depot/attribute_test.txt');
- $this->assertFalse($file->exists($file->getFilespec()), 'Expect file to not exist.');
- $file->open();
-
- // test that it has no attributes
- $attributes = $file->getAttributes();
- $this->assertSame(0, count($attributes), 'Expected attribute count on new file.');
-
- // verify lack of attribute
- $this->assertFalse($file->hasAttribute('foobar'), 'Expect depot foobar to not exist.');
- $this->assertFalse($file->hasOpenAttribute('foobar'), 'Expect client foobar to not exist.');
-
- // set the attribute
- $file->setAttribute('foobar', 'bazbar', false, false);
-
- // check that set attribute requires a string
- try {
- $file->setAttribute('fooerror', 2, false, false);
- $this->fail('Unexpected success setting attribute without string');
- } catch (\PHPUnit\Framework\AssertionFailedError $e) {
- $this->fail($e->getMessage());
- } catch (\InvalidArgumentException $e) {
- $this->assertEquals(
- 'Cannot set attribute. Value must be a string.',
- $e->getMessage(),
- 'Expected exception setting attribute without string'
- );
- } catch (\Exception $e) {
- $this->fail('Unexpected exception ('. get_class($e) .': '. $e->getMessage());
- }
-
- // check that depot attribute is not set
- $attributes = $file->getAttributes(false);
- $this->assertSame(0, count($attributes), 'Expected depot attribute count after setting attribute.');
-
- // check that client attribute is set
- $attributes = $file->getAttributes(true);
- $this->assertSame(1, count($attributes), 'Expected client attribute count after setting attribute.');
- $this->assertTrue($file->hasOpenAttribute('foobar'), 'Expect client foobar to exist.');
- $this->assertFalse($file->hasAttribute('foobar'), 'Expect depot foobar to not exist.');
-
- // verify the attribute value
- $this->assertSame(
- 'bazbar',
- $file->getOpenAttribute('foobar'),
- 'Expected client foobar value.'
- );
- try {
- $value = $file->getAttribute('foobar');
- $this->fail('Unexpected success getting depot foobar.');
- } catch (FileException $e) {
- $this->assertSame(
- "Can't fetch status. The requested field "
- . "('attr-foobar') does not exist.",
- $e->getMessage(),
- 'Expected exception using getAttribute on open attribute'
- );
- } catch (\Exception $e) {
- $this->fail(
- 'Unexpected exception when getting open attribute: '. $e->getMessage()
- ."\n$e"
- );
- }
-
- // clear the attribute
- $file->clearAttribute('foobar', false);
-
- // verify lack of attribute
- $this->assertFalse($file->hasOpenAttribute('foobar'), 'Expect client foobar to no longer exist.');
- $this->assertFalse($file->hasAttribute('foobar'), 'Expect depot foobar to still not exist.');
- }
-
- /**
- * Test depot attributes.
- */
- public function testDepotAttributes()
- {
- // setup a file
- $file = new File;
- $file->setFilespec('//depot/attribute_test.txt');
- $this->assertFalse($file->exists($file->getFilespec()), 'Expect file to not exist.');
- $file->open()
- ->setLocalContents('Some content.')
- ->submit('Attribute file for testing');
-
- // verify lack of attribute
- $this->assertFalse($file->hasOpenAttribute('foobar'), 'Expect client foobar to not exist.');
- $this->assertFalse($file->hasAttribute('foobar'), 'Expect depot foobar to not exist.');
-
- // set the attribute
- $file->setAttribute('foobar', 'bazbar', false, true);
-
- // check that client attribute is not set
- $attributes = $file->getAttributes(true);
- $this->assertSame(0, count($attributes), 'Expected client attribute count after setting attribute.');
-
- // check that depot attribute is set
- $attributes = $file->getAttributes(false);
- $this->assertSame(1, count($attributes), 'Expected depot attribute count after setting attribute.');
- $this->assertFalse($file->hasOpenAttribute('foobar'), 'Expect client foobar to not exist.');
- $this->assertTrue($file->hasAttribute('foobar'), 'Expect depot foobar to exist.');
-
- // verify the attribute value
- $this->assertSame(
- 'bazbar',
- $file->getAttribute('foobar'),
- 'Expected depot foobar value.'
- );
- try {
- $value = $file->getOpenAttribute('foobar');
- $this->fail('Unexpected success getting client foobar.');
- } catch (FileException $e) {
- $this->assertSame(
- "Can't fetch status. The requested field "
- . "('openattr-foobar') does not exist.",
- $e->getMessage(),
- 'Expected exception using getOpenAttribute on attribute'
- );
- } catch (\Exception $e) {
- $this->fail(
- 'Unexpected exception when getting attribute: '. $e->getMessage()
- ."\n$e"
- );
- }
-
- // clear the attribute
- $file->clearAttribute('foobar', true);
-
- // verify lack of attribute
- $this->assertFalse($file->hasOpenAttribute('foobar'), 'Expect client foobar to still not exist.');
- $this->assertFalse($file->hasAttribute('foobar'), 'Expect depot foobar to no longer exist.');
- }
-
-
- /**
- * Test attribute propagation.
- */
- public function testAttributePropagation()
- {
- // setup a file
- $file = new File;
- $file->setFilespec('//depot/attribute_test.txt');
- $this->assertFalse($file->exists($file->getFilespec()), 'Expect file to not exist.');
- $file->open();
-
- // verify lack of attribute
- $this->assertFalse($file->hasOpenAttribute('foobar'), 'Expect client foobar to not exist.');
- $this->assertFalse($file->hasAttribute('foobar'), 'Expect depot foobar to not exist.');
-
- // set the attribute with propagate, and test existence
- $file->setAttribute('foobar', 'bazbar', true, false);
- $this->assertTrue($file->hasOpenAttribute('foobar'), 'Expect client foobar to exist.');
- $this->assertFalse($file->hasAttribute('foobar'), 'Expect depot foobar to not exist.');
- $this->assertSame(
- 'bazbar',
- $file->getOpenAttribute('foobar'),
- 'Expected client foobar value.'
- );
-
- // set an additional attribute without propagate, and test existence
- $file->setAttribute('nopropagate', 'loseme', false, false);
- $this->assertTrue($file->hasOpenAttribute('nopropagate'), 'Expect client nopropagate to exist.');
- $this->assertFalse($file->hasAttribute('nopropagate'), 'Expect depot nopropagate to not exist.');
- $this->assertSame(
- 'loseme',
- $file->getOpenAttribute('nopropagate'),
- 'Expected client nopropagate value.'
- );
-
- // submit the file #1
- $file->setLocalContents('Some content.')
- ->submit('Attribute file for testing');
-
- // use a fresh file object, and verify attributes
- $file2 = new File;
- $file2->setFilespec('//depot/attribute_test.txt');
- $this->assertFalse($file2->hasOpenAttribute('foobar'), 'Expect client foobar to no longer exist.');
- $this->assertTrue($file2->hasAttribute('foobar'), 'Expect depot foobar to exist now.');
- $this->assertSame(
- 'bazbar',
- $file2->getAttribute('foobar'),
- 'Expected depot foobar value.'
- );
- // nopropagate should only be in depot, for this revision
- $this->assertFalse($file2->hasOpenAttribute('nopropagate'), 'Expect client nopropagate to no longer exist.');
- $this->assertTrue($file2->hasAttribute('nopropagate'), 'Expect depot nopropagate to exist now.');
-
- // now open the file and test whether the depot attribute has been opened
- $file2->open();
- $this->assertTrue($file2->hasOpenAttribute('foobar'), 'Expect client foobar to have been opened.');
- $this->assertTrue($file2->hasAttribute('foobar'), 'Expect depot foobar to exist now.');
- $this->assertSame(
- 'bazbar',
- $file2->getOpenAttribute('foobar'),
- 'Expected client foobar value.'
- );
- // make sure nopropagate does not get promoted to client
- $this->assertFalse(
- $file2->hasOpenAttribute('nopropagate'),
- 'Expect client nopropagate to not exist after open.'
- );
-
- // submit the file #2, and make sure attribute propagates
- $file2->setLocalContents('Some new content.')
- ->submit('Change attribute file content');
-
- // use a fresh file object
- $file3 = new File;
- $file3->setFilespec('//depot/attribute_test.txt');
-
- // verify original attribute exists
- $this->assertFalse($file3->hasOpenAttribute('foobar'), 'Expect client foobar to still not exist.');
- $this->assertTrue($file3->hasAttribute('foobar'), 'Expect depot foobar to still exist.');
- $this->assertSame(
- 'bazbar',
- $file3->getAttribute('foobar'),
- 'Expected client foobar value.'
- );
-
- // now open the file and test whether the depot attribute has been opened
- $file3->open();
- $this->assertTrue($file3->hasOpenAttribute('foobar'), 'Expect client foobar to have been opened.');
- $this->assertTrue($file3->hasAttribute('foobar'), 'Expect depot foobar to exist now.');
- $this->assertSame(
- 'bazbar',
- $file3->getOpenAttribute('foobar'),
- 'Expected client foobar value.'
- );
-
- // verify nopropagate attribute does not exist
- $this->assertFalse(
- $file3->hasOpenAttribute('nopropagate'),
- 'Expect client nopropagate to still not exist.'
- );
- $this->assertFalse(
- $file3->hasAttribute('nopropagate'),
- 'Expect depot nopropagate to no longer exist.'
- );
-
- // clear attribute at depot
- $file3->clearAttribute('foobar', false);
- $this->assertFalse(
- $file3->hasOpenAttribute('foobar'),
- 'Expect client foobar to not exist after clear.'
- );
- $this->assertTrue(
- $file3->hasAttribute('foobar'),
- 'Expect depot foobar to still exist after clear.'
- );
-
- // submit an update to verify lack of propagation
- $file3->setLocalContents('Final content.');
- $file3->submit('Update attribute file content');
-
- // use a fresh file object
- $file4 = new File;
- $file4->setFilespec('//depot/attribute_test.txt');
-
- // verify depot attribute still does not exist
- $this->assertFalse(
- $file4->hasAttribute('foobar'),
- 'Expect depot foobar to still be cleared.'
- );
-
- // verify non-existant depot attribute does not get promoted to client
- // after opening
- $file4->open();
- $this->assertFalse(
- $file4->hasOpenAttribute('foobar'),
- 'Expect client foobar to still, still, still not exist.'
- );
- }
-
- /**
- * Test setAttributes.
- */
- public function testSetAttributes()
- {
- // setup a file
- $file = new File;
- $file->setFilespec('//depot/multi_attribute_test.txt');
- $this->assertFalse($file->exists($file->getFilespec()), 'Expect file to not exist.');
- $file->open();
-
- // verify lack of attribute
- $attributes = $file->getAttributes(true);
- $this->assertSame(0, count($attributes), 'Expected initial attribute count.');
-
- // first, verify that we get an exception unless the
- // attributes array is an array
- try {
- $file->setAttributes(null);
- $this->fail('Unexpected success without attributes.');
- } catch (\InvalidArgumentException $e) {
- $this->assertSame(
- "Can't set attributes. Attributes must be an array.",
- $e->getMessage(),
- 'Expected error message.'
- );
- } catch (\Exception $e) {
- $this->fail('Unexpected exception with no attributes: '. $e->getMessage());
- }
-
- // set a list of client, no-propagate attributes
- $attributeList = array(
- 'foobar' => 'bazbar',
- 'another' => 'value',
- 'third' => 'three',
- );
- $file->setAttributes($attributeList, false, false);
-
- $attributes = $file->getAttributes(true);
- $this->assertSame(3, count($attributes), 'Expected attribute count after set.');
-
- foreach ($attributeList as $key => $value) {
- $this->assertTrue(
- $file->hasOpenAttribute($key),
- "Expect client '$key' to be set."
- );
- $this->assertSame(
- $value,
- $file->getOpenAttribute($key),
- "Exected value for '$key'"
- );
- }
-
- // test that invalid attributes are rejected.
- $tests = array(
- '1234',
- '-test',
- 'test foo',
- 'test*',
- 'test...',
- 'test#',
- 'test@',
- 123,
- 'foo/bar',
- "test\x00",
- array("lkasdfj\tasdf"),
- );
- for ($i = 0; $i < count($tests); $i++) {
- try {
- $file->setAttribute($tests[$i], 'foo');
- $this->fail('Test #' . $i . ': Unexpected success setting invalid attribute.');
- } catch (\InvalidArgumentException $e) {
- $this->assertTrue(true);
- } catch (\Exception $e) {
- $this->fail('Test #' . $i . ': Unexpected exception setting invalid attribute.');
- }
- }
- }
-
- /**
- * test deleteLocalFile.
- */
- public function testDeleteLocalFile()
- {
- $file = new File;
- $filespec = '//depot/a_file_to_delete.txt';
- $file->setFilespec($filespec);
- $this->assertFalse($file->exists($filespec), 'Expect depot file to not exist.');
- $this->assertFalse(file_exists($file->getLocalFilename()), 'Expect local file to not exist.');
-
- try {
- $file->deleteLocalFile();
- $this->fail('Unexpected success deleting file that does not exist.');
- } catch (FileException $e) {
- $this->assertSame(
- "Cannot delete local file. File does not exist.",
- $e->getMessage(),
- 'Expected error deleting a non-existant file'
- );
- } catch (\Exception $e) {
- $this->fail('Unexpected exception deleting non-existant file: '. $e->getMessage());
- }
-
- // create file
- $file->open()
- ->setLocalContents('Some file content.')
- ->submit('Establish file.');
- $this->assertTrue((bool)$file->exists($filespec), 'Expect depot file to exist.');
- $this->assertTrue((bool)file_exists($file->getLocalFilename()), 'Expect local file to exist.');
- $this->assertFalse($file->isDeleted(), 'Expect file to not have deleted status after create');
-
- // delete the local file
- $file->deleteLocalFile();
- $this->assertTrue((bool)$file->exists($filespec), 'Expect depot file to exist.');
- $this->assertFalse(file_exists($file->getLocalFilename()), 'Expect local file to no longer exist.');
- $this->assertFalse($file->isDeleted(), 'Expect file to not have deleted status after deleting local file');
- }
-
- /**
- * Test opening for add.
- */
- public function testAdd()
- {
- $file = new File;
- $filespec = '//depot/a_file_to_delete.txt';
- $file->setFilespec($filespec);
- $this->assertFalse($file->exists($filespec), 'Expect depot file to not exist.');
- $this->assertFalse(file_exists($file->getLocalFilename()), 'Expect local file to not exist.');
-
- $content = 'Some content.';
- $bytes = file_put_contents($file->getLocalFilename(), $content);
- $this->assertSame(strlen($content), $bytes, 'Expected content length');
-
- // open for add
- $object = $file->add();
- $this->assertSame($file, $object, 'Expect fluent interface return');
- $this->assertTrue($file->isOpened(), 'Expect file to be opened.');
-
- // open it again
- $object = $file->add();
-
- // revert file
- $file->revert();
- $this->assertFalse($file->isOpened(), 'Expect file to not be opened.');
-
- // add with type
- $object = $file->add(null, 'text');
- $this->assertTrue($file->isOpened(), 'Expect file to be opened again.');
-
- // submit the file, open it, and then try to add it.
- $file->submit('adding the file');
- $file->open();
- try {
- $file->add();
- $this->fail('Unexpected success adding a file opened for edit.');
- } catch (FileException $e) {
- $this->assertSame(
- "Failed to open file for add: //depot/a_file_to_delete.txt - can't add (already opened for edit)",
- $e->getMessage(),
- 'Expected error adding a file opened for edit.'
- );
- } catch (\Exception $e) {
- $this->fail('Unexpected exception adding a file opened for edit: '. $e->getMessage());
- }
-
- // test adding into a specific change.
- $change = new Change;
- $change->setDescription('test')->save();
- $file = new File;
- $file->setFilespec('//depot/testeroo')
- ->touchLocalFile()
- ->add($change->getId());
- $this->assertSame(
- intval($file->getStatus('change')),
- $change->getId(),
- "Expected file to be open in specified change."
- );
- $this->assertSame(
- array('//depot/testeroo'),
- $change->getFiles(),
- "Expected file in change."
- );
-
- // test adding into a different change.
- $change = new Change;
- $change->setDescription('test2')->save();
- $file->add($change->getId());
- $this->assertSame(
- intval($file->getStatus('change')),
- $change->getId(),
- "Expected file to be open in specified change."
- );
- }
-
- /**
- * Test fetching a file, plus content cache manipulation.
- */
- public function testFetch()
- {
- $file = new File;
- $filespec = '//depot/a_file_to_fetch.txt';
-
- // test non-existant file
- $file->setFilespec($filespec);
- try {
- $theFile = File::fetch($filespec);
- $this->fail('Unexpected success fetching a non-existant file.');
- } catch (NotFoundException $e) {
- $this->assertSame(
- "Cannot fetch file '$filespec'. File does not exist.",
- $e->getMessage(),
- 'Expected error while fetching a non-existant file.'
- );
- }
-
- // test non-existent file in non-existent depot
- try {
- $theFile = File::fetch('//woozle/wobble');
- $this->fail('Unexpected success fetching a non-existant file.');
- } catch (NotFoundException $e) {
- $this->assertSame(
- "Cannot fetch file '//woozle/wobble'. File does not exist.",
- $e->getMessage(),
- 'Expected error while fetching a non-existant file.'
- );
- }
-
- // now make the file exist
- $file->add();
- $contents = 'This file has some content.';
- $file->setLocalContents($contents);
- $file->submit('Make the file available for fetching.');
-
- $theFile = File::fetch($filespec);
- $this->assertSame($contents, $theFile->getDepotContents(), 'Expected content.');
-
- // manipulate the content cache
- $newContents = 'And now for something comepletely different.';
- $theFile->setContentCache($newContents);
- $this->assertSame($newContents, $theFile->getDepotContents(), 'Expected new content.');
-
- // clear the content cache, original content should then be available
- $theFile->clearContentCache();
- $this->assertSame($contents, $theFile->getDepotContents(), 'Expected content.');
-
- // test manipulation of client content
- $theFile->open();
- $clientContent = 'Different client content.';
- file_put_contents($theFile->getLocalFilename(), $clientContent);
- $this->assertSame($clientContent, $theFile->getLocalContents(), 'Expected client content.');
- $this->assertSame($contents, $theFile->getDepotContents(), 'Expected depot content to be unchanged.');
- }
-
- /**
- * Test getLocalContent.
- */
- public function testGetLocalContents()
- {
- $tests = array(
- array(
- 'label' => __LINE__ .': no setup',
- 'filespec' => null,
- 'add' => false,
- 'content' => null,
- 'error' => new FileException(
- 'Cannot complete operation, no filespec has been specified'
- ),
- ),
- array(
- 'label' => __LINE__ .': only filespec',
- 'filespec' => '//depot/file',
- 'add' => false,
- 'content' => null,
- 'error' => new FileException(
- 'Cannot get local file contents. Local file does not exist.'
- ),
- ),
- array(
- 'label' => __LINE__ .': filespec + content',
- 'filespec' => '//depot/file',
- 'add' => true,
- 'content' => 'Some content.',
- 'error' => false,
- ),
- );
-
- foreach ($tests as $test) {
- $label = $test['label'];
-
- // prep test conditions
- $file = new File;
- if (isset($test['filespec'])) {
- $file->setFilespec($test['filespec']);
- }
- if (isset($test['content'])) {
- $file->add();
- $file->setLocalContents($test['content']);
- }
-
- try {
- $content = $file->getLocalContents();
- if ($test['error']) {
- $this->fail("$label - Unexpected success");
- }
- } catch (\PHPUnit\Framework\AssertionFailedError $e) {
- $this->fail($e->getMessage());
- } catch (\Exception $e) {
- if (!$test['error']) {
- $this->fail(
- "$label - Unexpected exception ("
- . get_class($e) .') '. $e->getMessage()
- );
- } else {
- $this->assertSame(
- get_class($test['error']),
- get_class($e),
- "$label - Expected error class"
- );
- $this->assertSame(
- $test['error']->getMessage(),
- $e->getMessage(),
- "$label - Expected error message"
- );
- }
- }
-
- if (!$test['error']) {
- $this->assertSame(
- $test['content'],
- $content,
- "$label - Expected content"
- );
- }
- }
- }
-
- /**
- * Test getDepotContentLines.
- */
- public function testGetDepotContentLines()
- {
- // Create file content that does not end in newline
- $file = new File;
- $fileSpec = '//depot/file_get_depot_line.txt';
- $file->setFilespec($fileSpec);
- $file->add();
- $file->setLocalContents(
- "Some content.\nMore Content.\n2nd More Content\n3rd More Content\r\n4th More Content\r5th More Content"
- );
- $file->submit('Make the file available for fetching.');
-
- // Create file content that ends in newline
- $file = new File;
- $fileSpecNewline = '//depot/file_get_depot_line_newline.txt';
- $file->setFilespec($fileSpecNewline);
- $file->add();
- $file->setLocalContents(
- "Some content.\nMore Content.\n2nd More Content\n3rd More Content\r\n4th More Content\r5th More Content\n"
- );
- $file->submit('Make the file available for fetching.');
-
- // Create empty file
- $file = new File;
- $fileSpecEmpty = '//depot/file_empty.txt';
- $file->setFilespec($fileSpecEmpty);
- $file->add();
- $file->setLocalContents("");
- $file->submit('Make the file available for fetching.');
-
- $tests = array(
- array(
- 'params' => null,
- 'filespec' => $fileSpec,
- 'label' => __LINE__ .': null input',
- 'expected' => '',
- 'error' => new \InvalidArgumentException(
- 'String or array input expected'
- )
- ),
- array(
- 'params' => 'b1-1',
- 'filespec' => $fileSpec,
- 'label' => __LINE__ .': invalid input',
- 'expected' => '',
- 'error' => new \InvalidArgumentException(
- 'String arguments must be in the format 1-2'
- )
- ),
- array(
- 'params' => array(1, 2),
- 'filespec' => $fileSpec,
- 'label' => __LINE__ .': invalid array input',
- 'expected' => '',
- 'error' => new \InvalidArgumentException(
- 'Expected range to be in string or array format'
- )
- ),
- array(
- 'params' => array(array('start' => 'a', 'end' => 'b')),
- 'filespec' => $fileSpec,
- 'label' => __LINE__ .': non-numeric start and end input',
- 'expected' => '',
- 'error' => new \InvalidArgumentException(
- 'Array arguments must have a numeric start and end key'
- )
- ),
- array(
- 'params' => '0-1',
- 'filespec' => $fileSpec,
- 'label' => __LINE__ .': low array input',
- 'expected' => '',
- 'error' => new \InvalidArgumentException(
- 'Line numbers cannot be lower than 1'
- )
- ),
- array(
- 'params' => '2-1',
- 'filespec' => $fileSpec,
- 'label' => __LINE__ .': start greater than end',
- 'expected' => '',
- 'error' => new \InvalidArgumentException(
- 'Range end must be greater than or equal to range start'
- )
- ),
- array(
- 'params' => array(),
- 'filespec' => $fileSpec,
- 'label' => __LINE__ .': asked for empty array',
- 'expected' => array(),
- 'error' => false
- ),
- array(
- 'params' => '1-1',
- 'filespec' => $fileSpec,
- 'label' => __LINE__ .': ask using single string',
- 'expected' => array('1' => "Some content.\n"),
- 'error' => false
- ),
- array(
- 'params' => array('start' => 1, 'end' => 2),
- 'filespec' => $fileSpec,
- 'label' => __LINE__ .': ask using a single array',
- 'expected' => array('1' => "Some content.\n", '2' => "More Content.\n"),
- 'error' => false
- ),
- array(
- 'params' => array('1-2', '3-4', '5-6'),
- 'filespec' => $fileSpec,
- 'label' => __LINE__ .': adjacent ranges',
- 'expected' => array(
- '1' => "Some content.\n",
- '2' => "More Content.\n",
- '3' => "2nd More Content\n",
- '4' => "3rd More Content\r\n",
- '5' => "4th More Content\r",
- '6' => "5th More Content",
- ),
- 'error' => false
- ),
- array(
- 'params' => array('1-2', '2-3', '3-4'),
- 'filespec' => $fileSpec,
- 'label' => __LINE__ .': adjacent ranges single overlap',
- 'expected' => array(
- '1' => "Some content.\n",
- '2' => "More Content.\n",
- '3' => "2nd More Content\n",
- '4' => "3rd More Content\r\n"
- ),
- 'error' => false
- ),
- array(
- 'params' => array('1-4', '2-6'),
- 'filespec' => $fileSpec,
- 'label' => __LINE__ .': adjacent ranges multiline overlap',
- 'expected' => array(
- '1' => "Some content.\n",
- '2' => "More Content.\n",
- '3' => "2nd More Content\n",
- '4' => "3rd More Content\r\n",
- '5' => "4th More Content\r",
- '6' => "5th More Content",
- ),
- 'error' => false
- ),
- array(
- 'params' => array('2-6', '1-4'),
- 'filespec' => $fileSpec,
- 'label' => __LINE__ .': out of order',
- 'expected' => array(
- '1' => "Some content.\n",
- '2' => "More Content.\n",
- '3' => "2nd More Content\n",
- '4' => "3rd More Content\r\n",
- '5' => "4th More Content\r",
- '6' => "5th More Content",
- ),
- 'error' => false
- ),
- array(
- 'params' => array('1-2', '6-6'),
- 'filespec' => $fileSpec,
- 'label' => __LINE__ .': multiline gap',
- 'expected' => array(
- '1' => "Some content.\n",
- '2' => "More Content.\n",
- '6' => "5th More Content",
- ),
- 'error' => false
- ),
- array(
- 'params' => array('7-7'),
- 'filespec' => $fileSpecNewline,
- 'label' => __LINE__ .': last empty line only',
- 'expected' => array(
- '7' => ""
- ),
- 'error' => false
- ),
- array(
- 'params' => array('2-16'),
- 'filespec' => $fileSpec,
- 'label' => __LINE__ .': request past file',
- 'expected' => array(
- '2' => "More Content.\n",
- '3' => "2nd More Content\n",
- '4' => "3rd More Content\r\n",
- '5' => "4th More Content\r",
- '6' => "5th More Content",
- ),
- 'error' => false
- ),
- array(
- 'params' => array('8-10'),
- 'filespec' => $fileSpec,
- 'label' => __LINE__ .': out of file',
- 'expected' => array(),
- 'error' => false
- ),
- array(
- 'params' => array('1-10'),
- 'filespec' => $fileSpecEmpty,
- 'label' => __LINE__ .': empty file',
- 'expected' => array(),
- 'error' => false
- ),
- );
-
- foreach ($tests as $test) {
- $label = $test['label'];
- $file = File::fetch($test['filespec']);
-
- try {
- $content = $file->getDepotContentLines($test['params']);
- if ($test['error']) {
- $this->fail("$label - Unexpected success");
- }
- } catch (\PHPUnit\Framework\AssertionFailedError $e) {
- $this->fail($e->getMessage());
- } catch (\Exception $e) {
- if (!$test['error']) {
- $this->fail(
- "$label - Unexpected exception ("
- . get_class($e) .') '. $e->getMessage()
- );
- } else {
- $this->assertSame(
- get_class($test['error']),
- get_class($e),
- "$label - Expected error class"
- );
- $this->assertSame(
- $test['error']->getMessage(),
- $e->getMessage(),
- "$label - Expected error message"
- );
- }
- }
-
- if (!$test['error']) {
- $this->assertSame(
- $test['expected'],
- $content,
- "$label - Expected content"
- );
- }
- }
- }
-
- /**
- * Test annotated content.
- */
- public function testAnnotatedContent()
- {
- // increment change counter to ensure change numbers differ from rev numbers
- $change = new Change;
- $change->setDescription('bump')->save();
-
- // make a file with some sample content.
- $file = new File;
- $file
- ->setFilespec('//depot/foo')
- ->add()
- ->setLocalContents("1\n2\n3")
- ->submit('Add the first version');
-
- // make a second version of the file.
- $file
- ->edit()
- ->setLocalContents("1\n2\n3\n4")
- ->submit('Add the second version');
-
- $this->assertSame(
- array(
- array('upper' => '2', 'lower' => '1', 'data' => "1\n"),
- array('upper' => '2', 'lower' => '1', 'data' => "2\n"),
- array('upper' => '2', 'lower' => '2', 'data' => "3\n"),
- array('upper' => '2', 'lower' => '2', 'data' => "4")
- ),
- $file->getAnnotatedContent()
- );
-
- // test w.out content
- $this->assertSame(
- array(
- array('upper' => '2', 'lower' => '1'),
- array('upper' => '2', 'lower' => '1'),
- array('upper' => '2', 'lower' => '2'),
- array('upper' => '2', 'lower' => '2')
- ),
- $file->getAnnotatedContent(array(File::ANNOTATE_CONTENT => false))
- );
-
- // test w. change numbers
- $this->assertSame(
- array(
- array('upper' => '3', 'lower' => '2', 'data' => "1\n"),
- array('upper' => '3', 'lower' => '2', 'data' => "2\n"),
- array('upper' => '3', 'lower' => '3', 'data' => "3\n"),
- array('upper' => '3', 'lower' => '3', 'data' => "4")
- ),
- $file->getAnnotatedContent(array(File::ANNOTATE_CHANGES => true))
- );
-
- // test w. indirect history
- $this->p4->run('integ', array('//depot/foo', '//depot/bar'));
- $this->p4->run('submit', array('-d', 'branch'));
-
- $bar = new File;
- $bar
- ->setFilespec('//depot/bar')
- ->edit()
- ->setLocalContents("1\n2\n5\n4")
- ->submit('Edit in branched copy');
-
- $this->p4->run('integ', array('//depot/bar', '//depot/foo'));
- $this->p4->run('resolve', array('-at'));
- $this->p4->run('submit', array('-d', 'merge'));
-
- $this->assertSame(
- array(
- array('upper' => '6', 'lower' => '2', 'data' => "1\n"),
- array('upper' => '6', 'lower' => '2', 'data' => "2\n"),
- array('upper' => '6', 'lower' => '5', 'data' => "5\n"),
- array('upper' => '6', 'lower' => '3', 'data' => "4")
- ),
- $file->getAnnotatedContent(array(File::ANNOTATE_INTEG => true))
- );
- }
-
- /**
- * Test reopen.
- */
- public function testReopen()
- {
- $file = new File;
- $file->setFilespec('//depot/file.txt')
- ->add(null, 'binary')
- ->setLocalContents('Content.');
-
- $this->assertSame(
- 'binary',
- $file->getStatus('type'),
- 'Expect the type explicitly set.'
- );
-
- $tests = array(
- array(
- 'label' => __LINE__ .': no params',
- 'change' => null,
- 'type' => null,
- 'error' => new \InvalidArgumentException(
- 'Cannot reopen file. You must provide a change and/or a filetype.'
- ),
- 'expect' => false,
- ),
- array(
- 'label' => __LINE__ .': default change',
- 'change' => 'default',
- 'type' => null,
- 'error' => false,
- 'expect' => 'binary',
- ),
- array(
- 'label' => __LINE__ .': bogus change',
- 'change' => 'bogus',
- 'type' => null,
- 'error' => new CommandException(
- "Command failed: Invalid changelist number 'bogus'."
- ),
- 'expect' => 'binary',
- ),
- array(
- 'label' => __LINE__ .': binary type',
- 'change' => null,
- 'type' => 'binary',
- 'error' => false,
- 'expect' => 'binary',
- ),
- array(
- 'label' => __LINE__ .': text type',
- 'change' => null,
- 'type' => 'text',
- 'error' => false,
- 'expect' => 'text',
- ),
- );
-
- foreach ($tests as $test) {
- $label = $test['label'];
- try {
- $file->reopen($test['change'], $test['type']);
- if ($test['error']) {
- $this->fail("$label - unexpected success");
- }
- } catch (\Exception $e) {
- if ($test['error']) {
- $this->assertSame(
- get_class($test['error']),
- get_class($e),
- "$label - Expected exception class: ". $e->getMessage()
- );
- $this->assertSame(
- $test['error']->getMessage(),
- rtrim($e->getMessage()),
- "$label - Expected exception message."
- );
- } else {
- $this->fail(
- "$label - unexpected exception ("
- . get_class($e) .'): '. $e->getMessage()
- );
- }
- }
-
- if (!$test['error']) {
- $this->assertSame(
- $test['expect'],
- $file->getStatus('type'),
- "$label - expected type"
- );
- }
- }
-
-
- }
-
- /**
- * Test where functionality, with getDepotPath/getDepotFilename.
- */
- public function testWhere()
- {
- $file = new File;
- $filename = 'a_file.txt';
- $file->setFilespec("//depot/$filename")
- ->add()
- ->setLocalContents('This file has some content.')
- ->submit('Make the file available.');
-
- $where = $file->where();
- $this->assertSame(
- array(
- 0 => "//depot/$filename",
- 1 => "//test-client/$filename",
- 2 => $file->getLocalFilename(),
- ),
- $where,
- 'Expected where values'
- );
-
- // test getDepotPath and getDepotFilename
- $this->assertSame($file->getDepotPath(), dirname($where[0]), 'Expected depot path');
- $this->assertSame($file->getDepotFilename(), $where[0], 'Expected depot filename');
- }
-
- /**
- * Test hasRevspec.
- */
- public function testHasRevspec()
- {
- $tests = array(
- '//depot/file.txt' => false,
- '//depot/file.txt#head' => true,
- '//depot/file.txt@1' => true,
- );
-
- foreach ($tests as $filespec => $expected) {
- $result = File::hasRevspec($filespec);
- $this->assertSame($expected, $result, "Expected result for '$filespec'");
- }
- }
-
- /**
- * Test _validateFilespec via exists()
- */
- public function testValidateFilespec()
- {
- $tests = array(
- array(
- 'label' => __LINE__ .': valid filespec',
- 'filespec' => '//depot/file.txt',
- 'error' => false,
- ),
- array(
- 'label' => __LINE__ .': non-string filespec',
- 'filespec' => false,
- 'error' => true,
- ),
- array(
- 'label' => __LINE__ .': wildcard filespec',
- 'filespec' => '//depot/file*',
- 'error' => true,
- ),
- array(
- 'label' => __LINE__ .': multi-file filespec',
- 'filespec' => '//depot/...',
- 'error' => true,
- ),
- array(
- 'label' => __LINE__ .': empty string',
- 'filespec' => '',
- 'error' => true,
- ),
- );
-
- foreach ($tests as $test) {
- try {
- File::exists($test['filespec']);
- if ($test['error']) {
- $this->fail($test['label'] .' - unexpected success');
- }
- } catch (FileException $e) {
- if ($test['error']) {
- $this->assertSame(
- 'Invalid filespec provided. In this context, filespecs'
- . ' must be a reference to a single file.',
- $e->getMessage(),
- $test['label'] .' - expected error message'
- );
- } else {
- $this->fail($test['label'] .' - unexpected failure');
- }
- } catch (\Exception $e) {
- $this->fail($test['label'] .' - unexpected exception: '. $e->getMessage());
- }
- }
- }
-
- /**
- * Test lock/unlock.
- */
- public function testLockUnlock()
- {
- // In order to test lock/unlock properly, we need to create another user.
- $password = 'testUser1pass';
- $user2 = new User;
- $user2->set(
- array(
- 'User' => 'testUser1',
- 'Email' => 'testUser1@testhost',
- 'FullName' => 'Test User 1',
- 'Password' => $password,
- )
- )->save();
-
- // create the user's client spec
- $client = new Client;
- $client->setId($this->getP4Params('client') .'-'. $user2->getId());
- $client->setRoot($this->getP4Params('clientRoot') .'/'. $user2->getId())
- ->setView(array('//depot/... //'. $client->getId() .'/...'))
- ->setOwner($user2->getId())
- ->save();
-
- // create a connection for the new user
- $userP4 = \P4\Connection\Connection::factory(
- $this->getP4Params('port'),
- $user2->getId(),
- $client->getId(),
- $password,
- null,
- null
- );
-
- // and now the tests
- // have testuser create a file, submit it, and then open for edit and lock it
- $testFile = new File($userP4);
- $testFile->setFilespec('//depot/test_user_file.txt')
- ->add()
- ->setLocalContents('Test user content')
- ->submit('Adding test user file.')
- ->open()
- ->lock();
-
- // have superuser attempt to open/submit the file, expect failure
- $superFile = new File($this->p4);
- $superFile->setFilespec('//depot/test_user_file.txt')
- ->open()
- ->setLocalContents('Super user content.');
- try {
- $superFile->submit('Place super content in file.');
- $this->fail('Unexpected success submitting to a locked file.');
- } catch (CommandException $e) {
- $this->assertRegExp(
- "/Command failed: No files to submit.*"
- . "File\(s\) couldn't be locked.*"
- . "Submit failed -- fix problems above then use 'p4 submit -c 2'./s",
- $e->getMessage(),
- 'Expected error submitting to a locked file.'
- );
- } catch (\Exception $e) {
- $this->fail('Unexpected exception after submit to a locked file: '. $e->getMessage());
- }
-
- // have the testuser unlock the file
- $testFile->unlock();
-
- // have the superuser attempt to open/submit the file, expect success
- $superFile = new File($this->p4);
- $superFile->setFilespec('//depot/test_user_file.txt')
- ->edit()
- ->setLocalContents('Super user content.')
- ->submit('Place super content in file.');
- $this->assertTrue(true, 'Expect submit to succeed');
- $testFile->revert();
- }
-
- /**
- * Prepare files for fetchAll testing.
- *
- * @param string $basePath base depot path for file creation; default='//depot/'
- * @param bool $sleep Sleep between file creation to create unique timestamps,
- * true = 1 second sleep, false (default) no sleep.
- * @return array The list of File objects created.
- */
- protected function prepareFetchAllTests($basePath = '//depot/', $sleep = false)
- {
- $files = array();
- // make a small file
- $file = new File;
- $file->setFilespec($basePath .'small.txt')
- ->open()
- ->setLocalContents('A small file.')
- ->setAttribute('foo', 'small')
- ->submit('Add a small file.');
- $files[] = $file;
- if ($sleep) {
- sleep(1); // guarantee next file has different timestamp
- }
-
- // make a medium-sized file
- $file = new File;
- $file->setFilespec($basePath .'medium.jpg')
- ->add(null, 'binary')
- ->setLocalContents('This is a medium-sized file for testing.')
- ->setAttribute('foo', 'medium')
- ->submit('Add a medium file.');
- $files[] = $file;
- if ($sleep) {
- sleep(1); // guarantee next file has different timestamp
- }
-
- // make a large-sized file
- $largeContent = array();
- for ($i = 0; $i < 100; $i++) {
- $largeContent[] = 'Large files have plenty of content.';
- }
- $file = new File;
- $file->setFilespec($basePath .'large.txt')
- ->open()
- ->setLocalContents(join(' ', $largeContent))
- ->setAttribute('foo', 'large')
- ->submit('Add a large file.');
- $files[] = $file;
- if ($sleep) {
- sleep(1); // guarantee next file has different timestamp
- }
-
- // make another small file
- $file = new File;
- $file->setFilespec($basePath .'another_small.txt')
- ->open()
- ->setLocalContents('A small file.')
- ->setAttribute('foo', 'small')
- ->submit('Add another small file.');
- $files[] = $file;
- if ($sleep) {
- sleep(1); // guarantee next file has different timestamp
- }
-
- // make another medium file
- $file = new File;
- $file->setFilespec($basePath .'ze_medium_2.jpg')
- ->add(null, 'binary')
- ->setLocalContents('This is a medium-sized file for testing.')
- ->setAttribute('foo', 'another medium')
- ->submit('Add another medium file.');
- $files[] = $file;
- if ($sleep) {
- sleep(1); // guarantee next file has different timestamp
- }
-
- // make a pending file
- $file = new File;
- $file->setFilespec($basePath .'opened.txt')
- ->add()
- ->setLocalContents('opened.')
- ->setAttribute('foo', 'opened');
- $this->assertTrue(
- file_put_contents($file->getLocalFilename(), 'opened.') !== false,
- 'Should be able to write opened file to client workspace.'
- );
- $files[] = $file;
- // the final sleep is not necessary here.
-
- // add keys by filename for easier lookups
- foreach ($files as $file) {
- $files[basename($file->getFilespec())] = $file;
- }
- return $files;
- }
-
- /**
- * Test stripRevspec.
- */
- public function testStripRevspec()
- {
- $tests = array(
- array(
- 'label' => __LINE__ .': null',
- 'revspec' => null,
- 'expect' => null,
- ),
- array(
- 'label' => __LINE__ .': empty string',
- 'revspec' => '',
- 'expect' => '',
- ),
- array(
- 'label' => __LINE__ .': numeric',
- 'revspec' => 123,
- 'expect' => 123,
- ),
- array(
- 'label' => __LINE__ .': string',
- 'revspec' => 'abc',
- 'expect' => 'abc',
- ),
- array(
- 'label' => __LINE__ .': #',
- 'revspec' => '#',
- 'expect' => '',
- ),
- array(
- 'label' => __LINE__ .': string#',
- 'revspec' => 'abc#',
- 'expect' => 'abc',
- ),
- array(
- 'label' => __LINE__ .': #string',
- 'revspec' => '#abc',
- 'expect' => '',
- ),
- array(
- 'label' => __LINE__ .': @',
- 'revspec' => '@',
- 'expect' => '',
- ),
- array(
- 'label' => __LINE__ .': string@',
- 'revspec' => 'abc@',
- 'expect' => 'abc',
- ),
- array(
- 'label' => __LINE__ .': @string',
- 'revspec' => '@abc',
- 'expect' => '',
- ),
-
- array(
- 'label' => __LINE__ .': depot file',
- 'revspec' => '//depot/file.txt',
- 'expect' => '//depot/file.txt',
- ),
- array(
- 'label' => __LINE__ .': depot file #have',
- 'revspec' => '//depot/file.txt#have',
- 'expect' => '//depot/file.txt',
- ),
- array(
- 'label' => __LINE__ .': depot file #head',
- 'revspec' => '//depot/file.txt#head',
- 'expect' => '//depot/file.txt',
- ),
- array(
- 'label' => __LINE__ .': depot file #none',
- 'revspec' => '//depot/file.txt#none',
- 'expect' => '//depot/file.txt',
- ),
- array(
- 'label' => __LINE__ .': depot file #123',
- 'revspec' => '//depot/file.txt#123',
- 'expect' => '//depot/file.txt',
- ),
- array(
- 'label' => __LINE__ .': depot file @123',
- 'revspec' => '//depot/file.txt@123',
- 'expect' => '//depot/file.txt',
- ),
- array(
- 'label' => __LINE__ .': depot file @test-ws',
- 'revspec' => '//depot/file.txt@test-ws',
- 'expect' => '//depot/file.txt',
- ),
- array(
- 'label' => __LINE__ .': depot file @2009-12-31',
- 'revspec' => '//depot/file.txt@2009-12-31',
- 'expect' => '//depot/file.txt',
- ),
- array(
- 'label' => __LINE__ .': depot file #head@2009-12-31',
- 'revspec' => '//depot/file.txt#head@2009-12-31',
- 'expect' => '//depot/file.txt',
- ),
- array(
- 'label' => __LINE__ .': depot file @2009-12-31#head',
- 'revspec' => '//depot/file.txt@2009-12-31#head',
- 'expect' => '//depot/file.txt',
- ),
- );
-
- foreach ($tests as $test) {
- $label = $test['label'];
- $actual = File::stripRevspec($test['revspec']);
- $this->assertSame(
- $test['expect'],
- $actual,
- "$label - Expected result"
- );
- }
- }
-
- /**
- * Test stripRevspec.
- */
- public function testsStripWildcards()
- {
- $tests = array(
- array(
- 'label' => __LINE__ .': empty string',
- 'revspec' => '',
- 'expect' => '',
- ),
- array(
- 'label' => __LINE__ .': string',
- 'revspec' => 'abc',
- 'expect' => 'abc',
- ),
- array(
- 'label' => __LINE__ .': #',
- 'revspec' => '#',
- 'expect' => '#',
- ),
- array(
- 'label' => __LINE__ .': string#',
- 'revspec' => 'abc#',
- 'expect' => 'abc#',
- ),
- array(
- 'label' => __LINE__ .': #string',
- 'revspec' => '#abc',
- 'expect' => '#abc',
- ),
- array(
- 'label' => __LINE__ .': @',
- 'revspec' => '@',
- 'expect' => '@',
- ),
- array(
- 'label' => __LINE__ .': string@',
- 'revspec' => 'abc@',
- 'expect' => 'abc@',
- ),
- array(
- 'label' => __LINE__ .': @string',
- 'revspec' => '@abc',
- 'expect' => '@abc',
- ),
-
- array(
- 'label' => __LINE__ .': depot file',
- 'revspec' => '//depot/file.txt',
- 'expect' => '//depot/file.txt',
- ),
- array(
- 'label' => __LINE__ .': depot file #have',
- 'revspec' => '//depot/file.txt#have',
- 'expect' => '//depot/file.txt#have',
- ),
- array(
- 'label' => __LINE__ .': depot file/...',
- 'revspec' => '//depot/file.txt/...',
- 'expect' => '//depot/file.txt',
- ),
- array(
- 'label' => __LINE__ .': depot file/*',
- 'revspec' => '//depot/file.txt/*',
- 'expect' => '//depot/file.txt',
- ),
- array(
- 'label' => __LINE__ .': depot file/%%1',
- 'revspec' => '//depot/file.txt/%%1',
- 'expect' => '//depot/file.txt',
- ),
- array(
- 'label' => __LINE__ .': depot file/*/...',
- 'revspec' => '//depot/file.txt/*/...',
- 'expect' => '//depot/file.txt/*',
- ),
- array(
- 'label' => __LINE__ .': depot file/.../...',
- 'revspec' => '//depot/file.txt/.../...',
- 'expect' => '//depot/file.txt/...',
- ),
- array(
- 'label' => __LINE__ .': depot file/*/*',
- 'revspec' => '//depot/file.txt/*/*',
- 'expect' => '//depot/file.txt/*',
- ),
- array(
- 'label' => __LINE__ .': depot file/.../a@foo',
- 'revspec' => '//depot/file.txt/.../a@foo',
- 'expect' => '//depot/file.txt/.../a@foo',
- ),
- array(
- 'label' => __LINE__ .': depot file/%%1/%%2/%%3',
- 'revspec' => '//depot/file.txt/%%1/%%2/%%3',
- 'expect' => '//depot/file.txt/%%1/%%2',
- ),
- );
-
- foreach ($tests as $test) {
- $label = $test['label'];
- $actual = File::stripWildcards($test['revspec']);
- $this->assertSame(
- $test['expect'],
- $actual,
- "$label - Expected result"
- );
- }
- }
-
- /**
- * Ensure that binary data in files and attributes is handled safely.
- */
- public function testBinarySafeness()
- {
- // make test data that contains null bytes.
- $data = str_repeat("deadbeefcafe\0", 1000);
-
- // make file obj to stick data in.
- $file = new File;
- $file->setFilespec('//depot/test-file')
- ->setLocalContents($data);
-
- // make sure we wrote the local data correctly.
- $this->assertSame(
- $data,
- $file->getLocalContents(),
- 'Expected matching data.'
- );
-
- // open for add and ensure type is binary.
- $file->add();
- $this->assertTrue($file->isOpened(), 'Expected file to be open.');
- $this->assertSame(
- 'binary',
- $file->getStatus('type'),
- 'Expected binary file type.'
- );
- $file->submit('Test of binary data.');
-
- // ensure depot contents match test data.
- $this->assertSame(
- $data,
- $file->getDepotContents(),
- 'Expected matching depot vs. in-memory data post submit.'
- );
- $this->assertSame(
- $file->getLocalContents(),
- $file->getDepotContents(),
- 'Expected matching depot vs. local data post submit.'
- );
-
- // try again with fresh objects.
- $file = File::fetch('//depot/test-file');
- $this->assertSame(
- $data,
- $file->getDepotContents(),
- 'Expected matching data w. fresh file obj.'
- );
- $query = FileQuery::create()->addFilespec('//depot/...');
- $files = File::fetchAll($query);
- $this->assertSame(
- $data,
- $files->current()->getDepotContents(),
- 'Expected matching data via fetch all'
- );
-
- // re-type to text and try again (should still be binary safe).
- $file->edit(null, 'text')->submit('now text');
- $this->assertSame(
- 'text',
- $file->getStatus('headType'),
- 'Expected text file type.'
- );
- $this->assertSame(
- $data,
- $file->getDepotContents(),
- 'Expected matching data even w. text file type.'
- );
- $file = File::fetch('//depot/test-file');
- $this->assertSame(
- $data,
- $file->getDepotContents(),
- 'Expected matching data w. text type and fresh file obj.'
- );
-
- // try binary data in attributes.
- $file = new File;
- $file->setFilespec('//depot/file-w-attr')
- ->touchLocalFile()
- ->add()
- ->setAttribute('foo', $data);
- $this->assertSame(
- $data,
- $file->getOpenAttribute('foo'),
- 'Expected matching data in attribute.'
- );
-
- // submit and check again.
- $file->submit('binary attr.');
- $this->assertSame(
- $data,
- $file->getAttribute('foo'),
- 'Expected matching data in attribute post submit.'
- );
-
- // fetch and check again.
- $file = File::fetch('//depot/file-w-attr');
- $this->assertSame(
- $data,
- $file->getAttribute('foo'),
- 'Expected matching data in attribute post submit w. fresh file obj.'
- );
- }
-
- /**
- * Test retrieving changes related to a given file
- */
- public function testGetChanges()
- {
- $file = new File;
-
- try {
- $file->getChanges();
- $this->fail('expected exception when no filespec is set');
- } catch (FileException $e) {
- $this->assertSame(
- "Cannot complete operation, no filespec has been specified",
- $e->getMessage()
- );
- }
-
- $file->setFilespec("//depot/testFile2")
- ->add()
- ->setLocalContents('should not see me')
- ->submit('create a different file');
-
- $file = new File;
- $file->setFilespec("//depot/testFile")
- ->add()
- ->setLocalContents('0')
- ->submit('create file');
-
- for ($i=1; $i <= 10; $i++) {
- $file->edit()
- ->setLocalContents($i)
- ->submit('Test save ' . $i);
- }
-
- $this->assertSame(
- array (
- 0 => 'Test save 10',
- 1 => 'Test save 9',
- 2 => 'Test save 8',
- 3 => 'Test save 7',
- 4 => 'Test save 6',
- 5 => 'Test save 5',
- 6 => 'Test save 4',
- 7 => 'Test save 3',
- 8 => 'Test save 2',
- 9 => 'Test save 1',
- 10 => 'create file',
- ),
- array_map('trim', $file->getChanges()->invoke('getDescription'))
- );
- }
-
- /**
- * Test retrieving the change related to a given file
- */
- public function testGetChange()
- {
- $file = new File;
-
- try {
- $file->getChange();
- $this->fail('expected exception when no filespec is set');
- } catch (FileException $e) {
- $this->assertSame(
- "Cannot complete operation, no filespec has been specified",
- $e->getMessage()
- );
- }
-
- $file->setFilespec("//depot/testFile2")
- ->add()
- ->setLocalContents('should not see me')
- ->submit('create a different file');
-
- $file = new File;
- $file->setFilespec("//depot/testFile")
- ->add()
- ->setLocalContents('0')
- ->submit('create file');
-
- for ($i=1; $i <= 10; $i++) {
- $file->edit()
- ->setLocalContents($i)
- ->submit('Test save ' . $i);
- }
-
- $file = File::fetch('//depot/testFile#2');
- $this->assertEquals('Test save 1', trim($file->getChange()->getDescription()), 'Expected change description');
- }
-
- /**
- * Test fetching a given file that has been deleted
- */
- public function testFetchDeleted()
- {
- $file = new File;
- $file->setFilespec("//depot/testFile")
- ->setLocalContents('abc123')
- ->add()
- ->submit('create file');
-
- // grab the file and take a peek at its contents
- $testFile = File::fetch("//depot/testFile");
-
- $this->assertInstanceOf('P4\File\File', $testFile, 'Unexpected type returned by File::fetch()');
- $this->assertEquals('abc123', $testFile->getDepotContents(), 'Unexpected depot contents');
- $this->assertFalse($testFile->isDeleted(), 'File should not have been deleted');
-
- $file->delete()
- ->submit('delete file');
-
- // grab the deleted file and take a peek at its expected-to-be-nonexistent contents
- $testFile = File::fetch("//depot/testFile");
-
- $this->assertInstanceOf('P4\File\File', $testFile, 'Unexpected type returned by File::fetch()');
- $this->assertEquals('', $testFile->getDepotContents(), 'Depot contents should be empty for deleted files');
- $this->assertTrue($testFile->isDeleted(), 'File should have been deleted');
-
- $testFile = null;
- $e = null;
-
- try {
- $testFile = File::fetch("//depot/testFile", null, true);
- } catch (NotFoundException $e) {
- }
-
- $this->assertNull(
- $testFile,
- 'Null expected when using File::fetch() on deleted filespec with excludeDeleted=true'
- );
-
- $this->assertInstanceOf(
- 'P4\File\Exception\NotFoundException',
- $e,
- 'NotFoundException expected when using File::fetch() on deleted filespec with excludeDeleted=true'
- );
- }
- /**
- * Test retrieving previor revisions of a given file
- */
- public function testFetchRevision()
- {
- $file = new File;
- $file->setFilespec("//depot/testFile")
- ->add()
- ->setLocalContents('0')
- ->submit('create file');
-
- for ($i=1; $i <= 10; $i++) {
- $file->edit()
- ->setLocalContents($i)
- ->submit('Test save ' . $i);
- }
-
- $this->assertSame(11, count($file->getChanges()), 'expected matching number of changes');
-
- for ($i=1; $i <= 11; $i++) {
- $file = File::fetch("//depot/testFile#$i");
-
- $this->assertSame(
- (string)($i-1),
- $file->getDepotContents(),
- 'expected matching value for revision '.$i
- );
- }
- }
-
- /**
- * Test rolling back a files content
- */
- public function testRollback()
- {
- $file = new File;
- $file->setFilespec("//depot/testFile")
- ->add()
- ->setLocalContents('0')
- ->submit('create file');
-
- for ($i=1; $i <= 10; $i++) {
- $file->edit()
- ->setLocalContents($i)
- ->setAttribute('number', (string)$i)
- ->submit('Test save ' . $i);
- }
-
- $this->assertSame(11, count($file->getChanges()), 'expected matching number of changes');
-
- $file = File::fetch('//depot/testFile#2');
- $this->assertSame(
- '//depot/testFile#2',
- $file->getFilespec(),
- 'expected rev in filespec pre rollback'
- );
-
- $file->sync()
- ->edit()
- ->submit('rollin rollin rollin', File::RESOLVE_ACCEPT_YOURS);
-
- $this->assertSame(
- '//depot/testFile',
- $file->getFilespec(),
- 'expected updated filespec post rollback'
- );
- $this->assertSame(
- '1',
- File::fetch('//depot/testFile')->getDepotContents(),
- 'expected matching content post rollback'
- );
- $this->assertSame(
- '1',
- File::fetch('//depot/testFile')->getAttribute('number'),
- 'expected matching attribute post rollback'
- );
- }
-
- /**
- * Test competing adds
- *
- * @expectedException \P4\Connection\Exception\ConflictException
- */
- public function testCompetingAdds()
- {
- // create a second workspace.
- $clientOne = Client::fetch($this->p4->getClient());
- $clientTwo = new Client;
- $clientTwo->setId($clientOne->getId() . "-2")
- ->setRoot($clientOne->getRoot() . "-2")
- ->setView(array('//depot/... //' . $clientOne->getId() . '-2/...'))
- ->save();
-
- // create a second connection.
- $p4One = $this->p4;
- $p4Two = \P4\Connection\Connection::factory(
- $p4One->getPort(),
- $p4One->getUser(),
- $clientTwo->getId(),
- $p4One->getPassword()
- )->connect();
-
- $fileOne = new File($p4One);
- $fileOne->setFilespec('//depot/foo')
- ->setLocalContents('test one')
- ->add();
-
- $fileTwo = new File($p4Two);
- $fileTwo->setFilespec('//depot/foo')
- ->setLocalContents('test two')
- ->add();
-
- // conflict (can't help the user!)
- $fileOne->submit('test one');
- $fileTwo->submit('test two', File::RESOLVE_ACCEPT_YOURS);
- }
-
- /**
- * Test competing edits
- */
- public function testCompetingEdits()
- {
- // create a second workspace.
- $clientOne = Client::fetch($this->p4->getClient());
- $clientTwo = new Client;
- $clientTwo->setId($clientOne->getId() . "-2")
- ->setRoot($clientOne->getRoot() . "-2")
- ->setView(array('//depot/... //' . $clientOne->getId() . '-2/...'))
- ->save();
-
- // create a second connection.
- $p4One = $this->p4;
- $p4Two = \P4\Connection\Connection::factory(
- $p4One->getPort(),
- $p4One->getUser(),
- $clientTwo->getId(),
- $p4One->getPassword()
- )->connect();
-
- $fileOne = new File($p4One);
- $fileOne->setFilespec('//depot/foo')
- ->setLocalContents('test one')
- ->add()
- ->submit('inital add');
-
- $fileOne = File::fetch('//depot/foo', $p4One);
- $fileOne->edit()->setLocalContents('test two');
-
- $fileTwo = File::fetch('//depot/foo', $p4Two);
- $fileTwo->sync()->edit()->setLocalContents('test three');
-
- // conflict
- $fileOne->submit('test two')->edit()->setLocalContents('test laksdfj')->submit('lkasdfj');
- $fileTwo->submit('test three', File::RESOLVE_ACCEPT_YOURS);
- }
-
- /**
- * Test edit of deleted file.
- *
- * @expectedException \P4\File\Exception\Exception
- */
- public function testEditOfDeleted()
- {
- $file = new File;
- $file->setFilespec('//depot/foo')
- ->setLocalContents('one')
- ->add()
- ->submit('one');
-
- $file->edit()
- ->setLocalContents('two')
- ->submit('two');
-
- $file->delete()
- ->submit('three');
-
- $file = File::fetch('//depot/foo#1');
-
- // should throw.
- $file->sync()->edit();
- }
-
- /**
- * Test delete of deleted file.
- *
- * @expectedException \P4\File\Exception\Exception
- */
- public function testDeleteOfDeleted()
- {
- $file = new File;
- $file->setFilespec('//depot/foo')
- ->setLocalContents('one')
- ->add()
- ->submit('one');
-
- $file->edit()
- ->setLocalContents('two')
- ->submit('two');
-
- $file->delete()
- ->submit('three');
-
- $file = File::fetch('//depot/foo#1');
-
- // should throw.
- $file->sync()->delete();
- }
-
- /**
- * Test a corner case -- sync, edit and submit a file after removing it
- * from the client workspace and opening it for delete with -v.
- */
- public function testDeleteSyncEdit()
- {
- $file = new File;
- $file->setFilespec('//depot/foo')
- ->touchLocalFile()
- ->add()
- ->submit('test');
-
- $file->setFilespec('//depot/foo#0')->sync();
-
- $file = new File;
- $file->setFilespec('//depot/foo')
- ->delete();
-
- $file->sync()->edit()->submit('test');
- }
-
- /**
- * Verify attribute setting doesn't exceed p4d's N_OPTS limit.
- */
- public function testOptionLimit()
- {
- $file = new File;
- $file->setFilespec('//depot/foo');
- $file->open();
-
- $limit = $file->getConnection()->getOptionLimit() + 1;
- $attributes = array_fill(0, $limit, 'attribute');
- $file->clearAttributes($attributes);
- }
-
- /**
- * Test revert and revert unchanged.
- */
- public function testRevert()
- {
- $file = new File;
- $file->setFilespec('//depot/foo')
- ->setLocalContents('test content')
- ->add()
- ->submit('adding file');
-
- // no change, should revert.
- $file->edit()
- ->revert(File::REVERT_UNCHANGED);
- $this->assertFalse($file->isOpened());
-
- // content change, should not revert.
- $file->edit()
- ->setLocalContents('new content')
- ->revert(File::REVERT_UNCHANGED);
- $this->assertTrue($file->isOpened());
-
- // should revert regardless.
- $file->revert();
- $this->assertFalse($file->isOpened());
- }
- }