Skip to content

Commit

Permalink
Merge pull request #7 from sirbrillig/add/was_called_when
Browse files Browse the repository at this point in the history
Add `Expectation->when` and `Spy->was_called_when`
  • Loading branch information
sirbrillig authored Jul 22, 2016
2 parents 45bfa01 + 3e113f5 commit b6214a7
Show file tree
Hide file tree
Showing 5 changed files with 153 additions and 1 deletion.
2 changes: 2 additions & 0 deletions API.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
- `get_called_functions()`: Get the raw call record for the Spy. Each call is an instance of `SpyCall`.
- `was_called()`: Return true if the Spy was called.
- `was_called_with( $arg... )`: Return true if the Spy was called with specific arguments.
- `was_called_when( $callable )`: Return true if the passed function returns true at least once. For each spy call, the function will be called with the arguments from that call.
- `was_called_times( $count )`: Return true if the Spy was called exactly $count times.
- `was_called_before( $spy )`: Return true if the Spy was called before $spy.
- `get_times_called()`: Return the number of times the Spy was called.
Expand Down Expand Up @@ -85,6 +86,7 @@
- `to_be_called()`: Add an expected behavior that the spy was called when this is resolved.
- `to_have_been_called()`: Alias for `to_be_called()`.
- `with( $arg... )`: Add an expected behavior that the spy was called with particular arguments when this is resolved.
- `when( $callable )`: Return true if the passed function returns true at least once. For each spy call, the function will be called with the arguments from that call.
- `times( $count )`: Add an expected behavior that the spy was called exactly $count times.
- `once()`: Alias for `times( 1 )`.
- `twice()`: Alias for `times( 2 )`.
Expand Down
44 changes: 43 additions & 1 deletion src/Spies/Expectation.php
Original file line number Diff line number Diff line change
Expand Up @@ -76,16 +76,58 @@ public function verify() {
}
}


/**
* Set expected behavior
*
* Expectations will be evaluated when `verify()` is called.
*
* The passed function will be called each time the spy is called and
* passed the arguments of that call.
*
* @param callable $callable The function to run on every call
* @return Expectation This Expectation to allow chaining
*/
public function when( $callable ) {
$this->expected_function = $callable;
$this->delay_expectation( function() use ( $callable ) {
$result = $this->spy->was_called_when( $callable );
$description = $this->build_failure_message( function( $bits ) {
$called_functions = $this->spy->get_called_functions();
$bits[] = 'matching the provided function but instead';
if ( count( $called_functions ) === 1 ) {
$bits[] = 'it was called with ' . $this->format_arguments_for_output( [ $called_functions[0] ] );
} else if ( count( $called_functions ) === 0 ) {
$bits[] = 'it was not called at all.';
} else if ( count( $called_functions ) > 1 ) {
$bits[] = 'it was called with each of these sets of arguments ' . $this->format_arguments_for_output( $called_functions );
}
return $bits;
} );
if ( $this->negation ) {
return $this->assertFalse( $result, $description );
}
return $this->assertTrue( $result, $description );
} );
return $this;
}

