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/pehacker/pehacker_app.h"
16 :
17 : #include "base/strings/utf_string_conversions.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 pehacker {
24 :
25 : namespace {
26 :
27 : static wchar_t kConfigBadPathDoesNotExist[] =
28 : L"syzygy/pehacker/test_data/config-bad-path-does-not-exist.txt";
29 : static wchar_t kConfigBadEmpty[] =
30 : L"syzygy/pehacker/test_data/config-bad-empty.txt";
31 : static wchar_t kConfigBadNotJson[] =
32 : L"syzygy/pehacker/test_data/config-bad-not-json.txt";
33 : static wchar_t kConfigBadList[] =
34 : L"syzygy/pehacker/test_data/config-bad-list.txt";
35 : static wchar_t kConfigBadString[] =
36 : L"syzygy/pehacker/test_data/config-bad-string.txt";
37 : static wchar_t kConfigBadCircularVariables[] =
38 : L"syzygy/pehacker/test_data/config-circular-variables.txt";
39 : static wchar_t kConfigGoodMinimal[] =
40 : L"syzygy/pehacker/test_data/config-good-minimal.txt";
41 : static wchar_t kConfigGoodExistingOutput[] =
42 : L"syzygy/pehacker/test_data/config-good-existing-output.txt";
43 : static wchar_t kConfigGoodDefaultValue[] =
44 : L"syzygy/pehacker/test_data/config-good-default-value.txt";
45 : static wchar_t kConfigGoodNestedVariables[] =
46 : L"syzygy/pehacker/test_data/config-good-nested-variables.txt";
47 : static wchar_t kConfigGoodNop[] =
48 : L"syzygy/pehacker/test_data/config-good-nop.txt";
49 :
50 : class TestPEHackerApp : public PEHackerApp {
51 : public:
52 : using PEHackerApp::LoadAndValidateConfigurationFile;
53 :
54 : using PEHackerApp::config_file_;
55 : using PEHackerApp::overwrite_;
56 : using PEHackerApp::variables_;
57 : using PEHackerApp::config_;
58 : };
59 :
60 : typedef application::Application<TestPEHackerApp> TestApp;
61 :
62 : class PEHackerAppTest : public testing::PELibUnitTest {
63 : public:
64 : typedef testing::PELibUnitTest Super;
65 :
66 : PEHackerAppTest()
67 : : cmd_line_(base::FilePath(L"pehacker.exe")),
68 E : test_impl_(test_app_.implementation()) {
69 E : }
70 :
71 E : void SetUp() {
72 E : Super::SetUp();
73 :
74 E : logging::SetMinLogLevel(logging::LOG_ERROR);
75 :
76 : // Setup the IO streams.
77 E : CreateTemporaryDir(&temp_dir_);
78 E : stdin_path_ = temp_dir_.Append(L"NUL");
79 E : stdout_path_ = temp_dir_.Append(L"stdout.txt");
80 E : stderr_path_ = temp_dir_.Append(L"stderr.txt");
81 E : InitStreams(stdin_path_, stdout_path_, stderr_path_);
82 :
83 E : ASSERT_NO_FATAL_FAILURE(ConfigureTestApp(&test_app_));
84 :
85 E : config_file_ = temp_dir_.Append(L"config.txt");
86 E : }
87 :
88 : // Points the application at the fixture's command-line and IO streams.
89 : template<typename TestAppType>
90 E : void ConfigureTestApp(TestAppType* test_app) {
91 E : test_app->set_command_line(&cmd_line_);
92 E : test_app->set_in(in());
93 E : test_app->set_out(out());
94 E : test_app->set_err(err());
95 E : }
96 :
97 : // Stashes the current log-level before each test instance and restores it
98 : // after each test completes.
99 : testing::ScopedLogLevelSaver log_level_saver;
100 :
101 : // @name The application under test.
102 : // @{
103 : TestApp test_app_;
104 : TestApp::Implementation& test_impl_;
105 : base::FilePath temp_dir_;
106 : base::FilePath stdin_path_;
107 : base::FilePath stdout_path_;
108 : base::FilePath stderr_path_;
109 : // @}
110 :
111 : CommandLine cmd_line_;
112 : base::FilePath config_file_;
113 : };
114 :
115 : } // namespace
116 :
117 E : TEST_F(PEHackerAppTest, GetHelp) {
118 E : cmd_line_.AppendSwitch("help");
119 E : ASSERT_FALSE(test_impl_.ParseCommandLine(&cmd_line_));
120 E : }
121 :
122 E : TEST_F(PEHackerAppTest, ParseEmptyCommandLineFails) {
123 E : ASSERT_FALSE(test_impl_.ParseCommandLine(&cmd_line_));
124 E : }
125 :
126 E : TEST_F(PEHackerAppTest, ParseMinimalCommandLineSucceeds) {
127 E : cmd_line_.AppendSwitchPath("config-file", config_file_);
128 E : ASSERT_TRUE(test_impl_.ParseCommandLine(&cmd_line_));
129 E : EXPECT_EQ(config_file_, test_impl_.config_file_);
130 E : EXPECT_FALSE(test_impl_.overwrite_);
131 E : }
132 :
133 E : TEST_F(PEHackerAppTest, ParseMinimalCommandLineSucceedsEmptyVariable) {
134 E : cmd_line_.AppendSwitchPath("config-file", config_file_);
135 E : cmd_line_.AppendSwitch("Dvar");
136 E : ASSERT_TRUE(test_impl_.ParseCommandLine(&cmd_line_));
137 E : EXPECT_EQ(config_file_, test_impl_.config_file_);
138 E : EXPECT_FALSE(test_impl_.overwrite_);
139 :
140 E : std::string s;
141 E : EXPECT_TRUE(test_impl_.variables_.GetString("var", &s));
142 E : EXPECT_TRUE(s.empty());
143 E : }
144 :
145 E : TEST_F(PEHackerAppTest, ParseCommandLineFailsInvalidVariableName) {
146 E : cmd_line_.AppendSwitchPath("config-file", config_file_);
147 E : cmd_line_.AppendSwitchASCII("Dbad~variable-name", "true");
148 E : ASSERT_FALSE(test_impl_.ParseCommandLine(&cmd_line_));
149 E : }
150 :
151 E : TEST_F(PEHackerAppTest, ParseCommandLineFailsList) {
152 E : cmd_line_.AppendSwitchPath("config-file", config_file_);
153 E : cmd_line_.AppendSwitchASCII("Dvar", "[]");
154 E : ASSERT_FALSE(test_impl_.ParseCommandLine(&cmd_line_));
155 E : }
156 :
157 E : TEST_F(PEHackerAppTest, ParseCommandLineFailsDict) {
158 E : cmd_line_.AppendSwitchPath("config-file", config_file_);
159 E : cmd_line_.AppendSwitchASCII("Dvar", "{}");
160 E : ASSERT_FALSE(test_impl_.ParseCommandLine(&cmd_line_));
161 E : }
162 :
163 E : TEST_F(PEHackerAppTest, ParseCommandLineFailsDouble) {
164 E : cmd_line_.AppendSwitchPath("config-file", config_file_);
165 E : cmd_line_.AppendSwitchASCII("Dvar", "3.14");
166 E : ASSERT_FALSE(test_impl_.ParseCommandLine(&cmd_line_));
167 E : }
168 :
169 E : TEST_F(PEHackerAppTest, ParseFullCommandLineSucceeds) {
170 E : cmd_line_.AppendSwitchPath("config-file", config_file_);
171 E : cmd_line_.AppendSwitch("overwrite");
172 E : cmd_line_.AppendSwitchASCII("Dvar1", "val1");
173 E : cmd_line_.AppendSwitchASCII("Dvar2", "45");
174 E : cmd_line_.AppendSwitchASCII("Dvar3", "\"string\"");
175 E : cmd_line_.AppendSwitchASCII("Dvar4", "false");
176 E : cmd_line_.AppendSwitchASCII("Dvar5", "");
177 E : ASSERT_TRUE(test_impl_.ParseCommandLine(&cmd_line_));
178 E : EXPECT_EQ(config_file_, test_impl_.config_file_);
179 E : EXPECT_TRUE(test_impl_.overwrite_);
180 :
181 E : std::string s;
182 E : int i = 0;
183 E : double d = 0;
184 E : bool b = false;
185 :
186 E : EXPECT_TRUE(test_impl_.variables_.GetString("var1", &s));
187 E : EXPECT_EQ("val1", s);
188 :
189 E : EXPECT_TRUE(test_impl_.variables_.GetInteger("var2", &i));
190 E : EXPECT_EQ(45, i);
191 :
192 E : EXPECT_TRUE(test_impl_.variables_.GetString("var3", &s));
193 E : EXPECT_EQ("string", s);
194 :
195 E : EXPECT_TRUE(test_impl_.variables_.GetBoolean("var4", &b));
196 E : EXPECT_FALSE(b);
197 :
198 E : EXPECT_TRUE(test_impl_.variables_.GetString("var5", &s));
199 E : EXPECT_TRUE(s.empty());
200 E : }
201 :
202 E : TEST_F(PEHackerAppTest, ConfigurationFailsPathDoesNotExist) {
203 E : config_file_ = testing::GetSrcRelativePath(kConfigBadPathDoesNotExist);
204 E : cmd_line_.AppendSwitchPath("config-file", config_file_);
205 E : ASSERT_TRUE(test_impl_.ParseCommandLine(&cmd_line_));
206 E : ASSERT_FALSE(test_impl_.LoadAndValidateConfigurationFile());
207 E : }
208 :
209 E : TEST_F(PEHackerAppTest, ConfigurationFailsEmpty) {
210 E : config_file_ = testing::GetSrcRelativePath(kConfigBadEmpty);
211 E : cmd_line_.AppendSwitchPath("config-file", config_file_);
212 E : ASSERT_TRUE(test_impl_.ParseCommandLine(&cmd_line_));
213 E : ASSERT_FALSE(test_impl_.LoadAndValidateConfigurationFile());
214 E : }
215 :
216 E : TEST_F(PEHackerAppTest, ConfigurationFailsNotJson) {
217 E : config_file_ = testing::GetSrcRelativePath(kConfigBadNotJson);
218 E : cmd_line_.AppendSwitchPath("config-file", config_file_);
219 E : ASSERT_TRUE(test_impl_.ParseCommandLine(&cmd_line_));
220 E : ASSERT_FALSE(test_impl_.LoadAndValidateConfigurationFile());
221 E : }
222 :
223 E : TEST_F(PEHackerAppTest, ConfigurationFailsList) {
224 E : config_file_ = testing::GetSrcRelativePath(kConfigBadList);
225 E : cmd_line_.AppendSwitchPath("config-file", config_file_);
226 E : ASSERT_TRUE(test_impl_.ParseCommandLine(&cmd_line_));
227 E : ASSERT_FALSE(test_impl_.LoadAndValidateConfigurationFile());
228 E : }
229 :
230 E : TEST_F(PEHackerAppTest, ConfigurationFailsString) {
231 E : config_file_ = testing::GetSrcRelativePath(kConfigBadString);
232 E : cmd_line_.AppendSwitchPath("config-file", config_file_);
233 E : ASSERT_TRUE(test_impl_.ParseCommandLine(&cmd_line_));
234 E : ASSERT_FALSE(test_impl_.LoadAndValidateConfigurationFile());
235 E : }
236 :
237 E : TEST_F(PEHackerAppTest, ConfigurationFailsCircularVariables) {
238 E : config_file_ = testing::GetSrcRelativePath(kConfigBadCircularVariables);
239 E : cmd_line_.AppendSwitchPath("config-file", config_file_);
240 E : ASSERT_TRUE(test_impl_.ParseCommandLine(&cmd_line_));
241 E : ASSERT_FALSE(test_impl_.LoadAndValidateConfigurationFile());
242 E : }
243 :
244 E : TEST_F(PEHackerAppTest, ConfigurationLoadsMinimal) {
245 E : config_file_ = testing::GetSrcRelativePath(kConfigGoodMinimal);
246 E : cmd_line_.AppendSwitchPath("config-file", config_file_);
247 E : ASSERT_TRUE(test_impl_.ParseCommandLine(&cmd_line_));
248 E : ASSERT_TRUE(test_impl_.LoadAndValidateConfigurationFile());
249 :
250 : std::string expected_root = base::WideToUTF8(
251 E : config_file_.DirName().NormalizePathSeparators().value());
252 E : std::string root;
253 E : EXPECT_TRUE(test_impl_.variables_.GetString("ROOT", &root));
254 E : EXPECT_EQ(expected_root, root);
255 E : }
256 :
257 E : TEST_F(PEHackerAppTest, ConfigurationFailsExistingOutput) {
258 E : config_file_ = testing::GetSrcRelativePath(kConfigGoodExistingOutput);
259 E : cmd_line_.AppendSwitchPath("config-file", config_file_);
260 E : ASSERT_TRUE(test_impl_.ParseCommandLine(&cmd_line_));
261 E : ASSERT_FALSE(test_impl_.LoadAndValidateConfigurationFile());
262 E : }
263 :
264 E : TEST_F(PEHackerAppTest, ConfigurationLoadsExistingOutput) {
265 E : config_file_ = testing::GetSrcRelativePath(kConfigGoodExistingOutput);
266 E : cmd_line_.AppendSwitchPath("config-file", config_file_);
267 E : cmd_line_.AppendSwitch("overwrite");
268 E : ASSERT_TRUE(test_impl_.ParseCommandLine(&cmd_line_));
269 E : ASSERT_TRUE(test_impl_.LoadAndValidateConfigurationFile());
270 E : }
271 :
272 E : TEST_F(PEHackerAppTest, ConfigurationLoadsDefaultValue) {
273 E : config_file_ = testing::GetSrcRelativePath(kConfigGoodDefaultValue);
274 E : cmd_line_.AppendSwitchPath("config-file", config_file_);
275 E : ASSERT_TRUE(test_impl_.ParseCommandLine(&cmd_line_));
276 E : ASSERT_TRUE(test_impl_.LoadAndValidateConfigurationFile());
277 :
278 E : int i = 0;
279 E : EXPECT_TRUE(test_impl_.variables_.GetInteger("var1", &i));
280 E : EXPECT_EQ(42, i);
281 E : }
282 :
283 E : TEST_F(PEHackerAppTest, ConfigurationLoadsOverriddenDefaultValue) {
284 E : config_file_ = testing::GetSrcRelativePath(kConfigGoodDefaultValue);
285 E : cmd_line_.AppendSwitchPath("config-file", config_file_);
286 E : cmd_line_.AppendSwitchASCII("Dvar1", "0");
287 E : ASSERT_TRUE(test_impl_.ParseCommandLine(&cmd_line_));
288 E : ASSERT_TRUE(test_impl_.LoadAndValidateConfigurationFile());
289 :
290 E : int i = 0;
291 E : EXPECT_TRUE(test_impl_.variables_.GetInteger("var1", &i));
292 E : EXPECT_EQ(0, i);
293 E : }
294 :
295 E : TEST_F(PEHackerAppTest, ConfigurationLoadsNestedVariables) {
296 E : config_file_ = testing::GetSrcRelativePath(kConfigGoodNestedVariables);
297 E : cmd_line_.AppendSwitchPath("config-file", config_file_);
298 E : ASSERT_TRUE(test_impl_.ParseCommandLine(&cmd_line_));
299 E : ASSERT_TRUE(test_impl_.LoadAndValidateConfigurationFile());
300 E : }
301 :
302 E : TEST_F(PEHackerAppTest, RunNop) {
303 : base::FilePath input_module = testing::GetOutputRelativePath(
304 E : testing::kTestDllName);
305 E : base::FilePath output_module = temp_dir_.Append(testing::kTestDllName);
306 :
307 E : config_file_ = testing::GetSrcRelativePath(kConfigGoodNop);
308 E : cmd_line_.AppendSwitchPath("config-file", config_file_);
309 E : cmd_line_.AppendSwitchPath("Dinput_module", input_module);
310 E : cmd_line_.AppendSwitchPath("Doutput_module", output_module);
311 E : ASSERT_TRUE(test_impl_.ParseCommandLine(&cmd_line_));
312 :
313 E : EXPECT_EQ(0, test_impl_.Run());
314 E : EXPECT_TRUE(base::PathExists(output_module));
315 E : EXPECT_NO_FATAL_FAILURE(CheckTestDll(output_module));
316 E : }
317 :
318 : } // namespace pehacker
|