File Coverage

blib/lib/POE/Test/Loops.pm
Criterion Covered Total %
statement 33 127 25.9
branch 0 50 0.0
condition 0 9 0.0
subroutine 11 14 78.5
pod 1 1 100.0
total 45 201 22.3


line stmt bran cond sub pod time code
1             # vim: ts=2 sw=2 expandtab
2              
3             package POE::Test::Loops;
4             $POE::Test::Loops::VERSION = '1.360';
5 1     1   514 use warnings;
  1         1  
  1         34  
6 1     1   4 use strict;
  1         2  
  1         25  
7              
8 1     1   3 use File::Spec;
  1         1  
  1         23  
9 1     1   3 use File::Path;
  1         1  
  1         50  
10 1     1   3 use File::Find;
  1         2  
  1         44  
11              
12 1     1   3 use constant TEST_BLOCK_FOR_WHICH => 0x01;
  1         2  
  1         43  
13 1     1   3 use constant TEST_BLOCK_FOR_WRONG => 0x02;
  1         1  
  1         36  
14 1     1   4 use constant TEST_BLOCK_FOR_RIGHT => 0x04;
  1         1  
  1         31  
15 1     1   3 use constant TEST_BLOCK_BEGIN => 0x08;
  1         2  
  1         35  
16              
17             ### Find the test libraries.
18              
19 1     1   426 use lib qw(./lib ../lib);
  1         481  
  1         3  
20 1     1   412 use POE::Test::DondeEstan;
  1         2  
  1         1042  
