1 : // Copyright 2013 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/instrument/instrumenters/instrumenter_with_agent.h"
16 :
17 : #include "base/command_line.h"
18 : #include "gmock/gmock.h"
19 : #include "gtest/gtest.h"
20 : #include "syzygy/core/unittest_util.h"
21 : #include "syzygy/pe/unittest_util.h"
22 :
23 : namespace instrument {
24 : namespace instrumenters {
25 :
26 : namespace {
27 :
28 : using testing::StrictMock;
29 : using testing::Return;
30 : using testing::_;
31 :
32 : const char kTestAgentDllName[] = "test_agent_dll.dll";
33 :
34 : class MockRelinker : public pe::PERelinker {
35 : public:
36 E : MOCK_METHOD0(Init, bool());
37 E : MOCK_METHOD0(Relink, bool());
38 : };
39 :
40 : class TestInstrumenterWithAgent : public InstrumenterWithAgent {
41 : public:
42 : using InstrumenterWithAgent::input_dll_path_;
43 : using InstrumenterWithAgent::input_pdb_path_;
44 : using InstrumenterWithAgent::output_dll_path_;
45 : using InstrumenterWithAgent::output_pdb_path_;
46 : using InstrumenterWithAgent::allow_overwrite_;
47 : using InstrumenterWithAgent::new_decomposer_;
48 : using InstrumenterWithAgent::no_augment_pdb_;
49 : using InstrumenterWithAgent::no_parse_debug_info_;
50 : using InstrumenterWithAgent::no_strip_strings_;
51 :
52 E : TestInstrumenterWithAgent() {
53 E : agent_dll_ = kTestAgentDllName;
54 E : }
55 :
56 E : MOCK_METHOD0(InstrumentImpl, bool());
57 :
58 E : pe::PERelinker* GetRelinker() OVERRIDE {
59 E : return &mock_relinker_;
60 E : }
61 :
62 i : virtual const char* InstrumentationMode() { return "test"; }
63 :
64 : StrictMock<MockRelinker> mock_relinker_;
65 : };
66 :
67 : class InstrumenterWithAgentTest : public testing::PELibUnitTest {
68 : public:
69 : typedef testing::PELibUnitTest Super;
70 :
71 E : InstrumenterWithAgentTest()
72 : : cmd_line_(base::FilePath(L"instrument.exe")) {
73 E : }
74 :
75 E : virtual void SetUp() OVERRIDE {
76 E : testing::Test::SetUp();
77 :
78 : // Several of the tests generate progress and (deliberate) error messages
79 : // that would otherwise clutter the unittest output.
80 E : logging::SetMinLogLevel(logging::LOG_FATAL);
81 :
82 : // Setup the IO streams.
83 E : CreateTemporaryDir(&temp_dir_);
84 E : stdin_path_ = temp_dir_.Append(L"NUL");
85 E : stdout_path_ = temp_dir_.Append(L"stdout.txt");
86 E : stderr_path_ = temp_dir_.Append(L"stderr.txt");
87 E : InitStreams(stdin_path_, stdout_path_, stderr_path_);
88 :
89 : // Initialize the (potential) input and output path values.
90 E : abs_input_dll_path_ = testing::GetExeRelativePath(testing::kTestDllName);
91 E : input_dll_path_ = testing::GetRelativePath(abs_input_dll_path_);
92 E : abs_input_pdb_path_ = testing::GetExeRelativePath(testing::kTestDllPdbName);
93 E : input_pdb_path_ = testing::GetRelativePath(abs_input_pdb_path_);
94 E : output_dll_path_ = temp_dir_.Append(input_dll_path_.BaseName());
95 E : output_pdb_path_ = temp_dir_.Append(input_pdb_path_.BaseName());
96 E : }
97 :
98 E : void SetUpValidCommandLine() {
99 E : cmd_line_.AppendSwitchPath("input-dll", input_dll_path_);
100 E : cmd_line_.AppendSwitchPath("output-dll", output_dll_path_);
101 E : }
102 :
103 : protected:
104 : base::FilePath temp_dir_;
105 :
106 : // @name The redirected streams paths.
107 : // @{
108 : base::FilePath stdin_path_;
109 : base::FilePath stdout_path_;
110 : base::FilePath stderr_path_;
111 : // @}
112 :
113 : // @name Command-line and parameters.
114 : // @{
115 : CommandLine cmd_line_;
116 : base::FilePath input_dll_path_;
117 : base::FilePath input_pdb_path_;
118 : base::FilePath output_dll_path_;
119 : base::FilePath output_pdb_path_;
120 : // @}
121 :
122 : // @name Expected final values of input parameters.
123 : // @{
124 : base::FilePath abs_input_dll_path_;
125 : base::FilePath abs_input_pdb_path_;
126 : // @}
127 :
128 : // The fake instrumenter we delegate to.
129 : TestInstrumenterWithAgent instrumenter_;
130 : };
131 :
132 : } // namespace
133 :
134 E : TEST_F(InstrumenterWithAgentTest, EmptyCommandLineFails) {
135 E : ASSERT_FALSE(instrumenter_.ParseCommandLine(&cmd_line_));
136 E : }
137 :
138 E : TEST_F(InstrumenterWithAgentTest, ParseWithNoInputImageFails) {
139 E : cmd_line_.AppendSwitchPath("output-image", output_dll_path_);
140 :
141 E : ASSERT_FALSE(instrumenter_.ParseCommandLine(&cmd_line_));
142 E : }
143 :
144 E : TEST_F(InstrumenterWithAgentTest, ParseWithNoOutputImageFails) {
145 E : cmd_line_.AppendSwitchPath("input-image", input_dll_path_);
146 :
147 E : ASSERT_FALSE(instrumenter_.ParseCommandLine(&cmd_line_));
148 E : }
149 :
150 E : TEST_F(InstrumenterWithAgentTest, DeprecatedParseNoModeSpecifyDlls) {
151 E : cmd_line_.AppendSwitchPath("input-dll", input_dll_path_);
152 E : cmd_line_.AppendSwitchPath("output-dll", output_dll_path_);
153 :
154 E : EXPECT_TRUE(instrumenter_.ParseCommandLine(&cmd_line_));
155 E : EXPECT_EQ(abs_input_dll_path_, instrumenter_.input_dll_path_);
156 E : EXPECT_EQ(output_dll_path_, instrumenter_.output_dll_path_);
157 :
158 E : EXPECT_FALSE(instrumenter_.allow_overwrite_);
159 E : EXPECT_FALSE(instrumenter_.new_decomposer_);
160 E : EXPECT_FALSE(instrumenter_.no_augment_pdb_);
161 E : EXPECT_FALSE(instrumenter_.no_parse_debug_info_);
162 E : EXPECT_FALSE(instrumenter_.no_strip_strings_);
163 E : }
164 :
165 E : TEST_F(InstrumenterWithAgentTest, agent_dll) {
166 E : EXPECT_STREQ(kTestAgentDllName, instrumenter_.agent_dll().c_str());
167 E : }
168 :
169 E : TEST_F(InstrumenterWithAgentTest, Instrument) {
170 E : SetUpValidCommandLine();
171 :
172 E : EXPECT_TRUE(instrumenter_.ParseCommandLine(&cmd_line_));
173 E : EXPECT_CALL(instrumenter_.mock_relinker_, Init()).WillOnce(Return(true));
174 E : EXPECT_CALL(instrumenter_.mock_relinker_, Relink()).WillOnce(Return(true));
175 E : EXPECT_CALL(instrumenter_, InstrumentImpl()).WillOnce(Return(true));
176 :
177 E : EXPECT_TRUE(instrumenter_.Instrument());
178 E : }
179 :
180 E : TEST_F(InstrumenterWithAgentTest, InstrumentFailsInit) {
181 E : SetUpValidCommandLine();
182 :
183 E : EXPECT_CALL(instrumenter_.mock_relinker_, Init()).WillOnce(Return(false));
184 :
185 E : EXPECT_FALSE(instrumenter_.Instrument());
186 E : }
187 :
188 E : TEST_F(InstrumenterWithAgentTest, InstrumentFailsRelink) {
189 E : SetUpValidCommandLine();
190 :
191 E : EXPECT_CALL(instrumenter_.mock_relinker_, Init()).WillOnce(Return(true));
192 E : EXPECT_CALL(instrumenter_.mock_relinker_, Relink()).WillOnce(Return(false));
193 E : EXPECT_CALL(instrumenter_, InstrumentImpl()).WillOnce(Return(true));
194 :
195 E : EXPECT_FALSE(instrumenter_.Instrument());
196 E : }
197 :
198 : } // namespace instrumenters
199 : } // namespace instrument
|