auditionadmin/tests/Feature/app/Actions/Tabulation/RankAuditionEntriesTest.php

361 lines
13 KiB
PHP

<?php
/** @noinspection PhpUnhandledExceptionInspection */
use App\Actions\Tabulation\RankAuditionEntries;
use App\Exceptions\AuditionAdminException;
use App\Models\Audition;
use App\Models\BonusScoreDefinition;
use App\Models\Entry;
use App\Models\EntryTotalScore;
use Illuminate\Foundation\Testing\RefreshDatabase;
uses(RefreshDatabase::class);
beforeEach(function () {
$this->audition = Audition::factory()->create(['minimum_grade' => 1, 'maximum_grade' => 14]);
$this->entries = Entry::factory()->count(10)->create(['audition_id' => $this->audition->id]);
$this->ranker = app(RankAuditionEntries::class);
});
afterEach(function () {
cache()->flush();
});
it('throws an exception if an invalid rank type is specified', function () {
($this->ranker)($this->audition, 'bababoey');
})->throws(AuditionAdminException::class, 'Invalid rank type (must be seating or advancement)');
// Test Rank for Seating
it('ranks entries for seating if there are no ties', function () {
// entry 0 will be second place
$score0 = EntryTotalScore::create([
'entry_id' => $this->entries[0]->id,
'seating_total' => 50,
'advancement_total' => 50,
'seating_subscore_totals' => [5, 5],
'advancement_subscore_totals' => [5, 5],
]);
// entry 1 will be third place
$score1 = EntryTotalScore::create([
'entry_id' => $this->entries[1]->id,
'seating_total' => 25,
'advancement_total' => 75,
'seating_subscore_totals' => [5, 5],
'advancement_subscore_totals' => [5, 5],
]);
// entry 2 will be first place
$score1 = EntryTotalScore::create([
'entry_id' => $this->entries[2]->id,
'seating_total' => 75,
'advancement_total' => 25,
'seating_subscore_totals' => [5, 5],
'advancement_subscore_totals' => [5, 5],
]);
$sortedEntries = ($this->ranker)($this->audition, 'seating');
expect($sortedEntries[0]->id)->toEqual($this->entries[2]->id)
->and($sortedEntries[1]->id)->toEqual($this->entries[0]->id)
->and($sortedEntries[2]->id)->toEqual($this->entries[1]->id);
});
it('makes use of bonus scores when set', function () {
$bonusScoreDefinition = BonusScoreDefinition::create([
'name' => 'bonus',
'max_score' => 100,
'weight' => 1,
'for_seating' => 1,
'for_attendance' => 0,
]);
$bonusScoreDefinition->auditions()->attach($this->audition);
DB::table('bonus_scores')->insert([
'entry_id' => $this->entries[2]->id,
'user_id' => 1,
'originally_scored_entry' => $this->entries[2]->id,
'score' => 100,
'created_at' => now(),
'updated_at' => now(),
]);
// entry 0 will be second place
$score0 = EntryTotalScore::create([
'entry_id' => $this->entries[0]->id,
'seating_total' => 50,
'advancement_total' => 50,
'seating_subscore_totals' => [5, 5],
'advancement_subscore_totals' => [5, 5],
]);
// entry 1 will be third place
$score1 = EntryTotalScore::create([
'entry_id' => $this->entries[1]->id,
'seating_total' => 25,
'advancement_total' => 75,
'seating_subscore_totals' => [5, 5],
'advancement_subscore_totals' => [5, 5],
]);
// entry 2 will be first place
$score2 = EntryTotalScore::create([
'entry_id' => $this->entries[2]->id,
'seating_total' => 2,
'advancement_total' => 25,
'seating_subscore_totals' => [5, 5],
'advancement_subscore_totals' => [5, 5],
'bonus_total' => 100,
]);
$sortedEntries = ($this->ranker)($this->audition, 'seating');
expect($sortedEntries[0]->id)->toEqual($this->entries[2]->id)
->and($sortedEntries[1]->id)->toEqual($this->entries[0]->id)
->and($sortedEntries[2]->id)->toEqual($this->entries[1]->id);
});
it('assigns a seatingRank property to each entry that is scored', function () {
// entry 0 will be second place
$score0 = EntryTotalScore::create([
'entry_id' => $this->entries[0]->id,
'seating_total' => 50,
'advancement_total' => 50,
'seating_subscore_totals' => [5, 5],
'advancement_subscore_totals' => [5, 5],
]);
// entry 1 will be third place
$score1 = EntryTotalScore::create([
'entry_id' => $this->entries[1]->id,
'seating_total' => 25,
'advancement_total' => 75,
'seating_subscore_totals' => [5, 5],
'advancement_subscore_totals' => [5, 5],
]);
// entry 2 will be first place
$score1 = EntryTotalScore::create([
'entry_id' => $this->entries[2]->id,
'seating_total' => 75,
'advancement_total' => 25,
'seating_subscore_totals' => [5, 5],
'advancement_subscore_totals' => [5, 5],
]);
$sortedEntries = ($this->ranker)($this->audition, 'seating');
expect($sortedEntries[0]->seatingRank)->toEqual(1)
->and($sortedEntries[1]->seatingRank)->toEqual(2)
->and($sortedEntries[2]->seatingRank)->toEqual(3)
->and($sortedEntries->count())->toEqual(3);
});
it('skips a declined entry when assigning seatingRank properties', function () {
// entry 0 will be second place
$score0 = EntryTotalScore::create([
'entry_id' => $this->entries[0]->id,
'seating_total' => 50,
'advancement_total' => 50,
'seating_subscore_totals' => [5, 5],
'advancement_subscore_totals' => [5, 5],
]);
// entry 1 will be third place
$score1 = EntryTotalScore::create([
'entry_id' => $this->entries[1]->id,
'seating_total' => 25,
'advancement_total' => 75,
'seating_subscore_totals' => [5, 5],
'advancement_subscore_totals' => [5, 5],
]);
// entry 2 will be first place
$score1 = EntryTotalScore::create([
'entry_id' => $this->entries[2]->id,
'seating_total' => 75,
'advancement_total' => 25,
'seating_subscore_totals' => [5, 5],
'advancement_subscore_totals' => [5, 5],
]);
$this->entries[0]->addFlag('declined');
$sortedEntries = ($this->ranker)($this->audition, 'seating');
expect($sortedEntries[0]->seatingRank)->toEqual(1)
->and($sortedEntries[1]->seatingRank)->toEqual('declined')
->and($sortedEntries[2]->seatingRank)->toEqual(2);
});
it('uses the second subscore as a second tiebreaker for seating', function () {
// entry 0 will be second place
$score0 = EntryTotalScore::create([
'entry_id' => $this->entries[0]->id,
'seating_total' => 50,
'advancement_total' => 50,
'seating_subscore_totals' => [5, 5],
'advancement_subscore_totals' => [5, 5],
]);
// entry 1 will be third place
$score1 = EntryTotalScore::create([
'entry_id' => $this->entries[1]->id,
'seating_total' => 50,
'advancement_total' => 75,
'seating_subscore_totals' => [5, 4],
'advancement_subscore_totals' => [5, 5],
]);
// entry 2 will be first place
$score1 = EntryTotalScore::create([
'entry_id' => $this->entries[2]->id,
'seating_total' => 50,
'advancement_total' => 25,
'seating_subscore_totals' => [5, 6],
'advancement_subscore_totals' => [5, 5],
]);
$sortedEntries = ($this->ranker)($this->audition, 'seating');
expect($sortedEntries[0]->id)->toEqual($this->entries[2]->id)
->and($sortedEntries[1]->id)->toEqual($this->entries[0]->id)
->and($sortedEntries[2]->id)->toEqual($this->entries[1]->id);
});
it('uses the first subscore as a tiebreaker for seating', function () {
// entry 0 will be second place
$score0 = EntryTotalScore::create([
'entry_id' => $this->entries[0]->id,
'seating_total' => 50,
'advancement_total' => 50,
'seating_subscore_totals' => [5, 5],
'advancement_subscore_totals' => [5, 5],
]);
// entry 1 will be third place
$score1 = EntryTotalScore::create([
'entry_id' => $this->entries[1]->id,
'seating_total' => 50,
'advancement_total' => 75,
'seating_subscore_totals' => [4, 5],
'advancement_subscore_totals' => [5, 5],
]);
// entry 2 will be first place
$score1 = EntryTotalScore::create([
'entry_id' => $this->entries[2]->id,
'seating_total' => 50,
'advancement_total' => 25,
'seating_subscore_totals' => [6, 5],
'advancement_subscore_totals' => [5, 5],
]);
$sortedEntries = ($this->ranker)($this->audition, 'seating');
expect($sortedEntries[0]->id)->toEqual($this->entries[2]->id)
->and($sortedEntries[1]->id)->toEqual($this->entries[0]->id)
->and($sortedEntries[2]->id)->toEqual($this->entries[1]->id);
});
// Test Rank for Advancement
it('ranks entries for advancement if there are no ties', function () {
// entry 0 will be second place
$score0 = EntryTotalScore::create([
'entry_id' => $this->entries[0]->id,
'seating_total' => 50,
'advancement_total' => 50,
'seating_subscore_totals' => [5, 5],
'advancement_subscore_totals' => [5, 5],
]);
// entry 1 will be third place
$score1 = EntryTotalScore::create([
'entry_id' => $this->entries[1]->id,
'seating_total' => 75,
'advancement_total' => 25,
'seating_subscore_totals' => [5, 5],
'advancement_subscore_totals' => [5, 5],
]);
// entry 2 will be first place
$score1 = EntryTotalScore::create([
'entry_id' => $this->entries[2]->id,
'seating_total' => 25,
'advancement_total' => 75,
'seating_subscore_totals' => [5, 5],
'advancement_subscore_totals' => [5, 5],
]);
$sortedEntries = ($this->ranker)($this->audition, 'advancement');
expect($sortedEntries[0]->id)->toEqual($this->entries[2]->id)
->and($sortedEntries[1]->id)->toEqual($this->entries[0]->id)
->and($sortedEntries[2]->id)->toEqual($this->entries[1]->id);
});
it('assigns a advancementRank property to each entry that is scored', function () {
// entry 0 will be second place
$score0 = EntryTotalScore::create([
'entry_id' => $this->entries[0]->id,
'seating_total' => 50,
'advancement_total' => 50,
'seating_subscore_totals' => [5, 5],
'advancement_subscore_totals' => [5, 5],
]);
// entry 1 will be third place
$score1 = EntryTotalScore::create([
'entry_id' => $this->entries[1]->id,
'seating_total' => 75,
'advancement_total' => 25,
'seating_subscore_totals' => [5, 5],
'advancement_subscore_totals' => [5, 5],
]);
// entry 2 will be first place
$score1 = EntryTotalScore::create([
'entry_id' => $this->entries[2]->id,
'seating_total' => 25,
'advancement_total' => 75,
'seating_subscore_totals' => [5, 5],
'advancement_subscore_totals' => [5, 5],
]);
$sortedEntries = ($this->ranker)($this->audition, 'advancement');
expect($sortedEntries[0]->advancementRank)->toEqual(1)
->and($sortedEntries[1]->advancementRank)->toEqual(2)
->and($sortedEntries[2]->advancementRank)->toEqual(3)
->and($sortedEntries->count())->toEqual(3);
});
it('uses the second subscore as a second tiebreaker for advancement', function () {
// entry 0 will be second place
$score0 = EntryTotalScore::create([
'entry_id' => $this->entries[0]->id,
'seating_total' => 50,
'advancement_total' => 50,
'seating_subscore_totals' => [5, 5],
'advancement_subscore_totals' => [5, 5],
]);
// entry 1 will be third place
$score1 = EntryTotalScore::create([
'entry_id' => $this->entries[1]->id,
'seating_total' => 75,
'advancement_total' => 50,
'seating_subscore_totals' => [5, 5],
'advancement_subscore_totals' => [5, 4],
]);
// entry 2 will be first place
$score1 = EntryTotalScore::create([
'entry_id' => $this->entries[2]->id,
'seating_total' => 25,
'advancement_total' => 50,
'seating_subscore_totals' => [5, 5],
'advancement_subscore_totals' => [5, 6],
]);
$sortedEntries = ($this->ranker)($this->audition, 'advancement');
expect($sortedEntries[0]->id)->toEqual($this->entries[2]->id)
->and($sortedEntries[1]->id)->toEqual($this->entries[0]->id)
->and($sortedEntries[2]->id)->toEqual($this->entries[1]->id);
});
it('uses the first subscore as a tiebreaker for advancement', function () {
// entry 0 will be second place
$score0 = EntryTotalScore::create([
'entry_id' => $this->entries[0]->id,
'seating_total' => 50,
'advancement_total' => 50,
'seating_subscore_totals' => [5, 5],
'advancement_subscore_totals' => [5, 5],
]);
// entry 1 will be third place
$score1 = EntryTotalScore::create([
'entry_id' => $this->entries[1]->id,
'seating_total' => 50,
'advancement_total' => 50,
'seating_subscore_totals' => [5, 5],
'advancement_subscore_totals' => [4, 5],
]);
// entry 2 will be first place
$score1 = EntryTotalScore::create([
'entry_id' => $this->entries[2]->id,
'seating_total' => 50,
'advancement_total' => 50,
'seating_subscore_totals' => [5, 5],
'advancement_subscore_totals' => [6, 5],
]);
$sortedEntries = ($this->ranker)($this->audition, 'advancement');
expect($sortedEntries[0]->id)->toEqual($this->entries[2]->id)
->and($sortedEntries[1]->id)->toEqual($this->entries[0]->id)
->and($sortedEntries[2]->id)->toEqual($this->entries[1]->id);
});