Skip to content

with_deep tests failing when references are modified after test call is made #52

@cblake777

Description

@cblake777

Working through some tests today, came across this issue with with_deep tests.

When mocking a call being made within a method being tested, the test was failing because there were "extra keys" within the hash ref being checked, even though we could prove those keys were not there. Essentially, it looks like when _given_args is called, and the args sent contain a hash ref or array ref, those references are being stored directly, instead of a clone of the data at the time the call is made. Those references are then used when the check is run, but by that time, the references have been updated with additional data.

A sample test written to demonstrate the problem:

#!/usr/local/bin/lwperl
use Test::Spec;
use Data::Dumper qw/Dumper/;

describe "Testing 'with_deep' values" => sub {
	my ($mock, $fiddle);
	before each => sub {
		$mock = mock();
		$fiddle = sub {
			my ($hash1, $hash2) = @_;
			$mock->foo($hash1, $hash2);
			$hash1->{blah} = 9;
			$hash2->{count} = 1;
			$hash2->{faddle} = 2;
			return;
		};
	};
	it "should pass, at the time 'foo' was called, hash1 and hash2 are correct" => sub {
		my $hash1 = { big => 1 };
		my $hash2 = { bat => 2 };
		my $expect = $mock->expects('foo')
			->with_deep({ big => 1 }, {bat => 2})
			->returns(sub { print 'Values when foo was called => ' . Dumper(\@_) });
		$fiddle->($hash1, $hash2);
		ok($expect->verify);
	};
	it "should pass, at the time 'foo' was called, hash1 and hash2 are correct" => sub {
		my $hash1 = { big => 1, blah => 9 };
		my $hash2 = { bat => 2 };
		my $expect = $mock->expects('foo')
			->with_deep({ big => 1, blah => 9}, {bat => 2})
			->returns(sub { print 'Values when foo was called => ' . Dumper(\@_) });
		$fiddle->($hash1, $hash2);
		ok($expect->verify);
	};
	it "SHOULD DEFINITELY FAIL, at the time 'foo' was called, hash1 and hash2 are not correct" => sub {
		my $hash1 = { big => 1 };
		my $hash2 = { bat => 2 };
		my $expect = $mock->expects('foo')
			->with_deep({ big => 1, blah => 9}, {bat => 2, count => 1, faddle => 2})
			->returns(sub { print 'Values when foo was called => ' . Dumper(\@_) });
		$fiddle->($hash1, $hash2);
		ok($expect->verify);
	};
};

runtests unless caller;

The output of the test is as follows:

---- start of test 1 ----
Values when foo was called => $VAR1 = [
          bless( {}, 'Test::Spec::Mocks::MockObject' ),
          {
            'big' => 1
          },
          {
            'bat' => 2
          }
        ];
not ok 1 - Testing 'with_deep' values should pass, at the time 'foo' was called, hash1 and hash2 are correct


#   Failed test 'Testing 'with_deep' values should pass, at the time 'foo' was called, hash1 and hash2 are correct' by dying:
#     Comparing hash keys of $data->[0][0]
Extra: 'blah'

Comparing hash keys of $data->[0][0]
Extra: 'blah'

---- start of test 2 ----
Values when foo was called => $VAR1 = [
          bless( {}, 'Test::Spec::Mocks::MockObject' ),
          {
            'big' => 1,
            'blah' => 9
          },
          {
            'bat' => 2
          }
        ];
not ok 2 - Testing 'with_deep' values should pass, at the time 'foo' was called, hash1 and hash2 are correct


#   Failed test 'Testing 'with_deep' values should pass, at the time 'foo' was called, hash1 and hash2 are correct' by dying:
#     Comparing hash keys of $data->[0][1]
Extra: 'count', 'faddle'

Comparing hash keys of $data->[0][1]
Extra: 'count', 'faddle'

---- start of test 3 ----
Values when foo was called => $VAR1 = [
          bless( {}, 'Test::Spec::Mocks::MockObject' ),
          {
            'big' => 1
          },
          {
            'bat' => 2
          }
        ];
ok 3 - Testing 'with_deep' values SHOULD DEFINITELY FAIL, at the time 'foo' was called, hash1 and hash2 are not correct

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions