diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index 9b32f13..9e7499d 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -55,4 +55,4 @@ jobs: composer require "laravel/framework:${{ matrix.laravel }}" "orchestra/testbench:${{ matrix.testbench }}" --no-interaction --no-update composer update --${{ matrix.stability }} --prefer-dist --no-interaction - name: Execute tests - run: vendor/bin/phpunit --no-coverage + run: vendor/bin/pest --no-coverage diff --git a/composer.json b/composer.json index 6e53f8a..c8f2849 100644 --- a/composer.json +++ b/composer.json @@ -26,6 +26,7 @@ "require-dev": { "mockery/mockery": "^1.4", "orchestra/testbench": "^5.0|^6.0|^7.0", + "pestphp/pest-plugin-laravel": "^1.3", "phpunit/phpunit": "^9.5" }, "autoload": { @@ -39,10 +40,13 @@ } }, "scripts": { - "test": "vendor/bin/phpunit" + "test": "vendor/bin/pest" }, "config": { - "sort-packages": true + "sort-packages": true, + "allow-plugins": { + "pestphp/pest-plugin": true + } }, "extra": { "laravel": { @@ -53,4 +57,4 @@ }, "minimum-stability": "dev", "prefer-stable": true -} +} \ No newline at end of file diff --git a/tests/Commands/CleanupTest.php b/tests/Commands/CleanupTest.php index c7d8020..fcee7e1 100644 --- a/tests/Commands/CleanupTest.php +++ b/tests/Commands/CleanupTest.php @@ -1,53 +1,41 @@ clearDisk(); +it('can delete old snapshots keeping the desired number of snapshots', function () { + // Add sleep to make sure files do not have the same modified time. + // They may not sort properly if all have the same timestamp. + clearDisk(); - $this->disk->put('snapshot1.sql', 'new content'); + $this->disk->put('snapshot1.sql', 'new content'); - sleep(1); + sleep(1); - $this->disk->put('snapshot2.sql', 'new content'); + $this->disk->put('snapshot2.sql', 'new content'); - Artisan::call('snapshot:cleanup', ['--keep' => 1]); + Artisan::call('snapshot:cleanup', ['--keep' => 1]); - $this->disk->assertMissing('snapshot1.sql'); - $this->disk->assertExists('snapshot2.sql'); - } + $this->disk->assertMissing('snapshot1.sql'); + $this->disk->assertExists('snapshot2.sql'); +}); - /** @test */ - public function it_can_delete_all_snapshots_if_keep_is_zero() - { - $this->clearDisk(); +it('can delete all snapshots if keep is zero', function () { + clearDisk(); - $this->disk->put('snapshot.sql', 'new content'); + $this->disk->put('snapshot.sql', 'new content'); - Artisan::call('snapshot:cleanup --keep=0'); + Artisan::call('snapshot:cleanup --keep=0'); - $this->disk->assertMissing('snapshot.sql'); - } + $this->disk->assertMissing('snapshot.sql'); +}); - /** @test */ - public function it_warns_if_keep_is_not_specified() - { - $this->clearDisk(); +it('warns if keep is not specified', function () { + clearDisk(); - $this->disk->put('snapshot.sql', 'new content'); + $this->disk->put('snapshot.sql', 'new content'); - Artisan::call('snapshot:cleanup'); + Artisan::call('snapshot:cleanup'); - $this->disk->assertExists('snapshot.sql'); - $this->seeInConsoleOutput('No value for option --keep.'); - } -} + $this->disk->assertExists('snapshot.sql'); + seeInConsoleOutput('No value for option --keep.'); +}); diff --git a/tests/Commands/CreateTest.php b/tests/Commands/CreateTest.php index cd33634..77d1fcb 100644 --- a/tests/Commands/CreateTest.php +++ b/tests/Commands/CreateTest.php @@ -1,132 +1,114 @@ format('Y-m-d_H-i-s') . '.sql'; +it('can create a snapshot without a specific', function () { + Artisan::call('snapshot:create'); - $this->assertFileOnDiskPassesRegex($fileName, '/CREATE TABLE(?: IF NOT EXISTS){0,1} "models"/'); - $this->assertFileOnDiskPassesRegex($fileName, '/CREATE TABLE(?: IF NOT EXISTS){0,1} "users"/'); - $this->assertFileOnDiskPassesRegex($fileName, '/CREATE TABLE(?: IF NOT EXISTS){0,1} "posts"/'); - } + $fileName = Carbon::now()->format('Y-m-d_H-i-s') . '.sql'; - /** @test */ - public function it_can_create_a_snapshot_with_specific_name() - { - Artisan::call('snapshot:create', ['name' => 'test']); + expect($fileName) + ->fileOnDiskToPassRegex('/CREATE TABLE(?: IF NOT EXISTS){0,1} "models"/') + ->fileOnDiskToPassRegex('/CREATE TABLE(?: IF NOT EXISTS){0,1} "users"/') + ->fileOnDiskToPassRegex('/CREATE TABLE(?: IF NOT EXISTS){0,1} "posts"/'); +}); - $this->assertFileOnDiskPassesRegex('test.sql', '/CREATE TABLE(?: IF NOT EXISTS){0,1} "models"/'); - } +it('can create a snapshot with specific name') + ->tap(fn () => Artisan::call('snapshot:create', ['name' => 'test'])) + ->expect('test.sql') + ->fileOnDiskToPassRegex('/CREATE TABLE(?: IF NOT EXISTS){0,1} "models"/'); - /** @test */ - public function it_can_create_a_compressed_snapshot_from_cli_param() - { - Artisan::call('snapshot:create', ['--compress' => true]); +it('can create a compressed snapshot from CLI param', function () { + Artisan::call('snapshot:create', ['--compress' => true]); - $fileName = Carbon::now()->format('Y-m-d_H-i-s') . '.sql.gz'; + $fileName = Carbon::now()->format('Y-m-d_H-i-s') . '.sql.gz'; - $this->disk->assertExists($fileName); + $this->disk->assertExists($fileName); - $this->assertNotEmpty(gzdecode($this->disk->get($fileName))); - } + expect( + gzdecode($this->disk->get($fileName)) + )->not->toBeEmpty(); +}); - /** @test */ - public function it_can_create_a_compressed_snapshot_from_config() - { - $this->app['config']->set('db-snapshots.compress', true); +it('can create a compressed snapshot from config', function () { + $this->app['config']->set('db-snapshots.compress', true); - Artisan::call('snapshot:create'); + Artisan::call('snapshot:create'); - $fileName = Carbon::now()->format('Y-m-d_H-i-s') . '.sql.gz'; + $fileName = Carbon::now()->format('Y-m-d_H-i-s') . '.sql.gz'; - $this->disk->assertExists($fileName); + $this->disk->assertExists($fileName); - $this->assertNotEmpty(gzdecode($this->disk->get($fileName))); - } + expect(gzdecode($this->disk->get($fileName)))->not->toBeEmpty(); +}); - /** @test */ - public function it_can_create_a_snapshot_with_specific_tables_specified_in_the_command_options() - { - Artisan::call('snapshot:create', ['--table' => ['users', 'posts']]); +it('can create a snapshot with specific tables specified in the command options', function () { + Artisan::call('snapshot:create', ['--table' => ['users', 'posts']]); - $fileName = Carbon::now()->format('Y-m-d_H-i-s') . '.sql'; + $fileName = Carbon::now()->format('Y-m-d_H-i-s') . '.sql'; - $this->assertFileOnDiskPassesRegex($fileName, '/CREATE TABLE(?: IF NOT EXISTS){0,1} "users"/'); - $this->assertFileOnDiskPassesRegex($fileName, '/CREATE TABLE(?: IF NOT EXISTS){0,1} "posts"/'); - $this->assertFileOnDiskFailsRegex($fileName, '/CREATE TABLE(?: IF NOT EXISTS){0,1} "models"/'); - } + expect($fileName) + ->fileOnDiskToPassRegex('/CREATE TABLE(?: IF NOT EXISTS){0,1} "users"/') + ->fileOnDiskToPassRegex('/CREATE TABLE(?: IF NOT EXISTS){0,1} "posts"/') + ->fileOnDiskToFailRegex('/CREATE TABLE(?: IF NOT EXISTS){0,1} "models"/'); +}); - /** @test */ - public function it_can_create_a_snapshot_with_specific_tables_specified_in_the_command_options_as_a_string() - { - Artisan::call('snapshot:create', ['--table' => 'users,posts']); +it('can create a snapshot with specific tables specified in the command options as a string', function () { + Artisan::call('snapshot:create', ['--table' => 'users,posts']); - $fileName = Carbon::now()->format('Y-m-d_H-i-s') . '.sql'; + $fileName = Carbon::now()->format('Y-m-d_H-i-s') . '.sql'; - $this->assertFileOnDiskPassesRegex($fileName, '/CREATE TABLE(?: IF NOT EXISTS){0,1} "users"/'); - $this->assertFileOnDiskPassesRegex($fileName, '/CREATE TABLE(?: IF NOT EXISTS){0,1} "posts"/'); - $this->assertFileOnDiskFailsRegex($fileName, '/CREATE TABLE(?: IF NOT EXISTS){0,1} "models"/'); - } + expect($fileName) + ->fileOnDiskToPassRegex('/CREATE TABLE(?: IF NOT EXISTS){0,1} "users"/') + ->fileOnDiskToPassRegex('/CREATE TABLE(?: IF NOT EXISTS){0,1} "posts"/') + ->fileOnDiskToFailRegex('/CREATE TABLE(?: IF NOT EXISTS){0,1} "models"/'); +}); - /** @test */ - public function it_can_create_a_snapshot_with_specific_tables_specified_in_the_config() - { - $this->app['config']->set('db-snapshots.tables', ['users', 'posts']); +it('can create a snapshot with specific tables specified in the config', function () { + $this->app['config']->set('db-snapshots.tables', ['users', 'posts']); - Artisan::call('snapshot:create'); + Artisan::call('snapshot:create'); - $fileName = Carbon::now()->format('Y-m-d_H-i-s') . '.sql'; + $fileName = Carbon::now()->format('Y-m-d_H-i-s') . '.sql'; - $this->assertFileOnDiskPassesRegex($fileName, '/CREATE TABLE(?: IF NOT EXISTS){0,1} "users"/'); - $this->assertFileOnDiskPassesRegex($fileName, '/CREATE TABLE(?: IF NOT EXISTS){0,1} "posts"/'); - $this->assertFileOnDiskFailsRegex($fileName, '/CREATE TABLE(?: IF NOT EXISTS){0,1} "models"/'); - } + expect($fileName) + ->fileOnDiskToPassRegex('/CREATE TABLE(?: IF NOT EXISTS){0,1} "users"/') + ->fileOnDiskToPassRegex('/CREATE TABLE(?: IF NOT EXISTS){0,1} "posts"/') + ->fileOnDiskToFailRegex('/CREATE TABLE(?: IF NOT EXISTS){0,1} "models"/'); +}); - /** @test */ - public function it_can_create_a_snapshot_without_excluded_tables_specified_in_the_command_options() - { - Artisan::call('snapshot:create', ['--exclude' => ['users', 'posts']]); +it('can create a snapshot without excluded tables specified in the command options', function () { + Artisan::call('snapshot:create', ['--exclude' => ['users', 'posts']]); - $fileName = Carbon::now()->format('Y-m-d_H-i-s') . '.sql'; + $fileName = Carbon::now()->format('Y-m-d_H-i-s') . '.sql'; - $this->assertFileOnDiskFailsRegex($fileName, '/CREATE TABLE(?: IF NOT EXISTS){0,1} "users"/'); - $this->assertFileOnDiskFailsRegex($fileName, '/CREATE TABLE(?: IF NOT EXISTS){0,1} "posts"/'); - $this->assertFileOnDiskPassesRegex($fileName, '/CREATE TABLE(?: IF NOT EXISTS){0,1} "models"/'); - } + expect($fileName) + ->fileOnDiskToFailRegex('/CREATE TABLE(?: IF NOT EXISTS){0,1} "users"/') + ->fileOnDiskToFailRegex('/CREATE TABLE(?: IF NOT EXISTS){0,1} "posts"/') + ->fileOnDiskToPassRegex('/CREATE TABLE(?: IF NOT EXISTS){0,1} "models"/'); +}); - /** @test */ - public function it_can_create_a_snapshot_without_excluded_tables_specified_in_the_command_options_as_a_string() - { - Artisan::call('snapshot:create', ['--exclude' => 'users,posts']); +it('can create a snapshot without excluded tables specified in the command options as a string', function () { + Artisan::call('snapshot:create', ['--exclude' => 'users,posts']); - $fileName = Carbon::now()->format('Y-m-d_H-i-s') . '.sql'; + $fileName = Carbon::now()->format('Y-m-d_H-i-s') . '.sql'; - $this->assertFileOnDiskFailsRegex($fileName, '/CREATE TABLE(?: IF NOT EXISTS){0,1} "users"/'); - $this->assertFileOnDiskFailsRegex($fileName, '/CREATE TABLE(?: IF NOT EXISTS){0,1} "posts"/'); - $this->assertFileOnDiskPassesRegex($fileName, '/CREATE TABLE(?: IF NOT EXISTS){0,1} "models"/'); - } + expect($fileName) + ->fileOnDiskToFailRegex('/CREATE TABLE(?: IF NOT EXISTS){0,1} "users"/') + ->fileOnDiskToFailRegex('/CREATE TABLE(?: IF NOT EXISTS){0,1} "posts"/') + ->fileOnDiskToPassRegex('/CREATE TABLE(?: IF NOT EXISTS){0,1} "models"/'); +}); - /** @test */ - public function it_can_create_a_snapshot_without_excluded_tables_specified_in_the_config() - { - $this->app['config']->set('db-snapshots.exclude', ['users', 'posts']); +it('can create a snapshot without excluded tables specified in the config', function () { + $this->app['config']->set('db-snapshots.exclude', ['users', 'posts']); - Artisan::call('snapshot:create'); + Artisan::call('snapshot:create'); - $fileName = Carbon::now()->format('Y-m-d_H-i-s') . '.sql'; + $fileName = Carbon::now()->format('Y-m-d_H-i-s') . '.sql'; - $this->assertFileOnDiskFailsRegex($fileName, '/CREATE TABLE(?: IF NOT EXISTS){0,1} "users"/'); - $this->assertFileOnDiskFailsRegex($fileName, '/CREATE TABLE(?: IF NOT EXISTS){0,1} "posts"/'); - $this->assertFileOnDiskPassesRegex($fileName, '/CREATE TABLE(?: IF NOT EXISTS){0,1} "models"/'); - } -} + expect($fileName) + ->fileOnDiskToFailRegex('/CREATE TABLE(?: IF NOT EXISTS){0,1} "users"/') + ->fileOnDiskToFailRegex('/CREATE TABLE(?: IF NOT EXISTS){0,1} "posts"/') + ->fileOnDiskToPassRegex('/CREATE TABLE(?: IF NOT EXISTS){0,1} "models"/'); +}); diff --git a/tests/Commands/DeleteTest.php b/tests/Commands/DeleteTest.php index 4c18e6f..915c6b2 100644 --- a/tests/Commands/DeleteTest.php +++ b/tests/Commands/DeleteTest.php @@ -1,49 +1,33 @@ command = m::mock('Spatie\DbSnapshots\Commands\Delete[choice]'); +beforeEach(function () { + $this->command = m::mock('Spatie\DbSnapshots\Commands\Delete[choice]'); - $this->app->bind('command.snapshot:delete', function () { - return $this->command; - }); - } + $this->app->bind('command.snapshot:delete', function () { + return $this->command; + }); +}); - /** @test */ - public function it_can_delete_a_snapshot() - { - $this->disk->assertExists('snapshot2.sql'); +it('can delete a snapshot', function () { + $this->disk->assertExists('snapshot2.sql'); - $this->command - ->shouldReceive('choice') - ->once() - ->andReturn('snapshot2'); + $this->command + ->shouldReceive('choice') + ->once() + ->andReturn('snapshot2'); - Artisan::call('snapshot:delete'); + Artisan::call('snapshot:delete'); - $this->disk->assertMissing('snapshot2.sql'); - } + $this->disk->assertMissing('snapshot2.sql'); +}); - /** @test */ - public function it_can_delete_a_snapshot_with_a_specific_name() - { - $this->disk->assertExists('snapshot2.sql'); +it('can delete a snapshot with a specific name', function () { + $this->disk->assertExists('snapshot2.sql'); - Artisan::call('snapshot:delete', ['name' => 'snapshot2']); + Artisan::call('snapshot:delete', ['name' => 'snapshot2']); - $this->disk->assertMissing('snapshot2.sql'); - } -} + $this->disk->assertMissing('snapshot2.sql'); +}); diff --git a/tests/Commands/ListSnapshotsTest.php b/tests/Commands/ListSnapshotsTest.php index 1528cd5..6b4e58a 100644 --- a/tests/Commands/ListSnapshotsTest.php +++ b/tests/Commands/ListSnapshotsTest.php @@ -1,17 +1,9 @@ seeInConsoleOutput(['snapshot1', 'snapshot2', 'snapshot3']); - } -} + seeInConsoleOutput(['snapshot1', 'snapshot2', 'snapshot3']); +}); diff --git a/tests/Commands/LoadTest.php b/tests/Commands/LoadTest.php index 8939591..eb21cb6 100644 --- a/tests/Commands/LoadTest.php +++ b/tests/Commands/LoadTest.php @@ -1,169 +1,145 @@ command = m::mock('Spatie\DbSnapshots\Commands\Load[choice]'); +function assertSnapshotNotLoaded($snapshotName): void +{ + assertNotEquals( + $snapshotName, + getNameOfLoadedSnapshot(), + "Failed to assert that `{$snapshotName}` was not loaded." + ); +} - $this->app->bind('command.snapshot:load', function () { - return $this->command; - }); - } +function getNameOfLoadedSnapshot(): string +{ + $result = DB::select('select `name` from models;'); + + return count($result) ? $result[0]->name : ''; +} - /** @test */ - public function it_can_load_a_snapshot() - { - $this->assertSnapshotNotLoaded('snapshot2'); +beforeEach(function () { + $this->command = m::mock('Spatie\DbSnapshots\Commands\Load[choice]'); - $this->command - ->shouldReceive('choice') - ->once() - ->andReturn('snapshot2'); + $this->app->bind('command.snapshot:load', function () { + return $this->command; + }); +}); - Artisan::call('snapshot:load'); +it('can load a snapshot', function () { + assertSnapshotNotLoaded('snapshot2'); - $this->assertSnapshotLoaded('snapshot2'); - } + $this->command + ->shouldReceive('choice') + ->once() + ->andReturn('snapshot2'); - /** @test */ - public function it_can_load_a_snapshot_via_streaming() - { - $this->assertSnapshotNotLoaded('snapshot2'); + Artisan::call('snapshot:load'); - $this->command - ->shouldReceive('choice') - ->once() - ->andReturn('snapshot2'); + assertSnapshotLoaded('snapshot2'); +}); - Artisan::call('snapshot:load', [ - '--stream' => true, - ]); +it('can load a snapshot via streaming', function () { + assertSnapshotNotLoaded('snapshot2'); - $this->assertSnapshotLoaded('snapshot2'); - } + $this->command + ->shouldReceive('choice') + ->once() + ->andReturn('snapshot2'); - /** @test */ - public function it_can_load_a_compressed_snapshot_via_streaming() - { - $this->assertSnapshotNotLoaded('snapshot4'); + Artisan::call('snapshot:load', [ + '--stream' => true, + ]); - $this->command - ->shouldReceive('choice') - ->once() - ->andReturn('snapshot4'); + assertSnapshotLoaded('snapshot2'); +}); - Artisan::call('snapshot:load', [ - '--stream' => true, - ]); +it('can load a compressed snapshot via streaming', function () { + assertSnapshotNotLoaded('snapshot4'); - $this->assertSnapshotLoaded('snapshot4'); - } + $this->command + ->shouldReceive('choice') + ->once() + ->andReturn('snapshot4'); - /** @test */ - public function it_drops_tables_when_loading_a_snapshot() - { - DB::insert('insert into `users` (`id`, `name`) values (1, "test")'); + Artisan::call('snapshot:load', [ + '--stream' => true, + ]); - $this->command - ->shouldReceive('choice') - ->once() - ->andReturn('snapshot2'); + assertSnapshotLoaded('snapshot4'); +}); - Artisan::call('snapshot:load'); +it('drops tables when loading a snapshot', function () { + DB::insert('insert into `users` (`id`, `name`) values (1, "test")'); - $this->assertTableNotExists('users'); - } + $this->command + ->shouldReceive('choice') + ->once() + ->andReturn('snapshot2'); - /** @test */ - public function it_can_load_a_snapshot_without_dropping_existing_tables() - { - DB::insert('insert into `users` (`id`, `name`) values (1, "test")'); + Artisan::call('snapshot:load'); - $this->command - ->shouldReceive('choice') - ->once() - ->andReturn('snapshot2'); + assertTableNotExists('users'); +}); - Artisan::call('snapshot:load', ['--drop-tables' => 0]); +it('can load a snapshot without dropping existing tables', function () { + DB::insert('insert into `users` (`id`, `name`) values (1, "test")'); - $this->assertDatabaseCount('users', 1); - } + $this->command + ->shouldReceive('choice') + ->once() + ->andReturn('snapshot2'); - /** @test */ - public function it_can_load_a_snapshot_with_a_given_name() - { - $this->assertSnapshotNotLoaded('snapshot2'); + Artisan::call('snapshot:load', ['--drop-tables' => 0]); - Artisan::call('snapshot:load', ['name' => 'snapshot2']); + assertDatabaseCount('users', 1); +}); - $this->assertSnapshotLoaded('snapshot2'); - } +it('can load a snapshot with a given name', function () { + assertSnapshotNotLoaded('snapshot2'); - /** @test */ - public function it_can_load_the_latest_snapshot() - { - $this->assertSnapshotNotLoaded('snapshot4'); + Artisan::call('snapshot:load', ['name' => 'snapshot2']); - Artisan::call('snapshot:load', ['--latest' => true]); - - $this->assertSnapshotLoaded('snapshot4'); - } + assertSnapshotLoaded('snapshot2'); +}); - /** @test */ - public function it_can_load_a_snapshot_with_connection_option() - { - $this->assertSnapshotNotLoaded('snapshot2'); +it('can load the latest snapshot', function () { + assertSnapshotNotLoaded('snapshot4'); - Artisan::call('snapshot:load', ['name' => 'snapshot2', '--connection' => 'testing']); + Artisan::call('snapshot:load', ['--latest' => true]); - $this->assertSnapshotLoaded('snapshot2'); - } + assertSnapshotLoaded('snapshot4'); +}); - /** @test */ - public function it_can_load_a_compressed_snapshot() - { - $this->assertSnapshotNotLoaded('snapshot4'); +it('can load a snapshot with connection option', function () { + assertSnapshotNotLoaded('snapshot2'); - Artisan::call('snapshot:load', ['name' => 'snapshot4']); - - $this->assertSnapshotLoaded('snapshot4'); - } + Artisan::call('snapshot:load', ['name' => 'snapshot2', '--connection' => 'testing']); - protected function assertSnapshotLoaded($snapshotName) - { - $this->assertEquals( - $snapshotName, - $this->getNameOfLoadedSnapshot(), - "Failed to assert that `{$snapshotName}` is loaded. Current snapshot: `{$this->getNameOfLoadedSnapshot()}`" - ); - } + assertSnapshotLoaded('snapshot2'); +}); - protected function assertSnapshotNotLoaded($snapshotName) - { - $this->assertNotEquals( - $snapshotName, - $this->getNameOfLoadedSnapshot(), - "Failed to assert that `{$snapshotName}` was not loaded." - ); - } +it('can load a compressed snapshot', function () { + assertSnapshotNotLoaded('snapshot4'); - protected function getNameOfLoadedSnapshot(): string - { - $result = DB::select('select `name` from models;'); + Artisan::call('snapshot:load', ['name' => 'snapshot4']); - return count($result) ? $result[0]->name : ''; - } -} + assertSnapshotLoaded('snapshot4'); +}); diff --git a/tests/DbDumperFactoryTest.php b/tests/DbDumperFactoryTest.php index 69b2b83..ec41008 100644 --- a/tests/DbDumperFactoryTest.php +++ b/tests/DbDumperFactoryTest.php @@ -1,154 +1,124 @@ app['config']->set('database.default', 'mysql'); - - $dbConfig = [ - 'driver' => 'mysql', - 'host' => 'localhost', - 'username' => 'root', - 'password' => 'myPassword', - 'database' => 'myDb', - 'dump' => ['add_extra_option' => '--extra-option=value'], - ]; - - $this->app['config']->set('database.connections.mysql', $dbConfig); - } - - /** @test */ - public function it_can_create_instances_of_mysql_and_pgsql() - { - $this->assertInstanceOf(MySql::class, DbDumperFactory::createForConnection('mysql')); - $this->assertInstanceOf(PostgreSql::class, DbDumperFactory::createForConnection('pgsql')); - } - - /** @test */ - public function it_can_create_sqlite_instance() - { - $this->app['config']->set('database.connections.sqlite', [ - 'driver' => 'sqlite', - 'database' => 'database.sqlite', - // host, username and password are not required for the sqlite driver - ]); - - $this->assertInstanceOf(Sqlite::class, DbDumperFactory::createForConnection('sqlite')); - } - - /** @test */ - public function it_will_use_the_read_db_when_one_is_defined() - { - $dbConfig = [ - 'driver' => 'mysql', - 'read' => [ - 'host' => 'localhost-read', - ], - 'write' => [ - 'host' => 'localhost-write', - ], - 'username' => 'root', - 'password' => 'myPassword', - 'database' => 'myDb', - 'dump' => ['add_extra_option' => '--extra-option=value'], - ]; - - $this->app['config']->set('database.connections.mysql', $dbConfig); - - $dumper = DbDumperFactory::createForConnection('mysql'); - - $this->assertEquals('localhost-read', $dumper->getHost()); - } - - /** @test */ - public function it_will_use_connect_via_database_when_one_is_defined() - { - $dbConfig = [ - 'driver' => 'pgsql', - 'connect_via_database' => 'connection_pool', - 'username' => 'root', - 'password' => 'myPassword', - 'database' => 'myDb', - 'dump' => ['add_extra_option' => '--extra-option=value'], - ]; - - $this->app['config']->set('database.connections.pgsql', $dbConfig); - - $dumper = DbDumperFactory::createForConnection('pgsql'); - - $this->assertEquals('connection_pool', $dumper->getDbName()); - } - - /** @test */ - public function it_will_throw_an_exception_when_creating_an_unknown_type_of_dumper() - { - $this->expectException(CannotCreateDbDumper::class); - - DbDumperFactory::createForConnection('unknown type'); - } - - /** @test */ - public function it_will_throw_an_exception_when_no_disks_are_set_up() - { - config()->set('filesystem.disks', null); - - $this->expectException(CannotCreateDbDumper::class); - - DbDumperFactory::createForConnection('unknown type'); - } - - /** @test */ - public function it_can_add_named_options_to_the_dump_command() - { - $dumpConfig = ['use_single_transaction']; - - $this->app['config']->set('database.connections.mysql.dump', $dumpConfig); - - $this->assertStringContainsString('--single-transaction', $this->getDumpCommand('mysql')); - } - - /** @test */ - public function it_can_add_named_options_with_an_array_value_to_the_dump_command() - { - $dumpConfig = ['include_tables' => ['table1', 'table2']]; - - $this->app['config']->set('database.connections.mysql.dump', $dumpConfig); - - $this->assertStringContainsString(implode(' ', $dumpConfig['include_tables']), $this->getDumpCommand('mysql')); - } - - /** @test */ - public function it_can_add_arbritrary_options_to_the_dump_command() - { - $dumpConfig = ['add_extra_option' => '--extra-option=value']; - - $this->app['config']->set('database.connections.mysql.dump', $dumpConfig); - - $this->assertStringContainsString($dumpConfig['add_extra_option'], $this->getDumpCommand('mysql')); - } - - /** @test */ - public function it_adds_the_inserts_option_to_the_pgsql_dump_command() - { - $this->assertStringContainsString('--inserts', $this->getDumpCommand('pgsql')); - } - - protected function getDumpCommand(string $connectionName): string - { - $dumpFile = ''; - $credentialsFile = ''; - - return DbDumperFactory::createForConnection($connectionName)->getDumpCommand($dumpFile, $credentialsFile); - } + $dumpFile = ''; + $credentialsFile = ''; + + return DbDumperFactory::createForConnection($connectionName)->getDumpCommand($dumpFile, $credentialsFile); } + +beforeEach(function () { + $this->app['config']->set('database.default', 'mysql'); + + $dbConfig = [ + 'driver' => 'mysql', + 'host' => 'localhost', + 'username' => 'root', + 'password' => 'myPassword', + 'database' => 'myDb', + 'dump' => ['add_extra_option' => '--extra-option=value'], + ]; + + $this->app['config']->set('database.connections.mysql', $dbConfig); +}); + +it('can create instances of MySQL and pgSQL') + ->expect(fn () => DbDumperFactory::createForConnection('mysql')) + ->toBeInstanceOf(MySql::class) + ->and(fn () => DbDumperFactory::createForConnection('pgsql')) + ->toBeInstanceOf(PostgreSql::class); + +it('can create sqlite instance', function () { + $this->app['config']->set('database.connections.sqlite', [ + 'driver' => 'sqlite', + 'database' => 'database.sqlite', + // host, username and password are not required for the sqlite driver + ]); + + expect(DbDumperFactory::createForConnection('sqlite')) + ->toBeInstanceOf(Sqlite::class); +}); + +it('will use the read db when one is defined', function () { + $dbConfig = [ + 'driver' => 'mysql', + 'read' => [ + 'host' => 'localhost-read', + ], + 'write' => [ + 'host' => 'localhost-write', + ], + 'username' => 'root', + 'password' => 'myPassword', + 'database' => 'myDb', + 'dump' => ['add_extra_option' => '--extra-option=value'], + ]; + + $this->app['config']->set('database.connections.mysql', $dbConfig); + + $dumper = DbDumperFactory::createForConnection('mysql'); + + expect($dumper->getHost())->toEqual('localhost-read'); +}); + +it('will use connect via database when one is defined', function () { + $dbConfig = [ + 'driver' => 'pgsql', + 'connect_via_database' => 'connection_pool', + 'username' => 'root', + 'password' => 'myPassword', + 'database' => 'myDb', + 'dump' => ['add_extra_option' => '--extra-option=value'], + ]; + + $this->app['config']->set('database.connections.pgsql', $dbConfig); + + $dumper = DbDumperFactory::createForConnection('pgsql'); + + expect($dumper->getDbName())->toEqual('connection_pool'); +}); + +it('will throw an exception when creating an unknown type of dumper', function () { + DbDumperFactory::createForConnection('unknown type'); +})->throws(CannotCreateDbDumper::class); + +it('will throw an exception when no disks are set up', function () { + config()->set('filesystem.disks', null); + + DbDumperFactory::createForConnection('unknown type'); +})->throws(CannotCreateDbDumper::class); + +it('can add named options to the dump command', function () { + $dumpConfig = ['use_single_transaction']; + + $this->app['config']->set('database.connections.mysql.dump', $dumpConfig); + + expect(getDumpCommand('mysql'))->toContain('--single-transaction'); +}); + +it('can add named options with an array value to the dump command', function () { + $dumpConfig = ['include_tables' => ['table1', 'table2']]; + + $this->app['config']->set('database.connections.mysql.dump', $dumpConfig); + + expect(getDumpCommand('mysql'))->toContain(implode(' ', $dumpConfig['include_tables'])); +}); + +it('can add arbitrary options to the dump command', function () { + $dumpConfig = ['add_extra_option' => '--extra-option=value']; + + $this->app['config']->set('database.connections.mysql.dump', $dumpConfig); + + expect(getDumpCommand('mysql'))->toContain($dumpConfig['add_extra_option']); +}); + +it('adds the inserts option to the pgSQL dump command') + ->expect(fn () => getDumpCommand('pgsql')) + ->toContain('--inserts'); diff --git a/tests/Events/CreatedSnapshotTest.php b/tests/Events/CreatedSnapshotTest.php index 1b288ac..81c94e2 100644 --- a/tests/Events/CreatedSnapshotTest.php +++ b/tests/Events/CreatedSnapshotTest.php @@ -1,23 +1,15 @@ 'my-snapshot']); + Artisan::call('snapshot:create', ['name' => 'my-snapshot']); - Event::assertDispatched(CreatedSnapshot::class, function (CreatedSnapshot $event) { - return $event->snapshot->fileName === 'my-snapshot.sql'; - }); - } -} + Event::assertDispatched(CreatedSnapshot::class, function (CreatedSnapshot $event) { + return $event->snapshot->fileName === 'my-snapshot.sql'; + }); +}); diff --git a/tests/Events/CreatingSnapshotTest.php b/tests/Events/CreatingSnapshotTest.php index a5daa81..96cc226 100644 --- a/tests/Events/CreatingSnapshotTest.php +++ b/tests/Events/CreatingSnapshotTest.php @@ -1,35 +1,25 @@ 'my-snapshot']); + Artisan::call('snapshot:create', ['name' => 'my-snapshot']); - Event::assertDispatched(CreatingSnapshot::class, function (CreatingSnapshot $event) { - return $event->fileName === 'my-snapshot.sql'; - }); - } + Event::assertDispatched(CreatingSnapshot::class, function (CreatingSnapshot $event) { + return $event->fileName === 'my-snapshot.sql'; + }); +}); - /** @test */ - public function creating_a_snapshot_with_exclude_will_pass_excluded_tables() - { - Event::fake(); +test('creating a snapshot with exclude will pass excluded tables', function () { + Event::fake(); - Artisan::call('snapshot:create', ['name' => 'my-snapshot', '--exclude' => ['tb1', 'tb2']]); + Artisan::call('snapshot:create', ['name' => 'my-snapshot', '--exclude' => ['tb1', 'tb2']]); - Event::assertDispatched(CreatingSnapshot::class, function (CreatingSnapshot $event) { - return ($event->fileName === 'my-snapshot.sql') && $event->exclude === ['tb1', 'tb2']; - }); - } -} + Event::assertDispatched(CreatingSnapshot::class, function (CreatingSnapshot $event) { + return ($event->fileName === 'my-snapshot.sql') && $event->exclude === ['tb1', 'tb2']; + }); +}); diff --git a/tests/Events/DeletedSnapshotTest.php b/tests/Events/DeletedSnapshotTest.php index 95dde26..3d9a9d6 100644 --- a/tests/Events/DeletedSnapshotTest.php +++ b/tests/Events/DeletedSnapshotTest.php @@ -1,23 +1,15 @@ 'snapshot2']); + Artisan::call('snapshot:delete', ['name' => 'snapshot2']); - Event::assertDispatched(DeletedSnapshot::class, function (DeletedSnapshot $event) { - return $event->fileName === 'snapshot2.sql'; - }); - } -} + Event::assertDispatched(DeletedSnapshot::class, function (DeletedSnapshot $event) { + return $event->fileName === 'snapshot2.sql'; + }); +}); diff --git a/tests/Events/DeletingSnapshotTest.php b/tests/Events/DeletingSnapshotTest.php index 98b91d0..23a6f3e 100644 --- a/tests/Events/DeletingSnapshotTest.php +++ b/tests/Events/DeletingSnapshotTest.php @@ -1,23 +1,15 @@ 'snapshot2']); + Artisan::call('snapshot:delete', ['name' => 'snapshot2']); - Event::assertDispatched(DeletingSnapshot::class, function (DeletingSnapshot $event) { - return $event->snapshot->fileName === 'snapshot2.sql'; - }); - } -} + Event::assertDispatched(DeletingSnapshot::class, function (DeletingSnapshot $event) { + return $event->snapshot->fileName === 'snapshot2.sql'; + }); +}); diff --git a/tests/Events/LoadedSnapshotTest.php b/tests/Events/LoadedSnapshotTest.php index 9300bd2..fe613fc 100644 --- a/tests/Events/LoadedSnapshotTest.php +++ b/tests/Events/LoadedSnapshotTest.php @@ -1,23 +1,15 @@ 'snapshot2']); + Artisan::call('snapshot:load', ['name' => 'snapshot2']); - Event::assertDispatched(LoadedSnapshot::class, function (LoadedSnapshot $event) { - return $event->snapshot->fileName === 'snapshot2.sql'; - }); - } -} + Event::assertDispatched(LoadedSnapshot::class, function (LoadedSnapshot $event) { + return $event->snapshot->fileName === 'snapshot2.sql'; + }); +}); diff --git a/tests/Events/LoadingSnapshotTest.php b/tests/Events/LoadingSnapshotTest.php index c818d56..8222514 100644 --- a/tests/Events/LoadingSnapshotTest.php +++ b/tests/Events/LoadingSnapshotTest.php @@ -1,23 +1,15 @@ 'snapshot2']); + Artisan::call('snapshot:load', ['name' => 'snapshot2']); - Event::assertDispatched(LoadingSnapshot::class, function (LoadingSnapshot $event) { - return $event->snapshot->fileName === 'snapshot2.sql'; - }); - } -} + Event::assertDispatched(LoadingSnapshot::class, function (LoadingSnapshot $event) { + return $event->snapshot->fileName === 'snapshot2.sql'; + }); +}); diff --git a/tests/Helpers/FormatTest.php b/tests/Helpers/FormatTest.php index 01f5ea7..8820736 100644 --- a/tests/Helpers/FormatTest.php +++ b/tests/Helpers/FormatTest.php @@ -1,21 +1,12 @@ assertEquals('10 B', Format::humanReadableSize(10)); - $this->assertEquals('100 B', Format::humanReadableSize(100)); - $this->assertEquals('1000 B', Format::humanReadableSize(1000)); - $this->assertEquals('9.77 KB', Format::humanReadableSize(10000)); - $this->assertEquals('976.56 KB', Format::humanReadableSize(1000000)); - $this->assertEquals('9.54 MB', Format::humanReadableSize(10000000)); - $this->assertEquals('9.31 GB', Format::humanReadableSize(10000000000)); - } -} +it('can determine a human readable file size') + ->expect(fn () => Format::humanReadableSize(10))->toEqual('10 B') + ->and(fn () => Format::humanReadableSize(100))->toEqual('100 B') + ->and(fn () => Format::humanReadableSize(1000))->toEqual('1000 B') + ->and(fn () => Format::humanReadableSize(10000))->toEqual('9.77 KB') + ->and(fn () => Format::humanReadableSize(1000000))->toEqual('976.56 KB') + ->and(fn () => Format::humanReadableSize(10000000))->toEqual('9.54 MB') + ->and(fn () => Format::humanReadableSize(10000000000))->toEqual('9.31 GB'); diff --git a/tests/Pest.php b/tests/Pest.php new file mode 100644 index 0000000..8503696 --- /dev/null +++ b/tests/Pest.php @@ -0,0 +1,76 @@ +in('.'); + +/* +|-------------------------------------------------------------------------- +| Expectations +|-------------------------------------------------------------------------- +*/ + +expect()->extend('fileOnDiskToPassRegex', function (string $needle) { + /** @var string */ + $fileName = $this->value; + + test()->disk->assertExists($fileName); + + $contents = test()->disk->get($fileName); + + assertMatchesRegularExpression($needle, $contents); + + return $this; +}); + +expect()->extend('fileOnDiskToFailRegex', function (string $needle) { + /** @var string */ + $fileName = $this->value; + + test()->disk->assertExists($fileName); + + $contents = test()->disk->get($fileName); + + assertDoesNotMatchRegularExpression($needle, $contents); + + return $this; +}); + +// Functions + +function clearDisk(): void +{ + test()->disk->delete(test()->disk->allFiles()); +} + +function seeInConsoleOutput(string|array $searchStrings): void +{ + if (! is_array($searchStrings)) { + $searchStrings = [$searchStrings]; + } + + $output = Artisan::output(); + + foreach ($searchStrings as $searchString) { + expect($output)->toContain((string) $searchString); + } +} + +function assertTableNotExists(string $table): void +{ + assertFalse( + Schema::hasTable($table), + "Table {$table} should not exist" + ); +} diff --git a/tests/SnapshotRepositoryTest.php b/tests/SnapshotRepositoryTest.php index b14a27d..f18a889 100644 --- a/tests/SnapshotRepositoryTest.php +++ b/tests/SnapshotRepositoryTest.php @@ -1,48 +1,29 @@ repository = app(SnapshotRepository::class); - } - - /** @test */ - public function it_can_load_snapshots_from_a_disk() - { - $snapshots = $this->repository->getAll(); - - $this->assertCount(4, $snapshots); - - $this->assertInstanceOf(Snapshot::class, $snapshots->first()); - } - - /** @test */ - public function it_can_get_a_snapshot_by_name() - { - $this->assertInstanceOf(Snapshot::class, $this->repository->findByName('snapshot2')); +beforeEach(function () { + $this->repository = app(SnapshotRepository::class); +}); - $this->assertNull($this->repository->findByName('snapshot5')); - } +it('can load snapshots from a disk', function () { + $snapshots = $this->repository->getAll(); - /** @test */ - public function it_can_find_gz_compressed_snapshots() - { - $snapshot = $this->repository->findByName('snapshot4'); + expect($snapshots)->toHaveCount(4) + ->and($snapshots->first())->toBeInstanceOf(Snapshot::class); +}); - $this->assertInstanceOf(Snapshot::class, $snapshot); +it('can get a snapshot by name') + ->expect(fn () => $this->repository->findByName('snapshot2')) + ->toBeInstanceOf(Snapshot::class) + ->and(fn () => $this->repository->findByName('snapshot5')) + ->toBeNull(); - $this->assertEquals('gz', $snapshot->compressionExtension); +it('can find gz compressed snapshots', function () { + $snapshot = $this->repository->findByName('snapshot4'); - $this->assertNull($this->repository->findByName('snapshot5')); - } -} + expect($snapshot)->toBeInstanceOf(Snapshot::class) + ->and($snapshot->compressionExtension)->toEqual('gz') + ->and($this->repository->findByName('snapshot5'))->toBeNull(); +}); diff --git a/tests/TestCase.php b/tests/TestCase.php index 7fbfe78..823de94 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -6,16 +6,14 @@ use Illuminate\Contracts\Filesystem\Factory; use Illuminate\Database\Schema\Blueprint; use Illuminate\Filesystem\FilesystemAdapter; -use Illuminate\Support\Facades\Artisan; -use Illuminate\Support\Facades\Schema; use Orchestra\Testbench\TestCase as Orchestra; use Spatie\DbSnapshots\DbSnapshotsServiceProvider; abstract class TestCase extends Orchestra { - protected FilesystemAdapter $disk; + public FilesystemAdapter $disk; - public function setUp(): void + protected function setUp(): void { parent::setUp(); @@ -46,37 +44,19 @@ protected function getEnvironmentSetUp($app) $app['config']->set('database.default', 'testing'); $app['config']->set('database.connections.testing', [ 'driver' => 'sqlite', - 'database' => __DIR__.'/temp/database.sqlite', + 'database' => __DIR__ . '/temp/database.sqlite', 'prefix' => '', ]); $app['config']->set('filesystems.disks.snapshots', [ 'driver' => 'local', - 'root' => __DIR__.'/temp/snapshotsDisk', + 'root' => __DIR__ . '/temp/snapshotsDisk', ]); } - protected function assertFileOnDiskPassesRegex($fileName, $needle) - { - $this->disk->assertExists($fileName); - - $contents = $this->disk->get($fileName); - - $this->assertMatchesRegularExpression($needle, $contents); - } - - protected function assertFileOnDiskFailsRegex($fileName, $needle) - { - $this->disk->assertExists($fileName); - - $contents = $this->disk->get($fileName); - - $this->assertDoesNotMatchRegularExpression($needle, $contents); - } - protected function setupDatabase() { - $databasePath = __DIR__.'/temp/database.sqlite'; + $databasePath = __DIR__ . '/temp/database.sqlite'; if (file_exists($databasePath)) { unlink($databasePath); @@ -106,15 +86,10 @@ protected function setUpDisk() { $this->disk = app(Factory::class)->disk('snapshots'); - $this->clearDisk(); + clearDisk(); $this->createDummySnapshots(); } - protected function clearDisk() - { - $this->disk->delete($this->disk->allFiles()); - } - protected function createDummySnapshots() { foreach (range(1, 3) as $i) { @@ -131,32 +106,8 @@ protected function createDummySnapshots() protected function getSnapshotContent($modelName): string { - $snapshotContent = file_get_contents(__DIR__.'/fixtures/snapshotContent.sql'); + $snapshotContent = file_get_contents(__DIR__ . '/fixtures/snapshotContent.sql'); return str_replace('%%modelName%%', $modelName, $snapshotContent); } - - /** - * @param string|array $searchStrings - */ - protected function seeInConsoleOutput($searchStrings) - { - if (! is_array($searchStrings)) { - $searchStrings = [$searchStrings]; - } - - $output = Artisan::output(); - - foreach ($searchStrings as $searchString) { - $this->assertStringContainsString((string) $searchString, $output); - } - } - - protected function assertTableNotExists(string $table) - { - $this->assertFalse( - Schema::hasTable($table), - "Table {$table} should not exist" - ); - } }