From 350b9ba97fe6d3164cad0830877e1634ed07d283 Mon Sep 17 00:00:00 2001 From: kakiuchi-shigenao Date: Mon, 4 Aug 2025 15:44:03 +0900 Subject: [PATCH] =?UTF-8?q?=E9=96=89=E5=8C=BA=E9=96=93=E3=81=AE=E5=A0=B4?= =?UTF-8?q?=E5=90=88=20LocalDateRange=20isValidRange=20=E3=83=A1=E3=82=BD?= =?UTF-8?q?=E3=83=83=E3=83=89=E3=81=AE=E5=88=A4=E5=AE=9A=E3=81=8C=E9=96=93?= =?UTF-8?q?=E9=81=95=E3=81=A3=E3=81=A6=E3=81=84=E3=82=8B=20Fixes=20#50?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- phpunit.xml.dist | 1 + src/DateTime/LocalDateRange.php | 42 ++++- tests/Unit/DateTime/LocalDateRangeTest.php | 161 +++++++++++++----- .../Unit/DateTime/LocalDateTimeRangeTest.php | 61 ++++--- .../Decimal/NegativeDecimalValueTest.php | 42 +++-- .../Decimal/PositiveDecimalValueTest.php | 43 +++-- .../Integer/NegativeIntegerValueTest.php | 40 ++--- .../Integer/PositiveIntegerValueTest.php | 41 ++--- tests/Unit/ValueObjectListTest.php | 36 ++-- 9 files changed, 288 insertions(+), 179 deletions(-) diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 28dab84..543b92d 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -11,6 +11,7 @@ timeoutForSmallTests="1" timeoutForMediumTests="10" timeoutForLargeTests="60" + displayDetailsOnPhpunitDeprecations="true" > diff --git a/src/DateTime/LocalDateRange.php b/src/DateTime/LocalDateRange.php index b98456c..2df6649 100644 --- a/src/DateTime/LocalDateRange.php +++ b/src/DateTime/LocalDateRange.php @@ -43,6 +43,7 @@ final private function __construct( ) { // NOTE: 不変条件(invariant) assert(static::isValid($from, $to)->isOk()); + assert(static::isValidRange($from, $to)->isOk()); } // ------------------------------------------------------------------------- @@ -97,6 +98,7 @@ final public static function tryFrom( mixed $to, ): Result { return static::isValid($from, $to) + ->andThen(static fn () => self::isValidRange($from, $to)) ->andThen(static fn () => Result\ok(static::from($from, $to))); } @@ -104,25 +106,51 @@ final public static function tryFrom( // MARK: validation methods // ------------------------------------------------------------------------- /** - * 有効な値かどうか + * 日付範囲が有効であることを検証 * * @param TStart $from 開始日付 * @param TEnd $to 終了日付 * * @return Result */ - protected static function isValid(mixed $from, mixed $to): Result + final protected static function isValidRange(mixed $from, mixed $to): Result { - if ($from->isAfter($to)) { - return Result\err(ValueObjectError::of( - code: 'value_object.date_range.invalid_range', - message: '開始日付は終了日付以前である必要があります' - )); + [$isValidRange, $errorCode, $message] = match (static::rangeType()) { + RangeType::CLOSED => [ + $from->isBeforeOrEqualTo($to), + 'value_object.date_range.invalid_range', + '開始日付は終了日付以前である必要があります', + ], + RangeType::OPEN, + RangeType::HALF_OPEN_RIGHT, + RangeType::HALF_OPEN_LEFT => [ + $from->isBefore($to), + 'value_object.date_range.invalid_range', + '開始日付は終了日付より前である必要があります', + ], + }; + + if (!$isValidRange) { + return Result\err(ValueObjectError::of(code: $errorCode, message: $message)); } return Result\ok(true); } + /** + * 有効な値かどうか + * NOTE: 実装クラスでのオーバーライド用メソッド + * + * @param TStart $from 開始日付 + * @param TEnd $to 終了日付 + * + * @return Result + */ + protected static function isValid(mixed $from, mixed $to): Result + { + return Result\ok(true); + } + // ------------------------------------------------------------------------- // MARK: public methods // ------------------------------------------------------------------------- diff --git a/tests/Unit/DateTime/LocalDateRangeTest.php b/tests/Unit/DateTime/LocalDateRangeTest.php index d6988a0..0293cc9 100644 --- a/tests/Unit/DateTime/LocalDateRangeTest.php +++ b/tests/Unit/DateTime/LocalDateRangeTest.php @@ -5,6 +5,8 @@ namespace WizDevelop\PhpValueObject\Tests\Unit\DateTime; use AssertionError; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\TestCase; use WizDevelop\PhpValueObject\DateTime\LocalDate; use WizDevelop\PhpValueObject\DateTime\LocalDateRange; @@ -31,7 +33,8 @@ */ final class LocalDateRangeTest extends TestCase { - public function test_閉区間で有効な範囲を作成できる(): void + #[Test] + public function 閉区間で有効な範囲を作成できる(): void { // Arrange $from = LocalDate::of(2024, 1, 1); @@ -47,7 +50,8 @@ public function test_閉区間で有効な範囲を作成できる(): void $this->assertSame('[2024-01-01, 2024-01-31]', $range->toISOString()); } - public function test_開区間で有効な範囲を作成できる(): void + #[Test] + public function 開区間で有効な範囲を作成できる(): void { // Arrange $from = LocalDate::of(2024, 1, 1); @@ -61,7 +65,8 @@ public function test_開区間で有効な範囲を作成できる(): void $this->assertSame('(2024-01-01, 2024-01-31)', $range->toISOString()); } - public function test_半開区間で有効な範囲を作成できる(): void + #[Test] + public function 半開区間で有効な範囲を作成できる(): void { // Arrange $from = LocalDate::of(2024, 1, 1); @@ -78,7 +83,8 @@ public function test_半開区間で有効な範囲を作成できる(): void $this->assertSame('[2024-01-01, 2024-01-31)', $rangeRight->toISOString()); } - public function test_開始日付が終了日付より後の場合エラーになる(): void + #[Test] + public function 開始日付が終了日付より後の場合エラーになる(): void { // Arrange $from = LocalDate::of(2024, 1, 31); @@ -87,6 +93,24 @@ public function test_開始日付が終了日付より後の場合エラーに // Act $result = LocalDateRange::tryFrom($from, $to); + // Assert + $this->assertTrue($result->isErr()); + $error = $result->unwrapErr(); + $this->assertInstanceOf(ValueObjectError::class, $error); + $this->assertSame('value_object.date_range.invalid_range', $error->getCode()); + $this->assertSame('開始日付は終了日付より前である必要があります', $error->getMessage()); + } + + #[Test] + public function 開始日付が終了日付より後の場合エラーになる_閉区間(): void + { + // Arrange + $from = LocalDate::of(2024, 1, 31); + $to = LocalDate::of(2024, 1, 30); + + // Act + $result = LocalDateRangeClosed::tryFrom($from, $to); + // Assert $this->assertTrue($result->isErr()); $error = $result->unwrapErr(); @@ -95,7 +119,27 @@ public function test_開始日付が終了日付より後の場合エラーに $this->assertSame('開始日付は終了日付以前である必要があります', $error->getMessage()); } - public function test_contains_閉区間の境界値を含む(): void + #[Test] + public function 開始日付と終了日付が同じ場合成功する_閉区間(): void + { + // Arrange + $from = LocalDate::of(2024, 1, 31); + $to = LocalDate::of(2024, 1, 31); + + // Act + LocalDateRangeClosed::from($from, $to); // 成功することを確認 + $result = LocalDateRangeClosed::tryFrom($from, $to); + + // Assert + $this->assertTrue($result->isOk()); + $range = $result->unwrap(); + $this->assertInstanceOf(LocalDateRangeClosed::class, $range); + $this->assertSame($from, $range->getFrom()); + $this->assertSame($to, $range->getTo()); + } + + #[Test] + public function contains_閉区間の境界値を含む(): void { // Arrange $from = LocalDate::of(2024, 1, 1); @@ -110,7 +154,8 @@ public function test_contains_閉区間の境界値を含む(): void $this->assertFalse($range->contains(LocalDate::of(2024, 2, 1))); // 範囲後 } - public function test_contains_開区間の境界値を含まない(): void + #[Test] + public function contains_開区間の境界値を含まない(): void { // Arrange $from = LocalDate::of(2024, 1, 1); @@ -123,7 +168,8 @@ public function test_contains_開区間の境界値を含まない(): void $this->assertTrue($range->contains(LocalDate::of(2024, 1, 15))); // 中間 } - public function test_contains_半開区間の境界値(): void + #[Test] + public function contains_半開区間の境界値(): void { // Arrange $from = LocalDate::of(2024, 1, 1); @@ -145,11 +191,12 @@ public function test_contains_半開区間の境界値(): void * overlapsメソッドの包括的なテストケース(DataProvider使用) * RangeTypeの全組み合わせ(4×4 = 16パターン)と範囲の位置関係を網羅 * - * @dataProvider provideOverlaps_comprehensiveCases * @param RangeData $range1Data * @param RangeData $range2Data */ - public function test_overlaps_comprehensive( + #[DataProvider('provideOverlaps_comprehensiveCases')] + #[Test] + public function overlaps_comprehensive( array $range1Data, array $range2Data, bool $expectedOverlap, @@ -484,7 +531,8 @@ public static function provideOverlaps_comprehensiveCases(): iterable ]; } - public function test_days_閉区間の日数計算(): void + #[Test] + public function days_閉区間の日数計算(): void { // Arrange $from = LocalDate::of(2024, 1, 1); @@ -498,7 +546,8 @@ public function test_days_閉区間の日数計算(): void $this->assertSame(5, $days); // 1日から5日まで(両端含む)= 5日間 } - public function test_days_開区間の日数計算(): void + #[Test] + public function days_開区間の日数計算(): void { // Arrange $from = LocalDate::of(2024, 1, 1); @@ -512,7 +561,8 @@ public function test_days_開区間の日数計算(): void $this->assertSame(3, $days); // 1日と5日を含まない = 3日間(2日、3日、4日) } - public function test_days_半開区間の日数計算(): void + #[Test] + public function days_半開区間の日数計算(): void { // Arrange $from = LocalDate::of(2024, 1, 1); @@ -527,7 +577,8 @@ public function test_days_半開区間の日数計算(): void $this->assertSame(4, $daysRight); // 1日を含み、5日を含まない = 4日間 } - public function test_iterate_閉区間での日付の反復(): void + #[Test] + public function iterate_閉区間での日付の反復(): void { // Arrange $from = LocalDate::of(2024, 1, 1); @@ -544,7 +595,8 @@ public function test_iterate_閉区間での日付の反復(): void $this->assertSame(['2024-01-01', '2024-01-02', '2024-01-03'], $dates); } - public function test_iterate_開区間での日付の反復(): void + #[Test] + public function iterate_開区間での日付の反復(): void { // Arrange $from = LocalDate::of(2024, 1, 1); @@ -561,7 +613,8 @@ public function test_iterate_開区間での日付の反復(): void $this->assertSame(['2024-01-02', '2024-01-03', '2024-01-04'], $dates); } - public function test_equals_同じ範囲(): void + #[Test] + public function equals_同じ範囲(): void { // Arrange $from = LocalDate::of(2024, 1, 1); @@ -573,7 +626,8 @@ public function test_equals_同じ範囲(): void $this->assertTrue($range1->equals($range2)); } - public function test_equals_異なる範囲(): void + #[Test] + public function equals_異なる範囲(): void { // Arrange $from = LocalDate::of(2024, 1, 1); @@ -586,7 +640,8 @@ public function test_equals_異なる範囲(): void $this->assertFalse($range1->equals($range2)); // 範囲タイプが異なる } - public function test_jsonSerialize(): void + #[Test] + public function jsonSerialize(): void { // Arrange $from = LocalDate::of(2024, 1, 1); @@ -600,7 +655,8 @@ public function test_jsonSerialize(): void $this->assertSame('[2024-01-01, 2024-01-31]', $json); } - public function test_from_デフォルトは右開区間(): void + #[Test] + public function from_デフォルトは右開区間(): void { // Arrange $from = LocalDate::of(2024, 1, 1); @@ -614,7 +670,8 @@ public function test_from_デフォルトは右開区間(): void $this->assertSame('[2024-01-01, 2024-01-31)', $range->toISOString()); } - public function test_withFrom_新しい開始日付で範囲を作成(): void + #[Test] + public function withFrom_新しい開始日付で範囲を作成(): void { // Arrange $from = LocalDate::of(2024, 1, 1); @@ -634,7 +691,8 @@ public function test_withFrom_新しい開始日付で範囲を作成(): void $this->assertSame($from, $range->getFrom()); } - public function test_withFrom_無効な範囲の場合例外が発生(): void + #[Test] + public function withFrom_無効な範囲の場合例外が発生(): void { // Arrange $from = LocalDate::of(2024, 1, 1); @@ -647,7 +705,8 @@ public function test_withFrom_無効な範囲の場合例外が発生(): void $range->withFrom($newFrom); } - public function test_withTo_新しい終了日付で範囲を作成(): void + #[Test] + public function withTo_新しい終了日付で範囲を作成(): void { // Arrange $from = LocalDate::of(2024, 1, 1); @@ -667,7 +726,8 @@ public function test_withTo_新しい終了日付で範囲を作成(): void $this->assertSame($to, $range->getTo()); } - public function test_withTo_無効な範囲の場合例外が発生(): void + #[Test] + public function withTo_無効な範囲の場合例外が発生(): void { // Arrange $from = LocalDate::of(2024, 1, 20); @@ -680,7 +740,8 @@ public function test_withTo_無効な範囲の場合例外が発生(): void $range->withTo($newTo); } - public function test_tryWithFrom_有効な開始日付の場合成功(): void + #[Test] + public function tryWithFrom_有効な開始日付の場合成功(): void { // Arrange $from = LocalDate::of(2024, 1, 1); @@ -699,7 +760,8 @@ public function test_tryWithFrom_有効な開始日付の場合成功(): void $this->assertSame(RangeType::CLOSED, $newRange->rangeType()); } - public function test_tryWithFrom_無効な開始日付の場合エラー(): void + #[Test] + public function tryWithFrom_無効な開始日付の場合エラー(): void { // Arrange $from = LocalDate::of(2024, 1, 1); @@ -715,10 +777,11 @@ public function test_tryWithFrom_無効な開始日付の場合エラー(): void $error = $result->unwrapErr(); $this->assertInstanceOf(ValueObjectError::class, $error); $this->assertSame('value_object.date_range.invalid_range', $error->getCode()); - $this->assertSame('開始日付は終了日付以前である必要があります', $error->getMessage()); + $this->assertSame('開始日付は終了日付より前である必要があります', $error->getMessage()); } - public function test_tryWithTo_有効な終了日付の場合成功(): void + #[Test] + public function tryWithTo_有効な終了日付の場合成功(): void { // Arrange $from = LocalDate::of(2024, 1, 1); @@ -737,7 +800,8 @@ public function test_tryWithTo_有効な終了日付の場合成功(): void $this->assertSame(RangeType::CLOSED, $newRange->rangeType()); } - public function test_tryWithTo_無効な終了日付の場合エラー(): void + #[Test] + public function tryWithTo_無効な終了日付の場合エラー(): void { // Arrange $from = LocalDate::of(2024, 1, 20); @@ -753,10 +817,11 @@ public function test_tryWithTo_無効な終了日付の場合エラー(): void $error = $result->unwrapErr(); $this->assertInstanceOf(ValueObjectError::class, $error); $this->assertSame('value_object.date_range.invalid_range', $error->getCode()); - $this->assertSame('開始日付は終了日付以前である必要があります', $error->getMessage()); + $this->assertSame('開始日付は終了日付より前である必要があります', $error->getMessage()); } - public function test_strictlyBefore_完全に前にある範囲(): void + #[Test] + public function strictlyBefore_完全に前にある範囲(): void { // Arrange $range1 = LocalDateRangeClosed::from( @@ -773,7 +838,8 @@ public function test_strictlyBefore_完全に前にある範囲(): void $this->assertFalse($range2->strictlyBefore($range1)); } - public function test_strictlyBefore_境界で接する範囲_閉区間(): void + #[Test] + public function strictlyBefore_境界で接する範囲_閉区間(): void { // Arrange $range1 = LocalDateRangeClosed::from( @@ -790,7 +856,8 @@ public function test_strictlyBefore_境界で接する範囲_閉区間(): void $this->assertFalse($range2->strictlyBefore($range1)); } - public function test_strictlyBefore_境界で接する範囲_開区間(): void + #[Test] + public function strictlyBefore_境界で接する範囲_開区間(): void { // Arrange $range1 = LocalDateRangeOpen::from( @@ -807,7 +874,8 @@ public function test_strictlyBefore_境界で接する範囲_開区間(): void $this->assertFalse($range2->strictlyBefore($range1)); } - public function test_strictlyBefore_境界で接する範囲_右開区間と左開区間(): void + #[Test] + public function strictlyBefore_境界で接する範囲_右開区間と左開区間(): void { // Arrange $range1 = LocalDateRangeHalfOpenRight::from( @@ -824,7 +892,8 @@ public function test_strictlyBefore_境界で接する範囲_右開区間と左 $this->assertFalse($range2->strictlyBefore($range1)); } - public function test_strictlyBefore_重なる範囲(): void + #[Test] + public function strictlyBefore_重なる範囲(): void { // Arrange $range1 = LocalDateRangeClosed::from( @@ -841,7 +910,8 @@ public function test_strictlyBefore_重なる範囲(): void $this->assertFalse($range2->strictlyBefore($range1)); } - public function test_strictlyBefore_境界で接する範囲_左開区間と右開区間の逆パターン(): void + #[Test] + public function strictlyBefore_境界で接する範囲_左開区間と右開区間の逆パターン(): void { // Arrange $range1 = LocalDateRangeHalfOpenLeft::from( @@ -858,7 +928,8 @@ public function test_strictlyBefore_境界で接する範囲_左開区間と右 $this->assertFalse($range2->strictlyBefore($range1)); } - public function test_strictlyBefore_閉区間と開区間の混在(): void + #[Test] + public function strictlyBefore_閉区間と開区間の混在(): void { // Arrange // 閉区間の後に開区間 @@ -890,7 +961,8 @@ public function test_strictlyBefore_閉区間と開区間の混在(): void $this->assertFalse($range4->strictlyBefore($range3)); } - public function test_strictlyBefore_閉区間と半開区間の混在(): void + #[Test] + public function strictlyBefore_閉区間と半開区間の混在(): void { // Arrange // 閉区間の後に左開区間 @@ -922,7 +994,8 @@ public function test_strictlyBefore_閉区間と半開区間の混在(): void $this->assertFalse($range4->strictlyBefore($range3)); } - public function test_count_閉区間の要素数(): void + #[Test] + public function count_閉区間の要素数(): void { // Arrange $from = LocalDate::of(2024, 1, 1); @@ -936,7 +1009,8 @@ public function test_count_閉区間の要素数(): void $this->assertSame(5, $count); // 1日から5日まで(両端含む)= 5要素 } - public function test_count_同じ日付の範囲(): void + #[Test] + public function count_同じ日付の範囲(): void { // Arrange $date = LocalDate::of(2024, 1, 1); @@ -949,7 +1023,8 @@ public function test_count_同じ日付の範囲(): void $this->assertSame(1, $count); // 単一の日付 = 1要素 } - public function test_count_年をまたぐ範囲(): void + #[Test] + public function count_年をまたぐ範囲(): void { // Arrange $from = LocalDate::of(2023, 12, 30); @@ -963,7 +1038,8 @@ public function test_count_年をまたぐ範囲(): void $this->assertSame(4, $count); // 12/30, 12/31, 1/1, 1/2 = 4要素 } - public function test_count_大きな範囲(): void + #[Test] + public function count_大きな範囲(): void { // Arrange $from = LocalDate::of(2024, 1, 1); @@ -978,10 +1054,11 @@ public function test_count_大きな範囲(): void } /** - * @dataProvider provideGetAsClosedCases * @param LocalDateRange $range */ - public function test_getAsClosed( + #[DataProvider('provideGetAsClosedCases')] + #[Test] + public function getAsClosed( LocalDateRange $range, LocalDate $expectedFrom, LocalDate $expectedTo diff --git a/tests/Unit/DateTime/LocalDateTimeRangeTest.php b/tests/Unit/DateTime/LocalDateTimeRangeTest.php index 3eafded..d3b8cb7 100644 --- a/tests/Unit/DateTime/LocalDateTimeRangeTest.php +++ b/tests/Unit/DateTime/LocalDateTimeRangeTest.php @@ -5,6 +5,7 @@ namespace WizDevelop\PhpValueObject\Tests\Unit\DateTime; use DateTimeImmutable; +use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\TestCase; use WizDevelop\PhpValueObject\DateTime\LocalDateTime; use WizDevelop\PhpValueObject\DateTime\LocalDateTimeRange; @@ -13,7 +14,8 @@ final class LocalDateTimeRangeTest extends TestCase { - public function test_閉区間で有効な範囲を作成できる(): void + #[Test] + public function 閉区間で有効な範囲を作成できる(): void { // Arrange $from = LocalDateTime::from(new DateTimeImmutable('2024-01-01 10:00:00')); @@ -29,7 +31,8 @@ public function test_閉区間で有効な範囲を作成できる(): void $this->assertSame('[2024-01-01T10:00, 2024-01-31T18:00]', $range->toISOString()); } - public function test_開区間で有効な範囲を作成できる(): void + #[Test] + public function 開区間で有効な範囲を作成できる(): void { // Arrange $from = LocalDateTime::from(new DateTimeImmutable('2024-01-01 10:00:00')); @@ -43,7 +46,8 @@ public function test_開区間で有効な範囲を作成できる(): void $this->assertSame('(2024-01-01T10:00, 2024-01-31T18:00)', $range->toISOString()); } - public function test_半開区間で有効な範囲を作成できる(): void + #[Test] + public function 半開区間で有効な範囲を作成できる(): void { // Arrange $from = LocalDateTime::from(new DateTimeImmutable('2024-01-01 10:00:00')); @@ -60,7 +64,8 @@ public function test_半開区間で有効な範囲を作成できる(): void $this->assertSame('[2024-01-01T10:00, 2024-01-31T18:00)', $rangeRight->toISOString()); } - public function test_開始日時が終了日時より後の場合エラーになる(): void + #[Test] + public function 開始日時が終了日時より後の場合エラーになる(): void { // Arrange $from = LocalDateTime::from(new DateTimeImmutable('2024-01-31 18:00:00')); @@ -77,7 +82,8 @@ public function test_開始日時が終了日時より後の場合エラーに $this->assertSame('開始日時は終了日時以前である必要があります', $error->getMessage()); } - public function test_contains_閉区間の境界値を含む(): void + #[Test] + public function contains_閉区間の境界値を含む(): void { // Arrange $from = LocalDateTime::from(new DateTimeImmutable('2024-01-01 10:00:00')); @@ -92,7 +98,8 @@ public function test_contains_閉区間の境界値を含む(): void $this->assertFalse($range->contains(LocalDateTime::from(new DateTimeImmutable('2024-02-01 00:00:00')))); // 範囲後 } - public function test_contains_開区間の境界値を含まない(): void + #[Test] + public function contains_開区間の境界値を含まない(): void { // Arrange $from = LocalDateTime::from(new DateTimeImmutable('2024-01-01 10:00:00')); @@ -105,7 +112,8 @@ public function test_contains_開区間の境界値を含まない(): void $this->assertTrue($range->contains(LocalDateTime::from(new DateTimeImmutable('2024-01-15 12:00:00')))); // 中間 } - public function test_contains_半開区間の境界値(): void + #[Test] + public function contains_半開区間の境界値(): void { // Arrange $from = LocalDateTime::from(new DateTimeImmutable('2024-01-01 10:00:00')); @@ -123,7 +131,8 @@ public function test_contains_半開区間の境界値(): void $this->assertFalse($rangeRight->contains($to)); // 終了境界(含まない) } - public function test_overlaps_重なりがある範囲(): void + #[Test] + public function overlaps_重なりがある範囲(): void { // Arrange $range1 = LocalDateTimeRange::closed( @@ -140,7 +149,8 @@ public function test_overlaps_重なりがある範囲(): void $this->assertTrue($range2->overlaps($range1)); } - public function test_overlaps_重なりがない範囲(): void + #[Test] + public function overlaps_重なりがない範囲(): void { // Arrange $range1 = LocalDateTimeRange::closed( @@ -157,7 +167,8 @@ public function test_overlaps_重なりがない範囲(): void $this->assertFalse($range2->overlaps($range1)); } - public function test_overlaps_境界で接する範囲_閉区間(): void + #[Test] + public function overlaps_境界で接する範囲_閉区間(): void { // Arrange $range1 = LocalDateTimeRange::closed( @@ -174,7 +185,8 @@ public function test_overlaps_境界で接する範囲_閉区間(): void $this->assertTrue($range2->overlaps($range1)); } - public function test_overlaps_境界で接する範囲_開区間(): void + #[Test] + public function overlaps_境界で接する範囲_開区間(): void { // Arrange $range1 = LocalDateTimeRange::open( @@ -191,7 +203,8 @@ public function test_overlaps_境界で接する範囲_開区間(): void $this->assertFalse($range2->overlaps($range1)); } - public function test_duration_計算(): void + #[Test] + public function duration_計算(): void { // Arrange $from = LocalDateTime::from(new DateTimeImmutable('2024-01-01 10:00:00')); @@ -205,7 +218,8 @@ public function test_duration_計算(): void $this->assertSame(1.0, $range->durationInDays()); // 1日 } - public function test_equals_同じ範囲(): void + #[Test] + public function equals_同じ範囲(): void { // Arrange $from = LocalDateTime::from(new DateTimeImmutable('2024-01-01 10:00:00')); @@ -217,7 +231,8 @@ public function test_equals_同じ範囲(): void $this->assertTrue($range1->equals($range2)); } - public function test_equals_異なる範囲(): void + #[Test] + public function equals_異なる範囲(): void { // Arrange $from = LocalDateTime::from(new DateTimeImmutable('2024-01-01 10:00:00')); @@ -229,7 +244,8 @@ public function test_equals_異なる範囲(): void $this->assertFalse($range1->equals($range2)); // 範囲タイプが異なる } - public function test_fromNullable_両方の値がnullでない場合(): void + #[Test] + public function fromNullable_両方の値がnullでない場合(): void { // Arrange $from = LocalDateTime::from(new DateTimeImmutable('2024-01-01 10:00:00')); @@ -245,7 +261,8 @@ public function test_fromNullable_両方の値がnullでない場合(): void $this->assertTrue($range->getTo()->equals($to)); } - public function test_fromNullable_いずれかの値がnullの場合(): void + #[Test] + public function fromNullable_いずれかの値がnullの場合(): void { // Arrange $from = LocalDateTime::from(new DateTimeImmutable('2024-01-01 10:00:00')); @@ -261,7 +278,8 @@ public function test_fromNullable_いずれかの値がnullの場合(): void $this->assertTrue($option3->isNone()); } - public function test_jsonSerialize(): void + #[Test] + public function jsonSerialize(): void { // Arrange $from = LocalDateTime::from(new DateTimeImmutable('2024-01-01 10:00:00')); @@ -275,7 +293,8 @@ public function test_jsonSerialize(): void $this->assertSame('[2024-01-01T10:00, 2024-01-31T18:00]', $json); } - public function test_from_デフォルトは閉区間(): void + #[Test] + public function from_デフォルトは閉区間(): void { // Arrange $from = LocalDateTime::from(new DateTimeImmutable('2024-01-01 10:00:00')); @@ -289,7 +308,8 @@ public function test_from_デフォルトは閉区間(): void $this->assertSame('[2024-01-01T10:00, 2024-01-31T18:00]', $range->toISOString()); } - public function test_from_to引数省略時は最大日時になる(): void + #[Test] + public function from_to引数省略時は最大日時になる(): void { // Arrange $from = LocalDateTime::from(new DateTimeImmutable('2024-01-01 10:00:00')); @@ -303,7 +323,8 @@ public function test_from_to引数省略時は最大日時になる(): void $this->assertSame(RangeType::CLOSED, $range->getRangeType()); } - public function test_tryFrom_to引数省略時も正常に動作(): void + #[Test] + public function tryFrom_to引数省略時も正常に動作(): void { // Arrange $from = LocalDateTime::from(new DateTimeImmutable('2024-01-01 10:00:00')); diff --git a/tests/Unit/Number/Decimal/NegativeDecimalValueTest.php b/tests/Unit/Number/Decimal/NegativeDecimalValueTest.php index 4475d24..4521880 100644 --- a/tests/Unit/Number/Decimal/NegativeDecimalValueTest.php +++ b/tests/Unit/Number/Decimal/NegativeDecimalValueTest.php @@ -4,6 +4,7 @@ namespace WizDevelop\PhpValueObject\Tests\Unit\Number\Decimal; +use AssertionError; use BcMath\Number; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\Attributes\DataProvider; @@ -57,27 +58,12 @@ public function ゼロではエラーになる(): void $this->assertStringContainsString('負の数', $errorMessage); } - /** - * @return array - */ - public static function 境界値のテストデータを提供(): array - { - return [ - 'ゼロ' => ['0.00', false], - '最大値' => ['-0.01', true], - '最大値+0.01' => ['0.00', false], - '最小値' => ['-1000.00', true], - '最小値-0.01' => ['-1000.01', false], - '正の値' => ['0.01', false], - ]; - } - /** * @param string $value テスト対象の値 * @param bool $shouldBeOk 成功するべきかどうか */ #[Test] - #[DataProvider('境界値のテストデータを提供')] + #[DataProvider('provide境界値テストCases')] public function 境界値テスト(string $value, bool $shouldBeOk): void { $result = TestNegativeDecimalValue::tryFrom(new Number($value)); @@ -91,6 +77,21 @@ public function 境界値テスト(string $value, bool $shouldBeOk): void } } + /** + * @return array + */ + public static function provide境界値テストCases(): iterable + { + return [ + 'ゼロ' => ['0.00', false], + '最大値' => ['-0.01', true], + '最大値+0.01' => ['0.00', false], + '最小値' => ['-1000.00', true], + '最小値-0.01' => ['-1000.01', false], + '正の値' => ['0.01', false], + ]; + } + #[Test] public function 加算メソッドのテスト_正常系(): void { @@ -185,13 +186,8 @@ public function isZero関数は負の小数値に対して常にfalseを返す() $this->assertFalse($negativeValue->isZero()); // 仮にゼロを作れたとしても、テストのために - try { - $zero = TestNegativeDecimalValue::from(new Number('0.00')); - $this->assertFalse($zero->isZero()); - } catch (Throwable $e) { - // 例外が発生する場合はスキップ - $this->markTestSkipped('ゼロの値を持つNegativeDecimalValueは作成できません'); - } + $this->expectException(AssertionError::class); + $zero = TestNegativeDecimalValue::from(new Number('0.00')); // AssertionErrorが発生する想定 } #[Test] diff --git a/tests/Unit/Number/Decimal/PositiveDecimalValueTest.php b/tests/Unit/Number/Decimal/PositiveDecimalValueTest.php index c7ea76f..3f96270 100644 --- a/tests/Unit/Number/Decimal/PositiveDecimalValueTest.php +++ b/tests/Unit/Number/Decimal/PositiveDecimalValueTest.php @@ -4,6 +4,7 @@ namespace WizDevelop\PhpValueObject\Tests\Unit\Number\Decimal; +use AssertionError; use BcMath\Number; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\Attributes\DataProvider; @@ -11,7 +12,6 @@ use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\Attributes\TestDox; use ReflectionClass; -use Throwable; use WizDevelop\PhpValueObject\Error\ValueObjectError; use WizDevelop\PhpValueObject\Examples\Number\Decimal\TestPositiveDecimalValue; use WizDevelop\PhpValueObject\Number\PositiveDecimalValue; @@ -57,27 +57,12 @@ public function ゼロではエラーになる(): void $this->assertStringContainsString('正の数', $errorMessage); } - /** - * @return array - */ - public static function 境界値のテストデータを提供(): array - { - return [ - 'ゼロ' => ['0.00', false], - '最小値' => ['0.01', true], - '最小値-0.01' => ['0.00', false], - '最大値' => ['1000.00', true], - '最大値+0.01' => ['1000.01', false], - '負の値' => ['-0.01', false], - ]; - } - /** * @param string $value テスト対象の値 * @param bool $shouldBeOk 成功するべきかどうか */ #[Test] - #[DataProvider('境界値のテストデータを提供')] + #[DataProvider('provide境界値テストCases')] public function 境界値テスト(string $value, bool $shouldBeOk): void { $result = TestPositiveDecimalValue::tryFrom(new Number($value)); @@ -91,6 +76,21 @@ public function 境界値テスト(string $value, bool $shouldBeOk): void } } + /** + * @return array + */ + public static function provide境界値テストCases(): iterable + { + return [ + 'ゼロ' => ['0.00', false], + '最小値' => ['0.01', true], + '最小値-0.01' => ['0.00', false], + '最大値' => ['1000.00', true], + '最大値+0.01' => ['1000.01', false], + '負の値' => ['-0.01', false], + ]; + } + #[Test] public function 加算メソッドのテスト_正常系(): void { @@ -209,13 +209,8 @@ public function isZero関数は正の小数値に対して常にfalseを返す() $this->assertFalse($positiveValue->isZero()); // 仮にゼロを作れたとしても、テストのために - try { - $zero = TestPositiveDecimalValue::from(new Number('0.00')); - $this->assertFalse($zero->isZero()); - } catch (Throwable $e) { - // 例外が発生する場合はスキップ - $this->markTestSkipped('ゼロの値を持つPositiveDecimalValueは作成できません'); - } + $this->expectException(AssertionError::class); + $zero = TestPositiveDecimalValue::from(new Number('0.00')); // AssertionErrorが発生する想定 } #[Test] diff --git a/tests/Unit/Number/Integer/NegativeIntegerValueTest.php b/tests/Unit/Number/Integer/NegativeIntegerValueTest.php index 1bf671b..c4f6457 100644 --- a/tests/Unit/Number/Integer/NegativeIntegerValueTest.php +++ b/tests/Unit/Number/Integer/NegativeIntegerValueTest.php @@ -4,6 +4,7 @@ namespace WizDevelop\PhpValueObject\Tests\Unit\Number\Integer; +use AssertionError; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\Attributes\Group; @@ -57,26 +58,12 @@ public function ゼロではエラーになる(): void $this->assertStringContainsString('負の整数', $errorMessage); } - /** - * @phpstan-ignore-next-line - */ - public static function 境界値のテストデータを提供(): array - { - return [ - 'ゼロ' => [0, false], - '-1' => [-1, true], - '最小値' => [-1000, true], - '最小値-1' => [-1001, false], - '1' => [1, false], - ]; - } - /** * @param int $value テスト対象の値 * @param bool $shouldBeOk 成功するべきかどうか */ #[Test] - #[DataProvider('境界値のテストデータを提供')] + #[DataProvider('provide境界値テストCases')] public function 境界値テスト(int $value, bool $shouldBeOk): void { $result = TestNegativeIntegerValue::tryFrom($value); @@ -90,6 +77,20 @@ public function 境界値テスト(int $value, bool $shouldBeOk): void } } + /** + * @phpstan-ignore-next-line + */ + public static function provide境界値テストCases(): iterable + { + return [ + 'ゼロ' => [0, false], + '-1' => [-1, true], + '最小値' => [-1000, true], + '最小値-1' => [-1001, false], + '1' => [1, false], + ]; + } + #[Test] public function 加算メソッドのテスト_正常系(): void { @@ -184,13 +185,8 @@ public function isZero関数は負の整数値に対して常にfalseを返す() $this->assertFalse($negativeValue->isZero()); // 仮にゼロを作れたとしても、テストのために - try { - $zero = TestNegativeIntegerValue::from(0); - $this->assertFalse($zero->isZero()); - } catch (Throwable $e) { - // 例外が発生する場合はスキップ - $this->markTestSkipped('ゼロの値を持つNegativeIntegerValueは作成できません'); - } + $this->expectException(AssertionError::class); + $zero = TestNegativeIntegerValue::from(0); // AssertionErrorが発生する想定 } #[Test] diff --git a/tests/Unit/Number/Integer/PositiveIntegerValueTest.php b/tests/Unit/Number/Integer/PositiveIntegerValueTest.php index cc7d7e8..24c35f2 100644 --- a/tests/Unit/Number/Integer/PositiveIntegerValueTest.php +++ b/tests/Unit/Number/Integer/PositiveIntegerValueTest.php @@ -4,6 +4,7 @@ namespace WizDevelop\PhpValueObject\Tests\Unit\Number\Integer; +use AssertionError; use Error; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\Attributes\DataProvider; @@ -11,7 +12,6 @@ use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\Attributes\TestDox; use ReflectionClass; -use Throwable; use WizDevelop\PhpValueObject\Error\ValueObjectError; use WizDevelop\PhpValueObject\Examples\Number\Integer\TestPositiveIntegerValue; use WizDevelop\PhpValueObject\Number\PositiveIntegerValue; @@ -57,26 +57,12 @@ public function ゼロではエラーになる(): void $this->assertStringContainsString('正の整数', $errorMessage); } - /** - * @phpstan-ignore-next-line - */ - public static function 境界値のテストデータを提供(): array - { - return [ - 'ゼロ' => [0, false], - '1' => [1, true], - '最大値' => [1000, true], - '最大値+1' => [1001, false], - '-1' => [-1, false], - ]; - } - /** * @param int $value テスト対象の値 * @param bool $shouldBeOk 成功するべきかどうか */ #[Test] - #[DataProvider('境界値のテストデータを提供')] + #[DataProvider('provide境界値テストCases')] public function 境界値テスト(int $value, bool $shouldBeOk): void { $result = TestPositiveIntegerValue::tryFrom($value); @@ -90,6 +76,20 @@ public function 境界値テスト(int $value, bool $shouldBeOk): void } } + /** + * @phpstan-ignore-next-line + */ + public static function provide境界値テストCases(): iterable + { + return [ + 'ゼロ' => [0, false], + '1' => [1, true], + '最大値' => [1000, true], + '最大値+1' => [1001, false], + '-1' => [-1, false], + ]; + } + #[Test] public function 加算メソッドのテスト_正常系(): void { @@ -208,13 +208,8 @@ public function isZero関数は正の整数値に対して常にfalseを返す() $this->assertFalse($positiveValue->isZero()); // 仮にゼロを作れたとしても、テストのために - try { - $zero = TestPositiveIntegerValue::from(0); - $this->assertFalse($zero->isZero()); - } catch (Throwable $e) { - // 例外が発生する場合はスキップ - $this->markTestSkipped('ゼロの値を持つPositiveIntegerValueは作成できません'); - } + $this->expectException(AssertionError::class); + $zero = TestPositiveIntegerValue::from(0); // AssertionErrorが発生する想定 } #[Test] diff --git a/tests/Unit/ValueObjectListTest.php b/tests/Unit/ValueObjectListTest.php index 3cdc9cf..e35d1fc 100644 --- a/tests/Unit/ValueObjectListTest.php +++ b/tests/Unit/ValueObjectListTest.php @@ -9,8 +9,8 @@ use PHPUnit\Framework\Attributes\TestDox; use PHPUnit\Framework\TestCase; use WizDevelop\PhpValueObject\IValueObject; -use WizDevelop\PhpValueObject\String\StringValue; use WizDevelop\PhpValueObject\Number\IntegerValue; +use WizDevelop\PhpValueObject\String\StringValue; use WizDevelop\PhpValueObject\ValueObjectList; #[TestDox('ValueObjectListクラスのテスト')] @@ -19,7 +19,7 @@ final class ValueObjectListTest extends TestCase { #[Test] #[TestDox('has(): 値オブジェクトが存在する場合にtrueを返すこと')] - public function test_has_値オブジェクトが存在する場合にtrueを返すこと(): void + public function has_値オブジェクトが存在する場合にtrueを返すこと(): void { // Arrange $list = ValueObjectList::from([ @@ -37,7 +37,7 @@ public function test_has_値オブジェクトが存在する場合にtrueを返 #[Test] #[TestDox('has(): 値オブジェクトが存在しない場合にfalseを返すこと')] - public function test_has_値オブジェクトが存在しない場合にfalseを返すこと(): void + public function has_値オブジェクトが存在しない場合にfalseを返すこと(): void { // Arrange $list = ValueObjectList::from([ @@ -55,7 +55,7 @@ public function test_has_値オブジェクトが存在しない場合にfalse #[Test] #[TestDox('has(): 空のリストの場合にfalseを返すこと')] - public function test_has_空のリストの場合にfalseを返すこと(): void + public function has_空のリストの場合にfalseを返すこと(): void { // Arrange $list = ValueObjectList::from([]); @@ -69,7 +69,7 @@ public function test_has_空のリストの場合にfalseを返すこと(): void #[Test] #[TestDox('remove(): 値オブジェクトを削除した新しいリストを返すこと')] - public function test_remove_値オブジェクトを削除した新しいリストを返すこと(): void + public function remove_値オブジェクトを削除した新しいリストを返すこと(): void { // Arrange $list = ValueObjectList::from([ @@ -90,7 +90,7 @@ public function test_remove_値オブジェクトを削除した新しいリス #[Test] #[TestDox('remove(): 存在しない値オブジェクトを削除しても元のリストと同じになること')] - public function test_remove_存在しない値オブジェクトを削除しても元のリストと同じになること(): void + public function remove_存在しない値オブジェクトを削除しても元のリストと同じになること(): void { // Arrange $list = ValueObjectList::from([ @@ -109,7 +109,7 @@ public function test_remove_存在しない値オブジェクトを削除して #[Test] #[TestDox('remove(): 複数の同じ値オブジェクトが存在する場合、すべて削除されること')] - public function test_remove_複数の同じ値オブジェクトが存在する場合すべて削除されること(): void + public function remove_複数の同じ値オブジェクトが存在する場合すべて削除されること(): void { // Arrange $list = ValueObjectList::from([ @@ -131,7 +131,7 @@ public function test_remove_複数の同じ値オブジェクトが存在する #[Test] #[TestDox('put(): 既存の値オブジェクトを新しいインスタンスで置換すること')] - public function test_put_既存の値オブジェクトを新しいインスタンスで置換すること(): void + public function put_既存の値オブジェクトを新しいインスタンスで置換すること(): void { // Arrange $original20 = IntegerValue::from(20); @@ -147,7 +147,7 @@ public function test_put_既存の値オブジェクトを新しいインスタ // Assert $this->assertCount(3, $result); - $values = array_map(fn(IValueObject $v) => $v->value, $result->toArray()); + $values = array_map(static fn (IValueObject $v) => $v->value, $result->toArray()); $this->assertEquals([10, 20, 30], $values); // 新しいインスタンスに置き換わっていることを確認 $this->assertNotSame($original20, $result->toArray()[1]); @@ -156,7 +156,7 @@ public function test_put_既存の値オブジェクトを新しいインスタ #[Test] #[TestDox('put(): 複数の同じ値オブジェクトが存在する場合、すべて置換されること')] - public function test_put_複数の同じ値オブジェクトが存在する場合すべて置換されること(): void + public function put_複数の同じ値オブジェクトが存在する場合すべて置換されること(): void { // Arrange $original10_1 = IntegerValue::from(10); @@ -174,7 +174,7 @@ public function test_put_複数の同じ値オブジェクトが存在する場 // Assert $this->assertCount(4, $result); - $values = array_map(fn(IValueObject $v) => $v->value, $result->toArray()); + $values = array_map(static fn (IValueObject $v) => $v->value, $result->toArray()); $this->assertEquals([10, 20, 10, 30], $values); // すべて新しいインスタンスに置き換わっていることを確認 $this->assertSame($new10, $result->toArray()[0]); @@ -183,7 +183,7 @@ public function test_put_複数の同じ値オブジェクトが存在する場 #[Test] #[TestDox('put(): 存在しない値オブジェクトの場合、リストは変更されないこと')] - public function test_put_存在しない値オブジェクトの場合リストは変更されないこと(): void + public function put_存在しない値オブジェクトの場合リストは変更されないこと(): void { // Arrange $list = ValueObjectList::from([ @@ -197,13 +197,13 @@ public function test_put_存在しない値オブジェクトの場合リスト // Assert $this->assertCount(3, $result); - $values = array_map(fn(IValueObject $v) => $v->value, $result->toArray()); + $values = array_map(static fn (IValueObject $v) => $v->value, $result->toArray()); $this->assertEquals([10, 20, 30], $values); } #[Test] #[TestDox('diff(): 2つのリストの差分を返すこと')] - public function test_diff_2つのリストの差分を返すこと(): void + public function diff_2つのリストの差分を返すこと(): void { // Arrange $list1 = ValueObjectList::from([ @@ -231,7 +231,7 @@ public function test_diff_2つのリストの差分を返すこと(): void #[Test] #[TestDox('diff(): 空のリストとの差分は元のリストと同じになること')] - public function test_diff_空のリストとの差分は元のリストと同じになること(): void + public function diff_空のリストとの差分は元のリストと同じになること(): void { // Arrange $list1 = ValueObjectList::from([ @@ -251,7 +251,7 @@ public function test_diff_空のリストとの差分は元のリストと同じ #[Test] #[TestDox('diff(): 同じリストとの差分は空のリストになること')] - public function test_diff_同じリストとの差分は空のリストになること(): void + public function diff_同じリストとの差分は空のリストになること(): void { // Arrange $list1 = ValueObjectList::from([ @@ -272,7 +272,7 @@ public function test_diff_同じリストとの差分は空のリストになる #[Test] #[TestDox('diff(): 異なる型の値オブジェクトを含むリストでも正しく動作すること')] - public function test_diff_異なる型の値オブジェクトを含むリストでも正しく動作すること(): void + public function diff_異なる型の値オブジェクトを含むリストでも正しく動作すること(): void { // Arrange $list1 = ValueObjectList::from([ @@ -294,4 +294,4 @@ public function test_diff_異なる型の値オブジェクトを含むリスト $this->assertTrue($result->has(StringValue::from('banana'))); $this->assertFalse($result->has(IntegerValue::from(10))); } -} \ No newline at end of file +}