diff --git a/src/Node/DirectoryLink.php b/src/Node/DirectoryLink.php new file mode 100644 index 0000000..78296ae --- /dev/null +++ b/src/Node/DirectoryLink.php @@ -0,0 +1,104 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Vfs\Node; + +use DateTime; + +class DirectoryLink implements NodeContainerInterface, LinkInterface +{ + protected $dateAccessed; + protected $dateCreated; + protected $dateModified; + protected $file; + protected $mode; + + /** + * @param NodeContainerInterface $directory + */ + public function __construct(NodeContainerInterface $directory) + { + $this->directory = $directory; + $this->mode = self::TYPE_LINK; + + $this->dateAccessed = new DateTime(); + $this->dateCreated = clone $this->dateAccessed; + $this->dateModified = clone $this->dateAccessed; + } + + public function add($name, NodeInterface $node) + { + $this->directory->add($name, $node); + } + + public function get($name) + { + return $this->directory->get($name); + } + + public function has($name) + { + return $this->directory->has($name); + } + + public function remove($name) + { + $this->directory->remove($name); + } + + public function set($name, NodeInterface $node) + { + $this->directory->set($name, $node); + } + + public function getDateAccessed() + { + return $this->dateAccessed; + } + + public function setDateAccessed(DateTime $dateTime) + { + $this->dateAccessed = $dateTime; + } + + public function getDateCreated() + { + return $this->dateCreated; + } + + public function getDateModified() + { + return $this->dateModified; + } + + public function setDateModified(DateTime $dateTime) + { + $this->dateModified = $dateTime; + } + + public function getIterator() + { + return $this->directory->getIterator(); + } + + public function getMode() + { + return $this->mode; + } + + public function getSize() + { + return $this->directory->getSize(); + } + + public function getTarget() + { + return $this->directory; + } +} diff --git a/src/Node/FileLink.php b/src/Node/FileLink.php new file mode 100644 index 0000000..58bff67 --- /dev/null +++ b/src/Node/FileLink.php @@ -0,0 +1,84 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace Vfs\Node; + +use DateTime; + +class FileLink implements FileInterface, LinkInterface +{ + protected $dateAccessed; + protected $dateCreated; + protected $dateModified; + protected $file; + protected $mode; + + /** + * @param FileInterface $file + */ + public function __construct(FileInterface $file) + { + $this->file = $file; + $this->mode = self::TYPE_LINK; + + $this->dateAccessed = new DateTime(); + $this->dateCreated = clone $this->dateAccessed; + $this->dateModified = clone $this->dateAccessed; + } + + public function getContent() + { + return $this->file->getContent(); + } + + public function setContent($content) + { + $this->file->setContent($content); + } + + public function getDateAccessed() + { + return $this->dateAccessed; + } + + public function setDateAccessed(DateTime $dateTime) + { + $this->dateAccessed = $dateTime; + } + + public function getDateCreated() + { + return $this->dateCreated; + } + + public function getDateModified() + { + return $this->dateModified; + } + + public function setDateModified(DateTime $dateTime) + { + $this->dateModified = $dateTime; + } + + public function getMode() + { + return $this->mode; + } + + public function getSize() + { + return $this->file->getSize(); + } + + public function getTarget() + { + return $this->file; + } +} diff --git a/src/Node/LinkInterface.php b/src/Node/LinkInterface.php index e52df13..fd4b63f 100644 --- a/src/Node/LinkInterface.php +++ b/src/Node/LinkInterface.php @@ -9,6 +9,16 @@ */ namespace Vfs\Node; +/** + * Link node type + * + * This is an implementation of a hard link rather than a symbolic link; the + * key difference being it links directly to a node and not a path. If the + * target node is moved or renamed the link remains intact. + * + * The implementation is a simple proxy, whereby most other method calls should + * proxy through to the target where suitable. + */ interface LinkInterface extends NodeInterface { /** diff --git a/src/Node/StatInterface.php b/src/Node/StatInterface.php index 5841af2..afbbd60 100644 --- a/src/Node/StatInterface.php +++ b/src/Node/StatInterface.php @@ -41,6 +41,7 @@ interface StatInterface const S_IWOTH = 0000002; const S_IXOTH = 0000001; + const TYPE_MASK = self::S_IFMT; const TYPE_SOCKET = self::S_IFSOCK; const TYPE_LINK = self::S_IFLNK; const TYPE_FILE = self::S_IFREG; diff --git a/test/unit/Node/DirectoryLinkTest.php b/test/unit/Node/DirectoryLinkTest.php new file mode 100644 index 0000000..7a75a6e --- /dev/null +++ b/test/unit/Node/DirectoryLinkTest.php @@ -0,0 +1,118 @@ +nodeA = $a = Mockery::mock('Vfs\Node\NodeInterface'); + $this->nodeB = $b = Mockery::mock('Vfs\Node\NodeInterface'); + $this->nodeC = $c = Mockery::mock('Vfs\Node\NodeInterface'); + $this->nodes = ['foo' => $a, 'bar' => $b, 'baz' => $c]; + } + + public function testInstance() + { + $link = new DirectoryLink(new Directory()); + + $this->assertInstanceOf('Vfs\Node\NodeContainerInterface', $link); + $this->assertInstanceOf('Vfs\Node\LinkInterface', $link); + $this->assertInstanceOf('Vfs\Node\NodeInterface', $link); + $this->assertInstanceOf('Vfs\Node\StatInterface', $link); + } + + public function testAdd() + { + $dir = new Directory(); + $link = new DirectoryLink($dir); + $link->add('foo', $this->nodeA); + + $this->assertSame($this->nodeA, $dir->get('foo')); + } + + public function testGet() + { + $link = new DirectoryLink(new Directory($this->nodes)); + + $this->assertSame($this->nodeA, $link->get('foo')); + } + + public function testGetThrowsMissingNode() + { + $link = new DirectoryLink(new Directory()); + $this->setExpectedException('Vfs\Exception\MissingNodeException'); + + $link->get('foo'); + } + + public function testHasIsTrue() + { + $link = new DirectoryLink(new Directory($this->nodes)); + + $this->assertTrue($link->has('foo')); + } + + public function testHasIsFalse() + { + $link = new DirectoryLink(new Directory()); + + $this->assertFalse($link->has('foo')); + } + + public function testSet() + { + $dir = new Directory(); + $link = new DirectoryLink($dir); + $link->set('foo', $this->nodeA); + + $this->assertSame($this->nodeA, $dir->get('foo')); + } + + public function testGetDateAccessed() + { + $dir = new Directory(); + $link = new DirectoryLink($dir); + + $this->assertInstanceOf('DateTime', $link->getDateAccessed()); + $this->assertNotSame($link->getDateAccessed(), $dir->getDateAccessed()); + } + + public function testGetDateCreated() + { + $dir = new Directory(); + $link = new DirectoryLink($dir); + + $this->assertInstanceOf('DateTime', $link->getDateCreated()); + $this->assertNotSame($link->getDateCreated(), $dir->getDateCreated()); + } + + public function testGetDateModified() + { + $dir = new Directory(); + $link = new DirectoryLink($dir); + + $this->assertInstanceOf('DateTime', $link->getDateModified()); + $this->assertNotSame($link->getDateModified(), $dir->getDateModified()); + } + + public function testGetMode() + { + $link = new DirectoryLink(new Directory()); + + $this->assertEquals(StatInterface::TYPE_LINK, $link->getMode() & StatInterface::TYPE_MASK); + } + + public function testGetSize() + { + $link = new DirectoryLink(new Directory($this->nodes)); + + $this->nodeA->shouldReceive('getSize')->once()->withNoArgs()->andReturn(1); + $this->nodeB->shouldReceive('getSize')->once()->withNoArgs()->andReturn(2); + $this->nodeC->shouldReceive('getSize')->once()->withNoArgs()->andReturn(3); + + $this->assertEquals(6, $link->getSize()); + } +} diff --git a/test/unit/Node/FileLinkTest.php b/test/unit/Node/FileLinkTest.php new file mode 100644 index 0000000..c117a41 --- /dev/null +++ b/test/unit/Node/FileLinkTest.php @@ -0,0 +1,74 @@ +assertInstanceOf('Vfs\Node\FileInterface', $link); + $this->assertInstanceOf('Vfs\Node\LinkInterface', $link); + $this->assertInstanceOf('Vfs\Node\NodeInterface', $link); + $this->assertInstanceOf('Vfs\Node\StatInterface', $link); + } + + public function testGetContent() + { + $link = new FileLink(new File('foo')); + + $this->assertEquals('foo', $link->getContent()); + } + + public function testSetContent() + { + $file = new File(''); + $link = new FileLink($file); + $link->setContent('foo'); + + $this->assertEquals('foo', $file->getContent()); + } + + public function testGetDateAccessed() + { + $file = new File(); + $link = new FileLink($file); + + $this->assertInstanceOf('DateTime', $link->getDateAccessed()); + $this->assertNotSame($link->getDateAccessed(), $file->getDateAccessed()); + } + + public function testGetDateCreated() + { + $file = new File(); + $link = new FileLink($file); + + $this->assertInstanceOf('DateTime', $link->getDateCreated()); + $this->assertNotSame($link->getDateCreated(), $file->getDateCreated()); + } + + public function testGetDateModified() + { + $file = new File(); + $link = new FileLink($file); + + $this->assertInstanceOf('DateTime', $link->getDateModified()); + $this->assertNotSame($link->getDateModified(), $file->getDateModified()); + } + + public function testGetMode() + { + $link = new FileLink(new File()); + + $this->assertEquals(StatInterface::TYPE_LINK, $link->getMode() & StatInterface::TYPE_MASK); + } + + public function testGetSize() + { + $link = new FileLink(new File('foo')); + + $this->assertEquals(3, $link->getSize()); + } +}