rethink method parameters: options to new(), data to ranges()
[perl/list-index.git] / t / 25-apply.t
1 #!/usr/bin/env perl
2 use strict;
3 use warnings;
4
5 use Test::More tests => 6;
6 use Test::NoWarnings;
7 use Data::Dump 'pp';
8 use List::Util qw(first min max);
9 use List::MoreUtils qw(uniq firstidx);
10
11 BEGIN { use_ok('List::Index' => 'rangematch'); }
12
13 {
14         my %options = (pagesize => 10, context => 2);
15
16         # generate random test data
17         my @values;
18         for (0 .. rand 1000) {
19                 my $string = join '', map {
20                         # random character (a-z or random digit)
21                         chr((int rand(27) || rand(10)-ord('0')*0) + ord('a')-1)
22                 } 0 .. rand(16);
23                 push @values, $string
24                         unless @values and $values[-1] eq $string;
25         }
26         @values = uniq @values;
27
28         # find ranges for generated values
29         my $ranges = eval { List::Index->new(\%options)->ranges(\@values) };
30         my $failure = $@ || ref $ranges ne 'ARRAY' && (
31                 $ranges ? 'returned ranges not an array ref' : 'no ranges returned'
32         );
33         my $setup = scalar(@values)." rows at $options{pagesize}±$options{context}";
34         ok(!$failure, "ranges for $setup")
35                 or BAIL_OUT($failure);
36
37         # apply found ranges
38         my @matches = eval {
39                 my @contents;
40                 for (@$ranges) {
41                         my $match = rangematch($_);
42                         defined $match or die "Invalid range '$_'";
43                         push @contents, [ grep { /$match/ } @values ];
44                 }
45                 return @contents;
46         };
47         ok(first(sub {$_}, @matches), sprintf 'match %d pages', scalar(@$ranges))
48                 or BAIL_OUT($@);
49
50         # debugging report of data relevant to the first page with given size
51         sub pagecontext {
52                 my ($size) = @_;
53                 my $page = firstidx sub { @$_ == $size }, @matches;
54                 for (max($page - 1, 0) .. min($page + 1)) {
55                         my $pagevals = $matches[$_];
56                         printf("# page #%d [%s] (%d): %s\n",
57                                 $_, $ranges->[$_], scalar(@$pagevals),
58                                 join(' ', sort @$pagevals),
59                         );
60                 }
61         }
62
63         # analyse final page sizes
64         if (my $limit = $options{pagesize} + $options{context}) {
65                 my $largest = max(map { scalar @$_ } @matches);
66                 cmp_ok($largest, '<=', $limit, "page sizes under $limit")
67                         or pagecontext($largest);
68         }
69 #       pop @matches;
70         if (my $limit = $options{pagesize} - $options{context}) {
71                 my $smallest = min(map {scalar @$_} @matches);
72                 cmp_ok($smallest, '>=', $limit, "page sizes over $limit")
73                         or pagecontext($smallest);
74         }
75 }
76