1#!/usr/local/bin/perl
2#
3# Run tv_split on some input files and check the output looks
4# reasonable.  This is not done by diffing against expected output but
5# by reading the files generated and making sure channels and dates
6# seem to match.
7#
8# -- Ed Avis, ed@membled.com, 2003-10-04
9# $Id: test_tv_split.t,v 1.8 2015/07/12 00:46:37 knowledgejunkie Exp $
10#
11
12use warnings;
13use strict;
14use Getopt::Long;
15use Cwd;
16use File::Temp qw(tempdir);
17use File::Copy;
18use XMLTV::Usage <<END
19$0: test suite for tv_split
20usage: $0 [--tests-dir DIR] [--verbose]
21END
22  ;
23
24my $tests_dir = 't/data'; # where to find input XML files
25die "no directory $tests_dir" if not -d $tests_dir;
26my $cmds_dir = 'blib/script'; # directory tv_split lives in
27die "no directory $cmds_dir" if not -d $cmds_dir;
28my $verbose = 0;
29
30GetOptions('tests-dir=s' => \$tests_dir, 'cmds-dir=s' => \$cmds_dir,
31	   'verbose' => \$verbose)
32  or usage(0);
33usage(0) if @ARGV;
34
35my @inputs = <$tests_dir/*.xml>;
36my @inputs_gz = <$tests_dir/*.xml.gz>; s/\.gz$// foreach @inputs_gz;
37@inputs = sort (@inputs, @inputs_gz);
38die "no test cases (*.xml, *.xml.gz) found in $tests_dir"
39  if not @inputs;
40
41print '1..', (scalar @inputs), "\n";
42my $n = 0;
43my $old_cwd;
44INPUT: foreach my $input (@inputs) {
45    ++$n;
46
47    if (defined $old_cwd) {
48	chdir $old_cwd or die "cannot chdir to $old_cwd: $!";
49    }
50    else {
51	$old_cwd = cwd;
52    }
53
54    # Quick and dirty checking of XML files.  Before we start, read
55    # the input XML and note how many programmes of each kind.
56    #
57    my %input;
58    open(FH, $input) or die "cannot open $input: $!";
59    while (<FH>) {
60	next unless /<programme/;
61
62	/start="(.+?)"/ or die "$input:$.: no start\n";
63	my $start = $1;
64	$start =~ /^\d{4}(\d{2})/
65	  or die "$input:$.: don't understand start time $start\n";
66	my $month = $1;
67
68	/channel="(.+?)"/ or die "$input:$.: no channel\n";
69	my $channel = $1;
70	++$input{"channel$channel-month$month"};
71    }
72    close FH or warn "cannot close $input: $!";
73
74    # Make temporary directory and split into it.
75    my $dir = tempdir(CLEANUP => 1);
76    die if not -d $dir;
77    die 'gzipped files not supported (could add)'
78      if $input =~ /[.]gz$/;
79    my @cmd = ("$cmds_dir/tv_split",
80	       '--output', "$dir/channel%channel%-month%m.out",
81	       $input);
82    my $r = system @cmd;
83
84    # Check command return status.
85    if ($r) {
86	my ($status, $sig, $core) = ($? >> 8, $? & 127, $? & 128);
87	if ($sig) {
88	    die "@cmd killed by signal $sig, aborting";
89	}
90	warn "@cmd failed: $status, $sig, $core\n";
91	print "not ok $n\n";
92	next;
93    }
94
95    # Read the files generated.
96    chdir $dir or die "cannot chdir to $dir: $!";
97    my %found;
98    foreach my $f (<*.out>) {
99	open(FH, $f) or die "cannot open $f: $!";
100	(my $template = $f) =~ s/[.]out$// or die;
101	my (%seen_channel_elem, %used_channel);
102	while (<FH>) {
103	    if (/<channel/) {
104		/id="(.+?)"/ or die "$f:$.: no id\n";
105		$seen_channel_elem{$1} = 1;
106	    }
107	    elsif (/<programme/) {
108		/start="(.+?)"/ or die "$f:$.: no start\n";
109		my $start = $1;
110		$start =~ /^\d{4}(\d{2})/
111		  or die "$f:$.: don't understand start time $start\n";
112		my $month = $1;
113
114		/channel="(.+?)"/ or die "$f:$.: no channel\n";
115		my $channel = $1;
116		$used_channel{$channel} = 1;
117
118		if ("channel$channel-month$month" ne $template) {
119		    warn "in $f saw what should be channel$channel-month$month\n";
120		    print "not ok $n\n";
121		    next INPUT;
122		}
123
124		++$found{$template};
125	    }
126	}
127	close FH or warn "cannot close $f: $!";
128
129	# We don't check that every channel used has a <channel>
130	# element (it might not have been in the input files) but we
131	# do check that every <channel> written is used for at least
132	# one programme.
133	#
134	# (We shouldn't do this if tv_split has not been asked to
135	# split by channel, but at present all the tests we run do
136	# have %channel.)
137	#
138	foreach (sort keys %seen_channel_elem) {
139	    if (not $used_channel{$_}) {
140		warn "in $f saw <channel> for $_ but it's used for no programmes\n";
141		print "not ok $n\n";
142		next INPUT;
143	    }
144	}
145    }
146
147
148    # We've read each output file and checked the programmes it does
149    # contain have the right times; now check that every programme in
150    # the input has been given to an output file.
151    #
152    # (We don't check the contents of the programme elements or other
153    # details of the XML - we assume that if XMLTV.pm had a serious
154    # bug it would have been caught in the tests of other filter
155    # programs.)
156    #
157    foreach (keys %input) {
158	if ($input{$_} != $found{$_}) {
159	    warn "different number of programmes for template $_\n";
160	    print "not ok $n\n";
161	    next INPUT;
162	}
163    }
164    foreach (keys %found) {
165	if (not exists $input{$_}) {
166	    warn "generated template $_ not in input\n";
167	    print "not ok $n\n";
168	    next INPUT;
169	}
170    }
171
172    print "ok $n\n";
173}
174
175