move config pb <> txt into src/trace_config_utils
I'm extracting a library that can deal with txt<>pb conversion
for the TraceConfig. I'm planning to expose this in wasm and use
it in the Record UI, to get rid of a lot of hacks that try to
replicate the same logic in typescript.
Bug: 377651301
Change-Id: Ia9771603b8fd875f3fe9417f0d79b27ded58d826
diff --git a/Android.bp b/Android.bp
index 5d85a3d..d6e26f4 100644
--- a/Android.bp
+++ b/Android.bp
@@ -1233,11 +1233,11 @@
":perfetto_src_ipc_client",
":perfetto_src_ipc_common",
":perfetto_src_perfetto_cmd_bugreport_path",
- ":perfetto_src_perfetto_cmd_pbtxt_to_pb",
":perfetto_src_perfetto_cmd_perfetto_cmd",
":perfetto_src_perfetto_cmd_protos_cpp_gen",
":perfetto_src_perfetto_cmd_trigger_producer",
":perfetto_src_protozero_protozero",
+ ":perfetto_src_trace_config_utils_txt_to_pb",
":perfetto_src_tracing_common",
":perfetto_src_tracing_core_core",
":perfetto_src_tracing_ipc_common",
@@ -1303,8 +1303,8 @@
"perfetto_protos_perfetto_trace_track_event_zero_gen_headers",
"perfetto_protos_perfetto_trace_translation_zero_gen_headers",
"perfetto_src_base_version_gen_h",
- "perfetto_src_perfetto_cmd_gen_cc_config_descriptor",
"perfetto_src_perfetto_cmd_protos_cpp_gen_headers",
+ "perfetto_src_trace_config_utils_gen_cc_config_descriptor",
],
defaults: [
"perfetto_defaults",
@@ -11218,29 +11218,6 @@
name: "perfetto_src_perfetto_cmd_bugreport_path",
}
-// GN: //src/perfetto_cmd:gen_cc_config_descriptor
-genrule {
- name: "perfetto_src_perfetto_cmd_gen_cc_config_descriptor",
- srcs: [
- ":perfetto_protos_perfetto_config_descriptor",
- ],
- cmd: "$(location tools/gen_cc_proto_descriptor.py) --gen_dir=$(genDir) --cpp_out=$(out) $(in)",
- out: [
- "src/perfetto_cmd/config.descriptor.h",
- ],
- tool_files: [
- "tools/gen_cc_proto_descriptor.py",
- ],
-}
-
-// GN: //src/perfetto_cmd:pbtxt_to_pb
-filegroup {
- name: "perfetto_src_perfetto_cmd_pbtxt_to_pb",
- srcs: [
- "src/perfetto_cmd/pbtxt_to_pb.cc",
- ],
-}
-
// GN: //src/perfetto_cmd:perfetto_cmd
filegroup {
name: "perfetto_src_perfetto_cmd_perfetto_cmd",
@@ -11318,7 +11295,6 @@
srcs: [
"src/perfetto_cmd/config_unittest.cc",
"src/perfetto_cmd/packet_writer_unittest.cc",
- "src/perfetto_cmd/pbtxt_to_pb_unittest.cc",
],
}
@@ -12264,6 +12240,46 @@
],
}
+// GN: //src/trace_config_utils:gen_cc_config_descriptor
+genrule {
+ name: "perfetto_src_trace_config_utils_gen_cc_config_descriptor",
+ srcs: [
+ ":perfetto_protos_perfetto_config_descriptor",
+ ],
+ cmd: "$(location tools/gen_cc_proto_descriptor.py) --gen_dir=$(genDir) --cpp_out=$(out) $(in)",
+ out: [
+ "src/trace_config_utils/config.descriptor.h",
+ ],
+ tool_files: [
+ "tools/gen_cc_proto_descriptor.py",
+ ],
+}
+
+// GN: //src/trace_config_utils:pb_to_txt
+filegroup {
+ name: "perfetto_src_trace_config_utils_pb_to_txt",
+ srcs: [
+ "src/trace_config_utils/pb_to_txt.cc",
+ ],
+}
+
+// GN: //src/trace_config_utils:txt_to_pb
+filegroup {
+ name: "perfetto_src_trace_config_utils_txt_to_pb",
+ srcs: [
+ "src/trace_config_utils/txt_to_pb.cc",
+ ],
+}
+
+// GN: //src/trace_config_utils:unittests
+filegroup {
+ name: "perfetto_src_trace_config_utils_unittests",
+ srcs: [
+ "src/trace_config_utils/pb_to_txt_unittest.cc",
+ "src/trace_config_utils/txt_to_pb_unittest.cc",
+ ],
+}
+
// GN: //src/trace_processor/containers:containers
filegroup {
name: "perfetto_src_trace_processor_containers_containers",
@@ -15593,7 +15609,6 @@
":perfetto_src_kernel_utils_syscall_table",
":perfetto_src_kernel_utils_unittests",
":perfetto_src_perfetto_cmd_bugreport_path",
- ":perfetto_src_perfetto_cmd_pbtxt_to_pb",
":perfetto_src_perfetto_cmd_perfetto_cmd",
":perfetto_src_perfetto_cmd_protos_cpp_gen",
":perfetto_src_perfetto_cmd_trigger_producer",
@@ -15645,6 +15660,9 @@
":perfetto_src_protozero_unittests",
":perfetto_src_shared_lib_intern_map",
":perfetto_src_shared_lib_unittests",
+ ":perfetto_src_trace_config_utils_pb_to_txt",
+ ":perfetto_src_trace_config_utils_txt_to_pb",
+ ":perfetto_src_trace_config_utils_unittests",
":perfetto_src_trace_processor_containers_containers",
":perfetto_src_trace_processor_containers_unittests",
":perfetto_src_trace_processor_db_column_column",
@@ -15963,7 +15981,6 @@
"perfetto_src_base_version_gen_h",
"perfetto_src_ipc_test_messages_cpp_gen_headers",
"perfetto_src_ipc_test_messages_ipc_gen_headers",
- "perfetto_src_perfetto_cmd_gen_cc_config_descriptor",
"perfetto_src_perfetto_cmd_protos_cpp_gen_headers",
"perfetto_src_protozero_testing_messages_cpp_gen_headers",
"perfetto_src_protozero_testing_messages_lite_gen_headers",
@@ -15974,6 +15991,7 @@
"perfetto_src_protozero_testing_messages_subpackage_lite_gen_headers",
"perfetto_src_protozero_testing_messages_subpackage_zero_gen_headers",
"perfetto_src_protozero_testing_messages_zero_gen_headers",
+ "perfetto_src_trace_config_utils_gen_cc_config_descriptor",
"perfetto_src_trace_processor_gen_cc_test_messages_descriptor",
"perfetto_src_trace_processor_importers_proto_gen_cc_android_track_event_descriptor",
"perfetto_src_trace_processor_importers_proto_gen_cc_chrome_track_event_descriptor",
diff --git a/BUILD b/BUILD
index c1ffd78..fdb6c73 100644
--- a/BUILD
+++ b/BUILD
@@ -266,13 +266,13 @@
":include_perfetto_base_base",
":include_perfetto_public_abi_base",
":include_perfetto_public_base",
- ":src_perfetto_cmd_pbtxt_to_pb",
":src_protozero_filtering_bytecode_common",
":src_protozero_filtering_bytecode_generator",
":src_protozero_filtering_bytecode_parser",
":src_protozero_filtering_filter_util",
":src_protozero_filtering_message_filter",
":src_protozero_filtering_string_filter",
+ ":src_trace_config_utils_txt_to_pb",
"src/tools/proto_filter/proto_filter.cc",
],
deps = [
@@ -293,7 +293,7 @@
":protozero",
":src_base_base",
":src_base_version",
- ":src_perfetto_cmd_gen_cc_config_descriptor",
+ ":src_trace_config_utils_gen_cc_config_descriptor",
] + PERFETTO_CONFIG.deps.protobuf_full,
)
@@ -1412,26 +1412,6 @@
],
)
-# GN target: //src/perfetto_cmd:gen_cc_config_descriptor
-perfetto_cc_proto_descriptor(
- name = "src_perfetto_cmd_gen_cc_config_descriptor",
- deps = [
- ":protos_perfetto_config_descriptor",
- ],
- outs = [
- "src/perfetto_cmd/config.descriptor.h",
- ],
-)
-
-# GN target: //src/perfetto_cmd:pbtxt_to_pb
-perfetto_filegroup(
- name = "src_perfetto_cmd_pbtxt_to_pb",
- srcs = [
- "src/perfetto_cmd/pbtxt_to_pb.cc",
- "src/perfetto_cmd/pbtxt_to_pb.h",
- ],
-)
-
# GN target: //src/perfetto_cmd:perfetto_cmd
perfetto_filegroup(
name = "src_perfetto_cmd_perfetto_cmd",
@@ -1582,6 +1562,26 @@
],
)
+# GN target: //src/trace_config_utils:gen_cc_config_descriptor
+perfetto_cc_proto_descriptor(
+ name = "src_trace_config_utils_gen_cc_config_descriptor",
+ deps = [
+ ":protos_perfetto_config_descriptor",
+ ],
+ outs = [
+ "src/trace_config_utils/config.descriptor.h",
+ ],
+)
+
+# GN target: //src/trace_config_utils:txt_to_pb
+perfetto_filegroup(
+ name = "src_trace_config_utils_txt_to_pb",
+ srcs = [
+ "src/trace_config_utils/txt_to_pb.cc",
+ "src/trace_config_utils/txt_to_pb.h",
+ ],
+)
+
# GN target: //src/trace_processor/containers:containers
perfetto_cc_library(
name = "src_trace_processor_containers_containers",
@@ -6484,9 +6484,9 @@
":src_android_stats_android_stats",
":src_android_stats_perfetto_atoms",
":src_perfetto_cmd_bugreport_path",
- ":src_perfetto_cmd_pbtxt_to_pb",
":src_perfetto_cmd_perfetto_cmd",
":src_perfetto_cmd_trigger_producer",
+ ":src_trace_config_utils_txt_to_pb",
":src_tracing_common",
":src_tracing_core_core",
":src_tracing_ipc_common",
@@ -6554,8 +6554,8 @@
":protozero",
":src_base_base",
":src_base_version",
- ":src_perfetto_cmd_gen_cc_config_descriptor",
":src_perfetto_cmd_protos_cpp",
+ ":src_trace_config_utils_gen_cc_config_descriptor",
],
)
diff --git a/BUILD.gn b/BUILD.gn
index 7dd9d31..b495c20 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -57,7 +57,10 @@
}
if (enable_perfetto_traceconv) {
- all_targets += [ "src/traceconv" ]
+ all_targets += [
+ "src/traceconv",
+ "src/trace_config_utils",
+ ]
if (is_cross_compiling) {
# In many cross-compilation scenarios (typically Android) developers expect
# the host version of traceconv to be available somewhere in out/, so
@@ -66,7 +69,10 @@
# cc_binary_host("traceconv") target in Android.bp.
# Note that when cross-compiling the host executable will be available in
# out/xxx/gcc_like_host/traceconv NOT just out/xxx/traceconv.
- all_targets += [ "src/traceconv($host_toolchain)" ]
+ all_targets += [
+ "src/traceconv($host_toolchain)",
+ "src/trace_config_utils($host_toolchain)",
+ ]
}
}
diff --git a/gn/perfetto_unittests.gni b/gn/perfetto_unittests.gni
index f54ef7a..d1590c6 100644
--- a/gn/perfetto_unittests.gni
+++ b/gn/perfetto_unittests.gni
@@ -75,6 +75,7 @@
if (enable_perfetto_trace_processor) {
perfetto_unittests_targets += [ "src/trace_processor:unittests" ]
+ perfetto_unittests_targets += [ "src/trace_config_utils:unittests" ]
if (enable_perfetto_trace_processor_sqlite) {
perfetto_unittests_targets += [ "src/trace_processor/metrics:unittests" ]
diff --git a/src/perfetto_cmd/BUILD.gn b/src/perfetto_cmd/BUILD.gn
index 4cfe0ea..0edf72a 100644
--- a/src/perfetto_cmd/BUILD.gn
+++ b/src/perfetto_cmd/BUILD.gn
@@ -13,7 +13,6 @@
# limitations under the License.
import("../../gn/perfetto.gni")
-import("../../gn/perfetto_cc_proto_descriptor.gni")
import("../../gn/proto_library.gni")
import("../../gn/test.gni")
@@ -50,8 +49,6 @@
]
deps = [
":bugreport_path",
- ":gen_cc_config_descriptor",
- ":pbtxt_to_pb",
":trigger_producer",
"../../gn:default_deps",
"../../protos/perfetto/common:cpp",
@@ -62,6 +59,7 @@
"../base",
"../base:version",
"../protozero",
+ "../trace_config_utils:txt_to_pb",
"../tracing/ipc/consumer",
]
sources = [
@@ -72,6 +70,8 @@
"perfetto_cmd.cc",
"perfetto_cmd.h",
]
+ assert_no_deps = [ "../trace_processor/*" ]
+
if (is_android) {
deps += [ "../android_internal:lazy_library_loader" ]
sources += [ "perfetto_cmd_android.cc" ]
@@ -87,25 +87,6 @@
]
}
-source_set("pbtxt_to_pb") {
- deps = [
- ":gen_cc_config_descriptor",
- "../../gn:default_deps",
- "../../protos/perfetto/common:cpp",
- "../base",
- "../protozero",
- ]
- sources = [
- "pbtxt_to_pb.cc",
- "pbtxt_to_pb.h",
- ]
-}
-
-perfetto_cc_proto_descriptor("gen_cc_config_descriptor") {
- descriptor_name = "config.descriptor"
- descriptor_target = "../../protos/perfetto/config:descriptor"
-}
-
source_set("trigger_perfetto_cmd") {
public_deps = [
":protos_cpp",
@@ -143,7 +124,6 @@
testonly = true
public_deps = []
deps = [
- ":pbtxt_to_pb",
":perfetto_cmd",
"../../gn:default_deps",
"../../gn:gtest_and_gmock",
@@ -157,6 +137,5 @@
sources = [
"config_unittest.cc",
"packet_writer_unittest.cc",
- "pbtxt_to_pb_unittest.cc",
]
}
diff --git a/src/perfetto_cmd/pbtxt_to_pb.h b/src/perfetto_cmd/pbtxt_to_pb.h
deleted file mode 100644
index 6b9db32..0000000
--- a/src/perfetto_cmd/pbtxt_to_pb.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef SRC_PERFETTO_CMD_PBTXT_TO_PB_H_
-#define SRC_PERFETTO_CMD_PBTXT_TO_PB_H_
-
-#include <stdint.h>
-
-#include <string>
-#include <vector>
-
-namespace perfetto {
-
-class ErrorReporter {
- public:
- ErrorReporter();
- virtual ~ErrorReporter();
- virtual void AddError(size_t row,
- size_t column,
- size_t size,
- const std::string& message) = 0;
-};
-
-std::vector<uint8_t> PbtxtToPb(const std::string& input,
- ErrorReporter* reporter);
-
-} // namespace perfetto
-
-#endif // SRC_PERFETTO_CMD_PBTXT_TO_PB_H_
diff --git a/src/perfetto_cmd/perfetto_cmd.cc b/src/perfetto_cmd/perfetto_cmd.cc
index 31da575..74f4b64 100644
--- a/src/perfetto_cmd/perfetto_cmd.cc
+++ b/src/perfetto_cmd/perfetto_cmd.cc
@@ -77,8 +77,8 @@
#include "src/perfetto_cmd/bugreport_path.h"
#include "src/perfetto_cmd/config.h"
#include "src/perfetto_cmd/packet_writer.h"
-#include "src/perfetto_cmd/pbtxt_to_pb.h"
#include "src/perfetto_cmd/trigger_producer.h"
+#include "src/trace_config_utils/txt_to_pb.h"
#include "protos/perfetto/common/ftrace_descriptor.gen.h"
#include "protos/perfetto/common/tracing_service_state.gen.h"
@@ -100,60 +100,15 @@
const uint32_t kOnTraceDataTimeoutMs = 3000;
const uint32_t kCloneTimeoutMs = 30000;
-class LoggingErrorReporter : public ErrorReporter {
- public:
- LoggingErrorReporter(std::string file_name, const char* config)
- : file_name_(std::move(file_name)), config_(config) {}
-
- void AddError(size_t row,
- size_t column,
- size_t length,
- const std::string& message) override {
- parsed_successfully_ = false;
- std::string line = ExtractLine(row - 1).ToStdString();
- if (!line.empty() && line[line.length() - 1] == '\n') {
- line.erase(line.length() - 1);
- }
-
- std::string guide(column + length, ' ');
- for (size_t i = column; i < column + length; i++) {
- guide[i - 1] = i == column ? '^' : '~';
- }
- fprintf(stderr, "%s:%zu:%zu error: %s\n", file_name_.c_str(), row, column,
- message.c_str());
- fprintf(stderr, "%s\n", line.c_str());
- fprintf(stderr, "%s\n", guide.c_str());
- }
-
- bool Success() const { return parsed_successfully_; }
-
- private:
- base::StringView ExtractLine(size_t line) {
- const char* start = config_;
- const char* end = config_;
-
- for (size_t i = 0; i < line + 1; i++) {
- start = end;
- char c;
- while ((c = *end++) && c != '\n')
- ;
- }
- return base::StringView(start, static_cast<size_t>(end - start));
- }
-
- bool parsed_successfully_ = true;
- std::string file_name_;
- const char* config_;
-};
-
bool ParseTraceConfigPbtxt(const std::string& file_name,
const std::string& pbtxt,
TraceConfig* config) {
- LoggingErrorReporter reporter(file_name, pbtxt.c_str());
- std::vector<uint8_t> buf = PbtxtToPb(pbtxt, &reporter);
- if (!reporter.Success())
+ auto res = TraceConfigTxtToPb(pbtxt, file_name);
+ if (!res.ok()) {
+ fprintf(stderr, "%s\n", res.status().c_message());
return false;
- if (!config->ParseFromArray(buf.data(), buf.size()))
+ }
+ if (!config->ParseFromArray(res->data(), res->size()))
return false;
return true;
}
diff --git a/src/tools/proto_filter/BUILD.gn b/src/tools/proto_filter/BUILD.gn
index a9bb97a..e2e1d16 100644
--- a/src/tools/proto_filter/BUILD.gn
+++ b/src/tools/proto_filter/BUILD.gn
@@ -22,11 +22,11 @@
"../../../protos/perfetto/config:cpp",
"../../base",
"../../base:version",
- "../../perfetto_cmd:pbtxt_to_pb",
"../../protozero",
"../../protozero/filtering:bytecode_generator",
"../../protozero/filtering:filter_util",
"../../protozero/filtering:message_filter",
+ "../../trace_config_utils:txt_to_pb",
]
sources = [ "proto_filter.cc" ]
}
diff --git a/src/tools/proto_filter/proto_filter.cc b/src/tools/proto_filter/proto_filter.cc
index b3a9572..3994896 100644
--- a/src/tools/proto_filter/proto_filter.cc
+++ b/src/tools/proto_filter/proto_filter.cc
@@ -20,9 +20,9 @@
#include "perfetto/ext/base/string_utils.h"
#include "perfetto/ext/base/version.h"
#include "protos/perfetto/config/trace_config.gen.h"
-#include "src/perfetto_cmd/pbtxt_to_pb.h"
#include "src/protozero/filtering/filter_util.h"
#include "src/protozero/filtering/message_filter.h"
+#include "src/trace_config_utils/txt_to_pb.h"
namespace perfetto {
namespace proto_filter {
@@ -81,52 +81,6 @@
-f /tmp/bytecode
)";
-class LoggingErrorReporter : public ErrorReporter {
- public:
- LoggingErrorReporter(std::string file_name, const char* config)
- : file_name_(file_name), config_(config) {}
-
- void AddError(size_t row,
- size_t column,
- size_t length,
- const std::string& message) override {
- parsed_successfully_ = false;
- std::string line = ExtractLine(row - 1).ToStdString();
- if (!line.empty() && line[line.length() - 1] == '\n') {
- line.erase(line.length() - 1);
- }
-
- std::string guide(column + length, ' ');
- for (size_t i = column; i < column + length; i++) {
- guide[i - 1] = i == column ? '^' : '~';
- }
- fprintf(stderr, "%s:%zu:%zu error: %s\n", file_name_.c_str(), row, column,
- message.c_str());
- fprintf(stderr, "%s\n", line.c_str());
- fprintf(stderr, "%s\n", guide.c_str());
- }
-
- bool Success() const { return parsed_successfully_; }
-
- private:
- base::StringView ExtractLine(size_t line) {
- const char* start = config_;
- const char* end = config_;
-
- for (size_t i = 0; i < line + 1; i++) {
- start = end;
- char c;
- while ((c = *end++) && c != '\n')
- ;
- }
- return base::StringView(start, static_cast<size_t>(end - start));
- }
-
- bool parsed_successfully_ = true;
- std::string file_name_;
- const char* config_;
-};
-
using TraceFilter = protos::gen::TraceConfig::TraceFilter;
std::optional<protozero::StringFilter::Policy> ConvertPolicy(
TraceFilter::StringFilterPolicy policy) {
@@ -309,12 +263,13 @@
PERFETTO_ELOG("Could not open config file %s", config_in.c_str());
return 1;
}
- LoggingErrorReporter reporter(config_in, config_data.c_str());
- auto config_bytes = PbtxtToPb(config_data, &reporter);
- if (!reporter.Success()) {
+ auto res = TraceConfigTxtToPb(config_data, config_in);
+ if (!res.ok()) {
+ fprintf(stderr, "%s\n", res.status().c_message());
return 1;
}
+ std::vector<uint8_t>& config_bytes = res.value();
protos::gen::TraceConfig config;
config.ParseFromArray(config_bytes.data(), config_bytes.size());
diff --git a/src/trace_config_utils/BUILD.gn b/src/trace_config_utils/BUILD.gn
new file mode 100644
index 0000000..586b2de
--- /dev/null
+++ b/src/trace_config_utils/BUILD.gn
@@ -0,0 +1,99 @@
+# Copyright (C) 2024 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import("../../gn/perfetto.gni")
+import("../../gn/perfetto_cc_proto_descriptor.gni")
+import("../../gn/test.gni")
+import("../../gn/wasm.gni")
+
+source_set("txt_to_pb") {
+ deps = [
+ ":gen_cc_config_descriptor",
+ "../../gn:default_deps",
+ "../../protos/perfetto/common:cpp",
+ "../../protos/perfetto/config:cpp",
+ "../base",
+ "../protozero",
+ ]
+ sources = [
+ "txt_to_pb.cc",
+ "txt_to_pb.h",
+ ]
+}
+
+source_set("pb_to_txt") {
+ deps = [
+ ":gen_cc_config_descriptor",
+ "../../gn:default_deps",
+ "../base",
+ "../protozero",
+ "../trace_processor/util:descriptors",
+ "../trace_processor/util:protozero_to_text",
+ ]
+ sources = [
+ "pb_to_txt.cc",
+ "pb_to_txt.h",
+ ]
+}
+
+source_set("main") {
+ deps = [
+ ":pb_to_txt",
+ ":txt_to_pb",
+ "../../gn:default_deps",
+ "../../include/perfetto/ext/base:base",
+ ]
+ sources = [ "main.cc" ]
+}
+
+perfetto_cc_proto_descriptor("gen_cc_config_descriptor") {
+ descriptor_name = "config.descriptor"
+ descriptor_target = "../../protos/perfetto/config:descriptor"
+}
+
+executable("trace_config_utils") {
+ testonly = true
+ deps = [
+ ":main",
+ "../../gn:default_deps",
+ ]
+}
+
+if (enable_perfetto_ui) {
+ wasm_lib("trace_config_utils_wasm") {
+ name = "trace_config_utils"
+ deps = [
+ ":main",
+ "../../gn:default_deps",
+ ]
+ }
+}
+
+perfetto_unittest_source_set("unittests") {
+ testonly = true
+ deps = [
+ ":pb_to_txt",
+ ":txt_to_pb",
+ "../../gn:default_deps",
+ "../../gn:gtest_and_gmock",
+ "../../protos/perfetto/config:cpp",
+ "../../protos/perfetto/config/ftrace:cpp",
+ "../../protos/perfetto/trace:cpp",
+ "../base",
+ ]
+ sources = [
+ "pb_to_txt_unittest.cc",
+ "txt_to_pb_unittest.cc",
+ ]
+}
diff --git a/src/trace_config_utils/main.cc b/src/trace_config_utils/main.cc
new file mode 100644
index 0000000..95e641e
--- /dev/null
+++ b/src/trace_config_utils/main.cc
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "perfetto/ext/base/file_utils.h"
+#include "src/trace_config_utils/pb_to_txt.h"
+#include "src/trace_config_utils/txt_to_pb.h"
+
+namespace {
+void PrintUsage(const char* argv0) {
+ printf(R"(
+Converts a TraceConfig from pbtxt to proto-encoded bytes and viceversa
+
+Usage: %s txt_to_pb | pb_to_txt < in > out
+)",
+ argv0);
+}
+
+} // namespace
+
+int main(int argc, char** argv) {
+ using namespace ::perfetto;
+
+ if (argc < 2) {
+ PrintUsage(argv[0]);
+ return 1;
+ }
+
+ const char* cmd = argv[1];
+ std::string in_data;
+ if (argc == 2) {
+ base::ReadFileStream(stdin, &in_data);
+ } else {
+ bool ok = base::ReadFile(argv[2], &in_data);
+ if (!ok) {
+ printf("Failed to open input file %s\n", argv[2]);
+ return 1;
+ }
+ }
+
+ if (strcmp(cmd, "txt_to_pb") == 0) {
+ base::StatusOr<std::vector<uint8_t>> res = TraceConfigTxtToPb(in_data);
+ if (!res.ok()) {
+ printf("%s\n", res.status().c_message());
+ return 1;
+ }
+ fwrite(res->data(), res->size(), 1, stdout);
+ return 0;
+ }
+
+ if (strcmp(cmd, "pb_to_txt") == 0) {
+ std::string txt = TraceConfigPbToTxt(in_data.data(), in_data.size());
+ printf("%s\n", txt.c_str());
+ return 0;
+ }
+
+ PrintUsage(argv[0]);
+ return 1;
+}
diff --git a/src/trace_config_utils/pb_to_txt.cc b/src/trace_config_utils/pb_to_txt.cc
new file mode 100644
index 0000000..da84f6c
--- /dev/null
+++ b/src/trace_config_utils/pb_to_txt.cc
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "src/trace_config_utils/pb_to_txt.h"
+#include "src/trace_config_utils/config.descriptor.h"
+#include "src/trace_processor/util/descriptors.h"
+#include "src/trace_processor/util/protozero_to_text.h"
+
+namespace perfetto {
+
+std::string TraceConfigPbToTxt(const void* data, size_t size) {
+ trace_processor::DescriptorPool pool;
+ pool.AddFromFileDescriptorSet(kConfigDescriptor.data(),
+ kConfigDescriptor.size());
+
+ return trace_processor::protozero_to_text::ProtozeroToText(
+ pool, ".perfetto.protos.TraceConfig",
+ protozero::ConstBytes{static_cast<const uint8_t*>(data), size},
+ trace_processor::protozero_to_text::kIncludeNewLines);
+}
+
+} // namespace perfetto
diff --git a/src/trace_config_utils/pb_to_txt.h b/src/trace_config_utils/pb_to_txt.h
new file mode 100644
index 0000000..7fec31a
--- /dev/null
+++ b/src/trace_config_utils/pb_to_txt.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SRC_TRACE_CONFIG_UTILS_PB_TO_TXT_H_
+#define SRC_TRACE_CONFIG_UTILS_PB_TO_TXT_H_
+
+#include <stddef.h>
+#include <string>
+
+namespace perfetto {
+
+std::string TraceConfigPbToTxt(const void* data, size_t size);
+
+}
+#endif // SRC_TRACE_CONFIG_UTILS_PB_TO_TXT_H_
diff --git a/src/trace_config_utils/pb_to_txt_unittest.cc b/src/trace_config_utils/pb_to_txt_unittest.cc
new file mode 100644
index 0000000..ec7db25
--- /dev/null
+++ b/src/trace_config_utils/pb_to_txt_unittest.cc
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "src/trace_config_utils/pb_to_txt.h"
+
+#include "protos/perfetto/config/trace_config.gen.h"
+#include "test/gtest_and_gmock.h"
+
+namespace perfetto {
+namespace {
+
+using protos::gen::TraceConfig;
+
+TEST(PbToTxtTest, EmptyTraceConfig) {
+ TraceConfig tc;
+ std::vector<uint8_t> data = tc.SerializeAsArray();
+ std::string txt = TraceConfigPbToTxt(data.data(), data.size());
+ EXPECT_EQ(txt, "");
+}
+
+TEST(PbToTxtTest, ValidTraceConfig) {
+ TraceConfig tc;
+ tc.set_duration_ms(1234);
+ tc.set_trace_uuid_lsb(INT64_MAX);
+ tc.set_trace_uuid_msb(1234567890124LL);
+ auto* buf = tc.add_buffers();
+ buf->set_size_kb(4096);
+ buf->set_fill_policy(TraceConfig::BufferConfig::RING_BUFFER);
+ tc.set_write_into_file(true);
+
+ std::vector<uint8_t> data = tc.SerializeAsArray();
+ std::string txt = TraceConfigPbToTxt(data.data(), data.size());
+ EXPECT_EQ(txt, R"(buffers {
+ size_kb: 4096
+ fill_policy: RING_BUFFER
+}
+duration_ms: 1234
+write_into_file: true
+trace_uuid_msb: 1234567890124
+trace_uuid_lsb: 9223372036854775807)");
+}
+
+} // namespace
+} // namespace perfetto
diff --git a/src/perfetto_cmd/pbtxt_to_pb.cc b/src/trace_config_utils/txt_to_pb.cc
similarity index 91%
rename from src/perfetto_cmd/pbtxt_to_pb.cc
rename to src/trace_config_utils/txt_to_pb.cc
index 1f11a21..9c2e374 100644
--- a/src/perfetto_cmd/pbtxt_to_pb.cc
+++ b/src/trace_config_utils/txt_to_pb.cc
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include "src/perfetto_cmd/pbtxt_to_pb.h"
+#include "src/trace_config_utils/txt_to_pb.h"
#include <ctype.h>
#include <limits>
@@ -32,9 +32,9 @@
#include "perfetto/protozero/message.h"
#include "perfetto/protozero/message_handle.h"
#include "perfetto/protozero/scattered_heap_buffer.h"
-#include "src/perfetto_cmd/config.descriptor.h"
#include "protos/perfetto/common/descriptor.gen.h"
+#include "src/trace_config_utils/config.descriptor.h"
namespace perfetto {
constexpr char kConfigProtoName[] = ".perfetto.protos.TraceConfig";
@@ -143,6 +143,58 @@
std::set<std::string> seen_fields;
};
+class ErrorReporter {
+ public:
+ ErrorReporter(std::string file_name, const char* config)
+ : file_name_(std::move(file_name)), config_(config) {}
+
+ void AddError(size_t row,
+ size_t column,
+ size_t length,
+ const std::string& message) {
+ // Protobuf uses 1-indexed for row and column. Although in some rare cases
+ // they can be 0 if it can't locate the error.
+ row = row > 0 ? row - 1 : 0;
+ column = column > 0 ? column - 1 : 0;
+ parsed_successfully_ = false;
+ std::string line = ExtractLine(row).ToStdString();
+ if (!line.empty() && line[line.length() - 1] == '\n') {
+ line.erase(line.length() - 1);
+ }
+
+ std::string guide(column + length, ' ');
+ for (size_t i = column; i < column + length; i++) {
+ guide[i] = i == column ? '^' : '~';
+ }
+ error_ += file_name_ + ":" + std::to_string(row+1) + ":" +
+ std::to_string(column + 1) + " error: " + message + "\n";
+ error_ += line + "\n";
+ error_ += guide + "\n";
+ }
+
+ bool success() const { return parsed_successfully_; }
+ const std::string& error() const { return error_; }
+
+ private:
+ base::StringView ExtractLine(size_t line) {
+ const char* start = config_;
+ const char* end = config_;
+
+ for (size_t i = 0; i < line + 1; i++) {
+ start = end;
+ char c;
+ while ((c = *end++) && c != '\n')
+ ;
+ }
+ return base::StringView(start, static_cast<size_t>(end - start));
+ }
+
+ bool parsed_successfully_ = true;
+ std::string file_name_;
+ std::string error_;
+ const char* config_;
+};
+
class ParserDelegate {
public:
ParserDelegate(
@@ -704,11 +756,9 @@
} // namespace
-ErrorReporter::ErrorReporter() = default;
-ErrorReporter::~ErrorReporter() = default;
-
-std::vector<uint8_t> PbtxtToPb(const std::string& input,
- ErrorReporter* reporter) {
+perfetto::base::StatusOr<std::vector<uint8_t>> TraceConfigTxtToPb(
+ const std::string& input,
+ const std::string& file_name) {
std::map<std::string, const DescriptorProto*> name_to_descriptor;
std::map<std::string, const EnumDescriptorProto*> name_to_enum;
FileDescriptorSet file_descriptor_set;
@@ -736,10 +786,13 @@
PERFETTO_CHECK(descriptor);
protozero::HeapBuffered<protozero::Message> message;
- ParserDelegate delegate(descriptor, message.get(), reporter,
+ ErrorReporter reporter(file_name, input.c_str());
+ ParserDelegate delegate(descriptor, message.get(), &reporter,
std::move(name_to_descriptor),
std::move(name_to_enum));
Parse(input, &delegate);
+ if (!reporter.success())
+ return base::ErrStatus("%s", reporter.error().c_str());
return message.SerializeAsArray();
}
diff --git a/src/trace_config_utils/txt_to_pb.h b/src/trace_config_utils/txt_to_pb.h
new file mode 100644
index 0000000..3cf71ea
--- /dev/null
+++ b/src/trace_config_utils/txt_to_pb.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SRC_TRACE_CONFIG_UTILS_TXT_TO_PB_H_
+#define SRC_TRACE_CONFIG_UTILS_TXT_TO_PB_H_
+
+#include "perfetto/ext/base/status_or.h"
+
+#include <stdint.h>
+
+#include <string>
+#include <vector>
+
+namespace perfetto {
+
+base::StatusOr<std::vector<uint8_t>> TraceConfigTxtToPb(
+ const std::string& input,
+ const std::string& file_name = "-");
+
+} // namespace perfetto
+
+#endif // SRC_TRACE_CONFIG_UTILS_TXT_TO_PB_H_
diff --git a/src/perfetto_cmd/pbtxt_to_pb_unittest.cc b/src/trace_config_utils/txt_to_pb_unittest.cc
similarity index 65%
rename from src/perfetto_cmd/pbtxt_to_pb_unittest.cc
rename to src/trace_config_utils/txt_to_pb_unittest.cc
index 1b2f1d0..0b14feb 100644
--- a/src/perfetto_cmd/pbtxt_to_pb_unittest.cc
+++ b/src/trace_config_utils/txt_to_pb_unittest.cc
@@ -14,60 +14,44 @@
* limitations under the License.
*/
-#include "src/perfetto_cmd/pbtxt_to_pb.h"
+#include "src/trace_config_utils/txt_to_pb.h"
#include <memory>
#include <string>
#include "test/gtest_and_gmock.h"
-#include "perfetto/tracing/core/data_source_config.h"
-#include "perfetto/tracing/core/trace_config.h"
-
+#include "protos/perfetto/config/data_source_config.gen.h"
#include "protos/perfetto/config/ftrace/ftrace_config.gen.h"
#include "protos/perfetto/config/test_config.gen.h"
+#include "protos/perfetto/config/trace_config.gen.h"
namespace perfetto {
namespace {
using ::testing::Contains;
using ::testing::ElementsAre;
+using ::testing::HasSubstr;
using ::testing::StrictMock;
-
-class MockErrorReporter : public ErrorReporter {
- public:
- MockErrorReporter() {}
- ~MockErrorReporter() override = default;
- MOCK_METHOD(void,
- AddError,
- (size_t line,
- size_t column_start,
- size_t column_end,
- const std::string& message),
- (override));
-};
+using TraceConfig = ::perfetto::protos::gen::TraceConfig;
TraceConfig ToProto(const std::string& input) {
- StrictMock<MockErrorReporter> reporter;
- std::vector<uint8_t> output = PbtxtToPb(input, &reporter);
- EXPECT_FALSE(output.empty());
+ base::StatusOr<std::vector<uint8_t>> output = TraceConfigTxtToPb(input);
+ EXPECT_TRUE(output.ok());
+ EXPECT_FALSE(output->empty());
TraceConfig config;
- config.ParseFromArray(output.data(), output.size());
+ config.ParseFromArray(output->data(), output->size());
return config;
}
-void ToErrors(const std::string& input, MockErrorReporter* reporter) {
- std::vector<uint8_t> output = PbtxtToPb(input, reporter);
-}
-
-TEST(PbtxtToPb, OneField) {
+TEST(TxtToPbTest, OneField) {
TraceConfig config = ToProto(R"(
duration_ms: 1234
)");
EXPECT_EQ(config.duration_ms(), 1234u);
}
-TEST(PbtxtToPb, TwoFields) {
+TEST(TxtToPbTest, TwoFields) {
TraceConfig config = ToProto(R"(
duration_ms: 1234
file_write_period_ms: 5678
@@ -76,14 +60,14 @@
EXPECT_EQ(config.file_write_period_ms(), 5678u);
}
-TEST(PbtxtToPb, Enum) {
+TEST(TxtToPbTest, Enum) {
TraceConfig config = ToProto(R"(
compression_type: COMPRESSION_TYPE_DEFLATE
)");
EXPECT_EQ(config.compression_type(), 1);
}
-TEST(PbtxtToPb, LastCharacters) {
+TEST(TxtToPbTest, LastCharacters) {
EXPECT_EQ(ToProto(R"(
duration_ms: 123;)")
.duration_ms(),
@@ -121,7 +105,7 @@
1);
}
-TEST(PbtxtToPb, Semicolons) {
+TEST(TxtToPbTest, Semicolons) {
TraceConfig config = ToProto(R"(
duration_ms: 1234;
file_write_period_ms: 5678;
@@ -130,7 +114,7 @@
EXPECT_EQ(config.file_write_period_ms(), 5678u);
}
-TEST(PbtxtToPb, NestedMessage) {
+TEST(TxtToPbTest, NestedMessage) {
TraceConfig config = ToProto(R"(
buffers: {
size_kb: 123
@@ -140,7 +124,7 @@
EXPECT_EQ(config.buffers()[0].size_kb(), 123u);
}
-TEST(PbtxtToPb, SplitNested) {
+TEST(TxtToPbTest, SplitNested) {
TraceConfig config = ToProto(R"(
buffers: {
size_kb: 1
@@ -156,7 +140,7 @@
EXPECT_EQ(config.duration_ms(), 1000u);
}
-TEST(PbtxtToPb, MultipleNestedMessage) {
+TEST(TxtToPbTest, MultipleNestedMessage) {
TraceConfig config = ToProto(R"(
buffers: {
size_kb: 1
@@ -170,7 +154,7 @@
EXPECT_EQ(config.buffers()[1].size_kb(), 2u);
}
-TEST(PbtxtToPb, NestedMessageCrossFile) {
+TEST(TxtToPbTest, NestedMessageCrossFile) {
TraceConfig config = ToProto(R"(
data_sources {
config {
@@ -186,7 +170,7 @@
ASSERT_EQ(ftrace_config.drain_period_ms(), 42u);
}
-TEST(PbtxtToPb, Booleans) {
+TEST(TxtToPbTest, Booleans) {
TraceConfig config = ToProto(R"(
write_into_file: false; deferred_start: true;
)");
@@ -194,7 +178,7 @@
EXPECT_EQ(config.deferred_start(), true);
}
-TEST(PbtxtToPb, Comments) {
+TEST(TxtToPbTest, Comments) {
TraceConfig config = ToProto(R"(
write_into_file: false # deferred_start: true;
buffers# 1
@@ -218,7 +202,7 @@
EXPECT_EQ(config.deferred_start(), false);
}
-TEST(PbtxtToPb, Enums) {
+TEST(TxtToPbTest, Enums) {
TraceConfig config = ToProto(R"(
buffers: {
fill_policy: RING_BUFFER
@@ -228,7 +212,7 @@
EXPECT_EQ(config.buffers()[0].fill_policy(), kRingBuffer);
}
-TEST(PbtxtToPb, AllFieldTypes) {
+TEST(TxtToPbTest, AllFieldTypes) {
TraceConfig config = ToProto(R"(
data_sources {
config {
@@ -271,7 +255,7 @@
ASSERT_EQ(fields.field_bytes(), "14");
}
-TEST(PbtxtToPb, LeadingDots) {
+TEST(TxtToPbTest, LeadingDots) {
TraceConfig config = ToProto(R"(
data_sources {
config {
@@ -290,7 +274,7 @@
ASSERT_FLOAT_EQ(fields.field_float(), .2f);
}
-TEST(PbtxtToPb, NegativeNumbers) {
+TEST(TxtToPbTest, NegativeNumbers) {
TraceConfig config = ToProto(R"(
data_sources {
config {
@@ -325,17 +309,17 @@
ASSERT_EQ(fields.field_sint32(), -10);
}
-TEST(PbtxtToPb, EofEndsNumeric) {
+TEST(TxtToPbTest, EofEndsNumeric) {
TraceConfig config = ToProto(R"(duration_ms: 1234)");
EXPECT_EQ(config.duration_ms(), 1234u);
}
-TEST(PbtxtToPb, EofEndsIdentifier) {
+TEST(TxtToPbTest, EofEndsIdentifier) {
TraceConfig config = ToProto(R"(enable_extra_guardrails: true)");
EXPECT_EQ(config.enable_extra_guardrails(), true);
}
-TEST(PbtxtToPb, ExampleConfig) {
+TEST(TxtToPbTest, ExampleConfig) {
TraceConfig config = ToProto(R"(
buffers {
size_kb: 100024
@@ -394,7 +378,7 @@
EXPECT_EQ(config.producers()[0].producer_name(), "perfetto.traced_probes");
}
-TEST(PbtxtToPb, Strings) {
+TEST(TxtToPbTest, Strings) {
TraceConfig config = ToProto(R"(
data_sources {
config {
@@ -423,155 +407,139 @@
EXPECT_THAT(events, Contains("\0127_\03422.\177"));
}
-TEST(PbtxtToPb, UnknownField) {
- MockErrorReporter reporter;
- EXPECT_CALL(reporter,
- AddError(2, 5, 11,
- "No field named \"not_a_label\" in proto TraceConfig"));
- ToErrors(R"(
+TEST(TxtToPbTest, UnknownField) {
+ auto res = TraceConfigTxtToPb(R"(
not_a_label: false
- )",
- &reporter);
+ )");
+ EXPECT_FALSE(res.ok());
+ EXPECT_THAT(res.status().message(),
+ HasSubstr("No field named \"not_a_label\" in proto TraceConfig"));
}
-TEST(PbtxtToPb, UnknownNestedField) {
- MockErrorReporter reporter;
- EXPECT_CALL(
- reporter,
- AddError(
- 4, 5, 16,
- "No field named \"not_a_field_name\" in proto DataSourceConfig"));
- ToErrors(R"(
+TEST(TxtToPbTest, UnknownNestedField) {
+ auto res = TraceConfigTxtToPb(R"(
data_sources {
config {
not_a_field_name {
}
}
}
- )",
- &reporter);
+ )");
+ EXPECT_FALSE(res.ok());
+ EXPECT_THAT(
+ res.status().message(),
+ HasSubstr(
+ "No field named \"not_a_field_name\" in proto DataSourceConfig"));
}
-TEST(PbtxtToPb, BadBoolean) {
- MockErrorReporter reporter;
- EXPECT_CALL(reporter, AddError(2, 22, 3,
- "Expected 'true' or 'false' for boolean field "
- "write_into_file in proto TraceConfig instead "
- "saw 'foo'"));
- ToErrors(R"(
+TEST(TxtToPbTest, BadBoolean) {
+ auto res = TraceConfigTxtToPb(R"(
write_into_file: foo;
- )",
- &reporter);
+ )");
+ EXPECT_FALSE(res.ok());
+ EXPECT_THAT(res.status().message(),
+ HasSubstr("Expected 'true' or 'false' for boolean field "
+ "write_into_file in proto TraceConfig instead "
+ "saw 'foo'"));
}
-TEST(PbtxtToPb, MissingBoolean) {
- MockErrorReporter reporter;
- EXPECT_CALL(reporter, AddError(3, 3, 0, "Unexpected end of input"));
- ToErrors(R"(
+TEST(TxtToPbTest, MissingBoolean) {
+ auto res = TraceConfigTxtToPb(R"(
write_into_file:
- )",
- &reporter);
+ )");
+ EXPECT_FALSE(res.ok());
+ EXPECT_THAT(res.status().message(), HasSubstr("Unexpected end of input"));
}
-TEST(PbtxtToPb, RootProtoMustNotEndWithBrace) {
- MockErrorReporter reporter;
- EXPECT_CALL(reporter, AddError(2, 5, 0, "Unmatched closing brace"));
- ToErrors(R"(
- }
- )",
- &reporter);
+TEST(TxtToPbTest, RootProtoMustNotEndWithBrace) {
+ auto res = TraceConfigTxtToPb(" }");
+ EXPECT_FALSE(res.ok());
+ EXPECT_THAT(res.status().message(), HasSubstr("Unmatched closing brace"));
}
-TEST(PbtxtToPb, SawNonRepeatedFieldTwice) {
- MockErrorReporter reporter;
- EXPECT_CALL(
- reporter,
- AddError(3, 5, 15,
- "Saw non-repeating field 'write_into_file' more than once"));
- ToErrors(R"(
+TEST(TxtToPbTest, SawNonRepeatedFieldTwice) {
+ auto res = TraceConfigTxtToPb(R"(
write_into_file: true;
write_into_file: true;
- )",
- &reporter);
+ )");
+ EXPECT_FALSE(res.ok());
+ EXPECT_THAT(
+ res.status().message(),
+ HasSubstr("Saw non-repeating field 'write_into_file' more than once"));
}
-TEST(PbtxtToPb, WrongTypeBoolean) {
- MockErrorReporter reporter;
- EXPECT_CALL(reporter,
- AddError(2, 18, 4,
- "Expected value of type uint32 for field duration_ms in "
- "proto TraceConfig instead saw 'true'"));
- ToErrors(R"(
+TEST(TxtToPbTest, WrongTypeBoolean) {
+ auto res = TraceConfigTxtToPb(R"(
duration_ms: true;
- )",
- &reporter);
+ )");
+ EXPECT_FALSE(res.ok());
+ EXPECT_THAT(
+ res.status().message(),
+ HasSubstr("Expected value of type uint32 for field duration_ms in "
+ "proto TraceConfig instead saw 'true'"));
}
-TEST(PbtxtToPb, WrongTypeNumber) {
- MockErrorReporter reporter;
- EXPECT_CALL(reporter,
- AddError(2, 14, 3,
- "Expected value of type message for field buffers in "
- "proto TraceConfig instead saw '100'"));
- ToErrors(R"(
+TEST(TxtToPbTest, WrongTypeNumber) {
+ auto res = TraceConfigTxtToPb(R"(
buffers: 100;
- )",
- &reporter);
+ )");
+ EXPECT_FALSE(res.ok());
+ EXPECT_THAT(res.status().message(),
+ HasSubstr("Expected value of type message for field buffers in "
+ "proto TraceConfig instead saw '100'"));
}
-TEST(PbtxtToPb, NestedMessageDidNotTerminate) {
- MockErrorReporter reporter;
- EXPECT_CALL(reporter, AddError(2, 15, 0, "Nested message not closed"));
- ToErrors(R"(
- buffers: {)",
- &reporter);
+TEST(TxtToPbTest, NestedMessageDidNotTerminate) {
+ auto res = TraceConfigTxtToPb(R"(
+ buffers: {
+ )");
+ EXPECT_FALSE(res.ok());
+ EXPECT_THAT(res.status().message(), HasSubstr("Nested message not closed"));
}
-TEST(PbtxtToPb, BadEscape) {
- MockErrorReporter reporter;
- EXPECT_CALL(reporter, AddError(5, 23, 2,
- "Unknown string escape in ftrace_events in "
- "proto FtraceConfig: '\\p'"));
- ToErrors(R"(
-data_sources {
- config {
- ftrace_config {
- ftrace_events: "\p"
+TEST(TxtToPbTest, BadEscape) {
+ auto res = TraceConfigTxtToPb(R"(
+ data_sources {
+ config {
+ ftrace_config {
+ ftrace_events: "\p"
+ }
}
- }
-})",
- &reporter);
+ })");
+ EXPECT_FALSE(res.ok());
+ EXPECT_THAT(res.status().message(),
+ HasSubstr("Unknown string escape in ftrace_events in "
+ "proto FtraceConfig: '\\p'"));
}
-TEST(PbtxtToPb, BadEnumValue) {
- MockErrorReporter reporter;
- EXPECT_CALL(reporter, AddError(1, 18, 3,
- "Unexpected value 'FOO' for enum field "
- "compression_type in proto TraceConfig"));
- ToErrors(R"(compression_type: FOO)", &reporter);
+TEST(TxtToPbTest, BadEnumValue) {
+ auto res = TraceConfigTxtToPb("compression_type: FOO");
+ EXPECT_FALSE(res.ok());
+ EXPECT_THAT(res.status().message(),
+ HasSubstr("Unexpected value 'FOO' for enum field "
+ "compression_type in proto TraceConfig"));
}
-TEST(PbtxtToPb, UnexpectedBracket) {
- MockErrorReporter reporter;
- EXPECT_CALL(reporter, AddError(1, 0, 0, "Unexpected character '{'"));
- ToErrors(R"({)", &reporter);
+TEST(TxtToPbTest, UnexpectedBracket) {
+ auto res = TraceConfigTxtToPb("{");
+ EXPECT_FALSE(res.ok());
+ EXPECT_THAT(res.status().message(), HasSubstr("Unexpected character '{'"));
}
-TEST(PbtxtToPb, UnknownNested) {
- MockErrorReporter reporter;
- EXPECT_CALL(reporter, AddError(1, 0, 3,
- "No field named \"foo\" in "
- "proto TraceConfig"));
- ToErrors(R"(foo {}; bar: 42)", &reporter);
+TEST(TxtToPbTest, UnknownNested) {
+ auto res = TraceConfigTxtToPb("foo {}; bar: 42");
+ EXPECT_FALSE(res.ok());
+ EXPECT_THAT(res.status().message(), HasSubstr("No field named \"foo\" in "
+ "proto TraceConfig"));
}
// TODO(hjd): Add these tests.
-// TEST(PbtxtToPb, WrongTypeString)
-// TEST(PbtxtToPb, OverflowOnIntegers)
-// TEST(PbtxtToPb, NegativeNumbersForUnsignedInt)
-// TEST(PbtxtToPb, UnterminatedString) {
-// TEST(PbtxtToPb, NumberIsEof)
-// TEST(PbtxtToPb, OneOf)
+// TEST(TxtToPbTest, WrongTypeString)
+// TEST(TxtToPbTest, OverflowOnIntegers)
+// TEST(TxtToPbTest, NegativeNumbersForUnsignedInt)
+// TEST(TxtToPbTest, UnterminatedString) {
+// TEST(TxtToPbTest, NumberIsEof)
+// TEST(TxtToPbTest, OneOf)
} // namespace
} // namespace perfetto
diff --git a/ui/BUILD.gn b/ui/BUILD.gn
index 8c6d41a..2b47c79 100644
--- a/ui/BUILD.gn
+++ b/ui/BUILD.gn
@@ -22,6 +22,7 @@
group("ui") {
deps = [
":ui_build($host_toolchain)",
+ "../src/trace_config_utils:trace_config_utils.wasm($wasm_toolchain)",
"../src/trace_processor:trace_processor.wasm($wasm_toolchain)",
"../src/traceconv:traceconv.wasm($wasm_toolchain)",
]
diff --git a/ui/build.js b/ui/build.js
index 7d3c87d..0bf73f5 100644
--- a/ui/build.js
+++ b/ui/build.js
@@ -86,7 +86,7 @@
startHttpServer: false,
httpServerListenHost: '127.0.0.1',
httpServerListenPort: 10000,
- wasmModules: ['trace_processor', 'traceconv'],
+ wasmModules: ['trace_processor', 'traceconv', 'trace_config_utils'],
crossOriginIsolation: false,
testFilter: '',
noOverrideGnArgs: false,