| /* |
| * Copyright (C) 2021 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 "perfetto/tracing/traced_proto.h" |
| |
| #include "perfetto/test/traced_value_test_support.h" |
| #include "perfetto/tracing/track_event.h" |
| #include "protos/perfetto/trace/test_event.gen.h" |
| #include "protos/perfetto/trace/test_event.pb.h" |
| #include "protos/perfetto/trace/test_event.pbzero.h" |
| #include "protos/perfetto/trace/track_event/track_event.gen.h" |
| #include "protos/perfetto/trace/track_event/track_event.pb.h" |
| #include "test/gtest_and_gmock.h" |
| |
| namespace perfetto { |
| |
| class TracedProtoTest : public ::testing::Test { |
| public: |
| TracedProtoTest() : context_(track_event_.get(), &incremental_state_) {} |
| |
| EventContext& context() { return context_; } |
| |
| private: |
| protozero::HeapBuffered<protos::pbzero::TrackEvent> track_event_; |
| internal::TrackEventIncrementalState incremental_state_; |
| EventContext context_; |
| }; |
| |
| using TestPayload = protos::pbzero::TestEvent::TestPayload; |
| |
| TEST_F(TracedProtoTest, SingleInt_WriteField) { |
| protozero::HeapBuffered<TestPayload> event; |
| perfetto::TracedProto<TestPayload> proto = context().Wrap(event.get()); |
| WriteTracedProtoField(proto, TestPayload::kSingleInt, 42); |
| |
| protos::TestEvent::TestPayload result; |
| result.ParseFromString(event.SerializeAsString()); |
| EXPECT_TRUE(result.has_single_int()); |
| EXPECT_EQ(result.single_int(), 42); |
| } |
| |
| TEST_F(TracedProtoTest, SingleInt_Set) { |
| protozero::HeapBuffered<TestPayload> event; |
| perfetto::TracedProto<TestPayload> proto = context().Wrap(event.get()); |
| proto.Set(TestPayload::kSingleInt, 42); |
| |
| protos::TestEvent::TestPayload result; |
| result.ParseFromString(event.SerializeAsString()); |
| EXPECT_TRUE(result.has_single_int()); |
| EXPECT_EQ(result.single_int(), 42); |
| } |
| |
| TEST_F(TracedProtoTest, RepeatedInt_WriteField) { |
| protozero::HeapBuffered<TestPayload> event; |
| perfetto::TracedProto<TestPayload> proto = context().Wrap(event.get()); |
| WriteTracedProtoField(proto, TestPayload::kRepeatedInts, |
| std::vector<int>{1, 2, 3}); |
| |
| protos::TestEvent::TestPayload result; |
| result.ParseFromString(event.SerializeAsString()); |
| EXPECT_THAT(result.repeated_ints(), ::testing::ElementsAre(1, 2, 3)); |
| } |
| |
| TEST_F(TracedProtoTest, RepeatedInt_AppendValue) { |
| protozero::HeapBuffered<TestPayload> event; |
| perfetto::TracedProto<TestPayload> proto = context().Wrap(event.get()); |
| proto.AppendValue(TestPayload::kRepeatedInts, 1); |
| |
| protos::TestEvent::TestPayload result; |
| result.ParseFromString(event.SerializeAsString()); |
| EXPECT_THAT(result.repeated_ints(), ::testing::ElementsAre(1)); |
| } |
| |
| TEST_F(TracedProtoTest, RepeatedInt_AppendFrom) { |
| protozero::HeapBuffered<TestPayload> event; |
| perfetto::TracedProto<TestPayload> proto = context().Wrap(event.get()); |
| proto.AppendFrom(TestPayload::kRepeatedInts, std::vector<int>{1, 2, 3}); |
| |
| protos::TestEvent::TestPayload result; |
| result.ParseFromString(event.SerializeAsString()); |
| EXPECT_THAT(result.repeated_ints(), ::testing::ElementsAre(1, 2, 3)); |
| } |
| |
| TEST_F(TracedProtoTest, SingleString_WriteField) { |
| protozero::HeapBuffered<TestPayload> event; |
| perfetto::TracedProto<TestPayload> proto = context().Wrap(event.get()); |
| WriteTracedProtoField(proto, TestPayload::kSingleString, "foo"); |
| |
| protos::TestEvent::TestPayload result; |
| result.ParseFromString(event.SerializeAsString()); |
| EXPECT_TRUE(result.has_single_string()); |
| EXPECT_EQ(result.single_string(), "foo"); |
| } |
| |
| TEST_F(TracedProtoTest, SingleString_Set) { |
| protozero::HeapBuffered<TestPayload> event; |
| perfetto::TracedProto<TestPayload> proto = context().Wrap(event.get()); |
| proto.Set(TestPayload::kSingleString, "foo"); |
| |
| protos::TestEvent::TestPayload result; |
| result.ParseFromString(event.SerializeAsString()); |
| EXPECT_TRUE(result.has_single_string()); |
| EXPECT_EQ(result.single_string(), "foo"); |
| } |
| |
| TEST_F(TracedProtoTest, RepeatedString_WriteField) { |
| protozero::HeapBuffered<TestPayload> event; |
| perfetto::TracedProto<TestPayload> proto = context().Wrap(event.get()); |
| WriteTracedProtoField(proto, TestPayload::kStr, |
| std::vector<std::string>{"foo", "bar"}); |
| |
| protos::TestEvent::TestPayload result; |
| result.ParseFromString(event.SerializeAsString()); |
| EXPECT_THAT(result.str(), ::testing::ElementsAre("foo", "bar")); |
| } |
| |
| TEST_F(TracedProtoTest, RepeatedString_AppendFrom) { |
| protozero::HeapBuffered<TestPayload> event; |
| perfetto::TracedProto<TestPayload> proto = context().Wrap(event.get()); |
| proto.AppendFrom(TestPayload::kStr, std::vector<std::string>{"foo", "bar"}); |
| |
| protos::TestEvent::TestPayload result; |
| result.ParseFromString(event.SerializeAsString()); |
| EXPECT_THAT(result.str(), ::testing::ElementsAre("foo", "bar")); |
| } |
| |
| TEST_F(TracedProtoTest, RepeatedString_AppendValue) { |
| protozero::HeapBuffered<TestPayload> event; |
| perfetto::TracedProto<TestPayload> proto = context().Wrap(event.get()); |
| proto.AppendValue(TestPayload::kStr, "foo"); |
| |
| protos::TestEvent::TestPayload result; |
| result.ParseFromString(event.SerializeAsString()); |
| EXPECT_THAT(result.str(), ::testing::ElementsAre("foo")); |
| } |
| |
| namespace { |
| |
| struct Foo { |
| void WriteIntoTrace(TracedProto<TestPayload> message) const { |
| message->set_single_int(42); |
| |
| auto dict = std::move(message).AddDebugAnnotations(); |
| dict.Add("arg", "value"); |
| } |
| }; |
| |
| struct Bar {}; |
| |
| } // namespace |
| |
| template <> |
| struct TraceFormatTraits<Bar> { |
| static void WriteIntoTrace( |
| TracedProto<protos::pbzero::TestEvent::TestPayload> message, |
| const Bar&) { |
| message->set_single_string("value"); |
| } |
| }; |
| |
| TEST_F(TracedProtoTest, SingleNestedMessage_Method) { |
| protozero::HeapBuffered<protos::pbzero::TestEvent> event; |
| perfetto::TracedProto<protos::pbzero::TestEvent> proto = |
| context().Wrap(event.get()); |
| WriteTracedProtoField(proto, protos::pbzero::TestEvent::kPayload, Foo()); |
| |
| protos::TestEvent result; |
| result.ParseFromString(event.SerializeAsString()); |
| EXPECT_EQ(result.payload().single_int(), 42); |
| } |
| |
| TEST_F(TracedProtoTest, SingleNestedMessage_TraceFormatTraits) { |
| protozero::HeapBuffered<protos::pbzero::TestEvent> event; |
| perfetto::TracedProto<protos::pbzero::TestEvent> proto = |
| context().Wrap(event.get()); |
| WriteTracedProtoField(proto, protos::pbzero::TestEvent::kPayload, Bar()); |
| |
| protos::TestEvent result; |
| result.ParseFromString(event.SerializeAsString()); |
| EXPECT_EQ(result.payload().single_string(), "value"); |
| } |
| |
| TEST_F(TracedProtoTest, SingleNestedMessage_Pointer) { |
| protozero::HeapBuffered<protos::pbzero::TestEvent> event; |
| perfetto::TracedProto<protos::pbzero::TestEvent> proto = |
| context().Wrap(event.get()); |
| Bar bar; |
| WriteTracedProtoField(proto, protos::pbzero::TestEvent::kPayload, &bar); |
| |
| protos::TestEvent result; |
| result.ParseFromString(event.SerializeAsString()); |
| EXPECT_EQ(result.payload().single_string(), "value"); |
| } |
| |
| TEST_F(TracedProtoTest, SingleNestedMessage_UniquePtr) { |
| protozero::HeapBuffered<protos::pbzero::TestEvent> event; |
| perfetto::TracedProto<protos::pbzero::TestEvent> proto = |
| context().Wrap(event.get()); |
| std::unique_ptr<Bar> bar(new Bar); |
| WriteTracedProtoField(proto, protos::pbzero::TestEvent::kPayload, bar); |
| |
| protos::TestEvent result; |
| result.ParseFromString(event.SerializeAsString()); |
| EXPECT_EQ(result.payload().single_string(), "value"); |
| } |
| |
| TEST_F(TracedProtoTest, SingleNestedMessage_EmptyUniquePtr) { |
| protozero::HeapBuffered<protos::pbzero::TestEvent> event; |
| perfetto::TracedProto<protos::pbzero::TestEvent> proto = |
| context().Wrap(event.get()); |
| std::unique_ptr<Bar> bar; |
| WriteTracedProtoField(proto, protos::pbzero::TestEvent::kPayload, bar); |
| |
| protos::TestEvent result; |
| result.ParseFromString(event.SerializeAsString()); |
| EXPECT_FALSE(result.payload().has_single_string()); |
| } |
| |
| TEST_F(TracedProtoTest, SingleNestedMessage_Nullptr) { |
| protozero::HeapBuffered<protos::pbzero::TestEvent> event; |
| perfetto::TracedProto<protos::pbzero::TestEvent> proto = |
| context().Wrap(event.get()); |
| WriteTracedProtoField(proto, protos::pbzero::TestEvent::kPayload, nullptr); |
| |
| protos::TestEvent result; |
| result.ParseFromString(event.SerializeAsString()); |
| EXPECT_FALSE(result.payload().has_single_string()); |
| } |
| |
| TEST_F(TracedProtoTest, SingleNestedMessage_Method_Set) { |
| protozero::HeapBuffered<protos::pbzero::TestEvent> event; |
| perfetto::TracedProto<protos::pbzero::TestEvent> proto = |
| context().Wrap(event.get()); |
| WriteTracedProtoField(proto, protos::pbzero::TestEvent::kPayload, Foo()); |
| |
| protos::TestEvent result; |
| result.ParseFromString(event.SerializeAsString()); |
| EXPECT_EQ(result.payload().single_int(), 42); |
| } |
| |
| TEST_F(TracedProtoTest, SingleNestedMessage_TraceFormatTraits_Set) { |
| protozero::HeapBuffered<protos::pbzero::TestEvent> event; |
| perfetto::TracedProto<protos::pbzero::TestEvent> proto = |
| context().Wrap(event.get()); |
| proto.Set(protos::pbzero::TestEvent::kPayload, Bar()); |
| |
| protos::TestEvent result; |
| result.ParseFromString(event.SerializeAsString()); |
| EXPECT_EQ(result.payload().single_string(), "value"); |
| } |
| |
| TEST_F(TracedProtoTest, SingleNestedMessage_Pointer_Set) { |
| protozero::HeapBuffered<protos::pbzero::TestEvent> event; |
| perfetto::TracedProto<protos::pbzero::TestEvent> proto = |
| context().Wrap(event.get()); |
| Bar bar; |
| proto.Set(protos::pbzero::TestEvent::kPayload, &bar); |
| |
| protos::TestEvent result; |
| result.ParseFromString(event.SerializeAsString()); |
| EXPECT_EQ(result.payload().single_string(), "value"); |
| } |
| |
| TEST_F(TracedProtoTest, SingleNestedMessage_UniquePtr_Set) { |
| protozero::HeapBuffered<protos::pbzero::TestEvent> event; |
| perfetto::TracedProto<protos::pbzero::TestEvent> proto = |
| context().Wrap(event.get()); |
| std::unique_ptr<Bar> bar(new Bar); |
| proto.Set(protos::pbzero::TestEvent::kPayload, bar); |
| |
| protos::TestEvent result; |
| result.ParseFromString(event.SerializeAsString()); |
| EXPECT_EQ(result.payload().single_string(), "value"); |
| } |
| |
| TEST_F(TracedProtoTest, SingleNestedMessage_EmptyUniquePtr_Set) { |
| protozero::HeapBuffered<protos::pbzero::TestEvent> event; |
| perfetto::TracedProto<protos::pbzero::TestEvent> proto = |
| context().Wrap(event.get()); |
| std::unique_ptr<Bar> bar; |
| proto.Set(protos::pbzero::TestEvent::kPayload, bar); |
| |
| protos::TestEvent result; |
| result.ParseFromString(event.SerializeAsString()); |
| EXPECT_FALSE(result.payload().has_single_string()); |
| } |
| |
| TEST_F(TracedProtoTest, SingleNestedMessage_Nullptr_Set) { |
| protozero::HeapBuffered<protos::pbzero::TestEvent> event; |
| perfetto::TracedProto<protos::pbzero::TestEvent> proto = |
| context().Wrap(event.get()); |
| proto.Set(protos::pbzero::TestEvent::kPayload, nullptr); |
| |
| protos::TestEvent result; |
| result.ParseFromString(event.SerializeAsString()); |
| EXPECT_FALSE(result.payload().has_single_string()); |
| } |
| |
| TEST_F(TracedProtoTest, RepeatedNestedMessage_Method) { |
| protozero::HeapBuffered<TestPayload> event; |
| perfetto::TracedProto<TestPayload> proto = context().Wrap(event.get()); |
| WriteTracedProtoField(proto, TestPayload::kNested, |
| std::vector<Foo>{Foo(), Foo()}); |
| |
| protos::TestEvent::TestPayload result; |
| result.ParseFromString(event.SerializeAsString()); |
| EXPECT_EQ(result.nested_size(), 2); |
| EXPECT_EQ(result.nested(0).single_int(), 42); |
| EXPECT_EQ(result.nested(1).single_int(), 42); |
| } |
| |
| TEST_F(TracedProtoTest, RepeatedNestedMessage_TraceFormatTraits) { |
| protozero::HeapBuffered<TestPayload> event; |
| perfetto::TracedProto<TestPayload> proto = context().Wrap(event.get()); |
| WriteTracedProtoField(proto, TestPayload::kNested, |
| std::vector<Bar>{Bar(), Bar()}); |
| |
| protos::TestEvent::TestPayload result; |
| result.ParseFromString(event.SerializeAsString()); |
| EXPECT_EQ(result.nested_size(), 2); |
| EXPECT_EQ(result.nested(0).single_string(), "value"); |
| EXPECT_EQ(result.nested(1).single_string(), "value"); |
| } |
| |
| TEST_F(TracedProtoTest, RepeatedNestedMessage_Pointer) { |
| protozero::HeapBuffered<TestPayload> event; |
| perfetto::TracedProto<TestPayload> proto = context().Wrap(event.get()); |
| Bar bar; |
| std::vector<Bar*> bars; |
| bars.push_back(&bar); |
| bars.push_back(nullptr); |
| WriteTracedProtoField(proto, TestPayload::kNested, bars); |
| |
| protos::TestEvent::TestPayload result; |
| result.ParseFromString(event.SerializeAsString()); |
| EXPECT_EQ(result.nested_size(), 2); |
| EXPECT_EQ(result.nested(0).single_string(), "value"); |
| EXPECT_FALSE(result.nested(1).has_single_string()); |
| } |
| |
| TEST_F(TracedProtoTest, RepeatedNestedMessage_Method_AppendValue) { |
| protozero::HeapBuffered<TestPayload> event; |
| perfetto::TracedProto<TestPayload> proto = context().Wrap(event.get()); |
| proto.AppendValue(TestPayload::kNested, Foo()); |
| |
| protos::TestEvent::TestPayload result; |
| result.ParseFromString(event.SerializeAsString()); |
| EXPECT_EQ(result.nested_size(), 1); |
| EXPECT_EQ(result.nested(0).single_int(), 42); |
| } |
| |
| TEST_F(TracedProtoTest, RepeatedNestedMessage_TraceFormatTraits_AppendValue) { |
| protozero::HeapBuffered<TestPayload> event; |
| perfetto::TracedProto<TestPayload> proto = context().Wrap(event.get()); |
| proto.AppendValue(TestPayload::kNested, Bar()); |
| |
| protos::TestEvent::TestPayload result; |
| result.ParseFromString(event.SerializeAsString()); |
| EXPECT_EQ(result.nested_size(), 1); |
| EXPECT_EQ(result.nested(0).single_string(), "value"); |
| } |
| |
| TEST_F(TracedProtoTest, RepeatedNestedMessage_Pointer_AppendValue) { |
| protozero::HeapBuffered<TestPayload> event; |
| perfetto::TracedProto<TestPayload> proto = context().Wrap(event.get()); |
| Bar bar; |
| proto.AppendValue(TestPayload::kNested, &bar); |
| proto.AppendValue(TestPayload::kNested, nullptr); |
| |
| protos::TestEvent::TestPayload result; |
| result.ParseFromString(event.SerializeAsString()); |
| EXPECT_EQ(result.nested_size(), 2); |
| EXPECT_EQ(result.nested(0).single_string(), "value"); |
| EXPECT_FALSE(result.nested(1).has_single_string()); |
| } |
| |
| TEST_F(TracedProtoTest, RepeatedNestedMessage_Method_AppendFrom) { |
| protozero::HeapBuffered<TestPayload> event; |
| perfetto::TracedProto<TestPayload> proto = context().Wrap(event.get()); |
| proto.AppendFrom(TestPayload::kNested, std::vector<Foo>{Foo(), Foo()}); |
| |
| protos::TestEvent::TestPayload result; |
| result.ParseFromString(event.SerializeAsString()); |
| EXPECT_EQ(result.nested_size(), 2); |
| EXPECT_EQ(result.nested(0).single_int(), 42); |
| EXPECT_EQ(result.nested(1).single_int(), 42); |
| } |
| |
| TEST_F(TracedProtoTest, RepeatedNestedMessage_TraceFormatTraits_AppendFrom) { |
| protozero::HeapBuffered<TestPayload> event; |
| perfetto::TracedProto<TestPayload> proto = context().Wrap(event.get()); |
| proto.AppendFrom(TestPayload::kNested, std::vector<Bar>{Bar(), Bar()}); |
| |
| protos::TestEvent::TestPayload result; |
| result.ParseFromString(event.SerializeAsString()); |
| EXPECT_EQ(result.nested_size(), 2); |
| EXPECT_EQ(result.nested(0).single_string(), "value"); |
| EXPECT_EQ(result.nested(1).single_string(), "value"); |
| } |
| |
| TEST_F(TracedProtoTest, RepeatedNestedMessage_Pointer_AppendFrom) { |
| protozero::HeapBuffered<TestPayload> event; |
| perfetto::TracedProto<TestPayload> proto = context().Wrap(event.get()); |
| Bar bar; |
| std::vector<Bar*> bars; |
| bars.push_back(&bar); |
| bars.push_back(nullptr); |
| proto.AppendFrom(TestPayload::kNested, bars); |
| |
| protos::TestEvent::TestPayload result; |
| result.ParseFromString(event.SerializeAsString()); |
| EXPECT_EQ(result.nested_size(), 2); |
| EXPECT_EQ(result.nested(0).single_string(), "value"); |
| EXPECT_FALSE(result.nested(1).has_single_string()); |
| } |
| |
| TEST_F(TracedProtoTest, WriteDebugAnnotations) { |
| protozero::HeapBuffered<protos::pbzero::TestEvent> event; |
| perfetto::TracedProto<protos::pbzero::TestEvent> proto = |
| context().Wrap(event.get()); |
| WriteTracedProtoField(proto, protos::pbzero::TestEvent::kPayload, Foo()); |
| |
| protos::TestEvent result; |
| result.ParseFromString(event.SerializeAsString()); |
| |
| protos::DebugAnnotation dict; |
| for (const auto& annotation : result.payload().debug_annotations()) { |
| *dict.add_dict_entries() = annotation; |
| } |
| |
| EXPECT_EQ(internal::DebugAnnotationToString(dict.SerializeAsString()), |
| "{arg:value}"); |
| } |
| |
| } // namespace perfetto |