Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 104 additions & 1 deletion t/unit/Test2/Harness/Collector.t
Original file line number Diff line number Diff line change
@@ -1,5 +1,108 @@
use Test2::V0 -target => 'Test2::Harness::Collector';

skip_all "write me";
my $CLASS = CLASS();

subtest 'can be loaded' => sub {
ok($CLASS, "CLASS() returns the package name");
ok($CLASS->isa('Test2::Harness::Collector'), "is correct class");
};

subtest 'has expected accessor methods' => sub {
for my $method (qw/
run_id job_id job_try
parser output
workdir tempdir
run job
interactive always_flush
merge_outputs encoding
/) {
ok($CLASS->can($method), "has '$method' accessor/method");
}
};

subtest 'constructor requires parser' => sub {
like(
dies { $CLASS->new(output => sub {}) },
qr/parser.*required/i,
"missing parser dies"
);
};

subtest 'constructor requires output' => sub {
my $dummy_parser = bless {}, 'Test2::Harness::Collector::IOParser';
like(
dies { $CLASS->new(parser => $dummy_parser) },
qr/output.*required/i,
"missing output dies"
);
};

subtest 'constructor with coderef output' => sub {
my $dummy_parser = bless {}, 'Test2::Harness::Collector::IOParser';
my @received;
my $obj = $CLASS->new(
parser => $dummy_parser,
output => sub { push @received, @_ },
);
ok($obj, "object created with coderef output");
ok($obj->can('output_cb') ? $obj->output_cb : $obj->can('_output_cb'), "output_cb is set");
};

subtest 'constructor with GLOB output' => sub {
my $dummy_parser = bless {}, 'Test2::Harness::Collector::IOParser';
open(my $fh, '>', \my $buf) or die "Cannot open string ref: $!";
my $obj = $CLASS->new(
parser => $dummy_parser,
output => $fh,
);
ok($obj, "object created with GLOB output");
};

subtest 'constructor with unknown output type dies' => sub {
my $dummy_parser = bless {}, 'Test2::Harness::Collector::IOParser';
like(
dies { $CLASS->new(parser => $dummy_parser, output => "not a valid type") },
qr/Unknown output type/i,
"unknown output type dies"
);
};

subtest 'default field values after construction' => sub {
my $dummy_parser = bless {}, 'Test2::Harness::Collector::IOParser';
my $obj = $CLASS->new(
parser => $dummy_parser,
output => sub {},
);
is($obj->run_id, 0, "run_id defaults to 0");
is($obj->job_id, 0, "job_id defaults to 0");
is($obj->job_try, 0, "job_try defaults to 0");
ok(!$obj->merge_outputs, "merge_outputs defaults to false");
};

subtest 'handles set up during construction' => sub {
my $dummy_parser = bless {}, 'Test2::Harness::Collector::IOParser';
my $obj = $CLASS->new(
parser => $dummy_parser,
output => sub {},
);
my $handles = $obj->handles;
ok(ref($handles) eq 'HASH', "handles is a hash ref");
ok($handles->{out_r}, "out_r handle set");
ok($handles->{out_w}, "out_w handle set");
ok($handles->{err_r}, "err_r handle set");
ok($handles->{err_w}, "err_w handle set");
};

subtest 'merge_outputs shares out/err handles' => sub {
my $dummy_parser = bless {}, 'Test2::Harness::Collector::IOParser';
my $obj = $CLASS->new(
parser => $dummy_parser,
output => sub {},
merge_outputs => 1,
);
my $handles = $obj->handles;
is($handles->{out_r}, $handles->{err_r}, "out_r and err_r are same when merging");
is($handles->{out_w}, $handles->{err_w}, "out_w and err_w are same when merging");
};

done_testing;
55 changes: 54 additions & 1 deletion t/unit/Test2/Harness/Collector/Auditor.t
Original file line number Diff line number Diff line change
@@ -1,5 +1,58 @@
use Test2::V0 -target => 'Test2::Harness::Collector::Auditor';

skip_all "write me";
subtest 'can be loaded' => sub {
ok(CLASS(), "CLASS() returns the package name");
ok(CLASS()->isa('Test2::Harness::Collector::Auditor'), "is correct class");
};

subtest 'init is a no-op on base class' => sub {
my $obj = CLASS()->new();
ok($obj, "object created via new()");
};

subtest 'abstract methods die on base class' => sub {
my $obj = bless {}, CLASS();

like(
dies { $obj->audit() },
qr/does not implement audit/,
"audit() is abstract"
);

like(
dies { $obj->pass() },
qr/does not implement pass/,
"pass() is abstract"
);

like(
dies { $obj->fail() },
qr/does not implement fail/,
"fail() is abstract"
);

like(
dies { $obj->has_exit() },
qr/does not implement has_exit/,
"has_exit() is abstract"
);

like(
dies { $obj->has_plan() },
qr/does not implement has_plan/,
"has_plan() is abstract"
);
};

