Skip to content

Commit

Permalink
Merge pull request #86 from tarfin-labs/WB-623-event-machine-reset-al…
Browse files Browse the repository at this point in the history
…l-fakes

Able to Reset All Fakes
  • Loading branch information
tkaratug authored Nov 7, 2024
2 parents 2a4d4d7 + 6965248 commit 2d4f0f1
Show file tree
Hide file tree
Showing 6 changed files with 186 additions and 25 deletions.
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@
"Tarfinlabs\\EventMachine\\MachineServiceProvider"
],
"aliases": {
"MachineFacade": "Tarfinlabs\\EventMachine\\Facades\\MachineFacade"
"EventMachine": "Tarfinlabs\\EventMachine\\Facades\\EventMachine"
}
}
},
Expand Down
18 changes: 18 additions & 0 deletions src/EventMachine.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php

declare(strict_types=1);

namespace Tarfinlabs\EventMachine;

use Tarfinlabs\EventMachine\Behavior\InvokableBehavior;

class EventMachine
{
/**
* Resets all fake invocations to their default state.
*/
public function resetAllFakes(): void
{
InvokableBehavior::resetAllFakes();
}
}
25 changes: 25 additions & 0 deletions src/Facades/EventMachine.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

declare(strict_types=1);

namespace Tarfinlabs\EventMachine\Facades;

use Illuminate\Support\Facades\Facade;

/**
* The EventMachine class represents a facade for accessing the Event Machine service container.
*
* @method static void resetAllFakes() Resets all fake invocations to their default state.
*
* @see \Tarfinlabs\EventMachine\EventMachine
*/
class EventMachine extends Facade
{
/**
* Get the service container key for the facade.
*/
protected static function getFacadeAccessor(): string
{
return \Tarfinlabs\EventMachine\EventMachine::class;
}
}
21 changes: 0 additions & 21 deletions src/Facades/MachineFacade.php

This file was deleted.

59 changes: 56 additions & 3 deletions src/Traits/Fakeable.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,15 +44,68 @@ public static function getFake(): ?MockInterface
return static::$fakes[static::class] ?? null;
}

/**
* Remove the fake instance from Laravel's container.
*
* This method handles the cleanup of fake instances from Laravel's service container
* to prevent memory leaks and ensure proper state reset between tests.
*/
protected static function cleanupLaravelContainer(string $class): void
{
if (App::has($class)) {
App::forgetInstance($class);
App::offsetUnset($class);
}
}

/**
* Clean up Mockery expectations for a given mock instance.
*
* This method resets all expectations on a mock object by:
* 1. Getting all methods that have expectations
* 2. Creating new empty expectation directors for each method
* 3. Performing mockery teardown
*
* @param MockInterface $mock The mock instance to clean up
*/
protected static function cleanupMockeryExpectations(MockInterface $mock): void
{
foreach (array_keys($mock->mockery_getExpectations()) as $method) {
$mock->mockery_setExpectationsFor(
$method,
new Mockery\ExpectationDirector($method, $mock),
);
}

$mock->mockery_teardown();
}

/**
* Reset all fakes.
*/
public static function resetFakes(): void
{
static::$fakes = [];
if (App::has(id: static::class)) {
App::forgetInstance(abstract: static::class);
if (isset(static::$fakes[static::class])) {
$mock = static::$fakes[static::class];

self::cleanupLaravelContainer(class: static::class);
self::cleanupMockeryExpectations($mock);

unset(static::$fakes[static::class]);
}
}

/**
* Reset all fakes in application container.
*/
public static function resetAllFakes(): void
{
foreach (static::$fakes as $class => $mock) {
self::cleanupLaravelContainer(class: $class);
self::cleanupMockeryExpectations($mock);
}

static::$fakes = [];
}

/**
Expand Down
86 changes: 86 additions & 0 deletions tests/InvokableBehaviorFakeTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use RuntimeException;
use Mockery\MockInterface;
use Tarfinlabs\EventMachine\ContextManager;
use Tarfinlabs\EventMachine\Facades\EventMachine;
use Tarfinlabs\EventMachine\Behavior\GuardBehavior;
use Tarfinlabs\EventMachine\Behavior\ActionBehavior;

Expand Down Expand Up @@ -273,3 +274,88 @@ public function __invoke(ContextManager $context): bool
});

// endregion

// region Reset All Fakes

it('can reset all fakes at once', function (): void {
// 1. Arrange
TestIncrementAction::shouldRun()->once();
TestCountGuard::shouldRun()->twice();

// 2. Act
EventMachine::resetAllFakes();

// 3. Assert
expect(TestIncrementAction::isFaked())->toBeFalse()
->and(TestCountGuard::isFaked())->toBeFalse()
->and(TestIncrementAction::getFake())->toBeNull()
->and(TestCountGuard::getFake())->toBeNull();
});

it('removes all fake instances from container when resetting', function (): void {
// 1. Arrange
TestIncrementAction::shouldRun()->once();
TestCountGuard::shouldRun()->once();

// 2. Act
EventMachine::resetAllFakes();

// 3. Assert
expect(app()->bound(TestIncrementAction::class))->toBeFalse()
->and(app()->bound(TestCountGuard::class))->toBeFalse();
});

it('cleans mockery container when resetting fakes', function (): void {
// 1. Arrange
TestIncrementAction::shouldRun()->once();
TestCountGuard::shouldRun()->twice();

// 2. Act
EventMachine::resetAllFakes();

// 3. Assert
TestIncrementAction::shouldRun()->never();
TestIncrementAction::assertNotRan();

TestCountGuard::shouldRun()->never();
TestCountGuard::assertNotRan();
});

it('maintains behavior isolation after resetting all fakes', function (): void {
// 1. Arrange
TestIncrementAction::shouldRun()->once();
TestCountGuard::shouldRun()->twice();
EventMachine::resetAllFakes();

// 2. Act
TestIncrementAction::shouldRun()->once();
TestIncrementAction::run(new ContextManager(['count' => 0]));

// 3. Assert
TestIncrementAction::assertRan();
expect(TestCountGuard::isFaked())->toBeFalse();
});

it('can reset fakes with different trait instances consistently', function (): void {
// 1. Arrange
TestIncrementAction::shouldRun()->once();
TestCountGuard::shouldRun()->twice();

// 2. Act
TestIncrementAction::resetAllFakes();

// Try to create new fakes
TestIncrementAction::shouldRun()->once();
TestCountGuard::shouldRun()->once();

// Reset using another instance
TestCountGuard::resetAllFakes();

// 3. Assert
expect(TestIncrementAction::isFaked())->toBeFalse()
->and(TestCountGuard::isFaked())->toBeFalse()
->and(TestIncrementAction::getFake())->toBeNull()
->and(TestCountGuard::getFake())->toBeNull();
});

// endregion

0 comments on commit 2d4f0f1

Please sign in to comment.