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"
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.
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();
59 // Wrapper for the windows console operating in high-level IO mode.
60 class WinConsole
: public SimpleConsole
{
62 // The ctor allocates a console. This avoids having to ask the user to start
63 // chrome from a command prompt.
65 : std_out_(INVALID_HANDLE_VALUE
),
66 std_in_(INVALID_HANDLE_VALUE
) {
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
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");
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
|
96 color_combo
= FOREGROUND_RED
| FOREGROUND_INTENSITY
;
99 color_combo
= FOREGROUND_GREEN
| FOREGROUND_INTENSITY
;
106 return (TRUE
== ::SetConsoleTextAttribute(std_out_
, color_combo
));
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.
122 DISALLOW_COPY_AND_ASSIGN(WinConsole
);
127 SimpleConsole
* SimpleConsole::Create() { return new WinConsole(); }
129 #elif defined(OS_POSIX)
132 class PosixConsole
: public SimpleConsole
{
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
);
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());
149 void OnQuit() override
{
150 // The "press enter to continue" prompt isn't very unixy, so only do that on
154 bool SetColor(Color color
) override
{
158 const char* code
= "\033[m";
178 DISALLOW_COPY_AND_ASSIGN(PosixConsole
);
183 SimpleConsole
* SimpleConsole::Create() { return new PosixConsole(); }
185 #else // !defined(OS_WIN) && !defined(OS_POSIX)
186 SimpleConsole
* SimpleConsole::Create() { return NULL
; }
189 ///////////////////////////////////////////////////////////
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());
201 DiagnosticsWriter::~DiagnosticsWriter() {
206 bool DiagnosticsWriter::WriteInfoLine(const std::string
& info_text
) {
207 if (format_
== LOG
) {
208 LOG(WARNING
) << info_text
;
211 if (console_
.get()) {
212 console_
->SetColor(SimpleConsole::DEFAULT
);
213 console_
->Write(base::UTF8ToUTF16(info_text
+ "\n"));
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());
224 test_info
.GetTitle(),
225 test_info
.GetOutcomeCode(),
226 test_info
.GetAdditionalInfo());
229 void DiagnosticsWriter::OnAllTestsDone(DiagnosticsModel
* model
) {
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
,
247 const std::string
& extra
) {
249 SimpleConsole::Color color
;
253 color
= SimpleConsole::GREEN
;
255 color
= SimpleConsole::RED
;
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()));
269 return WriteInfoLine(name
+ "\n " + extra
+ "\n");
273 // For log output, we only care about the tests that failed.
274 return WriteInfoLine(base::StringPrintf("%s%03d %s (%s)",
284 } // namespace diagnostics