|
6 | 6 | use Salient\Console\Target\AnalogTarget; |
7 | 7 | use Salient\Console\Target\StreamTarget; |
8 | 8 | use Salient\Console\Console as ConsoleService; |
| 9 | +use Salient\Core\Exception\Exception; |
| 10 | +use Salient\Core\Exception\MultipleErrorException; |
9 | 11 | use Salient\Core\Facade\Console; |
10 | 12 | use Salient\Testing\Console\MockTarget; |
11 | 13 | use Salient\Testing\Core\MockPhpStream; |
12 | 14 | use Salient\Tests\TestCase; |
| 15 | +use Salient\Utility\Exception\InvalidArgumentTypeException; |
13 | 16 | use Salient\Utility\File; |
14 | 17 | use Salient\Utility\Get; |
15 | 18 |
|
@@ -447,6 +450,204 @@ public function testCloseAfterLogProgress(): void |
447 | 450 | $this->assertSameTargetOutput("\e[?7l\e[33m⠋ \e[39mStarting\r\e[K\e[?7h"); |
448 | 451 | } |
449 | 452 |
|
| 453 | + /** |
| 454 | + * @backupGlobals enabled |
| 455 | + */ |
| 456 | + public function testException(): void |
| 457 | + { |
| 458 | + $_ENV['DEBUG'] = '0'; |
| 459 | + $console = $this->Console; |
| 460 | + $line = __LINE__ + 1; |
| 461 | + $ex1 = new InvalidArgumentTypeException(1, 'class', 'class-string', 71); |
| 462 | + $ex2 = new Exception('message2', $ex1); |
| 463 | + $ex3 = new MultipleErrorException('message3', 'error1', 'error2'); |
| 464 | + $ex4 = new ExceptionWithMetadata('message4'); |
| 465 | + $console->exception($ex2); |
| 466 | + $console->exception($ex3, Console::LEVEL_ERROR, null); |
| 467 | + $ex3->reportErrors($console); |
| 468 | + $console->exception($ex3, Console::LEVEL_ERROR, null); |
| 469 | + $console->exception($ex4, Console::LEVEL_WARNING); |
| 470 | + $_ENV['DEBUG'] = '1'; |
| 471 | + $console->exception($ex4, Console::LEVEL_WARNING, null, false); |
| 472 | + |
| 473 | + $this->assertSameConsoleMessages([ |
| 474 | + [3, sprintf( |
| 475 | + "! Exception:\n message2 in %s:%d\n Caused by InvalidArgumentTypeException: Argument #1 (\$class) must be of type class-string, int given in %s:%d", |
| 476 | + __FILE__, |
| 477 | + $line + 1, |
| 478 | + __FILE__, |
| 479 | + $line, |
| 480 | + )], |
| 481 | + [7, sprintf( |
| 482 | + ": Stack trace:\n %s", |
| 483 | + str_replace("\n", "\n ", $ex2->getTraceAsString()), |
| 484 | + )], |
| 485 | + [3, sprintf( |
| 486 | + "! MultipleErrorException:\n message3:\n - error1\n - error2 in %s:%d", |
| 487 | + __FILE__, |
| 488 | + $line + 2, |
| 489 | + )], |
| 490 | + [3, 'Error: error1'], |
| 491 | + [3, 'Error: error2'], |
| 492 | + [3, sprintf( |
| 493 | + '! MultipleErrorException: message3 in %s:%d', |
| 494 | + __FILE__, |
| 495 | + $line + 2, |
| 496 | + )], |
| 497 | + [4, '^ ExceptionWithMetadata: message4'], |
| 498 | + [7, sprintf( |
| 499 | + ": Stack trace:\n %s", |
| 500 | + str_replace("\n", "\n ", $ex4->getTraceAsString()), |
| 501 | + )], |
| 502 | + [7, ": foo:\n bar"], |
| 503 | + [7, ": baz:\n 1"], |
| 504 | + [4, sprintf( |
| 505 | + '^ ExceptionWithMetadata: message4 in %s:%d', |
| 506 | + __FILE__, |
| 507 | + $line + 3, |
| 508 | + )], |
| 509 | + ], $this->TtyTarget->getMessages()); |
| 510 | + $this->assertSame(5, $console->errors()); |
| 511 | + $this->assertSame(1, $console->warnings()); |
| 512 | + } |
| 513 | + |
| 514 | + /** |
| 515 | + * @dataProvider summaryProvider |
| 516 | + * |
| 517 | + * @param array<array{Console::LEVEL_*,string,2?:array<string,mixed>}> $expected |
| 518 | + */ |
| 519 | + public function testSummary( |
| 520 | + array $expected, |
| 521 | + int $errors, |
| 522 | + int $warnings, |
| 523 | + string $finishedText = 'Command finished', |
| 524 | + string $successText = 'without errors', |
| 525 | + bool $withResourceUsage = false, |
| 526 | + bool $withoutErrorsAndWarnings = false, |
| 527 | + bool $withGenericType = false, |
| 528 | + bool $expectedHasPatterns = false |
| 529 | + ): void { |
| 530 | + $console = $this->Console; |
| 531 | + for ($i = 0; $i < $errors; $i++) { |
| 532 | + $console->count(Console::LEVEL_ERROR); |
| 533 | + } |
| 534 | + for ($i = 0; $i < $warnings; $i++) { |
| 535 | + $console->count(Console::LEVEL_WARNING); |
| 536 | + } |
| 537 | + $console->summary( |
| 538 | + $finishedText, |
| 539 | + $successText, |
| 540 | + $withResourceUsage, |
| 541 | + $withoutErrorsAndWarnings, |
| 542 | + $withGenericType, |
| 543 | + ); |
| 544 | + |
| 545 | + if ($expectedHasPatterns) { |
| 546 | + $this->assertConsoleMessagesMatch($expected, $this->TtyTarget->getMessages()); |
| 547 | + } else { |
| 548 | + $this->assertSameConsoleMessages($expected, $this->TtyTarget->getMessages()); |
| 549 | + } |
| 550 | + } |
| 551 | + |
| 552 | + /** |
| 553 | + * @return array<array{array<array{Console::LEVEL_*,string,2?:array<string,mixed>}>,int,int,3?:string,4?:string,5?:bool,6?:bool,7?:bool,8?:bool}> |
| 554 | + */ |
| 555 | + public static function summaryProvider(): array |
| 556 | + { |
| 557 | + return [ |
| 558 | + [ |
| 559 | + [[6, '✔ Command finished without errors']], |
| 560 | + 0, |
| 561 | + 0, |
| 562 | + ], |
| 563 | + [ |
| 564 | + [[3, '✘ Command finished with 1 error']], |
| 565 | + 1, |
| 566 | + 0, |
| 567 | + ], |
| 568 | + [ |
| 569 | + [[3, '✘ Command finished with 2 errors and 1 warning']], |
| 570 | + 2, |
| 571 | + 1, |
| 572 | + ], |
| 573 | + [ |
| 574 | + [[4, '✘ Command finished with 0 errors and 2 warnings']], |
| 575 | + 0, |
| 576 | + 2, |
| 577 | + ], |
| 578 | + [ |
| 579 | + [[6, '✔ Done successfully']], |
| 580 | + 0, |
| 581 | + 0, |
| 582 | + 'Done', |
| 583 | + 'successfully', |
| 584 | + false, |
| 585 | + true, |
| 586 | + ], |
| 587 | + [ |
| 588 | + [[6, '» Done']], |
| 589 | + 1, |
| 590 | + 0, |
| 591 | + 'Done', |
| 592 | + 'successfully', |
| 593 | + false, |
| 594 | + true, |
| 595 | + ], |
| 596 | + [ |
| 597 | + [[6, '» Done successfully']], |
| 598 | + 0, |
| 599 | + 0, |
| 600 | + 'Done', |
| 601 | + 'successfully', |
| 602 | + false, |
| 603 | + false, |
| 604 | + true, |
| 605 | + ], |
| 606 | + [ |
| 607 | + [[6, '» Done with 1 error']], |
| 608 | + 1, |
| 609 | + 0, |
| 610 | + 'Done', |
| 611 | + 'successfully', |
| 612 | + false, |
| 613 | + false, |
| 614 | + true, |
| 615 | + ], |
| 616 | + [ |
| 617 | + [[6, '» Done with 0 errors and 2 warnings']], |
| 618 | + 0, |
| 619 | + 2, |
| 620 | + 'Done', |
| 621 | + 'successfully', |
| 622 | + false, |
| 623 | + false, |
| 624 | + true, |
| 625 | + ], |
| 626 | + [ |
| 627 | + [[6, '/^✔ Done successfully in (0|[1-9][0-9]*+)\.[0-9]{3}s \((0|[1-9][0-9]*+)\.[0-9]{3}(B|[KMGTPEZY]iB) memory used\)$/D']], |
| 628 | + 0, |
| 629 | + 0, |
| 630 | + 'Done', |
| 631 | + 'successfully', |
| 632 | + true, |
| 633 | + false, |
| 634 | + false, |
| 635 | + true, |
| 636 | + ], |
| 637 | + [ |
| 638 | + [[3, '/^✘ Done with 1 error in (0|[1-9][0-9]*+)\.[0-9]{3}s \((0|[1-9][0-9]*+)\.[0-9]{3}(B|[KMGTPEZY]iB) memory used\)$/D']], |
| 639 | + 1, |
| 640 | + 0, |
| 641 | + 'Done', |
| 642 | + 'successfully', |
| 643 | + true, |
| 644 | + false, |
| 645 | + false, |
| 646 | + true, |
| 647 | + ], |
| 648 | + ]; |
| 649 | + } |
| 650 | + |
450 | 651 | /** |
451 | 652 | * @return array{int<0,max>,float|null} |
452 | 653 | */ |
@@ -504,3 +705,14 @@ protected function applyStream($stream): void |
504 | 705 | $this->IsTty = true; |
505 | 706 | } |
506 | 707 | } |
| 708 | + |
| 709 | +class ExceptionWithMetadata extends Exception |
| 710 | +{ |
| 711 | + public function getMetadata(): array |
| 712 | + { |
| 713 | + return [ |
| 714 | + 'foo' => 'bar', |
| 715 | + 'baz' => 1, |
| 716 | + ]; |
| 717 | + } |
| 718 | +} |
0 commit comments