Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F15386908
D19711.id47125.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
17 KB
Referenced Files
None
Subscribers
None
D19711.id47125.diff
View Options
diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -165,7 +165,7 @@
'ArcanistDeclarationParenthesesXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistDeclarationParenthesesXHPASTLinterRuleTestCase.php',
'ArcanistDefaultParametersXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistDefaultParametersXHPASTLinterRule.php',
'ArcanistDefaultParametersXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistDefaultParametersXHPASTLinterRuleTestCase.php',
- 'ArcanistDefaultUnitFormatter' => 'unit/formatter/ArcanistDefaultUnitFormatter.php',
+ 'ArcanistDefaultUnitSink' => 'unit/sink/ArcanistDefaultUnitSink.php',
'ArcanistDefaultsConfigurationSource' => 'config/source/ArcanistDefaultsConfigurationSource.php',
'ArcanistDeprecationXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistDeprecationXHPASTLinterRule.php',
'ArcanistDeprecationXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistDeprecationXHPASTLinterRuleTestCase.php',
@@ -279,7 +279,7 @@
'ArcanistJSONLintRenderer' => 'lint/renderer/ArcanistJSONLintRenderer.php',
'ArcanistJSONLinter' => 'lint/linter/ArcanistJSONLinter.php',
'ArcanistJSONLinterTestCase' => 'lint/linter/__tests__/ArcanistJSONLinterTestCase.php',
- 'ArcanistJSONUnitFormatter' => 'unit/formatter/ArcanistJSONUnitFormatter.php',
+ 'ArcanistJSONUnitSink' => 'unit/sink/ArcanistJSONUnitSink.php',
'ArcanistJscsLinter' => 'lint/linter/ArcanistJscsLinter.php',
'ArcanistJscsLinterTestCase' => 'lint/linter/__tests__/ArcanistJscsLinterTestCase.php',
'ArcanistKeywordCasingXHPASTLinterRule' => 'lint/linter/xhpast/rules/ArcanistKeywordCasingXHPASTLinterRule.php',
@@ -473,9 +473,9 @@
'ArcanistUnexpectedReturnValueXHPASTLinterRuleTestCase' => 'lint/linter/xhpast/rules/__tests__/ArcanistUnexpectedReturnValueXHPASTLinterRuleTestCase.php',
'ArcanistUnitConsoleRenderer' => 'unit/renderer/ArcanistUnitConsoleRenderer.php',
'ArcanistUnitEngine' => 'unit/engine/ArcanistUnitEngine.php',
- 'ArcanistUnitFormatter' => 'unit/formatter/ArcanistUnitFormatter.php',
'ArcanistUnitOverseer' => 'unit/overseer/ArcanistUnitOverseer.php',
'ArcanistUnitRenderer' => 'unit/renderer/ArcanistUnitRenderer.php',
+ 'ArcanistUnitSink' => 'unit/sink/ArcanistUnitSink.php',
'ArcanistUnitTestResult' => 'unit/ArcanistUnitTestResult.php',
'ArcanistUnitTestResultTestCase' => 'unit/__tests__/ArcanistUnitTestResultTestCase.php',
'ArcanistUnitTestableLintEngine' => 'lint/engine/ArcanistUnitTestableLintEngine.php',
@@ -1276,7 +1276,7 @@
'ArcanistDeclarationParenthesesXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistDefaultParametersXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistDefaultParametersXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
- 'ArcanistDefaultUnitFormatter' => 'ArcanistUnitFormatter',
+ 'ArcanistDefaultUnitSink' => 'ArcanistUnitSink',
'ArcanistDefaultsConfigurationSource' => 'ArcanistDictionaryConfigurationSource',
'ArcanistDeprecationXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
'ArcanistDeprecationXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
@@ -1390,7 +1390,7 @@
'ArcanistJSONLintRenderer' => 'ArcanistLintRenderer',
'ArcanistJSONLinter' => 'ArcanistLinter',
'ArcanistJSONLinterTestCase' => 'ArcanistLinterTestCase',
- 'ArcanistJSONUnitFormatter' => 'ArcanistUnitFormatter',
+ 'ArcanistJSONUnitSink' => 'ArcanistUnitSink',
'ArcanistJscsLinter' => 'ArcanistExternalLinter',
'ArcanistJscsLinterTestCase' => 'ArcanistExternalLinterTestCase',
'ArcanistKeywordCasingXHPASTLinterRule' => 'ArcanistXHPASTLinterRule',
@@ -1584,9 +1584,9 @@
'ArcanistUnexpectedReturnValueXHPASTLinterRuleTestCase' => 'ArcanistXHPASTLinterRuleTestCase',
'ArcanistUnitConsoleRenderer' => 'ArcanistUnitRenderer',
'ArcanistUnitEngine' => 'Phobject',
- 'ArcanistUnitFormatter' => 'Phobject',
'ArcanistUnitOverseer' => 'Phobject',
'ArcanistUnitRenderer' => 'Phobject',
+ 'ArcanistUnitSink' => 'Phobject',
'ArcanistUnitTestResult' => 'Phobject',
'ArcanistUnitTestResultTestCase' => 'PhutilTestCase',
'ArcanistUnitTestableLintEngine' => 'ArcanistLintEngine',
diff --git a/src/unit/ArcanistUnitTestResult.php b/src/unit/ArcanistUnitTestResult.php
--- a/src/unit/ArcanistUnitTestResult.php
+++ b/src/unit/ArcanistUnitTestResult.php
@@ -175,13 +175,8 @@
}
public static function getAllResultCodes() {
- return array(
- self::RESULT_PASS,
- self::RESULT_FAIL,
- self::RESULT_SKIP,
- self::RESULT_BROKEN,
- self::RESULT_UNSOUND,
- );
+ $map = self::getResultCodeSpecs();
+ return array_keys($map);
}
public static function getResultCodeName($result_code) {
@@ -205,31 +200,56 @@
return idx($specs, $result_code);
}
+ public function getANSIColor() {
+ $spec = $this->getResultMap();
+ return idx($spec, 'color.ansi', 'red');
+ }
+
+ public function getResultLabel() {
+ $spec = $this->getResultMap();
+ return idx($spec, 'label', $this->getResult());
+ }
+
+ private function getResultMap() {
+ $map = self::getResultCodeSpecs();
+ return idx($map, $this->getResult(), array());
+ }
+
private static function getResultCodeSpecs() {
return array(
self::RESULT_PASS => array(
'name' => pht('Pass'),
+ 'label' => pht('PASS'),
+ 'color.ansi' => 'green',
'description' => pht(
'The test passed.'),
),
self::RESULT_FAIL => array(
'name' => pht('Fail'),
+ 'label' => pht('FAIL'),
+ 'color.ansi' => 'red',
'description' => pht(
'The test failed.'),
),
self::RESULT_SKIP => array(
'name' => pht('Skip'),
+ 'label' => pht('SKIP'),
+ 'color.ansi' => 'cyan',
'description' => pht(
'The test was not executed.'),
),
self::RESULT_BROKEN => array(
'name' => pht('Broken'),
+ 'label' => pht('BROKEN'),
+ 'color.ansi' => 'red',
'description' => pht(
'The test failed in an abnormal or severe way. For example, the '.
'harness crashed instead of reporting a failure.'),
),
self::RESULT_UNSOUND => array(
'name' => pht('Unsound'),
+ 'label' => pht('UNSOUND'),
+ 'color.ansi' => 'yellow',
'description' => pht(
'The test failed, but this change is probably not what broke it. '.
'For example, it might have already been failing.'),
@@ -237,5 +257,15 @@
);
}
+ public function getDisplayName() {
+ $name = $this->getName();
+
+ $namespace = $this->getNamespace();
+ if (strlen($namespace)) {
+ $name = $namespace.'::'.$name;
+ }
+
+ return $name;
+ }
}
diff --git a/src/unit/engine/ArcanistUnitEngine.php b/src/unit/engine/ArcanistUnitEngine.php
--- a/src/unit/engine/ArcanistUnitEngine.php
+++ b/src/unit/engine/ArcanistUnitEngine.php
@@ -56,14 +56,7 @@
abstract public function runTests();
final protected function didRunTests(array $tests) {
- assert_instances_of($tests, 'ArcanistUnitTestResult');
-
- // TOOLSETS: Pass this stuff to result output so it can print progress or
- // stream results.
-
- foreach ($tests as $test) {
- echo "Ran Test: ".$test->getNamespace().'::'.$test->getName()."\n";
- }
+ return $this->getOverseer()->didRunTests($tests);
}
}
\ No newline at end of file
diff --git a/src/unit/formatter/ArcanistDefaultUnitFormatter.php b/src/unit/formatter/ArcanistDefaultUnitFormatter.php
deleted file mode 100644
--- a/src/unit/formatter/ArcanistDefaultUnitFormatter.php
+++ /dev/null
@@ -1,9 +0,0 @@
-<?php
-
-final class ArcanistDefaultUnitFormatter
- extends ArcanistUnitFormatter {
-
- const FORMATTER_KEY = 'default';
-
-
-}
diff --git a/src/unit/formatter/ArcanistJSONUnitFormatter.php b/src/unit/formatter/ArcanistJSONUnitFormatter.php
deleted file mode 100644
--- a/src/unit/formatter/ArcanistJSONUnitFormatter.php
+++ /dev/null
@@ -1,9 +0,0 @@
-<?php
-
-final class ArcanistJSONUnitFormatter
- extends ArcanistUnitFormatter {
-
- const FORMATTER_KEY = 'json';
-
-
-}
diff --git a/src/unit/formatter/ArcanistUnitFormatter.php b/src/unit/formatter/ArcanistUnitFormatter.php
deleted file mode 100644
--- a/src/unit/formatter/ArcanistUnitFormatter.php
+++ /dev/null
@@ -1,17 +0,0 @@
-<?php
-
-abstract class ArcanistUnitFormatter
- extends Phobject {
-
- final public function getUnitFormatterKey() {
- return $this->getPhobjectClassConstant('FORMATTER_KEY');
- }
-
- public static function getAllUnitFormatters() {
- return id(new PhutilClassMapQuery())
- ->setAncestorClass(__CLASS__)
- ->setUniqueMethod('getUnitFormatterKey')
- ->execute();
- }
-
-}
diff --git a/src/unit/overseer/ArcanistUnitOverseer.php b/src/unit/overseer/ArcanistUnitOverseer.php
--- a/src/unit/overseer/ArcanistUnitOverseer.php
+++ b/src/unit/overseer/ArcanistUnitOverseer.php
@@ -5,9 +5,9 @@
private $directory;
private $paths = array();
- private $formatter;
+ private $sinks = array();
- public function setPaths($paths) {
+ public function setPaths(array $paths) {
$this->paths = $paths;
return $this;
}
@@ -16,13 +16,14 @@
return $this->paths;
}
- public function setFormatter(ArcanistUnitFormatter $formatter) {
- $this->formatter = $formatter;
+ public function setSinks(array $sinks) {
+ assert_instances_of($sinks, 'ArcanistUnitSink');
+ $this->sinks = $sinks;
return $this;
}
- public function getFormatter() {
- return $this->formatter;
+ public function getSinks() {
+ return $this->sinks;
}
public function setDirectory($directory) {
@@ -50,9 +51,27 @@
}
}
+ $this->didCompleteTests($results);
+
return $results;
}
+ public function didRunTests(array $tests) {
+ assert_instances_of($tests, 'ArcanistUnitTestResult');
+
+ foreach ($this->getSinks() as $sink) {
+ $sink->sinkPartialResults($tests);
+ }
+ }
+
+ private function didCompleteTests(array $tests) {
+ assert_instances_of($tests, 'ArcanistUnitTestResult');
+
+ foreach ($this->getSinks() as $sink) {
+ $sink->sinkFinalResults($tests);
+ }
+ }
+
private function loadEngines() {
$root = $this->getDirectory();
diff --git a/src/unit/sink/ArcanistDefaultUnitSink.php b/src/unit/sink/ArcanistDefaultUnitSink.php
new file mode 100644
--- /dev/null
+++ b/src/unit/sink/ArcanistDefaultUnitSink.php
@@ -0,0 +1,169 @@
+<?php
+
+final class ArcanistDefaultUnitSink
+ extends ArcanistUnitSink {
+
+ const SINKKEY = 'default';
+
+ private $lastUpdateTime;
+ private $buffer = array();
+
+ public function sinkPartialResults(array $results) {
+
+ // We want to show the user both regular progress reports and make sure
+ // that important results aren't scrolled off screen. We'll print a summary
+ // at the end so it's not critical that users can never miss important
+ // results, but they may (for example) want to ^C early if tests fail and
+ // their fate is sealed.
+
+
+ $failed = array();
+ foreach ($results as $result) {
+ $result_code = $result->getResult();
+ switch ($result_code) {
+ case ArcanistUnitTestResult::RESULT_PASS:
+ case ArcanistUnitTestResult::RESULT_SKIP:
+ break;
+ default:
+ $failed[] = $result;
+ break;
+ }
+ }
+
+ $now = microtime(true);
+
+ if (!$failed) {
+ if ($this->lastUpdateTime) {
+ $delay = 1;
+ if (($now - $this->lastUpdateTime) < $delay) {
+ $this->buffer[] = $results;
+ return;
+ }
+ }
+ }
+
+ $this->buffer[] = $results;
+ $results = array_mergev($this->buffer);
+ $this->buffer = array();
+
+ $pass_count = 0;
+ $skip_count = 0;
+ $failed = array();
+ foreach ($results as $result) {
+ $result_code = $result->getResult();
+ switch ($result_code) {
+ case ArcanistUnitTestResult::RESULT_PASS:
+ $pass_count++;
+ break;
+ case ArcanistUnitTestResult::RESULT_SKIP:
+ $skip_count++;
+ break;
+ default:
+ $failed[] = $result;
+ break;
+ }
+ }
+
+ if ($pass_count) {
+ echo tsprintf(
+ "%s\n",
+ pht('%s tests passed.', $pass_count));
+ }
+
+ if ($skip_count) {
+ echo tsprintf(
+ "%s\n",
+ pht('%s tests skipped.', $skip_count));
+ }
+
+ foreach ($failed as $result) {
+ echo $this->getDisplayForTest($result, false);
+ }
+
+ $this->lastUpdateTime = $now;
+
+ return $this;
+ }
+
+ public function sinkFinalResults(array $results) {
+
+ $passed = array();
+ $skipped = array();
+ $failed = array();
+ foreach ($results as $result) {
+ $result_code = $result->getResult();
+ switch ($result_code) {
+ case ArcanistUnitTestResult::RESULT_PASS:
+ $passed[] = $result;
+ break;
+ case ArcanistUnitTestResult::RESULT_SKIP:
+ $skipped[] = $result;
+ break;
+ default:
+ $failed[] = $result;
+ break;
+ }
+ }
+
+ echo tsprintf(
+ "%s\n",
+ pht('RESULT SUMMARY'));
+
+
+ if ($skipped) {
+ echo tsprintf(
+ "%s\n",
+ pht('SKIPPED TESTS'));
+
+ foreach ($skipped as $result) {
+ echo $this->getDisplayForTest($result);
+ }
+ }
+
+ if ($failed) {
+ echo tsprintf(
+ "%s\n",
+ pht('FAILED TESTS'));
+
+ foreach ($failed as $result) {
+ echo $this->getDisplayForTest($result);
+ }
+ }
+
+
+ echo tsprintf(
+ "**<bg:red> ~~~ %s </bg>**\n",
+ pht(
+ "%s PASSED * %s SKIPPED * %s FAILED/BROKEN/UNSTABLE",
+ phutil_count($passed),
+ phutil_count($skipped),
+ phutil_count($failed)));
+ }
+
+ private function getDisplayForTest(ArcanistUnitTestResult $result) {
+
+ $color = $result->getANSIColor();
+ $status = $result->getResultLabel();
+ $name = $result->getDisplayName();
+
+ // TOOLSETS: Restore timing information.
+ $timing = ' ';
+
+ $output = tsprintf(
+ "**<bg:".$color."> %s </bg>** %s %s\n",
+ $status,
+ $timing,
+ $name);
+
+ $user_data = $result->getUserData();
+ if (strlen($user_data)) {
+ $output = tsprintf(
+ "%s%B\n",
+ $output,
+ $user_data);
+ }
+
+ return $output;
+ }
+
+}
diff --git a/src/unit/sink/ArcanistJSONUnitSink.php b/src/unit/sink/ArcanistJSONUnitSink.php
new file mode 100644
--- /dev/null
+++ b/src/unit/sink/ArcanistJSONUnitSink.php
@@ -0,0 +1,9 @@
+<?php
+
+final class ArcanistJSONUnitSink
+ extends ArcanistUnitSink {
+
+ const SINKKEY = 'json';
+
+
+}
diff --git a/src/unit/sink/ArcanistUnitSink.php b/src/unit/sink/ArcanistUnitSink.php
new file mode 100644
--- /dev/null
+++ b/src/unit/sink/ArcanistUnitSink.php
@@ -0,0 +1,31 @@
+<?php
+
+abstract class ArcanistUnitSink
+ extends Phobject {
+
+ private $results;
+
+ final public function getUnitSinkKey() {
+ return $this->getPhobjectClassConstant('SINKKEY');
+ }
+
+ public static function getAllUnitSinks() {
+ return id(new PhutilClassMapQuery())
+ ->setAncestorClass(__CLASS__)
+ ->setUniqueMethod('getUnitSinkKey')
+ ->execute();
+ }
+
+ public function sinkPartialResults(array $results) {
+ return $this;
+ }
+
+ public function sinkFinalResults(array $results) {
+ return $this;
+ }
+
+ public function getOutput() {
+ return null;
+ }
+
+}
diff --git a/src/workflow/ArcanistUnitWorkflow.php b/src/workflow/ArcanistUnitWorkflow.php
--- a/src/workflow/ArcanistUnitWorkflow.php
+++ b/src/workflow/ArcanistUnitWorkflow.php
@@ -23,7 +23,7 @@
return array(
$this->newWorkflowArgument('commit')
->setParameter('commit'),
- $this->newWorkflowArgument('format')
+ $this->newWorkflowArgument('sink')
->setParameter('format'),
$this->newWorkflowArgument('everything'),
$this->newWorkflowArgument('paths')
@@ -51,32 +51,40 @@
// though it is "arc unit --everything", and ignoring the "--commit" flag
// and "paths" arguments.
- $formatter = $this->newUnitFormatter();
- $overseer->setFormatter($formatter);
+ $sinks = array();
+ $sinks[] = $this->newUnitSink();
+ $overseer->setSinks($sinks);
$overseer->execute();
+ foreach ($sinks as $sink) {
+ $result = $sink->getOutput();
+ if ($result !== null) {
+ echo $result;
+ }
+ }
+
return 0;
}
- private function newUnitFormatter() {
- $formatters = ArcanistUnitFormatter::getAllUnitFormatters();
- $format_key = $this->getArgument('format');
- if (!strlen($format_key)) {
- $format_key = ArcanistDefaultUnitFormatter::FORMATTER_KEY;
+ private function newUnitSink() {
+ $sinks = ArcanistUnitSink::getAllUnitSinks();
+ $sink_key = $this->getArgument('sink');
+ if (!strlen($sink_key)) {
+ $sink_key = ArcanistDefaultUnitSink::SINKKEY;
}
- $formatter = idx($formatters, $format_key);
- if (!$formatter) {
+ $sink = idx($sinks, $sink_key);
+ if (!$sink) {
throw new ArcanistUsageException(
pht(
- 'Unit test output format ("%s") is unknown. Supported formats '.
+ 'Unit test output sink ("%s") is unknown. Supported sinks '.
'are: %s.',
- $format_key,
- implode(', ', array_keys($formatters))));
+ $sink_key,
+ implode(', ', array_keys($sinks))));
}
- return $formatter;
+ return $sink;
}
}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sun, Mar 16, 1:30 AM (6 d, 3 h ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7704951
Default Alt Text
D19711.id47125.diff (17 KB)
Attached To
Mode
D19711: [Wilds] Rename "formatters" to "sinks" and restore the console output sufficiently to see which tests are failing
Attached
Detach File
Event Timeline
Log In to Comment