/**
* Set expected arguments
*
* Expectations will be evaluated when `verify()` is called.
*
* @param mixed $arg... The arguments we expect
* If passed a function, it will be called each time the spy is called and
* passed the arguments of that call.
*
* @param mixed $arg... The arguments we expect or a function
* @return Expectation This Expectation to allow chaining
*/
public function with() {
$args = func_get_args();
if ( is_callable( $args[0] ) ) {
return $this->when( $args[0] );
}
$this->expected_args = $args;
$this->delay_expectation( function() use ( $args ) {
$result = call_user_func_array( [ $this->spy, 'was_called_with' ], $args );
Expand Down
13 changes: 13 additions & 0 deletions src/Spies/Spy.php
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,19 @@ public function was_called_with() {
return ( count( $matching_calls ) > 0 );
}

/**
* Return true if a spy call causes a function to return true
*
* @param callable $callable A function to call with every set of arguments
* @return boolean True if the callable function matches at least one set of arguments
*/
public function was_called_when( $callable ) {
$matching_calls = array_filter( $this->get_called_functions(), function( $call ) use ( $callable ) {
return $callable( $call->get_args() );
} );
return ( count( $matching_calls ) > 0 );
}

public function was_called_before( $spy ) {
$call_record = $this->get_called_functions();
if ( count( $call_record ) < 1 ) {
Expand Down
66 changes: 66 additions & 0 deletions tests/ExpectationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,72 @@ public function test_with_is_met_if_the_spy_is_called_with_the_same_arguments()
$expectation->verify();
}

public function test_when_is_met_if_the_spy_is_called_and_function_returns_true() {
$spy = \Spies\make_spy();
$expectation = \Spies\expect_spy( $spy )->to_have_been_called->when( function() {
return true;
} );
$spy( 'foo', 'bar' );
$expectation->verify();
}

public function test_when_function_receives_arguments_for_each_call() {
$found = [];
$spy = \Spies\make_spy();
$expectation = \Spies\expect_spy( $spy )->to_have_been_called->when( function( $args ) use ( &$found ) {
$found[] = $args;
return true;
} );
$spy( 'foo', 'bar' );
$spy( 'boo', 'far' );
$expectation->verify();
$this->assertEquals( [ 'foo', 'bar' ], $found[0] );
$this->assertEquals( [ 'boo', 'far' ], $found[1] );
}

public function test_when_is_not_met_if_the_spy_is_called_and_function_returns_false() {
$spy = \Spies\make_spy();
$expectation = \Spies\expect_spy( $spy )->to_have_been_called->when( function() {
return false;
} );
$expectation->silent_failures = true;
$spy( 'foo', 'bar' );
$this->assertInternalType( 'string', $expectation->verify() );
}

public function test_with_is_met_if_the_spy_is_called_and_function_returns_true() {
$spy = \Spies\make_spy();
$expectation = \Spies\expect_spy( $spy )->to_have_been_called->with( function() {
return true;
} );
$spy( 'foo', 'bar' );
$expectation->verify();
}

public function test_with_function_receives_arguments_for_each_call() {
$found = [];
$spy = \Spies\make_spy();
$expectation = \Spies\expect_spy( $spy )->to_have_been_called->with( function( $args ) use ( &$found ) {
$found[] = $args;
return true;
} );
$spy( 'foo', 'bar' );
$spy( 'boo', 'far' );
$expectation->verify();
$this->assertEquals( [ 'foo', 'bar' ], $found[0] );
$this->assertEquals( [ 'boo', 'far' ], $found[1] );
}

public function test_with_is_not_met_if_the_spy_is_called_and_function_returns_false() {
$spy = \Spies\make_spy();
$expectation = \Spies\expect_spy( $spy )->to_have_been_called->with( function() {
return false;
} );
$expectation->silent_failures = true;
$spy( 'foo', 'bar' );
$this->assertInternalType( 'string', $expectation->verify() );
}

public function test_with_any_is_met_if_the_spy_is_called_with_any_arguments() {
$spy = \Spies\make_spy();
$expectation = \Spies\expect_spy( $spy )->to_have_been_called->with( 'foo', \Spies\any() );
Expand Down
29 changes: 29 additions & 0 deletions tests/SpyTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,35 @@ public function test_spy_was_called_with_returns_false_if_the_spy_was_not_called
$this->assertFalse( $spy->was_called_with( 'foo', 'bar', 'baz' ) );
}

public function test_spy_was_called_when_returns_true_if_the_spy_was_called_when_the_function_returns_true() {
$spy = \Spies\make_spy();
$spy( 'foo', 'bar', 'baz' );
$this->assertTrue( $spy->was_called_when( function() {
return true;
} ) );
}

public function test_spy_was_called_when_gets_the_arguments_for_each_call() {
$spy = \Spies\make_spy();
$spy( 'foo', 'bar' );
$spy( 'boo', 'far' );
$found = [];
$spy->was_called_when( function( $args ) use ( &$found ) {
$found[] = $args;
return true;
} );
$this->assertEquals( [ 'foo', 'bar' ], $found[0] );
$this->assertEquals( [ 'boo', 'far' ], $found[1] );
}

public function test_spy_was_called_when_returns_false_if_the_spy_was_called_when_the_function_returns_false() {
$spy = \Spies\make_spy();
$spy( 'foo', 'bar', 'baz' );
$this->assertFalse( $spy->was_called_when( function() {
return false;
} ) );
}

public function test_spy_was_called_before_returns_true_if_called_before_target_spy() {
$spy_1 = \Spies\make_spy();
$spy_2 = \Spies\make_spy();
Expand Down

0 comments on commit b6214a7

Please sign in to comment.