Initial commit
This commit is contained in:
160
tests/Unit/OperatingWindowServiceTest.php
Normal file
160
tests/Unit/OperatingWindowServiceTest.php
Normal file
@@ -0,0 +1,160 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit;
|
||||
|
||||
use App\Models\EvaluationRuleSet;
|
||||
use App\Models\WorkingQso;
|
||||
use App\Services\Evaluation\OperatingWindowService;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Tests\TestCase;
|
||||
|
||||
class OperatingWindowServiceTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
private function createQso(int $runId, int $logId, int $bandId, Carbon $ts, int $points, bool $valid = true): int
|
||||
{
|
||||
$logQso = $this->createLogQso(['log_id' => $logId]);
|
||||
|
||||
$this->createQsoResult([
|
||||
'evaluation_run_id' => $runId,
|
||||
'log_qso_id' => $logQso->id,
|
||||
'is_valid' => $valid,
|
||||
'points' => $points,
|
||||
]);
|
||||
|
||||
WorkingQso::create([
|
||||
'evaluation_run_id' => $runId,
|
||||
'log_qso_id' => $logQso->id,
|
||||
'log_id' => $logId,
|
||||
'ts_utc' => $ts,
|
||||
'band_id' => $bandId,
|
||||
'call_norm' => 'OK1AAA',
|
||||
'rcall_norm' => 'OK1BBB',
|
||||
'loc_norm' => 'JN00AA',
|
||||
'rloc_norm' => 'JN00AA',
|
||||
]);
|
||||
|
||||
return $logQso->id;
|
||||
}
|
||||
|
||||
public function test_pick_best_window_prefers_higher_score(): void
|
||||
{
|
||||
$ruleSet = $this->createRuleSet([
|
||||
'use_multipliers' => false,
|
||||
'multiplier_type' => 'NONE',
|
||||
'multiplier_scope' => 'OVERALL',
|
||||
'multiplier_source' => 'VALID_ONLY',
|
||||
]);
|
||||
$round = $this->createRound();
|
||||
$log = $this->createLog(['round_id' => $round->id]);
|
||||
$run = $this->createEvaluationRun(['rule_set_id' => $ruleSet->id, 'round_id' => $round->id]);
|
||||
$band = $this->createBand();
|
||||
|
||||
$t0 = Carbon::create(2025, 1, 1, 0, 0, 0, 'UTC');
|
||||
$t1 = Carbon::create(2025, 1, 1, 1, 0, 0, 'UTC');
|
||||
$t2 = Carbon::create(2025, 1, 1, 7, 0, 0, 'UTC');
|
||||
$t3 = Carbon::create(2025, 1, 1, 8, 0, 0, 'UTC');
|
||||
|
||||
$firstA = $this->createQso($run->id, $log->id, $band->id, $t0, 10);
|
||||
$firstB = $this->createQso($run->id, $log->id, $band->id, $t1, 10);
|
||||
$bestA = $this->createQso($run->id, $log->id, $band->id, $t2, 25);
|
||||
$bestB = $this->createQso($run->id, $log->id, $band->id, $t3, 25);
|
||||
|
||||
$service = new OperatingWindowService();
|
||||
$result = $service->pickBestOperatingWindow($run->id, $log->id, 6, $ruleSet);
|
||||
|
||||
$this->assertNotNull($result);
|
||||
$this->assertSame($t0->toDateTimeString(), $result['startUtc']->toDateTimeString());
|
||||
$this->assertSame($t1->toDateTimeString(), $result['endUtc']->toDateTimeString());
|
||||
$this->assertSame($t2->toDateTimeString(), $result['secondStartUtc']?->toDateTimeString());
|
||||
$this->assertSame($t3->toDateTimeString(), $result['secondEndUtc']?->toDateTimeString());
|
||||
$this->assertSame([$firstA, $firstB, $bestA, $bestB], $result['includedLogQsoIds']);
|
||||
$this->assertSame(4, $result['qsoCount']);
|
||||
}
|
||||
|
||||
public function test_tie_break_prefers_earlier_start(): void
|
||||
{
|
||||
$ruleSet = $this->createRuleSet([
|
||||
'use_multipliers' => false,
|
||||
'multiplier_type' => 'NONE',
|
||||
'multiplier_scope' => 'OVERALL',
|
||||
'multiplier_source' => 'VALID_ONLY',
|
||||
]);
|
||||
$round = $this->createRound();
|
||||
$log = $this->createLog(['round_id' => $round->id]);
|
||||
$run = $this->createEvaluationRun(['rule_set_id' => $ruleSet->id, 'round_id' => $round->id]);
|
||||
$band = $this->createBand();
|
||||
|
||||
$t0 = Carbon::create(2025, 1, 1, 0, 0, 0, 'UTC');
|
||||
$t1 = Carbon::create(2025, 1, 1, 1, 0, 0, 'UTC');
|
||||
$t2 = Carbon::create(2025, 1, 1, 15, 0, 0, 'UTC');
|
||||
$t3 = Carbon::create(2025, 1, 1, 21, 0, 0, 'UTC');
|
||||
|
||||
$firstA = $this->createQso($run->id, $log->id, $band->id, $t0, 10);
|
||||
$firstB = $this->createQso($run->id, $log->id, $band->id, $t1, 10);
|
||||
$this->createQso($run->id, $log->id, $band->id, $t2, 10);
|
||||
$this->createQso($run->id, $log->id, $band->id, $t3, 10);
|
||||
|
||||
$service = new OperatingWindowService();
|
||||
$result = $service->pickBestOperatingWindow($run->id, $log->id, 6, $ruleSet);
|
||||
|
||||
$this->assertNotNull($result);
|
||||
$this->assertSame($t0->toDateTimeString(), $result['startUtc']->toDateTimeString());
|
||||
$this->assertSame($t1->toDateTimeString(), $result['endUtc']->toDateTimeString());
|
||||
$this->assertNull($result['secondStartUtc']);
|
||||
$this->assertNull($result['secondEndUtc']);
|
||||
$this->assertSame([$firstA, $firstB], $result['includedLogQsoIds']);
|
||||
}
|
||||
|
||||
public function test_window_includes_boundary_at_six_hours(): void
|
||||
{
|
||||
$ruleSet = $this->createRuleSet([
|
||||
'use_multipliers' => false,
|
||||
'multiplier_type' => 'NONE',
|
||||
'multiplier_scope' => 'OVERALL',
|
||||
'multiplier_source' => 'VALID_ONLY',
|
||||
]);
|
||||
$round = $this->createRound();
|
||||
$log = $this->createLog(['round_id' => $round->id]);
|
||||
$run = $this->createEvaluationRun(['rule_set_id' => $ruleSet->id, 'round_id' => $round->id]);
|
||||
$band = $this->createBand();
|
||||
|
||||
$t0 = Carbon::create(2025, 1, 1, 0, 0, 0, 'UTC');
|
||||
$t1 = Carbon::create(2025, 1, 1, 6, 0, 0, 'UTC');
|
||||
|
||||
$this->createQso($run->id, $log->id, $band->id, $t0, 10);
|
||||
$this->createQso($run->id, $log->id, $band->id, $t1, 10);
|
||||
|
||||
$service = new OperatingWindowService();
|
||||
$result = $service->pickBestOperatingWindow($run->id, $log->id, 6, $ruleSet);
|
||||
|
||||
$this->assertNotNull($result);
|
||||
$this->assertSame($t0->toDateTimeString(), $result['startUtc']->toDateTimeString());
|
||||
$this->assertSame($t1->toDateTimeString(), $result['endUtc']->toDateTimeString());
|
||||
$this->assertSame(2, $result['qsoCount']);
|
||||
}
|
||||
|
||||
public function test_returns_null_when_no_valid_qso(): void
|
||||
{
|
||||
$ruleSet = $this->createRuleSet([
|
||||
'use_multipliers' => false,
|
||||
'multiplier_type' => 'NONE',
|
||||
'multiplier_scope' => 'OVERALL',
|
||||
'multiplier_source' => 'VALID_ONLY',
|
||||
]);
|
||||
$round = $this->createRound();
|
||||
$log = $this->createLog(['round_id' => $round->id]);
|
||||
$run = $this->createEvaluationRun(['rule_set_id' => $ruleSet->id, 'round_id' => $round->id]);
|
||||
$band = $this->createBand();
|
||||
|
||||
$t0 = Carbon::create(2025, 1, 1, 0, 0, 0, 'UTC');
|
||||
$this->createQso($run->id, $log->id, $band->id, $t0, 10, false);
|
||||
|
||||
$service = new OperatingWindowService();
|
||||
$result = $service->pickBestOperatingWindow($run->id, $log->id, 6, $ruleSet);
|
||||
|
||||
$this->assertNull($result);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user