Page MenuHomePhabricator

D19729.id.diff
No OneTemporary

D19729.id.diff

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

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)

Event Timeline