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/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 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 : 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 E : const CommandLine* current_command_line = CommandLine::ForCurrentProcess();
115 E : ASSERT_TRUE(current_command_line != NULL);
116 :
117 : // Validate the application name.
118 E : EXPECT_EQ(kTestAppImplName, test_app_.name());
119 :
120 : // Check the default command line and streams.
121 E : EXPECT_EQ(current_command_line, test_app_.command_line());
122 :
123 : // Validate the accessors.
124 E : test_app_.set_command_line(&cmd_line_);
125 E : EXPECT_EQ(&cmd_line_, test_app_.command_line());
126 :
127 E : EXPECT_EQ(0, test_app_.Run());
128 E : }
129 :
130 E : TEST_F(ApplicationTest, AppImplBaseVerbosity) {
131 E : ScopedLogLevelSaver log_level_saver;
132 :
133 E : cmd_line_.AppendSwitchASCII("verbose", "2");
134 E : test_app_.set_command_line(&cmd_line_);
135 :
136 E : ASSERT_EQ(0, test_app_.Run());
137 E : ASSERT_EQ(-2, logging::GetMinLogLevel());
138 E : }
139 :
140 E : TEST_F(ApplicationTest, MockAppFailsCommandLineParsing) {
141 E : MockAppImpl& mock_impl = mock_app_.implementation();
142 :
143 : EXPECT_CALL(mock_impl, ParseCommandLine(_))
144 E : .WillOnce(Return(false));
145 E : EXPECT_NE(0, mock_app_.Run());
146 E : }
147 :
148 E : TEST_F(ApplicationTest, MockAppFailsSetup) {
149 E : MockAppImpl& mock_impl = mock_app_.implementation();
150 :
151 : EXPECT_CALL(mock_impl, ParseCommandLine(_))
152 E : .WillOnce(Return(true));
153 : EXPECT_CALL(mock_impl, SetUp())
154 E : .WillOnce(Return(false));
155 E : EXPECT_NE(0, mock_app_.Run());
156 E : }
157 :
158 E : TEST_F(ApplicationTest, MockAppFailsRun) {
159 E : MockAppImpl& mock_impl = mock_app_.implementation();
160 :
161 : EXPECT_CALL(mock_impl, ParseCommandLine(_))
162 E : .WillOnce(Return(true));
163 : EXPECT_CALL(mock_impl, SetUp())
164 E : .WillOnce(Return(true));
165 : EXPECT_CALL(mock_impl, Run())
166 E : .WillOnce(Return(2));
167 E : EXPECT_CALL(mock_impl, TearDown());
168 E : EXPECT_EQ(2, mock_app_.Run());
169 E : }
170 :
171 E : TEST_F(ApplicationTest, AbsolutePath) {
172 E : AppImplBase& app_impl = test_app_.implementation();
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 E : EXPECT_EQ(base::FilePath(), app_impl.AbsolutePath(base::FilePath()));
180 E : EXPECT_EQ(kAbsolutePath, app_impl.AbsolutePath(kRelativePath));
181 E : EXPECT_EQ(kAbsolutePath, app_impl.AbsolutePath(kAbsolutePath));
182 E : }
183 :
184 E : TEST_F(ApplicationTest, AppendMatchingPaths) {
185 : // Create some files to match against.
186 E : base::FilePath temp_dir;
187 E : ASSERT_NO_FATAL_FAILURE(CreateTemporaryDir(&temp_dir));
188 E : ASSERT_TRUE(CreateEmptyFile(temp_dir.Append(L"a.txt")));
189 E : ASSERT_TRUE(CreateEmptyFile(temp_dir.Append(L"b.txt")));
190 E : ASSERT_TRUE(CreateEmptyFile(temp_dir.Append(L"c.txt")));
191 E : ASSERT_TRUE(CreateEmptyFile(temp_dir.Append(L"a.bin")));
192 :
193 : // Should get false on no match.
194 E : std::vector<base::FilePath> no_matching_paths;
195 : ASSERT_FALSE(TestAppImpl::AppendMatchingPaths(temp_dir.Append(L"d.*"),
196 E : &no_matching_paths));
197 E : EXPECT_TRUE(no_matching_paths.empty());
198 :
199 : // Match a pattern where the extension is a wildcard.
200 E : std::vector<base::FilePath> a_star_paths;
201 : ASSERT_TRUE(TestAppImpl::AppendMatchingPaths(temp_dir.Append(L"a.*"),
202 E : &a_star_paths));
203 : EXPECT_THAT(a_star_paths,
204 : testing::ElementsAre(temp_dir.Append(L"a.bin"),
205 E : temp_dir.Append(L"a.txt")));
206 :
207 : // Match a pattern where the extension is set but the root name is a wildcard.
208 E : std::vector<base::FilePath> star_txt_paths;
209 : ASSERT_TRUE(TestAppImpl::AppendMatchingPaths(temp_dir.Append(L"*.txt"),
210 E : &star_txt_paths));
211 : EXPECT_THAT(star_txt_paths,
212 : testing::ElementsAre(temp_dir.Append(L"a.txt"),
213 : temp_dir.Append(L"b.txt"),
214 E : temp_dir.Append(L"c.txt")));
215 E : }
216 :
217 E : TEST_F(ApplicationTest, GetDeprecatedSwitch) {
218 E : const std::string kFoo("foo");
219 E : const std::string kBar("bar");
220 E : const std::string kMissing("missing");
221 E : const base::FilePath kFooPath(L"C:\\foo");
222 E : const base::FilePath kBarPath(L"C:\\bar");
223 E : ASSERT_NE(kFoo, kBar);
224 E : ASSERT_NE(kFooPath, kBarPath);
225 :
226 E : base::FilePath path;
227 : EXPECT_TRUE(TestAppImpl::GetDeprecatedSwitch(
228 E : &cmd_line_, kFoo, kBar, &CommandLine::GetSwitchValuePath, &path));
229 E : EXPECT_TRUE(path.empty());
230 :
231 E : cmd_line_.AppendSwitchPath(kFoo, kFooPath);
232 E : cmd_line_.AppendSwitchPath(kBar, kBarPath);
233 :
234 : EXPECT_FALSE(TestAppImpl::GetDeprecatedSwitch(
235 E : &cmd_line_, kFoo, kBar, &CommandLine::GetSwitchValuePath, &path));
236 :
237 : EXPECT_TRUE(TestAppImpl::GetDeprecatedSwitch(
238 E : &cmd_line_, kFoo, kMissing, &CommandLine::GetSwitchValuePath, &path));
239 E : EXPECT_EQ(kFooPath, path);
240 :
241 : EXPECT_TRUE(TestAppImpl::GetDeprecatedSwitch(
242 E : &cmd_line_, kMissing, kBar, &CommandLine::GetSwitchValuePath, &path));
243 E : EXPECT_EQ(kBarPath, path);
244 E : }
245 :
246 : } // namespace application
|