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
60 changes: 59 additions & 1 deletion t/unit/App/Yath/Renderer.t
Original file line number Diff line number Diff line change
@@ -1,5 +1,63 @@
use Test2::V0 -target => 'App::Yath::Renderer';

skip_all "write me";
# Minimal subclass used to test the base class contract
package App::Yath::Renderer::TestSub;
use parent 'App::Yath::Renderer';
sub render_event {}

package main;

my $settings = bless({}, 'MockSettings');

# --- Construction ---

like(
dies { $CLASS->new() },
qr/'settings' is required/,
"init() croaks without settings",
);

ok(my $r = $CLASS->new(settings => $settings), "can construct with settings");

# --- Inheritance & interface ---

can_ok($CLASS, qw/
init render_event
start step signal finish exit_hook
weight end_of_events
/);

# --- render_event must be overridden ---

like(
dies { $r->render_event({}) },
qr/forgot to override 'render_event\(\)'/,
"base render_event() croaks — subclass must override",
);

# --- Default weight ---

is($r->weight, 0, "weight() returns 0 by default");

# --- Lifecycle hooks are no-ops ---

ok(lives { $r->start() }, "start() does not die");
ok(lives { $r->step() }, "step() does not die");
ok(lives { $r->signal('INT') }, "signal() does not die");
ok(lives { $r->finish() }, "finish() does not die");
ok(lives { $r->exit_hook() }, "exit_hook() does not die");
ok(lives { $r->end_of_events() }, "end_of_events() does not die");

# --- Subclass satisfies the contract ---

ok(
my $sub = App::Yath::Renderer::TestSub->new(settings => $settings),
"subclass with render_event can be constructed",
);
ok(lives { $sub->render_event({}) }, "subclass render_event() does not die");

# --- Attributes are accessible ---

is($r->settings, $settings, "settings attribute is stored");

done_testing;
43 changes: 41 additions & 2 deletions t/unit/App/Yath/Renderer/DB.t
Original file line number Diff line number Diff line change
@@ -1,5 +1,44 @@
use Test2::V0 -target => 'App::Yath::Renderer::DB';
use Test2::V0;

skip_all "write me";
# App::Yath::Renderer::DB requires several optional modules (Consumer::NonBlock,
# App::Yath::Schema::RunProcessor, etc.). Skip gracefully when they are absent.
eval { require App::Yath::Renderer::DB; 1 }
or skip_all "App::Yath::Renderer::DB requires optional dependencies: $@";

our $CLASS = 'App::Yath::Renderer::DB';

# DB's init() calls $settings->yath->project which must return a truthy value.
package MockYath {
sub new { bless {project => 'test-project'}, shift }
sub project { $_[0]->{project} }
}
package MockSettings {
sub new { bless {}, shift }
sub yath { MockYath->new() }
}

my $settings = MockSettings->new();

# --- Inheritance ---

isa_ok($CLASS, ['App::Yath::Renderer'], "inherits from App::Yath::Renderer");

# --- Interface ---

can_ok($CLASS, qw/init start render_event finish/);

# --- Construction ---

ok(my $r = $CLASS->new(settings => $settings), "can construct");

# --- Tracking attributes ---

ok(!defined($r->pid), "pid starts undef");
ok(!defined($r->writer), "writer starts undef");
ok(!defined($r->stopped), "stopped starts undef");

# --- render_event is a no-op (data flows to the writer process) ---

ok(lives { $r->render_event({}) }, "render_event() does not die without a writer");

done_testing;
70 changes: 68 additions & 2 deletions t/unit/App/Yath/Renderer/Default.t
Original file line number Diff line number Diff line change
@@ -1,5 +1,71 @@
use Test2::V0 -target => 'App::Yath::Renderer::Default';
use Test2::V0;

skip_all "write me";
eval { require App::Yath::Renderer::Default; 1 }
or skip_all "App::Yath::Renderer::Default requires optional dependencies: $@";

eval { require App::Yath::Theme; 1 }
or skip_all "App::Yath::Theme required: $@";

our $CLASS = 'App::Yath::Renderer::Default';

my $settings = bless({}, 'MockSettings');
my $theme = App::Yath::Theme->new();

sub make_renderer {
my %extra = @_;
return $CLASS->new(
settings => $settings,
theme => $theme,
color => 0,
%extra,
);
}

# --- Inheritance ---

isa_ok($CLASS, ['App::Yath::Renderer'], "inherits from App::Yath::Renderer");

# --- Interface ---

can_ok($CLASS, qw/init render_event write finish step/);

# --- Construction ---

ok(my $r = make_renderer(), "can construct with required arguments");

# --- Defaults set by init() ---

ok(defined $r->verbose, "verbose is set after init");
ok(defined $r->start_time, "start_time is set after init");

# --- IO handle is initialised ---

ok($r->io, "io handle is set after init");

# --- Composer is initialised ---

isa_ok($r->{composer}, ['App::Yath::Renderer::Default::Composer'],
"composer is an instance of the Composer class");

# --- color is false when explicitly disabled ---

my $no_color = make_renderer(color => 0);
ok(!$no_color->color, "color is false when color => 0");

# --- weight defaults to 0 (inherited) ---

is($r->weight, 0, "weight() returns 0");

# --- render_event does not die for a minimal event ---

