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/grinder/grinder_app.h"
16 :
17 : #include "base/files/scoped_temp_dir.h"
18 : #include "base/win/scoped_com_initializer.h"
19 : #include "gtest/gtest.h"
20 : #include "syzygy/application/application.h"
21 : #include "syzygy/core/unittest_util.h"
22 : #include "syzygy/pe/unittest_util.h"
23 : #include "syzygy/sampler/unittest_util.h"
24 :
25 : namespace grinder {
26 :
27 : namespace {
28 :
29 : class TestGrinderApp : public GrinderApp {
30 : public:
31 : // Expose for testing.
32 : using GrinderApp::trace_files_;
33 : using GrinderApp::output_file_;
34 : };
35 :
36 : class GrinderAppTest : public testing::PELibUnitTest {
37 : public:
38 : typedef testing::PELibUnitTest Super;
39 : typedef application::Application<TestGrinderApp> TestApplication;
40 :
41 : GrinderAppTest()
42 : : cmd_line_(base::FilePath(L"grinder.exe")),
43 E : impl_(app_.implementation()) {
44 E : }
45 :
46 E : virtual void SetUp() override {
47 E : Super::SetUp();
48 :
49 : // Setup the IO streams.
50 E : ASSERT_NO_FATAL_FAILURE(CreateTemporaryDir(&temp_dir_));
51 E : stdin_path_ = temp_dir_.Append(L"NUL");
52 E : stdout_path_ = temp_dir_.Append(L"stdout.txt");
53 E : stderr_path_ = temp_dir_.Append(L"stderr.txt");
54 E : ASSERT_NO_FATAL_FAILURE(InitStreams(
55 : stdin_path_, stdout_path_, stderr_path_));
56 :
57 : // Point the application at the test's command-line and IO streams.
58 E : app_.set_command_line(&cmd_line_);
59 E : app_.set_in(in());
60 E : app_.set_out(out());
61 E : app_.set_err(err());
62 E : }
63 :
64 : protected:
65 : // Ensures that COM is initialized for tests in this fixture.
66 : base::win::ScopedCOMInitializer com_initializer_;
67 :
68 : // The command line to be given to the application under test.
69 : base::CommandLine cmd_line_;
70 :
71 : // The application object under test.
72 : TestApplication app_;
73 :
74 : // A reference to the underlying application implementation for convenience.
75 : TestGrinderApp& impl_;
76 :
77 : // A temporary folder where all IO will be stored.
78 : base::FilePath temp_dir_;
79 :
80 : // @name File paths used for the standard IO streams.
81 : // @{
82 : base::FilePath stdin_path_;
83 : base::FilePath stdout_path_;
84 : base::FilePath stderr_path_;
85 : // @}
86 : };
87 :
88 : } // namespace
89 :
90 E : TEST_F(GrinderAppTest, ParseCommandLineFailsWithNoMode) {
91 E : cmd_line_.AppendArgPath(base::FilePath(L"foo.dat"));
92 E : ASSERT_FALSE(impl_.ParseCommandLine(&cmd_line_));
93 E : }
94 :
95 E : TEST_F(GrinderAppTest, ParseCommandLineFailsWithNoFiles) {
96 E : cmd_line_.AppendSwitchASCII("mode", "profile");
97 E : ASSERT_FALSE(impl_.ParseCommandLine(&cmd_line_));
98 E : }
99 :
100 E : TEST_F(GrinderAppTest, ParseCommandLineTraceFiles) {
101 E : std::vector<base::FilePath> temp_files;
102 E : cmd_line_.AppendSwitchASCII("mode", "profile");
103 E : for (size_t i = 0; i < 10; ++i) {
104 E : base::FilePath temp_file;
105 E : ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_dir_, &temp_file));
106 E : cmd_line_.AppendArgPath(temp_file);
107 E : temp_files.push_back(temp_file);
108 E : }
109 :
110 E : ASSERT_TRUE(impl_.ParseCommandLine(&cmd_line_));
111 E : ASSERT_EQ(temp_files, impl_.trace_files_);
112 E : }
113 :
114 E : TEST_F(GrinderAppTest, ParseCommandLineOutputFile) {
115 E : ASSERT_TRUE(impl_.output_file_.empty());
116 E : cmd_line_.AppendSwitchASCII("mode", "profile");
117 E : cmd_line_.AppendSwitchPath("output-file", base::FilePath(L"output.txt"));
118 : cmd_line_.AppendArgPath(testing::GetExeTestDataRelativePath(
119 E : testing::kProfileTraceFiles[0]));
120 :
121 E : ASSERT_TRUE(impl_.ParseCommandLine(&cmd_line_));
122 E : ASSERT_EQ(L"output.txt", impl_.output_file_.value());
123 E : }
124 :
125 E : TEST_F(GrinderAppTest, BasicBlockEntryEndToEnd) {
126 E : cmd_line_.AppendSwitchASCII("mode", "bbentry");
127 : cmd_line_.AppendArgPath(testing::GetExeTestDataRelativePath(
128 E : testing::kBBEntryTraceFiles[0]));
129 :
130 E : base::FilePath output_file;
131 E : ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_dir_, &output_file));
132 E : ASSERT_TRUE(base::DeleteFile(output_file, false));
133 E : cmd_line_.AppendSwitchPath("output-file", output_file);
134 :
135 E : ASSERT_TRUE(!base::PathExists(output_file));
136 :
137 E : EXPECT_EQ(0, app_.Run());
138 :
139 : // Verify that the output file was created.
140 E : EXPECT_TRUE(base::PathExists(output_file));
141 E : }
142 :
143 E : TEST_F(GrinderAppTest, MemReplayEndToEnd) {
144 E : cmd_line_.AppendSwitchASCII("mode", "memreplay");
145 : cmd_line_.AppendArgPath(testing::GetExeTestDataRelativePath(
146 E : testing::kMemProfTraceFile));
147 :
148 E : base::FilePath output_file;
149 E : ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_dir_, &output_file));
150 E : ASSERT_TRUE(base::DeleteFile(output_file, false));
151 E : cmd_line_.AppendSwitchPath("output-file", output_file);
152 :
153 E : ASSERT_TRUE(!base::PathExists(output_file));
154 :
155 E : EXPECT_EQ(0, app_.Run());
156 :
157 : // Verify that the output file was created.
158 E : EXPECT_TRUE(base::PathExists(output_file));
159 E : }
160 :
161 E : TEST_F(GrinderAppTest, ProfileEndToEnd) {
162 E : cmd_line_.AppendSwitchASCII("mode", "profile");
163 : cmd_line_.AppendArgPath(testing::GetExeTestDataRelativePath(
164 E : testing::kProfileTraceFiles[0]));
165 :
166 E : base::FilePath output_file;
167 E : ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_dir_, &output_file));
168 E : ASSERT_TRUE(base::DeleteFile(output_file, false));
169 E : cmd_line_.AppendSwitchPath("output-file", output_file);
170 :
171 E : ASSERT_TRUE(!base::PathExists(output_file));
172 :
173 E : EXPECT_EQ(0, app_.Run());
174 :
175 : // Verify that the output file was created.
176 E : EXPECT_TRUE(base::PathExists(output_file));
177 E : }
178 :
179 E : TEST_F(GrinderAppTest, CoverageEndToEnd) {
180 E : cmd_line_.AppendSwitchASCII("mode", "coverage");
181 : cmd_line_.AppendArgPath(testing::GetExeTestDataRelativePath(
182 E : testing::kCoverageTraceFiles[0]));
183 :
184 E : base::FilePath output_file;
185 E : ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_dir_, &output_file));
186 E : ASSERT_TRUE(base::DeleteFile(output_file, false));
187 E : cmd_line_.AppendSwitchPath("output-file", output_file);
188 E : cmd_line_.AppendSwitchASCII("output-format", "lcov");
189 :
190 E : ASSERT_TRUE(!base::PathExists(output_file));
191 :
192 E : EXPECT_EQ(0, app_.Run());
193 :
194 : // Verify that the output file was created.
195 E : EXPECT_TRUE(base::PathExists(output_file));
196 E : }
197 :
198 E : TEST_F(GrinderAppTest, SampleEndToEnd) {
199 E : base::FilePath trace_file = temp_dir_.Append(L"sampler.bin");
200 E : ASSERT_NO_FATAL_FAILURE(testing::WriteDummySamplerTraceFile(trace_file));
201 E : ASSERT_TRUE(base::PathExists(trace_file));
202 :
203 E : cmd_line_.AppendSwitchASCII("mode", "sample");
204 : cmd_line_.AppendSwitchPath(
205 E : "image", testing::GetOutputRelativePath(testing::kTestDllName));
206 E : cmd_line_.AppendArgPath(trace_file);
207 :
208 E : base::FilePath output_file;
209 E : ASSERT_TRUE(base::CreateTemporaryFileInDir(temp_dir_, &output_file));
210 E : ASSERT_TRUE(base::DeleteFile(output_file, false));
211 E : cmd_line_.AppendSwitchPath("output-file", output_file);
212 :
213 E : ASSERT_TRUE(!base::PathExists(output_file));
214 :
215 E : EXPECT_EQ(0, app_.Run());
216 :
217 : // Verify that the output file was created.
218 E : EXPECT_TRUE(base::PathExists(output_file));
219 E : }
220 :
221 : } // namespace grinder
|