diff --git a/handler/crashpad_handler_test.cc b/handler/crashpad_handler_test.cc index 1534443a..65fed90f 100644 --- a/handler/crashpad_handler_test.cc +++ b/handler/crashpad_handler_test.cc @@ -37,8 +37,8 @@ namespace { constexpr DWORD kExpectedExitCode = 0x1CEB00DA; void StartAndCrashWithExtendedHandler(const base::FilePath& temp_dir) { - base::FilePath handler_path = TestPaths::Executable().DirName().Append( - FILE_PATH_LITERAL("crashpad_handler_test_extended_handler.exe")); + base::FilePath handler_path = TestPaths::BuildArtifact( + L"handler", L"extended_handler", TestPaths::FileType::kExecutable); CrashpadClient client; ASSERT_TRUE(client.StartHandler(handler_path, diff --git a/handler/win/crash_other_program.cc b/handler/win/crash_other_program.cc index 93a3a07a..ddad4c53 100644 --- a/handler/win/crash_other_program.cc +++ b/handler/win/crash_other_program.cc @@ -90,8 +90,8 @@ int CrashOtherProgram(int argc, wchar_t* argv[]) { // Launch another process that hangs. base::FilePath test_executable = TestPaths::Executable(); - std::wstring child_test_executable = - test_executable.DirName().Append(L"hanging_program.exe").value(); + base::FilePath child_test_executable = + test_executable.DirName().Append(L"hanging_program.exe"); ChildLauncher child(child_test_executable, argv[1]); child.Start(); if (testing::Test::HasFatalFailure()) { diff --git a/snapshot/crashpad_info_client_options_test.cc b/snapshot/crashpad_info_client_options_test.cc index 697c14ec..45f3f17b 100644 --- a/snapshot/crashpad_info_client_options_test.cc +++ b/snapshot/crashpad_info_client_options_test.cc @@ -141,13 +141,10 @@ TEST(CrashpadInfoClientOptions, OneModule) { TEST(CrashpadInfoClientOptions, TwoModules) { // Open the module, which has its own CrashpadInfo structure. -#if defined(OS_MACOSX) - const base::FilePath::StringType kDlExtension = FILE_PATH_LITERAL(".so"); -#elif defined(OS_WIN) - const base::FilePath::StringType kDlExtension = FILE_PATH_LITERAL(".dll"); -#endif - base::FilePath module_path = TestPaths::Executable().DirName().Append( - FILE_PATH_LITERAL("crashpad_snapshot_test_module") + kDlExtension); + base::FilePath module_path = + TestPaths::BuildArtifact(FILE_PATH_LITERAL("snapshot"), + FILE_PATH_LITERAL("module"), + TestPaths::FileType::kLoadableModule); #if defined(OS_MACOSX) ScopedModuleHandle module( dlopen(module_path.value().c_str(), RTLD_LAZY | RTLD_LOCAL)); diff --git a/snapshot/mac/mach_o_image_annotations_reader_test.cc b/snapshot/mac/mach_o_image_annotations_reader_test.cc index cda76116..3e7864b0 100644 --- a/snapshot/mac/mach_o_image_annotations_reader_test.cc +++ b/snapshot/mac/mach_o_image_annotations_reader_test.cc @@ -51,13 +51,16 @@ namespace test { namespace { // \return The path to crashpad_snapshot_test_module_crashy_initializer.so -std::string ModuleWithCrashyInitializer() { - return TestPaths::Executable().value() + "_module_crashy_initializer.so"; +base::FilePath ModuleWithCrashyInitializer() { + return TestPaths::BuildArtifact("snapshot", + "module_crashy_initializer", + TestPaths::FileType::kLoadableModule); } //! \return The path to the crashpad_snapshot_test_no_op executable. base::FilePath NoOpExecutable() { - return base::FilePath(TestPaths::Executable().value() + "_no_op"); + return TestPaths::BuildArtifact( + "snapshot", "no_op", TestPaths::FileType::kExecutable); } class TestMachOImageAnnotationsReader final @@ -183,7 +186,7 @@ class TestMachOImageAnnotationsReader final case kCrashModuleInitialization: // This message is set by dyld-353.2.1/src/ImageLoaderMachO.cpp // ImageLoaderMachO::doInitialization(). - expected_annotation = ModuleWithCrashyInitializer(); + expected_annotation = ModuleWithCrashyInitializer().value(); break; case kCrashDyld: @@ -402,7 +405,7 @@ class TestMachOImageAnnotationsReader final case kCrashModuleInitialization: { // Load a module that crashes while executing a module initializer. - void* dl_handle = dlopen(ModuleWithCrashyInitializer().c_str(), + void* dl_handle = dlopen(ModuleWithCrashyInitializer().value().c_str(), RTLD_LAZY | RTLD_LOCAL); // This should have crashed in the dlopen(). If dlopen() failed, the diff --git a/snapshot/win/exception_snapshot_win_test.cc b/snapshot/win/exception_snapshot_win_test.cc index 6ed07396..843ad263 100644 --- a/snapshot/win/exception_snapshot_win_test.cc +++ b/snapshot/win/exception_snapshot_win_test.cc @@ -121,7 +121,7 @@ class CrashingDelegate : public ExceptionHandlerServer::Delegate { DISALLOW_COPY_AND_ASSIGN(CrashingDelegate); }; -void TestCrashingChild(const base::FilePath& directory) { +void TestCrashingChild(TestPaths::Architecture architecture) { // Set up the registration server on a background thread. ScopedKernelHANDLE server_ready(CreateEvent(nullptr, false, false, nullptr)); ASSERT_TRUE(server_ready.is_valid()) << ErrorMessage("CreateEvent"); @@ -141,13 +141,11 @@ void TestCrashingChild(const base::FilePath& directory) { << ErrorMessage("WaitForSingleObject"); // Spawn a child process, passing it the pipe name to connect to. - std::wstring child_test_executable = directory - .Append(TestPaths::Executable() - .BaseName() - .RemoveFinalExtension() - .value() + - L"_crashing_child.exe") - .value(); + base::FilePath child_test_executable = + TestPaths::BuildArtifact(L"snapshot", + L"crashing_child", + TestPaths::FileType::kExecutable, + architecture); ChildLauncher child(child_test_executable, pipe_name); ASSERT_NO_FATAL_FAILURE(child.Start()); @@ -166,17 +164,16 @@ void TestCrashingChild(const base::FilePath& directory) { } TEST(ExceptionSnapshotWinTest, ChildCrash) { - TestCrashingChild(TestPaths::Executable().DirName()); + TestCrashingChild(TestPaths::Architecture::kDefault); } #if defined(ARCH_CPU_64_BITS) TEST(ExceptionSnapshotWinTest, ChildCrashWOW64) { - base::FilePath output_32_bit_directory = TestPaths::Output32BitDirectory(); - if (output_32_bit_directory.empty()) { + if (!TestPaths::Has32BitBuildArtifacts()) { DISABLED_TEST(); } - TestCrashingChild(output_32_bit_directory); + TestCrashingChild(TestPaths::Architecture::k32Bit); } #endif // ARCH_CPU_64_BITS @@ -229,7 +226,7 @@ class SimulateDelegate : public ExceptionHandlerServer::Delegate { DISALLOW_COPY_AND_ASSIGN(SimulateDelegate); }; -void TestDumpWithoutCrashingChild(const base::FilePath& directory) { +void TestDumpWithoutCrashingChild(TestPaths::Architecture architecture) { // Set up the registration server on a background thread. ScopedKernelHANDLE server_ready(CreateEvent(nullptr, false, false, nullptr)); ASSERT_TRUE(server_ready.is_valid()) << ErrorMessage("CreateEvent"); @@ -249,14 +246,11 @@ void TestDumpWithoutCrashingChild(const base::FilePath& directory) { << ErrorMessage("WaitForSingleObject"); // Spawn a child process, passing it the pipe name to connect to. - std::wstring child_test_executable = - directory - .Append(TestPaths::Executable() - .BaseName() - .RemoveFinalExtension() - .value() + - L"_dump_without_crashing.exe") - .value(); + base::FilePath child_test_executable = + TestPaths::BuildArtifact(L"snapshot", + L"dump_without_crashing", + TestPaths::FileType::kExecutable, + architecture); ChildLauncher child(child_test_executable, pipe_name); ASSERT_NO_FATAL_FAILURE(child.Start()); @@ -275,17 +269,16 @@ void TestDumpWithoutCrashingChild(const base::FilePath& directory) { } TEST(SimulateCrash, ChildDumpWithoutCrashing) { - TestDumpWithoutCrashingChild(TestPaths::Executable().DirName()); + TestDumpWithoutCrashingChild(TestPaths::Architecture::kDefault); } #if defined(ARCH_CPU_64_BITS) TEST(SimulateCrash, ChildDumpWithoutCrashingWOW64) { - base::FilePath output_32_bit_directory = TestPaths::Output32BitDirectory(); - if (output_32_bit_directory.empty()) { + if (!TestPaths::Has32BitBuildArtifacts()) { DISABLED_TEST(); } - TestDumpWithoutCrashingChild(output_32_bit_directory); + TestDumpWithoutCrashingChild(TestPaths::Architecture::k32Bit); } #endif // ARCH_CPU_64_BITS diff --git a/snapshot/win/extra_memory_ranges_test.cc b/snapshot/win/extra_memory_ranges_test.cc index d0820a04..dcef8055 100644 --- a/snapshot/win/extra_memory_ranges_test.cc +++ b/snapshot/win/extra_memory_ranges_test.cc @@ -43,15 +43,14 @@ enum TestType { kCrashDebugBreak, }; -void TestExtraMemoryRanges(TestType type, const base::FilePath& directory) { +void TestExtraMemoryRanges(TestType type, + TestPaths::Architecture architecture) { // Spawn a child process, passing it the pipe name to connect to. - std::wstring child_test_executable = directory - .Append(TestPaths::Executable() - .BaseName() - .RemoveFinalExtension() - .value() + - L"_extra_memory_ranges.exe") - .value(); + base::FilePath child_test_executable = + TestPaths::BuildArtifact(L"snapshot", + L"extra_memory_ranges", + TestPaths::FileType::kExecutable, + architecture); ChildLauncher child(child_test_executable, L""); ASSERT_NO_FATAL_FAILURE(child.Start()); @@ -101,30 +100,28 @@ void TestExtraMemoryRanges(TestType type, const base::FilePath& directory) { } TEST(ExtraMemoryRanges, DontCrash) { - TestExtraMemoryRanges(kDontCrash, TestPaths::Executable().DirName()); + TestExtraMemoryRanges(kDontCrash, TestPaths::Architecture::kDefault); } TEST(ExtraMemoryRanges, CrashDebugBreak) { - TestExtraMemoryRanges(kCrashDebugBreak, TestPaths::Executable().DirName()); + TestExtraMemoryRanges(kCrashDebugBreak, TestPaths::Architecture::kDefault); } #if defined(ARCH_CPU_64_BITS) TEST(ExtraMemoryRanges, DontCrashWOW64) { - base::FilePath output_32_bit_directory = TestPaths::Output32BitDirectory(); - if (output_32_bit_directory.empty()) { + if (!TestPaths::Has32BitBuildArtifacts()) { DISABLED_TEST(); } - TestExtraMemoryRanges(kDontCrash, output_32_bit_directory); + TestExtraMemoryRanges(kDontCrash, TestPaths::Architecture::k32Bit); } TEST(ExtraMemoryRanges, CrashDebugBreakWOW64) { - base::FilePath output_32_bit_directory = TestPaths::Output32BitDirectory(); - if (output_32_bit_directory.empty()) { + if (!TestPaths::Has32BitBuildArtifacts()) { DISABLED_TEST(); } - TestExtraMemoryRanges(kCrashDebugBreak, output_32_bit_directory); + TestExtraMemoryRanges(kCrashDebugBreak, TestPaths::Architecture::k32Bit); } #endif // ARCH_CPU_64_BITS diff --git a/snapshot/win/pe_image_annotations_reader_test.cc b/snapshot/win/pe_image_annotations_reader_test.cc index 7277bbdf..f576394c 100644 --- a/snapshot/win/pe_image_annotations_reader_test.cc +++ b/snapshot/win/pe_image_annotations_reader_test.cc @@ -48,15 +48,14 @@ enum TestType { kCrashDebugBreak, }; -void TestAnnotationsOnCrash(TestType type, const base::FilePath& directory) { +void TestAnnotationsOnCrash(TestType type, + TestPaths::Architecture architecture) { // Spawn a child process, passing it the pipe name to connect to. - std::wstring child_test_executable = directory - .Append(TestPaths::Executable() - .BaseName() - .RemoveFinalExtension() - .value() + - L"_annotations.exe") - .value(); + base::FilePath child_test_executable = + TestPaths::BuildArtifact(L"snapshot", + L"annotations", + TestPaths::FileType::kExecutable, + architecture); ChildLauncher child(child_test_executable, L""); ASSERT_NO_FATAL_FAILURE(child.Start()); @@ -148,30 +147,28 @@ void TestAnnotationsOnCrash(TestType type, const base::FilePath& directory) { } TEST(PEImageAnnotationsReader, DontCrash) { - TestAnnotationsOnCrash(kDontCrash, TestPaths::Executable().DirName()); + TestAnnotationsOnCrash(kDontCrash, TestPaths::Architecture::kDefault); } TEST(PEImageAnnotationsReader, CrashDebugBreak) { - TestAnnotationsOnCrash(kCrashDebugBreak, TestPaths::Executable().DirName()); + TestAnnotationsOnCrash(kCrashDebugBreak, TestPaths::Architecture::kDefault); } #if defined(ARCH_CPU_64_BITS) TEST(PEImageAnnotationsReader, DontCrashWOW64) { - base::FilePath output_32_bit_directory = TestPaths::Output32BitDirectory(); - if (output_32_bit_directory.empty()) { + if (!TestPaths::Has32BitBuildArtifacts()) { DISABLED_TEST(); } - TestAnnotationsOnCrash(kDontCrash, output_32_bit_directory); + TestAnnotationsOnCrash(kDontCrash, TestPaths::Architecture::k32Bit); } TEST(PEImageAnnotationsReader, CrashDebugBreakWOW64) { - base::FilePath output_32_bit_directory = TestPaths::Output32BitDirectory(); - if (output_32_bit_directory.empty()) { + if (!TestPaths::Has32BitBuildArtifacts()) { DISABLED_TEST(); } - TestAnnotationsOnCrash(kCrashDebugBreak, output_32_bit_directory); + TestAnnotationsOnCrash(kCrashDebugBreak, TestPaths::Architecture::k32Bit); } #endif // ARCH_CPU_64_BITS diff --git a/snapshot/win/process_snapshot_win_test.cc b/snapshot/win/process_snapshot_win_test.cc index 11291a00..b2448fcf 100644 --- a/snapshot/win/process_snapshot_win_test.cc +++ b/snapshot/win/process_snapshot_win_test.cc @@ -31,20 +31,18 @@ namespace crashpad { namespace test { namespace { -void TestImageReaderChild(const base::FilePath& directory) { +void TestImageReaderChild(const TestPaths::Architecture architecture) { UUID done_uuid; done_uuid.InitializeWithNew(); ScopedKernelHANDLE done( CreateEvent(nullptr, true, false, done_uuid.ToString16().c_str())); ASSERT_TRUE(done.is_valid()) << ErrorMessage("CreateEvent"); - std::wstring child_test_executable = directory - .Append(TestPaths::Executable() - .BaseName() - .RemoveFinalExtension() - .value() + - L"_image_reader.exe") - .value(); + base::FilePath child_test_executable = + TestPaths::BuildArtifact(L"snapshot", + L"image_reader", + TestPaths::FileType::kExecutable, + architecture); ChildLauncher child(child_test_executable, done_uuid.ToString16()); ASSERT_NO_FATAL_FAILURE(child.Start()); @@ -113,17 +111,16 @@ void TestImageReaderChild(const base::FilePath& directory) { } TEST(ProcessSnapshotTest, CrashpadInfoChild) { - TestImageReaderChild(TestPaths::Executable().DirName()); + TestImageReaderChild(TestPaths::Architecture::kDefault); } #if defined(ARCH_CPU_64_BITS) TEST(ProcessSnapshotTest, CrashpadInfoChildWOW64) { - base::FilePath output_32_bit_directory = TestPaths::Output32BitDirectory(); - if (output_32_bit_directory.empty()) { + if (!TestPaths::Has32BitBuildArtifacts()) { DISABLED_TEST(); } - TestImageReaderChild(output_32_bit_directory); + TestImageReaderChild(TestPaths::Architecture::k32Bit); } #endif diff --git a/test/multiprocess_exec.h b/test/multiprocess_exec.h index 9b2ffc1c..258a3f8e 100644 --- a/test/multiprocess_exec.h +++ b/test/multiprocess_exec.h @@ -18,6 +18,7 @@ #include #include +#include "base/files/file_path.h" #include "base/macros.h" #include "build/build_config.h" #include "test/multiprocess.h" @@ -48,7 +49,7 @@ class MultiprocessExec : public Multiprocess { //! process in its `argv[]` vector. This vector must begin at `argv[1]`, //! as \a command is implicitly used as `argv[0]`. This argument may be //! `nullptr` if no command-line arguments are to be passed. - void SetChildCommand(const std::string& command, + void SetChildCommand(const base::FilePath& command, const std::vector* arguments); protected: @@ -61,7 +62,7 @@ class MultiprocessExec : public Multiprocess { // Multiprocess: void MultiprocessChild() override; - std::string command_; + base::FilePath command_; std::vector arguments_; #if defined(OS_POSIX) std::vector argv_; diff --git a/test/multiprocess_exec_posix.cc b/test/multiprocess_exec_posix.cc index 3d7212d1..528e8c77 100644 --- a/test/multiprocess_exec_posix.cc +++ b/test/multiprocess_exec_posix.cc @@ -40,7 +40,8 @@ MultiprocessExec::MultiprocessExec() } void MultiprocessExec::SetChildCommand( - const std::string& command, const std::vector* arguments) { + const base::FilePath& command, + const std::vector* arguments) { command_ = command; if (arguments) { arguments_ = *arguments; @@ -62,7 +63,7 @@ void MultiprocessExec::PreFork() { // process, building it is a hazardous operation in that process. ASSERT_TRUE(argv_.empty()); - argv_.push_back(command_.c_str()); + argv_.push_back(command_.value().c_str()); for (const std::string& argument : arguments_) { argv_.push_back(argument.c_str()); } diff --git a/test/multiprocess_exec_test.cc b/test/multiprocess_exec_test.cc index f35519a0..b8a5bc19 100644 --- a/test/multiprocess_exec_test.cc +++ b/test/multiprocess_exec_test.cc @@ -48,17 +48,10 @@ class TestMultiprocessExec final : public MultiprocessExec { TEST(MultiprocessExec, MultiprocessExec) { TestMultiprocessExec multiprocess_exec; - base::FilePath test_executable = TestPaths::Executable(); -#if defined(OS_POSIX) - std::string child_test_executable = test_executable.value(); -#elif defined(OS_WIN) - std::string child_test_executable = - base::UTF16ToUTF8(test_executable.RemoveFinalExtension().value()); -#endif // OS_POSIX - child_test_executable += "_multiprocess_exec_test_child"; -#if defined(OS_WIN) - child_test_executable += ".exe"; -#endif + base::FilePath child_test_executable = TestPaths::BuildArtifact( + FILE_PATH_LITERAL("test"), + FILE_PATH_LITERAL("multiprocess_exec_test_child"), + TestPaths::FileType::kExecutable); multiprocess_exec.SetChildCommand(child_test_executable, nullptr); multiprocess_exec.Run(); } diff --git a/test/multiprocess_exec_win.cc b/test/multiprocess_exec_win.cc index 5eb5d803..f3a10c42 100644 --- a/test/multiprocess_exec_win.cc +++ b/test/multiprocess_exec_win.cc @@ -102,7 +102,7 @@ MultiprocessExec::MultiprocessExec() } void MultiprocessExec::SetChildCommand( - const std::string& command, + const base::FilePath& command, const std::vector* arguments) { command_ = command; if (arguments) { @@ -119,7 +119,7 @@ void MultiprocessExec::PreFork() { ASSERT_FALSE(command_.empty()); command_line_.clear(); - AppendCommandLineArgument(base::UTF8ToUTF16(command_), &command_line_); + AppendCommandLineArgument(command_.value(), &command_line_); for (size_t i = 0; i < arguments_.size(); ++i) { AppendCommandLineArgument(base::UTF8ToUTF16(arguments_[i]), &command_line_); } @@ -154,7 +154,7 @@ void MultiprocessExec::MultiprocessChild() { startup_info.hStdOutput = info()->pipe_c2p_write.get(); startup_info.hStdError = GetStdHandle(STD_ERROR_HANDLE); startup_info.dwFlags = STARTF_USESTDHANDLES; - PCHECK(CreateProcess(base::UTF8ToUTF16(command_).c_str(), + PCHECK(CreateProcess(command_.value().c_str(), &command_line_[0], // This cannot be constant, per MSDN. nullptr, nullptr, diff --git a/test/test_paths.cc b/test/test_paths.cc index a6012085..ae1c5baa 100644 --- a/test/test_paths.cc +++ b/test/test_paths.cc @@ -90,6 +90,23 @@ base::FilePath TestDataRootInternal() { return base::FilePath(base::FilePath::kCurrentDirectory); } +#if defined(OS_WIN) && defined(ARCH_CPU_64_BITS) + +// Returns the pathname of a directory containing 32-bit test build output. +// +// It would be better for this to be named 32BitOutputDirectory(), but that’s +// not a legal name. +base::FilePath Output32BitDirectory() { + const wchar_t* environment_value = _wgetenv(L"CRASHPAD_TEST_32_BIT_OUTPUT"); + if (!environment_value) { + return base::FilePath(); + } + + return base::FilePath(environment_value); +} + +#endif // defined(OS_WIN) && defined(ARCH_CPU_64_BITS) + } // namespace // static @@ -106,16 +123,61 @@ base::FilePath TestPaths::TestDataRoot() { return *test_data_root; } +// static +base::FilePath TestPaths::BuildArtifact( + const base::FilePath::StringType& module, + const base::FilePath::StringType& artifact, + FileType file_type, + Architecture architecture) { + base::FilePath directory; + switch (architecture) { + case Architecture::kDefault: + directory = Executable().DirName(); + break; + +#if defined(OS_WIN) && defined(ARCH_CPU_64_BITS) + case Architecture::k32Bit: + directory = Output32BitDirectory(); + CHECK(!directory.empty()); + break; +#endif // OS_WIN && ARCH_CPU_64_BITS + } + + base::FilePath::StringType test_name = + FILE_PATH_LITERAL("crashpad_") + module + FILE_PATH_LITERAL("_test"); +#if !defined(CRASHPAD_IN_CHROMIUM) + CHECK(Executable().BaseName().RemoveFinalExtension().value() == test_name); +#endif // !CRASHPAD_IN_CHROMIUM + + base::FilePath::StringType extension; + switch (file_type) { + case FileType::kNone: + break; + + case FileType::kExecutable: +#if defined(OS_WIN) + extension = FILE_PATH_LITERAL(".exe"); +#endif // OS_WIN + break; + + case FileType::kLoadableModule: +#if defined(OS_WIN) + extension = FILE_PATH_LITERAL(".dll"); +#else // OS_WIN + extension = FILE_PATH_LITERAL(".so"); +#endif // OS_WIN + break; + } + + return directory.Append(test_name + FILE_PATH_LITERAL("_") + artifact + + extension); +} + #if defined(OS_WIN) && defined(ARCH_CPU_64_BITS) // static -base::FilePath TestPaths::Output32BitDirectory() { - const wchar_t* environment_value = _wgetenv(L"CRASHPAD_TEST_32_BIT_OUTPUT"); - if (!environment_value) { - return base::FilePath(); - } - - return base::FilePath(environment_value); +bool TestPaths::Has32BitBuildArtifacts() { + return !Output32BitDirectory().empty(); } #endif // defined(OS_WIN) && defined(ARCH_CPU_64_BITS) diff --git a/test/test_paths.h b/test/test_paths.h index f5629ed5..2e89ac79 100644 --- a/test/test_paths.h +++ b/test/test_paths.h @@ -25,6 +25,38 @@ namespace test { //! \brief Functions to obtain paths from within tests. class TestPaths { public: + //! \brief The type of file requested of BuildArtifact(). + //! + //! This is used to establish the file extension used by the returned path. + enum class FileType { + //! \brief No file extension is requested. + kNone = 0, + + //! \brief `.exe` will be used on Windows, and no file extension will be + //! used on other platforms. + kExecutable, + + //! \brief `.dll` will be used on Windows, and `.so` will be used on other + //! platforms. + kLoadableModule, + }; + + //! \brief The architecture of the file requested of BuildArtifact(). + enum class Architecture { + //! \brief The default architecture is requested. This is usually the same + //! architecture as the running process. + kDefault = 0, + +#if (defined(OS_WIN) && defined(ARCH_CPU_64_BITS)) || DOXYGEN + //! \brief The 32-bit variant is requested. + //! + //! On Windows, when running 64-bit code, the 32-bit variant can be + //! requested. Before doing so, Has32BitBuildArtifacts() must be called and + //! must return `true`. Otherwise, execution will be aborted. + k32Bit, +#endif // OS_WIN && ARCH_CPU_64_BITS + }; + //! \brief Returns the pathname of the currently-running test executable. //! //! On failure, aborts execution. @@ -43,21 +75,50 @@ class TestPaths { //! files. static base::FilePath TestDataRoot(); + //! \brief Returns the pathname of a build artifact. + //! + //! \param[in] module The name of the Crashpad module associated with the + //! artifact, such as `"util"` or `"snapshot"`. \a module must correspond + //! to the module of the calling code, or execution will be aborted. + //! \param[in] artifact The name of the specific artifact. + //! \param[in] file_type The artifact’s type, used to establish the returned + //! path’s extension. + //! \param[in] architecture The artifact’s architecture. + //! + //! \return The computed pathname to the build artifact. + //! + //! For example, the following snippet will return a path to + //! `crashpad_snapshot_test_module.so` or `crashpad_snapshot_test_module.dll` + //! (depending on platform) in the same directory as the currently running + //! executable: + //! + //! \code + //! base::FilePath path = TestPaths::BuildArtifact( + //! FILE_PATH_LITERAL("snapshot"), + //! FILE_PATH_LITERAL("module"), + //! TestPaths::FileType::kLoadableModule); + //! \endcode + static base::FilePath BuildArtifact( + const base::FilePath::StringType& module, + const base::FilePath::StringType& artifact, + FileType file_type, + Architecture architecture = Architecture::kDefault); + #if (defined(OS_WIN) && defined(ARCH_CPU_64_BITS)) || DOXYGEN - //! \brief Returns the pathname of a directory containing 32-bit test build - //! output. + //! \return `true` if 32-bit build artifacts are available. //! //! Tests that require the use of 32-bit build output should call this - //! function to locate that output. This function is only provided to allow - //! 64-bit test code to locate 32-bit output. 32-bit test code can find 32-bit - //! output in its own directory, the parent of Executable(). + //! function to determine whether that output is available. This function is + //! only provided to aid 64-bit test code in locating 32-bit output. Only if + //! this function indicates that 32-bit output is available, 64-bit test code + //! may call BuildArtifact() with Architecture::k32Bit to obtain a path to the + //! 32-bit output. //! - //! If the `CRASHPAD_TEST_32_BIT_OUTPUT` environment variable is set, its - //! value will be returned. Otherwise, this function will return an empty - //! path, and tests that require the use of 32-bit build output should disable - //! themselves. The DISABLED_TEST() macro may be useful for this purpose. - static base::FilePath Output32BitDirectory(); -#endif + //! 32-bit test code may assume the existence of 32-bit build output, which + //! can be found its own directory, and located by calling BuildArtifact() + //! with Architecture::kDefault. + static bool Has32BitBuildArtifacts(); +#endif // OS_WIN && ARCH_CPU_64_BITS DISALLOW_IMPLICIT_CONSTRUCTORS(TestPaths); }; diff --git a/test/win/child_launcher.cc b/test/win/child_launcher.cc index c5f897c3..abd2e3d9 100644 --- a/test/win/child_launcher.cc +++ b/test/win/child_launcher.cc @@ -21,15 +21,14 @@ namespace crashpad { namespace test { -ChildLauncher::ChildLauncher(const std::wstring& executable, +ChildLauncher::ChildLauncher(const base::FilePath& executable, const std::wstring& command_line) : executable_(executable), command_line_(command_line), process_handle_(), main_thread_handle_(), stdout_read_handle_(), - stdin_write_handle_() { -} + stdin_write_handle_() {} ChildLauncher::~ChildLauncher() { if (process_handle_.is_valid()) @@ -76,10 +75,10 @@ void ChildLauncher::Start() { startup_info.dwFlags = STARTF_USESTDHANDLES; PROCESS_INFORMATION process_information; std::wstring command_line; - AppendCommandLineArgument(executable_, &command_line); + AppendCommandLineArgument(executable_.value(), &command_line); command_line += L" "; command_line += command_line_; - ASSERT_TRUE(CreateProcess(executable_.c_str(), + ASSERT_TRUE(CreateProcess(executable_.value().c_str(), &command_line[0], nullptr, nullptr, diff --git a/test/win/child_launcher.h b/test/win/child_launcher.h index 6674efe2..854e1247 100644 --- a/test/win/child_launcher.h +++ b/test/win/child_launcher.h @@ -19,6 +19,7 @@ #include +#include "base/files/file_path.h" #include "util/win/scoped_handle.h" namespace crashpad { @@ -32,7 +33,7 @@ class ChildLauncher { public: //! \brief Creates the object. \a executable will be escaped and prepended to //! \a command_line to build the command line of the child. - ChildLauncher(const std::wstring& executable, + ChildLauncher(const base::FilePath& executable, const std::wstring& command_line); ~ChildLauncher(); @@ -62,7 +63,7 @@ class ChildLauncher { HANDLE stdin_write_handle() const { return stdin_write_handle_.get(); } private: - std::wstring executable_; + base::FilePath executable_; std::wstring command_line_; ScopedKernelHANDLE process_handle_; ScopedKernelHANDLE main_thread_handle_; diff --git a/util/net/http_transport_test.cc b/util/net/http_transport_test.cc index 3b7e7ebd..fc02ba19 100644 --- a/util/net/http_transport_test.cc +++ b/util/net/http_transport_test.cc @@ -59,7 +59,7 @@ class HTTPTransportTestFixture : public MultiprocessExec { base::FilePath server_path = TestPaths::TestDataRoot().Append( FILE_PATH_LITERAL("util/net/http_transport_test_server.py")); #if defined(OS_POSIX) - SetChildCommand(server_path.value(), nullptr); + SetChildCommand(server_path, nullptr); #elif defined(OS_WIN) // Explicitly invoke a shell and python so that python can be found in the // path, and run the test script. @@ -67,7 +67,7 @@ class HTTPTransportTestFixture : public MultiprocessExec { args.push_back("/c"); args.push_back("python"); args.push_back(base::UTF16ToUTF8(server_path.value())); - SetChildCommand(getenv("COMSPEC"), &args); + SetChildCommand(base::FilePath(_wgetenv(L"COMSPEC")), &args); #endif // OS_POSIX } diff --git a/util/win/process_info_test.cc b/util/win/process_info_test.cc index 051479d1..93cf099e 100644 --- a/util/win/process_info_test.cc +++ b/util/win/process_info_test.cc @@ -132,7 +132,7 @@ TEST(ProcessInfo, Self) { FromPointerCast(_ReturnAddress())); } -void TestOtherProcess(const base::FilePath& directory) { +void TestOtherProcess(TestPaths::Architecture architecture) { ProcessInfo process_info; UUID done_uuid; @@ -142,15 +142,11 @@ void TestOtherProcess(const base::FilePath& directory) { CreateEvent(nullptr, true, false, done_uuid.ToString16().c_str())); ASSERT_TRUE(done.get()) << ErrorMessage("CreateEvent"); - std::wstring child_test_executable = - directory - .Append(TestPaths::Executable() - .BaseName() - .RemoveFinalExtension() - .value() + - L"_process_info_test_child.exe") - .value(); - + base::FilePath child_test_executable = + TestPaths::BuildArtifact(L"util", + L"process_info_test_child", + TestPaths::FileType::kExecutable, + architecture); std::wstring args; AppendCommandLineArgument(done_uuid.ToString16(), &args); @@ -191,17 +187,16 @@ void TestOtherProcess(const base::FilePath& directory) { } TEST(ProcessInfo, OtherProcess) { - TestOtherProcess(TestPaths::Executable().DirName()); + TestOtherProcess(TestPaths::Architecture::kDefault); } #if defined(ARCH_CPU_64_BITS) TEST(ProcessInfo, OtherProcessWOW64) { - base::FilePath output_32_bit_directory = TestPaths::Output32BitDirectory(); - if (output_32_bit_directory.empty()) { + if (!TestPaths::Has32BitBuildArtifacts()) { DISABLED_TEST(); } - TestOtherProcess(output_32_bit_directory); + TestOtherProcess(TestPaths::Architecture::k32Bit); } #endif // ARCH_CPU_64_BITS diff --git a/util/win/safe_terminate_process_test.cc b/util/win/safe_terminate_process_test.cc index e3bfde7f..3aba1591 100644 --- a/util/win/safe_terminate_process_test.cc +++ b/util/win/safe_terminate_process_test.cc @@ -163,14 +163,11 @@ TEST(SafeTerminateProcess, PatchBadly) { } TEST(SafeTerminateProcess, TerminateChild) { - base::FilePath test_executable = TestPaths::Executable(); - std::wstring child_executable = - test_executable.DirName() - .Append(test_executable.BaseName().RemoveFinalExtension().value() + - L"_safe_terminate_process_test_child.exe") - .value(); - - ChildLauncher child(child_executable, std::wstring()); + base::FilePath child_executable = + TestPaths::BuildArtifact(L"util", + L"safe_terminate_process_test_child", + TestPaths::FileType::kExecutable); + ChildLauncher child(child_executable, L""); ASSERT_NO_FATAL_FAILURE(child.Start()); constexpr DWORD kExitCode = 0x51ee9d1e; // Sort of like “sleep and die.”