]> git.vpit.fr Git - perl/modules/VPIT-TestHelpers.git/blob - lib/VPIT/TestHelpers.pm
68f11f0092e8b89cee24aa1e8bcb1473d39c79b9
[perl/modules/VPIT-TestHelpers.git] / lib / VPIT / TestHelpers.pm
1 package VPIT::TestHelpers;
2
3 use strict;
4 use warnings;
5
6 use Config ();
7
8 sub export_to_pkg {
9  my ($subs, $pkg) = @_;
10
11  while (my ($name, $code) = each %$subs) {
12   no strict 'refs';
13   *{$pkg.'::'.$name} = $code;
14  }
15
16  return 1;
17 }
18
19 my %default_exports = (
20  load_or_skip     => \&load_or_skip,
21  load_or_skip_all => \&load_or_skip_all,
22  run_perl         => \&run_perl,
23  skip_all         => \&skip_all,
24 );
25
26 my %features = (
27  usleep => \&init_usleep,
28 );
29
30 sub import {
31  shift;
32  my @opts = @_;
33
34  my %exports = %default_exports;
35
36  for (my $i = 0; $i <= $#opts; ++$i) {
37   my $feature = $opts[$i];
38   next unless defined $feature;
39
40   my $args;
41   if ($i < $#opts and defined $opts[$i+1] and ref $opts[$i+1] eq 'ARRAY') {
42    ++$i;
43    $args = $opts[$i];
44   } else {
45    $args = [ ];
46   }
47
48   my $handler = $features{$feature};
49   die "Unknown feature '$feature'" unless defined $handler;
50
51   my %syms = $handler->(@$args);
52
53   $exports{$_} = $syms{$_} for sort keys %syms;
54  }
55
56  export_to_pkg \%exports => scalar caller;
57 }
58
59 my $test_sub = sub {
60  my $sub = shift;
61
62  my $stash;
63  if ($INC{'Test/Leaner.pm'}) {
64   $stash = \%Test::Leaner::;
65  } else {
66   require Test::More;
67   $stash = \%Test::More::;
68  }
69
70  my $glob = $stash->{$sub};
71  return $glob ? *$glob{CODE} : undef;
72 };
73
74 sub skip { $test_sub->('skip')->(@_) }
75
76 sub skip_all { $test_sub->('plan')->(skip_all => $_[0]) }
77
78 sub diag {
79  my $diag = $test_sub->('diag');
80  $diag->($_) for @_;
81 }
82
83 our $TODO;
84 local $TODO;
85
86 sub load {
87  my ($pkg, $ver, $imports) = @_;
88
89  my $spec = $ver && $ver !~ /^[0._]*$/ ? "$pkg $ver" : $pkg;
90  my $err;
91
92  local $@;
93  if (eval "use $spec (); 1") {
94   $ver = do { no strict 'refs'; ${"${pkg}::VERSION"} };
95   $ver = 'undef' unless defined $ver;
96
97   if ($imports) {
98    my @imports = @$imports;
99    my $caller  = (caller 1)[0];
100    local $@;
101    my $res = eval <<"IMPORTER";
102 package
103         $caller;
104 BEGIN { \$pkg->import(\@imports) }
105 1;
106 IMPORTER
107    $err = "Could not import '@imports' from $pkg $ver: $@" unless $res;
108   }
109  } else {
110   (my $file = "$pkg.pm") =~ s{::}{/}g;
111   delete $INC{$file};
112   $err = "Could not load $spec";
113  }
114
115  if ($err) {
116   return wantarray ? (0, $err) : 0;
117  } else {
118   diag "Using $pkg $ver";
119   return 1;
120  }
121 }
122
123 sub load_or_skip {
124  my ($pkg, $ver, $imports, $tests) = @_;
125
126  die 'You must specify how many tests to skip' unless defined $tests;
127
128  my ($loaded, $err) = load($pkg, $ver, $imports);
129  skip $err => $tests unless $loaded;
130
131  return $loaded;
132 }
133
134 sub load_or_skip_all {
135  my ($pkg, $ver, $imports) = @_;
136
137  my ($loaded, $err) = load($pkg, $ver, $imports);
138  skip_all $err unless $loaded;
139
140  return $loaded;
141 }
142
143 sub run_perl {
144  my $code = shift;
145
146  my ($SystemRoot, $PATH) = @ENV{qw<SystemRoot PATH>};
147  my $ld_name  = $Config::Config{ldlibpthname};
148  my $ldlibpth = $ENV{$ld_name};
149
150  local %ENV;
151  $ENV{$ld_name}   = $ldlibpth   if                      defined $ldlibpth;
152  $ENV{SystemRoot} = $SystemRoot if $^O eq 'MSWin32' and defined $SystemRoot;
153  $ENV{PATH}       = $PATH       if $^O eq 'cygwin'  and defined $PATH;
154
155  system { $^X } $^X, '-T', map("-I$_", @INC), '-e', $code;
156 }
157
158 sub init_usleep {
159  my $usleep;
160
161  if (do { local $@; eval { require Time::HiRes; 1 } }) {
162   defined and diag "Using usleep() from Time::HiRes $_"
163                                                       for $Time::HiRes::VERSION;
164   $usleep = \&Time::HiRes::usleep;
165  } else {
166   diag 'Using fallback usleep()';
167   $usleep = sub {
168    my $s = int($_[0] / 2.5e5);
169    sleep $s if $s;
170   };
171  }
172
173  return usleep => $usleep;
174 }
175
176 package VPIT::TestHelpers::Guard;
177
178 sub new {
179  my ($class, $code) = @_;
180
181  bless { code => $code }, $class;
182 }
183
184 sub DESTROY { $_[0]->{code}->() }
185
186 1;