assertEquals(1, $restriction->id); $this->assertEquals(123, $restriction->doctorId); $this->assertNull($restriction->serviceId); $this->assertEquals(RestrictionType::HIDE_DOCTOR, $restriction->type); $this->assertTrue($restriction->isActive); } /** * Test factory method for creating new restrictions * * @return void * @since 1.0.0 */ public function testCreateRestriction(): void { $restriction = Restriction::create( doctorId: 456, serviceId: 789, type: RestrictionType::HIDE_COMBINATION ); $this->assertEquals(0, $restriction->id); // Not yet saved $this->assertEquals(456, $restriction->doctorId); $this->assertEquals(789, $restriction->serviceId); $this->assertEquals(RestrictionType::HIDE_COMBINATION, $restriction->type); $this->assertTrue($restriction->isActive); $this->assertInstanceOf(DateTimeImmutable::class, $restriction->createdAt); } /** * Test CSS selector generation * * @return void * @since 1.0.0 */ public function testCssSelectorGeneration(): void { $doctorRestriction = new Restriction( id: 1, doctorId: 123, serviceId: null, type: RestrictionType::HIDE_DOCTOR ); $this->assertEquals('[data-doctor-id="123"]', $doctorRestriction->getCssSelector()); $combinationRestriction = new Restriction( id: 2, doctorId: 123, serviceId: 456, type: RestrictionType::HIDE_COMBINATION ); $this->assertEquals( '[data-doctor-id="123"][data-service-id="456"]', $combinationRestriction->getCssSelector() ); } /** * Test appliesTo method for different scenarios * * @return void * @since 1.0.0 */ public function testAppliesTo(): void { $doctorRestriction = new Restriction( id: 1, doctorId: 123, serviceId: null, type: RestrictionType::HIDE_DOCTOR ); $this->assertTrue($doctorRestriction->appliesTo(123)); $this->assertTrue($doctorRestriction->appliesTo(123, 999)); $this->assertFalse($doctorRestriction->appliesTo(456)); $serviceRestriction = new Restriction( id: 2, doctorId: 123, serviceId: 456, type: RestrictionType::HIDE_SERVICE ); $this->assertTrue($serviceRestriction->appliesTo(999, 456)); $this->assertFalse($serviceRestriction->appliesTo(999, 789)); $combinationRestriction = new Restriction( id: 3, doctorId: 123, serviceId: 456, type: RestrictionType::HIDE_COMBINATION ); $this->assertTrue($combinationRestriction->appliesTo(123, 456)); $this->assertFalse($combinationRestriction->appliesTo(123, 789)); $this->assertFalse($combinationRestriction->appliesTo(999, 456)); } /** * Test inactive restrictions don't apply * * @return void * @since 1.0.0 */ public function testInactiveRestrictionsDoNotApply(): void { $restriction = new Restriction( id: 1, doctorId: 123, serviceId: null, type: RestrictionType::HIDE_DOCTOR, isActive: false ); $this->assertFalse($restriction->appliesTo(123)); } /** * Test restriction priority for CSS ordering * * @return void * @since 1.0.0 */ public function testPriority(): void { $doctorRestriction = new Restriction( id: 1, doctorId: 123, serviceId: null, type: RestrictionType::HIDE_DOCTOR ); $serviceRestriction = new Restriction( id: 2, doctorId: 123, serviceId: 456, type: RestrictionType::HIDE_SERVICE ); $combinationRestriction = new Restriction( id: 3, doctorId: 123, serviceId: 456, type: RestrictionType::HIDE_COMBINATION ); $this->assertEquals(1, $doctorRestriction->getPriority()); $this->assertEquals(2, $serviceRestriction->getPriority()); $this->assertEquals(3, $combinationRestriction->getPriority()); } /** * Test creating updated restriction * * @return void * @since 1.0.0 */ public function testWithUpdates(): void { $original = new Restriction( id: 1, doctorId: 123, serviceId: null, type: RestrictionType::HIDE_DOCTOR, isActive: true, metadata: ['original' => true] ); $updated = $original->withUpdates( isActive: false, metadata: ['updated' => true] ); $this->assertTrue($original->isActive); $this->assertFalse($updated->isActive); $this->assertEquals(['original' => true], $original->metadata); $this->assertEquals(['updated' => true], $updated->metadata); $this->assertEquals($original->doctorId, $updated->doctorId); $this->assertEquals($original->type, $updated->type); $this->assertNotEquals($original->updatedAt, $updated->updatedAt); } /** * Test validation errors * * @return void * @since 1.0.0 */ public function testValidationErrors(): void { $this->expectException(\InvalidArgumentException::class); $this->expectExceptionMessage('Doctor ID must be positive'); new Restriction( id: 1, doctorId: 0, serviceId: null, type: RestrictionType::HIDE_DOCTOR ); } /** * Test service restriction requires service ID * * @return void * @since 1.0.0 */ public function testServiceRestrictionRequiresServiceId(): void { $this->expectException(\InvalidArgumentException::class); $this->expectExceptionMessage('requires a service ID'); new Restriction( id: 1, doctorId: 123, serviceId: null, type: RestrictionType::HIDE_SERVICE ); } /** * Test doctor restriction should not specify service ID * * @return void * @since 1.0.0 */ public function testDoctorRestrictionShouldNotSpecifyServiceId(): void { $this->expectException(\InvalidArgumentException::class); $this->expectExceptionMessage('should not specify a service ID'); new Restriction( id: 1, doctorId: 123, serviceId: 456, type: RestrictionType::HIDE_DOCTOR ); } /** * Test array conversion for database storage * * @return void * @since 1.0.0 */ public function testToArray(): void { $createdAt = new DateTimeImmutable('2024-01-01 12:00:00'); $updatedAt = new DateTimeImmutable('2024-01-01 13:00:00'); $restriction = new Restriction( id: 1, doctorId: 123, serviceId: 456, type: RestrictionType::HIDE_COMBINATION, isActive: true, createdAt: $createdAt, updatedAt: $updatedAt, createdBy: 789, metadata: ['test' => 'data'] ); $array = $restriction->toArray(); $expected = [ 'id' => 1, 'doctor_id' => 123, 'service_id' => 456, 'restriction_type' => 'hide_combination', 'is_active' => true, 'created_at' => '2024-01-01 12:00:00', 'updated_at' => '2024-01-01 13:00:00', 'created_by' => 789, 'metadata' => '{"test":"data"}' ]; $this->assertEquals($expected, $array); } }