create(['organisation_id' => $org->id]); } public function test_artist_uses_soft_deletes_trait(): void { $this->assertContains(SoftDeletes::class, class_uses_recursive(Artist::class)); $this->assertContains(SoftDeletes::class, class_uses_recursive(ArtistEngagement::class)); $this->assertContains(SoftDeletes::class, class_uses_recursive(Performance::class)); } public function test_genre_stage_stagemay_advance_models_do_not_use_soft_deletes(): void { $noSoftDelete = [Genre::class, Stage::class, StageDay::class, AdvanceSection::class, AdvanceSubmission::class, ArtistContact::class]; foreach ($noSoftDelete as $cls) { $this->assertNotContains(SoftDeletes::class, class_uses_recursive($cls), "{$cls} should not soft-delete"); } } public function test_artist_belongs_to_organisation_genre_and_agent(): void { $org = Organisation::factory()->create(); $genre = Genre::factory()->create(['organisation_id' => $org->id]); $artist = Artist::factory()->withGenre($genre)->create(['organisation_id' => $org->id]); $this->assertSame($org->id, $artist->organisation->id); $this->assertSame($genre->id, $artist->defaultGenre->id); } public function test_artist_slug_collisions_within_org_get_numeric_suffix(): void { $org = Organisation::factory()->create(); $a = Artist::create(['organisation_id' => $org->id, 'name' => 'Same Name']); $b = Artist::create(['organisation_id' => $org->id, 'name' => 'Same Name']); $c = Artist::create(['organisation_id' => $org->id, 'name' => 'Same Name']); $this->assertSame('same-name', $a->slug); $this->assertSame('same-name-2', $b->slug); $this->assertSame('same-name-3', $c->slug); } public function test_artist_slug_can_repeat_across_organisations(): void { $orgA = Organisation::factory()->create(); $orgB = Organisation::factory()->create(); $a = Artist::create(['organisation_id' => $orgA->id, 'name' => 'Shared Name']); $b = Artist::create(['organisation_id' => $orgB->id, 'name' => 'Shared Name']); $this->assertSame('shared-name', $a->slug); $this->assertSame('shared-name', $b->slug); } public function test_engagement_casts_enums(): void { $org = Organisation::factory()->create(); $event = Event::factory()->for($org)->create(); $artist = $this->artistInOrg($org); $eng = ArtistEngagement::create([ 'artist_id' => $artist->id, 'event_id' => $event->id, 'booking_status' => ArtistEngagementStatus::Confirmed->value, 'buma_handled_by' => BumaHandledBy::BookingAgency->value, ]); $this->assertInstanceOf(ArtistEngagementStatus::class, $eng->fresh()->booking_status); $this->assertSame(ArtistEngagementStatus::Confirmed, $eng->fresh()->booking_status); $this->assertSame(BumaHandledBy::BookingAgency, $eng->fresh()->buma_handled_by); } public function test_performance_is_parked_when_stage_id_null(): void { $perf = new Performance(['stage_id' => null]); $this->assertTrue($perf->isParked()); $perfWithStage = new Performance(['stage_id' => '01ABCDEFGHIJKLMNOPQRSTUVWX']); $this->assertFalse($perfWithStage->isParked()); } public function test_engagement_relationships(): void { $org = Organisation::factory()->create(); $event = Event::factory()->for($org)->create(); $artist = $this->artistInOrg($org); $eng = ArtistEngagement::create([ 'artist_id' => $artist->id, 'event_id' => $event->id, 'booking_status' => ArtistEngagementStatus::Draft->value, ]); $stage = Stage::factory()->for($event)->create(); $start = CarbonImmutable::now(); Performance::create([ 'engagement_id' => $eng->id, 'event_id' => $event->id, 'stage_id' => $stage->id, 'start_at' => $start, 'end_at' => $start->addHour(), ]); $this->assertSame(1, $eng->performances()->count()); $this->assertSame($artist->id, $eng->artist->id); $this->assertSame($event->id, $eng->event->id); } public function test_artist_contact_primary_scope(): void { $org = Organisation::factory()->create(); $artist = $this->artistInOrg($org); ArtistContact::factory()->for($artist)->create(['is_primary' => false]); ArtistContact::factory()->for($artist)->primary()->create(); $primary = ArtistContact::query() ->withoutGlobalScope(OrganisationScope::class) ->primary() ->get(); $this->assertCount(1, $primary); $this->assertTrue($primary->first()->is_primary); } public function test_purpose_subject_fqcn_artist_resolves_to_instantiable_class(): void { $reflection = new \ReflectionClass(\App\Providers\AppServiceProvider::class); $constant = $reflection->getReflectionConstant('PURPOSE_SUBJECT_FQCN'); $this->assertNotFalse($constant); /** @var array $map */ $map = $constant->getValue(); $this->assertArrayHasKey('artist', $map); $this->assertSame(Artist::class, $map['artist']); $this->assertTrue(class_exists($map['artist'])); $this->assertInstanceOf(Artist::class, new $map['artist']); } }