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/common/unittest_util.h"
16 :
17 : #include "base/files/file_path.h"
18 : #include "base/strings/string_piece.h"
19 : #include "base/strings/stringprintf.h"
20 : #include "base/strings/utf_string_conversions.h"
21 : #include "syzygy/core/unittest_util.h"
22 :
23 : namespace testing {
24 :
25 : ApplicationTestBase* ApplicationTestBase::self_ = NULL;
26 :
27 : void ApplicationTestBase::InitStreams(const base::FilePath& in_path,
28 : const base::FilePath& out_path,
29 E : const base::FilePath& err_path) {
30 E : ASSERT_FALSE(in_path.empty());
31 E : ASSERT_FALSE(out_path.empty());
32 E : ASSERT_FALSE(err_path.empty());
33 :
34 E : in_.reset(base::OpenFile(in_path, "r"));
35 E : out_.reset(base::OpenFile(out_path, "w"));
36 E : err_.reset(base::OpenFile(err_path, "w"));
37 :
38 E : ASSERT_TRUE(in_.get() != NULL);
39 E : ASSERT_TRUE(out_.get() != NULL);
40 E : ASSERT_TRUE(err_.get() != NULL);
41 :
42 : // Intercept logging.
43 E : ASSERT_TRUE(self_ == NULL);
44 E : ASSERT_TRUE(log_handler_ == NULL);
45 E : self_ = this;
46 E : log_handler_ = logging::GetLogMessageHandler();
47 E : logging::SetLogMessageHandler(&HandleLogMessage);
48 E : }
49 :
50 E : void ApplicationTestBase::TearDownStreams() {
51 E : if (self_ != NULL) {
52 E : logging::SetLogMessageHandler(log_handler_);
53 E : log_handler_ = NULL;
54 E : self_ = NULL;
55 : }
56 :
57 E : ASSERT_NO_FATAL_FAILURE(TearDownStream(&in_));
58 E : ASSERT_NO_FATAL_FAILURE(TearDownStream(&out_));
59 E : ASSERT_NO_FATAL_FAILURE(TearDownStream(&err_));
60 E : }
61 :
62 E : void ApplicationTestBase::SetUp() {
63 E : Super::SetUp();
64 :
65 : // Save the log level so that we can restore it in TearDown.
66 E : log_level_ = logging::GetMinLogLevel();
67 :
68 : // By default we don't log to console.
69 E : log_to_console_ = false;
70 E : }
71 :
72 E : void ApplicationTestBase::TearDown() {
73 E : logging::SetMinLogLevel(log_level_);
74 :
75 : // These need to be shut down before we can delete the temporary
76 : // directories.
77 E : EXPECT_NO_FATAL_FAILURE(TearDownStreams());
78 :
79 E : DirList::const_iterator iter;
80 E : for (iter = temp_dirs_.begin(); iter != temp_dirs_.end(); ++iter) {
81 E : bool success = base::DeleteFile(*iter, true);
82 : // VS2013 holds open handles to any PDB file that has been loaded while
83 : // the debugger is active. This often prevents our unittests from
84 : // cleaning up after themselves.
85 E : EXPECT_TRUE(success || ::IsDebuggerPresent());
86 E : }
87 :
88 E : Super::TearDown();
89 E : }
90 :
91 : bool ApplicationTestBase::HandleLogMessage(int severity, const char* file,
92 E : int line, size_t message_start, const std::string& str) {
93 E : DCHECK(self_ != NULL);
94 E : if (severity < logging::GetMinLogLevel())
95 i : return true;
96 E : fprintf(self_->err(), "%s", str.c_str());
97 E : fflush(self_->err());
98 :
99 : // If we're logging to console then repeat the message there.
100 E : if (self_->log_to_console_) {
101 i : fprintf(stdout, "%s", str.c_str());
102 i : fflush(stdout);
103 : }
104 :
105 : // Pass FATAL log messages, like those coming from DCHECKs to default handler
106 : // to crash the program.
107 E : if (severity == logging::LOG_FATAL)
108 i : return false;
109 :
110 E : return true;
111 E : }
112 :
113 E : void ApplicationTestBase::TearDownStream(base::ScopedFILE* stream) {
114 E : ASSERT_TRUE(stream != NULL);
115 E : if (stream->get() == NULL)
116 E : return;
117 E : ASSERT_EQ(0, ::fclose(stream->get()));
118 E : stream->reset();
119 E : }
120 :
121 : FILE* ApplicationTestBase::GetOrInitFile(base::ScopedFILE* f,
122 E : const char* mode) {
123 E : DCHECK(f != NULL);
124 E : DCHECK(mode != NULL);
125 E : if (f->get() == NULL)
126 E : f->reset(base::OpenFile(base::FilePath(L"NUL"), mode));
127 E : return f->get();
128 E : }
129 :
130 E : ScopedEnvironmentVariable::ScopedEnvironmentVariable() {
131 E : }
132 :
133 : ScopedEnvironmentVariable::ScopedEnvironmentVariable(base::StringPiece name,
134 E : base::StringPiece value) {
135 E : CHECK(Set(name, value));
136 E : }
137 :
138 E : ScopedEnvironmentVariable::~ScopedEnvironmentVariable() {
139 E : if (should_restore_) {
140 E : CHECK(env_->SetVar(name_.c_str(), restore_value_));
141 E : } else {
142 E : CHECK(env_->UnSetVar(name_.c_str()));
143 : }
144 E : }
145 :
146 : bool ScopedEnvironmentVariable::Set(base::StringPiece name,
147 E : base::StringPiece value) {
148 E : DCHECK(!name.empty());
149 E : if (env_)
150 i : return false; // Setting more than once is disallowed.
151 :
152 E : name.CopyToString(&name_);
153 E : env_.reset(base::Environment::Create());
154 E : CHECK(env_);
155 :
156 : // Get restoration info.
157 E : should_restore_ = true;
158 E : if (!env_->GetVar(name_.c_str(), &restore_value_))
159 E : should_restore_ = false; // Variable does not exist.
160 :
161 : // Set the variable.
162 E : CHECK(env_->SetVar(name_.c_str(), value.as_string()));
163 :
164 E : return true;
165 E : }
166 :
167 : namespace {
168 :
169 : // Symbol path.
170 : const wchar_t kLocalSymbolDir[] = L"symbols";
171 : const char kNtSymbolPathPrefix[] = "SRV*";
172 : const char kNtSymbolPathSuffixMicrosoft[] =
173 : "*http://msdl.microsoft.com/download/symbols";
174 : const char kNtSymbolPathSuffixGoogle[] =
175 : "*https://chromium-browser-symsrv.commondatastorage.googleapis.com";
176 :
177 E : bool GetPathValueNarrow(const base::FilePath& path, std::string* value) {
178 E : const std::wstring value_wide = path.value();
179 E : return base::WideToUTF8(value_wide.c_str(), value_wide.length(), value);
180 E : }
181 :
182 E : bool GetNtSymbolPathValue(std::string* nt_symbol_path) {
183 E : DCHECK(nt_symbol_path);
184 :
185 : base::FilePath output_path =
186 E : testing::GetOutputRelativePath(L"").NormalizePathSeparators();
187 :
188 : // Build the local symbol directory path and ensure it exists.
189 E : base::FilePath local_symbol_path = output_path.Append(kLocalSymbolDir);
190 E : if (!base::CreateDirectory(local_symbol_path))
191 i : return false;
192 :
193 : // Build the full symbol path.
194 E : std::string output_path_str;
195 E : if (!GetPathValueNarrow(output_path, &output_path_str))
196 i : return false;
197 :
198 E : std::string local_symbol_path_microsoft;
199 : if (!GetPathValueNarrow(local_symbol_path.Append(L"microsoft"),
200 E : &local_symbol_path_microsoft)) {
201 i : return false;
202 : }
203 E : std::string local_symbol_path_google;
204 : if (!GetPathValueNarrow(local_symbol_path.Append(L"google"),
205 E : &local_symbol_path_google)) {
206 i : return false;
207 : }
208 :
209 : base::SStringPrintf(
210 : nt_symbol_path, "%s;%s%s%s;%s%s%s", output_path_str.c_str(),
211 : kNtSymbolPathPrefix, local_symbol_path_google.c_str(),
212 : kNtSymbolPathSuffixGoogle, kNtSymbolPathPrefix,
213 E : local_symbol_path_microsoft.c_str(), kNtSymbolPathSuffixMicrosoft);
214 :
215 E : return true;
216 E : }
217 :
218 : } // namespace
219 :
220 E : bool ScopedSymbolPath::Setup() {
221 : // Override NT symbol path.
222 E : std::string nt_symbol_path;
223 E : if (!GetNtSymbolPathValue(&nt_symbol_path))
224 i : return false;
225 :
226 E : if (!nt_symbol_path_.Set(testing::kNtSymbolPathEnvVar, nt_symbol_path))
227 i : return false;
228 :
229 E : return true;
230 E : }
231 :
232 : } // namespace testing
|