File: 12-systemsafe-errors.t

package info (click to toggle)
libtest-trap-perl 0.2.4-1
  • links: PTS, VCS
  • area: main
  • in suites: jessie, jessie-kfreebsd
  • size: 264 kB
  • ctags: 54
  • sloc: perl: 2,315; makefile: 2
file content (142 lines) | stat: -rw-r--r-- 4,783 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
#!perl -T
# -*- mode: cperl ; compile-command: "cd .. ; ./Build ; prove -vb t/12-*.t" -*-

BEGIN { $_ = defined && /(.*)/ && $1 for @ENV{qw/ TMPDIR TEMP TMP /} } # taint vs tempfile
use Test::More tests => 10;
use strict;
use warnings;

# A whole lot simpler testing -- we're now just checking that all the
# error situations are caught and behave sensibly.  Okay, it's not
# that simple -- just simpler than the implementation ...

my $errnum = 11; # "Resource temporarily unavailable" locally -- sounds good :-P
my $errstring = do { local $! = $errnum; "$!" };

{
  my $fileno = fileno STDIN;
  die "STDIN not on fd 0"
    unless defined $fileno and $fileno == 0;
};

our ($when_to_fail, $when_to_persist);
my ($glob, $mode, @what);
BEGIN {
  # make the open calls in SystemSafe.pm fail or just fdopen STDIN in
  # different situations:
  *Test::Trap::Builder::SystemSafe::open = # silence warnings
  *Test::Trap::Builder::SystemSafe::open = sub (*;$@) {
    ($glob, $mode, @what) = @_;
    unless (@what) {
      ($mode, @what) = $mode =~ /^([>&=]*)\s*(.*)/s;
    }
    if ($when_to_persist and $when_to_persist->()) {
      eval { open $_[0], '<&=STDIN' } or CORE::exit diag "Cannot fdopen STDIN; STDIN fd: ". fileno STDIN;
      for (fileno $_[0]) {
	defined or CORE::exit diag "fdopen STDIN gives undefined fd";
	$_ == 0 or CORE::exit diag "fdopen STDIN gives fd $_";
      }
      return 1;
    }
    if ($when_to_fail and $when_to_fail->()) {
      $! = $errnum;
      return;
    }
    my $return;
    if (@_ > 2) {
      $return = open $_[0], $_[1], @_[2..$#_];
    }
    elsif (defined $_[0]){
      $return = open $_[0], $_[1];
    }
    else {
      $return = open my $fh, $_[1];
      $_[0] = $fh;
    }
    return $return;
  };
}

use Test::Trap::Builder::SystemSafe;
use Test::Trap qw( trap $T :flow:stderr(systemsafe):stdout(systemsafe):warn );
use Test::Trap qw( protect $P );

SKIP: {
  skip 'These tests are broken on old perls', 3 if $] < 5.008;

  protect { # return fd 0 again and again on appending
    local $when_to_persist = sub { $mode eq '>>' };
    eval { trap { 1 } };
    like( $@, qr/^\QGetting several files opened on fileno 0 at ${\__FILE__}/, 'Persisting on STDIN' );
  };

  protect { # return fd 0 once(!) on appending
    my $count = 1;
    local $when_to_persist = sub { $mode eq '>>' and !--$count };
    eval { trap { 1 } };
    like( $@, qr/^Getting fileno \d+; \Qexpecting 0 at ${\__FILE__}/, "Mixed-up filenos" );
  };

  protect { # return fd 0 once(!) on appending -- then fail!
    my $count = 1;
    local $when_to_persist = sub { $mode eq '>>' and !--$count };
    local $when_to_fail = sub { $mode eq '>>' and $count == -1 };
    eval { trap { 1 } };
    like( $@, qr/^Cannot open \S+ \Qfor stdout: '$errstring' at ${\__FILE__}/, 'Delayed append to tempfile' );
  };
}

protect { # fail on the first dup() -- stdout, coming in
  my $count = 1;
  local $when_to_fail = sub { $mode eq '>&' and !--$count };
  eval { trap { 1 } };
  like( $@, qr/^Cannot dup '\d+' \Qfor stdout: '$errstring' at ${\__FILE__}/, 'First dup() -- setting up STDOUT' );
};

protect { # fail on the second dup() -- stderr, coming in
  my $count = 2;
  local $when_to_fail = sub { $mode eq '>&' and !--$count }; # second dup()
  eval { trap { 1 } };
  like( $@, qr/^Cannot dup '\d+' \Qfor stderr: '$errstring' at ${\__FILE__}/, 'Second dup() -- setting up STDERR' );
};

protect { # fail on the third dup() -- stderr, going out
  my $count = 3;
  local $when_to_fail = sub { $mode eq '>&' and !--$count };
  eval { trap { 1 } };
  like( $@, qr/^Cannot dup '\d+' \Qfor stderr: '$errstring' at ${\__FILE__}/, 'Third dup() -- restoring STDERR' );
};

protect { # fourth dup() -- stdout, going out
  my $count = 4;
  local $when_to_fail = sub { $mode eq '>&' and !--$count };
  eval { trap { 1 } };
  like( $@, qr/^Cannot dup '\d+' \Qfor stdout: '$errstring' at ${\__FILE__}/, 'Fourth dup() -- restoring STDOUT' );
};

protect { # fail on first opening the stderr tempfile for append
  my $count = 1;
  local $when_to_fail = sub { $mode eq '>>' and !--$count };
  eval { trap { 1 } };
  like( $@, qr/^Cannot open \S+ \Qfor stdout: '$errstring' at ${\__FILE__}/, 'First append to tempfile' );
};

SKIP: {
  protect {
    skip 'Need PerlIO', 1 unless eval 'use PerlIO; 1';
    local *STDOUT;
    open STDOUT, '>', \ my $buffer;
    eval { trap { 1 } };
    like( $@, qr/^\QSystemSafe only works with real file descriptors; aborting at ${\__FILE__}/, 'Negative fileno' );
  };
}

SKIP: {
  protect {
    skip 'Need IO::Scalar', 1 unless eval 'use IO::Scalar; 1';
    local *STDOUT;
    tie *STDOUT, 'IO::Scalar', \my $s;
    eval { trap { 1 } };
    like( $@, qr/^\QSystemSafe only works with real file descriptors; aborting at ${\__FILE__}/, 'Tied handle' );
  };
}