/core/externals/google-toolbox-for-mac/Foundation/GTMScriptRunnerTest.m

http://macfuse.googlecode.com/ · Objective C · 471 lines · 325 code · 82 blank · 64 comment · 3 complexity · c87e05d04f4825b37c4da570c4822882 MD5 · raw file

  1. //
  2. // GTMScriptRunnerTest.m
  3. //
  4. // Copyright 2007-2008 Google Inc.
  5. //
  6. // Licensed under the Apache License, Version 2.0 (the "License"); you may not
  7. // use this file except in compliance with the License. You may obtain a copy
  8. // of the License at
  9. //
  10. // http://www.apache.org/licenses/LICENSE-2.0
  11. //
  12. // Unless required by applicable law or agreed to in writing, software
  13. // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  14. // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  15. // License for the specific language governing permissions and limitations under
  16. // the License.
  17. //
  18. #import <sys/types.h>
  19. #import <unistd.h>
  20. #import "GTMSenTestCase.h"
  21. #import "GTMScriptRunner.h"
  22. #import "GTMUnitTestDevLog.h"
  23. @interface GTMScriptRunnerTest : GTMTestCase {
  24. @private
  25. NSString *shScript_;
  26. NSString *perlScript_;
  27. NSString *shOutputScript_;
  28. }
  29. @end
  30. @interface GTMScriptRunnerTest (PrivateMethods)
  31. - (void)helperTestBourneShellUsingScriptRunner:(GTMScriptRunner *)sr;
  32. @end
  33. @implementation GTMScriptRunnerTest
  34. - (void)setUp {
  35. shScript_ = [NSString stringWithFormat:@"/tmp/script_runner_unittest_%d_%d_sh", geteuid(), getpid()];
  36. [@"#!/bin/sh\n"
  37. @"i=1\n"
  38. @"if [ -n \"$1\" ]; then\n"
  39. @" i=$1\n"
  40. @"fi\n"
  41. @"echo $i\n"
  42. writeToFile:shScript_ atomically:YES encoding:NSUTF8StringEncoding error:nil];
  43. perlScript_ = [NSString stringWithFormat:@"/tmp/script_runner_unittest_%d_%d_pl", geteuid(), getpid()];
  44. [@"#!/usr/bin/perl\n"
  45. @"use strict;\n"
  46. @"my $i = 1;\n"
  47. @"if (defined $ARGV[0]) {\n"
  48. @" $i = $ARGV[0];\n"
  49. @"}\n"
  50. @"print \"$i\n\"\n"
  51. writeToFile:perlScript_ atomically:YES encoding:NSUTF8StringEncoding error:nil];
  52. shOutputScript_ = [NSString stringWithFormat:@"/tmp/script_runner_unittest_err_%d_%d_sh", geteuid(), getpid()];
  53. [@"#!/bin/sh\n"
  54. @"if [ \"err\" = \"$1\" ]; then\n"
  55. @" echo \" on err \" > /dev/stderr\n"
  56. @"else\n"
  57. @" echo \" on out \"\n"
  58. @"fi\n"
  59. writeToFile:shOutputScript_ atomically:YES encoding:NSUTF8StringEncoding error:nil];
  60. }
  61. - (void)tearDown {
  62. const char *path = [shScript_ fileSystemRepresentation];
  63. if (path) {
  64. unlink(path);
  65. }
  66. path = [perlScript_ fileSystemRepresentation];
  67. if (path) {
  68. unlink(path);
  69. }
  70. path = [shOutputScript_ fileSystemRepresentation];
  71. if (path) {
  72. unlink(path);
  73. }
  74. }
  75. - (void)testShCommands {
  76. GTMScriptRunner *sr = [GTMScriptRunner runner];
  77. [self helperTestBourneShellUsingScriptRunner:sr];
  78. }
  79. - (void)testBashCommands {
  80. GTMScriptRunner *sr = [GTMScriptRunner runnerWithBash];
  81. [self helperTestBourneShellUsingScriptRunner:sr];
  82. }
  83. - (void)testZshCommands {
  84. GTMScriptRunner *sr = [GTMScriptRunner runnerWithInterpreter:@"/bin/zsh"];
  85. [self helperTestBourneShellUsingScriptRunner:sr];
  86. }
  87. - (void)testBcCommands {
  88. GTMScriptRunner *sr = [GTMScriptRunner runnerWithInterpreter:@"/usr/bin/bc"
  89. withArgs:[NSArray arrayWithObject:@"-lq"]];
  90. STAssertNotNil(sr, @"Script runner must not be nil");
  91. NSString *output = nil;
  92. // Simple expression (NOTE that bc requires that commands end with a newline)
  93. output = [sr run:@"1 + 2\n"];
  94. STAssertEqualObjects(output, @"3", @"output should equal '3'");
  95. // Simple expression with variables and multiple statements
  96. output = [sr run:@"i=1; i+2\n"];
  97. STAssertEqualObjects(output, @"3", @"output should equal '3'");
  98. // Simple expression with base conversion
  99. output = [sr run:@"obase=2; 2^5\n"];
  100. STAssertEqualObjects(output, @"100000", @"output should equal '100000'");
  101. // Simple expression with sine and cosine functions
  102. output = [sr run:@"scale=3;s(0)+c(0)\n"];
  103. STAssertEqualObjects(output, @"1.000", @"output should equal '1.000'");
  104. }
  105. - (void)testPerlCommands {
  106. GTMScriptRunner *sr = [GTMScriptRunner runnerWithPerl];
  107. STAssertNotNil(sr, @"Script runner must not be nil");
  108. NSString *output = nil;
  109. // Simple print
  110. output = [sr run:@"print 'hi'"];
  111. STAssertEqualObjects(output, @"hi", @"output should equal 'hi'");
  112. // Simple print x4
  113. output = [sr run:@"print 'A'x4"];
  114. STAssertEqualObjects(output, @"AAAA", @"output should equal 'AAAA'");
  115. // Simple perl-y stuff
  116. output = [sr run:@"my $i=0; until ($i++==41){} print $i"];
  117. STAssertEqualObjects(output, @"42", @"output should equal '42'");
  118. }
  119. - (void)testPythonCommands {
  120. GTMScriptRunner *sr = [GTMScriptRunner runnerWithPython];
  121. STAssertNotNil(sr, @"Script runner must not be nil");
  122. NSString *output = nil;
  123. // Simple print
  124. output = [sr run:@"print 'hi'"];
  125. STAssertEqualObjects(output, @"hi", @"output should equal 'hi'");
  126. // Simple python expression
  127. output = [sr run:@"print '-'.join(['a', 'b', 'c'])"];
  128. STAssertEqualObjects(output, @"a-b-c", @"output should equal 'a-b-c'");
  129. }
  130. - (void)testBashScript {
  131. GTMScriptRunner *sr = [GTMScriptRunner runnerWithBash];
  132. STAssertNotNil(sr, @"Script runner must not be nil");
  133. NSString *output = nil;
  134. // Simple sh script
  135. output = [sr runScript:shScript_];
  136. STAssertEqualObjects(output, @"1", @"output should equal '1'");
  137. // Simple sh script with 1 command line argument
  138. output = [sr runScript:shScript_ withArgs:[NSArray arrayWithObject:@"2"]];
  139. STAssertEqualObjects(output, @"2", @"output should equal '2'");
  140. }
  141. - (void)testPerlScript {
  142. GTMScriptRunner *sr = [GTMScriptRunner runnerWithPerl];
  143. STAssertNotNil(sr, @"Script runner must not be nil");
  144. NSString *output = nil;
  145. // Simple Perl script
  146. output = [sr runScript:perlScript_];
  147. STAssertEqualObjects(output, @"1", @"output should equal '1'");
  148. // Simple perl script with 1 command line argument
  149. output = [sr runScript:perlScript_ withArgs:[NSArray arrayWithObject:@"2"]];
  150. STAssertEqualObjects(output, @"2", @"output should equal '2'");
  151. }
  152. - (void)testEnvironment {
  153. GTMScriptRunner *sr = [GTMScriptRunner runner];
  154. STAssertNotNil(sr, @"Script runner must not be nil");
  155. NSString *output = nil;
  156. NSString *error = nil;
  157. STAssertNil([sr environment], @"should start w/ empty env");
  158. output = [sr run:@"/usr/bin/env | wc -l" standardError:&error];
  159. int numVars = [output intValue];
  160. STAssertGreaterThan(numVars, 0,
  161. @"numVars should be positive. StdErr %@", error);
  162. // By default the environment is wiped clean, however shells often add a few
  163. // of their own env vars after things have been wiped. For example, sh will
  164. // add about 3 env vars (PWD, _, and SHLVL).
  165. STAssertLessThan(numVars, 5, @"Our env should be almost empty");
  166. NSDictionary *newEnv = [NSDictionary dictionaryWithObject:@"bar"
  167. forKey:@"foo"];
  168. [sr setEnvironment:newEnv];
  169. output = [sr run:@"/usr/bin/env | wc -l" standardError:&error];
  170. STAssertEquals([output intValue], numVars + 1,
  171. @"should have one more env var now. StdErr %@", error);
  172. [sr setEnvironment:nil];
  173. output = [sr run:@"/usr/bin/env | wc -l" standardError:&error];
  174. STAssertEquals([output intValue], numVars,
  175. @"should be back down to %d vars. StdErr:%@", numVars, error);
  176. NSMutableDictionary *currVars
  177. = [[[[NSProcessInfo processInfo] environment] mutableCopy] autorelease];
  178. // When debugging a release build _ was not in the processInfo environment
  179. // causing the assert below to fail. Not sure why, but it appeared
  180. // to be harmless, and easy to account for.
  181. [currVars setObject:@"/usr/bin/env" forKey:@"_"];
  182. [sr setEnvironment:currVars];
  183. output = [sr run:@"/usr/bin/env | /usr/bin/sort" standardError:&error];
  184. NSArray *lineArray = [output componentsSeparatedByString:@"\n"];
  185. STAssertEquals([lineArray count], [currVars count],
  186. @"StdErr:%@\nCurrentEnvironment:\n%@\nExpected environment:\n%@",
  187. error, output, currVars);
  188. }
  189. - (void)testDescription {
  190. // make sure description doesn't choke
  191. GTMScriptRunner *sr = [GTMScriptRunner runner];
  192. STAssertNotNil(sr, @"Script runner must not be nil");
  193. STAssertGreaterThan([[sr description] length], (NSUInteger)10,
  194. @"expected a description of at least 10 chars");
  195. }
  196. - (void)testRunCommandOutputHandling {
  197. // Test whitespace trimming & stdout vs. stderr w/ run command api
  198. GTMScriptRunner *sr = [GTMScriptRunner runnerWithBash];
  199. STAssertNotNil(sr, @"Script runner must not be nil");
  200. NSString *output = nil;
  201. NSString *err = nil;
  202. // w/o whitespace trimming
  203. {
  204. [sr setTrimsWhitespace:NO];
  205. STAssertFalse([sr trimsWhitespace], @"setTrimsWhitespace to NO failed");
  206. // test stdout
  207. output = [sr run:@"echo \" on out \"" standardError:&err];
  208. STAssertEqualObjects(output, @" on out \n", @"failed to get stdout output");
  209. STAssertNil(err, @"stderr should have been empty");
  210. // test stderr
  211. output = [sr run:@"echo \" on err \" > /dev/stderr" standardError:&err];
  212. STAssertNil(output, @"stdout should have been empty");
  213. STAssertEqualObjects(err, @" on err \n", nil);
  214. }
  215. // w/ whitespace trimming
  216. {
  217. [sr setTrimsWhitespace:YES];
  218. STAssertTrue([sr trimsWhitespace], @"setTrimsWhitespace to YES failed");
  219. // test stdout
  220. output = [sr run:@"echo \" on out \"" standardError:&err];
  221. STAssertEqualObjects(output, @"on out", @"failed to get stdout output");
  222. STAssertNil(err, @"stderr should have been empty");
  223. // test stderr
  224. output = [sr run:@"echo \" on err \" > /dev/stderr" standardError:&err];
  225. STAssertNil(output, @"stdout should have been empty");
  226. STAssertEqualObjects(err, @"on err", nil);
  227. }
  228. }
  229. - (void)testScriptOutputHandling {
  230. // Test whitespace trimming & stdout vs. stderr w/ script api
  231. GTMScriptRunner *sr = [GTMScriptRunner runner];
  232. STAssertNotNil(sr, @"Script runner must not be nil");
  233. NSString *output = nil;
  234. NSString *err = nil;
  235. // w/o whitespace trimming
  236. {
  237. [sr setTrimsWhitespace:NO];
  238. STAssertFalse([sr trimsWhitespace], @"setTrimsWhitespace to NO failed");
  239. // test stdout
  240. output = [sr runScript:shOutputScript_
  241. withArgs:[NSArray arrayWithObject:@"out"]
  242. standardError:&err];
  243. STAssertEqualObjects(output, @" on out \n", nil);
  244. STAssertNil(err, @"stderr should have been empty");
  245. // test stderr
  246. output = [sr runScript:shOutputScript_
  247. withArgs:[NSArray arrayWithObject:@"err"]
  248. standardError:&err];
  249. STAssertNil(output, @"stdout should have been empty");
  250. STAssertEqualObjects(err, @" on err \n", nil);
  251. }
  252. // w/ whitespace trimming
  253. {
  254. [sr setTrimsWhitespace:YES];
  255. STAssertTrue([sr trimsWhitespace], @"setTrimsWhitespace to YES failed");
  256. // test stdout
  257. output = [sr runScript:shOutputScript_
  258. withArgs:[NSArray arrayWithObject:@"out"]
  259. standardError:&err];
  260. STAssertEqualObjects(output, @"on out", nil);
  261. STAssertNil(err, @"stderr should have been empty");
  262. // test stderr
  263. output = [sr runScript:shOutputScript_
  264. withArgs:[NSArray arrayWithObject:@"err"]
  265. standardError:&err];
  266. STAssertNil(output, @"stdout should have been empty");
  267. STAssertEqualObjects(err, @"on err", nil);
  268. }
  269. }
  270. - (void)testBadRunCommandInput {
  271. GTMScriptRunner *sr = [GTMScriptRunner runner];
  272. STAssertNotNil(sr, @"Script runner must not be nil");
  273. NSString *err = nil;
  274. STAssertNil([sr run:nil standardError:&err], nil);
  275. STAssertNil(err, nil);
  276. }
  277. - (void)testBadScriptInput {
  278. GTMScriptRunner *sr = [GTMScriptRunner runner];
  279. STAssertNotNil(sr, @"Script runner must not be nil");
  280. NSString *err = nil;
  281. STAssertNil([sr runScript:nil withArgs:nil standardError:&err], nil);
  282. STAssertNil(err, nil);
  283. STAssertNil([sr runScript:@"/path/that/does/not/exists/foo/bar/baz"
  284. withArgs:nil standardError:&err], nil);
  285. STAssertNotNil(err,
  286. @"should have gotten something about the path not existing");
  287. }
  288. - (void)testBadCmdInterpreter {
  289. GTMScriptRunner *sr =
  290. [GTMScriptRunner runnerWithInterpreter:@"/path/that/does/not/exists/interpreter"];
  291. STAssertNotNil(sr, @"Script runner must not be nil");
  292. NSString *err = nil;
  293. STAssertNil([sr run:nil standardError:&err], nil);
  294. STAssertNil(err, nil);
  295. [GTMUnitTestDevLog expectString:@"Failed to launch interpreter "
  296. "'/path/that/does/not/exists/interpreter' due to: launch path not accessible"];
  297. STAssertNil([sr run:@"ls /" standardError:&err], nil);
  298. STAssertNil(err, nil);
  299. }
  300. - (void)testBadScriptInterpreter {
  301. GTMScriptRunner *sr =
  302. [GTMScriptRunner runnerWithInterpreter:@"/path/that/does/not/exists/interpreter"];
  303. STAssertNotNil(sr, @"Script runner must not be nil");
  304. NSString *err = nil;
  305. [GTMUnitTestDevLog expectString:@"Failed to launch interpreter "
  306. "'/path/that/does/not/exists/interpreter' due to: launch path not accessible"];
  307. STAssertNil([sr runScript:shScript_ withArgs:nil standardError:&err], nil);
  308. STAssertNil(err, nil);
  309. [GTMUnitTestDevLog expectString:@"Failed to launch interpreter "
  310. "'/path/that/does/not/exists/interpreter' due to: launch path not accessible"];
  311. STAssertNil([sr runScript:@"/path/that/does/not/exists/foo/bar/baz"
  312. withArgs:nil standardError:&err], nil);
  313. STAssertNil(err, nil);
  314. }
  315. - (void)testLargeOutput {
  316. // These tests cover the issues found in
  317. // http://code.google.com/p/google-toolbox-for-mac/issues/detail?id=25
  318. GTMScriptRunner *sr = [GTMScriptRunner runnerWithPython];
  319. STAssertNotNil(sr, @"Script runner must not be nil");
  320. NSString *output = nil, *err = nil, *cmd = nil;
  321. #define GENERATOR_FORMAT_STR \
  322. @"import sys\n" \
  323. @"block = '.' * 512\n" \
  324. @"for x in [%@]:\n" \
  325. @" to_where = x[0]\n" \
  326. @" how_many = int(x[1:])\n" \
  327. @" for x in xrange(0, how_many):\n" \
  328. @" if to_where in [ 'o', 'b' ]:\n" \
  329. @" sys.stdout.write(block)\n" \
  330. @" if to_where in [ 'e', 'b' ]:\n" \
  331. @" sys.stderr.write(block)\n"
  332. // Make sure we get both blocks
  333. cmd = [NSString stringWithFormat:GENERATOR_FORMAT_STR, @"'b1'"];
  334. STAssertNotNil(cmd, nil);
  335. output = [sr run:cmd standardError:&err];
  336. STAssertEquals([output length], (NSUInteger)512, nil);
  337. STAssertEquals([err length], (NSUInteger)512, nil);
  338. // Test a large amount of data on only one connections at a time.
  339. cmd = [NSString stringWithFormat:GENERATOR_FORMAT_STR, @"'b1', 'o200'"];
  340. STAssertNotNil(cmd, nil);
  341. output = [sr run:cmd standardError:&err];
  342. STAssertEquals([output length], (NSUInteger)(512 + 512*200), nil);
  343. STAssertEquals([err length], (NSUInteger)512, nil);
  344. cmd = [NSString stringWithFormat:GENERATOR_FORMAT_STR, @"'b1', 'e200'"];
  345. STAssertNotNil(cmd, nil);
  346. output = [sr run:cmd standardError:&err];
  347. STAssertEquals([output length], (NSUInteger)512, nil);
  348. STAssertEquals([err length], (NSUInteger)(512 + 512*200), nil);
  349. // Now send a large amount down both to make sure we spool it all in.
  350. cmd = [NSString stringWithFormat:GENERATOR_FORMAT_STR, @"'b200'"];
  351. STAssertNotNil(cmd, nil);
  352. output = [sr run:cmd standardError:&err];
  353. STAssertEquals([output length], (NSUInteger)(512*200), nil);
  354. STAssertEquals([err length], (NSUInteger)(512*200), nil);
  355. }
  356. @end
  357. @implementation GTMScriptRunnerTest (PrivateMethods)
  358. - (void)helperTestBourneShellUsingScriptRunner:(GTMScriptRunner *)sr {
  359. STAssertNotNil(sr, @"Script runner must not be nil");
  360. NSString *output = nil;
  361. // Simple command
  362. output = [sr run:@"ls /etc/passwd"];
  363. STAssertEqualObjects(output, @"/etc/passwd", @"output should equal '/etc/passwd'");
  364. // Simple command pipe-line
  365. output = [sr run:@"ls /etc/ | grep passwd | tail -1"];
  366. STAssertEqualObjects(output, @"passwd", @"output should equal 'passwd'");
  367. // Simple pipe-line with quotes and awk variables
  368. output = [sr run:@"ps jaxww | awk '{print $2}' | sort -nr | tail -2 | head -1"];
  369. STAssertEqualObjects(output, @"1", @"output should equal '1'");
  370. // Simple shell loop with variables
  371. output = [sr run:@"i=0; while [ $i -lt 100 ]; do i=$((i+1)); done; echo $i"];
  372. STAssertEqualObjects(output, @"100", @"output should equal '100'");
  373. // Simple command with newlines
  374. output = [sr run:@"i=1\necho $i"];
  375. STAssertEqualObjects(output, @"1", @"output should equal '1'");
  376. // Simple full shell script
  377. output = [sr run:@"#!/bin/sh\ni=1\necho $i\n"];
  378. STAssertEqualObjects(output, @"1", @"output should equal '1'");
  379. NSString *err = nil;
  380. // Test getting standard error with no stdout
  381. output = [sr run:@"ls /etc/does-not-exist" standardError:&err];
  382. STAssertNil(output, @"output should be nil due to expected error");
  383. STAssertEqualObjects(err, @"ls: /etc/does-not-exist: No such file or directory", @"");
  384. // Test getting standard output along with some standard error
  385. output = [sr run:@"ls /etc/does-not-exist /etc/passwd" standardError:&err];
  386. STAssertEqualObjects(output, @"/etc/passwd", @"");
  387. STAssertEqualObjects(err, @"ls: /etc/does-not-exist: No such file or directory", @"");
  388. }
  389. @end