From 23de496ce65c0339b5645ee56e09beba5990322a Mon Sep 17 00:00:00 2001 From: Matt Young Date: Wed, 2 Jul 2025 02:30:01 -0500 Subject: [PATCH] Create tests for app/actions/fortify/EnterBonusScore --- app/Actions/Tabulation/EnterBonusScore.php | 30 ++--- .../Tabulation/EnterBonusScoreTest.php | 115 ++++++++++++++++++ 2 files changed, 122 insertions(+), 23 deletions(-) create mode 100644 tests/Feature/app/Actions/Tabulation/EnterBonusScoreTest.php diff --git a/app/Actions/Tabulation/EnterBonusScore.php b/app/Actions/Tabulation/EnterBonusScore.php index 7f57d8e..145106d 100644 --- a/app/Actions/Tabulation/EnterBonusScore.php +++ b/app/Actions/Tabulation/EnterBonusScore.php @@ -4,19 +4,14 @@ namespace App\Actions\Tabulation; -use App\Exceptions\ScoreEntryException; +use App\Exceptions\AuditionAdminException; use App\Models\BonusScore; use App\Models\Entry; use App\Models\User; -use Illuminate\Database\Eloquent\Collection; use Illuminate\Support\Facades\App; class EnterBonusScore { - public function __construct() - { - } - public function __invoke(User $judge, Entry $entry, int $score): void { @@ -38,27 +33,16 @@ class EnterBonusScore } - protected function getRelatedEntries(Entry $entry): Collection - { - $bonusScore = $entry->audition->bonusScore->first(); - $relatedAuditions = $bonusScore->auditions; - - // Get all entries that have a student_id equal to that of entry and an audition_id in the related auditions - return Entry::where('student_id', $entry->student_id) - ->whereIn('audition_id', $relatedAuditions->pluck('id')) - ->get(); - } - protected function basicValidations(User $judge, Entry $entry): void { if (! $judge->exists) { - throw new ScoreEntryException('Invalid judge provided'); + throw new AuditionAdminException('Invalid judge provided'); } if (! $entry->exists) { - throw new ScoreEntryException('Invalid entry provided'); + throw new AuditionAdminException('Invalid entry provided'); } if ($entry->audition->bonusScore->count() === 0) { - throw new ScoreEntryException('Entry does not have a bonus score'); + throw new AuditionAdminException('Entry does not have a bonus score'); } } @@ -66,15 +50,15 @@ class EnterBonusScore protected function validateJudgeValidity(User $judge, Entry $entry, $score): void { if (BonusScore::where('entry_id', $entry->id)->where('user_id', $judge->id)->exists()) { - throw new ScoreEntryException('That judge has already scored that entry'); + throw new AuditionAdminException('That judge has already scored that entry'); } $bonusScore = $entry->audition->bonusScore->first(); if (! $bonusScore->judges->contains($judge)) { - throw new ScoreEntryException('That judge is not assigned to judge that bonus score'); + throw new AuditionAdminException('That judge is not assigned to judge that bonus score'); } if ($score > $bonusScore->max_score) { - throw new ScoreEntryException('That score exceeds the maximum'); + throw new AuditionAdminException('That score exceeds the maximum'); } } } diff --git a/tests/Feature/app/Actions/Tabulation/EnterBonusScoreTest.php b/tests/Feature/app/Actions/Tabulation/EnterBonusScoreTest.php new file mode 100644 index 0000000..013eb04 --- /dev/null +++ b/tests/Feature/app/Actions/Tabulation/EnterBonusScoreTest.php @@ -0,0 +1,115 @@ +room = Room::factory()->create(); + $scoringGuide = ScoringGuide::factory()->create(); + $this->audition1 = Audition::factory()->create([ + 'name' => 'Alto Sax', + 'room_id' => $this->room->id, + 'order_in_room' => 1, + 'minimum_grade' => 1, + 'maximum_grade' => 14, + 'scoring_guide_id' => $scoringGuide->id, + ]); + $this->audition2 = Audition::factory()->create([ + 'name' => 'Tenor Sax', + 'event_id' => $this->audition1->event_id, + 'room_id' => $this->room->id, + 'order_in_room' => 2, + 'minimum_grade' => 1, + 'maximum_grade' => 14, + 'scoring_guide_id' => $scoringGuide->id, + ]); + $this->audition3 = Audition::factory()->create([ + 'name' => 'Bari Sax', + 'event_id' => $this->audition1->event_id, + 'room_id' => $this->room->id, + 'order_in_room' => 3, + 'minimum_grade' => 1, + 'maximum_grade' => 14, + 'scoring_guide_id' => $scoringGuide->id, + ]); + $this->bonusScoreDefinition = BonusScoreDefinition::create([ + 'name' => 'Sax Improv', + 'max_score' => 10, + 'weight' => 1, + 'for_seating' => 1, + 'for_attendance' => 0, + ]); + $this->bonusScoreDefinition->auditions()->attach([ + $this->audition1->id, $this->audition2->id, $this->audition3->id, + ]); + $this->judge1 = User::factory()->create(); + $this->bonusScoreDefinition->judges()->attach([$this->judge1->id]); + $this->scribe = app(EnterBonusScore::class); + $this->studentEnteredOnce = Student::factory()->create(); + $this->studentEnteredTwice = Student::factory()->create(); + $this->studentEnteredThrice = Student::factory()->create(); + $entryAdder = app(CreateEntry::class); + $this->s1a1 = $entryAdder($this->studentEnteredOnce, $this->audition1); + $this->s2a1 = $entryAdder($this->studentEnteredTwice, $this->audition1); + $this->s2a2 = $entryAdder($this->studentEnteredTwice, $this->audition2); + $this->s3a1 = $entryAdder($this->studentEnteredThrice, $this->audition1); + $this->s3a2 = $entryAdder($this->studentEnteredThrice, $this->audition2); + $this->s3a3 = $entryAdder($this->studentEnteredThrice, $this->audition3); +}); + +it('enters a bonus score for an entry in one audition', function () { + ($this->scribe)($this->judge1, $this->s1a1, 7); + expect(BonusScore::count())->toEqual(1) + ->and(BonusScore::where('entry_id', $this->s1a1->id)->exists())->toBeTrue(); +}); +it('enters a bonus score for an student in multiple auditions and copies bonus to all entries', function () { + ($this->scribe)($this->judge1, $this->s3a2, 7); + expect(BonusScore::count())->toEqual(3); + $altoBS = BonusScore::where('entry_id', $this->s3a1->id)->first(); + expect($altoBS->score)->toEqual(7) + ->and($altoBS->originally_scored_entry)->toEqual($this->s3a2->id); + $tenorBS = BonusScore::where('entry_id', $this->s3a2->id)->first(); + expect($tenorBS->score)->toEqual(7) + ->and($tenorBS->originally_scored_entry)->toEqual($this->s3a2->id); + $bariBS = BonusScore::where('entry_id', $this->s3a3->id)->first(); + expect($bariBS->score)->toEqual(7) + ->and($bariBS->originally_scored_entry)->toEqual($this->s3a2->id); +}); +it('will not enter a score for a non existent judge', function () { + $fakeJudge = User::factory()->make(); + ($this->scribe)($fakeJudge, $this->s3a2, 7); +})->throws(AuditionAdminException::class, 'Invalid judge provided'); +it('will not enter a score for a non existent entry', function () { + $fakeEntry = Entry::factory()->make(); + ($this->scribe)($this->judge1, $fakeEntry, 7); +})->throws(AuditionAdminException::class, 'Invalid entry provided'); +it('will not enter a score for an audition with no bonus score', function () { + $newAudition = Audition::factory()->create(); + $newEntry = Entry::factory()->create(['audition_id' => $newAudition->id]); + ($this->scribe)($this->judge1, $newEntry, 7); +})->throws(AuditionAdminException::class, 'Entry does not have a bonus score'); +it('will not enter a bonus score for a judge that has already given one', function () { + ($this->scribe)($this->judge1, $this->s2a1, 7); + ($this->scribe)($this->judge1, $this->s2a2, 7); +})->throws(AuditionAdminException::class, 'That judge has already scored that entry'); +it('will not accept a score for a jduge not assigned to judge that audition', function () { + $dirtyJudge = User::factory()->create(); + ($this->scribe)($dirtyJudge, $this->s2a1, 7); +})->throws(AuditionAdminException::class, 'That judge is not assigned to judge that bonus score'); +it('will not enter a bonus score in excess of the maximum score', function () { + ($this->scribe)($this->judge1, $this->s1a1, 38); +})->throws(AuditionAdminException::class, 'That score exceeds the maximum');