Skip to content

Commit

Permalink
[8.x] Add assertNotSoftDeleted Method (#38886)
Browse files Browse the repository at this point in the history
* Add assertNotSoftDelete Method

* add test

Co-authored-by: Taylor Otwell <taylorotwell@gmail.com>
  • Loading branch information
xiCO2k and taylorotwell authored Sep 21, 2021
1 parent 195529f commit cb72e7b
Show file tree
Hide file tree
Showing 3 changed files with 206 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use Illuminate\Support\Facades\DB;
use Illuminate\Testing\Constraints\CountInDatabase;
use Illuminate\Testing\Constraints\HasInDatabase;
use Illuminate\Testing\Constraints\NotSoftDeletedInDatabase;
use Illuminate\Testing\Constraints\SoftDeletedInDatabase;
use PHPUnit\Framework\Constraint\LogicalNot as ReverseConstraint;

Expand Down Expand Up @@ -108,6 +109,28 @@ protected function assertSoftDeleted($table, array $data = [], $connection = nul
return $this;
}

/**
* Assert the given record has not been "soft deleted".
*
* @param \Illuminate\Database\Eloquent\Model|string $table
* @param array $data
* @param string|null $connection
* @param string|null $deletedAtColumn
* @return $this
*/
protected function assertNotSoftDeleted($table, array $data = [], $connection = null, $deletedAtColumn = 'deleted_at')
{
if ($this->isSoftDeletableModel($table)) {
return $this->assertNotSoftDeleted($table->getTable(), [$table->getKeyName() => $table->getKey()], $table->getConnectionName(), $table->getDeletedAtColumn());
}

$this->assertThat(
$this->getTable($table), new NotSoftDeletedInDatabase($this->getConnection($connection), $data, $deletedAtColumn)
);

return $this;
}

/**
* Assert the given model exists in the database.
*
Expand Down
115 changes: 115 additions & 0 deletions src/Illuminate/Testing/Constraints/NotSoftDeletedInDatabase.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
<?php

namespace Illuminate\Testing\Constraints;

use Illuminate\Database\Connection;
use PHPUnit\Framework\Constraint\Constraint;

class NotSoftDeletedInDatabase extends Constraint
{
/**
* Number of records that will be shown in the console in case of failure.
*
* @var int
*/
protected $show = 3;

/**
* The database connection.
*
* @var \Illuminate\Database\Connection
*/
protected $database;

/**
* The data that will be used to narrow the search in the database table.
*
* @var array
*/
protected $data;

/**
* The name of the column that indicates soft deletion has occurred.
*
* @var string
*/
protected $deletedAtColumn;

/**
* Create a new constraint instance.
*
* @param \Illuminate\Database\Connection $database
* @param array $data
* @param string $deletedAtColumn
* @return void
*/
public function __construct(Connection $database, array $data, string $deletedAtColumn)
{
$this->database = $database;
$this->data = $data;
$this->deletedAtColumn = $deletedAtColumn;
}

/**
* Check if the data is found in the given table.
*
* @param string $table
* @return bool
*/
public function matches($table): bool
{
return $this->database->table($table)
->where($this->data)
->whereNull($this->deletedAtColumn)
->count() > 0;
}

/**
* Get the description of the failure.
*
* @param string $table
* @return string
*/
public function failureDescription($table): string
{
return sprintf(
"any existing row in the table [%s] matches the attributes %s.\n\n%s",
$table, $this->toString(), $this->getAdditionalInfo($table)
);
}

/**
* Get additional info about the records found in the database table.
*
* @param string $table
* @return string
*/
protected function getAdditionalInfo($table)
{
$query = $this->database->table($table);

$results = $query->limit($this->show)->get();

if ($results->isEmpty()) {
return 'The table is empty';
}

$description = 'Found: '.json_encode($results, JSON_PRETTY_PRINT);

if ($query->count() > $this->show) {
$description .= sprintf(' and %s others', $query->count() - $this->show);
}

return $description;
}

/**
* Get a string representation of the object.
*
* @return string
*/
public function toString(): string
{
return json_encode($this->data);
}
}
68 changes: 68 additions & 0 deletions tests/Foundation/FoundationInteractsWithDatabaseTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,72 @@ public function testAssertSoftDeletedInDatabaseDoesNotFindModelWithCustomColumnR
$this->assertSoftDeleted(new CustomProductStub($this->data));
}

public function testAssertNotSoftDeletedInDatabaseFindsResults()
{
$builder = $this->mockCountBuilder(1);

$this->assertNotSoftDeleted($this->table, $this->data);
}

public function testAssertNotSoftDeletedSupportModelStrings()
{
$this->mockCountBuilder(1);

$this->assertNotSoftDeleted(ProductStub::class, $this->data);
}

public function testAssertNotSoftDeletedOnlyFindsMatchingModels()
{
$this->expectException(ExpectationFailedException::class);
$this->expectExceptionMessage('Failed asserting that any existing row');

$builder = $this->mockCountBuilder(0);

$builder->shouldReceive('get')->andReturn(collect(), collect(1));

$this->assertNotSoftDeleted(ProductStub::class, $this->data);
}

public function testAssertNotSoftDeletedInDatabaseDoesNotFindResults()
{
$this->expectException(ExpectationFailedException::class);
$this->expectExceptionMessage('The table is empty.');

$builder = $this->mockCountBuilder(0);

$builder->shouldReceive('get')->andReturn(collect());

$this->assertNotSoftDeleted($this->table, $this->data);
}

public function testAssertNotSoftDeletedInDatabaseDoesNotFindModelResults()
{
$this->expectException(ExpectationFailedException::class);
$this->expectExceptionMessage('The table is empty.');

$this->data = ['id' => 1];

$builder = $this->mockCountBuilder(0);

$builder->shouldReceive('get')->andReturn(collect());

$this->assertNotSoftDeleted(new ProductStub($this->data));
}

public function testAssertNotSoftDeletedInDatabaseDoesNotFindModelWithCustomColumnResults()
{
$this->expectException(ExpectationFailedException::class);
$this->expectExceptionMessage('The table is empty.');

$this->data = ['id' => 1];

$builder = $this->mockCountBuilder(0, 'trashed_at');

$builder->shouldReceive('get')->andReturn(collect());

$this->assertNotSoftDeleted(new CustomProductStub($this->data));
}

public function testAssertExistsPassesWhenFindsResults()
{
$this->data = ['id' => 1];
Expand Down Expand Up @@ -283,6 +349,8 @@ protected function mockCountBuilder($countResult, $deletedAtColumn = 'deleted_at

$builder->shouldReceive('whereNotNull')->with($deletedAtColumn)->andReturnSelf();

$builder->shouldReceive('whereNull')->with($deletedAtColumn)->andReturnSelf();

$builder->shouldReceive('count')->andReturn($countResult)->byDefault();

$this->connection->shouldReceive('table')
Expand Down

0 comments on commit cb72e7b

Please sign in to comment.