1 : // Copyright 2012 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 : #include "syzygy/pdbfind/pdbfind_app.h"
16 :
17 : #include "base/files/file_util.h"
18 : #include "base/strings/string_util.h"
19 : #include "base/strings/stringprintf.h"
20 : #include "base/strings/utf_string_conversions.h"
21 : #include "gmock/gmock.h"
22 : #include "gtest/gtest.h"
23 : #include "syzygy/core/unittest_util.h"
24 : #include "syzygy/pe/unittest_util.h"
25 :
26 : namespace pdbfind {
27 :
28 : namespace {
29 :
30 : class TestPdbFindApp : public PdbFindApp {
31 : public:
32 : using PdbFindApp::input_image_path_;
33 : };
34 :
35 : typedef application::Application<TestPdbFindApp> TestApp;
36 :
37 : class PdbFindAppTest : public testing::PELibUnitTest {
38 : public:
39 : typedef testing::PELibUnitTest Super;
40 :
41 : PdbFindAppTest()
42 : : app_impl_(app_.implementation()),
43 : cmd_line_(base::FilePath(L"pdbfind.exe")),
44 E : old_log_level_(0) {
45 E : }
46 :
47 E : void SetUp() override {
48 E : Super::SetUp();
49 :
50 : // Several of the tests generate progress and (deliberate) error messages
51 : // that would otherwise clutter the unittest output.
52 E : old_log_level_ = logging::GetMinLogLevel();
53 E : logging::SetMinLogLevel(logging::LOG_FATAL);
54 :
55 : // Setup the IO streams.
56 E : CreateTemporaryDir(&temp_dir_);
57 E : stdin_path_ = temp_dir_.Append(L"NUL");
58 E : stdout_path_ = temp_dir_.Append(L"stdout.txt");
59 E : stderr_path_ = temp_dir_.Append(L"stderr.txt");
60 E : InitStreams(stdin_path_, stdout_path_, stderr_path_);
61 :
62 : // Point the application at the test's command-line, IO streams and mock
63 : // machinery.
64 E : app_.set_command_line(&cmd_line_);
65 E : app_.set_in(in());
66 E : app_.set_out(out());
67 E : app_.set_err(err());
68 E : }
69 :
70 E : void TearDown() override {
71 E : logging::SetMinLogLevel(old_log_level_);
72 :
73 E : Super::TearDown();
74 E : }
75 :
76 : TestApp app_;
77 : TestApp::Implementation& app_impl_;
78 :
79 : base::FilePath temp_dir_;
80 : base::FilePath stdin_path_;
81 : base::FilePath stdout_path_;
82 : base::FilePath stderr_path_;
83 :
84 : base::CommandLine cmd_line_;
85 : int old_log_level_;
86 : };
87 :
88 : } // namespace
89 :
90 E : TEST_F(PdbFindAppTest, GetHelp) {
91 E : cmd_line_.AppendSwitch("help");
92 E : ASSERT_FALSE(app_impl_.ParseCommandLine(&cmd_line_));
93 E : }
94 :
95 E : TEST_F(PdbFindAppTest, EmptyCommandLineFails) {
96 E : ASSERT_FALSE(app_impl_.ParseCommandLine(&cmd_line_));
97 E : }
98 :
99 E : TEST_F(PdbFindAppTest, TooManyArgumentsFails) {
100 E : cmd_line_.AppendArg("foo.dll");
101 E : cmd_line_.AppendArg("bar.dll");
102 E : ASSERT_FALSE(app_impl_.ParseCommandLine(&cmd_line_));
103 E : }
104 :
105 E : TEST_F(PdbFindAppTest, ParseWithOneArgumentPasses) {
106 E : cmd_line_.AppendArg("foo.dll");
107 E : ASSERT_TRUE(app_impl_.ParseCommandLine(&cmd_line_));
108 E : EXPECT_EQ(app_impl_.input_image_path_, base::FilePath(L"foo.dll"));
109 E : }
110 :
111 E : TEST_F(PdbFindAppTest, ModuleNotFound) {
112 E : base::FilePath module = testing::GetExeRelativePath(L"made_up_module.dll");
113 E : cmd_line_.AppendArgPath(module);
114 E : ASSERT_EQ(1, app_.Run());
115 E : }
116 :
117 : // TODO(chrisha): More tests with images that are missing the corresponding
118 : // PDB or are missing CodeView records.
119 :
120 E : TEST_F(PdbFindAppTest, Succeeds) {
121 E : base::FilePath test_dll = testing::GetExeRelativePath(testing::kTestDllName);
122 E : cmd_line_.AppendArgPath(test_dll);
123 E : ASSERT_EQ(0, app_.Run());
124 :
125 : base::FilePath expected_pdb_path = testing::GetExeRelativePath(
126 E : testing::kTestDllPdbName);
127 :
128 : // We have to tear down the streams to make sure their contents are flushed
129 : // to disk.
130 E : TearDownStreams();
131 E : std::string actual_stdout;
132 E : ASSERT_TRUE(base::ReadFileToString(stdout_path_, &actual_stdout));
133 : base::TrimWhitespaceASCII(actual_stdout, base::TRIM_TRAILING,
134 E : &actual_stdout);
135 E : base::FilePath actual_pdb_path(base::ASCIIToUTF16(actual_stdout));
136 E : EXPECT_TRUE(base::PathExists(actual_pdb_path));
137 :
138 : #ifdef _COVERAGE_BUILD
139 : // In the coverage build the module is actually copied to a temporary
140 : // directory, but the CodeView entry still points to the original PDB.
141 E : expected_pdb_path = expected_pdb_path.BaseName();
142 E : actual_pdb_path = actual_pdb_path.BaseName();
143 E : EXPECT_EQ(expected_pdb_path, actual_pdb_path);
144 : #else
145 : // Our typical build environment includes a secondary drive that is mounted
146 : // at a location on the C drive. As such there are two possible paths to the
147 : // same file. We actually care that the expected path and the returned path
148 : // refer to the same file on disk rather than having exactly the same path.
149 : EXPECT_SAME_FILE(expected_pdb_path, actual_pdb_path);
150 : #endif
151 E : }
152 :
153 : } // namespace pdbfind
|