539 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			539 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * Copyright (C) 2007 The Android Open Source Project
 | |
|  *
 | |
|  * Licensed under the Apache License, Version 2.0 (the "License");
 | |
|  * you may not use this file except in compliance with the License.
 | |
|  * You may obtain a copy of the License at
 | |
|  *
 | |
|  *      http://www.apache.org/licenses/LICENSE-2.0
 | |
|  *
 | |
|  * Unless required by applicable law or agreed to in writing, software
 | |
|  * distributed under the License is distributed on an "AS IS" BASIS,
 | |
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | |
|  * See the License for the specific language governing permissions and
 | |
|  * limitations under the License.
 | |
|  */
 | |
| 
 | |
| #include <stdlib.h>
 | |
| #include <string.h>
 | |
| #include <stdio.h>
 | |
| #undef NDEBUG
 | |
| #include <assert.h>
 | |
| #include "commands.h"
 | |
| 
 | |
| static struct {
 | |
|     bool called;
 | |
|     const char *name;
 | |
|     void *cookie;
 | |
|     int argc;
 | |
|     const char **argv;
 | |
|     PermissionRequestList *permissions;
 | |
|     int returnValue;
 | |
|     char *functionResult;
 | |
| } gTestCommandState;
 | |
| 
 | |
| static int
 | |
| testCommand(const char *name, void *cookie, int argc, const char *argv[],
 | |
|         PermissionRequestList *permissions)
 | |
| {
 | |
|     gTestCommandState.called = true;
 | |
|     gTestCommandState.name = name;
 | |
|     gTestCommandState.cookie = cookie;
 | |
|     gTestCommandState.argc = argc;
 | |
|     gTestCommandState.argv = argv;
 | |
|     gTestCommandState.permissions = permissions;
 | |
|     return gTestCommandState.returnValue;
 | |
| }
 | |
| 
 | |
| static int
 | |
| testFunction(const char *name, void *cookie, int argc, const char *argv[],
 | |
|         char **result, size_t *resultLen, PermissionRequestList *permissions)
 | |
| {
 | |
|     gTestCommandState.called = true;
 | |
|     gTestCommandState.name = name;
 | |
|     gTestCommandState.cookie = cookie;
 | |
|     gTestCommandState.argc = argc;
 | |
|     gTestCommandState.argv = argv;
 | |
|     gTestCommandState.permissions = permissions;
 | |
|     if (result != NULL) {
 | |
|         *result = gTestCommandState.functionResult;
 | |
|         if (resultLen != NULL) {
 | |
|             *resultLen = strlen(*result);
 | |
|         }
 | |
|     }
 | |
|     return gTestCommandState.returnValue;
 | |
| }
 | |
| 
 | |
| static int
 | |
| test_commands()
 | |
