1use strict;
2use warnings;
3use Test2::Tools::Defer;
4# HARNESS-NO-FORK
5
6my $file = __FILE__;
7
8my $START_LINE;
9BEGIN {
10    $START_LINE = __LINE__;
11    def ok => (1, "truth");
12    def is => (1, 1, "1 is 1");
13    def is => ({}, {}, "hash is hash");
14
15    def ok => (0, 'lies');
16    def is => (0, 1, "1 is not 0");
17    def is => ({}, [], "a hash is not an array");
18}
19
20use Test2::Bundle::Extended -target => 'Test2::Tools::Defer';
21
22sub capture(&) {
23    my $code = shift;
24
25    my ($err, $out) = ("", "");
26
27    my ($ok, $e);
28    {
29        local *STDOUT;
30        local *STDERR;
31
32        ($ok, $e) = Test2::Util::try(sub {
33            open(STDOUT, '>', \$out) or die "Failed to open a temporary STDOUT: $!";
34            open(STDERR, '>', \$err) or die "Failed to open a temporary STDERR: $!";
35
36            $code->();
37        });
38    }
39
40    die $e unless $ok;
41
42    return {
43        STDOUT => $out,
44        STDERR => $err,
45    };
46}
47
48is(
49    intercept { do_def },
50    array {
51        filter_items { grep { $_->isa('Test2::Event::Ok') || $_->isa('Test2::Event::Fail') } @_ };
52
53        event Ok => sub {
54            call pass => 1;
55            call name => 'truth';
56            prop file => "(eval in Test2::Tools::Defer) " . __FILE__;
57            prop line => $START_LINE + 1;
58            prop package => __PACKAGE__;
59        };
60
61        event Ok => sub {
62            call pass => 1;
63            call name => '1 is 1';
64            prop file => "(eval in Test2::Tools::Defer) " . __FILE__;
65            prop line => $START_LINE + 2;
66            prop package => __PACKAGE__;
67        };
68
69        event Ok => sub {
70            call pass => 1;
71            call name => 'hash is hash';
72            prop file => "(eval in Test2::Tools::Defer) " . __FILE__;
73            prop line => $START_LINE + 3;
74            prop package => __PACKAGE__;
75        };
76
77        event Ok => sub {
78            call pass => 0;
79            call name => 'lies';
80            prop file => "(eval in Test2::Tools::Defer) " . __FILE__;
81            prop line => $START_LINE + 5;
82            prop package => __PACKAGE__;
83        };
84
85        event Fail => sub {
86            call name => '1 is not 0';
87            prop file => "(eval in Test2::Tools::Defer) " . __FILE__;
88            prop line => $START_LINE + 6;
89            prop package => __PACKAGE__;
90        };
91
92        event Fail => sub {
93            call name => 'a hash is not an array';
94            prop file => "(eval in Test2::Tools::Defer) " . __FILE__;
95            prop line => $START_LINE + 7;
96            prop package => __PACKAGE__;
97        };
98
99        end;
100    },
101    "got expected events"
102);
103
104def ok => (1, "truth");
105def is => (1, 1, "1 is 1");
106def is => ({}, {}, "hash is hash");
107
108# Actually run some that pass
109do_def();
110
111like(
112    dies { do_def() },
113    qr/No tests to run/,
114    "Fails if there are no tests"
115);
116
117my $line1 = __LINE__ + 1;
118sub oops { die 'oops' }
119
120my $line2 = __LINE__ + 1;
121def oops => (1);
122like( dies { do_def() }, <<EOT, "Exceptions in the test are propogated");
123Exception: oops at $file line $line1.
124--eval--
125package main;
126# line $line2 "(eval in Test2::Tools::Defer) $file"
127&oops(\@\$args);
1281;
129--------
130Tool:   oops
131Caller: main, $file, $line2
132\$args:  [
133          1
134        ];
135EOT
136
137
138{
139    {
140        package Foo;
141        main::def ok => (1, "pass");
142    }
143    def ok => (1, "pass");
144
145    my $new_exit = 0;
146    my $out = capture { Test2::Tools::Defer::_verify(undef, 0, \$new_exit) };
147
148    is($new_exit, 255, "exit set to 255 due to unrun tests");
149    like(
150        $out->{STDOUT},
151        qr/not ok - deferred tests were not run/,
152        "Got failed STDOUT line"
153    );
154
155    like(
156        $out->{STDERR},
157        qr/# 'main' has deferred tests that were never run/,
158        "We see that main failed"
159    );
160
161    like(
162        $out->{STDERR},
163        qr/# 'Foo' has deferred tests that were never run/,
164        "We see that Foo failed"
165    );
166}
167
168{
169    local $? = 101;
170    def ok => (1, "pass");
171    my $out = capture { Test2::Tools::Defer::_verify() };
172    is($?, 101, "did not change exit code");
173    like(
174        $out->{STDOUT},
175        qr/not ok - deferred tests were not run/,
176        "Got failed STDOUT line"
177    );
178
179    like(
180        $out->{STDERR},
181        qr/# 'main' has deferred tests that were never run/,
182        "We see that main failed"
183    );
184}
185
186done_testing;
187