mirror of
https://we.phorge.it/source/arcanist.git
synced 2024-11-10 00:42:40 +01:00
[Wilds] Pass or skip all remaining Windows unit test failures
Summary: Ref T13209. This gives us a clean suite under Windows. The actual changes are a lot of miscellaneous stuff which I'll walk through inline in more detail. The biggest change here is just rewriting some stuff like `cat`, `echo`, `sleep`, etc., in PHP. These commands either don't exist, don't work the same way, or are shell builtins (and we're now bypassing the shell) under Windows. So replace `cat ...` with `php -f cat.php -- ...` to make the tests portable. Test Plan: No remaining test failures on Windows. Reviewers: amckinley Reviewed By: amckinley Maniphest Tasks: T13209 Differential Revision: https://secure.phabricator.com/D19729
This commit is contained in:
parent
fa27ad761a
commit
79d3692f66
30 changed files with 249 additions and 75 deletions
|
@ -24,6 +24,8 @@ class PhutilLibraryTestCase extends PhutilTestCase {
|
|||
* 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);
|
||||
|
||||
|
|
|
@ -45,7 +45,9 @@ final class PhutilPHPObjectProtocolChannelTestCase extends PhutilTestCase {
|
|||
}
|
||||
|
||||
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);
|
||||
|
|
|
@ -898,8 +898,23 @@ final class Filesystem extends Phobject {
|
|||
// 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);
|
||||
|
|
|
@ -125,6 +125,16 @@ final class FileFinderTestCase extends PhutilTestCase {
|
|||
}
|
||||
|
||||
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 @@ final class FileFinderTestCase extends PhutilTestCase {
|
|||
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)
|
||||
|
|
|
@ -111,22 +111,17 @@ final class FilesystemTestCase extends PhutilTestCase {
|
|||
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));
|
||||
|
|
|
@ -95,8 +95,7 @@ final class PhutilDeferredLogTestCase extends PhutilTestCase {
|
|||
}
|
||||
|
||||
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 @@ final class PhutilDeferredLogTestCase extends PhutilTestCase {
|
|||
|
||||
$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))
|
||||
|
|
|
@ -170,14 +170,20 @@ final class PhutilFileLockTestCase extends PhutilTestCase {
|
|||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -43,7 +43,9 @@ final class LinesOfALargeExecFutureTestCase extends PhutilTestCase {
|
|||
}
|
||||
|
||||
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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -6,15 +6,27 @@ final class ExecFutureTestCase extends PhutilTestCase {
|
|||
// 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 @@ final class ExecFutureTestCase extends PhutilTestCase {
|
|||
// 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 @@ final class ExecFutureTestCase extends PhutilTestCase {
|
|||
// 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 @@ final class ExecFutureTestCase extends PhutilTestCase {
|
|||
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 @@ final class ExecFutureTestCase extends PhutilTestCase {
|
|||
// 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 @@ final class ExecFutureTestCase extends PhutilTestCase {
|
|||
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 @@ final class ExecFutureTestCase extends PhutilTestCase {
|
|||
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 @@ final class ExecFutureTestCase extends PhutilTestCase {
|
|||
$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 @@ final class ExecFutureTestCase extends PhutilTestCase {
|
|||
|
||||
|
||||
// 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.
|
||||
|
|
|
@ -8,7 +8,9 @@ final class ExecPassthruTestCase extends PhutilTestCase {
|
|||
// 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);
|
||||
}
|
||||
|
|
|
@ -63,6 +63,10 @@ final class PhutilOAuth1FutureTestCase extends PhutilTestCase {
|
|||
}
|
||||
|
||||
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 @@ EOKEY;
|
|||
md5($future->getSignature()));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
final class ArcanistXHPASTLinterTestCase extends ArcanistLinterTestCase {
|
||||
|
||||
public function testLinter() {
|
||||
$this->assertExecutable('xhpast');
|
||||
|
||||
$this->executeTestsInDirectory(dirname(__FILE__).'/xhpast/');
|
||||
}
|
||||
|
||||
|
|
|
@ -29,6 +29,8 @@ abstract class ArcanistXHPASTLinterRuleTestCase
|
|||
* @return ArcanistXHPASTLinterRule
|
||||
*/
|
||||
protected function getLinterRule() {
|
||||
$this->assertExecutable('xhpast');
|
||||
|
||||
$class = get_class($this);
|
||||
$matches = null;
|
||||
|
||||
|
|
|
@ -45,6 +45,12 @@ final class PhutilRemarkupEngineTestCase extends PhutilTestCase {
|
|||
$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);
|
||||
|
|
|
@ -14,6 +14,8 @@ final class PhutilXHPASTSyntaxHighlighterTestCase extends PhutilTestCase {
|
|||
}
|
||||
|
||||
public function testBuiltinClassnames() {
|
||||
$this->assertExecutable('xhpast');
|
||||
|
||||
$this->assertEqual(
|
||||
$this->read('builtin-classname.expect'),
|
||||
(string)$this->highlight($this->read('builtin-classname.source')),
|
||||
|
|
|
@ -107,9 +107,16 @@ final class PhutilEditorConfig extends Phobject {
|
|||
$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;
|
||||
|
@ -164,11 +171,10 @@ final class PhutilEditorConfig extends Phobject {
|
|||
*/
|
||||
private function getEditorConfigs($path) {
|
||||
$configs = array();
|
||||
$found_root = false;
|
||||
$root = $this->root;
|
||||
|
||||
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 @@ final class PhutilEditorConfig extends Phobject {
|
|||
if ($found_root) {
|
||||
break;
|
||||
}
|
||||
} while ($path != $root && Filesystem::isDescendant($path, $root));
|
||||
}
|
||||
|
||||
return $configs;
|
||||
}
|
||||
|
|
|
@ -11,6 +11,8 @@ final class ArcanistBundleTestCase extends PhutilTestCase {
|
|||
}
|
||||
|
||||
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',
|
||||
|
|
|
@ -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 @@ final class XHPASTNodeTestCase extends PhutilTestCase {
|
|||
}
|
||||
|
||||
private function assertStringVariables($expected, $string) {
|
||||
$this->assertExecutable('xhpast');
|
||||
|
||||
$statement = XHPASTTree::newStatementFromString($string);
|
||||
$this->assertEqual(
|
||||
$expected,
|
||||
|
@ -28,6 +32,8 @@ final class XHPASTNodeTestCase extends PhutilTestCase {
|
|||
}
|
||||
|
||||
public function testGetNamespace() {
|
||||
$this->assertExecutable('xhpast');
|
||||
|
||||
$dir = dirname(__FILE__).'/namespace/';
|
||||
$files = id(new FileFinder($dir))
|
||||
->withType('f')
|
||||
|
|
|
@ -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');
|
||||
|
|
|
@ -32,7 +32,7 @@ final class PhutilXHPASTBinary extends Phobject {
|
|||
$command = 'make';
|
||||
}
|
||||
|
||||
$root = phutil_get_library_root('phutil');
|
||||
$root = phutil_get_library_root('arcanist');
|
||||
$path = Filesystem::resolvePath($root.'/../support/xhpast');
|
||||
|
||||
// Run the build.
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
||||
|
|
|
@ -3,33 +3,29 @@
|
|||
final class ArcanistRepositoryAPIStateTestCase extends PhutilTestCase {
|
||||
|
||||
public function testGitStateParsing() {
|
||||
if (Filesystem::binaryExists('git')) {
|
||||
$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');
|
||||
} else {
|
||||
$this->assertSkipped(pht('Git is not installed'));
|
||||
}
|
||||
}
|
||||
|
||||
public function testHgStateParsing() {
|
||||
if (Filesystem::binaryExists('hg')) {
|
||||
$this->assertExecutable('hg');
|
||||
|
||||
$this->parseState('hg_basic.hg.tgz');
|
||||
} else {
|
||||
$this->assertSkipped(pht('Mercurial is not installed'));
|
||||
}
|
||||
}
|
||||
|
||||
public function testSvnStateParsing() {
|
||||
if (Filesystem::binaryExists('svn')) {
|
||||
$this->assertExecutable('svn');
|
||||
|
||||
$this->parseState('svn_basic.svn.tgz');
|
||||
} else {
|
||||
$this->assertSkipped(pht('Subversion is not installed'));
|
||||
}
|
||||
}
|
||||
|
||||
private function parseState($test) {
|
||||
$this->assertExecutable('tar');
|
||||
|
||||
$dir = dirname(__FILE__).'/state/';
|
||||
$fixture = PhutilDirectoryFixture::newFromArchive($dir.'/'.$test);
|
||||
|
||||
|
|
|
@ -20,6 +20,8 @@ abstract class PhutilTestCase extends Phobject {
|
|||
private $paths;
|
||||
private $renderer;
|
||||
|
||||
private static $executables = array();
|
||||
|
||||
|
||||
/* -( Making Test Assertions )--------------------------------------------- */
|
||||
|
||||
|
@ -110,15 +112,24 @@ abstract class PhutilTestCase extends Phobject {
|
|||
|
||||
$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 @@ abstract class PhutilTestCase extends Phobject {
|
|||
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';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -39,7 +39,14 @@ final class PhutilCsprintfTestCase extends PhutilTestCase {
|
|||
}
|
||||
|
||||
public function testNoPowershell() {
|
||||
if (!phutil_is_windows()) {
|
||||
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);
|
||||
|
||||
|
@ -47,17 +54,18 @@ final class PhutilCsprintfTestCase extends PhutilTestCase {
|
|||
'\'#\'',
|
||||
(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 @@ final class PhutilCsprintfTestCase extends PhutilTestCase {
|
|||
|
||||
|
||||
// "%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'));
|
||||
|
||||
|
||||
|
|
1
support/unit/cat.php
Executable file
1
support/unit/cat.php
Executable file
|
@ -0,0 +1 @@
|
|||
<?php echo file_get_contents('php://stdin');
|
8
support/unit/echo.php
Executable file
8
support/unit/echo.php
Executable file
|
@ -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;
|
1
support/unit/exit.php
Executable file
1
support/unit/exit.php
Executable file
|
@ -0,0 +1 @@
|
|||
<?php exit(0);
|
20
support/unit/sleep.php
Executable file
20
support/unit/sleep.php
Executable file
|
@ -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));
|
||||
}
|
Loading…
Reference in a new issue