From eae342699059215fc50ddd7a414bf14664ed1496 Mon Sep 17 00:00:00 2001 From: Baptiste Langlade Date: Sun, 14 Jun 2020 11:13:06 +0200 Subject: [PATCH 1/7] fix test --- tests/OperatingSystem/Remote/Ssh/VolumesTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/OperatingSystem/Remote/Ssh/VolumesTest.php b/tests/OperatingSystem/Remote/Ssh/VolumesTest.php index 9dee4fc..a8869cd 100644 --- a/tests/OperatingSystem/Remote/Ssh/VolumesTest.php +++ b/tests/OperatingSystem/Remote/Ssh/VolumesTest.php @@ -31,7 +31,7 @@ public function testInterface() VolumesInterface::class, new Volumes( $this->createMock(VolumesInterface::class), - Authority::any()->values()->current()->unwrap(), + $this->seeder()(Authority::any()), $this->createMock(SendActivity::class), ), ); From add3382bb073a803c395f275a15719315715bd34 Mon Sep 17 00:00:00 2001 From: Baptiste Langlade Date: Sun, 14 Jun 2020 13:01:17 +0200 Subject: [PATCH 2/7] use blackbox printer --- phpunit.xml.dist | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 48faee0..57135cb 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,6 +1,6 @@ - + ./tests From 78028e2dc57438b47a277d452fe8c6a7771c3bb8 Mon Sep 17 00:00:00 2001 From: Baptiste Langlade Date: Sun, 14 Jun 2020 15:22:22 +0200 Subject: [PATCH 3/7] only run 10 scenarii on dev environment --- phpunit.xml.dist | 3 +++ 1 file changed, 3 insertions(+) diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 57135cb..e631ed2 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,6 +1,9 @@ + + + ./tests From 6077532643f6cdf4004833f5a7fdff9a50a588da Mon Sep 17 00:00:00 2001 From: Baptiste Langlade Date: Sun, 14 Jun 2020 15:25:41 +0200 Subject: [PATCH 4/7] send activity for all loaded files (even inside directories) --- src/OperatingSystem/Filesystem/Adapter.php | 39 ++-- src/OperatingSystem/Filesystem/Directory.php | 151 +++++++++++++ src/OperatingSystem/Filesystem/File.php | 45 ++++ .../Filesystem/AdapterTest.php | 51 ++++- .../Filesystem/DirectoryTest.php | 208 ++++++++++++++++++ tests/OperatingSystem/Filesystem/FileTest.php | 61 +++++ 6 files changed, 534 insertions(+), 21 deletions(-) create mode 100644 src/OperatingSystem/Filesystem/Directory.php create mode 100644 src/OperatingSystem/Filesystem/File.php create mode 100644 tests/OperatingSystem/Filesystem/DirectoryTest.php create mode 100644 tests/OperatingSystem/Filesystem/FileTest.php diff --git a/src/OperatingSystem/Filesystem/Adapter.php b/src/OperatingSystem/Filesystem/Adapter.php index d1c4433..9ad3ad6 100644 --- a/src/OperatingSystem/Filesystem/Adapter.php +++ b/src/OperatingSystem/Filesystem/Adapter.php @@ -6,12 +6,12 @@ use Innmind\SilentCartographer\{ SendActivity, Room\Program\Activity\Filesystem\FilePersisted, - Room\Program\Activity\Filesystem\FileLoaded, Room\Program\Activity\Filesystem\FileRemoved, }; use Innmind\Filesystem\{ Adapter as AdapterInterface, - File, + File as FileInterface, + Directory as DirectoryInterface, Name, }; use Innmind\Url\Path; @@ -21,7 +21,7 @@ final class Adapter implements AdapterInterface { private AdapterInterface $adapter; private SendActivity $send; - private string $path; + private Path $path; public function __construct( AdapterInterface $adapter, @@ -30,10 +30,10 @@ public function __construct( ) { $this->adapter = $adapter; $this->send = $send; - $this->path = \rtrim($path->toString(), '/'); + $this->path = $path; } - public function add(File $file): void + public function add(FileInterface $file): void { ($this->send)(new FilePersisted($this->path($file->name()))); $this->adapter->add($file); @@ -42,11 +42,9 @@ public function add(File $file): void /** * {@inheritdoc} */ - public function get(Name $file): File + public function get(Name $file): FileInterface { - ($this->send)(new FileLoaded($this->path($file))); - - return $this->adapter->get($file); + return $this->wrap($this->adapter->get($file)); } public function contains(Name $file): bool @@ -68,16 +66,27 @@ public function remove(Name $file): void */ public function all(): Set { - $all = $this->adapter->all(); - $all->foreach(function(File $file): void { - ($this->send)(new FileLoaded($this->path($file->name()))); - }); + return $this + ->adapter + ->all() + ->map(fn(FileInterface $file): FileInterface => $this->wrap($file)); + } + + private function wrap(FileInterface $file): FileInterface + { + if ($file instanceof DirectoryInterface) { + return Directory::load( + $file, + $this->send, + $this->path->resolve(Path::of($file->name()->toString().'/')), + ); + } - return $all; + return new File($file, $this->send, $this->path); } private function path(Name $file): Path { - return Path::of($this->path.'/'.$file->toString()); + return $this->path->resolve(Path::of($file->toString())); } } diff --git a/src/OperatingSystem/Filesystem/Directory.php b/src/OperatingSystem/Filesystem/Directory.php new file mode 100644 index 0000000..d998ea5 --- /dev/null +++ b/src/OperatingSystem/Filesystem/Directory.php @@ -0,0 +1,151 @@ +directory = $directory; + $this->send = $send; + $this->path = $path; + } + + public static function load( + DirectoryInterface $directory, + SendActivity $send, + Path $path + ): self { + $self = new self($directory, $send, $path); + $send(new FileLoaded($path)); + + return $self; + } + + public function name(): Name + { + return $this->directory->name(); + } + + public function content(): Readable + { + return $this->directory->content(); + } + + public function mediaType(): MediaType + { + return $this->directory->mediaType(); + } + + public function add(FileInterface $file): DirectoryInterface + { + return new self( + $this->directory->add($file), + $this->send, + $this->path, + ); + } + + public function get(Name $name): FileInterface + { + return $this->wrap($this->directory->get($name)); + } + + public function contains(Name $name): bool + { + return $this->directory->contains($name); + } + + public function remove(Name $name): DirectoryInterface + { + $directory = $this->directory->remove($name); + + if ($directory === $this->directory) { + return $this; + } + + return new self( + $this->directory->remove($name), + $this->send, + $this->path, + ); + } + + public function replaceAt(Path $path, FileInterface $file): DirectoryInterface + { + return new self( + $this->directory->replaceAt($path, $file), + $this->send, + $this->path, + ); + } + + public function foreach(callable $function): void + { + $this->directory->foreach(function(FileInterface $file) use ($function): void { + $function($this->wrap($file)); + }); + } + + public function filter(callable $predicate): Set + { + return $this->directory->filter(function(FileInterface $file) use ($predicate): bool { + return $predicate($this->wrap($file)); + }); + } + + public function reduce($carry, callable $reducer) + { + /** @psalm-suppress MissingClosureParamType */ + return $this->directory->reduce( + $carry, + function($carry, FileInterface $file) use ($reducer) { + /** @psalm-suppress MixedArgument */ + return $reducer($carry, $this->wrap($file)); + }, + ); + } + + public function modifications(): Sequence + { + return $this->directory->modifications(); + } + + private function wrap(FileInterface $file): FileInterface + { + if ($file instanceof DirectoryInterface) { + return new self( + $file, + $this->send, + $this->path->resolve(Path::of($file->name()->toString().'/')), + ); + } + + return new File($file, $this->send, $this->path); + } +} diff --git a/src/OperatingSystem/Filesystem/File.php b/src/OperatingSystem/Filesystem/File.php new file mode 100644 index 0000000..5705240 --- /dev/null +++ b/src/OperatingSystem/Filesystem/File.php @@ -0,0 +1,45 @@ +file = $file; + $send(new FileLoaded($folder->resolve(Path::of($file->name()->toString())))); + } + + public function name(): Name + { + return $this->file->name(); + } + + public function content(): Readable + { + return $this->file->content(); + } + + public function mediaType(): MediaType + { + return $this->file->mediaType(); + } +} diff --git a/tests/OperatingSystem/Filesystem/AdapterTest.php b/tests/OperatingSystem/Filesystem/AdapterTest.php index 3e2857d..1694c2a 100644 --- a/tests/OperatingSystem/Filesystem/AdapterTest.php +++ b/tests/OperatingSystem/Filesystem/AdapterTest.php @@ -5,6 +5,8 @@ use Innmind\SilentCartographer\{ OperatingSystem\Filesystem\Adapter, + OperatingSystem\Filesystem\File as DecoratedFile, + OperatingSystem\Filesystem\Directory as DecoratedDirectory, SendActivity, Room\Program\Activity\Filesystem\FilePersisted, Room\Program\Activity\Filesystem\FileLoaded, @@ -13,11 +15,13 @@ use Innmind\Filesystem\{ Adapter as AdapterInterface, File, + Directory, Name, }; use Innmind\Url\Path; use Innmind\Stream\Readable; use Innmind\Immutable\Set; +use function Innmind\Immutable\first; use PHPUnit\Framework\TestCase; class AdapterTest extends TestCase @@ -64,7 +68,7 @@ public function testGet() $send = $this->createMock(SendActivity::class), Path::of('/tmp/') ); - $file = File\File::named( + $expected = File\File::named( 'foo', $this->createMock(Readable::class) ); @@ -76,9 +80,37 @@ public function testGet() ->expects($this->once()) ->method('get') ->with(new Name('foo')) - ->willReturn($file); + ->willReturn($expected); + + $file = $adapter->get(new Name('foo')); - $this->assertSame($file, $adapter->get(new Name('foo'))); + $this->assertInstanceOf(DecoratedFile::class, $file); + $this->assertSame($expected->name(), $file->name()); + $this->assertSame($expected->content(), $file->content()); + $this->assertSame($expected->mediaType(), $file->mediaType()); + } + + public function testGetDirectory() + { + $adapter = new Adapter( + $inner = $this->createMock(AdapterInterface::class), + $send = $this->createMock(SendActivity::class), + Path::of('/tmp/') + ); + $expected = Directory\Directory::named('foo'); + $send + ->expects($this->once()) + ->method('__invoke') + ->with(new FileLoaded(Path::of('/tmp/foo/'))); + $inner + ->expects($this->once()) + ->method('get') + ->with(new Name('foo')) + ->willReturn($expected); + + $directory = $adapter->get(new Name('foo')); + + $this->assertInstanceOf(DecoratedDirectory::class, $directory); } public function testHas() @@ -135,7 +167,7 @@ public function testAll() $send = $this->createMock(SendActivity::class), Path::of('/tmp/') ); - $file = File\File::named( + $expected = File\File::named( 'foo', $this->createMock(Readable::class) ); @@ -147,9 +179,16 @@ public function testAll() ->expects($this->once()) ->method('all') ->willReturn( - $all = Set::of(File::class, $file) + Set::of(File::class, $expected) ); - $this->assertSame($all, $adapter->all()); + $all = $adapter->all(); + + $this->assertInstanceOf(Set::class, $all); + $this->assertSame(File::class, $all->type()); + $this->assertInstanceOf(DecoratedFile::class, first($all)); + $this->assertSame($expected->name(), first($all)->name()); + $this->assertSame($expected->content(), first($all)->content()); + $this->assertSame($expected->mediaType(), first($all)->mediaType()); } } diff --git a/tests/OperatingSystem/Filesystem/DirectoryTest.php b/tests/OperatingSystem/Filesystem/DirectoryTest.php new file mode 100644 index 0000000..52d7647 --- /dev/null +++ b/tests/OperatingSystem/Filesystem/DirectoryTest.php @@ -0,0 +1,208 @@ +forAll( + Properties::properties(), + Fixture::any(), + Path::directories(), + ) + ->then(function($properties, $inner, $path) { + $properties->ensureHeldBy(Directory::load( + $inner, + $this->createMock(SendActivity::class), + $path, + )); + }); + } + + public function testSendActivityWhenLoadingDirectory() + { + $this + ->forAll( + Fixture::any(), + Path::directories(), + ) + ->then(function($inner, $path) { + $send = $this->createMock(SendActivity::class); + $send + ->expects($this->once()) + ->method('__invoke') + ->with($this->callback(function(FileLoaded $activity) use ($path) { + return $activity->path() === $path; + })); + + Directory::load($inner, $send, $path); + }); + } + + public function testContentIsNotAltered() + { + $this + ->forAll( + Fixture::any(), + Path::directories(), + ) + ->then(function($inner, $path) { + $file = Directory::load( + $inner, + $this->createMock(SendActivity::class), + $path, + ); + + $this->assertSame($inner->name(), $file->name()); + $this->assertSame($inner->content(), $file->content()); + $this->assertSame($inner->mediaType(), $file->mediaType()); + }); + } + + public function testAddingFileDoesntSendActivity() + { + $this + ->forAll( + Fixture::any(), + File::any(), + Path::directories(), + ) + ->then(function($inner, $file, $path) { + $send = $this->createMock(SendActivity::class); + $send + ->expects($this->once()) + ->method('__invoke'); + + $directory = Directory::load($inner, $send, $path)->add($file); + $this->assertInstanceOf(Directory::class, $directory); + }); + } + + public function testReplaceAtConserveDecoration() + { + $this + ->forAll( + Fixture::any(), + Path::any(), + File::any() + ) + ->then(function($inner, $path, $file) { + $send = $this->createMock(SendActivity::class); + $send + ->expects($this->once()) + ->method('__invoke'); + $directory = Directory::load($inner, $send, $path)->replaceAt( + RealPath::of('/'), + $file, + ); + + $this->assertInstanceOf(Directory::class, $directory); + }); + } + + public function testForeachDecorateFiles() + { + $this + ->forAll( + Fixture::any(), + Path::any(), + ) + ->then(function($inner, $path) { + $directory = Directory::load( + $inner, + $this->createMock(SendActivity::class), + $path, + ); + + $directory->foreach(function($file) { + $this->assertThat( + $file, + $this->logicalOr( + $this->isInstanceOf(Directory::class), + $this->isInstanceOf(DecoratedFile::class), + ), + ); + }); + }); + } + + public function testFilterDecorateFiles() + { + $this + ->forAll( + Fixture::any(), + Path::any(), + ) + ->then(function($inner, $path) { + $directory = Directory::load( + $inner, + $this->createMock(SendActivity::class), + $path, + ); + + $directory->filter(function($file) { + $this->assertThat( + $file, + $this->logicalOr( + $this->isInstanceOf(Directory::class), + $this->isInstanceOf(DecoratedFile::class), + ), + ); + + return true; + }); + }); + } + + public function testReduceDecorateFiles() + { + $this + ->forAll( + Fixture::any(), + Path::any(), + ) + ->then(function($inner, $path) { + $directory = Directory::load( + $inner, + $this->createMock(SendActivity::class), + $path, + ); + + $directory->reduce(null, function($carry, $file) { + $this->assertThat( + $file, + $this->logicalOr( + $this->isInstanceOf(Directory::class), + $this->isInstanceOf(DecoratedFile::class), + ), + ); + + return null; + }); + }); + } +} diff --git a/tests/OperatingSystem/Filesystem/FileTest.php b/tests/OperatingSystem/Filesystem/FileTest.php new file mode 100644 index 0000000..358dbc9 --- /dev/null +++ b/tests/OperatingSystem/Filesystem/FileTest.php @@ -0,0 +1,61 @@ +forAll( + Fixture::any(), + Path::any(), + ) + ->then(function($inner, $path) { + $file = new File( + $inner, + $this->createMock(SendActivity::class), + $path, + ); + + $this->assertSame($inner->name(), $file->name()); + $this->assertSame($inner->content(), $file->content()); + $this->assertSame($inner->mediaType(), $file->mediaType()); + }); + } + + public function testActivityMessageContainsBothFolderAndFileNames() + { + $this + ->forAll( + Fixture::any(), + Path::directories(), + ) + ->then(function($inner, $path) { + $send = $this->createMock(SendActivity::class); + $send + ->expects($this->once()) + ->method('__invoke') + ->with($this->callback(function($activity) use ($inner, $path) { + return $activity->path()->toString() === $path->toString().$inner->name()->toString(); + })); + + new File($inner, $send, $path); + }); + } +} From 84326553e09d1fcc22bb24ba47bbea17f33b57df Mon Sep 17 00:00:00 2001 From: Baptiste Langlade Date: Sun, 14 Jun 2020 15:27:10 +0200 Subject: [PATCH 5/7] split jobs between coverage and full tests run --- .github/workflows/ci.yml | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ccd3fdc..79f50ee 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,6 +10,36 @@ jobs: os: [ubuntu-latest, macOS-latest] php-version: ['7.4'] name: 'PHPUnit - PHP/${{ matrix.php-version }} - OS/${{ matrix.os }}' + steps: + - name: Checkout + uses: actions/checkout@v1 + - name: Setup PHP + uses: shivammathur/setup-php@v1 + with: + php-version: ${{ matrix.php-version }} + extensions: mbstring, intl + - name: Get Composer Cache Directory + id: composer-cache + run: echo "::set-output name=dir::$(composer config cache-files-dir)" + - name: Cache dependencies + uses: actions/cache@v1 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} + restore-keys: ${{ runner.os }}-composer- + - name: Install Dependencies + run: composer install --no-progress + - name: PHPUnit + run: vendor/bin/phpunit --coverage-clover=coverage.clover + env: + CI: 'github' + coverage: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest, macOS-latest] + php-version: ['7.4'] + name: 'Coverage - PHP/${{ matrix.php-version }} - OS/${{ matrix.os }}' steps: - name: Checkout uses: actions/checkout@v1 @@ -19,7 +49,6 @@ jobs: php-version: ${{ matrix.php-version }} extensions: mbstring, intl coverage: xdebug - ini-values: xdebug.max_nesting_level=2048 - name: Get Composer Cache Directory id: composer-cache run: echo "::set-output name=dir::$(composer config cache-files-dir)" @@ -35,6 +64,7 @@ jobs: run: vendor/bin/phpunit --coverage-clover=coverage.clover env: CI: 'github' + BLACKBOX_SET_SIZE: '1' - uses: codecov/codecov-action@v1 with: token: ${{ secrets.CODECOV_TOKEN }} From c1b2c5a6b482ab3211a642187a1c111dbcfb18b4 Mon Sep 17 00:00:00 2001 From: Baptiste Langlade Date: Sun, 14 Jun 2020 15:37:24 +0200 Subject: [PATCH 6/7] replace eris by blackbox --- composer.json | 1 - tests/Room/Program/Activity/GenericTest.php | 14 +++++++------- tests/Room/Program/Activity/TagsTest.php | 20 ++++++++------------ 3 files changed, 15 insertions(+), 20 deletions(-) diff --git a/composer.json b/composer.json index 53371b8..e80e698 100644 --- a/composer.json +++ b/composer.json @@ -36,7 +36,6 @@ }, "require-dev": { "phpunit/phpunit": "~8.0", - "giorgiosironi/eris": "^0.11.0", "innmind/object-graph": "~2.0", "vimeo/psalm": "^3.10", "innmind/black-box": "^4.2" diff --git a/tests/Room/Program/Activity/GenericTest.php b/tests/Room/Program/Activity/GenericTest.php index dd523cc..55428fe 100644 --- a/tests/Room/Program/Activity/GenericTest.php +++ b/tests/Room/Program/Activity/GenericTest.php @@ -9,22 +9,22 @@ Activity\Tags, }; use PHPUnit\Framework\TestCase; -use Eris\{ - Generator, - TestTrait, +use Innmind\BlackBox\{ + PHPUnit\BlackBox, + Set, }; class GenericTest extends TestCase { - use TestTrait; + use BlackBox; public function testInterface() { $this ->forAll( - Generator\string(), - Generator\string(), - Generator\string() + Set\Unicode::strings(), + Set\Unicode::strings(), + Set\Unicode::strings() ) ->then(function($s1, $s2, $s3): void { $activity = new Generic( diff --git a/tests/Room/Program/Activity/TagsTest.php b/tests/Room/Program/Activity/TagsTest.php index 5b6d632..c2c4620 100644 --- a/tests/Room/Program/Activity/TagsTest.php +++ b/tests/Room/Program/Activity/TagsTest.php @@ -5,27 +5,23 @@ use Innmind\SilentCartographer\Room\Program\Activity\Tags; use PHPUnit\Framework\TestCase; -use Eris\{ - Generator, - TestTrait, +use Innmind\BlackBox\{ + PHPUnit\BlackBox, + Set, }; class TagsTest extends TestCase { - use TestTrait; + use BlackBox; public function testInterface() { $this - ->forAll( - Generator\string(), - Generator\string(), - Generator\string() - ) - ->then(function($s1, $s2, $s3): void { + ->forAll(Set\Sequence::of(Set\Unicode::strings())) + ->then(function($tags): void { $this->assertSame( - [$s1, $s2, $s3], - (new Tags($s1, $s2, $s3))->list(), + $tags, + (new Tags(...$tags))->list(), ); }); } From ab5f5976f61f419c0199e8071ca0aa889877f276 Mon Sep 17 00:00:00 2001 From: Baptiste Langlade Date: Sun, 14 Jun 2020 15:54:38 +0200 Subject: [PATCH 7/7] add roave bc check --- .github/workflows/ci.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 79f50ee..ccc5234 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -3,6 +3,15 @@ name: CI on: [push] jobs: + roave_bc_check: + name: Roave BC Check + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@master + - name: fetch tags + run: git fetch --depth=1 origin +refs/tags/*:refs/tags/* + - name: Roave BC Check + uses: docker://nyholm/roave-bc-check-ga phpunit: runs-on: ${{ matrix.os }} strategy: