diff --git a/README.md b/README.md index 34e0513d..cef1868c 100644 --- a/README.md +++ b/README.md @@ -163,6 +163,7 @@ timestampRFC3339 | Regex match a timestamp using the RFC3339 format. | Value (De like | Match a value against its data type. | Value | $matcher->like(12) somethingLike | Alias to like matcher. | Value | $matcher->somethingLike(12) eachLike | Match on an object like the example. | Value, Min (Defaults to 1) | $matcher->eachLike(12) +constrainedArrayLike | Behaves like the `eachLike` matcher, but also applies a minimum and maximum length validation on the length of the array. The optional `count` parameter controls the number of examples generated. | Value, Min, Max, count (Defaults to null) | $matcher->constrainedArrayLike('test', 1, 5, 3) boolean | Match against boolean true. | none | $matcher->boolean() integer | Match a value against integer. | Value (Defaults to 13) | $matcher->integer() decimal | Match a value against float. | Value (Defaults to 13.01) | $matcher->decimal() diff --git a/src/PhpPact/Consumer/Matcher/Matcher.php b/src/PhpPact/Consumer/Matcher/Matcher.php index a8da98f2..81f04f5b 100644 --- a/src/PhpPact/Consumer/Matcher/Matcher.php +++ b/src/PhpPact/Consumer/Matcher/Matcher.php @@ -93,22 +93,35 @@ public function atMostLike(mixed $value, int $max): array } /** - * @param mixed $value example of what the expected data would be - * @param int $min minimum number of objects to verify against - * - * @return array - */ - public function atLeastAndMostLike(mixed $value, int $min, int $max): array - { - if ($min <= 0 || $min > $max) { - throw new Exception('Invalid minimum number of elements'); + * @param mixed $value example of what the expected data would be + * @param int $min minimum number of objects to verify against + * @param int $max maximum number of objects to verify against + * @param int|null $count number of examples to generate, defaults to one + * + * @return array + */ + public function constrainedArrayLike(mixed $value, int $min, int $max, ?int $count = null): array + { + $elements = $count ?? $min; + if ($count !== null) { + if ($count < $min) { + throw new Exception( + "constrainedArrayLike has a minimum of {$min} but {$count} elements where requested." . + ' Make sure the count is greater than or equal to the min.' + ); + } elseif ($count > $max) { + throw new Exception( + "constrainedArrayLike has a maximum of {$max} but {$count} elements where requested." . + ' Make sure the count is less than or equal to the max.' + ); + } } return [ - 'value' => array_fill(0, $min, $value), - 'pact:matcher:type' => 'type', 'min' => $min, 'max' => $max, + 'pact:matcher:type' => 'type', + 'value' => array_fill(0, $elements, $value), ]; } diff --git a/tests/PhpPact/Consumer/Matcher/MatcherTest.php b/tests/PhpPact/Consumer/Matcher/MatcherTest.php index 39b0e168..f5ab12eb 100644 --- a/tests/PhpPact/Consumer/Matcher/MatcherTest.php +++ b/tests/PhpPact/Consumer/Matcher/MatcherTest.php @@ -134,17 +134,29 @@ public function testAtMostLike(object|array $value) /** * @throws Exception */ - public function testAtLeastAndMostLikeInvalidMin() + public function testConstrainedArrayLikeCountLessThanMin() { $this->expectException(Exception::class); - $this->expectExceptionMessage('Invalid minimum number of elements'); - $this->matcher->atLeastAndMostLike('text', 10, 1); + $this->expectExceptionMessage('constrainedArrayLike has a minimum of 2 but 1 elements where requested.' . + ' Make sure the count is greater than or equal to the min.'); + $this->matcher->constrainedArrayLike('text', 2, 4, 1); + } + + /** + * @throws Exception + */ + public function testConstrainedArrayLikeCountLargerThanMax() + { + $this->expectException(Exception::class); + $this->expectExceptionMessage('constrainedArrayLike has a maximum of 5 but 7 elements where requested.' . + ' Make sure the count is less than or equal to the max.'); + $this->matcher->constrainedArrayLike('text', 3, 5, 7); } /** * @dataProvider dataProviderForEachLikeTest */ - public function testAtLeastAndMostLike(object|array $value) + public function testConstrainedArrayLike(object|array $value) { $eachValueMatcher = [ 'value1' => [ @@ -154,16 +166,17 @@ public function testAtLeastAndMostLike(object|array $value) 'value2' => 2, ]; $expected = \json_encode([ + 'min' => 2, + 'max' => 4, + 'pact:matcher:type' => 'type', 'value' => [ $eachValueMatcher, $eachValueMatcher, + $eachValueMatcher, ], - 'pact:matcher:type' => 'type', - 'min' => 2, - 'max' => 4, ]); - $actual = \json_encode($this->matcher->atLeastAndMostLike($value, 2, 4)); + $actual = \json_encode($this->matcher->constrainedArrayLike($value, 2, 4, 3)); $this->assertEquals($expected, $actual); }