# Copyright (c) 2012 Network Appliance, Inc. # All rights reserved. ## @summary Setup Expectation Library ## @author Adam.Ciapponi@netapp.com ## @pod here =head1 NAME NACL::Expectation =head1 DESCRIPTION This module implements RSpec-like expectations in perl. They provide a simple and straightforward interface to for validation and checking in tests that results in natural language expressions that are easier to read. On failure, verbose information is logged to make tracking down issues easier. The Expectation module is the public facing portion of the Matchers library and should be the only module included unless custom Matchers are being created. The Matchers library is available by using the Expectation module. use NACL::Expectation; The sections that follow will detail each of the methods of the library and give an example of common usage. If you need to write a specialized Matcher class, you can get further information in the Matcher base class: L =head1 GENERAL USAGE All functions and methods in this library take only scalars and references as parameters. Parameter validation is present for the methods to ensure correct usage. The primary usage of matchers and expectations library is to check values returned against the expected value. There are built in matchers provided to do most basic comparisons. Another usage is to check whether or not exceptions are returned when a block of code is executed. The following example has an example of both use cases: # Create a volume my $volume = NACL::STask::Volume->create( command_interface => $Node, vserver => 'vs0', volume => 'repo_vol', ); # Check that the volume is online this($volume->get_one_state_attribute('state'))->should(Be->lexically_equal_to('online')); # Try to recreate the volume, should fail (raise an exception) this_block { NACL::STask::Volume->create( command_interface => $Node, vserver => 'vs0', volume => 'repo_vol', ); } should( fail() ); If the volume was not online, the first expectation would fail and throw an ExpectationNotMetError with verbose information on what the actual value was and what was expected. If attempting to recreate the volume was successful, an ExpectationNotMetError would be throw saying that the code block was expected to fail but passed unexpectedly. =head1 METHODS =cut package NACL::Expectation; # Compiler directives. use strict; use warnings; # Module import. use CR::Setup::Constants; use NACL::Exceptions::ExpectationNotMetError; use NACL::Matcher; use NACL::MatcherValue; use NACL::Matchers::DeeplyEqualMatcher; use NACL::Matchers::EvaluationMatcher; use NACL::Matchers::ExceptionMatcher; use NACL::Matchers::MockObjectMatcher; use NACL::Matchers::MetaMatchers::PeriodicMatcher; use Data::Dumper; use Params::Validate qw(:all); use Scalar::Util qw(blessed); use Storable qw(dclone); use base qw(Exporter); our @EXPORT = qw( continually continually_not evaluate_expectation eventually eventually_not fail pass should should_not these this this_block ); # Matcher stack tracing allows for exceptions to return all the matchers along # a stack trace. Useful for diagnostics of failures. our $Matcher_Stacktracing = $FALSE; my @isa_matcher_validate_spec = ( { isa => 'NACL::Matcher' }, ); =head2 UNIVERSAL::should Adds a method to all objects that allow them to be matched against matchers in the positive sense. It is called as any class method would be, in the form $object->should(some_comparison) =head3 Example Usage This example demonstrates how the Universal should method can be used. In the following statement, we call the Vserver->find method, but to verify that the method has returned a valid vserver object we call the attached should method to verify that the object's type is indeed a NACL::C::Vserver. my $vs = NACL::C::Vserver->find( command_interface => $Node, filter => { vserver => $Defaults->Vserver->vserver } ); $vs->should( Be->a( 'NACL::C::Vserver' ) ); =cut sub UNIVERSAL::should { validate_pos( @{[@_[1..$#_]]}, @isa_matcher_validate_spec); if ( !$_[1]->matches(NACL::MatcherValue->make_matcher_value_if_not_already( value => $_[0], decoderef => $FALSE )) ) { my $e = NACL::Exceptions::ExpectationNotMetError->new($_[1]->failure_message()); if ( $Matcher_Stacktracing ) { $e->matcher_stacktrace($_[1]->matcher_stacktrace()); } die $e; } (); } =head2 UNIVERSAL::should_not Adds a method to all objects that allow them to be matched against matchers in the negative sense. It behaves and is used in the same manner as the Universal should method above, except it expects the matcher not to match. =head3 Example Usage While this is not a typical use, if we rewrite the previous example as a negative test case, we can test to ensure that the returned object is not some other type that we were not expecting, in this case, a NACL::C::Volume. my $vs = NACL::C::Vserver->find( command_interface => $Node, filter => { vserver => $Defaults->Vserver->vserver } ); $vs->should_not( Be->a( 'NACL::C::Volume' ) ); =cut sub UNIVERSAL::should_not { validate_pos( @{[@_[1..$#_]]}, @isa_matcher_validate_spec); if ( $_[1]->matches(NACL::MatcherValue->make_matcher_value_if_not_already( value => $_[0], decoderef => $FALSE )) ) { my $e = NACL::Exceptions::ExpectationNotMetError->new($_[1]->negative_failure_message()); if ( $Matcher_Stacktracing ) { $e->matcher_stacktrace($_[1]->matcher_stacktrace()); } die $e; } (); } =head2 this This function returns a blessed reference to the input if it was not already a blessed reference. It either takes an object as a parameter, or takes a scalar or reference and converts it to an object in order to make a specific comparison. =head3 Example Usage In this example, we have a volume object who's name we wish to verify. We encapsulate the object's name property in the this statement and then make the comparison to the value 'repo_vol' this($volume->volume)->should(Be->lexically_equal_to('repo_vol')); =cut sub this { # In order to pass the result from a function doing return; # the parameter needs to be optional validate_pos( @{[@_[1..$#_]]}); CR::Setup::Exception->throw('this() must never be called in a void context') if ! defined wantarray; NACL::MatcherValue->make_matcher_value_if_not_already( value => $_[0], decoderef => $FALSE ); } =head2 these This function is merely an alias for this() and is used to make proper english natural language expressions with plural variables. =cut sub these { this(@_); } =head2 this_block This function encapsulates a block of code in order to match the resulting value or status against a specific condition or result. =head3 Example Usage Consider the following example, where we create an Infinite Volume on a vserver and then attempt to create a second volume on the same vserver. We are expecting a certain error message that we have defined in the variable $error_message, and the test case will succeed, unless the error message returned by the command is not what we expect. this_block { NACL::STask::Volume->create( command_interface => $Node, vserver => 'vs0', 'constituent-role' => 'data', ); } should( fail()->with_error_message_like(qr/"aggregate" is a required field/) ); =cut my @this_block_validate_spec = ( { type => CODEREF }, { type => ARRAYREF }, ); sub this_block (&$) { validate_pos( @_, @this_block_validate_spec ); evaluate_expectation( $_[0], $_[1]->[0], $_[1]->[1] ); } =head2 should This function allows calling a matcher in the positive sense outside an object context. It is typically used at the end of a this or this_block statement as the beginning of a verification statement. =head3 Example Usage For the most basic example, see the example usage of the this_block statement above. In it, we attempt to create a volume with the same name as an existing one and state that the command should fail. =cut my @should_validate_spec = ( $TRUE, { isa => 'NACL::Matcher', optional => $TRUE }, ); sub should { # Due to the overlap with UNIVERSAL::should, this needs to handle two modes of # operation, exported and called as a function or used as a method validate_pos( @_, @should_validate_spec ); if ( scalar(@_) == 2 ) { # Method context $_[0]->SUPER::should($_[1]); } else { # Function context CR::Setup::Exception->throw('should() in function context must never be called in a void context') if ! defined wantarray; [ $_[0], 'positive' ]; } } =head2 should_not This function allows calling a matcher in the negative sense outside an object context. Just like the should statement, it is typically used at the end of a this or this_block statement as the beginning of a verification statement. =head3 Example Usage In this example, we retrieve the state of an Infinite Volume, then verify that it is not currently in an offline state. this($iv->get_one_state_attribute('state'))->should_not( Be->lexically_equal_to('offline') ); =cut my @should_not_validate_spec = ( $TRUE, { isa => 'NACL::Matcher', optional => $TRUE }, ); sub should_not { # Due to the overlap with UNIVERSAL::should_not, this needs to handle two modes of # operation, exported and called as a function or used as a method validate_pos( @_, @should_not_validate_spec ); if ( scalar(@_) == 2 ) { # Method context $_[0]->SUPER::should_not($_[1]); } else { # Function context CR::Setup::Exception->throw('should_not() in function context must never be called in a void context') if ! defined wantarray; [ $_[0], 'negative' ]; } } =head2 evaluate_expectation This function handles the generic evaluation of an expectation outside the context of an object. It essentially encapsulates a this() statement with a should() or should_not() operator, depending on the test case. =cut my @evaluate_expectation_validate_spec = ( $TRUE, { isa => 'NACL::Matcher' }, { type => SCALAR, regex => qr/^positive|negative$/ }, ); sub evaluate_expectation { validate_pos( @_, @evaluate_expectation_validate_spec ); if ( $_[2] eq 'positive' ) { this($_[0])->should($_[1]); } else { # negative sense this($_[0])->should_not($_[1]); } (); } =head2 fail This function provides the exception matcher initialized in the failure context. It is the basic operator to evaluate and handle expected failures in a test script, and its functionality can be extended in a number of ways, depending on what particular conditions you are testing for. =head3 Example Usage In this example, we attempt to create an Infinite Volume on a non-existent vserver, bad_vserver. We define the text of the expected error message beforehand, and then declare that the block will fail with that predefined error. this_block { NACL::STask::Volume->create( command_interface => $Node, vserver => 'bad_vserver', volume => 'repo_vol', ); } should( fail()->with_error_message_like(qr/Vserver bad_vserver does not exist/) ); =cut sub fail { validate_pos(@_); NACL::Matchers::ExceptionMatcher->new( expected => {} )->with_failure(); } =head2 pass This function provides the exception matcher initialized in the success context. It is the basic operator to handle positive cases in test scripts, and like the fail() operator above, it can be extended with a number of supplementary operators, although it is most often used on its own to denote a passing test case. =head3 Example Usage The following demostrates the most basic use of the pass() operator. In it, we create a new Infinite Volume on a vserver, expecting the creation to pass without difficulty. my $volume; this_block { $volume = NACL::STask::Volume->create( command_interface => $Node, vserver => 'vs0', volume => 'repo_vol', ); } should( pass() ); =cut sub pass { validate_pos(@_); NACL::Matchers::ExceptionMatcher->new( expected => {} )->with_success(); } =head2 eventually This function provides the periodic matcher initialized in the eventually context. =head3 Example Usage in this example, we have a volume we wish to bring online, but want the script to wait until the operation has completed. The statement essentially says that the state of $volume should eventually be equal to 'online', and to wait for 10 seconds for that to happen. Note that in this case, the script will wait for ten seconds, and then check the state of the volume. If it is not online, it will fail the verification. There are also a variety of other operators that allow more fine-grained control of such verification. They will described later in this document. $volume->online(); this_block { $volume->get_one_state_attribute('state'); } should( eventually( Be->lexically_equal_to('online') )->every(2)->within(10)->seconds() ); =cut # NOTE: Metamatchers are special and cannot actually be passed a generalized value, only a matcher sub eventually { validate_pos( @_, @isa_matcher_validate_spec); NACL::Matchers::MetaMatchers::PeriodicMatcher->new( expected => $_[0] ) ->with_eventually()->with_positive_sense(); } =head2 eventually_not This function provides the periodic matcher initialized in the eventually not context. This statement is essentailly the opposite case of the eventually matcher described above. =cut # NOTE: Metamatchers are special and cannot actually be passed a generalized value, only a matcher sub eventually_not { validate_pos( @_, @isa_matcher_validate_spec); NACL::Matchers::MetaMatchers::PeriodicMatcher->new( expected => $_[0] ) ->with_eventually()->with_negative_sense(); } =head2 continually This function provides the periodic matcher initialized in the continually context. It will, as the name suggests, continually check a particular value or condition, typically for a predetermined length of time =head3 Example Usage In this example, we offline an Infinite Volume and then monitor the state of the volume for three seconds, making a check of the state every half-second. If the volume's state remains the same for that three second period, the case will pass. If the volume offline operation completes before that, it will fail. $volume->offline(); this_block { $volume->get_one_state_attribute('state'); } should( continually( Be->lexically_equal_to('offline'))->every(1)->for_exactly(3)->seconds() ); =cut # NOTE: Metamatchers are special and cannot actually be passed a generalized value, only a matcher sub continually { validate_pos( @_, @isa_matcher_validate_spec); NACL::Matchers::MetaMatchers::PeriodicMatcher->new( expected => $_[0] ) ->with_continually()->with_positive_sense(); } =head2 continually_not This function provides the periodic matcher initialized in the continually not context. As its name suggests, is is the opposite case of the continually operator above. =cut # NOTE: Metamatchers are special and cannot actually be passed a generalized value, only a matcher sub continually_not { validate_pos( @_, @isa_matcher_validate_spec); NACL::Matchers::MetaMatchers::PeriodicMatcher->new( expected => $_[0] ) ->with_continually()->with_negative_sense(); } package Be; use CR::Setup::Constants; use Params::Validate qw(:all); =head2 Be->true This function provides the evaluation matcher initialized to expect a value that evaluates to true. =head3 Example Usage In this example, we create an Infinite Volume through a predefined function and then verify that the creation was successful by evaluating the returned variable. If the creation fails, the variable will remain undefined and evaluate to false. my $iv = find_or_create_infinitevol(); this($iv)->should( Be->true() ); =cut sub true { validate_pos( @{[@_[1..$#_]]}); NACL::Matchers::EvaluationMatcher->new( expected => 'A true value.', failure_message => 'Expected true but got false.', negative_failure_message => 'Expected false but got true.', )->with_prefix('')->with_suffix('')->with_actual_dereferenced(); } =head2 Be->false This function provides the evaluation matcher initialized to expect a value that evaluates to false. It has exactly the same functionality as the true operator above, only for values of false instead. =cut sub false { validate_pos( @{[@_[1..$#_]]}); NACL::Matchers::EvaluationMatcher->new( expected => 'A false value.', failure_message => 'Expected false but got true.', negative_failure_message => 'Expected true but got false.', )->with_prefix('!')->with_suffix('')->with_actual_dereferenced(); } =head2 Be->numerically_equal_to This function provides the evaluation matcher initialized to expect a value which is numerically equal to the actual value. As the name suggests, it should be used in any case where numeric equality is expected. =head3 Example Usage Below is the simplest example of the numeric equality operator. Here, we have a variable whose value has been changed by our test case and we wish to test it against the expected value. this(1)->should( Be->numerically_equal_to(1) ); =cut sub numerically_equal_to { validate_pos( @{[@_[1..$#_]]}, $TRUE ); NACL::Matchers::EvaluationMatcher->new( expected => $_[1], failure_message => 'Expected the actual value to be numerically equal to the expected value but it was not.', negative_failure_message => 'Expected the actual value to not be numerically equal to the expected value but it was.', )->with_prefix('')->with_middle(' == ')->with_suffix('') ->with_actual_dereferenced()->with_expected_in_expression() ->with_expected_dereferenced(); } =head2 Be->numerically_greater_than This function provides the evaluation matcher initialized to expect a value which is numerically greater than the actual value. =head3 Example Usage This is the simplest example of this operator. As above, our test case has changed a variable, and we wish to verify that the new value is numerically greater than the original. this(2)->should( Be->numerically_greater_than(1) ); =cut sub numerically_greater_than { validate_pos( @{[@_[1..$#_]]}, $TRUE ); NACL::Matchers::EvaluationMatcher->new( expected => $_[1], failure_message => 'Expected the actual value to be numerically greater than the expected value but it was not.', negative_failure_message => 'Expected the actual value to not be numerically greater than the expected value but it was.', )->with_prefix('')->with_middle(' > ')->with_suffix('') ->with_actual_dereferenced()->with_expected_in_expression() ->with_expected_dereferenced(); } =head2 Be->numerically_greater_than_or_equal_to This function provides the evaluation matcher initialized to expect a value which is numerically greater than or equal to the actual value. =head3 Example Usage This is the simplest example of this operator. As above, our test case has changed a variable, and we wish to verify that the new value is numerically greater than or equal to the original. this(2)->should( Be->numerically_greater_than_or_equal_to(2) ); =cut sub numerically_greater_than_or_equal_to { validate_pos( @{[@_[1..$#_]]}, $TRUE ); NACL::Matchers::EvaluationMatcher->new( expected => $_[1], failure_message => 'Expected the actual value to be numerically greater than or equal to the expected value but it was not.', negative_failure_message => 'Expected the actual value to not be numerically greater than or equal to the expected value but it was.', )->with_prefix('')->with_middle(' >= ')->with_suffix('') ->with_actual_dereferenced()->with_expected_in_expression() ->with_expected_dereferenced(); } =head2 Be->numerically_less_than This function provides the evaluation matcher initialized to expect a value which is numerically less than the actual value. =head3 Example Usage This is the simplest example of this operator. As above, our test case has changed a variable, and we wish to verify that the new value is numerically lesser than the original. this(1)->should( Be->numerically_less_than(2) ); =cut sub numerically_less_than { validate_pos( @{[@_[1..$#_]]}, $TRUE ); NACL::Matchers::EvaluationMatcher->new( expected => $_[1], failure_message => 'Expected the actual value to be numerically less than the expected value but it was not.', negative_failure_message => 'Expected the actual value to not be numerically less than the expected value but it was.', )->with_prefix('')->with_middle(' < ')->with_suffix('') ->with_actual_dereferenced()->with_expected_in_expression() ->with_expected_dereferenced(); } =head2 Be->numerically_less_than_or_equal_to This function provides the evaluation matcher initialized to expect a value which is numerically less than or equal to the actual value. =head3 Example Usage This is the simplest example of this operator. As above, our test case has changed a variable, and we wish to verify that the new value is numerically lesser than or equal to the original. this(1)->should( Be->numerically_less_than_or_equal_to(1) ); =cut sub numerically_less_than_or_equal_to { validate_pos( @{[@_[1..$#_]]}, $TRUE ); NACL::Matchers::EvaluationMatcher->new( expected => $_[1], failure_message => 'Expected the actual value to be numerically less than or equal to the expected value but it was not.', negative_failure_message => 'Expected the actual value to not be numerically less than or equal to the expected value but it was.', )->with_prefix('')->with_middle(' <= ')->with_suffix('') ->with_actual_dereferenced()->with_expected_in_expression() ->with_expected_dereferenced(); } =head2 Be->lexically_equal_to This function provides the evaluation matcher initialized to expect a value which is lexically equal to the actual value. This operator expects a text value to perform the comparison against. =head3 Example Usage One of the more common uses for this operator is in error message verification. If we call a particular function to test a specific error condition and wish to verify the text of the returned error message, we would use a statement like the following: this('apple')->should( Be->lexically_equal_to('apple') ); =cut sub lexically_equal_to { validate_pos( @{[@_[1..$#_]]}, $TRUE ); NACL::Matchers::EvaluationMatcher->new( expected => $_[1], failure_message => 'Expected the actual value to be lexically equal to the expected value but it was not.', negative_failure_message => 'Expected the actual value to not be lexically equal to the expected value but it was.', )->with_prefix('')->with_middle(' eq ')->with_suffix('') ->with_actual_dereferenced()->with_expected_in_expression() ->with_expected_dereferenced(); } =head2 Be->lexically_greater_than This function provides the evaluation matcher initialized to expect a value which is lexically greater than the actual value. It uses basic perl text matching facilities, so the comparison is performed in a dictionary-style alphabetical order. =head3 Example Usage This operator is very straightforward in its use, as shown below. this('banana')->should( Be->lexically_greater_than('apple') ); =cut sub lexically_greater_than { validate_pos( @{[@_[1..$#_]]}, $TRUE ); NACL::Matchers::EvaluationMatcher->new( expected => $_[1], failure_message => 'Expected the actual value to be lexically greater than the expected value but it was not.', negative_failure_message => 'Expected the actual value to not be lexically greater than the expected value but it was.', )->with_prefix('')->with_middle(' gt ')->with_suffix('') ->with_actual_dereferenced()->with_expected_in_expression() ->with_expected_dereferenced(); } =head2 Be->lexically_greater_than_or_equal_to This function provides the evaluation matcher initialized to expect a value which is lexically greater than or equal to the actual value. As with the above examples, it uses basic perl text matching facilities, so the comparison is performed in a dictionary-style alphabetical order. =head3 Example Usage As with the rest of the lexical operators, it is very straightforward in its use, as shown below. this('banana')->should( Be->lexically_greater_than_or_equal_to('apple') ); =cut sub lexically_greater_than_or_equal_to { validate_pos( @{[@_[1..$#_]]}, $TRUE ); NACL::Matchers::EvaluationMatcher->new( expected => $_[1], failure_message => 'Expected the actual value to be lexically greater than or equal to the expected value but it was not.', negative_failure_message => 'Expected the actual value to not be lexically greater than or equal to the expected value but it was.', )->with_prefix('')->with_middle(' ge ')->with_suffix('') ->with_actual_dereferenced()->with_expected_in_expression() ->with_expected_dereferenced(); } =head2 Be->lexically_less_than This function provides the evaluation matcher initialized to expect a value which is lexically less than the actual value. As with the above examples, it uses basic perl text matching facilities, so the comparison is performed in a dictionary-style alphabetical order. =head3 Example Usage As with the rest of the lexical operators, it is very straightforward in its use, as shown below. this('apple')->should( Be->lexically_less_than('banana') ); =cut sub lexically_less_than { validate_pos( @{[@_[1..$#_]]}, $TRUE ); NACL::Matchers::EvaluationMatcher->new( expected => $_[1], failure_message => 'Expected the actual value to be lexically less than the expected value but it was not.', negative_failure_message => 'Expected the actual value to not be lexically less than the expected value but it was.', )->with_prefix('')->with_middle(' lt ')->with_suffix('') ->with_actual_dereferenced()->with_expected_in_expression() ->with_expected_dereferenced(); } =head2 Be->lexically_less_than_or_equal_to This function provides the evaluation matcher initialized to expect a value which is lexically less than or equal to the actual value. As with the above examples, it uses basic perl text matching facilities, so the comparison is performed in a dictionary-style alphabetical order. =head3 Example Usage As with the rest of the lexical operators, it is very straightforward in its use, as shown below. this('apple')->should( Be->lexically_less_than('banana') ); =cut sub lexically_less_than_or_equal_to { validate_pos( @{[@_[1..$#_]]}, $TRUE ); NACL::Matchers::EvaluationMatcher->new( expected => $_[1], failure_message => 'Expected the actual value to be lexically less than or equal to the expected value but it was not.', negative_failure_message => 'Expected the actual value to not be lexically less than or equal to the expected value but it was.', )->with_prefix('')->with_middle(' le ')->with_suffix('') ->with_actual_dereferenced()->with_expected_in_expression() ->with_expected_dereferenced(); } =head2 Be->a This function provides the evaluation matcher initialized to expect an object that is a particular class. The class identifier should be provided as a text string with the complete inheritance chain of the type. =head3 Example Usage In this example, we attempt to get a vserver object and verify that the returned object is in fact a Vserver object. If there are no Vservers to find, the statement will return a failure. my $vs = NACL::C::Vserver->find( command_interface => $Node, filter => { vserver => $Defaults->Vserver->vserver } ); $vs->should( Be->a( 'NACL::C::Vserver' ) ); =cut sub a { validate_pos( @{[@_[1..$#_]]}, $TRUE ); NACL::Matchers::EvaluationMatcher->new( expected => $_[1], failure_message => 'Expected the actual object to be of the expected class but it was not.', negative_failure_message => 'Expected the actual object to not be of the expected class but it was.', )->with_prefix('')->with_middle('->isa(')->with_suffix(')') ->with_expected_in_expression()->with_expected_dereferenced(); } =head2 Be->deeply_equal_to This function provides the evaluation matcher initialized to expect a value which is deeply equal to the actual value. =head3 Example Usage The most basic example of this operator is in comparing two references to complex data structures as below. Note that Be->deeply_equal_to must take references as parameters. this({ 'a' => 1, 'b' => 2 })->should( Be->deeply_equal_to({ 'a' => 1, 'b' => 2 })); =cut sub deeply_equal_to { validate_pos( @{[@_[1..$#_]]}, $TRUE ); NACL::Matchers::DeeplyEqualMatcher->new( expected => $_[1], failure_message => 'Expected the actual value to be deeply equal to the expected value but it was not.', negative_failure_message => 'Expected the actual value to not be deeply equal to the expected value but it was.', ); } =head2 Be->the_same_reference_as This function provides the evaluation matcher initialized to expect a reference which is the same as the actual reference. Note: Only blessed objects work for both this and this_block. References only work for this_block. =cut sub the_same_reference_as { validate_pos( @{[@_[1..$#_]]}, $TRUE ); NACL::Matchers::EvaluationMatcher->new( expected => $_[1], failure_message => 'Expected the actual reference to be the same as the expected reference but it was not.', negative_failure_message => 'Expected the actual reference to not be the same as the expected reference but it was.', )->with_prefix('')->with_middle(' == ')->with_suffix('') ->with_expected_in_expression(); } package Have; use CR::Setup::Constants; use Params::Validate qw(:all); =head2 Have->received This function provides the mock object matcher used to evaluate calls made to the mock for the function specified. This statement is most commonly used in unit tests to verify the values and objects passed back and forth in test cases. =cut sub received { validate_pos( @{[@_[1..$#_]]}, $TRUE ); NACL::Matchers::MockObjectMatcher->new( expected => $_[1], failure_message => 'Expected the mock object to have been called in the specified manner but it was not.', negative_failure_message => 'Expected the mock object to not have been called in the specified manner but it was.', ); } package Match; use CR::Setup::Constants; use Params::Validate qw(:all); =head2 Match->regex This function provides the evaluation matcher initialized to expect a value that matches a particular regex. The usage of this operator is very straightforward, in that it expects a precompiled quote (qr//) and then performs comparison on it. =head3 Example Usage The following statement demonstrates the most basic use of the Match->regex operator. We start with a response variable that should contain a given substring or expression and test that against it. this( $response )->should( Match->regex(qr/$expected_value/) ); =cut my $regex_validate_spec_regex_callback = sub { ref($_[0]) eq 'Regexp'; }; my $regex_validate_spec = { callbacks => { 'is it a qr// regex?' => $regex_validate_spec_regex_callback}}; sub regex { validate_pos( @{[@_[1..$#_]]}, $TRUE ); NACL::Matchers::EvaluationMatcher->new( expected => NACL::MatcherValue->make_matcher_value_if_not_already( value => $_[1], value_validation => $TRUE, value_spec => $regex_validate_spec ), failure_message => 'Expected the actual value to match the expected regex but it did not.', negative_failure_message => 'Expected the actual value to not match the expected regex but it did.', )->with_prefix('')->with_middle(' =~ ')->with_suffix('') ->with_actual_dereferenced()->with_expected_in_expression(); } package NACL::Expectation; 1;