Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F15395466
D19729.id.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
26 KB
Referenced Files
None
Subscribers
None
D19729.id.diff
View Options
diff --git a/src/__tests__/PhutilLibraryTestCase.php b/src/__tests__/PhutilLibraryTestCase.php
--- a/src/__tests__/PhutilLibraryTestCase.php
+++ b/src/__tests__/PhutilLibraryTestCase.php
@@ -24,6 +24,8 @@
* that all the library map is up-to-date.
*/
public function testLibraryMap() {
+ $this->assertExecutable('xhpast');
+
$root = $this->getLibraryRoot();
$library = phutil_get_library_name_for_root($root);
diff --git a/src/channel/__tests__/PhutilPHPObjectProtocolChannelTestCase.php b/src/channel/__tests__/PhutilPHPObjectProtocolChannelTestCase.php
--- a/src/channel/__tests__/PhutilPHPObjectProtocolChannelTestCase.php
+++ b/src/channel/__tests__/PhutilPHPObjectProtocolChannelTestCase.php
@@ -45,7 +45,9 @@
}
public function testCloseExecWriteChannel() {
- $future = new ExecFuture('cat');
+ $bin = $this->getSupportExecutable('cat');
+
+ $future = new ExecFuture('php -f %R', $bin);
// If this test breaks, we want to explode, not hang forever.
$future->setTimeout(5);
diff --git a/src/filesystem/Filesystem.php b/src/filesystem/Filesystem.php
--- a/src/filesystem/Filesystem.php
+++ b/src/filesystem/Filesystem.php
@@ -898,8 +898,23 @@
// This won't work if the file doesn't exist or is on an unreadable mount
// or something crazy like that. Try to resolve a parent so we at least
// cover the nonexistent file case.
- $parts = explode(DIRECTORY_SEPARATOR, trim($path, DIRECTORY_SEPARATOR));
- while (end($parts) !== false) {
+
+ // We're also normalizing path separators to whatever is normal for the
+ // environment.
+
+ if (phutil_is_windows()) {
+ $parts = trim($path, '/\\');
+ $parts = preg_split('([/\\\\])', $parts);
+
+ // Normalize the directory separators in the path. If we find a parent
+ // below, we'll overwrite this with a better resolved path.
+ $path = str_replace('/', '\\', $path);
+ } else {
+ $parts = trim($path, '/');
+ $parts = explode('/', $parts);
+ }
+
+ while ($parts) {
array_pop($parts);
if (phutil_is_windows()) {
$attempt = implode(DIRECTORY_SEPARATOR, $parts);
diff --git a/src/filesystem/__tests__/FileFinderTestCase.php b/src/filesystem/__tests__/FileFinderTestCase.php
--- a/src/filesystem/__tests__/FileFinderTestCase.php
+++ b/src/filesystem/__tests__/FileFinderTestCase.php
@@ -125,6 +125,16 @@
}
public function testFinderWithGlobMagic() {
+ if (phutil_is_windows()) {
+ // We can't write files with "\" since this is the path separator.
+ // We can't write files with "*" since Windows rejects them.
+ // This doesn't leave us too many interesting paths to test, so just
+ // skip this test case under Windows.
+ $this->assertSkipped(
+ pht(
+ 'Windows can not write files with sufficiently absurd names.'));
+ }
+
// Fill a temporary directory with all this magic garbage so we don't have
// to check a bunch of files with backslashes in their names into version
// control.
@@ -209,8 +219,12 @@
private function assertFinder($label, FileFinder $finder, $expect) {
$modes = array(
'php',
- 'shell',
);
+
+ if (!phutil_is_windows()) {
+ $modes[] = 'shell';
+ }
+
foreach ($modes as $mode) {
$actual = id(clone $finder)
->setForceMode($mode)
diff --git a/src/filesystem/__tests__/FilesystemTestCase.php b/src/filesystem/__tests__/FilesystemTestCase.php
--- a/src/filesystem/__tests__/FilesystemTestCase.php
+++ b/src/filesystem/__tests__/FilesystemTestCase.php
@@ -111,22 +111,17 @@
array(),
),
- 'fictional paths work' => array(
- '/x/y/z',
- '/',
- array(
- '/x/y/z',
- '/x/y',
- '/x',
- '/',
- ),
- ),
-
);
foreach ($test_cases as $test_case) {
list($path, $root, $expected) = $test_case;
+ // On Windows, paths will have backslashes rather than forward slashes.
+ // Normalize our expectations to the path format for the environment.
+ foreach ($expected as $key => $epath) {
+ $expected[$key] = str_replace('/', DIRECTORY_SEPARATOR, $epath);
+ }
+
$this->assertEqual(
$expected,
Filesystem::walkToRoot($path, $root));
diff --git a/src/filesystem/__tests__/PhutilDeferredLogTestCase.php b/src/filesystem/__tests__/PhutilDeferredLogTestCase.php
--- a/src/filesystem/__tests__/PhutilDeferredLogTestCase.php
+++ b/src/filesystem/__tests__/PhutilDeferredLogTestCase.php
@@ -95,8 +95,7 @@
}
public function testManyWriters() {
- $root = phutil_get_library_root('arcanist').'/../';
- $bin = $root.'support/unit/deferred_log.php';
+ $bin = $this->getSupportExecutable('log');
$n_writers = 3;
$n_lines = 8;
@@ -105,7 +104,11 @@
$futures = array();
for ($ii = 0; $ii < $n_writers; $ii++) {
- $futures[] = new ExecFuture('%s %d %s', $bin, $n_lines, (string)$tmp);
+ $futures[] = new ExecFuture(
+ 'php -f %R -- %d %s',
+ $bin,
+ $n_lines,
+ (string)$tmp);
}
id(new FutureIterator($futures))
diff --git a/src/filesystem/__tests__/PhutilFileLockTestCase.php b/src/filesystem/__tests__/PhutilFileLockTestCase.php
--- a/src/filesystem/__tests__/PhutilFileLockTestCase.php
+++ b/src/filesystem/__tests__/PhutilFileLockTestCase.php
@@ -170,14 +170,20 @@
throw new Exception(pht('Unable to hold lock in external process!'));
}
- private function buildLockFuture($flags, $file) {
- $root = dirname(phutil_get_library_root('arcanist'));
- $bin = $root.'/support/unit/lock.php';
+ private function buildLockFuture(/* ... */) {
+ $argv = func_get_args();
+ $bin = $this->getSupportExecutable('lock');
+
+ if (phutil_is_windows()) {
+ $future = new ExecFuture('php -f %R -- %Ls', $bin, $argv);
+ } else {
+ // NOTE: Use `exec` so this passes on Ubuntu, where the default `dash`
+ // shell will eat any kills we send during the tests.
+ $future = new ExecFuture('exec php -f %R -- %Ls', $bin, $argv);
+ }
- // NOTE: Use `exec` so this passes on Ubuntu, where the default `dash` shell
- // will eat any kills we send during the tests.
- $future = new ExecFuture('exec php %s %C %s', $bin, $flags, $file);
$future->start();
+
return $future;
}
diff --git a/src/filesystem/linesofalarge/__tests__/LinesOfALargeExecFutureTestCase.php b/src/filesystem/linesofalarge/__tests__/LinesOfALargeExecFutureTestCase.php
--- a/src/filesystem/linesofalarge/__tests__/LinesOfALargeExecFutureTestCase.php
+++ b/src/filesystem/linesofalarge/__tests__/LinesOfALargeExecFutureTestCase.php
@@ -43,7 +43,9 @@
}
private function writeAndRead($write, $read) {
- $future = new ExecFuture('cat');
+ $bin = $this->getSupportExecutable('cat');
+
+ $future = new ExecFuture('php -f %R', $bin);
$future->write($write);
$lines = array();
diff --git a/src/future/__tests__/FutureIteratorTestCase.php b/src/future/__tests__/FutureIteratorTestCase.php
--- a/src/future/__tests__/FutureIteratorTestCase.php
+++ b/src/future/__tests__/FutureIteratorTestCase.php
@@ -3,8 +3,10 @@
final class FutureIteratorTestCase extends PhutilTestCase {
public function testAddingFuture() {
- $future1 = new ExecFuture('cat');
- $future2 = new ExecFuture('cat');
+ $bin = $this->getSupportExecutable('cat');
+
+ $future1 = new ExecFuture('php -f %R', $bin);
+ $future2 = new ExecFuture('php -f %R', $bin);
$iterator = new FutureIterator(array($future1));
$iterator->limit(2);
diff --git a/src/future/exec/__tests__/ExecFutureTestCase.php b/src/future/exec/__tests__/ExecFutureTestCase.php
--- a/src/future/exec/__tests__/ExecFutureTestCase.php
+++ b/src/future/exec/__tests__/ExecFutureTestCase.php
@@ -6,15 +6,27 @@
// NOTE: This is mostly testing that we don't hang while doing an empty
// write.
- list($stdout) = id(new ExecFuture('cat'))->write('')->resolvex();
+ list($stdout) = $this->newCat()
+ ->write('')
+ ->resolvex();
$this->assertEqual('', $stdout);
}
+ private function newCat() {
+ $bin = $this->getSupportExecutable('cat');
+ return new ExecFuture('php -f %R', $bin);
+ }
+
+ private function newSleep($duration) {
+ $bin = $this->getSupportExecutable('sleep');
+ return new ExecFuture('php -f %R -- %s', $bin, $duration);
+ }
+
public function testKeepPipe() {
// NOTE: This is mostly testing the semantics of $keep_pipe in write().
- list($stdout) = id(new ExecFuture('cat'))
+ list($stdout) = $this->newCat()
->write('', true)
->start()
->write('x', true)
@@ -30,14 +42,14 @@
// flushing a buffer.
$data = str_repeat('x', 1024 * 1024 * 4);
- list($stdout) = id(new ExecFuture('cat'))->write($data)->resolvex();
+ list($stdout) = $this->newCat()->write($data)->resolvex();
$this->assertEqual($data, $stdout);
}
public function testBufferLimit() {
$data = str_repeat('x', 1024 * 1024);
- list($stdout) = id(new ExecFuture('cat'))
+ list($stdout) = $this->newCat()
->setStdoutSizeLimit(1024)
->write($data)
->resolvex();
@@ -49,7 +61,7 @@
// NOTE: This tests interactions between the resolve() timeout and the
// ExecFuture timeout, which are similar but not identical.
- $future = id(new ExecFuture('sleep 32000'))->start();
+ $future = $this->newSleep(32000)->start();
$future->setTimeout(32000);
// We expect this to return in 0.01s.
@@ -66,7 +78,7 @@
public function testTerminateWithoutStart() {
// We never start this future, but it should be fine to kill a future from
// any state.
- $future = new ExecFuture('sleep 1');
+ $future = $this->newSleep(1);
$future->resolveKill();
$this->assertTrue(true);
@@ -76,7 +88,7 @@
// NOTE: This is partly testing that we choose appropriate select wait
// times; this test should run for significantly less than 1 second.
- $future = new ExecFuture('sleep 32000');
+ $future = $this->newSleep(32000);
list($err) = $future->setTimeout(0.01)->resolve();
$this->assertTrue($err > 0);
@@ -86,7 +98,7 @@
public function testMultipleTimeoutsTestShouldRunLessThan1Sec() {
$futures = array();
for ($ii = 0; $ii < 4; $ii++) {
- $futures[] = id(new ExecFuture('sleep 32000'))->setTimeout(0.01);
+ $futures[] = $this->newSleep(32000)->setTimeout(0.01);
}
foreach (new FutureIterator($futures) as $future) {
@@ -100,8 +112,9 @@
public function testMultipleResolves() {
// It should be safe to call resolve(), resolvex(), resolveKill(), etc.,
// as many times as you want on the same process.
+ $bin = $this->getSupportExecutable('echo');
- $future = new ExecFuture('echo quack');
+ $future = new ExecFuture('php -f %R -- quack', $bin);
$future->resolve();
$future->resolvex();
list($err) = $future->resolveKill();
@@ -114,7 +127,7 @@
$str_len_4 = 'abcd';
// This is a write/read with no read buffer.
- $future = new ExecFuture('cat');
+ $future = $this->newCat();
$future->write($str_len_8);
do {
@@ -131,7 +144,7 @@
// This is a write/read with a read buffer.
- $future = new ExecFuture('cat');
+ $future = $this->newCat();
$future->write($str_len_8);
// Set the read buffer size.
diff --git a/src/future/exec/__tests__/ExecPassthruTestCase.php b/src/future/exec/__tests__/ExecPassthruTestCase.php
--- a/src/future/exec/__tests__/ExecPassthruTestCase.php
+++ b/src/future/exec/__tests__/ExecPassthruTestCase.php
@@ -8,7 +8,9 @@
// the terminal, which is undesirable). This makes crafting effective unit
// tests a fairly involved process.
- $exec = new PhutilExecPassthru('exit');
+ $bin = $this->getSupportExecutable('exit');
+
+ $exec = new PhutilExecPassthru('php -f %R', $bin);
$err = $exec->execute();
$this->assertEqual(0, $err);
}
diff --git a/src/future/oauth/__tests__/PhutilOAuth1FutureTestCase.php b/src/future/oauth/__tests__/PhutilOAuth1FutureTestCase.php
--- a/src/future/oauth/__tests__/PhutilOAuth1FutureTestCase.php
+++ b/src/future/oauth/__tests__/PhutilOAuth1FutureTestCase.php
@@ -63,6 +63,10 @@
}
public function testOAuth1SigningWithJIRAExamples() {
+ if (!function_exists('openssl_pkey_get_private')) {
+ $this->assertSkipped(
+ pht('Required "openssl" extension is not installed.'));
+ }
// NOTE: This is an emprically example against JIRA v6.0.6, in that the
// code seems to work when actually authing. It primarily serves as a check
@@ -156,4 +160,5 @@
md5($future->getSignature()));
}
+
}
diff --git a/src/lint/linter/__tests__/ArcanistXHPASTLinterTestCase.php b/src/lint/linter/__tests__/ArcanistXHPASTLinterTestCase.php
--- a/src/lint/linter/__tests__/ArcanistXHPASTLinterTestCase.php
+++ b/src/lint/linter/__tests__/ArcanistXHPASTLinterTestCase.php
@@ -3,6 +3,8 @@
final class ArcanistXHPASTLinterTestCase extends ArcanistLinterTestCase {
public function testLinter() {
+ $this->assertExecutable('xhpast');
+
$this->executeTestsInDirectory(dirname(__FILE__).'/xhpast/');
}
diff --git a/src/lint/linter/xhpast/rules/__tests__/ArcanistXHPASTLinterRuleTestCase.php b/src/lint/linter/xhpast/rules/__tests__/ArcanistXHPASTLinterRuleTestCase.php
--- a/src/lint/linter/xhpast/rules/__tests__/ArcanistXHPASTLinterRuleTestCase.php
+++ b/src/lint/linter/xhpast/rules/__tests__/ArcanistXHPASTLinterRuleTestCase.php
@@ -29,6 +29,8 @@
* @return ArcanistXHPASTLinterRule
*/
protected function getLinterRule() {
+ $this->assertExecutable('xhpast');
+
$class = get_class($this);
$matches = null;
diff --git a/src/markup/engine/__tests__/PhutilRemarkupEngineTestCase.php b/src/markup/engine/__tests__/PhutilRemarkupEngineTestCase.php
--- a/src/markup/engine/__tests__/PhutilRemarkupEngineTestCase.php
+++ b/src/markup/engine/__tests__/PhutilRemarkupEngineTestCase.php
@@ -45,6 +45,12 @@
$engine->setConfig('uri.base', 'http://www.example.com/');
$engine->setConfig('uri.here', 'http://www.example.com/page/');
break;
+ case 'quoted-code-block.txt':
+ // These tests depend on the syntax highlighting provided by "xhpast",
+ // so the output will differ if we're falling back to a different
+ // syntax highlighter.
+ $this->assertExecutable('xhpast');
+ break;
}
$actual_output = (string)$engine->markupText($input_remarkup);
diff --git a/src/markup/syntax/highlighter/__tests__/PhutilXHPASTSyntaxHighlighterTestCase.php b/src/markup/syntax/highlighter/__tests__/PhutilXHPASTSyntaxHighlighterTestCase.php
--- a/src/markup/syntax/highlighter/__tests__/PhutilXHPASTSyntaxHighlighterTestCase.php
+++ b/src/markup/syntax/highlighter/__tests__/PhutilXHPASTSyntaxHighlighterTestCase.php
@@ -14,6 +14,8 @@
}
public function testBuiltinClassnames() {
+ $this->assertExecutable('xhpast');
+
$this->assertEqual(
$this->read('builtin-classname.expect'),
(string)$this->highlight($this->read('builtin-classname.source')),
diff --git a/src/parser/PhutilEditorConfig.php b/src/parser/PhutilEditorConfig.php
--- a/src/parser/PhutilEditorConfig.php
+++ b/src/parser/PhutilEditorConfig.php
@@ -107,9 +107,16 @@
$configs = $this->getEditorConfigs($path);
$matches = array();
+ // Normalize directory separators to "/". The ".editorconfig" standard
+ // uses only "/" as a directory separator, not "\".
+ $path = str_replace(DIRECTORY_SEPARATOR, '/', $path);
+
foreach ($configs as $config) {
list($path_prefix, $editorconfig) = $config;
+ // Normalize path separators, as above.
+ $path_prefix = str_replace(DIRECTORY_SEPARATOR, '/', $path_prefix);
+
foreach ($editorconfig as $glob => $properties) {
if (!$glob) {
continue;
@@ -163,12 +170,11 @@
* return list<pair<string, map>>
*/
private function getEditorConfigs($path) {
- $configs = array();
- $found_root = false;
- $root = $this->root;
+ $configs = array();
- do {
- $path = dirname($path);
+ $found_root = false;
+ $paths = Filesystem::walkToRoot($path, $this->root);
+ foreach ($paths as $path) {
$file = $path.'/.editorconfig';
if (!Filesystem::pathExists($file)) {
@@ -187,7 +193,7 @@
if ($found_root) {
break;
}
- } while ($path != $root && Filesystem::isDescendant($path, $root));
+ }
return $configs;
}
diff --git a/src/parser/__tests__/ArcanistBundleTestCase.php b/src/parser/__tests__/ArcanistBundleTestCase.php
--- a/src/parser/__tests__/ArcanistBundleTestCase.php
+++ b/src/parser/__tests__/ArcanistBundleTestCase.php
@@ -11,6 +11,8 @@
}
private function loadDiff($old, $new) {
+ $this->assertExecutable('diff');
+
list($err, $stdout) = exec_manual(
'diff --unified=65535 --label %s --label %s -- %s %s',
'file 9999-99-99',
diff --git a/src/parser/xhpast/api/__tests__/XHPASTNodeTestCase.php b/src/parser/xhpast/api/__tests__/XHPASTNodeTestCase.php
--- a/src/parser/xhpast/api/__tests__/XHPASTNodeTestCase.php
+++ b/src/parser/xhpast/api/__tests__/XHPASTNodeTestCase.php
@@ -3,6 +3,8 @@
final class XHPASTNodeTestCase extends PhutilTestCase {
public function testGetStringVariables() {
+ $this->assertExecutable('xhpast');
+
$this->assertStringVariables(array(), '""');
$this->assertStringVariables(array(2 => 'abc'), '"$abc"');
$this->assertStringVariables(array(), '"\$abc"');
@@ -20,6 +22,8 @@
}
private function assertStringVariables($expected, $string) {
+ $this->assertExecutable('xhpast');
+
$statement = XHPASTTree::newStatementFromString($string);
$this->assertEqual(
$expected,
@@ -28,6 +32,8 @@
}
public function testGetNamespace() {
+ $this->assertExecutable('xhpast');
+
$dir = dirname(__FILE__).'/namespace/';
$files = id(new FileFinder($dir))
->withType('f')
diff --git a/src/parser/xhpast/api/__tests__/XHPASTTreeTestCase.php b/src/parser/xhpast/api/__tests__/XHPASTTreeTestCase.php
--- a/src/parser/xhpast/api/__tests__/XHPASTTreeTestCase.php
+++ b/src/parser/xhpast/api/__tests__/XHPASTTreeTestCase.php
@@ -6,6 +6,8 @@
final class XHPASTTreeTestCase extends PhutilTestCase {
public function testEvalStaticString() {
+ $this->assertExecutable('xhpast');
+
$this->assertEval(1, '1');
$this->assertEval('a', '"a"');
$this->assertEval(-1.1, '-1.1');
diff --git a/src/parser/xhpast/bin/PhutilXHPASTBinary.php b/src/parser/xhpast/bin/PhutilXHPASTBinary.php
--- a/src/parser/xhpast/bin/PhutilXHPASTBinary.php
+++ b/src/parser/xhpast/bin/PhutilXHPASTBinary.php
@@ -32,7 +32,7 @@
$command = 'make';
}
- $root = phutil_get_library_root('phutil');
+ $root = phutil_get_library_root('arcanist');
$path = Filesystem::resolvePath($root.'/../support/xhpast');
// Run the build.
diff --git a/src/phage/__tests__/PhageAgentTestCase.php b/src/phage/__tests__/PhageAgentTestCase.php
--- a/src/phage/__tests__/PhageAgentTestCase.php
+++ b/src/phage/__tests__/PhageAgentTestCase.php
@@ -3,6 +3,10 @@
final class PhageAgentTestCase extends PhutilTestCase {
public function testPhagePHPAgent() {
+ if (phutil_is_windows()) {
+ $this->assertSkipped(pht('Phage does not target Windows.'));
+ }
+
return $this->runBootloaderTests(new PhagePHPAgentBootloader());
}
diff --git a/src/repository/api/__tests__/ArcanistRepositoryAPIStateTestCase.php b/src/repository/api/__tests__/ArcanistRepositoryAPIStateTestCase.php
--- a/src/repository/api/__tests__/ArcanistRepositoryAPIStateTestCase.php
+++ b/src/repository/api/__tests__/ArcanistRepositoryAPIStateTestCase.php
@@ -3,33 +3,29 @@
final class ArcanistRepositoryAPIStateTestCase extends PhutilTestCase {
public function testGitStateParsing() {
- if (Filesystem::binaryExists('git')) {
- $this->parseState('git_basic.git.tgz');
- $this->parseState('git_submodules_dirty.git.tgz');
- $this->parseState('git_submodules_staged.git.tgz');
- $this->parseState('git_spaces.git.tgz');
- } else {
- $this->assertSkipped(pht('Git is not installed'));
- }
+ $this->assertExecutable('git');
+
+ $this->parseState('git_basic.git.tgz');
+ $this->parseState('git_submodules_dirty.git.tgz');
+ $this->parseState('git_submodules_staged.git.tgz');
+ $this->parseState('git_spaces.git.tgz');
}
public function testHgStateParsing() {
- if (Filesystem::binaryExists('hg')) {
- $this->parseState('hg_basic.hg.tgz');
- } else {
- $this->assertSkipped(pht('Mercurial is not installed'));
- }
+ $this->assertExecutable('hg');
+
+ $this->parseState('hg_basic.hg.tgz');
}
public function testSvnStateParsing() {
- if (Filesystem::binaryExists('svn')) {
- $this->parseState('svn_basic.svn.tgz');
- } else {
- $this->assertSkipped(pht('Subversion is not installed'));
- }
+ $this->assertExecutable('svn');
+
+ $this->parseState('svn_basic.svn.tgz');
}
private function parseState($test) {
+ $this->assertExecutable('tar');
+
$dir = dirname(__FILE__).'/state/';
$fixture = PhutilDirectoryFixture::newFromArchive($dir.'/'.$test);
diff --git a/src/unit/engine/phutil/PhutilTestCase.php b/src/unit/engine/phutil/PhutilTestCase.php
--- a/src/unit/engine/phutil/PhutilTestCase.php
+++ b/src/unit/engine/phutil/PhutilTestCase.php
@@ -20,6 +20,8 @@
private $paths;
private $renderer;
+ private static $executables = array();
+
/* -( Making Test Assertions )--------------------------------------------- */
@@ -110,15 +112,24 @@
$output .= "\n";
+ static $have_diff;
+ if ($have_diff === null) {
+ $have_diff = Filesystem::binaryExists('diff');
+ }
+
if (strpos($expect, "\n") === false && strpos($result, "\n") === false) {
$output .= pht("Expected: %s\n Actual: %s", $expect, $result);
- } else {
+ } else if ($have_diff) {
$output .= pht(
"Expected vs Actual Output Diff\n%s",
ArcanistDiffUtils::renderDifferences(
$expect,
$result,
$lines = 0xFFFF));
+ } else {
+ // On systems without `diff`, including Windows, just show the raw
+ // values instead of using `diff` to compare them.
+ $output .= "EXPECTED\n{$expect}\n\nACTUAL\n{$result}\n";
}
$this->failTest($output);
@@ -751,4 +762,37 @@
throw new PhutilTestTerminatedException($output);
}
+ final protected function assertExecutable($binary) {
+ if (!isset(self::$executables[$binary])) {
+ switch ($binary) {
+ case 'xhpast':
+ $ok = true;
+ if (!PhutilXHPASTBinary::isAvailable()) {
+ try {
+ PhutilXHPASTBinary::build();
+ } catch (Exception $ex) {
+ $ok = false;
+ }
+ }
+ break;
+ default:
+ $ok = Filesystem::binaryExists($binary);
+ break;
+ }
+
+ self::$executables[$binary] = $ok;
+ }
+
+ if (!self::$executables[$binary]) {
+ $this->assertSkipped(
+ pht('Required executable "%s" is not available.', $binary));
+ }
+ }
+
+ final protected function getSupportExecutable($executable) {
+ $root = dirname(phutil_get_library_root('arcanist'));
+ return $root.'/support/unit/'.$executable.'.php';
+ }
+
+
}
diff --git a/src/xsprintf/__tests__/PhutilCsprintfTestCase.php b/src/xsprintf/__tests__/PhutilCsprintfTestCase.php
--- a/src/xsprintf/__tests__/PhutilCsprintfTestCase.php
+++ b/src/xsprintf/__tests__/PhutilCsprintfTestCase.php
@@ -39,25 +39,33 @@
}
public function testNoPowershell() {
- if (!phutil_is_windows()) {
- $cmd = csprintf('%s', '#');
- $cmd->setEscapingMode(PhutilCommandString::MODE_DEFAULT);
-
- $this->assertEqual(
- '\'#\'',
- (string)$cmd);
+ if (phutil_is_windows()) {
+ // TOOLSETS: Restructure this. We must skip because tests fail if they
+ // do not make any assertions.
+ $this->assertSkipped(
+ pht(
+ 'This test can not currently run under Windows.'));
}
+
+ $cmd = csprintf('%s', '#');
+ $cmd->setEscapingMode(PhutilCommandString::MODE_DEFAULT);
+
+ $this->assertEqual(
+ '\'#\'',
+ (string)$cmd);
}
public function testPasswords() {
+ $bin = $this->getSupportExecutable('echo');
+
// Normal "%s" doesn't do anything special.
- $command = csprintf('echo %s', 'hunter2trustno1');
+ $command = csprintf('php -f %R -- %s', $bin, 'hunter2trustno1');
$this->assertTrue(strpos($command, 'hunter2trustno1') !== false);
// "%P" takes a PhutilOpaqueEnvelope.
$caught = null;
try {
- csprintf('echo %P', 'hunter2trustno1');
+ csprintf('php -f %R -- %P', $bin, 'hunter2trustno1');
} catch (Exception $ex) {
$caught = $ex;
}
@@ -65,7 +73,10 @@
// "%P" masks the provided value.
- $command = csprintf('echo %P', new PhutilOpaqueEnvelope('hunter2trustno1'));
+ $command = csprintf(
+ 'php -f %R -- %P',
+ $bin,
+ new PhutilOpaqueEnvelope('hunter2trustno1'));
$this->assertFalse(strpos($command, 'hunter2trustno1'));
diff --git a/support/unit/cat.php b/support/unit/cat.php
new file mode 100755
--- /dev/null
+++ b/support/unit/cat.php
@@ -0,0 +1 @@
+<?php echo file_get_contents('php://stdin');
diff --git a/support/unit/echo.php b/support/unit/echo.php
new file mode 100755
--- /dev/null
+++ b/support/unit/echo.php
@@ -0,0 +1,8 @@
+<?php
+
+$args = array_slice($argv, 1);
+foreach ($args as $key => $arg) {
+ $args[$key] = addcslashes($arg, "\\\n");
+}
+$args = implode($args, "\n");
+echo $args;
diff --git a/support/unit/exit.php b/support/unit/exit.php
new file mode 100755
--- /dev/null
+++ b/support/unit/exit.php
@@ -0,0 +1 @@
+<?php exit(0);
\ No newline at end of file
diff --git a/support/unit/deferred_log.php b/support/unit/log.php
rename from support/unit/deferred_log.php
rename to support/unit/log.php
diff --git a/support/unit/sleep.php b/support/unit/sleep.php
new file mode 100755
--- /dev/null
+++ b/support/unit/sleep.php
@@ -0,0 +1,20 @@
+<?php
+
+if ($argc != 2) {
+ echo "usage: sleep <duration>\n";
+ exit(1);
+}
+
+// NOTE: Sleep for the requested duration even if our actual sleep() call is
+// interrupted by a signal.
+
+$then = microtime(true) + (double)$argv[1];
+while (true) {
+ $now = microtime(true);
+ if ($now >= $then) {
+ break;
+ }
+
+ $sleep = max(1, ($then - $now));
+ usleep((int)($sleep * 1000000));
+}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Mon, Mar 17, 7:11 AM (5 d, 8 h ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7707470
Default Alt Text
D19729.id.diff (26 KB)
Attached To
Mode
D19729: [Wilds] Pass or skip all remaining Windows unit test failures
Attached
Detach File
Event Timeline
Log In to Comment