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/application/application.h"
16 :
17 : #include <shellapi.h>
18 :
19 : #include "base/files/file_util.h"
20 : #include "gmock/gmock.h"
21 : #include "gtest/gtest.h"
22 : #include "syzygy/common/unittest_util.h"
23 :
24 : namespace application {
25 :
26 : using ::testing::Return;
27 : using ::testing::ScopedLogLevelSaver;
28 : using ::testing::StrictMock;
29 : using ::testing::_;
30 :
31 : namespace {
32 :
33 : const char kTestAppImplName[] = "Test Application (Unit Test)";
34 :
35 : // A test application that simply makes the AppImplBase concrete.
36 : class TestAppImpl : public AppImplBase {
37 : public:
38 E : TestAppImpl() : AppImplBase(kTestAppImplName) {
39 E : }
40 : };
41 :
42 : // A mock application implementation class
43 : class MockAppImpl : public AppImplBase {
44 : public:
45 E : MockAppImpl() : AppImplBase("Mock Application (Unit Test)") {
46 E : }
47 :
48 E : MOCK_METHOD1(ParseCommandLine, bool(const base::CommandLine*));
49 E : MOCK_METHOD0(SetUp, bool());
50 E : MOCK_METHOD0(Run, int());
51 E : MOCK_METHOD0(TearDown, bool());
52 : };
53 :
54 : // Handy types we'll use below.
55 : typedef Application<TestAppImpl, INIT_LOGGING_YES> TestApp;
56 : typedef Application<StrictMock<MockAppImpl>, INIT_LOGGING_NO> MockApp;
57 :
58 : // A basic test fixture that sets up dummy standard streams.
59 : class ApplicationTest : public testing::ApplicationTestBase {
60 : protected:
61 E : ApplicationTest() : cmd_line_(base::FilePath(L"test.exe")) {
62 E : }
63 :
64 : template<typename App>
65 E : void RerouteAppStreams(App* app) {
66 E : ASSERT_TRUE(app != NULL);
67 :
68 : // Validate that app's streams were initialized properly.
69 E : ASSERT_EQ(stdin, app->in());
70 E : ASSERT_EQ(stdout, app->out());
71 E : ASSERT_EQ(stderr, app->err());
72 :
73 : // Route test_app_ streams to
74 E : app->set_in(in());
75 E : app->set_out(out());
76 E : app->set_err(err());
77 :
78 E : ASSERT_EQ(in(), app->in());
79 E : ASSERT_EQ(out(), app->out());
80 E : ASSERT_EQ(err(), app->err());
81 E : }
82 :
83 E : virtual void SetUp() override {
84 E : testing::Test::SetUp();
85 :
86 : // Validate test streams were created.
87 E : ASSERT_TRUE(in() != NULL);
88 E : ASSERT_TRUE(out() != NULL);
89 E : ASSERT_TRUE(err() != NULL);
90 :
91 : // Reroute the test application streams.
92 E : RerouteAppStreams(&test_app_);
93 E : RerouteAppStreams(&mock_app_);
94 E : }
95 :
96 : base::CommandLine cmd_line_;
97 : TestApp test_app_;
98 : MockApp mock_app_;
99 : };
100 :
101 E : bool CreateEmptyFile(const base::FilePath& path) {
102 E : base::ScopedFILE f(base::OpenFile(path, "wb"));
103 E : if (f.get() == NULL)
104 i : return false;
105 E : return true;
106 E : }
107 :
108 : } // namespace
109 :
110 E : TEST_F(ApplicationTest, AppImplBaseDefault) {
111 : // The command line for this process has already been set we can pass
112 : // whatever we want to Main and it will end up using the current
113 : // command line.
114 : const base::CommandLine* current_command_line =
115 E : base::CommandLine::ForCurrentProcess();
116 E : ASSERT_TRUE(current_command_line != NULL);
117 :
118 : // Validate the application name.
119 E : EXPECT_EQ(kTestAppImplName, test_app_.name());
120 :
121 : // Check the default command line and streams.
122 E : EXPECT_EQ(current_command_line, test_app_.command_line());
123 :
124 : // Validate the accessors.
125 E : test_app_.set_command_line(&cmd_line_);
126 E : EXPECT_EQ(&cmd_line_, test_app_.command_line());
127 :
128 E : EXPECT_EQ(0, test_app_.Run());
129 E : }
130 :
131 E : TEST_F(ApplicationTest, AppImplBaseVerbosity) {
132 E : ScopedLogLevelSaver log_level_saver;
133 :
134 E : cmd_line_.AppendSwitchASCII("verbose", "2");
135 E : test_app_.set_command_line(&cmd_line_);
136 :
137 E : ASSERT_EQ(0, test_app_.Run());
138 E : ASSERT_EQ(-2, logging::GetMinLogLevel());
139 E : }
140 :
141 E : TEST_F(ApplicationTest, MockAppFailsCommandLineParsing) {
142 E : MockAppImpl& mock_impl = mock_app_.implementation();
143 :
144 : EXPECT_CALL(mock_impl, ParseCommandLine(_))
145 E : .WillOnce(Return(false));
146 E : EXPECT_NE(0, mock_app_.Run());
147 E : }
148 :
149 E : TEST_F(ApplicationTest, MockAppFailsSetup) {
150 E : MockAppImpl& mock_impl = mock_app_.implementation();
151 :
152 : EXPECT_CALL(mock_impl, ParseCommandLine(_))
153 E : .WillOnce(Return(true));
154 : EXPECT_CALL(mock_impl, SetUp())
155 E : .WillOnce(Return(false));
156 E : EXPECT_NE(0, mock_app_.Run());
157 E : }
158 :
159 E : TEST_F(ApplicationTest, MockAppFailsRun) {
160 E : MockAppImpl& mock_impl = mock_app_.implementation();
161 :
162 : EXPECT_CALL(mock_impl, ParseCommandLine(_))
163 E : .WillOnce(Return(true));
164 : EXPECT_CALL(mock_impl, SetUp())
165 E : .WillOnce(Return(true));
166 : EXPECT_CALL(mock_impl, Run())
167 E : .WillOnce(Return(2));
168 E : EXPECT_CALL(mock_impl, TearDown());
169 E : EXPECT_EQ(2, mock_app_.Run());
170 E : }
171 :
172 E : TEST_F(ApplicationTest, AbsolutePath) {
173 E : base::FilePath current_dir;
174 E : ASSERT_TRUE(base::GetCurrentDirectory(¤t_dir));
175 :
176 E : const base::FilePath kRelativePath(L"foo\\bar\\file.txt");
177 E : const base::FilePath kAbsolutePath(current_dir.Append(kRelativePath));
178 :
179 : EXPECT_EQ(base::FilePath(),
180 E : test_app_.implementation().AbsolutePath(base::FilePath()));
181 : EXPECT_EQ(kAbsolutePath,
182 E : test_app_.implementation().AbsolutePath(kRelativePath));
183 : EXPECT_EQ(kAbsolutePath,
184 E : test_app_.implementation().AbsolutePath(kAbsolutePath));
185 E : }
186 :
187 E : TEST_F(ApplicationTest, AppendMatchingPaths) {
188 : // Create some files to match against.
189 E : base::FilePath temp_dir;
190 E : ASSERT_NO_FATAL_FAILURE(CreateTemporaryDir(&temp_dir));
191 E : ASSERT_TRUE(CreateEmptyFile(temp_dir.Append(L"a.txt")));
192 E : ASSERT_TRUE(CreateEmptyFile(temp_dir.Append(L"b.txt")));
193 E : ASSERT_TRUE(CreateEmptyFile(temp_dir.Append(L"c.txt")));
194 E : ASSERT_TRUE(CreateEmptyFile(temp_dir.Append(L"a.bin")));
195 :
196 : // Should get false on no match.
197 E : std::vector<base::FilePath> no_matching_paths;
198 : ASSERT_FALSE(TestAppImpl::AppendMatchingPaths(temp_dir.Append(L"d.*"),
199 E : &no_matching_paths));
200 E : EXPECT_TRUE(no_matching_paths.empty());
201 :
202 : // Match a pattern where the extension is a wildcard.
203 E : std::vector<base::FilePath> a_star_paths;
204 : ASSERT_TRUE(TestAppImpl::AppendMatchingPaths(temp_dir.Append(L"a.*"),
205 E : &a_star_paths));
206 : EXPECT_THAT(a_star_paths,
207 : testing::ElementsAre(temp_dir.Append(L"a.bin"),
208 E : temp_dir.Append(L"a.txt")));
209 :
210 : // Match a pattern where the extension is set but the root name is a wildcard.
211 E : std::vector<base::FilePath> star_txt_paths;
212 : ASSERT_TRUE(TestAppImpl::AppendMatchingPaths(temp_dir.Append(L"*.txt"),
213 E : &star_txt_paths));
214 : EXPECT_THAT(star_txt_paths,
215 : testing::ElementsAre(temp_dir.Append(L"a.txt"),
216 : temp_dir.Append(L"b.txt"),
217 E : temp_dir.Append(L"c.txt")));
218 E : }
219 :
220 E : TEST_F(ApplicationTest, GetDeprecatedSwitch) {
221 E : const std::string kFoo("foo");
222 E : const std::string kBar("bar");
223 E : const std::string kMissing("missing");
224 E : const base::FilePath kFooPath(L"C:\\foo");
225 E : const base::FilePath kBarPath(L"C:\\bar");
226 E : ASSERT_NE(kFoo, kBar);
227 E : ASSERT_NE(kFooPath, kBarPath);
228 :
229 E : base::FilePath path;
230 : EXPECT_TRUE(TestAppImpl::GetDeprecatedSwitch(
231 E : &cmd_line_, kFoo, kBar, &base::CommandLine::GetSwitchValuePath, &path));
232 E : EXPECT_TRUE(path.empty());
233 :
234 E : cmd_line_.AppendSwitchPath(kFoo, kFooPath);
235 E : cmd_line_.AppendSwitchPath(kBar, kBarPath);
236 :
237 : EXPECT_FALSE(TestAppImpl::GetDeprecatedSwitch(
238 E : &cmd_line_, kFoo, kBar, &base::CommandLine::GetSwitchValuePath, &path));
239 :
240 : EXPECT_TRUE(TestAppImpl::GetDeprecatedSwitch(
241 : &cmd_line_, kFoo, kMissing, &base::CommandLine::GetSwitchValuePath,
242 E : &path));
243 E : EXPECT_EQ(kFooPath, path);
244 :
245 : EXPECT_TRUE(TestAppImpl::GetDeprecatedSwitch(
246 : &cmd_line_, kMissing, kBar, &base::CommandLine::GetSwitchValuePath,
247 E : &path));
248 E : EXPECT_EQ(kBarPath, path);
249 E : }
250 :
251 : } // namespace application
|