Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F88678
D7594.diff
All Users
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
11 KB
Referenced Files
None
Subscribers
None
D7594.diff
View Options
diff --git a/src/unit/engine/CSharpToolsTestEngine.php b/src/unit/engine/CSharpToolsTestEngine.php
--- a/src/unit/engine/CSharpToolsTestEngine.php
+++ b/src/unit/engine/CSharpToolsTestEngine.php
@@ -128,6 +128,9 @@
}
}
}
+ if (count($assemblies_to_instrument) === 0) {
+ return parent::buildTestFuture($test_assembly);
+ }
$future = new ExecFuture(
"%C -o %s -c %s -a %s -w %s %Ls",
trim($this->runtimeEngine." ".$this->coverEngine),
diff --git a/src/unit/engine/XUnitTestEngine.php b/src/unit/engine/XUnitTestEngine.php
--- a/src/unit/engine/XUnitTestEngine.php
+++ b/src/unit/engine/XUnitTestEngine.php
@@ -17,6 +17,7 @@
protected $testEngine;
protected $projectRoot;
protected $xunitHintPath;
+ protected $discoveryRules;
/**
* This test engine supports running all tests.
@@ -54,16 +55,24 @@
throw new Exception("Unable to find Mono and you are not on Windows!");
}
+ // Read the discovery rules.
+ $this->discoveryRules =
+ $this->getConfigurationManager()->getConfigFromAnySource(
+ 'unit.csharp.discovery');
+ if ($this->discoveryRules === null) {
+ throw new Exception(
+ "You must configure discovery rules to map C# files ".
+ "back to test projects (`unit.csharp.discovery` in .arcconfig).");
+ }
+
// Determine xUnit test runner path.
if ($this->xunitHintPath === null) {
$this->xunitHintPath =
$this->getConfigurationManager()->getConfigFromAnySource(
- 'unit.xunit.binary');
- }
- if ($this->xunitHintPath === null) {
+ 'unit.csharp.xunit.binary');
}
- $xunit = $this->projectRoot."/".$this->xunitHintPath;
- if (file_exists($xunit)) {
+ $xunit = $this->projectRoot.DIRECTORY_SEPARATOR.$this->xunitHintPath;
+ if (file_exists($xunit) && $this->xunitHintPath !== null) {
$this->testEngine = Filesystem::resolvePath($xunit);
} else if (Filesystem::binaryExists("xunit.console.clr4.exe")) {
$this->testEngine = "xunit.console.clr4.exe";
@@ -75,39 +84,6 @@
}
/**
- * Returns all available tests and related projects. Recurses into
- * Protobuild submodules if they are present.
- *
- * @return array Mappings of test project to project being tested.
- */
- public function getAllAvailableTestsAndRelatedProjects($path = null) {
- if ($path == null) {
- $path = $this->projectRoot;
- }
- $entries = Filesystem::listDirectory($path);
- $mappings = array();
- foreach ($entries as $entry) {
- if (substr($entry, -6) === ".Tests") {
- if (is_dir($path."/".$entry)) {
- $mappings[$path."/".$entry] = $path."/".
- substr($entry, 0, strlen($entry) - 6);
- }
- } elseif (is_dir($path."/".$entry."/Build")) {
- if (file_exists($path."/".$entry."/Build/Module.xml")) {
- // The entry is a Protobuild submodule, which we should
- // also recurse into.
- $submappings =
- $this->getAllAvailableTestsAndRelatedProjects($path."/".$entry);
- foreach ($submappings as $key => $value) {
- $mappings[$key] = $value;
- }
- }
- }
- }
- return $mappings;
- }
-
- /**
* Main entry point for the test engine. Determines what assemblies to
* build and test based on the files that have changed.
*
@@ -117,69 +93,82 @@
$this->loadEnvironment();
- $affected_tests = array();
if ($this->getRunAllTests()) {
- echo "Loading tests..."."\n";
- $entries = $this->getAllAvailableTestsAndRelatedProjects();
- foreach ($entries as $key => $value) {
- echo "Test: ".substr($key, strlen($this->projectRoot) + 1)."\n";
- $affected_tests[] = substr($key, strlen($this->projectRoot) + 1);
- }
+ $paths = id(new FileFinder($this->projectRoot))->find();
} else {
$paths = $this->getPaths();
+ }
+
+ return $this->runAllTests($this->mapPathsToResults($paths));
+ }
+ /**
+ * Applies the discovery rules to the set of paths specified.
+ *
+ * @param array Array of paths.
+ * @return array Array of paths to test projects and assemblies.
+ */
+ public function mapPathsToResults(array $paths) {
+ $results = array();
+ foreach ($this->discoveryRules as $regex => $targets) {
+ $regex = str_replace('/', '\\/', $regex);
foreach ($paths as $path) {
- if (substr($path, -4) == ".dll" ||
- substr($path, -4) == ".mdb") {
- continue;
- }
- if (substr_count($path, "/") > 0) {
- $components = explode("/", $path);
- $affected_assembly = $components[0];
-
- // If the change is made inside an assembly that has a `.Tests`
- // extension, then the developer has changed the actual tests.
- if (substr($affected_assembly, -6) === ".Tests") {
- $affected_assembly_path = Filesystem::resolvePath(
- $affected_assembly);
- $test_assembly = $affected_assembly;
- } else {
- $affected_assembly_path = Filesystem::resolvePath(
- $affected_assembly.".Tests");
- $test_assembly = $affected_assembly.".Tests";
- }
- if (is_dir($affected_assembly_path) &&
- !in_array($test_assembly, $affected_tests)) {
- $affected_tests[] = $test_assembly;
+ if (preg_match('/'.$regex.'/', $path) === 1) {
+ foreach ($targets as $target) {
+ // Index 0 is the test project (.csproj file)
+ // Index 1 is the output assembly (.dll file)
+ $project = preg_replace('/'.$regex.'/', $target[0], $path);
+ $project = $this->projectRoot.DIRECTORY_SEPARATOR.$project;
+ $assembly = preg_replace('/'.$regex.'/', $target[1], $path);
+ $assembly = $this->projectRoot.DIRECTORY_SEPARATOR.$assembly;
+ if (file_exists($project)) {
+ $project = Filesystem::resolvePath($project);
+ $assembly = Filesystem::resolvePath($assembly);
+
+ // Check to ensure uniqueness.
+ $exists = false;
+ foreach ($results as $existing) {
+ if ($existing['assembly'] === $assembly) {
+ $exists = true;
+ break;
+ }
+ }
+
+ if (!$exists) {
+ print "Discovered test at ".$assembly."\n";
+ $results[] = array(
+ 'project' => $project,
+ 'assembly' => $assembly);
+ }
+ }
}
}
}
}
-
- return $this->runAllTests($affected_tests);
+ return $results;
}
/**
* Builds and runs the specified test assemblies.
*
- * @param array Array of test assemblies.
+ * @param array Array of paths to test project files.
* @return array Array of test results.
*/
- public function runAllTests(array $test_assemblies) {
- if (empty($test_assemblies)) {
+ public function runAllTests(array $test_projects) {
+ if (empty($test_projects)) {
return array();
}
$results = array();
$results[] = $this->generateProjects();
if ($this->resultsContainFailures($results)) {
return array_mergev($results);
}
- $results[] = $this->buildProjects($test_assemblies);
+ $results[] = $this->buildProjects($test_projects);
if ($this->resultsContainFailures($results)) {
return array_mergev($results);
}
- $results[] = $this->testAssemblies($test_assemblies);
+ $results[] = $this->testAssemblies($test_projects);
return array_mergev($results);
}
@@ -220,6 +209,13 @@
return array();
}
+ // No "Protobuild.exe" file; so skip generation of projects.
+ if (!is_file(Filesystem::resolvePath(
+ $this->projectRoot."/Protobuild.exe"))) {
+
+ return array();
+ }
+
// Work out what platform the user is building for already.
$platform = phutil_is_windows() ? "Windows" : "Linux";
$files = Filesystem::listDirectory($this->projectRoot);
@@ -280,8 +276,8 @@
$this->buildEngine,
"/p:SkipTestsOnBuild=True");
$build_future->setCWD(Filesystem::resolvePath(
- $this->projectRoot."/".$test_assembly));
- $build_futures[$test_assembly] = $build_future;
+ dirname($test_assembly['project'])));
+ $build_futures[$test_assembly['project']] = $build_future;
}
$iterator = Futures($build_futures)->limit(1);
foreach ($iterator as $test_assembly => $future) {
@@ -319,17 +315,22 @@
// FIXME: Can't use TempFile here as xUnit doesn't like
// UNIX-style full paths. It sees the leading / as the
// start of an option flag, even when quoted.
- $xunit_temp = $test_assembly.".results.xml";
+ $xunit_temp = Filesystem::readRandomCharacters(10).".results.xml";
if (file_exists($xunit_temp)) {
unlink($xunit_temp);
}
$future = new ExecFuture(
- "%C %s /xml %s /silent",
+ "%C %s /xml %s",
trim($this->runtimeEngine." ".$this->testEngine),
- $test_assembly."/bin/Debug/".$test_assembly.".dll",
+ $test_assembly,
$xunit_temp);
- $future->setCWD(Filesystem::resolvePath($this->projectRoot));
- return array($future, $xunit_temp, null);
+ $folder = Filesystem::resolvePath($this->projectRoot);
+ $future->setCWD($folder);
+ $combined = $folder."/".$xunit_temp;
+ if (phutil_is_windows()) {
+ $combined = $folder."\\".$xunit_temp;
+ }
+ return array($future, $combined, null);
}
/**
@@ -348,29 +349,33 @@
$outputs = array();
$coverages = array();
foreach ($test_assemblies as $test_assembly) {
- list($future, $xunit_temp, $coverage) =
- $this->buildTestFuture($test_assembly);
- $futures[$test_assembly] = $future;
- $outputs[$test_assembly] = $xunit_temp;
- $coverages[$test_assembly] = $coverage;
+ list($future_r, $xunit_temp, $coverage) =
+ $this->buildTestFuture($test_assembly['assembly']);
+ $futures[$test_assembly['assembly']] = $future_r;
+ $outputs[$test_assembly['assembly']] = $xunit_temp;
+ $coverages[$test_assembly['assembly']] = $coverage;
}
// Run all of the tests.
- foreach (Futures($futures) as $test_assembly => $future) {
- $future->resolve();
+ foreach (Futures($futures)->limit(8) as $test_assembly => $future) {
+ list($err, $stdout, $stderr) = $future->resolve();
if (file_exists($outputs[$test_assembly])) {
$result = $this->parseTestResult(
$outputs[$test_assembly],
$coverages[$test_assembly]);
$results[] = $result;
unlink($outputs[$test_assembly]);
} else {
- $result = new ArcanistUnitTestResult();
- $result->setName("(execute) ".$test_assembly);
- $result->setResult(ArcanistUnitTestResult::RESULT_BROKEN);
- $result->setUserData($outputs[$test_assembly]." not found on disk.");
- $results[] = array($result);
+ // FIXME: There's a bug in Mono which causes a segmentation fault
+ // when xUnit.NET runs; this causes the XML file to not appear
+ // (depending on when the segmentation fault occurs). See
+ // https://bugzilla.xamarin.com/show_bug.cgi?id=16379
+ // for more information.
+
+ // Since it's not possible for the user to correct this error, we
+ // ignore the fact the tests didn't run here.
+ //
}
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Storage Engine
amazon-s3
Storage Format
Raw Data
Storage Handle
phabricator/ak/jc/cbkec2kmpzfu3len
Default Alt Text
D7594.diff (11 KB)
Attached To
Mode
D7594: Fix issues in C# unit test engine
Attached
Detach File
Event Timeline
Log In to Comment