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 : base::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 : bool b = false;
184 :
185 E : EXPECT_TRUE(test_impl_.variables_.GetString("var1", &s));
186 E : EXPECT_EQ("val1", s);
187 :
188 E : EXPECT_TRUE(test_impl_.variables_.GetInteger("var2", &i));
189 E : EXPECT_EQ(45, i);
190 :
191 E : EXPECT_TRUE(test_impl_.variables_.GetString("var3", &s));
192 E : EXPECT_EQ("string", s);
193 :
194 E : EXPECT_TRUE(test_impl_.variables_.GetBoolean("var4", &b));
195 E : EXPECT_FALSE(b);
196 :
197 E : EXPECT_TRUE(test_impl_.variables_.GetString("var5", &s));
198 E : EXPECT_TRUE(s.empty());
199 E : }
200 :
201 E : TEST_F(PEHackerAppTest, ConfigurationFailsPathDoesNotExist) {
202 E : config_file_ = testing::GetSrcRelativePath(kConfigBadPathDoesNotExist);
203 E : cmd_line_.AppendSwitchPath("config-file", config_file_);
204 E : ASSERT_TRUE(test_impl_.ParseCommandLine(&cmd_line_));
205 E : ASSERT_FALSE(test_impl_.LoadAndValidateConfigurationFile());
206 E : }
207 :
208 E : TEST_F(PEHackerAppTest, ConfigurationFailsEmpty) {
209 E : config_file_ = testing::GetSrcRelativePath(kConfigBadEmpty);
210 E : cmd_line_.AppendSwitchPath("config-file", config_file_);
211 E : ASSERT_TRUE(test_impl_.ParseCommandLine(&cmd_line_));
212 E : ASSERT_FALSE(test_impl_.LoadAndValidateConfigurationFile());
213 E : }
214 :
215 E : TEST_F(PEHackerAppTest, ConfigurationFailsNotJson) {
216 E : config_file_ = testing::GetSrcRelativePath(kConfigBadNotJson);
217 E : cmd_line_.AppendSwitchPath("config-file", config_file_);
218 E : ASSERT_TRUE(test_impl_.ParseCommandLine(&cmd_line_));
219 E : ASSERT_FALSE(test_impl_.LoadAndValidateConfigurationFile());
220 E : }
221 :
222 E : TEST_F(PEHackerAppTest, ConfigurationFailsList) {
223 E : config_file_ = testing::GetSrcRelativePath(kConfigBadList);
224 E : cmd_line_.AppendSwitchPath("config-file", config_file_);
225 E : ASSERT_TRUE(test_impl_.ParseCommandLine(&cmd_line_));
226 E : ASSERT_FALSE(test_impl_.LoadAndValidateConfigurationFile());
227 E : }
228 :
229 E : TEST_F(PEHackerAppTest, ConfigurationFailsString) {
230 E : config_file_ = testing::GetSrcRelativePath(kConfigBadString);
231 E : cmd_line_.AppendSwitchPath("config-file", config_file_);
232 E : ASSERT_TRUE(test_impl_.ParseCommandLine(&cmd_line_));
233 E : ASSERT_FALSE(test_impl_.LoadAndValidateConfigurationFile());
234 E : }
235 :
236 E : TEST_F(PEHackerAppTest, ConfigurationFailsCircularVariables) {
237 E : config_file_ = testing::GetSrcRelativePath(kConfigBadCircularVariables);
238 E : cmd_line_.AppendSwitchPath("config-file", config_file_);
239 E : ASSERT_TRUE(test_impl_.ParseCommandLine(&cmd_line_));
240 E : ASSERT_FALSE(test_impl_.LoadAndValidateConfigurationFile());
241 E : }
242 :
243 E : TEST_F(PEHackerAppTest, ConfigurationLoadsMinimal) {
244 E : config_file_ = testing::GetSrcRelativePath(kConfigGoodMinimal);
245 E : cmd_line_.AppendSwitchPath("config-file", config_file_);
246 E : ASSERT_TRUE(test_impl_.ParseCommandLine(&cmd_line_));
247 E : ASSERT_TRUE(test_impl_.LoadAndValidateConfigurationFile());
248 :
249 : std::string expected_root = base::WideToUTF8(
250 E : config_file_.DirName().NormalizePathSeparators().value());
251 E : std::string root;
252 E : EXPECT_TRUE(test_impl_.variables_.GetString("ROOT", &root));
253 E : EXPECT_EQ(expected_root, root);
254 E : }
255 :
256 E : TEST_F(PEHackerAppTest, ConfigurationFailsExistingOutput) {
257 E : config_file_ = testing::GetSrcRelativePath(kConfigGoodExistingOutput);
258 E : cmd_line_.AppendSwitchPath("config-file", config_file_);
259 E : ASSERT_TRUE(test_impl_.ParseCommandLine(&cmd_line_));
260 E : ASSERT_FALSE(test_impl_.LoadAndValidateConfigurationFile());
261 E : }
262 :
263 E : TEST_F(PEHackerAppTest, ConfigurationLoadsExistingOutput) {
264 E : config_file_ = testing::GetSrcRelativePath(kConfigGoodExistingOutput);
265 E : cmd_line_.AppendSwitchPath("config-file", config_file_);
266 E : cmd_line_.AppendSwitch("overwrite");
267 E : ASSERT_TRUE(test_impl_.ParseCommandLine(&cmd_line_));
268 E : ASSERT_TRUE(test_impl_.LoadAndValidateConfigurationFile());
269 E : }
270 :
271 E : TEST_F(PEHackerAppTest, ConfigurationLoadsDefaultValue) {
272 E : config_file_ = testing::GetSrcRelativePath(kConfigGoodDefaultValue);
273 E : cmd_line_.AppendSwitchPath("config-file", config_file_);
274 E : ASSERT_TRUE(test_impl_.ParseCommandLine(&cmd_line_));
275 E : ASSERT_TRUE(test_impl_.LoadAndValidateConfigurationFile());
276 :
277 E : int i = 0;
278 E : EXPECT_TRUE(test_impl_.variables_.GetInteger("var1", &i));
279 E : EXPECT_EQ(42, i);
280 E : }
281 :
282 E : TEST_F(PEHackerAppTest, ConfigurationLoadsOverriddenDefaultValue) {
283 E : config_file_ = testing::GetSrcRelativePath(kConfigGoodDefaultValue);
284 E : cmd_line_.AppendSwitchPath("config-file", config_file_);
285 E : cmd_line_.AppendSwitchASCII("Dvar1", "0");
286 E : ASSERT_TRUE(test_impl_.ParseCommandLine(&cmd_line_));
287 E : ASSERT_TRUE(test_impl_.LoadAndValidateConfigurationFile());
288 :
289 E : int i = 0;
290 E : EXPECT_TRUE(test_impl_.variables_.GetInteger("var1", &i));
291 E : EXPECT_EQ(0, i);
292 E : }
293 :
294 E : TEST_F(PEHackerAppTest, ConfigurationLoadsNestedVariables) {
295 E : config_file_ = testing::GetSrcRelativePath(kConfigGoodNestedVariables);
296 E : cmd_line_.AppendSwitchPath("config-file", config_file_);
297 E : ASSERT_TRUE(test_impl_.ParseCommandLine(&cmd_line_));
298 E : ASSERT_TRUE(test_impl_.LoadAndValidateConfigurationFile());
299 E : }
300 :
301 E : TEST_F(PEHackerAppTest, RunNop) {
302 : base::FilePath input_module = testing::GetOutputRelativePath(
303 E : testing::kTestDllName);
304 E : base::FilePath output_module = temp_dir_.Append(testing::kTestDllName);
305 :
306 E : config_file_ = testing::GetSrcRelativePath(kConfigGoodNop);
307 E : cmd_line_.AppendSwitchPath("config-file", config_file_);
308 E : cmd_line_.AppendSwitchPath("Dinput_module", input_module);
309 E : cmd_line_.AppendSwitchPath("Doutput_module", output_module);
310 E : ASSERT_TRUE(test_impl_.ParseCommandLine(&cmd_line_));
311 :
312 E : EXPECT_EQ(0, test_impl_.Run());
313 E : EXPECT_TRUE(base::PathExists(output_module));
314 E : EXPECT_NO_FATAL_FAILURE(CheckTestDll(output_module));
315 E : }
316 :
317 : } // namespace pehacker
|