From 53ccc5a7a3b68a34414e05848e3f682acb66c873 Mon Sep 17 00:00:00 2001 From: Matt Young Date: Wed, 2 Jul 2025 03:30:55 -0500 Subject: [PATCH] Create tests for app/actions/tabulation/EnterScore --- app/Actions/Tabulation/EnterScore.php | 27 ++-- .../app/Actions/Tabulation/EnterScoreTest.php | 127 ++++++++++++++++++ 2 files changed, 141 insertions(+), 13 deletions(-) create mode 100644 tests/Feature/app/Actions/Tabulation/EnterScoreTest.php diff --git a/app/Actions/Tabulation/EnterScore.php b/app/Actions/Tabulation/EnterScore.php index e38faa8..54023c4 100644 --- a/app/Actions/Tabulation/EnterScore.php +++ b/app/Actions/Tabulation/EnterScore.php @@ -6,6 +6,7 @@ namespace App\Actions\Tabulation; +use App\Exceptions\AuditionAdminException; use App\Exceptions\ScoreEntryException; use App\Models\AuditLogEntry; use App\Models\Entry; @@ -33,17 +34,17 @@ class EnterScore $scores = collect($scores); // Basic Validity Checks - if (! $user->exists()) { - throw new ScoreEntryException('User does not exist'); + if (! User::where('id', $user->id)->exists()) { + throw new AuditionAdminException('User does not exist'); } - if (! $entry->exists()) { - throw new ScoreEntryException('Entry does not exist'); + if (! Entry::where('id', $entry->id)->exists()) { + throw new AuditionAdminException('Entry does not exist'); } if ($entry->audition->hasFlag('seats_published')) { - throw new ScoreEntryException('Cannot score an entry in an audition with published seats'); + throw new AuditionAdminException('Cannot score an entry in an audition where seats are published'); } if ($entry->audition->hasFlag('advancement_published')) { - throw new ScoreEntryException('Cannot score an entry in an audition with published advancement'); + throw new AuditionAdminException('Cannot score an entry in an audition where advancement is published'); } // Check that the specified user is assigned to judge this entry @@ -51,20 +52,20 @@ class EnterScore ->where('room_id', $entry->audition->room_id) ->where('user_id', $user->id)->exists(); if (! $check) { - throw new ScoreEntryException('This judge is not assigned to judge this entry'); + throw new AuditionAdminException('This judge is not assigned to judge this entry'); } // Check if a score already exists if (! $scoreSheet) { if (ScoreSheet::where('user_id', $user->id)->where('entry_id', $entry->id)->exists()) { - throw new ScoreEntryException('That judge has already entered scores for that entry'); + throw new AuditionAdminException('That judge has already entered scores for that entry'); } } else { if ($scoreSheet->user_id !== $user->id) { - throw new ScoreEntryException('Existing score sheet is from a different judge'); + throw new AuditionAdminException('Existing score sheet is from a different judge'); } if ($scoreSheet->entry_id !== $entry->id) { - throw new ScoreEntryException('Existing score sheet is for a different entry'); + throw new AuditionAdminException('Existing score sheet is for a different entry'); } } @@ -76,16 +77,16 @@ class EnterScore $advancementTotal = 0; $advancementMaxPossible = 0; if ($scores->count() !== $subscoresRequired->count()) { - throw new ScoreEntryException('Invalid number of scores'); + throw new AuditionAdminException('Invalid number of scores'); } foreach ($subscoresRequired as $subscore) { // check that there is an element in the $scores collection with the key = $subscore->id if (! $scores->keys()->contains($subscore->id)) { - throw new ScoreEntryException('Invalid Score Submission'); + throw new AuditionAdminException('Invalid Score Submission'); } if ($scores[$subscore->id] > $subscore->max_score) { - throw new ScoreEntryException('Supplied subscore exceeds maximum allowed'); + throw new AuditionAdminException('Supplied subscore exceeds maximum allowed'); } // Add subscore to the storage array diff --git a/tests/Feature/app/Actions/Tabulation/EnterScoreTest.php b/tests/Feature/app/Actions/Tabulation/EnterScoreTest.php new file mode 100644 index 0000000..89b5ff6 --- /dev/null +++ b/tests/Feature/app/Actions/Tabulation/EnterScoreTest.php @@ -0,0 +1,127 @@ +run(); + SubscoreDefinition::where('id', '<', 900)->delete(); + $this->audition = Audition::first(); + $this->judge1 = User::factory()->create(); + $this->judge2 = User::factory()->create(); + $this->audition->judges()->attach([$this->judge1->id, $this->judge2->id]); + $this->entry1 = Entry::factory()->create(['audition_id' => $this->audition->id]); + $this->entry2 = Entry::factory()->create(['audition_id' => $this->audition->id]); + $this->scribe = app(EnterScore::class); + $this->possibleScoreArray = [ + 1001 => 10, + 1002 => 11, + 1003 => 12, + 1004 => 13, + 1005 => 14, + ]; + $this->anotherPossibleScoreArray = [ + 1001 => 20, + 1002 => 21, + 1003 => 22, + 1004 => 23, + 1005 => 24, + ]; +}); + +it('can enter a score', function () { + ($this->scribe)($this->judge1, $this->entry1, $this->possibleScoreArray); + expect($this->entry1->scoreSheets()->count())->toBe(1) + ->and($this->entry1->scoreSheets()->first()->seating_total)->toBe(11.875) + ->and($this->entry1->scoreSheets()->first()->advancement_total)->toBe(12.375); +}); + +it('will not enter a score for a judge that does not exist', function () { + $fakeJudge = User::factory()->make(); + ($this->scribe)($fakeJudge, $this->entry1, $this->possibleScoreArray); +})->throws(AuditionAdminException::class, 'User does not exist'); + +it('will not enter a score for an entry that does not exist', function () { + $fakeEntry = Entry::factory()->make(); + ($this->scribe)($this->judge1, $fakeEntry, $this->possibleScoreArray); +})->throws(AuditionAdminException::class, 'Entry does not exist'); + +it('will not score an entry if the audition seats are published', function () { + $this->audition->addFlag('seats_published'); + ($this->scribe)($this->judge1, $this->entry1, $this->possibleScoreArray); +})->throws(AuditionAdminException::class, 'Cannot score an entry in an audition where seats are published'); + +it('will not score an entry if the audition advancement is published', function () { + $this->audition->addFlag('advancement_published'); + ($this->scribe)($this->judge1, $this->entry1, $this->possibleScoreArray); +})->throws(AuditionAdminException::class, 'Cannot score an entry in an audition where advancement is published'); + +it('will not score an entry if the judge is not assigned to judge the entry', function () { + $fakeJudge = User::factory()->create(); + ($this->scribe)($fakeJudge, $this->entry1, $this->possibleScoreArray); +})->throws(AuditionAdminException::class, 'This judge is not assigned to judge this entry'); + +it('can modify an existing score sheet', function () { + ($this->scribe)($this->judge1, $this->entry1, $this->possibleScoreArray); + $scoreSheet = ScoreSheet::first(); + ($this->scribe)($this->judge1, $this->entry1, $this->anotherPossibleScoreArray, $scoreSheet); + expect($this->entry1->scoreSheets()->count())->toBe(1) + ->and($this->entry1->scoreSheets()->first()->seating_total)->toBe(21.875) + ->and($this->entry1->scoreSheets()->first()->advancement_total)->toBe(22.375); +}); + +it('will not change the judge on a score sheet', function () { + ($this->scribe)($this->judge1, $this->entry1, $this->possibleScoreArray); + $scoreSheet = ScoreSheet::first(); + ($this->scribe)($this->judge2, $this->entry1, $this->anotherPossibleScoreArray, $scoreSheet); +})->throws(AuditionAdminException::class, 'Existing score sheet is from a different judge'); + +it('will not accept a second score sheet for a judge ane entry', function () { + ($this->scribe)($this->judge1, $this->entry1, $this->possibleScoreArray); + ($this->scribe)($this->judge1, $this->entry1, $this->anotherPossibleScoreArray); +})->throws(AuditionAdminException::class, 'That judge has already entered scores for that entry'); + +it('will not change the entry on a score sheet', function () { + ($this->scribe)($this->judge1, $this->entry1, $this->possibleScoreArray); + $scoreSheet = ScoreSheet::first(); + ($this->scribe)($this->judge1, $this->entry2, $this->anotherPossibleScoreArray, $scoreSheet); +})->throws(AuditionAdminException::class, 'Existing score sheet is for a different entry'); + +it('will not accept an incorrect number of subscores', function () { + array_pop($this->possibleScoreArray); + ($this->scribe)($this->judge1, $this->entry1, $this->possibleScoreArray); +})->throws(AuditionAdminException::class, 'Invalid number of scores'); + +it('will not accept an invalid subscores', function () { + array_pop($this->possibleScoreArray); + $this->possibleScoreArray[3001] = 100; + ($this->scribe)($this->judge1, $this->entry1, $this->possibleScoreArray); +})->throws(AuditionAdminException::class, 'Invalid Score Submission'); + +it('will. not accept a subscore in excess of its maximum', function () { + $this->possibleScoreArray[1001] = 1500; + ($this->scribe)($this->judge1, $this->entry1, $this->possibleScoreArray); +})->throws(AuditionAdminException::class, 'Supplied subscore exceeds maximum allowed'); + +it('removes a no-show flag from an entry', function () { + $this->entry1->addFlag('no_show'); + ($this->scribe)($this->judge1, $this->entry1, $this->possibleScoreArray); + expect($this->entry1->hasFlag('no_show'))->toBeFalse(); +}); + +it('logs score entry', function () { + ($this->scribe)($this->judge1, $this->entry1, $this->possibleScoreArray); + $logEntry = \App\Models\AuditLogEntry::latest()->first(); + expect($logEntry->message)->toStartWith('Entered Score for entry id '); +});