The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

Data::Focus::LensTester - tester for Lens implementations

SYNOPSIS

    use Test::More;
    use Data::Focus::LensTester;
    use Data::Focus::Lens::HashArray::Index;
    
    my $tester = Data::Focus::LensTester->new(
        test_whole => sub { is_deeply($_[0], $_[1]) },
        test_part  => sub { is($_[0], $_[1]) },
        parts => [undef, 1, "str"]
    );
    
    my $create_target = sub {
        +{ foo => "bar" }
    };
    
    my $lens = Data::Focus::Lens::HashArray::Index->new(
        index => "foo"
    );
    
    $tester->test_lens_laws(
        lens => $lens, target => $create_target,
        exp_focal_points => 1
    );

DESCRIPTION

Data::Focus::LensTester tests some common properties for lenses. They are called the "lens laws".

Concepturally, the lens laws are described as follows.

set-get law
    focus( focus($target)->set($lens, $part) )->get($lens) == $part

You get the exact $part you just set.

get-set law
    focus($target)->set( $lens, focus($target)->get($lens) ) == $target

If you put back the part you just got out of the $target, it changes nothing.

set-set law
    focus( focus($target)->set($lens, $part1) )->set($lens, $part2) == focus($target)->set($lens, $part2)

The $lens's focal point is consistent, so $part1 is overwritten by $part2.

Data::Focus::LensTester tests these laws with given set of $parts.

Tests and Focal Points

Depending on how many focal points the lens creates on the target, test_lens_laws() method tests the following laws.

0 focal point

It tests "get-set" and "set-set" laws. "set-get" law cannot be met.

1 focal point

It tests all three laws.

more than one focal points

It tests "set-get" and "set-set" laws.

In "set-get" law, the set() method should set all focal points to the same value.

Exception

Not all lenses meet all the lens laws.

Consider the following code for example.

    use strict;
    use warnings;
    use Data::Dumper;
    
    my $undef;
    $undef->[0] = $undef->[0]; ## get and set
    print Dumper $undef;
    
    ## => $VAR1 = [
    ## =>           undef
    ## =>         ];

If we think of ->[0] as a lens, the above example clearly breaks the "get-set" law because of autovivification.

If you expect that kind of behavior, do not use test_lens_laws() method. Use test_set_get() etc instead.

CLASS METHODS

$tester = Data::Focus::LensTester->new(%args)

The constructor. Fields in %args are:

test_whole => CODE (mandatory)

A code-ref that tests if two "whole" data are the same. A whole data is a data whose level of complexity is the same as the target data.

This code-ref is called like:

    $test_whole->($whole1, $whole2)

$test_whole must test equality between $whole1 and $whole2 in a Test::More way.

test_part => CODE (mandatory)

A code-ref that tests if two "part" data are the same. A part data is a data that can be included in a whole data.

This code-ref is called like:

    $test_part->($part1, $part2)

$test_part must test equality between $part1 and $part2 in a Test::More way.

parts => ARRAYREF_OF_PARTS (mandatory)

List of "part" data used for testing. At least two parts are necessary.

OBJECT METHODS

$tester->test_lens_laws(%args)

Test a Data::Focus::Lens object to see if it follows the lens law. See "Tests and Focal Points".

Fields in %args are:

lens => Data::Focus::Lens object (mandatory)

The lens to be tested.

target => CODE (mandatory)

A code-ref that returns the target object. It is called without argument.

    $target_data = $target->()

The $target code-ref must return a brand-new $target_data object for every call.

exp_focal_points => INT (mandatory)

Expected number of focal points the lens creates for the target.

$tester->test_set_get(%args)

$tester->test_get_set(%args)

$tester->test_set_set(%args)

Test individual lens laws. %args are the same as test_lens_laws() method.

@parts = $tester->parts

Get the parts passed in new() method.

AUTHOR

Toshio Ito, <toshioito at cpan.org>