| blib/lib/Moonshine/Test.pm | |||
|---|---|---|---|
| Criterion | Covered | Total | % |
| statement | 112 | 117 | 95.7 |
| branch | 49 | 60 | 81.6 |
| condition | 2 | 4 | 50.0 |
| subroutine | 43 | 44 | 97.7 |
| pod | 4 | 4 | 100.0 |
| total | 210 | 229 | 91.7 |
| line | stmt | bran | cond | sub | pod | time | code |
|---|---|---|---|---|---|---|---|
| 1 | package Moonshine::Test; | ||||||
| 2 | |||||||
| 3 | 7 | 7 | 880558 | use strict; | |||
| 7 | 16 | ||||||
| 7 | 283 | ||||||
| 4 | 7 | 7 | 69 | use warnings; | |||
| 7 | 13 | ||||||
| 7 | 415 | ||||||
| 5 | 7 | 7 | 4399 | use Test::More; | |||
| 7 | 64676 | ||||||
| 7 | 71 | ||||||
| 6 | 7 | 7 | 4110 | use Scalar::Util qw/blessed/; | |||
| 7 | 19 | ||||||
| 7 | 349 | ||||||
| 7 | 7 | 7 | 4626 | use Params::Validate qw/:all/; | |||
| 7 | 84695 | ||||||
| 7 | 1805 | ||||||
| 8 | 7 | 7 | 67 | use B qw/svref_2object/; | |||
| 7 | 17 | ||||||
| 7 | 928 | ||||||
| 9 | 7 | 7 | 48 | use Exporter 'import'; | |||
| 7 | 12 | ||||||
| 7 | 323 | ||||||
| 10 | 7 | 7 | 4195 | use Acme::AsciiEmoji; | |||
| 7 | 78118 | ||||||
| 7 | 104 | ||||||
| 11 | 7 | 7 | 69277 | use Switch::Again qw/switch/; | |||
| 7 | 146153 | ||||||
| 7 | 67 | ||||||
| 12 | |||||||
| 13 | our @EMO = @Acme::AsciiEmoji::EXPORT_OK; | ||||||
| 14 | our @EXPORT = qw/render_me moon_test moon_test_one sunrise/; | ||||||
| 15 | our @EXPORT_OK = (qw/render_me moon_test moon_test_one sunrise/, @EMO); | ||||||
| 16 | our %EXPORT_TAGS = ( | ||||||
| 17 | all => [qw/render_me moon_test moon_test_one sunrise/, @EMO], | ||||||
| 18 | element => [qw/render_me sunrise/], | ||||||
| 19 | emo => [@EMO], | ||||||
| 20 | ); | ||||||
| 21 | |||||||
| 22 | |||||||
| 23 | =head1 NAME | ||||||
| 24 | |||||||
| 25 | Moonshine::Test - Test! | ||||||
| 26 | |||||||
| 27 | =head1 VERSION | ||||||
| 28 | |||||||
| 29 | Version 0.18 | ||||||
| 30 | |||||||
| 31 | =cut | ||||||
| 32 | |||||||
| 33 | our $VERSION = '0.18'; | ||||||
| 34 | |||||||
| 35 | =head1 SYNOPSIS | ||||||
| 36 | |||||||
| 37 | use Moonshine::Test qw/:all/; | ||||||
| 38 | |||||||
| 39 | moon_test_one( | ||||||
| 40 | test => 'scalar', | ||||||
| 41 | meth => \&Moonshine::Util::append_str, | ||||||
| 42 | args => [ | ||||||
| 43 | 'first', 'second' | ||||||
| 44 | ], | ||||||
| 45 | args_list => 1, | ||||||
| 46 | expected => 'first second', | ||||||
| 47 | ); | ||||||
| 48 | |||||||
| 49 | sunrise(1); | ||||||
| 50 | |||||||
| 51 | =head1 EXPORT | ||||||
| 52 | |||||||
| 53 | =head2 all | ||||||
| 54 | |||||||
| 55 | =over | ||||||
| 56 | |||||||
| 57 | =item moon_test | ||||||
| 58 | |||||||
| 59 | =item moon_test_one | ||||||
| 60 | |||||||
| 61 | =item render_me | ||||||
| 62 | |||||||
| 63 | =item done_testing | ||||||
| 64 | |||||||
| 65 | =back | ||||||
| 66 | |||||||
| 67 | =head2 element | ||||||
| 68 | |||||||
| 69 | =over | ||||||
| 70 | |||||||
| 71 | =item render_me | ||||||
| 72 | |||||||
| 73 | =item done_testing | ||||||
| 74 | |||||||
| 75 | =back | ||||||
| 76 | |||||||
| 77 | =head1 SUBROUTINES/METHODS | ||||||
| 78 | |||||||
| 79 | =head2 moon_test_one | ||||||
| 80 | |||||||
| 81 | moon_test_one( | ||||||
| 82 | test => 'render_me', | ||||||
| 83 | instance => Moonshine::Component->new(), | ||||||
| 84 | func => 'button', | ||||||
| 85 | args => { | ||||||
| 86 | data => '...' | ||||||
| 87 | }, | ||||||
| 88 | expected => '', | ||||||
| 89 | ); | ||||||
| 90 | |||||||
| 91 | =head2 Instructions | ||||||
| 92 | |||||||
| 93 | Valid instructions moon_test_one accepts | ||||||
| 94 | |||||||
| 95 | =head3 test/expected | ||||||
| 96 | |||||||
| 97 | test => 'like' | ||||||
| 98 | expected => 'a horrible death' | ||||||
| 99 | .... | ||||||
| 100 | like($test_outcome, qr/$expected/, "function: $func is like - $expected"); | ||||||
| 101 | |||||||
| 102 | moon_test_one can currently run the following tests. | ||||||
| 103 | |||||||
| 104 | =over | ||||||
| 105 | |||||||
| 106 | =item ok - ok - a true value | ||||||
| 107 | |||||||
| 108 | =item ref - is_deeply - expected [] or {} | ||||||
| 109 | |||||||
| 110 | =item scalar - is - expected '', | ||||||
| 111 | |||||||
| 112 | =item hash - is_deeply - expected {}, | ||||||
| 113 | |||||||
| 114 | =item array - is_deeply - expected [], | ||||||
| 115 | |||||||
| 116 | =item obj - isa_ok - expected '', | ||||||
| 117 | |||||||
| 118 | =item like - like - '', | ||||||
| 119 | |||||||
| 120 | =item true - is - 1, | ||||||
| 121 | |||||||
| 122 | =item false - is - 0, | ||||||
| 123 | |||||||
| 124 | =item undef - is - undef | ||||||
| 125 | |||||||
| 126 | =item ref_key_scalar - is - '' (requires key) | ||||||
| 127 | |||||||
| 128 | =item ref_key_ref - is_deeply - [] or {} (requires key) | ||||||
| 129 | |||||||
| 130 | =item ref_key_like - like - '' | ||||||
| 131 | |||||||
| 132 | =item ref_index_scalar - is - '' (requires index) | ||||||
| 133 | |||||||
| 134 | =item ref_index_ref - is_deeply - [] or {} (required index) | ||||||
| 135 | |||||||
| 136 | =item ref_index_like - like - '' | ||||||
| 137 | |||||||
| 138 | =item ref_index_obj - isa_ok - '' | ||||||
| 139 | |||||||
| 140 | =item list_key_scalar - is - '' (requires key) | ||||||
| 141 | |||||||
| 142 | =item list_key_ref - is_deeply - [] or {} (requires key) | ||||||
| 143 | |||||||
| 144 | =item list_key_like - like - '' | ||||||
| 145 | |||||||
| 146 | =item list_index_scalar - is - '' (requires index) | ||||||
| 147 | |||||||
| 148 | =item list_index_ref - is_deeply - [] or {} (required index) | ||||||
| 149 | |||||||
| 150 | =item list_index_obj - isa_ok - '' | ||||||
| 151 | |||||||
| 152 | =item list_index_like - like - '' | ||||||
| 153 | |||||||
| 154 | =item count - is - '' | ||||||
| 155 | |||||||
| 156 | =item count_ref - is - '' | ||||||
| 157 | |||||||
| 158 | =item skip - ok(1) | ||||||
| 159 | |||||||
| 160 | =back | ||||||
| 161 | |||||||
| 162 | =head3 catch | ||||||
| 163 | |||||||
| 164 | when you want to catch exceptions.... | ||||||
| 165 | |||||||
| 166 | catch => 1, | ||||||
| 167 | |||||||
| 168 | defaults the instruction{test} to like. | ||||||
| 169 | |||||||
| 170 | =head3 instance | ||||||
| 171 | |||||||
| 172 | my $instance = Moonshine::Element->new(); | ||||||
| 173 | instance => $instance, | ||||||
| 174 | |||||||
| 175 | =head3 func | ||||||
| 176 | |||||||
| 177 | call a function from the instance | ||||||
| 178 | |||||||
| 179 | instance => $instance, | ||||||
| 180 | func => 'render' | ||||||
| 181 | |||||||
| 182 | =head3 meth | ||||||
| 183 | |||||||
| 184 | meth => \&Moonshine::Element::render, | ||||||
| 185 | |||||||
| 186 | =head3 args | ||||||
| 187 | |||||||
| 188 | {} or [] | ||||||
| 189 | |||||||
| 190 | =head3 args_list | ||||||
| 191 | |||||||
| 192 | args => [qw/one, two/], | ||||||
| 193 | args_list => 1, | ||||||
| 194 | |||||||
| 195 | =head3 index | ||||||
| 196 | |||||||
| 197 | index - required when testing - ref_index_* | ||||||
| 198 | |||||||
| 199 | =head3 key | ||||||
| 200 | |||||||
| 201 | key - required when testing - ref_key_* | ||||||
| 202 | |||||||
| 203 | =cut | ||||||
| 204 | |||||||
| 205 | sub moon_test_one { | ||||||
| 206 | 86 | 86 | 1 | 638693 | my %instruction = validate_with( | ||
| 207 | params => \@_, | ||||||
| 208 | spec => { | ||||||
| 209 | instance => 0, | ||||||
| 210 | meth => 0, | ||||||
| 211 | func => 0, | ||||||
| 212 | args => { default => {} }, | ||||||
| 213 | args_list => 0, | ||||||
| 214 | test => 0, | ||||||
| 215 | expected => 0, | ||||||
| 216 | catch => 0, | ||||||
| 217 | key => 0, | ||||||
| 218 | index => 0, | ||||||
| 219 | built => 0, | ||||||
| 220 | } | ||||||
| 221 | ); | ||||||
| 222 | |||||||
| 223 | 86 | 908 | my @test = (); | ||||
| 224 | 86 | 199 | my $test_name = ''; | ||||
| 225 | 86 | 307 | my @expected = $instruction{expected}; | ||||
| 226 | |||||||
| 227 | 86 | 100 | 264 | if ( $instruction{catch} ) { | |||
| 228 | 3 | 5 | $test_name = 'catch'; | ||||
| 229 | 3 | 50 | 14 | exists $instruction{test} or $instruction{test} = 'like'; | |||
| 230 | 3 | 4 | eval { _run_the_code( \%instruction ) }; | ||||
| 3 | 11 | ||||||
| 231 | 3 | 162 | @test = $@; | ||||
| 232 | } | ||||||
| 233 | else { | ||||||
| 234 | 83 | 364 | @test = _run_the_code( \%instruction ); | ||||
| 235 | 83 | 6520 | $test_name = shift @test; | ||||
| 236 | } | ||||||
| 237 | |||||||
| 238 | 86 | 100 | 283 | if ( not exists $instruction{test} ) { | |||
| 239 | 1 | 7 | ok(0); | ||||
| 240 | 1 | 415 | diag 'No instruction{test} passed to moon_test_one'; | ||||
| 241 | 1 | 136 | return; | ||||
| 242 | } | ||||||
| 243 | |||||||
| 244 | switch( $instruction{test}, | ||||||
| 245 | 'ref' => sub { | ||||||
| 246 | 6 | 6 | 1411 | return is_deeply( $test[0], $expected[0], | |||
| 247 | "$test_name is ref - is_deeply" ); | ||||||
| 248 | }, | ||||||
| 249 | 'ref_key_scalar' => sub { | ||||||
| 250 | return exists $instruction{key} | ||||||
| 251 | ? is( | ||||||
| 252 | $test[0]->{ $instruction{key} }, | ||||||
| 253 | 3 | 100 | 3 | 687 | $expected[0], | ||
| 254 | "$test_name is ref - has scalar key: $instruction{key} - is - $expected[0]" | ||||||
| 255 | ) | ||||||
| 256 | : ok( | ||||||
| 257 | 0, | ||||||
| 258 | "No key passed to test - ref_key_scalar - testing - $test_name" | ||||||
| 259 | ); | ||||||
| 260 | }, | ||||||
| 261 | 'ref_key_like' => sub { | ||||||
| 262 | return exists $instruction{key} | ||||||
| 263 | ? like( | ||||||
| 264 | $test[0]->{ $instruction{key} }, | ||||||
| 265 | 3 | 100 | 3 | 839 | qr/$expected[0]/, | ||
| 266 | "$test_name is ref - has scalar key: $instruction{key} - like - $expected[0]" | ||||||
| 267 | ) | ||||||
| 268 | : ok( 0, | ||||||
| 269 | "No key passed to test - ref_key_like - testing - $test_name" ); | ||||||
| 270 | }, | ||||||
| 271 | 'ref_key_ref' => sub { | ||||||
| 272 | return exists $instruction{key} | ||||||
| 273 | ? is_deeply( | ||||||
| 274 | $test[0]->{ $instruction{key} }, | ||||||
| 275 | 5 | 100 | 5 | 1390 | $expected[0], | ||
| 276 | "$test_name is ref - has ref key: $instruction{key} - is_deeply - ref" | ||||||
| 277 | ) | ||||||
| 278 | : ok( 0, | ||||||
| 279 | "No key passed to test - ref_key_ref - testing - $test_name" ); | ||||||
| 280 | }, | ||||||
| 281 | 'ref_index_scalar' => sub { | ||||||
| 282 | return exists $instruction{index} | ||||||
| 283 | ? is( | ||||||
| 284 | 6 | 100 | 6 | 1867 | $test[0]->[ $instruction{index} ], | ||
| 285 | $expected[0], | ||||||
| 286 | "$test_name is ref - has scalar index: $instruction{index} - is - $expected[0]" | ||||||
| 287 | ) | ||||||
| 288 | : ok( | ||||||
| 289 | 0, | ||||||
| 290 | "No index passed to test - ref_index_scalar - testing - $test_name" | ||||||
| 291 | ); | ||||||
| 292 | }, | ||||||
| 293 | 'ref_index_ref' => sub { | ||||||
| 294 | return exists $instruction{index} | ||||||
| 295 | ? is_deeply( | ||||||
| 296 | 3 | 100 | 3 | 1018 | $test[0]->[ $instruction{index} ], | ||
| 297 | $expected[0], | ||||||
| 298 | "$test_name is ref - has ref index: $instruction{index} - is_deeply - ref" | ||||||
| 299 | ) | ||||||
| 300 | : ok( | ||||||
| 301 | 0, | ||||||
| 302 | "No index passed to test - ref_index_ref - testing - $test_name" | ||||||
| 303 | ); | ||||||
| 304 | }, | ||||||
| 305 | 'ref_index_like' => sub { | ||||||
| 306 | return exists $instruction{index} | ||||||
| 307 | ? like( | ||||||
| 308 | 3 | 100 | 3 | 881 | $test[0]->[ $instruction{index} ], | ||
| 309 | qr/$expected[0]/, | ||||||
| 310 | "$test_name is ref - has scalar index: $instruction{index} - like - $expected[0]" | ||||||
| 311 | ) | ||||||
| 312 | : ok( | ||||||
| 313 | 0, | ||||||
| 314 | "No index passed to test - ref_index_like - testing - $test_name" | ||||||
| 315 | ); | ||||||
| 316 | }, | ||||||
| 317 | 'ref_index_obj' => sub { | ||||||
| 318 | return exists $instruction{index} | ||||||
| 319 | ? isa_ok( | ||||||
| 320 | 1 | 50 | 1 | 271 | $test[0]->[ $instruction{index} ], | ||
| 321 | $expected[0], | ||||||
| 322 | "$test_name is ref - has obj index: $instruction{index} - isa_ok - $expected[0]" | ||||||
| 323 | ) | ||||||
| 324 | : ok( | ||||||
| 325 | 0, | ||||||
| 326 | "No index passed to test - ref_index_obj - testing - $test_name" | ||||||
| 327 | ); | ||||||
| 328 | }, | ||||||
| 329 | 'list_index_scalar' => sub { | ||||||
| 330 | return exists $instruction{index} | ||||||
| 331 | ? is( | ||||||
| 332 | 3 | 100 | 3 | 921 | $test[ $instruction{index} ], | ||
| 333 | $expected[0], | ||||||
| 334 | "$test_name is list - has scalar index: $instruction{index} - is - $expected[0]" | ||||||
| 335 | ) | ||||||
| 336 | : ok( | ||||||
| 337 | 0, | ||||||
| 338 | "No index passed to test - list_index_scalar - testing - $test_name" | ||||||
| 339 | ); | ||||||
| 340 | }, | ||||||
| 341 | 'list_index_ref' => sub { | ||||||
| 342 | return exists $instruction{index} | ||||||
| 343 | ? is_deeply( | ||||||
| 344 | 3 | 100 | 3 | 926 | $test[ $instruction{index} ], | ||
| 345 | $expected[0], | ||||||
| 346 | "$test_name is list - has ref index: $instruction{index} - is_deeply - ref" | ||||||
| 347 | ) | ||||||
| 348 | : ok( | ||||||
| 349 | 0, | ||||||
| 350 | "No index passed to test - list_index_ref - testing - $test_name" | ||||||
| 351 | ); | ||||||
| 352 | }, | ||||||
| 353 | 'list_index_like' => sub { | ||||||
| 354 | return exists $instruction{index} | ||||||
| 355 | ? like( | ||||||
| 356 | 3 | 100 | 3 | 1032 | $test[ $instruction{index} ], | ||
| 357 | qr/$expected[0]/, | ||||||
| 358 | "$test_name is list - has scalar index: $instruction{index} - like - $expected[0]" | ||||||
| 359 | ) | ||||||
| 360 | : ok( | ||||||
| 361 | 0, | ||||||
| 362 | "No index passed to test - list_index_like - testing - $test_name" | ||||||
| 363 | ); | ||||||
| 364 | }, | ||||||
| 365 | 'list_index_obj' => sub { | ||||||
| 366 | return exists $instruction{index} | ||||||
| 367 | ? isa_ok( | ||||||
| 368 | 1 | 50 | 1 | 622 | $test[ $instruction{index} ], | ||
| 369 | $expected[0], | ||||||
| 370 | "$test_name is list - has obj index: $instruction{index} - isa_ok - $expected[0]" | ||||||
| 371 | ) | ||||||
| 372 | : ok( | ||||||
| 373 | 0, | ||||||
| 374 | "No index passed to test - list_index_obj - testing - $test_name" | ||||||
| 375 | ); | ||||||
| 376 | }, | ||||||
| 377 | 'list_key_scalar' => sub { | ||||||
| 378 | return exists $instruction{key} | ||||||
| 379 | ? is( | ||||||
| 380 | {@test}->{ $instruction{key} }, | ||||||
| 381 | 3 | 100 | 3 | 1091 | $expected[0], | ||
| 382 | "$test_name is list - has scalar key: $instruction{key} - is - $expected[0]" | ||||||
| 383 | ) | ||||||
| 384 | : ok( | ||||||
| 385 | 0, | ||||||
| 386 | "No key passed to test - list_key_scalar - testing - $test_name" | ||||||
| 387 | ); | ||||||
| 388 | }, | ||||||
| 389 | 'list_key_ref' => sub { | ||||||
| 390 | return exists $instruction{key} | ||||||
| 391 | ? is_deeply( | ||||||
| 392 | {@test}->{ $instruction{key} }, | ||||||
| 393 | 3 | 100 | 3 | 1172 | $expected[0], | ||
| 394 | "$test_name is list - has ref key: $instruction{key} - is_deeply - ref" | ||||||
| 395 | ) | ||||||
| 396 | : ok( 0, | ||||||
| 397 | "No key passed to test - list_key_ref - testing - $test_name" ); | ||||||
| 398 | }, | ||||||
| 399 | 'list_key_like' => sub { | ||||||
| 400 | return exists $instruction{key} | ||||||
| 401 | ? like( | ||||||
| 402 | {@test}->{ $instruction{key} }, | ||||||
| 403 | 3 | 100 | 3 | 1245 | qr/$expected[0]/, | ||
| 404 | "$test_name is list - has scalar key: $instruction{key} - like - $expected[0]" | ||||||
| 405 | ) | ||||||
| 406 | : ok( | ||||||
| 407 | 0, | ||||||
| 408 | "No key passed to test - list_key_like - testing - $test_name" | ||||||
| 409 | ); | ||||||
| 410 | }, | ||||||
| 411 | 'count' => sub { | ||||||
| 412 | 1 | 1 | 494 | return is( | |||
| 413 | scalar @test, | ||||||
| 414 | $expected[0], | ||||||
| 415 | "$test_name is list - count - is - $expected[0]" | ||||||
| 416 | ); | ||||||
| 417 | }, | ||||||
| 418 | 'count_ref' => sub { | ||||||
| 419 | return is( | ||||||
| 420 | 2 | 2 | 981 | scalar @{ $test[0] }, | |||
| 2 | 18 | ||||||
| 421 | $expected[0], | ||||||
| 422 | "$test_name is ref - count - is - $expected[0]" | ||||||
| 423 | ); | ||||||
| 424 | }, | ||||||
| 425 | 'scalar' => sub { | ||||||
| 426 | 2 | 50 | 2 | 1224 | return is( $test[0], $expected[0], sprintf "%s is scalar - is - %s", | ||
| 427 | $test_name, defined $expected[0] ? $expected[0] : 'undef' ); | ||||||
| 428 | }, | ||||||
| 429 | 'hash' => sub { | ||||||
| 430 | 3 | 3 | 1844 | return is_deeply( {@test}, $expected[0], | |||
| 431 | "$test_name is hash - reference - is_deeply" ); | ||||||
| 432 | }, | ||||||
| 433 | 'array' => sub { | ||||||
| 434 | 5 | 5 | 2884 | return is_deeply( \@test, $expected[0], | |||
| 435 | "$test_name is array - reference - is_deeply" ); | ||||||
| 436 | }, | ||||||
| 437 | 'obj' => sub { | ||||||
| 438 | 7 | 7 | 4385 | return isa_ok( $test[0], $expected[0], | |||
| 439 | "$test_name is Object - blessed - is - $expected[0]" ); | ||||||
| 440 | }, | ||||||
| 441 | 'like' => sub { | ||||||
| 442 | 3 | 3 | 1547 | return like( $test[0], qr/$expected[0]/, | |||
| 443 | "$test_name is like - $expected[0]" ); | ||||||
| 444 | }, | ||||||
| 445 | 'true' => sub { | ||||||
| 446 | 2 | 2 | 1100 | return is( $test[0], 1, "$test_name is true - 1" ); | |||
| 447 | }, | ||||||
| 448 | 'false' => sub { | ||||||
| 449 | 2 | 2 | 1225 | return is( $test[0], 0, "$test_name is false - 0" ); | |||
| 450 | }, | ||||||
| 451 | 'undef' => sub { | ||||||
| 452 | 2 | 2 | 1174 | return is( $test[0], undef, "$test_name is undef" ); | |||
| 453 | }, | ||||||
| 454 | 'render' => sub { | ||||||
| 455 | 4 | 4 | 2638 | return render_me( | |||
| 456 | instance => $test[0], | ||||||
| 457 | expected => $expected[0], | ||||||
| 458 | ); | ||||||
| 459 | }, | ||||||
| 460 | 'ok' => sub { | ||||||
| 461 | 2 | 2 | 1249 | return ok(@test, "$test_name is ok"); | |||
| 462 | }, | ||||||
| 463 | 'skip' => sub { | ||||||
| 464 | 1 | 1 | 470 | return ok(1, "$test_name - skip"); | |||
| 465 | }, | ||||||
| 466 | default => sub { | ||||||
| 467 | 0 | 0 | 0 | ok(0); | |||
| 468 | 0 | 0 | diag "Unknown instruction{test}: $_ passed to moon_test_one"; | ||||
| 469 | 0 | 0 | return; | ||||
| 470 | } | ||||||
| 471 | 85 | 5722 | ); | ||||
| 472 | } | ||||||
| 473 | |||||||
| 474 | =head2 moon_test | ||||||
| 475 | |||||||
| 476 | moon_test( | ||||||
| 477 | name => 'Checking Many Things' | ||||||
| 478 | build => { | ||||||
| 479 | class => 'Moonshine::Element', | ||||||
| 480 | args => { | ||||||
| 481 | tag => 'p', | ||||||
| 482 | text => 'hello' | ||||||
| 483 | } | ||||||
| 484 | }, | ||||||
| 485 | instructions => [ | ||||||
| 486 | { | ||||||
| 487 | test => 'scalar', | ||||||
| 488 | func => 'tag', | ||||||
| 489 | expected => 'p', | ||||||
| 490 | }, | ||||||
| 491 | { | ||||||
| 492 | test => 'scalar', | ||||||
| 493 | action => 'text', | ||||||
| 494 | expected => 'hello', | ||||||
| 495 | }, | ||||||
| 496 | { | ||||||
| 497 | test => 'render' | ||||||
| 498 | expected => ' hello ' |
||||||
| 499 | }, | ||||||
| 500 | ], | ||||||
| 501 | ); | ||||||
| 502 | |||||||
| 503 | =head3 name | ||||||
| 504 | |||||||
| 505 | The tests name | ||||||
| 506 | |||||||
| 507 | name => 'I rule the world', | ||||||
| 508 | |||||||
| 509 | =head3 instance | ||||||
| 510 | |||||||
| 511 | my $instance = My::Object->new(); | ||||||
| 512 | instance => $instance, | ||||||
| 513 | |||||||
| 514 | =head3 build | ||||||
| 515 | |||||||
| 516 | Build an instance | ||||||
| 517 | |||||||
| 518 | build => { | ||||||
| 519 | class => 'My::Object', | ||||||
| 520 | args => { }, | ||||||
| 521 | }, | ||||||
| 522 | |||||||
| 523 | =head3 instructions | ||||||
| 524 | |||||||
| 525 | instructions => [ | ||||||
| 526 | { | ||||||
| 527 | test => 'scalar', | ||||||
| 528 | func => 'tag', | ||||||
| 529 | expected => 'hello', | ||||||
| 530 | }, | ||||||
| 531 | { | ||||||
| 532 | test => 'scalar', | ||||||
| 533 | action => 'text', | ||||||
| 534 | expected => 'hello', | ||||||
| 535 | }, | ||||||
| 536 | { | ||||||
| 537 | test => 'render' | ||||||
| 538 | expected => ' hello ' |
||||||
| 539 | }, | ||||||
| 540 | ], | ||||||
| 541 | |||||||
| 542 | =head3 subtest | ||||||
| 543 | |||||||
| 544 | instructions => [ | ||||||
| 545 | { | ||||||
| 546 | test => 'obj', | ||||||
| 547 | func => 'glyphicon', | ||||||
| 548 | args => { switch => 'search' }, | ||||||
| 549 | subtest => [ | ||||||
| 550 | { | ||||||
| 551 | test => 'scalar', | ||||||
| 552 | func => 'class', | ||||||
| 553 | expected => 'glyphicon glyphicon-search', | ||||||
| 554 | }, | ||||||
| 555 | ... | ||||||
| 556 | ] | ||||||
| 557 | } | ||||||
| 558 | ] | ||||||
| 559 | |||||||
| 560 | =cut | ||||||
| 561 | |||||||
| 562 | sub moon_test { | ||||||
| 563 | 7 | 7 | 1 | 736323 | my %instruction = validate_with( | ||
| 564 | params => \@_, | ||||||
| 565 | spec => { | ||||||
| 566 | build => { type => HASHREF, optional => 1, }, | ||||||
| 567 | instance => { optional => 1, }, | ||||||
| 568 | instructions => { type => ARRAYREF }, | ||||||
| 569 | name => { type => SCALAR }, | ||||||
| 570 | } | ||||||
| 571 | ); | ||||||
| 572 | |||||||
| 573 | my $instance = | ||||||
| 574 | $instruction{build} | ||||||
| 575 | ? _build_me( $instruction{build} ) | ||||||
| 576 | 7 | 50 | 85 | : $instruction{instance}; | |||
| 577 | |||||||
| 578 | 7 | 33 | my %test_info = ( | ||||
| 579 | fail => 0, | ||||||
| 580 | tested => 0, | ||||||
| 581 | ); | ||||||
| 582 | |||||||
| 583 | 7 | 17 | foreach my $test ( @{ $instruction{instructions} } ) { | ||||
| 7 | 27 | ||||||
| 584 | 40 | 32610 | $test_info{tested}++; | ||||
| 585 | 40 | 100 | 163 | if ( my $subtests = delete $test->{subtest} ) { | |||
| 586 | my ( $test_name, $new_instance ) = _run_the_code( | ||||||
| 587 | { | ||||||
| 588 | instance => $instance, | ||||||
| 589 | 2 | 6 | %{$test} | ||||
| 2 | 16 | ||||||
| 590 | } | ||||||
| 591 | ); | ||||||
| 592 | |||||||
| 593 | $test_info{fail}++ | ||||||
| 594 | unless moon_test_one( | ||||||
| 595 | instance => $new_instance, | ||||||
| 596 | test => $test->{test}, | ||||||
| 597 | expected => $test->{expected}, | ||||||
| 598 | 2 | 50 | 219 | ); | |||
| 599 | |||||||
| 600 | |||||||
| 601 | 2 | 3350 | my $new_instructions = { | ||||
| 602 | instance => $new_instance, | ||||||
| 603 | instructions => $subtests, | ||||||
| 604 | name => "Subtest -> $instruction{name} -> $test_name", | ||||||
| 605 | }; | ||||||
| 606 | |||||||
| 607 | 2 | 6 | moon_test(%{$new_instructions}); | ||||
| 2 | 16 | ||||||
| 608 | 2 | 863 | next; | ||||
| 609 | } | ||||||
| 610 | |||||||
| 611 | $test_info{fail}++ | ||||||
| 612 | unless moon_test_one( | ||||||
| 613 | instance => $instance, | ||||||
| 614 | 38 | 50 | 72 | %{$test} | |||
| 38 | 192 | ||||||
| 615 | ); | ||||||
| 616 | } | ||||||
| 617 | |||||||
| 618 | 7 | 50 | 4790 | $test_info{ok} = $test_info{fail} ? 0 : 1; | |||
| 619 | return ok( | ||||||
| 620 | $test_info{ok}, | ||||||
| 621 | sprintf( | ||||||
| 622 | "moon_test: %s - tested %d instructions - success: %d - failure: %d", | ||||||
| 623 | $instruction{name}, $test_info{tested}, | ||||||
| 624 | ( $test_info{tested} - $test_info{fail} ), $test_info{fail}, | ||||||
| 625 | ) | ||||||
| 626 | 7 | 101 | ); | ||||
| 627 | } | ||||||
| 628 | |||||||
| 629 | sub _build_me { | ||||||
| 630 | 3 | 3 | 78 | my %instruction = validate_with( | |||
| 631 | params => \@_, | ||||||
| 632 | spec => { | ||||||
| 633 | class => 1, | ||||||
| 634 | new => { default => 'new' }, | ||||||
| 635 | args => { optional => 1, type => HASHREF }, | ||||||
| 636 | } | ||||||
| 637 | ); | ||||||
| 638 | |||||||
| 639 | 3 | 22 | my $new = $instruction{new}; | ||||
| 640 | return $instruction{args} | ||||||
| 641 | ? $instruction{class}->$new( $instruction{args} ) | ||||||
| 642 | 3 | 50 | 33 | : $instruction{class}->$new; | |||
| 643 | } | ||||||
| 644 | |||||||
| 645 | =head2 render_me | ||||||
| 646 | |||||||
| 647 | Test render directly on a Moonshine::Element. | ||||||
| 648 | |||||||
| 649 | render_me( | ||||||
| 650 | instance => $element, | ||||||
| 651 | expected => ' echo ' |
||||||
| 652 | ); | ||||||
| 653 | |||||||
| 654 | Or test a function.. | ||||||
| 655 | |||||||
| 656 | render_me( | ||||||
| 657 | instance => $instance, | ||||||
| 658 | func => 'div', | ||||||
| 659 | args => { data => 'echo' }, | ||||||
| 660 | expected => ' echo ', |
||||||
| 661 | ); | ||||||
| 662 | |||||||
| 663 | =cut | ||||||
| 664 | |||||||
| 665 | sub render_me { | ||||||
| 666 | 7 | 7 | 1 | 282728 | my %instruction = validate_with( | ||
| 667 | params => \@_, | ||||||
| 668 | spec => { | ||||||
| 669 | instance => 0, | ||||||
| 670 | func => 0, | ||||||
| 671 | meth => 0, | ||||||
| 672 | args => { default => {} }, | ||||||
| 673 | expected => { type => SCALAR }, | ||||||
| 674 | } | ||||||
| 675 | ); | ||||||
| 676 | |||||||
| 677 | 7 | 78 | my ( $test_name, $instance ) = _run_the_code( \%instruction ); | ||||
| 678 | |||||||
| 679 | return is( $instance->render, | ||||||
| 680 | 7 | 389 | $instruction{expected}, "render $test_name: $instruction{expected}" ); | ||||
| 681 | } | ||||||
| 682 | |||||||
| 683 | sub _run_the_code { | ||||||
| 684 | 98 | 98 | 205 | my $instruction = shift; | |||
| 685 | |||||||
| 686 | 98 | 157 | my $test_name; | ||||
| 687 | 98 | 100 | 377 | if ( my $func = $instruction->{func} ) { | |||
| 100 | |||||||
| 100 | |||||||
| 688 | 79 | 196 | $test_name = "function: ${func}"; | ||||
| 689 | |||||||
| 690 | return defined $instruction->{args} | ||||||
| 691 | ? defined $instruction->{args_list} | ||||||
| 692 | ? ( | ||||||
| 693 | $test_name, | ||||||
| 694 | 0 | 0 | $instruction->{instance}->$func( @{ $instruction->{args} } ) | ||||
| 695 | ) | ||||||
| 696 | : ( | ||||||
| 697 | $test_name, $instruction->{instance}->$func( $instruction->{args} // {}) | ||||||
| 698 | ) | ||||||
| 699 | 79 | 50 | 50 | 1227 | : ( $test_name, $instruction->{instance}->$func ); | ||
| 100 | |||||||
| 700 | } | ||||||
| 701 | elsif ( my $meth = $instruction->{meth} ) { | ||||||
| 702 | 6 | 115 | my $meth_name = svref_2object($meth)->GV->NAME; | ||||
| 703 | 6 | 81 | $test_name = "method: ${meth_name}"; | ||||
| 704 | return | ||||||
| 705 | defined $instruction->{args_list} | ||||||
| 706 | 0 | 0 | ? ( $test_name, $meth->( @{ $instruction->{args} } ) ) | ||||
| 707 | 6 | 50 | 31 | : ( $test_name, $meth->( $instruction->{args} ) ); | |||
| 708 | } | ||||||
| 709 | elsif ( exists $instruction->{instance} ) { | ||||||
| 710 | 12 | 26 | $test_name = 'instance'; | ||||
| 711 | 12 | 49 | return ( $test_name, $instruction->{instance} ); | ||||
| 712 | } | ||||||
| 713 | |||||||
| 714 | die( | ||||||
| 715 | 1 | 6 | 'instruction passed to _run_the_code must have a func, meth or instance' | ||||
| 716 | ); | ||||||
| 717 | } | ||||||
| 718 | |||||||
| 719 | =head2 sunrise | ||||||
| 720 | |||||||
| 721 | sunrise(); # done_testing(); | ||||||
| 722 | |||||||
| 723 | =cut | ||||||
| 724 | |||||||
| 725 | sub sunrise { | ||||||
| 726 | 6 | 6 | 1 | 112271 | my $done_testing = done_testing(shift); | ||
| 727 | 6 | 7379 | diag explain $done_testing; | ||||
| 728 | 6 | 50 | 72851 | diag sprintf( ' | |||
| 729 | %s | ||||||
| 730 | ^^ @@@@@@@@@ | ||||||
| 731 | ^^ ^^ @@@@@@@@@@@@@@@ | ||||||
| 732 | @@@@@@@@@@@@@@@@@@ ^^ | ||||||
| 733 | @@@@@@@@@@@@@@@@@@@@ | ||||||
| 734 | ---- -- ----- -------- -- &&&&&&&&&&&&&&&&&&&& ------- ----------- --- | ||||||
| 735 | - -- - - -------------------- - -- -- - | ||||||
| 736 | - -- -- -- -- ------------- ---- - --- - --- - -- | ||||||
| 737 | - -- - - ------ -- --- -- - -- -- - | ||||||
| 738 | - - - - - -- ------ - -- - -- | ||||||
| 739 | - - - - -- - -', | ||||||
| 740 | shift // ' \o/ ' ); | ||||||
| 741 | 6 | 3914 | return $done_testing; | ||||
| 742 | } | ||||||
| 743 | |||||||
| 744 | =head1 AUTHOR | ||||||
| 745 | |||||||
| 746 | LNATION, C<< |
||||||
| 747 | |||||||
| 748 | =head1 BUGS | ||||||
| 749 | |||||||
| 750 | Please report any bugs or feature requests to C |
||||||
| 751 | the web interface at L |
||||||
| 752 | automatically be notified of progress on your bug as I make changes. | ||||||
| 753 | |||||||
| 754 | =head1 SUPPORT | ||||||
| 755 | |||||||
| 756 | You can find documentation for this module with the perldoc command. | ||||||
| 757 | |||||||
| 758 | perldoc Moonshine::Test | ||||||
| 759 | |||||||
| 760 | You can also look for information at: | ||||||
| 761 | |||||||
| 762 | =over 4 | ||||||
| 763 | |||||||
| 764 | =item * RT: CPAN's request tracker (report bugs here) | ||||||
| 765 | |||||||
| 766 | L |
||||||
| 767 | |||||||
| 768 | =item * Search CPAN | ||||||
| 769 | |||||||
| 770 | L |
||||||
| 771 | |||||||
| 772 | =back | ||||||
| 773 | |||||||
| 774 | =head1 ACKNOWLEDGEMENTS | ||||||
| 775 | |||||||
| 776 | =head1 LICENSE AND COPYRIGHT | ||||||
| 777 | |||||||
| 778 | Copyright 2017->2025 Robert Acock. | ||||||
| 779 | |||||||
| 780 | This program is free software; you can redistribute it and/or modify it | ||||||
| 781 | under the terms of the the Artistic License (2.0). You may obtain a | ||||||
| 782 | copy of the full license at: | ||||||
| 783 | |||||||
| 784 | L |
||||||
| 785 | |||||||
| 786 | Any use, modification, and distribution of the Standard or Modified | ||||||
| 787 | Versions is governed by this Artistic License. By using, modifying or | ||||||
| 788 | distributing the Package, you accept this license. Do not use, modify, | ||||||
| 789 | or distribute the Package, if you do not accept this license. | ||||||
| 790 | |||||||
| 791 | If your Modified Version has been derived from a Modified Version made | ||||||
| 792 | by someone other than you, you are nevertheless required to ensure that | ||||||
| 793 | your Modified Version complies with the requirements of this license. | ||||||
| 794 | |||||||
| 795 | This license does not grant you the right to use any trademark, service | ||||||
| 796 | mark, tradename, or logo of the Copyright Holder. | ||||||
| 797 | |||||||
| 798 | This license includes the non-exclusive, worldwide, free-of-charge | ||||||
| 799 | patent license to make, have made, use, offer to sell, sell, import and | ||||||
| 800 | otherwise transfer the Package with respect to any patent claims | ||||||
| 801 | licensable by the Copyright Holder that are necessarily infringed by the | ||||||
| 802 | Package. If you institute patent litigation (including a cross-claim or | ||||||
| 803 | counterclaim) against any party alleging that the Package constitutes | ||||||
| 804 | direct or contributory patent infringement, then this Artistic License | ||||||
| 805 | to you shall terminate on the date that such litigation is filed. | ||||||
| 806 | |||||||
| 807 | Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER | ||||||
| 808 | AND CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. | ||||||
| 809 | THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR | ||||||
| 810 | PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY | ||||||
| 811 | YOUR LOCAL LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR | ||||||
| 812 | CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR | ||||||
| 813 | CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE, | ||||||
| 814 | EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||||||
| 815 | |||||||
| 816 | =cut | ||||||
| 817 | |||||||
| 818 | 1; # End of Moonshine::Test |