[inspector] fix timestamp formatting with non C locales
If current locale has "," as decimal separator then message for consoleAPICalled will be corrupted. BUG=chromium:653424 R=dgozman@chromium.org Review-Url: https://codereview.chromium.org/2410933002 Cr-Commit-Position: refs/heads/master@{#40190}
This commit is contained in:
parent
d4c4618174
commit
dde5ef75cb
@ -8,8 +8,10 @@
|
||||
#include <cctype>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <iomanip>
|
||||
#include <limits>
|
||||
#include <locale>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
#include "src/base/platform/platform.h"
|
||||
@ -381,26 +383,19 @@ String16 String16::fromInteger(size_t number) {
|
||||
|
||||
// static
|
||||
String16 String16::fromDouble(double number) {
|
||||
const size_t kBufferSize = 100;
|
||||
char buffer[kBufferSize];
|
||||
v8::base::OS::SNPrintF(buffer, kBufferSize, "%f", number);
|
||||
return String16(buffer);
|
||||
std::ostringstream s;
|
||||
s.imbue(std::locale("C"));
|
||||
s << std::fixed << std::setprecision(std::numeric_limits<double>::digits10)
|
||||
<< number;
|
||||
return String16(s.str().c_str());
|
||||
}
|
||||
|
||||
// static
|
||||
String16 String16::fromDoublePrecision3(double number) {
|
||||
const size_t kBufferSize = 100;
|
||||
char buffer[kBufferSize];
|
||||
v8::base::OS::SNPrintF(buffer, kBufferSize, "%.3g", number);
|
||||
return String16(buffer);
|
||||
}
|
||||
|
||||
// static
|
||||
String16 String16::fromDoublePrecision6(double number) {
|
||||
const size_t kBufferSize = 100;
|
||||
char buffer[kBufferSize];
|
||||
v8::base::OS::SNPrintF(buffer, kBufferSize, "%.6g", number);
|
||||
return String16(buffer);
|
||||
String16 String16::fromDouble(double number, int precision) {
|
||||
std::ostringstream s;
|
||||
s.imbue(std::locale("C"));
|
||||
s << std::fixed << std::setprecision(precision) << number;
|
||||
return String16(s.str().c_str());
|
||||
}
|
||||
|
||||
int String16::toInteger(bool* ok) const {
|
||||
|
@ -35,8 +35,7 @@ class String16 {
|
||||
static String16 fromInteger(int);
|
||||
static String16 fromInteger(size_t);
|
||||
static String16 fromDouble(double);
|
||||
static String16 fromDoublePrecision3(double);
|
||||
static String16 fromDoublePrecision6(double);
|
||||
static String16 fromDouble(double, int precision);
|
||||
|
||||
int toInteger(bool* ok = nullptr) const;
|
||||
String16 stripWhiteSpace() const;
|
||||
|
@ -93,8 +93,8 @@ class V8ValueStringBuilder {
|
||||
if (value->IsSymbolObject())
|
||||
return append(v8::Local<v8::SymbolObject>::Cast(value)->ValueOf());
|
||||
if (value->IsNumberObject()) {
|
||||
m_builder.append(String16::fromDoublePrecision6(
|
||||
v8::Local<v8::NumberObject>::Cast(value)->ValueOf()));
|
||||
m_builder.append(String16::fromDouble(
|
||||
v8::Local<v8::NumberObject>::Cast(value)->ValueOf(), 6));
|
||||
return true;
|
||||
}
|
||||
if (value->IsBooleanObject()) {
|
||||
|
@ -431,7 +431,7 @@ static void timeEndFunction(const v8::FunctionCallbackInfo<v8::Value>& info,
|
||||
double elapsed = client->currentTimeMS() -
|
||||
helper.getDoubleFromMap(timeMap, protocolTitle, 0.0);
|
||||
String16 message =
|
||||
protocolTitle + ": " + String16::fromDoublePrecision3(elapsed) + "ms";
|
||||
protocolTitle + ": " + String16::fromDouble(elapsed, 3) + "ms";
|
||||
helper.reportCallWithArgument(ConsoleAPIType::kTimeEnd, message);
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,8 @@
|
||||
#include <unistd.h> // NOLINT
|
||||
#endif // !defined(_WIN32) && !defined(_WIN64)
|
||||
|
||||
#include <locale.h>
|
||||
|
||||
#include "include/libplatform/libplatform.h"
|
||||
#include "include/v8.h"
|
||||
|
||||
@ -29,7 +31,9 @@ class UtilsExtension : public v8::Extension {
|
||||
public:
|
||||
UtilsExtension()
|
||||
: v8::Extension("v8_inspector/utils",
|
||||
"native function print(); native function quit();") {}
|
||||
"native function print();"
|
||||
"native function quit();"
|
||||
"native function setlocale();") {}
|
||||
virtual v8::Local<v8::FunctionTemplate> GetNativeFunctionTemplate(
|
||||
v8::Isolate* isolate, v8::Local<v8::String> name) {
|
||||
v8::Local<v8::Context> context = isolate->GetCurrentContext();
|
||||
@ -44,6 +48,12 @@ class UtilsExtension : public v8::Extension {
|
||||
.ToLocalChecked())
|
||||
.FromJust()) {
|
||||
return v8::FunctionTemplate::New(isolate, UtilsExtension::Quit);
|
||||
} else if (name->Equals(context,
|
||||
v8::String::NewFromUtf8(isolate, "setlocale",
|
||||
v8::NewStringType::kNormal)
|
||||
.ToLocalChecked())
|
||||
.FromJust()) {
|
||||
return v8::FunctionTemplate::New(isolate, UtilsExtension::SetLocale);
|
||||
}
|
||||
return v8::Local<v8::FunctionTemplate>();
|
||||
}
|
||||
@ -83,6 +93,15 @@ class UtilsExtension : public v8::Extension {
|
||||
}
|
||||
|
||||
static void Quit(const v8::FunctionCallbackInfo<v8::Value>& args) { Exit(); }
|
||||
|
||||
static void SetLocale(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
if (args.Length() != 1 || !args[0]->IsString()) {
|
||||
fprintf(stderr, "Internal error: setlocale get one string argument.");
|
||||
Exit();
|
||||
}
|
||||
v8::String::Utf8Value str(args[0]);
|
||||
setlocale(LC_NUMERIC, *str);
|
||||
}
|
||||
};
|
||||
|
||||
class SetTimeoutTask : public TaskRunner::Task {
|
||||
|
@ -0,0 +1,138 @@
|
||||
Running test: consoleLogWithDefaultLocale
|
||||
{
|
||||
method : Runtime.consoleAPICalled
|
||||
params : {
|
||||
args : [
|
||||
[0] : {
|
||||
description : 239
|
||||
type : number
|
||||
value : 239
|
||||
}
|
||||
]
|
||||
executionContextId : <executionContextId>
|
||||
stackTrace : {
|
||||
callFrames : [
|
||||
[0] : {
|
||||
columnNumber : 8
|
||||
functionName :
|
||||
lineNumber : 0
|
||||
scriptId : <scriptId>
|
||||
url :
|
||||
}
|
||||
]
|
||||
}
|
||||
timestamp : <timestamp>
|
||||
type : log
|
||||
}
|
||||
}
|
||||
|
||||
Running test: consoleTimeWithCommaAsSeparator
|
||||
set locale to fr_CA.UTF-8 (has comma as separator)
|
||||
{
|
||||
method : Runtime.consoleAPICalled
|
||||
params : {
|
||||
args : [
|
||||
[0] : {
|
||||
type : string
|
||||
value : a: x.xms
|
||||
}
|
||||
]
|
||||
executionContextId : <executionContextId>
|
||||
stackTrace : {
|
||||
callFrames : [
|
||||
[0] : {
|
||||
columnNumber : 27
|
||||
functionName :
|
||||
lineNumber : 0
|
||||
scriptId : <scriptId>
|
||||
url :
|
||||
}
|
||||
]
|
||||
}
|
||||
timestamp : <timestamp>
|
||||
type : debug
|
||||
}
|
||||
}
|
||||
|
||||
Running test: consoleLogWithCommaAsSeparator
|
||||
set locale to fr_CA.UTF-8 (has comma as separator)
|
||||
{
|
||||
method : Runtime.consoleAPICalled
|
||||
params : {
|
||||
args : [
|
||||
[0] : {
|
||||
description : 239
|
||||
type : number
|
||||
value : 239
|
||||
}
|
||||
]
|
||||
executionContextId : <executionContextId>
|
||||
stackTrace : {
|
||||
callFrames : [
|
||||
[0] : {
|
||||
columnNumber : 8
|
||||
functionName :
|
||||
lineNumber : 0
|
||||
scriptId : <scriptId>
|
||||
url :
|
||||
}
|
||||
]
|
||||
}
|
||||
timestamp : <timestamp>
|
||||
type : log
|
||||
}
|
||||
}
|
||||
|
||||
Running test: consoleTimeWithCommaAfterConsoleLog
|
||||
set locale to fr_CA.UTF-8 (has comma as separator)
|
||||
{
|
||||
method : Runtime.consoleAPICalled
|
||||
params : {
|
||||
args : [
|
||||
[0] : {
|
||||
description : 239
|
||||
type : number
|
||||
value : 239
|
||||
}
|
||||
]
|
||||
executionContextId : <executionContextId>
|
||||
stackTrace : {
|
||||
callFrames : [
|
||||
[0] : {
|
||||
columnNumber : 8
|
||||
functionName :
|
||||
lineNumber : 0
|
||||
scriptId : <scriptId>
|
||||
url :
|
||||
}
|
||||
]
|
||||
}
|
||||
timestamp : <timestamp>
|
||||
type : log
|
||||
}
|
||||
}
|
||||
{
|
||||
method : Runtime.consoleAPICalled
|
||||
params : {
|
||||
args : [
|
||||
[0] : {
|
||||
type : string
|
||||
value : a: x.xms
|
||||
}
|
||||
]
|
||||
executionContextId : <executionContextId>
|
||||
stackTrace : {
|
||||
callFrames : [
|
||||
[0] : {
|
||||
columnNumber : 27
|
||||
functionName :
|
||||
lineNumber : 0
|
||||
scriptId : <scriptId>
|
||||
url :
|
||||
}
|
||||
]
|
||||
}
|
||||
timestamp : <timestamp>
|
||||
type : debug
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
// Copyright 2016 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
Protocol.Runtime.enable();
|
||||
|
||||
Protocol.Runtime.onConsoleAPICalled(dumpConsoleApiCalled);
|
||||
|
||||
InspectorTest.runTestSuite([
|
||||
function consoleLogWithDefaultLocale(next) {
|
||||
Protocol.Runtime.evaluate({ expression: "console.log(239) "}).then(next);
|
||||
},
|
||||
|
||||
function consoleTimeWithCommaAsSeparator(next) {
|
||||
InspectorTest.log("set locale to fr_CA.UTF-8 (has comma as separator)");
|
||||
setlocale("fr_CA.UTF-8");
|
||||
Protocol.Runtime.evaluate({ expression: "console.time(\"a\"); console.timeEnd(\"a\")"}).then(next);
|
||||
},
|
||||
|
||||
function consoleLogWithCommaAsSeparator(next) {
|
||||
InspectorTest.log("set locale to fr_CA.UTF-8 (has comma as separator)");
|
||||
setlocale("fr_CA.UTF-8");
|
||||
Protocol.Runtime.evaluate({ expression: "console.log(239) "}).then(next);
|
||||
},
|
||||
|
||||
function consoleTimeWithCommaAfterConsoleLog(next) {
|
||||
InspectorTest.log("set locale to fr_CA.UTF-8 (has comma as separator)");
|
||||
setlocale("fr_CA.UTF-8");
|
||||
Protocol.Runtime.evaluate({ expression: "console.log(239) "})
|
||||
.then(() => Protocol.Runtime.evaluate({ expression: "console.time(\"a\"); console.timeEnd(\"a\")"}))
|
||||
.then(next);
|
||||
}
|
||||
]);
|
||||
|
||||
function dumpConsoleApiCalled(message) {
|
||||
var firstArg = message.params.args[0];
|
||||
if (firstArg.type === "string")
|
||||
firstArg.value = firstArg.value.replace(/[0-9]+/g, "x");
|
||||
InspectorTest.logMessage(message);
|
||||
}
|
Loading…
Reference in New Issue
Block a user