1#include "KCAPI_Keychain.h"
2#include "KCAPI_Manager.h"
3#include "testKeychainAPI.h"
4#include "Radar.h"
5#include <unistd.h>
6
7#if TARGET_RT_MAC_MACHO
8	#include <OSServices/KeychainCore.h>
9	#include <OSServices/KeychainCorePriv.h>
10	#include <SecurityHI/KeychainHI.h>
11#else
12	#include <Keychain.h>
13	#include <iostream>
14	#include <SIOUX.h>
15	static void GetArg(int &outArgc, char**	&outArgv);
16#endif
17
18static char*	gResourcePath = NULL;
19static char*	GetResourcePath(char**argv);
20static int gSleep=0;
21
22#ifndef TEST_SCRIPT_PATH
23	#define TEST_SCRIPT_PATH	(getenv("TESTKEYCHAINAPI_TEST_SCRIPT_PATH") ? getenv("TESTKEYCHAINAPI_TEST_SCRIPT_PATH") : gResourcePath)
24#endif
25
26
27int main(int argc, char** argv)
28{
29
30#if defined(__MWERKS__)
31										// Set SIOUX window position to top left corner
32										// so that Security Dialogs will not cover the
33										// window
34	SIOUXSettings.toppixel = 40;
35	SIOUXSettings.leftpixel = 5;
36
37										// emulate argc, argv
38	GetArg(argc, argv);
39#endif
40
41	gResourcePath = GetResourcePath(argv);
42
43	try{
44		CTestApp	aTestApp(argc, argv);
45					aTestApp.Run();
46	}
47	catch(const char *inErrorMsg){
48		fprintf(stderr, "ERROR : %s\n", inErrorMsg);
49	}
50
51	if(gSleep)
52	{
53		fprintf(stderr, "\n-----> sleeping...\n");
54		sleep(60000);
55	}
56
57}
58
59CTestApp::CTestApp(
60	int 	inArgc,
61	char **	inArgv)
62	:mArgc(inArgc), mArgv(inArgv),
63	mVerbose(false), mRelaxErrorChecking(false)
64{
65}
66
67void
68CTestApp::Run()
69{
70	int				ch;
71	bool 			didWork = false;
72	const char		*options = "hH?vlew:f:r:R:n:s:S";
73
74#if TARGET_RT_MAC_MACHO
75	extern char *	optarg;
76	while ((ch = getopt(mArgc, mArgv, options)) != -1){
77#else
78	char *	optarg = NULL;
79	for(int i=1; i<mArgc; i++){
80		if(mArgv[i][0] == '-'){
81			char *p;
82			ch = mArgv[i][1];
83			if(p = strchr(options, ch))
84				if(p[1] == ':') optarg = mArgv[++i];
85		}
86#endif
87		switch(ch){
88			case 'v':{
89				mVerbose = true;
90				break;
91			}
92
93			case 'e':{
94				mRelaxErrorChecking = true;
95				break;
96			}
97
98			case 's':{
99				DoRunSubTestScript(optarg);
100				didWork = true;
101				break;
102			}
103
104			case 'w':{
105				DoDumpScript(optarg);
106				didWork = true;
107				break;
108			}
109
110			case 'f':{
111				UInt32	aPass, aFail;
112				DoRunScript(optarg, aPass, aFail);
113				didWork = true;
114				break;
115			}
116
117			case 'n':{
118				DoRunTestScript(optarg);
119				didWork = true;
120				break;
121			}
122
123			case 'R':
124			case 'r':{
125				DoRadar(optarg);
126				didWork = true;
127				break;
128			}
129
130			case 'l':{
131				DoRadar(NULL);
132				didWork = true;
133				break;
134			}
135
136			case 'h':
137			case 'H':
138			case '?':
139				break;
140
141			case 'S':
142				gSleep=1;
143				break;
144		}
145	}
146	if(!didWork) goto showUsage;
147        return;
148showUsage:
149    {
150        char	* aProgname = strrchr(mArgv[0], '/');
151        aProgname = (aProgname) ? aProgname+1 : mArgv[0];
152
153        fprintf(stderr, "Usage : %s [-v][-e][-r {all} {ID}][-l][-n scriptNo][-s scriptNo][-f filename][-w {all} {ID}][-S]  \n", aProgname);
154        fprintf(stderr, "        -v    verbose\n");
155        fprintf(stderr, "        -e    relax return code checking\n");
156        fprintf(stderr, "        -s    run sub-test cases\n");
157        fprintf(stderr, "        -r    run a Radar bug\n");
158        fprintf(stderr, "        -l    list all Radar bugs\n");
159        fprintf(stderr, "        -n    run a test script\n");
160        fprintf(stderr, "        -f    run your script\n");
161        fprintf(stderr, "        -w    dump a script template\n");
162        fprintf(stderr, "        -S    sleep before exiting (for use with MallocDebug)\n");
163        fprintf(stderr, "\n      default args -venall\n");
164
165
166    }
167}
168
169
170// ���������������������������������������������������������������������������
171// 	� DoRunTestScript
172// ���������������������������������������������������������������������������
173void
174CTestApp::DoRunTestScript(
175	const char *inScriptNo)
176{
177	FILE	*aInput;
178	char	aFullPath[256];
179	UInt32	aPassCount = 0;
180	UInt32	aFailCount = 0;
181
182        if(!strcmp(inScriptNo, "all")){
183		for(UInt32 i=0; i<50 /* 9999 */; i++){
184#if TARGET_RT_MAC_MACHO
185			sprintf(aFullPath, "%s/script%04ld", TEST_SCRIPT_PATH, i);
186#else
187			sprintf(aFullPath, "%s:script%04ld", TEST_SCRIPT_PATH, i);
188#endif
189			if((aInput = fopen(aFullPath, "r")) != NULL){
190				UInt32	aPass=0, aFail=0;
191				if(mVerbose) printf("\n\n-> -> -> Running script%04ld ...\n", i);
192				DoRunScript(aInput, aPass, aFail);
193				aPassCount += aPass;
194				aFailCount += aFail;
195				fclose(aInput);
196			}
197		}
198	}
199        else{
200
201#if TARGET_RT_MAC_MACHO
202		sprintf(aFullPath, "%s//script%04d", TEST_SCRIPT_PATH, atoi(inScriptNo));
203#else
204		sprintf(aFullPath, "%s:script%04d", TEST_SCRIPT_PATH, atoi(inScriptNo));
205#endif
206
207		if((aInput = fopen(aFullPath, "r")) != NULL){
208			DoRunScript(aInput, aPassCount, aFailCount);
209			fclose(aInput);
210		}
211		else{
212			fprintf(stderr, "No script file for [%s]\n", inScriptNo);
213			return;
214		}
215	}
216
217	printf("Total number of test cases executed %ld : (passed = %ld, failed = %ld)\n", aPassCount+aFailCount, aPassCount, aFailCount);
218}
219
220// ���������������������������������������������������������������������������
221// 	� DoRunSubTestScript
222// ���������������������������������������������������������������������������
223void
224CTestApp::DoRunSubTestScript(
225	const char *	inScriptNo)
226{
227	FILE	*aInput;
228	char	aFullPath[256];
229	UInt32	aPassCount = 0;
230	UInt32	aFailCount = 0;
231	UInt32	aStartScript = 0;
232	UInt32	aEndScript = 50; /* 9999 */
233
234                                        // not "all" - run the specified test case's sub-test cases
235        if(strcmp(inScriptNo, "all")){
236            aStartScript = aEndScript = atoi(inScriptNo);
237        }
238
239        for(UInt32 j=aStartScript; j<=aEndScript; j++){
240            for(UInt32 i=0; i<5 /*999*/; i++){
241#if TARGET_RT_MAC_MACHO
242		sprintf(aFullPath, "%s//script%04ld.%03ld", TEST_SCRIPT_PATH, j, i);
243#else
244		sprintf(aFullPath, "%s:script%04ld.%03ld", TEST_SCRIPT_PATH, j, i);
245#endif
246
247		if((aInput = fopen(aFullPath, "r")) != NULL){
248			UInt32	aPass, aFail;
249			if(mVerbose) printf("\n\n-> -> -> Running script%04ld.%03ld ...\n", j, i);
250			DoRunScript(aInput, aPass, aFail);
251			aPassCount += aPass;
252			aFailCount += aFail;
253			fclose(aInput);
254		}
255            }
256	}
257
258	printf("Total number of test cases executed %ld : (passed = %ld, failed = %ld)\n", aPassCount+aFailCount, aPassCount, aFailCount);
259}
260
261// ���������������������������������������������������������������������������
262// 	� DoRunScript
263// ���������������������������������������������������������������������������
264void
265CTestApp::DoRunScript(
266	const char	*inPath,
267	UInt32		&outPass,
268	UInt32		&outFail)
269{
270	Cleanup();
271
272	FILE			*aInput = fopen(inPath, "r");
273	if(aInput == NULL){
274		fprintf(stderr, "ERROR Cannot open the file %s\n", inPath);
275		return;
276	}
277	DoRunScript(aInput, outPass, outFail);
278	fclose(aInput);
279}
280
281// ���������������������������������������������������������������������������
282// 	� DoRunScript
283// ���������������������������������������������������������������������������
284void
285CTestApp::DoRunScript(
286	FILE	*inFile,
287	UInt32	&outPass,
288	UInt32	&outFail)
289{
290	Cleanup();
291
292	eKCOperationID	aID;
293	UInt32			aPassCount = 0;
294	UInt32			aFailCount = 0;
295
296	try{
297		while(KCOperation::ReadScript(inFile, aID) != EOF){
298                                       KCOperation	*aOperation = (KCOperation*)COpRegister::CreateOperation(aID, this);
299			if(aOperation == NULL){
300				fprintf(stderr, "ERROR COpRegister::CreateOperation(%d) failed\n", aID);
301				break;
302			}
303
304			bool	aResult = aOperation->RunScript(inFile);
305			aPassCount += (aResult) ? 1 : 0;
306			aFailCount += (!aResult) ? 1 : 0;
307			if(mVerbose){
308				printf("TestCase No.%04ld (%s): %s\n", aPassCount+aFailCount, COpRegister::GetOperationName(aID), (aResult) ? "PASSED" : "FAILED");
309				if(!aResult){
310					fprintf(stdout, "%d %s\n", aID, COpRegister::GetOperationName(aID));
311					aOperation->WriteResults(stdout);
312				}
313			}
314			delete aOperation;
315		}
316	}
317	catch(const char *inErrorMsg){
318		fprintf(stderr, "ERROR : %s\n", inErrorMsg);
319		fprintf(stderr, "   Terminating this script\n");
320	}
321
322	outPass = aPassCount;
323	outFail = aFailCount;
324
325}
326
327// ���������������������������������������������������������������������������
328// 	� DoDumpScript
329// ���������������������������������������������������������������������������
330void
331CTestApp::DoDumpScript(
332	const char	*inOperationNo)
333{
334	FILE	*aOutput = stdout;
335	bool	aDoAll = (strcmp(inOperationNo, "all") == 0);
336
337	for(long i=0; i<OpID_NumOperations; i++){
338		if(aDoAll || (atoi(inOperationNo) == i)){
339			KCOperation	*aOperation = (KCOperation*)COpRegister::CreateOperation((eKCOperationID)i, this);
340			if(aOperation == NULL){
341				fprintf(stderr, "ERROR COpRegister::CreateOperation(%ld) failed\n", i);
342				continue;
343			}
344//			aOperation->Operate();
345			aOperation->WriteScript(aOutput);
346			delete aOperation;
347		}
348	}
349}
350
351
352
353// ���������������������������������������������������������������������������
354// 	� DoRadar
355// ���������������������������������������������������������������������������
356void
357CTestApp::DoRadar(
358	const char *inArg)
359{
360    UInt32	i=0;
361
362										// -l (list all Radar bug descriptions)
363    if(inArg == NULL){
364        while(gRadarBugs[i].testCaseFunc){
365            printf("%s %s\n", gRadarBugs[i].ID, gRadarBugs[i].desc);
366            i++;
367        }
368    }
369										// -r all (run all Radar bugs)
370    else if(!strcmp(inArg, "all")){
371        while(gRadarBugs[i].testCaseFunc){
372            printf(">>>>>>>>>> Radar %s >>>>>>>>>>\n", gRadarBugs[i].ID);
373            printf("%s\n", gRadarBugs[i].desc);
374            (gRadarBugs[i].testCaseFunc)(this);
375            printf("<<<<<<<<<< Radar %s done <<<<<<<<<<\n\n", gRadarBugs[i].ID);
376
377            i++;
378        }
379    }
380										// -r nnnnn (run a specific Radar bug)
381    else{
382        while(gRadarBugs[i].testCaseFunc){
383            if(!strcmp(inArg, gRadarBugs[i].ID)){
384                (gRadarBugs[i].testCaseFunc)(this);
385                return;
386            }
387            i++;
388        }
389        fprintf(stderr, "No such Radar ID\n");
390        DoRadar(NULL);
391    }
392}
393
394void
395CTestApp::Cleanup()
396{
397	KCOperation::Cleanup();
398	KCItemOperation::Cleanup();
399	KCSearchOperation::Cleanup();
400}
401
402#if TARGET_RT_MAC_MACHO
403char*
404GetResourcePath(char **inArgv)
405{
406									// Can I do better than this ?
407	const char	*aResourcesDir = "../Resources/";
408	const char	*progname;
409	char		*aResourcePath = NULL;
410	int			len;
411
412	progname = strrchr(inArgv[0], '/');
413	len = (progname) ? (strlen(inArgv[0]) - strlen(progname)+1) : 0;
414	aResourcePath = new char[len + strlen(aResourcesDir)+1];
415	if(len) memcpy(aResourcePath, inArgv[0], len);
416	memcpy(aResourcePath+len, aResourcesDir, strlen(aResourcesDir));
417        aResourcePath[len+strlen(aResourcesDir)] = '\0';
418	return(aResourcePath);
419}
420#else
421char*
422GetResourcePath(char **inArgv)
423{
424										// ��� temp solution
425	return("Work:CVS Project:Security:Tests:testKeychainAPI:testKeychainAPI:scripts");
426}
427
428void GetArg(
429	int		&outArgc,
430	char**	&outArgv)
431{
432										// emulate the command line arg
433	const char	*kProgname = "testKeychainAPI";
434	char		*aBuffer = new char[1024];
435
436	memset(aBuffer, 0, 1024);
437	strcpy(aBuffer, kProgname);
438	int	i = strlen(kProgname)+1;
439
440	cout << kProgname << " ";
441	cin.getline(aBuffer+i, 1024-i);
442	for(; i<1028; i++) if(aBuffer[i] == ' ') aBuffer[i] = '\0';
443
444	int		j = 0;
445	char	*p = aBuffer;
446	char	**argv = new char*[128];
447	do{
448		if(strlen(p) > 0) argv[j++] = p;
449		p += strlen(p)+1;
450	} while(p < aBuffer+1024);
451
452	outArgc = j;
453	outArgv = argv;
454}
455
456char*
457UNIX_fgets(
458	char	*inBuffer,
459	int		inSize,
460	FILE	*inFile)
461{
462									// Scripts are in UNIX format
463									// so fgets() does not work on ClassicMac
464									// as is
465	for(int i=0; i<inSize; i++){
466		inBuffer[i] = fgetc(inFile);
467		if(inBuffer[i] != '\r' && inBuffer[i] != '\n' && inBuffer[i] != EOF) continue;
468		if(inBuffer[i] == EOF && i==0) return NULL;
469		inBuffer[i] = '\n';
470		inBuffer[i+1] = '\0';
471		break;
472	}
473	return inBuffer;
474}
475
476#endif
477