codes.txt
This commit is contained in:
73
tests/Unit/CouponCodePoolTest.php
Normal file
73
tests/Unit/CouponCodePoolTest.php
Normal file
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit;
|
||||
|
||||
use App\Models\Coupon;
|
||||
use App\Services\CouponCodePool;
|
||||
use Illuminate\Foundation\Testing\LazilyRefreshDatabase;
|
||||
use Tests\TestCase;
|
||||
|
||||
class CouponCodePoolTest extends TestCase
|
||||
{
|
||||
use LazilyRefreshDatabase;
|
||||
|
||||
private string $codesPath;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->codesPath = tempnam(sys_get_temp_dir(), 'codes_');
|
||||
file_put_contents($this->codesPath, "1_AAAA\n2_BBBB\n3_CCCC\n");
|
||||
}
|
||||
|
||||
protected function tearDown(): void
|
||||
{
|
||||
if (is_file($this->codesPath)) {
|
||||
unlink($this->codesPath);
|
||||
}
|
||||
|
||||
parent::tearDown();
|
||||
}
|
||||
|
||||
public function test_all_codes_loads_from_file(): void
|
||||
{
|
||||
$pool = new CouponCodePool($this->codesPath);
|
||||
|
||||
$this->assertSame(['1_AAAA', '2_BBBB', '3_CCCC'], $pool->allCodes());
|
||||
}
|
||||
|
||||
public function test_available_codes_excludes_used_coupons(): void
|
||||
{
|
||||
Coupon::factory()->create(['code' => '1_AAAA', 'phone' => '61111111']);
|
||||
|
||||
$pool = new CouponCodePool($this->codesPath);
|
||||
|
||||
$this->assertEqualsCanonicalizing(['2_BBBB', '3_CCCC'], $pool->availableCodes());
|
||||
}
|
||||
|
||||
public function test_pick_random_returns_only_unused_code(): void
|
||||
{
|
||||
Coupon::factory()->create(['code' => '2_BBBB', 'phone' => '61111111']);
|
||||
|
||||
$pool = new CouponCodePool($this->codesPath);
|
||||
|
||||
for ($i = 0; $i < 20; $i++) {
|
||||
$picked = $pool->pickRandom();
|
||||
$this->assertContains($picked, ['1_AAAA', '3_CCCC']);
|
||||
}
|
||||
}
|
||||
|
||||
public function test_has_available_is_false_when_all_codes_used(): void
|
||||
{
|
||||
Coupon::factory()->create(['code' => '1_AAAA', 'phone' => '61111111']);
|
||||
Coupon::factory()->create(['code' => '2_BBBB', 'phone' => '62222222']);
|
||||
Coupon::factory()->create(['code' => '3_CCCC', 'phone' => '63333333']);
|
||||
|
||||
$pool = new CouponCodePool($this->codesPath);
|
||||
|
||||
$this->assertFalse($pool->hasAvailable());
|
||||
$this->assertNull($pool->pickRandom());
|
||||
$this->assertSame([], $pool->availableCodes());
|
||||
}
|
||||
}
|
||||
64
tests/Unit/CouponServiceTest.php
Normal file
64
tests/Unit/CouponServiceTest.php
Normal file
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit;
|
||||
|
||||
use App\Exceptions\CouponPoolExhaustedException;
|
||||
use App\Models\Coupon;
|
||||
use App\Services\CouponCodePool;
|
||||
use App\Services\CouponService;
|
||||
use Illuminate\Foundation\Testing\LazilyRefreshDatabase;
|
||||
use Mockery;
|
||||
use Mockery\MockInterface;
|
||||
use Tests\TestCase;
|
||||
|
||||
class CouponServiceTest extends TestCase
|
||||
{
|
||||
use LazilyRefreshDatabase;
|
||||
|
||||
public function test_find_or_create_assigns_code_from_pool(): void
|
||||
{
|
||||
$this->mock(CouponCodePool::class, function (MockInterface $mock): void {
|
||||
$mock->shouldReceive('pickRandom')->once()->andReturn('1_AAAA');
|
||||
});
|
||||
|
||||
$coupon = app(CouponService::class)->findOrCreateForPhone('61929248');
|
||||
|
||||
$this->assertSame('61929248', $coupon->phone);
|
||||
$this->assertSame('1_AAAA', $coupon->code);
|
||||
$this->assertDatabaseHas(Coupon::class, [
|
||||
'phone' => '61929248',
|
||||
'code' => '1_AAAA',
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_find_or_create_returns_existing_coupon_without_picking(): void
|
||||
{
|
||||
$existing = Coupon::factory()->create(['phone' => '61929248', 'code' => '2_BBBB']);
|
||||
|
||||
$this->mock(CouponCodePool::class, function (MockInterface $mock): void {
|
||||
$mock->shouldNotReceive('pickRandom');
|
||||
});
|
||||
|
||||
$coupon = app(CouponService::class)->findOrCreateForPhone('61929248');
|
||||
|
||||
$this->assertTrue($existing->is($coupon));
|
||||
}
|
||||
|
||||
public function test_find_or_create_throws_when_pool_exhausted(): void
|
||||
{
|
||||
$this->mock(CouponCodePool::class, function (MockInterface $mock): void {
|
||||
$mock->shouldReceive('pickRandom')->andReturn(null);
|
||||
});
|
||||
|
||||
$this->expectException(CouponPoolExhaustedException::class);
|
||||
|
||||
app(CouponService::class)->findOrCreateForPhone('61929248');
|
||||
}
|
||||
|
||||
protected function tearDown(): void
|
||||
{
|
||||
Mockery::close();
|
||||
|
||||
parent::tearDown();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user