Back to home page

Enduro/X

 
 

    


0001 #ifdef WIN32
0002 #include "runner.h"
0003 #include "cgreen/internal/runner_platform.h"
0004 #include "cgreen/messaging.h"
0005 #include "wincompat.h"
0006 
0007 #ifdef __cplusplus
0008 namespace cgreen {
0009 #endif
0010 
0011 
0012 #include "Strsafe.h"
0013 #define SECOND  (1000)
0014 static void run_named_test_child(TestSuite *suite, const char *name, TestReporter *reporter);
0015 static void run_test_in_its_own_process_child(TestSuite *suite, CgreenTest *test, TestReporter *reporter);
0016 
0017 
0018 static void CALLBACK stop(UINT uTimerID, UINT uMsg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2)
0019 {
0020     _exit(EXIT_SUCCESS);
0021 }
0022 
0023 void die_in(unsigned int seconds) {
0024     MMRESULT signal_result = timeSetEvent(seconds*SECOND,SECOND,&stop,0,TIME_ONESHOT);
0025     if (0 == signal_result){
0026         fprintf(stderr, "could not set alarm signal hander\n");
0027         return;
0028     }
0029 }
0030 
0031 static void run_test_in_the_current_process_child(TestSuite *suite, CgreenTest *test, TestReporter *reporter) {
0032     (*reporter->start_test)(reporter, test->name);
0033     run_the_test_code(suite, test, reporter);
0034     send_reporter_completion_notification(reporter);
0035     stop(0, 0, 0, 0, 0);
0036 }
0037 
0038 static void run_named_test_child(TestSuite *suite, const char *name, TestReporter *reporter) {
0039     int i;
0040     //(*reporter->start_suite)(reporter, suite->name, count_tests(suite));
0041     for (i = 0; i < suite->size; i++) {
0042         if (suite->tests[i].type == test_function) {
0043             if (strcmp(suite->tests[i].name, name) == 0) {
0044                 run_test_in_the_current_process_child(suite, suite->tests[i].Runnable.test, reporter);
0045             }
0046         } else if (has_test(suite->tests[i].Runnable.suite, name)) {
0047             TestSuite* newSuite=suite->tests[i].Runnable.suite;
0048             (*suite->setup)();
0049             //moved recursive calls to start_suite and finish_suite to the caller, so I
0050             //can control the printf that occurs in the first one.
0051             //This may have undesireable side effects.  Not sure of the best solution
0052             (*reporter->start_suite)(reporter, newSuite->name, count_tests(newSuite));
0053             run_named_test_child(newSuite, name, reporter);
0054             (*reporter->finish_suite)(reporter, newSuite->filename, newSuite->line);
0055             (*suite->teardown)();
0056         }
0057     }
0058     send_reporter_completion_notification(reporter);
0059 }
0060 
0061 void run_specified_test_if_child(TestSuite *suite, TestReporter *reporter){
0062     //figure out if we are a child process, and if so, use the test name provided by our parent
0063     char testName[256];
0064     DWORD result = GetEnvironmentVariableA(CGREEN_TEST_TO_RUN,testName,sizeof(testName));
0065 
0066     if (result) //we are a child process, only run the specified test
0067     {
0068         //May have to deal with some issues here.  I don't call the function pointer for
0069         //reporter start and finish in order to avoid extraneous prints to the console,
0070         //but this may cause problems for other types of reporters.  Not sure the
0071         //best solution for this.
0072         reporter_start(reporter, testName);  //add breadcrumb without triggering output to console
0073         run_named_test_child(suite, testName, reporter);
0074         reporter_finish(reporter, suite->filename, suite->line, NULL);
0075 
0076         return; //never happens because we call stop inside run_named_test_child
0077     }
0078 
0079 }
0080 
0081 struct environment
0082 {
0083     char env[MAX_PATH];
0084     char *p_head;
0085 };
0086 
0087 struct environment* create_environment()
0088 {
0089     struct environment* p = (struct environment*)malloc(sizeof(struct environment));
0090     memset(p->env, 0, sizeof(p->env));
0091     p->p_head = p->env;
0092     return p;
0093 }
0094 
0095 static void AddEnvironmentVariable(struct environment* env,const char* varName, const char* valueString)
0096 {
0097     size_t len;
0098     size_t envSize = MAX_PATH - (env->p_head-env->env);
0099     StringCbCopyA(env->p_head, envSize, varName);
0100     StringCbCatA(env->p_head, envSize, "=");
0101     StringCbCatA(env->p_head, envSize, valueString);
0102     StringCbCatA(env->p_head, envSize, "\0");
0103     len = strnlen_s(env->p_head, envSize);
0104     env->p_head += (len + 1);
0105 }
0106 
0107 static const char* get_environment_block(const struct environment* env)
0108 {
0109     return env->env;
0110 }
0111 
0112 static void dispose_environment(struct environment* env)
0113 {
0114     free(env);
0115 }
0116 
0117 
0118 void run_test_in_its_own_process(TestSuite *suite, CgreenTest *test, TestReporter *reporter) {
0119 #define COMMAND_LINE_LENGTH (2*MAX_PATH)
0120     BOOL success;
0121     char fname[MAX_PATH+1]; //make enough room for full path  plus null terminator
0122     struct environment* p_environment = create_environment();
0123     char handleString[256];
0124 
0125     STARTUPINFOA siStartupInfo;
0126     PROCESS_INFORMATION piProcessInfo;
0127 
0128     //get executable path
0129     GetModuleFileNameA(NULL, fname,MAX_PATH);
0130 
0131     //launch process
0132     memset(&siStartupInfo, 0, sizeof(siStartupInfo));
0133     memset(&piProcessInfo, 0, sizeof(piProcessInfo));
0134     siStartupInfo.cb = sizeof(siStartupInfo);
0135 
0136     sprintf_s(handleString,sizeof(handleString), "%i", get_pipe_read_handle());
0137     AddEnvironmentVariable(p_environment, CGREEN_READ_HANDLE, handleString);
0138 
0139     sprintf_s(handleString,sizeof(handleString), "%i", get_pipe_write_handle());
0140     AddEnvironmentVariable(p_environment, CGREEN_WRITE_HANDLE, handleString);
0141 
0142     //put name of test to run in environment
0143     AddEnvironmentVariable(p_environment, CGREEN_TEST_TO_RUN, test->name);
0144 
0145     (*reporter->start_test)(reporter, test->name);
0146     //success = CreateProcessA(fname, NULL, NULL, NULL, true, NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW , p_environment, NULL, &siStartupInfo, &piProcessInfo);
0147     success = CreateProcessA(fname, NULL, NULL, NULL, true, NORMAL_PRIORITY_CLASS , p_environment, NULL, &siStartupInfo, &piProcessInfo);
0148     dispose_environment(p_environment);
0149     WaitForSingleObject(piProcessInfo.hProcess,INFINITE);
0150     (*reporter->finish_test)(reporter, test->filename, test->line, NULL);
0151 
0152     return;
0153 }
0154 
0155 
0156 #ifdef __cplusplus
0157 } // namespace cgreen
0158 #endif
0159 
0160 #endif
0161 /* vim: set ts=4 sw=4 et cindent: */