subtest 'error messages mention the method name' => sub {
my $obj = bless {}, CLASS();

my $err = dies { $obj->audit() };
ok($err, "got an error");
like($err, qr/does not implement audit\(\)/, "error message mentions method name");

$err = dies { $obj->has_plan() };
like($err, qr/does not implement has_plan\(\)/, "error message mentions has_plan");
};

done_testing;
142 changes: 141 additions & 1 deletion t/unit/Test2/Harness/Collector/Auditor/Job.t
Original file line number Diff line number Diff line change
@@ -1,5 +1,145 @@
use Test2::V0 -target => 'Test2::Harness::Collector::Auditor::Job';

skip_all "write me";
my $CLASS = CLASS();

subtest 'inherits from Auditor' => sub {
ok($CLASS->isa('Test2::Harness::Collector::Auditor'), "inherits from Auditor");
};

subtest 'constructor requires mandatory fields' => sub {
like(
dies { $CLASS->new(job_id => 'j1', job_try => 0, file => 't/foo.t') },
qr/run_id.*required/i,
"missing run_id dies"
);

like(
dies { $CLASS->new(run_id => 'r1', job_try => 0, file => 't/foo.t') },
qr/job_id.*required/i,
"missing job_id dies"
);

like(
dies { $CLASS->new(run_id => 'r1', job_id => 'j1', file => 't/foo.t') },
qr/job_try.*required/i,
"missing job_try dies"
);

like(
dies { $CLASS->new(run_id => 'r1', job_id => 'j1', job_try => 0) },
qr/file.*required/i,
"missing file dies"
);
};

my $auditor = $CLASS->new(
run_id => 'run-1',
job_id => 'job-1',
job_try => 0,
file => 't/example.t',
);

subtest 'constructor with valid args' => sub {
ok($auditor, "object created");
is($auditor->run_id, 'run-1', "run_id accessor");
is($auditor->job_id, 'job-1', "job_id accessor");
is($auditor->job_try, 0, "job_try accessor");
is($auditor->file, 't/example.t', "file accessor");
};

subtest 'initial state' => sub {
ok(!$auditor->has_exit, "has_exit returns false initially");
ok(!$auditor->has_plan, "has_plan returns false initially");
is($auditor->assertion_count, 0, "assertion_count starts at 0");
is($auditor->nested, 0, "nested starts at 0");
# pass/fail state with no events depends on fail_error_facet_list logic
# (no plan + no assertions = fail). Check that pass and fail are consistent.
my $p = $auditor->pass;
my $f = $auditor->fail;
ok(($p && !$f) || (!$p && $f) || (!$p && !$f), "pass and fail are consistent");
};

subtest 'fail_error_facet_list with no assertions and no plan' => sub {
my $obj = $CLASS->new(
run_id => 'r',
job_id => 'j',
job_try => 0,
file => 't/test.t',
);
my @errors = $obj->fail_error_facet_list();
ok(@errors, "has error facets when no plan and no assertions");
my ($no_plan) = grep { $_->{details} =~ /No plan/ } @errors;
ok($no_plan, "error mentions missing plan");
};

subtest 'subtest_fail_error_facet_list with no plan' => sub {
my $obj = $CLASS->new(
run_id => 'r',
job_id => 'j',
job_try => 0,
file => 't/test.t',
);
my @errors = $obj->subtest_fail_error_facet_list();
ok(@errors, "has errors when no plan seen");
my ($no_plan) = grep { $_->{details} =~ /No plan/ } @errors;
ok($no_plan, "error mentions no plan");
};

subtest 'pass and fail are inverses' => sub {
my $obj = $CLASS->new(
run_id => 'r',
job_id => 'j',
job_try => 0,
file => 't/test.t',
);
# pass() is defined as !fail(), so they are always inverses
my $pass = $obj->pass;
my $fail = $obj->fail;
# They must be logical inverses
ok(($pass ? 1 : 0) != ($fail ? 1 : 0), "pass and fail are logical inverses");
};

subtest 'has_exit with no exit set' => sub {
my $obj = $CLASS->new(
run_id => 'r',
job_id => 'j',
job_try => 0,
file => 't/test.t',
);
ok(!$obj->has_exit, "has_exit returns false when exit not seen");
};

subtest 'has_plan with no plan set' => sub {
my $obj = $CLASS->new(
run_id => 'r',
job_id => 'j',
job_try => 0,
file => 't/test.t',
);
ok(!$obj->has_plan, "has_plan returns false when no plan seen");
};

subtest 'times accessor returns TimeTracker' => sub {
my $obj = $CLASS->new(
run_id => 'r',
job_id => 'j',
job_try => 0,
file => 't/test.t',
);
my $times = $obj->times;
ok($times, "times accessor returns something");
ok($times->isa('Test2::Harness::Log::TimeTracker'), "times is a TimeTracker");
};

subtest 'update_summary with no summary_file' => sub {
my $obj = $CLASS->new(
run_id => 'r',
job_id => 'j',
job_try => 0,
file => 't/test.t',
);
# Should not die when no summary_file is set
ok(lives { $obj->update_summary() }, "update_summary doesn't die without summary_file");
};

done_testing;
Loading
Loading