App-Rssfilter

 view release on metacpan or  search on metacpan

t/app/rssfilter/rule.t  view on Meta::CPAN

use strict;
use warnings;

use Test::Most;
use App::Rssfilter::Rule;
use List::MoreUtils;
use Mojo::DOM;

{
    package Test::Match;
    sub match {
        my( $item, @patterns ) = @_;
        unshift @patterns, 'match';
        @patterns = map { qr/\Q$_\E/ } @patterns;
        return List::MoreUtils::any { $item->title->text =~ $_ } @patterns;
    }
}

{
    package Test::Filter;
    sub filter {
        my( $item, $condition_name, %replacements ) = @_;
        %replacements = ( filter => 'WAS_FILTERED', %replacements );
        my $item_description = $item->description->text;
        while( my ($k,$v) = each %replacements ) {
            $item_description =~ s/\Q$k\E/$v/xmseg;
        }
        $item->description->replace_content( $item_description );
    }
}

my $rss = Mojo::DOM->new(<<'END_OF_RSS');
<?xml version=1.0">
<rss>
  <channel>
    <title>Test RSS</title>
    <item>
      <title>match this item and filter it</title>
      <description><![CDATA[hi hello filter me please]]></description>
      <pubdate></pubdate>
      <guid>http://example.org/test/1</guid>
    </item>
  </channel>
</rss>
END_OF_RSS

subtest 'passing match & filter as strings referring to locally declared packages', sub {
    my $string_opt_rule = App::Rssfilter::Rule->new( 'Test::Match' => 'Test::Filter' );
    is(
        $string_opt_rule->condition_name,
        'Test::Match',
        'condition_name defaults to condition attr (if a string)'
    );

    my $string_opt_rss = Mojo::DOM->new( $rss );
    my $count = $string_opt_rule->constrain( $string_opt_rss );

    is(
        $string_opt_rss->find( 'item' )->first->description->text,
        'hi hello WAS_FILTERED me please',
        'looks up match & filter when namespace passed as string'
    );

    is(
        $count,
        1,
        'constrain returns the number of items the rule was applied to'
    );
};

subtest 'passing match & filter as strings with additional arguments', sub {
    my $addn_args_rule = App::Rssfilter::Rule->new( 'Test::Match[heyo]' => 'Test::Filter[house,piece]' );

    my $addn_args_rss = Mojo::DOM->new( $rss );
    $addn_args_rss->at('channel')->append(<<'END_OF_ITEM');
<item>
  <title>heyo here's a new item</title>
  <description><![CDATA[holla up in this house]]></description>
  <pubdate></pubdate>
  <guid>http://example.org/test/2</guid>
</item>
END_OF_ITEM

    is(
        $addn_args_rule->condition_name,
        'Test::Match[heyo]',
        'condition_name is set to condition attr (including additional arguments)'
    );

    my $count = $addn_args_rule->constrain( $addn_args_rss );

    is(
        $addn_args_rss->find( 'item' )->[1]->description->text,
        'holla up in this piece',
        'passed additional args were used when matching and filtering'
    );

    is(
        $count,
        2,
        'constrain returns the number of items the rule was applied to'
    );
};

{
    package App::Rssfilter::Match::Everything;
    sub match {
        1;
    }
};

{
    package App::Rssfilter::Filter::MoreCowbell;
    sub filter {
      my( $item, $condition_name ) = @_;
      $item->description->replace_content('cowbell');
    }
}

subtest 'passing match and filter as non-fully qualified strings', sub {
    my $relative_module_rule = App::Rssfilter::Rule->new( 'Everything' => 'MoreCowbell' );

t/app/rssfilter/rule.t  view on Meta::CPAN

};

{
    package Test::Match::OO;
    use Moo;
    sub BUILDARGS {
        my( $self, @addn_args ) = @_;
        return { additional_args => \@addn_args };
    }
    has additional_args => (
        is => 'ro',
    );

    sub match {
        my( $self, $item ) = @_;
        my @patterns = map { qr/\Q$_\E/ } @{ $self->additional_args };
        return List::MoreUtils::any { $item->title->text =~ $_ } @patterns;
    }
}

{
    package Test::Filter::OO;
    use Moo;
    sub BUILDARGS {
        my( $self, @addn_args ) = @_;
        return { additional_args => \@addn_args };
    }
    has additional_args => (
        is => 'ro',
    );

    sub filter {
      my( $self, $item, $condition_name ) = @_;
      my %replacements = ( filter => 'WAS_FILTERED', @{ $self->additional_args } );
      my $item_description = $item->description->text;
      while( my ($k,$v) = each %replacements ) {
          $item_description =~ s/\Q$k\E/$v/xmseg;
      }
      $item->description->replace_content( $item_description );
    }
}

subtest 'passing match and filter as strings to OO modules', sub {
    my $oo_rule = App::Rssfilter::Rule->new( 'Test::Match::OO[just this]' => 'Test::Filter::OO[good cop,bad cop]' );

    my $oo_rss =  Mojo::DOM->new( $rss );
    $oo_rss->at('channel')->append(<<'END_OF_ITEM');
<item>
  <title>oo should match just this item</title>
  <description><![CDATA[good cop on the beat]]></description>
  <pubdate></pubdate>
  <guid>http://example.org/test/4</guid>
</item>
END_OF_ITEM

    my $count = $oo_rule->constrain( $oo_rss );

    is(
        $oo_rss->find( 'item' )->[1]->description->text,
        'bad cop on the beat',
        'looks up match & filter when OO module passed as string, and pass addition args to the ctors'
    );
};

subtest 'passing match and filter as OO instances', sub {
    my $oo_rule = App::Rssfilter::Rule->new(
        condition => Test::Match::OO->new('just this'),
        action    => Test::Filter::OO->new("good cop" => "bad cop" ),
    );

    is(
        $oo_rule->condition_name,
        'Test::Match::OO',
        'condition_name uses class name of passed instance'
    );

    my $oo_rss =  Mojo::DOM->new( $rss );
    $oo_rss->at('channel')->append(<<'END_OF_ITEM');
<item>
  <title>oo should match just this item</title>
  <description><![CDATA[good cop on the beat]]></description>
  <pubdate></pubdate>
  <guid>http://example.org/test/4</guid>
</item>
END_OF_ITEM

    my $count = $oo_rule->constrain( $oo_rss );

    is(
        $oo_rss->find( 'item' )->[1]->description->text,
        'bad cop on the beat',
        'uses objects with match or filter methods'
    );
};

subtest 'passing match and filter as anonymous subs', sub {
    my $anon_sub_rule = App::Rssfilter::Rule->new(
        condition => sub {
          $_[0]->title->text =~ /A[.] [ ] Noni [ ] Mouse/xmsi;
        },
        action    => sub {
          $_[0]->description->replace_content( 'Kilroy was here' );
        },
    );

    is(
        $anon_sub_rule->condition_name,
        'unnamed RSS matcher',
        q{condition_name falls back to default if it can't work out the name of condition attr}
    );

    my $anon_sub_rss =  Mojo::DOM->new( $rss );
    $anon_sub_rss->at('channel')->append(<<'END_OF_ITEM');
<item>
  <title>new art work produced by A. Noni Mouse</title>
  <description><![CDATA[picture goes here]]></description>
  <pubdate></pubdate>
  <guid>http://example.org/test/3</guid>
</item>
END_OF_ITEM



( run in 0.595 second using v1.01-cache-2.11-cpan-39bf76dae61 )