Skip to content

Instantly share code, notes, and snippets.

@jubianchi
Last active December 25, 2015 15:29
Show Gist options
  • Select an option

  • Save jubianchi/6998632 to your computer and use it in GitHub Desktop.

Select an option

Save jubianchi/6998632 to your computer and use it in GitHub Desktop.
<?php
namespace
{
use mageekguy\atoum;
require_once __DIR__ . '/../vendor/autoload.php';
class locker
{
protected $adapter;
public function __construct(atoum\adapter $adapter = null)
{
$this->adapter = $adapter ?: new atoum\adapter();
}
public function lock($handle)
{
if(false === $this->adapter->flock($handle, LOCK_EX)) {
throw new \RuntimeException('Could not lock file');
}
return $this;
}
public function unlock($handle)
{
if(false === $this->adapter->flock($handle, LOCK_UN)) {
throw new \RuntimeException('Could not unlock file');
}
return $this;
}
}
class writer
{
protected $path;
protected $locker;
protected $adapter;
protected $handle;
public function __construct($path, locker $locker = null, atoum\adapter $adapter = null)
{
$this->path = $path;
$this->adapter = $adapter ?: new atoum\adapter();
$this->locker = $locker ?: new locker($this->adapter);
}
public function getPath()
{
return $this->path;
}
public function open()
{
if (false === file_exists($this->path))
{
throw new \RuntimeException(sprintf('File %s does not exist', $this->path));
}
$this->handle = $this->adapter->fopen($this->path, 'w');
if (false === $this->handle)
{
$this->handle = null;
throw new \RuntimeException(sprintf('Could not open %s for writing', $this->path));
}
try
{
$this->locker->lock($this->handle);
}
catch (\RuntimeException $exception)
{
$this->close();
throw new \RuntimeException(sprintf('Could not lock %s', $this->path), null, $exception);
}
return $this;
}
public function write($str)
{
if (false === is_writable($this->isOpen()->path))
{
throw new \RuntimeException(sprintf('File %s is not writable', $this->path));
}
if(false === $this->adapter->fwrite($this->handle, $str))
{
throw new \RuntimeException(sprintf('Could not write to %s', $this->path));
}
return $this;
}
public function close()
{
try
{
$this->locker->unlock($this->isOpen()->handle);
}
catch (\RuntimeException $exception) {}
$this->adapter->fclose($this->handle);
$this->handle = null;
return $this;
}
protected function isOpen()
{
if (null === $this->handle)
{
throw new \LogicException(sprintf('File %s was not opened', $this->path));
}
return $this;
}
}
}
namespace tests\units
{
use
mageekguy\atoum,
mageekguy\atoum\mock\streams\fs,
locker as testedLocker,
writer as testedWriter
;
class locker extends atoum
{
public function testLock()
{
$this
->if($handle = fopen((string) fs\file::get(), 'r'))
->and($adapter = new atoum\test\adapter())
->and($locker = new testedLocker($adapter))
->then
->object($locker->lock($handle))->isIdenticalTo($locker)
->adapter($adapter)
->call('flock')->withArguments($handle, LOCK_EX)->once()
->if($adapter->flock = false)
->then
->exception(function() use ($locker, $handle) {
$locker->lock($handle);
})
->isInstanceOf('RuntimeException')
->hasMessage('Could not lock file')
;
}
public function testUnlock()
{
$this
->if($handle = fopen((string) fs\file::get(), 'r'))
->and($adapter = new atoum\test\adapter())
->and($locker = new testedLocker($adapter))
->then
->object($locker->unlock($handle))->isIdenticalTo($locker)
->adapter($adapter)
->call('flock')->withArguments($handle, LOCK_UN)->once()
->if($adapter->flock = false)
->then
->exception(function() use ($locker, $handle) {
$locker->unlock($handle);
})
->isInstanceOf('RuntimeException')
->hasMessage('Could not unlock file')
;
}
}
class writer extends atoum
{
public function test__construct()
{
$this
->if($writer = new testedWriter($path = uniqid()))
->then
->string($writer->getPath())->isEqualTo($path)
;
}
public function testOpen()
{
$this
->given($file = fs\file::get())
->and($adapter = new atoum\test\adapter())
->and($locker = new \mock\locker($adapter))
->and($writer = new testedWriter((string) $file, $locker, $adapter))
->if($file->notExists())
->then
->exception(function() use ($writer) {
$writer->open();
})
->isInstanceOf('RuntimeException')
->hasMessage(sprintf('File %s does not exist', $file))
->if($file->exists())
->and($adapter->fopen = false)
->then
->exception(function() use ($writer) {
$writer->open();
})
->isInstanceOf('RuntimeException')
->hasMessage(sprintf('Could not open %s for writing', $file))
->if($this->resetAdapter($adapter))
->and($this->resetMock($locker))
->and($this->calling($locker)->lock->throw = $exception = new \RuntimeException())
->and($this->calling($locker)->unlock = $locker)
->and($adapter->fopen = $handle = uniqid())
->and($adapter->fclose = true)
->then
->exception(function() use ($writer) {
$writer->open();
})
->isInstanceOf('RuntimeException')
->hasMessage(sprintf('Could not lock %s', $file))
->object($this->exception->getPrevious())->isIdenticalTo($exception)
->adapter($adapter)
->call('fclose')->withArguments($handle)
->after($this->adapter($adapter)->call('fopen')->withArguments((string) $file, 'w'))
->after($this->mock($locker)->call('lock')->withArguments($handle))
->after($this->mock($locker)->call('unlock')->withArguments($handle))
->once()
->mock($locker)
->call('lock')->withArguments($handle)
->after($this->adapter($adapter)->call('fopen')->withArguments((string) $file, 'w'))
->once()
->call('unlock')->withArguments($handle)
->before($this->adapter($adapter)->call('fclose')->withArguments($handle))
->once()
->if($this->resetAdapter($adapter))
->and($this->resetMock($locker))
->and($this->calling($locker)->lock = $locker)
->and($this->calling($locker)->unlock = $locker)
->then
->object($writer->open())->isIdenticalTo($writer)
->adapter($adapter)
->call('fopen')->withArguments((string) $file, 'w')
->before($this->mock($locker)->call('lock')->withArguments($handle))
->once()
;
}
public function testWrite()
{
$this
->given($file = fs\file::get())
->and($adapter = new atoum\test\adapter())
->if($writer = new testedWriter((string) $file, null, $adapter))
->then
->exception(function() use ($writer) {
$writer->write(uniqid());
})
->isInstanceOf('LogicException')
->hasMessage(sprintf('File %s was not opened', $file))
->if($writer->open())
->and($file->isNotWritable())
->then
->exception(function() use ($writer) {
$writer->write(uniqid());
})
->isInstanceOf('RuntimeException')
->hasMessage(sprintf('File %s is not writable', $file))
->if($file->isWritable())
->then
->object($writer->write($str = uniqid()))->isIdenticalTo($writer)
->adapter($file)
->call('stream_write')->withArguments($str)->once()
->if($adapter->fwrite = false)
->then
->exception(function() use ($writer) {
$writer->write(uniqid());
})
->isInstanceOf('RuntimeException')
->hasMessage(sprintf('Could not write to %s', $file))
;
}
public function testClose()
{
$this
->given($file = fs\file::get())
->and($adapter = new atoum\test\adapter())
->and($locker = new \mock\locker($adapter))
->if($writer = new testedWriter((string) $file, $locker, $adapter))
->then
->exception(function() use ($writer) {
$writer->close();
})
->isInstanceOf('LogicException')
->hasMessage(sprintf('File %s was not opened', $file))
->if($adapter->fopen = $handle = uniqid())
->and($adapter->fclose = true)
->and($this->calling($locker)->lock = $locker)
->and($this->calling($locker)->unlock = $locker)
->and($writer->open())
->then
->object($writer->close())->isIdenticalTo($writer)
->adapter($adapter)
->call('fclose')->withArguments($handle)
->after($this->mock($locker)->call('unlock')->withArguments($handle))
->once()
;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment