skip subtests if Test::More is too old
[perl/list-index.git] / t / 10-ranges.t
index 84f4dbbc7f64dca807831325c08d2a4f29b9aece..9befbb68160ca850f17e33685e3ade61e7a10812 100644 (file)
 use strict;
 use warnings;
 
 use strict;
 use warnings;
 
-use Test::More tests => 7;
+use Test::More tests => 10;
 use Test::NoWarnings;
 use Data::Dump 'pp';
 
 BEGIN { use_ok('List::Index'); }
 ok(eval { List::Index->VERSION(1) }, 'version 1.00 compatibility');
 
 use Test::NoWarnings;
 use Data::Dump 'pp';
 
 BEGIN { use_ok('List::Index'); }
 ok(eval { List::Index->VERSION(1) }, 'version 1.00 compatibility');
 
-subtest 'single-char alphabet' => sub {
-       plan tests => 4;
-       my @uniform = 'a'..'z';
-       my $index = List::Index->new(\@uniform) or return;
-       is_deeply(\@uniform, ['a'..'z'], 'original data unaltered');
-       is_deeply($index->ranges, ['-'], 'single page');
-       is_deeply($index->ranges({pages => 3}), [qw(-i j-q r-)], 'given pages');
-       is_deeply($index->ranges({pagesize => @uniform / 2.1}), [qw(
-               -i j-q r-
-       )], 'equivalent pagesize');
+eval { Test::More->VERSION(0.93) } or eval q{
+       diag "Install Test::More v0.93 to run subtests\n";
+       sub subtest {
+               SKIP: { skip 'subtest', 1; }
+       }
 };
 
 };
 