21             my $source_base = POE::Test::DondeEstan->marco();
22              
23             ### Generate loop tests.
24              
25             sub generate {
26 0     0 1   my ($dir_base, $loops, $flag_verbose) = @_;
27              
28 0           foreach my $loop (@$loops) {
29 0           my $loop_dir = lc($loop);
30 0           $loop_dir =~ s/::/_/g;
31              
32 0           my $fqmn = _find_event_loop_file($loop);
33 0 0         unless ($fqmn) {
34 0 0         $flag_verbose and print "Couldn't find a loop for $loop ...\n";
35 0           next;
36             }
37              
38 0 0         $flag_verbose and print "Found $fqmn\n";
39              
40 0           my $loop_cfg = _get_loop_cfg($fqmn);
41 0 0 0       unless (defined $loop_cfg and length $loop_cfg) {
42 0           $loop_cfg = (
43             "sub skip_tests { return }"
44             );
45             }
46              
47 0           my $source = (
48             "#!/usr/bin/perl -w\n" .
49             "\n" .
50             "use strict;\n" .
51             "\n" .
52             "use lib qw(--base_lib--);\n" .
53             "use Test::More;\n" .
54             "use POSIX qw(_exit);\n" .
55             "\n" .
56             "--loop_cfg--\n" .
57             "\n" .
58             "BEGIN {\n" .
59             " if (my \$why = skip_tests('--test_name--')) {\n" .
60             " plan skip_all => \$why\n" .
61             " }\n" .
62             "}\n" .
63             "\n" .
64             "# Run the tests themselves.\n" .
65             "require '--base_file--';\n" .
66             "\n" .
67             "_exit 0 if \$^O eq 'MSWin32';\n" .
68             "CORE::exit 0;\n"
69             );
70              
71             # Full directory where source files are found.
72              
73 0           my $dir_src = File::Spec->catfile($source_base, "Loops");
74 0           my $dir_dst = File::Spec->catfile($dir_base, $loop_dir);
75              
76             # Gather the list of source files.
77             # Each will be used to generate a real test file.
78              
79 0 0         opendir BASE, $dir_src or die $!;
80 0           my @base_files = grep /\.pm$/, readdir(BASE);
81 0           closedir BASE;
82              
83             # Initialize the destination directory. Clear or create as needed.
84              
85 0           $dir_dst =~ tr[/][/]s;
86 0           $dir_dst =~ s{/+$}{};
87              
88 0           rmtree($dir_dst);
89 0           mkpath($dir_dst, 0, 0755);
90              
91             # For each source file, generate a corresponding one in the
92             # configured destination directory. Expand various bits to
93             # customize the test.
94              
95 0           foreach my $base_file (@base_files) {
96 0           my $test_name = $base_file;
97 0           $test_name =~ s/\.pm$//;
98              
99 0           my $full_file = File::Spec->catfile($dir_dst, $base_file);
100 0           $full_file =~ s/\.pm$/.t/;
101              
102             # These hardcoded expansions are for the base file to be required,
103             # and the base library directory where it'll be found.
104              
105 0           my $expanded_src = $source;
106 0           $expanded_src =~ s/--base_file--/$base_file/g;
107 0           $expanded_src =~ s/--base_lib--/$dir_src/g;
108 0           $expanded_src =~ s/--loop_cfg--/$loop_cfg/g;
109 0           $expanded_src =~ s/--test_name--/$test_name/g;
110              
111             # Write with lots of error checking.
112              
113 0 0         open EXPANDED, ">$full_file" or die $!;
114 0           print EXPANDED $expanded_src;
115 0 0         close EXPANDED or die $!;
116             }
117             }
118             }
119              
120             sub _find_event_loop_file {
121 0     0     my $loop_name = shift;
122              
123 0           my $loop_module;
124 0 0         if ($loop_name =~ /^POE::/) {
125 0           $loop_module = File::Spec->catfile(split(/::/, $loop_name)) . ".pm";
126             }
127             else {
128 0           $loop_name =~ s/::/_/g;
129 0           $loop_module = File::Spec->catfile("POE", "Loop", $loop_name) . ".pm";
130             }
131              
132 0           foreach my $inc (@INC) {
133 0           my $fqmn = File::Spec->catfile($inc, $loop_module);
134 0 0         next unless -f $fqmn;
135 0           return $fqmn;
136             }
137              
138 0           return;
139             }
140              
141             sub _get_loop_cfg {
142 0     0     my $fqmn = shift;
143              
144 0           my ($in_test_block, @test_source);
145              
146 0 0         open SOURCE, "<$fqmn" or die $!;
147 0           while () {
148             # Not in a test block.
149 0 0         unless ($in_test_block) {
150              
151             # Proper =for syntax.
152 0 0         if (/^=for\s+poe_tests\s+(\S.*?)$/) {
153 0           push @test_source, $1;
154 0           $in_test_block = TEST_BLOCK_FOR_RIGHT;
155 0           next;
156             }
157              
158             # Not sure which =for syntax is in use.
159 0 0         if (/^=for\s+poe_tests\s*$/) {
160 0           $in_test_block = TEST_BLOCK_FOR_WHICH;
161 0           next;
162             }
163              
164 0 0         if (/^=begin\s+(poe_tests)\s*$/) {
165 0           $in_test_block = TEST_BLOCK_BEGIN;
166 0           next;
167             }
168              
169             # Some random line. Do nothing.
170 0           next;
171             }
172              
173             # Which test block format are we in?
174 0 0         if ($in_test_block & TEST_BLOCK_FOR_WHICH) {
175             # If the following line is blank, then we're probably in the
176             # wrong, multi-line kind originally documented and now
177             # deprecated.
178 0 0         if (/^\s*$/) {
179 0           $in_test_block = TEST_BLOCK_FOR_WRONG;
180 0           next;
181             }
182              
183             # The following line is not blank, so it appears we're in a
184             # properly formatted =for paragraph.
185 0           $in_test_block = TEST_BLOCK_FOR_RIGHT;
186 0           push @test_source, $_;
187 0           next;
188             }
189              
190             # The =begin syntax ends with an =end.
191 0 0         if ($in_test_block & TEST_BLOCK_BEGIN) {
192 0 0         if (/^=end\s*poe_tests\s*$/) {
193 0           $in_test_block = 0;
194 0           next;
195             }
196              
197             # Be helpful?
198 0 0         die "=cut not the proper way to end =begin poe_tests" if /^=cut\s*$/;
199              
200 0           push @test_source, $_;
201 0           next;
202             }
203              
204             # The proper =for syntax ends on a blank line.
205 0 0         if ($in_test_block & TEST_BLOCK_FOR_RIGHT) {
206 0 0         if (/^$/) {
207 0           $in_test_block = 0;
208 0           next;
209             }
210              
211             # Be helpful?
212 0 0         die "=cut not the proper way to end =for poe_tests" if /^=cut\s*$/;
213              
214 0           push @test_source, $_;
215 0           next;
216             }
217              
218             # The wrong =for syntax ends on =cut.
219 0 0         if ($in_test_block & TEST_BLOCK_FOR_WRONG) {
220 0 0         if (/^=cut\s*$/) {
221 0           $in_test_block = 0;
222 0           next;
223             }
224              
225             # Be helpful?
226 0 0         die "=end not the proper way to end =for poe_tests" if /^=end/;
227              
228 0           push @test_source, $_;
229 0           next;
230             }
231              
232 0           die "parser in unknown state: $in_test_block";
233             }
234              
235 0   0       shift @test_source while @test_source and $test_source[0] =~ /^\s*$/;
236 0   0       pop @test_source while @test_source and $test_source[-1] =~ /^\s*$/;
237              
238 0           return join "", @test_source;
239             }
240              
241             1;
242              
243             __END__