Popular sites on the NTP: check that experiment group StartsWith (rather than IS...
[chromium-blink-merge.git] / chrome / browser / diagnostics / diagnostics_writer.cc
blobf219812cb3ee7e11e4d7eede35a58f20e64c839c
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/diagnostics/diagnostics_writer.h"
7 #include "build/build_config.h"
9 #if defined(OS_POSIX)
10 #include <stdio.h>
11 #include <unistd.h>
12 #endif
14 #include <string>
16 #include "base/basictypes.h"
17 #include "base/command_line.h"
18 #include "base/logging.h"
19 #include "base/strings/string16.h"
20 #include "base/strings/stringprintf.h"
21 #include "base/strings/utf_string_conversions.h"
22 #include "chrome/common/chrome_switches.h"
23 #include "ui/base/ui_base_paths.h"
25 namespace diagnostics {
27 // This is a minimalistic interface to wrap the platform console.
28 class SimpleConsole {
29 public:
30 enum Color {
31 DEFAULT,
32 RED,
33 GREEN,
36 virtual ~SimpleConsole() {}
38 // Init must be called before using any other method. If it returns
39 // false there will be no console output.
40 virtual bool Init() = 0;
42 // Writes a string to the console with the current color.
43 virtual bool Write(const base::string16& text) = 0;
45 // Called when the program is about to exit.
46 virtual void OnQuit() = 0;
48 // Sets the foreground text color.
49 virtual bool SetColor(Color color) = 0;
51 // Create an appropriate SimpleConsole instance. May return NULL if there is
52 // no implementation for the current platform.
53 static SimpleConsole* Create();
56 #if defined(OS_WIN)
57 namespace {
59 // Wrapper for the windows console operating in high-level IO mode.
60 class WinConsole : public SimpleConsole {
61 public:
62 // The ctor allocates a console. This avoids having to ask the user to start
63 // chrome from a command prompt.
64 WinConsole()
65 : std_out_(INVALID_HANDLE_VALUE),
66 std_in_(INVALID_HANDLE_VALUE) {
67 ::AllocConsole();
70 ~WinConsole() override { ::FreeConsole(); }
72 bool Init() override { return SetIOHandles(); }
74 bool Write(const base::string16& txt) override {
75 DWORD sz = txt.size();
76 return (TRUE == ::WriteConsoleW(std_out_, txt.c_str(), sz, &sz, NULL));
79 // Reads a string from the console. Internally it is limited to 256
80 // characters.
81 void OnQuit() override {
82 // Block here so the user can see the results.
83 SetColor(SimpleConsole::DEFAULT);
84 Write(L"Press [enter] to continue\n");
85 wchar_t buf[256];
86 DWORD read = arraysize(buf);
87 ::ReadConsoleW(std_in_, buf, read, &read, NULL);
90 // Sets the foreground and background color.
91 bool SetColor(Color color) override {
92 uint16 color_combo = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE |
93 FOREGROUND_INTENSITY;
94 switch (color) {
95 case RED:
96 color_combo = FOREGROUND_RED | FOREGROUND_INTENSITY;
97 break;
98 case GREEN:
99 color_combo = FOREGROUND_GREEN | FOREGROUND_INTENSITY;
100 break;
101 case DEFAULT:
102 break;
103 default:
104 NOTREACHED();
106 return (TRUE == ::SetConsoleTextAttribute(std_out_, color_combo));
109 private:
110 bool SetIOHandles() {
111 std_out_ = ::GetStdHandle(STD_OUTPUT_HANDLE);
112 std_in_ = ::GetStdHandle(STD_INPUT_HANDLE);
113 return ((std_out_ != INVALID_HANDLE_VALUE) &&
114 (std_in_ != INVALID_HANDLE_VALUE));
117 // The input and output handles to the screen. They seem to be
118 // implemented as pipes but they have non-documented protocol.
119 HANDLE std_out_;
120 HANDLE std_in_;
122 DISALLOW_COPY_AND_ASSIGN(WinConsole);
125 } // namespace
127 SimpleConsole* SimpleConsole::Create() { return new WinConsole(); }
129 #elif defined(OS_POSIX)
130 namespace {
132 class PosixConsole : public SimpleConsole {
133 public:
134 PosixConsole() : use_color_(false) {}
136 bool Init() override {
137 // Technically, we should also check the terminal capabilities before using
138 // color, but in practice this is unlikely to be an issue.
139 use_color_ = isatty(STDOUT_FILENO);
140 return true;
143 bool Write(const base::string16& text) override {
144 // We're assuming that the terminal is using UTF-8 encoding.
145 printf("%s", base::UTF16ToUTF8(text).c_str());
146 return true;
149 void OnQuit() override {
150 // The "press enter to continue" prompt isn't very unixy, so only do that on
151 // Windows.
154 bool SetColor(Color color) override {
155 if (!use_color_)
156 return false;
158 const char* code = "\033[m";
159 switch (color) {
160 case RED:
161 code = "\033[1;31m";
162 break;
163 case GREEN:
164 code = "\033[1;32m";
165 break;
166 case DEFAULT:
167 break;
168 default:
169 NOTREACHED();
171 printf("%s", code);
172 return true;
175 private:
176 bool use_color_;
178 DISALLOW_COPY_AND_ASSIGN(PosixConsole);
181 } // namespace
183 SimpleConsole* SimpleConsole::Create() { return new PosixConsole(); }
185 #else // !defined(OS_WIN) && !defined(OS_POSIX)
186 SimpleConsole* SimpleConsole::Create() { return NULL; }
187 #endif
189 ///////////////////////////////////////////////////////////
190 // DiagnosticsWriter
192 DiagnosticsWriter::DiagnosticsWriter(FormatType format)
193 : failures_(0), format_(format) {
194 // Only create consoles for non-log output.
195 if (format_ != LOG) {
196 console_.reset(SimpleConsole::Create());
197 console_->Init();
201 DiagnosticsWriter::~DiagnosticsWriter() {
202 if (console_.get())
203 console_->OnQuit();
206 bool DiagnosticsWriter::WriteInfoLine(const std::string& info_text) {
207 if (format_ == LOG) {
208 LOG(WARNING) << info_text;
209 return true;
210 } else {
211 if (console_.get()) {
212 console_->SetColor(SimpleConsole::DEFAULT);
213 console_->Write(base::UTF8ToUTF16(info_text + "\n"));
216 return true;
219 void DiagnosticsWriter::OnTestFinished(int index, DiagnosticsModel* model) {
220 const DiagnosticsModel::TestInfo& test_info = model->GetTest(index);
221 bool success = (DiagnosticsModel::TEST_OK == test_info.GetResult());
222 WriteResult(success,
223 test_info.GetName(),
224 test_info.GetTitle(),
225 test_info.GetOutcomeCode(),
226 test_info.GetAdditionalInfo());
229 void DiagnosticsWriter::OnAllTestsDone(DiagnosticsModel* model) {
230 WriteInfoLine(
231 base::StringPrintf("Finished %d tests.", model->GetTestRunCount()));
234 void DiagnosticsWriter::OnRecoveryFinished(int index, DiagnosticsModel* model) {
235 const DiagnosticsModel::TestInfo& test_info = model->GetTest(index);
236 WriteInfoLine("Finished Recovery for: " + test_info.GetTitle());
239 void DiagnosticsWriter::OnAllRecoveryDone(DiagnosticsModel* model) {
240 WriteInfoLine("Finished All Recovery operations.");
243 bool DiagnosticsWriter::WriteResult(bool success,
244 const std::string& id,
245 const std::string& name,
246 int outcome_code,
247 const std::string& extra) {
248 std::string result;
249 SimpleConsole::Color color;
251 if (success) {
252 result = "[PASS] ";
253 color = SimpleConsole::GREEN;
254 } else {
255 color = SimpleConsole::RED;
256 result = "[FAIL] ";
257 failures_++;
260 if (format_ != LOG) {
261 if (console_.get()) {
262 console_->SetColor(color);
263 console_->Write(base::ASCIIToUTF16(result));
265 if (format_ == MACHINE) {
266 return WriteInfoLine(base::StringPrintf(
267 "%03d %s (%s)", outcome_code, id.c_str(), extra.c_str()));
268 } else {
269 return WriteInfoLine(name + "\n " + extra + "\n");
271 } else {
272 if (!success) {
273 // For log output, we only care about the tests that failed.
274 return WriteInfoLine(base::StringPrintf("%s%03d %s (%s)",
275 result.c_str(),
276 outcome_code,
277 id.c_str(),
278 extra.c_str()));
281 return true;
284 } // namespace diagnostics