-subtest 'uniform alphanumeric' => sub {
+subtest('single-char alphabet' => sub {
+       plan tests => 5;
+       my @data = ('a'..'z');
+
+       is_deeply(List::Index->new->ranges(\@data), ['-'], 'single page');
+       is_deeply(\@data, ['a'..'z'], 'original data unaltered');
+       is_deeply(
+               List::Index->new({ pages => 3 })->ranges(\@data),
+               [qw(-i j-q r-)],
+               'given pages'
+       );
+       is_deeply(
+               List::Index->new({ pagesize => @data / 2.1 })->ranges(\@data),
+               [qw(-i j-q r-)],
+               'equivalent pagesize'
+       );
+       is_deeply(
+               List::Index->new({ pages => 500 })->ranges(\@data),
+               ['-a', 'b'..'y', 'z-'],
+               'max pages'
+       );
+});
+
+subtest('uniform alphanumeric' => sub {
        plan tests => 2;
        plan tests => 2;
-       my $index = List::Index->new(['aa'..'zz', 1..202]) or return;
-       is_deeply($index->ranges, [qw(
-               -.
-               .-bp bq-dm dn-fi fj-hf hg-i j-k l-m n-os ot-qp qq-sm sn-uj uk-wf wg-x y-
+       my @data = ('aa'..'zz', 1..202);
+       my $index = List::Index->new or return;
 
 
-       )], 'default ranges');
-       is_deeply($index->ranges({pagesize => 300}), [qw(-c d-n o-)], 'large pagesize');
-};
+       is_deeply(
+               $index->ranges(\@data),
+               [qw(
+                       -.. ..-...
+                       ...-bp bq-dm dn-fi fj-hf hg-i j-k l-m n-os ot-qp qq-sm sn-uj uk-wf wg-x y-
+               )],
+               'default ranges'
+       );
+       is_deeply(
+               $index->ranges(\@data, { pagesize => 300 }),
+               [qw(-c d-n o-)],
+               'large pagesize'
+       );
+});
 
 
-subtest 'context' => sub {
+subtest('context' => sub {
        plan tests => 9;
        plan tests => 9;
-       my $index = List::Index->new([qw(
+       my @data = qw(
                kkeg kl km kmlu knsy    koxb kpeo kuaa kuab kuac
                kuapa kuq kur kux kzb   lc lg lgu lgua lguc
                lguq lgur lgus lgx lka  lkq lks lln llq llx
                kkeg kl km kmlu knsy    koxb kpeo kuaa kuab kuac
                kuapa kuq kur kux kzb   lc lg lgu lgua lguc
                lguq lgur lgus lgx lka  lkq lks lln llq llx
-       )]) or return;
+       );
+       my $index = List::Index->new({ pagesize => 10 }) or return;
+
        is_deeply(
        is_deeply(
-               $index->ranges({ pagesize=>10, context=>0, length=>5 }),
+               $index->ranges(\@data, { context => 0, length => 5 }),
                # ranges should match offsets exactly
                [qw(-kuap. kuapa-lgup lguq-)],
                'no context'
        );
        is_deeply(
                # ranges should match offsets exactly
                [qw(-kuap. kuapa-lgup lguq-)],
                'no context'
        );
        is_deeply(
-               $index->ranges({ pagesize=>10, context=>0 }),
+               $index->ranges(\@data, { context => 0 }),
                # default length limits to 4 chars
                [qw(-kuao kuap-lgup lguq-)],
                'default length'
        );
        is_deeply(
                # default length limits to 4 chars
                [qw(-kuao kuap-lgup lguq-)],
                'default length'
        );
        is_deeply(
-               $index->ranges({ pagesize=>10, context=>1 }),
+               $index->ranges(\@data, { context => 1 }),
                # lookbehinds aren't shorter (kuac<kuap, lguc<lguq)
                # 'kuap' can advance to 'kuq'
                [qw(-kup kuq-lgup lguq-)],
                'lookahead'
        );
                # lookbehinds aren't shorter (kuac<kuap, lguc<lguq)
                # 'kuap' can advance to 'kuq'
                [qw(-kup kuq-lgup lguq-)],
                'lookahead'
        );
-TODO: {
-       local $TODO = 'backtrack';
        is_deeply(
        is_deeply(
-               $index->ranges({ pagesize=>10, context=>2 }),
+               $index->ranges(\@data, { context => 2 }),
                # allowed to advance to 'kur', but provides no benefits over 'kuq'
                [qw(-kup kuq-lgup lguq-)],
                'minimal lookahead'
        );
                # allowed to advance to 'kur', but provides no benefits over 'kuq'
                [qw(-kup kuq-lgup lguq-)],
                'minimal lookahead'
        );
-}
        is_deeply(
        is_deeply(
-               $index->ranges({ pagesize=>10, context=>3 }),
+               $index->ranges(\@data, { context => 3 }),
                # shorten 'kuap' to 'ku' because lookbehind is 'kp...'
                # 'lguq' matches 'lg', but may only backtrack to 'lgu'
                [qw(-kt ku-lgt lgu-)],
                'lookbehind'
        );
        is_deeply(
                # shorten 'kuap' to 'ku' because lookbehind is 'kp...'
                # 'lguq' matches 'lg', but may only backtrack to 'lgu'
                [qw(-kt ku-lgt lgu-)],
                'lookbehind'
        );
        is_deeply(
-               $index->ranges({ pagesize=>10, context=>4 }),
+               $index->ranges(\@data, { context => 4 }),
                [qw(-kt ku-lf lg-)],
                'maximal lookahead'
        );
        is_deeply(
                [qw(-kt ku-lf lg-)],
                'maximal lookahead'
        );
        is_deeply(
-               $index->ranges({ pagesize=>10, context=>5 }),
+               $index->ranges(\@data, { context => 5 }),
                # after forwarding 'kuap' to 'lc'
                # disallow backtracking of 'lguq' to 'lc' to prevent qw[-k l-]
                # so only lookahead (to 'lkq') remains
                [qw(-k l-lj lk-)],
                # after forwarding 'kuap' to 'lc'
                # disallow backtracking of 'lguq' to 'lc' to prevent qw[-k l-]
                # so only lookahead (to 'lkq') remains
                [qw(-k l-lj lk-)],
-               'no lookbehind after full lookahead'
+               'lookbehind forbidden'
        );
        is_deeply(
        );
        is_deeply(
-               $index->ranges({ pagesize=>10, context=>9 }),
+               $index->ranges(\@data, { context => 9 }),
                # allow a single (10-9) entry (l-lf = lc) to remain
                [qw(-k l-lf lg-)],
                # allow a single (10-9) entry (l-lf = lc) to remain
                [qw(-k l-lf lg-)],
-               'lookbehind after full lookahead'
+               'lookbehind penalty'
        );
        is_deeply(
        );
        is_deeply(
-               $index->ranges({ pagesize=>10, context=>10 }),
+               $index->ranges(\@data, { context => 10 }),
                # allow the last page to go back upto 'lc', replacing the 2nd page
                [qw(-k l-)],
                'full overlap'
        );
                # allow the last page to go back upto 'lc', replacing the 2nd page
                [qw(-k l-)],
                'full overlap'
        );
-};
+});
+
+subtest('distribution' => sub {
+       plan tests => 2;
+       my @data = qw(
+               gnihka gniub go gsearnrqns gtdvcxyt gw gwoufolwcvmtueyg gysgphci h habkdgifjfxoh
+               hbbvjf hbqleexnqts hccg hd hdoeqwdmgqwaoya hfbegicieuxz hfm hj hkoysmws hmylu
+               hnvtvpievbdlkrmb hs hvdvcqn hvn hyrybeur iaiaab ib ibavqyar idfniqvxpohbk idh
+       );
+       my $index = List::Index->new({ pagesize => 10 }) or return;
+
+       is_deeply(
+               $index->ranges(\@data, { context => 7 }),
+               [qw(-g h i-)],
+               'large context'
+       );
+       is_deeply(
+               $index->ranges(\@data, { context => 6 }),
+               # after 2nd page is enlarged by lookbehind to 'h', limit subsequent lookahead
+               # to prevent the page from getting too large (17 entries if forwarded to 'i')
+               [qw(-g h-hm hn-)],
+               'lookahead penalty'
+       );
+       # page #14 [gn-g] (8): gnihka gniub go gsearnrqns gtdvcxyt gwawkvmueovdjtfj gwoufolwcvmtueyg gysgphci
+       # page #15 [h] (17): h habkdgifjfxoh hbbvjf hbqleexnqts hccgszftbaymfu hdaqzkow hdoeqwdmgqwaoya hfbegicieu hfmlpzzioqjbthz hj hkoysmws hmylu hnvtvpievbdlkrmb hsodfpkatk hvdvcqn hvn hyrybeurqtevjfmi
+       # page #16 [i-ie] (5): i iaab ibiavqyar idfniqvxpohbk idh
+});
+
+subtest('modulo' => sub {
+       plan tests => 2;
+       my @data = qw( a b ccb   ccd  cce gf ggg   ggh  i j );
+       my $index = List::Index->new({ pagesize => 4, context => 0 }) or return;
+       # 10 entries at 4 per page requires 3 pages
+       # so actual target page sizes should be 3,4,3 (not 4,4,2)
+
+       is_deeply(
+               $index->ranges(\@data),
+               [qw(-ccc ccd-ggg ggh-)],
+               'uniform page sizes'
+       );
+       is_deeply(
+               $index->ranges(\@data, { context => 1 }),
+               [qw(-b c-gf gg-)],
+               'context at new intervals'
+       );
+});
+
+subtest('corner cases' => sub {
+       plan tests => 1;
+
+       is_deeply(
+               List::Index->new->ranges(['foo','bar']),
+               ['-'],
+               '2 rows 1 page'
+       );
+});
 
 
-subtest 'context' => sub {
+subtest('context' => sub {
        plan tests => 4;
        plan tests => 4;
-       my $index = List::Index->new([qw(
-               baa1 baa2  baa3 baaa  bbc cbc  daaa ea  eaaa zed
-       )]) or return;
-       is_deeply($index->ranges({pagesize => 2, context => 0}), [
-               qw(-baa. baa.-bbb bbc-daa. daaa-eaa. eaaa-)
-       ], 'no context');
-       is_deeply($index->ranges({pagesize => 2}), [
-               qw(-a b c d e-)
-       ], 'default context');  # context should be 1
-       is_deeply($index->ranges({pagesize => 2, context => 2}), [
-               qw(-a b-c d e-)
-       ], 'overlap');  # first item equals second due to large context
-       is_deeply($index->ranges({pagesize => 2, context => 0, length => 1}), [
-               qw(-a b-c d e-)
-       ], 'single char');
-
-       #pp($index->ranges({pagesize => 2, context => 2, length => 1}));
-};
+       my @data = qw( baa1 baa2  baa3 baaa  bbc cbc  daaa ea  eaaa zed );
+       my $index = List::Index->new({ pagesize => 2 }) or return;
+
+       is_deeply(
+               $index->ranges(\@data, { context => 0 }),
+               [qw(-baa. baa.-bbb bbc-daa. daaa-eaa. eaaa-)],
+               'no context'
+       );
+       is_deeply(
+               $index->ranges(\@data, { context => undef }),
+               [qw(-baa. baa.-b c d e-)],
+               'default context'  # context should be 1
+       );
+       is_deeply(
+               $index->ranges(\@data, { context => 2 }),
+               # first item equals second due to large context
+               [qw(-ba bb-b c d e-)],
+               'overlap'
+       );
+       is_deeply(
+               $index->ranges(\@data, { context => 0, length => 1 }),
+               [qw(-a b-c d e-)],
+               'single char'
+       );
+
+       #pp(List::Index->new({pagesize => 2, context => 2, length => 1}))->ranges(\@data);
+});