ok(
lives {
$r->render_event({
facet_data => {},
stamp => time(),
});
},
"render_event() does not die for a minimal event",
);

done_testing;
90 changes: 89 additions & 1 deletion t/unit/App/Yath/Renderer/Default/Composer.t
Original file line number Diff line number Diff line change
@@ -1,5 +1,93 @@
use Test2::V0 -target => 'App::Yath::Renderer::Default::Composer';

skip_all "write me";
# --- Construction ---

ok(my $c = $CLASS->new(), "can construct");
ref_ok($c, 'HASH', "instance is a hashref");

# --- Interface ---

can_ok($CLASS, qw/
new
render_one_line
render_verbose
render_super_verbose
render_brief
render_assert
render_plan
render_info
render_errors
/);

# --- render_one_line: passing assert ---

{
my $f = { assert => { pass => 1, details => 'test description' } };
my $out = $c->render_one_line($f);
ref_ok($out, 'ARRAY', "render_one_line returns arrayref for assert");
is($out->[1], 'PASS', "tag is PASS for a passing assert");
}

# --- render_one_line: failing assert ---

{
my $f = { assert => { pass => 0, details => 'oops' } };
my $out = $c->render_one_line($f);
ref_ok($out, 'ARRAY', "render_one_line returns arrayref for failing assert");
is($out->[1], 'FAIL', "tag is FAIL for a failing assert");
}

# --- render_one_line: plan ---

{
my $f = { plan => { count => 3 } };
my $out = $c->render_one_line($f);
ref_ok($out, 'ARRAY', "render_one_line returns arrayref for plan");
}

# --- render_one_line: empty facet_data returns undef ---

{
my $out = $c->render_one_line({});
ok(!defined($out), "render_one_line returns undef for empty facet data");
}

# --- render_verbose: returns arrayref of lines ---

{
my $f = { plan => { count => 5 } };
my $out = $c->render_verbose($f);
ref_ok($out, 'ARRAY', "render_verbose returns arrayref");
ok(scalar(@$out) > 0, "render_verbose returns at least one line for plan");
}

# --- render_verbose: passing assert ---

{
my $f = { assert => { pass => 1, details => 'ok' } };
my $out = $c->render_verbose($f);
ref_ok($out, 'ARRAY', "render_verbose returns arrayref for passing assert");
ok(scalar(@$out) > 0, "render_verbose returns lines for assert");
}

# --- render_verbose: failing assert includes debug output ---

{
my $f = {
assert => { pass => 0, details => 'nope' },
errors => [{ tag => 'ERROR', details => 'something went wrong', fail => 1 }],
};
my $out = $c->render_verbose($f);
ref_ok($out, 'ARRAY', "render_verbose returns arrayref for failing assert");
ok(scalar(@$out) > 0, "render_verbose returns lines for failing assert");
}

# --- render_super_verbose: wraps render_verbose ---

{
my $f = { assert => { pass => 1, details => 'test' } };
my $out = $c->render_super_verbose($f);
ref_ok($out, 'ARRAY', "render_super_verbose returns arrayref");
}

done_testing;
79 changes: 77 additions & 2 deletions t/unit/App/Yath/Renderer/Formatter.t
Original file line number Diff line number Diff line change
@@ -1,5 +1,80 @@
use Test2::V0 -target => 'App::Yath::Renderer::Formatter';
use Test2::V0;

skip_all "write me";
eval { require App::Yath::Renderer::Formatter; 1 }
or skip_all "App::Yath::Renderer::Formatter requires optional dependencies: $@";

our $CLASS = 'App::Yath::Renderer::Formatter';

# We use a minimal mock formatter so we can instantiate the renderer without a
# real Test2 formatter being present.
{
package MockFormatter;
sub new { bless {}, shift }
sub write { }
sub step { }
sub finalize { }
sub can {
my ($self, $meth) = @_;
return $self->SUPER::can($meth);
}
}
$INC{'MockFormatter.pm'} = 1;

my $settings = bless({}, 'MockSettings');

sub make_renderer {
my %extra = @_;
return $CLASS->new(
settings => $settings,
formatter => 'MockFormatter',
io => \*STDOUT,
io_err => \*STDERR,
%extra,
);
}

# --- Inheritance ---

isa_ok($CLASS, ['App::Yath::Renderer'], "inherits from App::Yath::Renderer");

# --- Interface ---

can_ok($CLASS, qw/init render_event step finish formatter/);

# --- Construction ---

ok(my $r = make_renderer(), "can construct with a mock formatter");

# --- formatter attribute is the instantiated formatter object ---

isa_ok($r->formatter, ['MockFormatter'], "formatter attribute holds a MockFormatter instance");

# --- do_step is set based on whether formatter has step() ---

ok($r->do_step, "do_step is true when formatter has step()");

# --- show_job_end defaults to 1 ---

ok($r->show_job_end, "show_job_end defaults to 1");

# --- render_event does not die for a minimal event ---

ok(
lives {
$r->render_event({
facet_data => {},
stamp => time(),
});
},
"render_event() does not die for a minimal event",
);

# --- step() delegates to the formatter ---

ok(lives { $r->step() }, "step() does not die");

# --- finish() calls formatter finalize() ---

ok(lives { $r->finish() }, "finish() does not die");

done_testing;
Loading
Loading