Coverage for /Syzygy/integration_tests/integration_tests_harness.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
64.4%56870.C++source

Line-by-line coverage:

   1    :  // Copyright 2014 Google Inc. All Rights Reserved.
   2    :  //
   3    :  // Licensed under the Apache License, Version 2.0 (the "License");
   4    :  // you may not use this file except in compliance with the License.
   5    :  // You may obtain a copy of the License at
   6    :  //
   7    :  //     http://www.apache.org/licenses/LICENSE-2.0
   8    :  //
   9    :  // Unless required by applicable law or agreed to in writing, software
  10    :  // distributed under the License is distributed on an "AS IS" BASIS,
  11    :  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12    :  // See the License for the specific language governing permissions and
  13    :  // limitations under the License.
  14    :  //
  15    :  // A harness for loading integration_tests_dll, and calling a test function
  16    :  // within it. This is intended for use with instrumented versions of the
  17    :  // DLL, and is required for certain tests that raise exceptions. The test has
  18    :  // to be moved to a separate process so as to avoid gtest interference in
  19    :  // exception handling.
  20    :  
  21    :  #include "base/command_line.h"
  22    :  #include "base/file_util.h"
  23    :  #include "base/logging.h"
  24    :  #include "base/files/file_path.h"
  25    :  #include "base/strings/string_number_conversions.h"
  26    :  #include "syzygy/common/com_utils.h"
  27    :  #include "syzygy/integration_tests/integration_tests_dll.h"
  28    :  
  29    :  namespace {
  30    :  
  31    :  typedef unsigned int (__stdcall* EndToEndTestFunction)(unsigned int);
  32    :  
  33    :  #define _STRINGIFY(s) #s
  34    :  #define STRINGIFY(s) _STRINGIFY(s)
  35    :  
  36    :  // An array of test names. The test integer ID is the position of the name in
  37    :  // the array.
  38    :  const char* kTestNames[] = {
  39    :  #define DEFINE_TEST_NAME(enum_name, function_name) STRINGIFY(enum_name),
  40    :    END_TO_END_TEST_ID_TABLE(DEFINE_TEST_NAME)
  41    :  #undef DEFINE_TEST_NAME
  42    :  };
  43    :  
  44    :  // Top level configuration and parameters.
  45    :  LPTOP_LEVEL_EXCEPTION_FILTER previous_unhandled_exception_filter = NULL;
  46  E :  base::FilePath dll;
  47    :  size_t test_id = 0;
  48    :  bool expect_exception = false;
  49    :  
  50  E :  bool ParseTestId(CommandLine* cmd_line) {
  51  E :    DCHECK_NE(reinterpret_cast<CommandLine*>(NULL), cmd_line);
  52    :  
  53  E :    std::string test = cmd_line->GetSwitchValueASCII("test");
  54  E :    if (test.empty()) {
  55  i :      LOG(ERROR) << "Must specify --test.";
  56  i :      return false;
  57    :    }
  58    :  
  59    :    // Search for the test by name
  60  E :    for (size_t i = 0; i < arraysize(kTestNames); ++i) {
  61  E :      if (test == kTestNames[i]) {
  62  i :        test_id = i;
  63  i :        return true;
  64    :      }
  65  E :    }
  66    :  
  67    :    // Try to convert the string to an integer.
  68  E :    if (!base::StringToSizeT(test, &test_id)) {
  69  i :      LOG(ERROR) << "Invalid test name or id: " << test;
  70  i :      return false;
  71    :    }
  72    :  
  73    :    // If integer parsing worked then ensure it's a valid test id.
  74  E :    if (test_id >= arraysize(kTestNames)) {
  75  i :      LOG(ERROR) << "Invalid test id: " << test_id;
  76  i :      return false;
  77    :    }
  78    :  
  79  E :    return true;
  80  E :  }
  81    :  
  82  E :  bool ParseCommandLine(CommandLine* cmd_line) {
  83  E :    DCHECK_NE(reinterpret_cast<CommandLine*>(NULL), cmd_line);
  84    :  
  85    :    // Parse and validate the path to the DLL.
  86  E :    dll = cmd_line->GetSwitchValuePath("dll");
  87  E :    if (dll.empty()) {
  88  i :      LOG(ERROR) << "Must specify --dll.";
  89  i :      return false;
  90    :    }
  91  E :    if (!base::PathExists(dll)) {
  92  i :      LOG(ERROR) << "File does not exist: " << dll.value();
  93  i :      return false;
  94    :    }
  95    :  
  96    :    // Parse the test ID.
  97  E :    if (!ParseTestId(cmd_line))
  98  i :      return false;
  99    :  
 100  E :    expect_exception = cmd_line->HasSwitch("expect-exception");
 101    :  
 102  E :    return true;
 103  E :  }
 104    :  
 105    :  // A utility function for terminating the process with a given return code.
 106  E :  void Exit(UINT code) {
 107  E :    if (code != 0) {
 108  i :      LOG(ERROR) << "Exiting with an error.";
 109  i :    } else {
 110  E :      VLOG(1) << "Terminating successfully.";
 111    :    }
 112  E :    ::TerminateProcess(::GetCurrentProcess(), code);
 113  E :  }
 114    :  
 115    :  // The base unhandled exception filter. If an exception is raised then this is
 116    :  // our exit path.
 117  E :  LONG WINAPI MyUnhandledExceptionFilter(struct _EXCEPTION_POINTERS* exception) {
 118  E :    VLOG(1) << "Entering UnhandledExceptionFilter.";
 119    :  
 120  E :    if (!expect_exception) {
 121  i :      LOG(ERROR) << "An exception was raised, but none was expected.";
 122  i :      Exit(1);
 123    :    }
 124  E :    Exit(0);
 125    :  
 126  E :    LOG(ERROR) << "Something went terribly wrong.";
 127  i :    return EXCEPTION_EXECUTE_HANDLER;
 128  i :  }
 129    :  
 130    :  }  // namespace
 131    :  
 132  E :  int main(int argc, char** argv) {
 133    :    // Initialize the command-line.
 134  E :    CommandLine::Init(argc, argv);
 135  E :    CommandLine* cmd_line = CommandLine::ForCurrentProcess();
 136    :  
 137    :    // Initialize logging.
 138  E :    logging::LoggingSettings settings;
 139  E :    settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG;
 140  E :    settings.lock_log = logging::DONT_LOCK_LOG_FILE;
 141  E :    settings.delete_old = logging::APPEND_TO_OLD_LOG_FILE;
 142  E :    logging::InitLogging(settings);
 143  E :    logging::SetMinLogLevel(logging::LOG_ERROR);
 144  E :    if (cmd_line->HasSwitch("verbose"))
 145  i :      logging::SetMinLogLevel(logging::LOG_VERBOSE);
 146    :  
 147    :    // Parse the command-line.
 148  E :    if (!ParseCommandLine(cmd_line))
 149  i :      return 1;
 150    :  
 151    :    // Prevent dialog boxes from popping up.
 152  E :    ::SetErrorMode(SEM_FAILCRITICALERRORS);
 153    :  
 154  E :    VLOG(1) << "Registering unhandled exception filter and callback.";
 155    :    previous_unhandled_exception_filter = ::SetUnhandledExceptionFilter(
 156  E :        &MyUnhandledExceptionFilter);
 157    :  
 158    :    // Load the module.
 159  E :    LOG(INFO) << "Loading module: " << dll.value();
 160  E :    HMODULE module = ::LoadLibrary(dll.value().c_str());
 161  E :    if (module == NULL) {
 162  i :      DWORD error = ::GetLastError();
 163  i :      LOG(ERROR) << "LoadLibrary failed: " << common::LogWe(error);
 164  i :      return 1;
 165    :    }
 166    :  
 167    :    // Get the EndToEndTest function. It is the entry point for calling
 168    :    // the various tests.
 169  E :    LOG(INFO) << "Looking up EndToEndTest function.";
 170    :    EndToEndTestFunction func = reinterpret_cast<EndToEndTestFunction>(
 171  E :        ::GetProcAddress(module, "EndToEndTest"));
 172  E :    if (func == NULL) {
 173  i :      LOG(ERROR) << "Failed to find EndToEndTest function.";
 174  i :      return 1;
 175    :    }
 176    :  
 177    :    // Invoke the test function.
 178  E :    LOG(INFO) << "Invoking test " << test_id << ".";
 179  E :    size_t ret = func(test_id);
 180    :  
 181  E :    if (expect_exception) {
 182  i :      LOG(ERROR) << "Expected an exception, but none was raised.";
 183  i :      LOG(ERROR) << "Command-line: " << cmd_line->GetCommandLineString();
 184  i :      Exit(1);
 185    :    }
 186  E :    Exit(0);
 187    :  
 188  E :    LOG(ERROR) << "Something went terribly wrong.";
 189  i :    return 1;
 190  i :  }

Coverage information generated Thu Mar 26 16:15:41 2015.