diff --git a/README.md b/README.md
index b4194283..d7426ca0 100644
--- a/README.md
+++ b/README.md
@@ -387,6 +387,37 @@ Feature: Listing user toys
"""
```
+## PHPUnit integration
+
+The `assertMatchesPattern()` is a handy assertion that matches values in PHPUnit tests.
+To use it either include the `Coduo\PHPMatcher\PHPUnit\PHPMatcherAssertions` trait,
+or extend the `Coduo\PHPMatcher\PHPUnit\PHPMatcherTestCase`:
+
+```php
+namespace Coduo\PHPMatcher\Tests\PHPUnit;
+
+use Coduo\PHPMatcher\PHPUnit\PHPMatcherAssertions;
+
+class PHPMatcherAssertionsTest extends \PHPUnit_Framework_TestCase
+{
+ use PHPMatcherAssertions;
+
+ public function test_it_asserts_if_a_value_matches_the_pattern()
+ {
+ $this->assertMatchesPattern('@string@', 'foo');
+ }
+}
+```
+
+The `matchesPattern()` method can be used in PHPUnit stubs or mocks:
+
+```php
+$mock = $this->getMock(Foo::class);
+$mock->method('bar')
+ ->with($this->matchesPattern('@string@'))
+ ->willReturn('foo');
+```
+
## License
This library is distributed under the MIT license. Please see the LICENSE file.
diff --git a/phpunit.xml.dist b/phpunit.xml.dist
index c2cbcfc9..60e0cdae 100644
--- a/phpunit.xml.dist
+++ b/phpunit.xml.dist
@@ -13,11 +13,13 @@
./tests/
+ tests/PHPUnit/PHPMatcherAssertionsTest.php
+ tests/PHPUnit/PHPMatcherAssertionsTest.php
- ./src/Coduo/PHPMatcher/
+ ./src/
diff --git a/src/PHPUnit/PHPMatcherAssertions.php b/src/PHPUnit/PHPMatcherAssertions.php
new file mode 100644
index 00000000..4a71afc1
--- /dev/null
+++ b/src/PHPUnit/PHPMatcherAssertions.php
@@ -0,0 +1,26 @@
+pattern = $pattern;
+ $this->matcher = $this->createMatcher();
+ }
+
+ /**
+ * @return string
+ */
+ public function toString()
+ {
+ return 'matches the pattern';
+ }
+
+ /**
+ * @param mixed $other
+ *
+ * @return null|string
+ */
+ protected function additionalFailureDescription($other)
+ {
+ return $this->matcher->getError();
+ }
+
+ /**
+ * @param mixed $value
+ *
+ * @return bool
+ */
+ protected function matches($value)
+ {
+ return $this->matcher->match($value, $this->pattern);
+ }
+
+ /**
+ * @return Matcher
+ */
+ private function createMatcher()
+ {
+ $factory = new SimpleFactory();
+
+ return $factory->createMatcher();
+ }
+}
\ No newline at end of file
diff --git a/src/PHPUnit/PHPMatcherTestCase.php b/src/PHPUnit/PHPMatcherTestCase.php
new file mode 100644
index 00000000..42c92762
--- /dev/null
+++ b/src/PHPUnit/PHPMatcherTestCase.php
@@ -0,0 +1,26 @@
+assertThat($value, self::matchesPattern($pattern), $message);
+ }
+
+ /**
+ * @param string $pattern
+ *
+ * @return PHPMatcherConstraint
+ */
+ protected static function matchesPattern($pattern)
+ {
+ return new PHPMatcherConstraint($pattern);
+ }
+}
\ No newline at end of file
diff --git a/tests/PHPUnit/PHPMatcherAssertionsTest.php b/tests/PHPUnit/PHPMatcherAssertionsTest.php
new file mode 100644
index 00000000..bc394055
--- /dev/null
+++ b/tests/PHPUnit/PHPMatcherAssertionsTest.php
@@ -0,0 +1,41 @@
+assertMatchesPattern('@string@', 'foo');
+ }
+
+ /**
+ * @expectedException \PHPUnit_Framework_ExpectationFailedException
+ * @expectedExceptionMessage Failed asserting that '{"foo":"bar"}' matches the pattern
+ */
+ public function test_it_throws_an_expectation_failed_exception_if_a_value_does_not_match_the_pattern()
+ {
+ $this->assertMatchesPattern('{"foo": "@integer@"}', json_encode(array('foo' => 'bar')));
+ }
+
+ /**
+ * @expectedException \PHPUnit_Framework_ExpectationFailedException
+ * @expectedExceptionMessage Failed asserting that 42 matches the pattern.
+ */
+ public function test_it_creates_a_constraint_for_stubs()
+ {
+ $mock = $this->getMockBuilder('stdClass')
+ ->setMethods(array('getTitle'))
+ ->getMock();
+
+ $mock->method('getTitle')
+ ->with($this->matchesPattern('@string@'))
+ ->willReturn('foo');
+
+ $mock->getTitle(42);
+ }
+}
diff --git a/tests/PHPUnit/PHPMatcherConstraintTest.php b/tests/PHPUnit/PHPMatcherConstraintTest.php
new file mode 100644
index 00000000..a0870977
--- /dev/null
+++ b/tests/PHPUnit/PHPMatcherConstraintTest.php
@@ -0,0 +1,56 @@
+assertInstanceOf('PHPUnit_Framework_Constraint', new PHPMatcherConstraint('@string@'));
+ }
+
+ public function test_it_returns_true_if_a_value_matches_the_pattern()
+ {
+ $constraint = new PHPMatcherConstraint('@string@');
+
+ $this->assertTrue($constraint->evaluate('foo', '', true));
+ }
+
+ public function test_it_returns_false_if_a_value_does_not_match_the_pattern()
+ {
+ $constraint = new PHPMatcherConstraint('@string@');
+
+ $this->assertFalse($constraint->evaluate(42, '', true));
+ }
+
+ public function test_it_returns_false_if_a_pattern_is_not_a_string()
+ {
+ $constraint = new PHPMatcherConstraint(new \stdClass());
+
+ $this->assertFalse($constraint->evaluate('foo', '', true));
+ }
+
+ /**
+ * @expectedException \PHPUnit_Framework_ExpectationFailedException
+ * @expectedExceptionMessage Failed asserting that 42 matches the pattern
+ */
+ public function test_it_sets_a_failure_description_if_not_given()
+ {
+ $constraint = new PHPMatcherConstraint('@string@');
+
+ $this->assertFalse($constraint->evaluate(42));
+ }
+
+ /**
+ * @expectedException \PHPUnit_Framework_ExpectationFailedException
+ * @expectedExceptionMessage integer "42" is not a valid string
+ */
+ public function test_it_sets_additional_failure_description()
+ {
+ $constraint = new PHPMatcherConstraint('@string@');
+
+ $this->assertFalse($constraint->evaluate(42));
+ }
+}
diff --git a/tests/PHPUnit/PHPMatcherTestCaseTest.php b/tests/PHPUnit/PHPMatcherTestCaseTest.php
new file mode 100644
index 00000000..b5f63a22
--- /dev/null
+++ b/tests/PHPUnit/PHPMatcherTestCaseTest.php
@@ -0,0 +1,39 @@
+assertMatchesPattern('@string@', 'foo');
+ }
+
+ /**
+ * @expectedException \PHPUnit_Framework_ExpectationFailedException
+ * @expectedExceptionMessage Failed asserting that '{"foo":"bar"}' matches the pattern
+ */
+ public function test_it_throws_an_expectation_failed_exception_if_a_value_does_not_match_the_pattern()
+ {
+ $this->assertMatchesPattern('{"foo": "@integer@"}', json_encode(array('foo' => 'bar')));
+ }
+
+ /**
+ * @expectedException \PHPUnit_Framework_ExpectationFailedException
+ * @expectedExceptionMessage Failed asserting that 42 matches the pattern.
+ */
+ public function test_it_creates_a_constraint_for_stubs()
+ {
+ $mock = $this->getMockBuilder('stdClass')
+ ->setMethods(array('getTitle'))
+ ->getMock();
+
+ $mock->method('getTitle')
+ ->with($this->matchesPattern('@string@'))
+ ->willReturn('foo');
+
+ $mock->getTitle(42);
+ }
+}