| {
 | |
|     Command *cmd;
 | |
|     int ret;
 | |
|     CommandArgumentType argType;
 | |
| 
 | |
|     ret = commandInit();
 | |
|     assert(ret == 0);
 | |
| 
 | |
|     /* Make sure we can't initialize twice.
 | |
|      */
 | |
|     ret = commandInit();
 | |
|     assert(ret < 0);
 | |
| 
 | |
|     /* Try calling with some bad values.
 | |
|      */
 | |
|     ret = registerCommand(NULL, CMD_ARGS_UNKNOWN, NULL, NULL);
 | |
|     assert(ret < 0);
 | |
| 
 | |
|     ret = registerCommand("hello", CMD_ARGS_UNKNOWN, NULL, NULL);
 | |
|     assert(ret < 0);
 | |
| 
 | |
|     ret = registerCommand("hello", CMD_ARGS_WORDS, NULL, NULL);
 | |
|     assert(ret < 0);
 | |
| 
 | |
|     cmd = findCommand(NULL);
 | |
|     assert(cmd == NULL);
 | |
| 
 | |
|     argType = getCommandArgumentType(NULL);
 | |
|     assert((int)argType < 0);
 | |
| 
 | |
|     ret = callCommand(NULL, -1, NULL);
 | |
|     assert(ret < 0);
 | |
| 
 | |
|     ret = callBooleanCommand(NULL, false);
 | |
|     assert(ret < 0);
 | |
| 
 | |
|     /* Register some commands.
 | |
|      */
 | |
|     ret = registerCommand("one", CMD_ARGS_WORDS, testCommand,
 | |
|             &gTestCommandState);
 | |
|     assert(ret == 0);
 | |
| 
 | |
|     ret = registerCommand("two", CMD_ARGS_WORDS, testCommand,
 | |
|             &gTestCommandState);
 | |
|     assert(ret == 0);
 | |
| 
 | |
|     ret = registerCommand("bool", CMD_ARGS_BOOLEAN, testCommand,
 | |
|             &gTestCommandState);
 | |
|     assert(ret == 0);
 | |
| 
 | |
|     /* Make sure that all of those commands exist and that their
 | |
|      * argument types are correct.
 | |
|      */
 | |
|     cmd = findCommand("one");
 | |
|     assert(cmd != NULL);
 | |
|     argType = getCommandArgumentType(cmd);
 | |
|     assert(argType == CMD_ARGS_WORDS);
 | |
| 
 | |
|     cmd = findCommand("two");
 | |
|     assert(cmd != NULL);
 | |
|     argType = getCommandArgumentType(cmd);
 | |
|     assert(argType == CMD_ARGS_WORDS);
 | |
| 
 | |
|     cmd = findCommand("bool");
 | |
|     assert(cmd != NULL);
 | |
|     argType = getCommandArgumentType(cmd);
 | |
|     assert(argType == CMD_ARGS_BOOLEAN);
 | |
| 
 | |
|     /* Make sure that no similar commands exist.
 | |
|      */
 | |
|     cmd = findCommand("on");
 | |
|     assert(cmd == NULL);
 | |
| 
 | |
|     cmd = findCommand("onee");
 | |
|     assert(cmd == NULL);
 | |
| 
 | |
|     /* Make sure that a double insertion fails.
 | |
|      */
 | |
|     ret = registerCommand("one", CMD_ARGS_WORDS, testCommand,
 | |
|             &gTestCommandState);
 | |
|     assert(ret < 0);
 | |
| 
 | |
|     /* Make sure that bad args fail.
 | |
|      */
 | |
|     cmd = findCommand("one");
 | |
|     assert(cmd != NULL);
 | |
| 
 | |
|     ret = callCommand(cmd, -1, NULL);   // argc must be non-negative
 | |
|     assert(ret < 0);
 | |
| 
 | |
|     ret = callCommand(cmd, 1, NULL);    // argv can't be NULL if argc > 0
 | |
|     assert(ret < 0);
 | |
| 
 | |
|     /* Make sure that you can't make a boolean call on a regular command.
 | |
|      */
 | |
|     cmd = findCommand("one");
 | |
|     assert(cmd != NULL);
 | |
| 
 | |
|     ret = callBooleanCommand(cmd, false);
 | |
|     assert(ret < 0);
 | |
| 
 | |
|     /* Make sure that you can't make a regular call on a boolean command.
 | |
|      */
 | |
|     cmd = findCommand("bool");
 | |
|     assert(cmd != NULL);
 | |
| 
 | |
|     ret = callCommand(cmd, 0, NULL);
 | |
|     assert(ret < 0);
 | |
| 
 | |
|     /* Set up some arguments.
 | |
|      */
 | |
|     int argc = 4;
 | |
|     const char *argv[4] = { "ONE", "TWO", "THREE", "FOUR" };
 | |
| 
 | |
|     /* Make a call and make sure that it occurred.
 | |
|      */
 | |
|     cmd = findCommand("one");
 | |
|     assert(cmd != NULL);
 | |
|     memset(&gTestCommandState, 0, sizeof(gTestCommandState));
 | |
|     gTestCommandState.called = false;
 | |
|     gTestCommandState.returnValue = 25;
 | |
|     gTestCommandState.permissions = (PermissionRequestList *)1;
 | |
|     ret = callCommand(cmd, argc, argv);
 | |
| //xxx also try calling with a null argv element (should fail)
 | |
|     assert(ret == 25);
 | |
|     assert(gTestCommandState.called);
 | |
|     assert(strcmp(gTestCommandState.name, "one") == 0);
 | |
|     assert(gTestCommandState.cookie == &gTestCommandState);
 | |
|     assert(gTestCommandState.argc == argc);
 | |
|     assert(gTestCommandState.argv == argv);
 | |
|     assert(gTestCommandState.permissions == NULL);
 | |
| 
 | |
|     /* Make a boolean call and make sure that it occurred.
 | |
|      */
 | |
|     cmd = findCommand("bool");
 | |
|     assert(cmd != NULL);
 | |
| 
 | |
|     memset(&gTestCommandState, 0, sizeof(gTestCommandState));
 | |
|     gTestCommandState.called = false;
 | |
|     gTestCommandState.returnValue = 12;
 | |
|     gTestCommandState.permissions = (PermissionRequestList *)1;
 | |
|     ret = callBooleanCommand(cmd, false);
 | |
|     assert(ret == 12);
 | |
|     assert(gTestCommandState.called);
 | |
|     assert(strcmp(gTestCommandState.name, "bool") == 0);
 | |
|     assert(gTestCommandState.cookie == &gTestCommandState);
 | |
|     assert(gTestCommandState.argc == 0);
 | |
|     assert(gTestCommandState.argv == NULL);
 | |
|     assert(gTestCommandState.permissions == NULL);
 | |
| 
 | |
|     memset(&gTestCommandState, 0, sizeof(gTestCommandState));
 | |
|     gTestCommandState.called = false;
 | |
|     gTestCommandState.returnValue = 13;
 | |
|     gTestCommandState.permissions = (PermissionRequestList *)1;
 | |
|     ret = callBooleanCommand(cmd, true);
 | |
|     assert(ret == 13);
 | |
|     assert(gTestCommandState.called);
 | |
|     assert(strcmp(gTestCommandState.name, "bool") == 0);
 | |
|     assert(gTestCommandState.cookie == &gTestCommandState);
 | |
|     assert(gTestCommandState.argc == 1);
 | |
|     assert(gTestCommandState.argv == NULL);
 | |
|     assert(gTestCommandState.permissions == NULL);
 | |
| 
 | |
|     /* Try looking up permissions.
 | |
|      */
 | |
|     PermissionRequestList permissions;
 | |
|     cmd = findCommand("one");
 | |
|     assert(cmd != NULL);
 | |
|     memset(&gTestCommandState, 0, sizeof(gTestCommandState));
 | |
|     gTestCommandState.called = false;
 | |
|     gTestCommandState.returnValue = 27;
 | |
|     gTestCommandState.permissions = (PermissionRequestList *)1;
 | |
|     argv[1] = NULL; // null out an arg, which should be ok
 | |
|     ret = getCommandPermissions(cmd, argc, argv, &permissions);
 | |
|     assert(ret == 27);
 | |
|     assert(gTestCommandState.called);
 | |
|     assert(strcmp(gTestCommandState.name, "one") == 0);
 | |
|     assert(gTestCommandState.cookie == &gTestCommandState);
 | |
|     assert(gTestCommandState.argc == argc);
 | |
|     assert(gTestCommandState.argv == argv);
 | |
|     assert(gTestCommandState.permissions == &permissions);
 | |
| 
 | |
|     /* Boolean command permissions
 | |
|      */
 | |
|     cmd = findCommand("bool");
 | |
|     assert(cmd != NULL);
 | |
|     memset(&gTestCommandState, 0, sizeof(gTestCommandState));
 | |
|     gTestCommandState.called = false;
 | |
|     gTestCommandState.returnValue = 55;
 | |
|     gTestCommandState.permissions = (PermissionRequestList *)1;
 | |
|     // argv[1] is still NULL
 | |
|     ret = getBooleanCommandPermissions(cmd, true, &permissions);
 | |
|     assert(ret == 55);
 | |
|     assert(gTestCommandState.called);
 | |
|     assert(strcmp(gTestCommandState.name, "bool") == 0);
 | |
|     assert(gTestCommandState.cookie == &gTestCommandState);
 | |
|     assert(gTestCommandState.argc == 1);
 | |
|     assert(gTestCommandState.argv == NULL);
 | |
|     assert(gTestCommandState.permissions == &permissions);
 | |
| 
 | |
| 
 | |
|     /* Smoke test commandCleanup().
 | |
|      */
 | |
|     commandCleanup();
 | |
| 
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| static int
 | |
| test_functions()
 | |
| {
 | |
|     Function *fn;
 | |
|     int ret;
 | |
| 
 | |
|     ret = commandInit();
 | |
|     assert(ret == 0);
 | |
| 
 | |
|     /* Try calling with some bad values.
 | |
|      */
 | |
|     ret = registerFunction(NULL, NULL, NULL);
 | |
|     assert(ret < 0);
 | |
| 
 | |
|     ret = registerFunction("hello", NULL, NULL);
 | |
|     assert(ret < 0);
 | |
| 
 | |
|     fn = findFunction(NULL);
 | |
|     assert(fn == NULL);
 | |
| 
 | |
|     ret = callFunction(NULL, -1, NULL, NULL, NULL);
 | |
|     assert(ret < 0);
 | |
| 
 | |
|     /* Register some functions.
 | |
|      */
 | |
|     ret = registerFunction("one", testFunction, &gTestCommandState);
 | |
|     assert(ret == 0);
 | |
| 
 | |
|     ret = registerFunction("two", testFunction, &gTestCommandState);
 | |
|     assert(ret == 0);
 | |
| 
 | |
|     ret = registerFunction("three", testFunction, &gTestCommandState);
 | |
|     assert(ret == 0);
 | |
| 
 | |
|     /* Make sure that all of those functions exist.
 | |
|      * argument types are correct.
 | |
|      */
 | |
|     fn = findFunction("one");
 | |
|     assert(fn != NULL);
 | |
| 
 | |
|     fn = findFunction("two");
 | |
|     assert(fn != NULL);
 | |
| 
 | |
|     fn = findFunction("three");
 | |
|     assert(fn != NULL);
 | |
| 
 | |
|     /* Make sure that no similar functions exist.
 | |
|      */
 | |
|     fn = findFunction("on");
 | |
|     assert(fn == NULL);
 | |
| 
 | |
|     fn = findFunction("onee");
 | |
|     assert(fn == NULL);
 | |
| 
 | |
|     /* Make sure that a double insertion fails.
 | |
|      */
 | |
|     ret = registerFunction("one", testFunction, &gTestCommandState);
 | |
|     assert(ret < 0);
 | |
| 
 | |
|     /* Make sure that bad args fail.
 | |
|      */
 | |
|     fn = findFunction("one");
 | |
|     assert(fn != NULL);
 | |
| 
 | |
|     // argc must be non-negative
 | |
|     ret = callFunction(fn, -1, NULL, (char **)1, NULL);
 | |
|     assert(ret < 0);
 | |
| 
 | |
|     // argv can't be NULL if argc > 0
 | |
|     ret = callFunction(fn, 1, NULL, (char **)1, NULL);
 | |
|     assert(ret < 0);
 | |
| 
 | |
|     // result can't be NULL
 | |
|     ret = callFunction(fn, 0, NULL, NULL, NULL);
 | |
|     assert(ret < 0);
 | |
| 
 | |
|     /* Set up some arguments.
 | |
|      */
 | |
|     int argc = 4;
 | |
|     const char *argv[4] = { "ONE", "TWO", "THREE", "FOUR" };
 | |
| 
 | |
|     /* Make a call and make sure that it occurred.
 | |
|      */
 | |
|     char *functionResult;
 | |
|     size_t functionResultLen;
 | |
|     fn = findFunction("one");
 | |
|     assert(fn != NULL);
 | |
|     memset(&gTestCommandState, 0, sizeof(gTestCommandState));
 | |
|     gTestCommandState.called = false;
 | |
|     gTestCommandState.returnValue = 25;
 | |
|     gTestCommandState.functionResult = "1234";
 | |
|     gTestCommandState.permissions = (PermissionRequestList *)1;
 | |
|     functionResult = NULL;
 | |
|     functionResultLen = 55;
 | |
|     ret = callFunction(fn, argc, argv,
 | |
|             &functionResult, &functionResultLen);
 | |
| //xxx also try calling with a null resultLen arg (should succeed)
 | |
| //xxx also try calling with a null argv element (should fail)
 | |
|     assert(ret == 25);
 | |
|     assert(gTestCommandState.called);
 | |
|     assert(strcmp(gTestCommandState.name, "one") == 0);
 | |
|     assert(gTestCommandState.cookie == &gTestCommandState);
 | |
|     assert(gTestCommandState.argc == argc);
 | |
|     assert(gTestCommandState.argv == argv);
 | |
|     assert(gTestCommandState.permissions == NULL);
 | |
|     assert(strcmp(functionResult, "1234") == 0);
 | |
|     assert(functionResultLen == strlen(functionResult));
 | |
| 
 | |
|     /* Try looking up permissions.
 | |
|      */
 | |
|     PermissionRequestList permissions;
 | |
|     fn = findFunction("one");
 | |
|     assert(fn != NULL);
 | |
|     memset(&gTestCommandState, 0, sizeof(gTestCommandState));
 | |
|     gTestCommandState.called = false;
 | |
|     gTestCommandState.returnValue = 27;
 | |
|     gTestCommandState.permissions = (PermissionRequestList *)1;
 | |
|     argv[1] = NULL; // null out an arg, which should be ok
 | |
|     ret = getFunctionPermissions(fn, argc, argv, &permissions);
 | |
|     assert(ret == 27);
 | |
|     assert(gTestCommandState.called);
 | |
|     assert(strcmp(gTestCommandState.name, "one") == 0);
 | |
|     assert(gTestCommandState.cookie == &gTestCommandState);
 | |
|     assert(gTestCommandState.argc == argc);
 | |
|     assert(gTestCommandState.argv == argv);
 | |
|     assert(gTestCommandState.permissions == &permissions);
 | |
| 
 | |
|     /* Smoke test commandCleanup().
 | |
|      */
 | |
|     commandCleanup();
 | |
| 
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| static int
 | |
| test_interaction()
 | |
| {
 | |
|     Command *cmd;
 | |
|     Function *fn;
 | |
|     int ret;
 | |
| 
 | |
|     ret = commandInit();
 | |
|     assert(ret == 0);
 | |
| 
 | |
|     /* Register some commands.
 | |
|      */
 | |
|     ret = registerCommand("one", CMD_ARGS_WORDS, testCommand, (void *)0xc1);
 | |
|     assert(ret == 0);
 | |
| 
 | |
|     ret = registerCommand("two", CMD_ARGS_WORDS, testCommand, (void *)0xc2);
 | |
|     assert(ret == 0);
 | |
| 
 | |
|     /* Register some functions, one of which shares a name with a command.
 | |
|      */
 | |
|     ret = registerFunction("one", testFunction, (void *)0xf1);
 | |
|     assert(ret == 0);
 | |
| 
 | |
|     ret = registerFunction("three", testFunction, (void *)0xf3);
 | |
|     assert(ret == 0);
 | |
| 
 | |
|     /* Look up each of the commands, and make sure no command exists
 | |
|      * with the name used only by our function.
 | |
|      */
 | |
|     cmd = findCommand("one");
 | |
|     assert(cmd != NULL);
 | |
| 
 | |
|     cmd = findCommand("two");
 | |
|     assert(cmd != NULL);
 | |
| 
 | |
|     cmd = findCommand("three");
 | |
|     assert(cmd == NULL);
 | |
| 
 | |
|     /* Look up each of the functions, and make sure no function exists
 | |
|      * with the name used only by our command.
 | |
|      */
 | |
|     fn = findFunction("one");
 | |
|     assert(fn != NULL);
 | |
| 
 | |
|     fn = findFunction("two");
 | |
|     assert(fn == NULL);
 | |
| 
 | |
|     fn = findFunction("three");
 | |
|     assert(fn != NULL);
 | |
| 
 | |
|     /* Set up some arguments.
 | |
|      */
 | |
|     int argc = 4;
 | |
|     const char *argv[4] = { "ONE", "TWO", "THREE", "FOUR" };
 | |
| 
 | |
|     /* Call the overlapping command and make sure that the cookie is correct.
 | |
|      */
 | |
|     cmd = findCommand("one");
 | |
|     assert(cmd != NULL);
 | |
|     memset(&gTestCommandState, 0, sizeof(gTestCommandState));
 | |
|     gTestCommandState.called = false;
 | |
|     gTestCommandState.returnValue = 123;
 | |
|     gTestCommandState.permissions = (PermissionRequestList *)1;
 | |
|     ret = callCommand(cmd, argc, argv);
 | |
|     assert(ret == 123);
 | |
|     assert(gTestCommandState.called);
 | |
|     assert(strcmp(gTestCommandState.name, "one") == 0);
 | |
|     assert((int)gTestCommandState.cookie == 0xc1);
 | |
|     assert(gTestCommandState.argc == argc);
 | |
|     assert(gTestCommandState.argv == argv);
 | |
|     assert(gTestCommandState.permissions == NULL);
 | |
| 
 | |
|     /* Call the overlapping function and make sure that the cookie is correct.
 | |
|      */
 | |
|     char *functionResult;
 | |
|     size_t functionResultLen;
 | |
|     fn = findFunction("one");
 | |
|     assert(fn != NULL);
 | |
|     memset(&gTestCommandState, 0, sizeof(gTestCommandState));
 | |
|     gTestCommandState.called = false;
 | |
|     gTestCommandState.returnValue = 125;
 | |
|     gTestCommandState.functionResult = "5678";
 | |
|     gTestCommandState.permissions = (PermissionRequestList *)2;
 | |
|     functionResult = NULL;
 | |
|     functionResultLen = 66;
 | |
|     ret = callFunction(fn, argc, argv, &functionResult, &functionResultLen);
 | |
|     assert(ret == 125);
 | |
|     assert(gTestCommandState.called);
 | |
|     assert(strcmp(gTestCommandState.name, "one") == 0);
 | |
|     assert((int)gTestCommandState.cookie == 0xf1);
 | |
|     assert(gTestCommandState.argc == argc);
 | |
|     assert(gTestCommandState.argv == argv);
 | |
|     assert(gTestCommandState.permissions == NULL);
 | |
|     assert(strcmp(functionResult, "5678") == 0);
 | |
|     assert(functionResultLen == strlen(functionResult));
 | |
| 
 | |
|     /* Clean up.
 | |
|      */
 | |
|     commandCleanup();
 | |
| 
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| int
 | |
| test_cmd_fn()
 | |
| {
 | |
|     int ret;
 | |
| 
 | |
|     ret = test_commands();
 | |
|     if (ret != 0) {
 | |
|         fprintf(stderr, "test_commands() failed: %d\n", ret);
 | |
|         return ret;
 | |
|     }
 | |
| 
 | |
|     ret = test_functions();
 | |
|     if (ret != 0) {
 | |
|         fprintf(stderr, "test_functions() failed: %d\n", ret);
 | |
|         return ret;
 | |
|     }
 | |
| 
 | |
|     ret = test_interaction();
 | |
|     if (ret != 0) {
 | |
|         fprintf(stderr, "test_interaction() failed: %d\n", ret);
 | |
|         return ret;
 | |
|     }
 | |
| 
 | |
|     return 0;
 | |
| }
 |