|  | /* | 
|  | * Copyright (C) 2017 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/ftrace_reader/format_parser.h" | 
|  |  | 
|  | #include "gmock/gmock.h" | 
|  | #include "gtest/gtest.h" | 
|  |  | 
|  | namespace perfetto { | 
|  | namespace { | 
|  |  | 
|  | using testing::ElementsAre; | 
|  | using testing::Eq; | 
|  |  | 
|  | TEST(FtraceEventParserTest, HappyPath) { | 
|  | const std::string input = R"(name: the_name | 
|  | ID: 42 | 
|  | format: | 
|  | field:unsigned short common_type;	offset:0;	size:2;	signed:0; | 
|  | field:unsigned char common_flags;	offset:2;	size:1;	signed:0; | 
|  | field:unsigned char common_preempt_count;	offset:3;	size:1;	signed:0; | 
|  | field:int common_pid;	offset:4;	size:4;	signed:1; | 
|  |  | 
|  | field:char client_name[64];	offset:8;	size:64;	signed:0; | 
|  | field:const char * heap_name;	offset:72;	size:4;	signed:1; | 
|  |  | 
|  | print fmt: "client_name=%s heap_name=%s len=%zu mask=0x%x flags=0x%x", REC->client_name, REC->heap_name, REC->len, REC->mask, REC->flags | 
|  | )"; | 
|  |  | 
|  | FtraceEvent output; | 
|  | EXPECT_TRUE(ParseFtraceEvent(input)); | 
|  | EXPECT_TRUE(ParseFtraceEvent(input, &output)); | 
|  | EXPECT_EQ(output.name, "the_name"); | 
|  | EXPECT_EQ(output.id, 42); | 
|  | EXPECT_THAT( | 
|  | output.fields, | 
|  | ElementsAre( | 
|  | Eq(FtraceEvent::Field{"char client_name[64]", 8, 64, false}), | 
|  | Eq(FtraceEvent::Field{"const char * heap_name", 72, 4, true}))); | 
|  | EXPECT_THAT( | 
|  | output.common_fields, | 
|  | ElementsAre( | 
|  | Eq(FtraceEvent::Field{"unsigned short common_type", 0, 2, false}), | 
|  | Eq(FtraceEvent::Field{"unsigned char common_flags", 2, 1, false}), | 
|  | Eq(FtraceEvent::Field{"unsigned char common_preempt_count", 3, 1, | 
|  | false}), | 
|  | Eq(FtraceEvent::Field{"int common_pid", 4, 4, true}))); | 
|  | } | 
|  |  | 
|  | TEST(FtraceEventParserTest, MissingName) { | 
|  | const std::string input = R"(ID: 42 | 
|  | format: | 
|  | field:unsigned short common_type;	offset:0;	size:2;	signed:0; | 
|  | field:unsigned char common_flags;	offset:2;	size:1;	signed:0; | 
|  | field:unsigned char common_preempt_count;	offset:3;	size:1;	signed:0; | 
|  | field:int common_pid;	offset:4;	size:4;	signed:1; | 
|  |  | 
|  | print fmt: "client_name=%s heap_name=%s len=%zu mask=0x%x flags=0x%x", REC->client_name, REC->heap_name, REC->len, REC->mask, REC->flags | 
|  | )"; | 
|  |  | 
|  | EXPECT_FALSE(ParseFtraceEvent(input)); | 
|  | } | 
|  |  | 
|  | TEST(FtraceEventParserTest, MissingID) { | 
|  | const std::string input = R"(name: the_name | 
|  | format: | 
|  | field:unsigned short common_type;	offset:0;	size:2;	signed:0; | 
|  | field:unsigned char common_flags;	offset:2;	size:1;	signed:0; | 
|  | field:unsigned char common_preempt_count;	offset:3;	size:1;	signed:0; | 
|  | field:int common_pid;	offset:4;	size:4;	signed:1; | 
|  |  | 
|  | print fmt: "client_name=%s heap_name=%s len=%zu mask=0x%x flags=0x%x", REC->client_name, REC->heap_name, REC->len, REC->mask, REC->flags | 
|  | )"; | 
|  |  | 
|  | EXPECT_FALSE(ParseFtraceEvent(input)); | 
|  | } | 
|  |  | 
|  | TEST(FtraceEventParserTest, NoFields) { | 
|  | const std::string input = R"(name: the_name | 
|  | ID: 10 | 
|  | print fmt: "client_name=%s heap_name=%s len=%zu mask=0x%x flags=0x%x", REC->client_name, REC->heap_name, REC->len, REC->mask, REC->flags | 
|  | )"; | 
|  |  | 
|  | EXPECT_FALSE(ParseFtraceEvent(input)); | 
|  | } | 
|  |  | 
|  | TEST(FtraceEventParserTest, BasicFuzzing) { | 
|  | const std::string input = R"(name: the_name | 
|  | ID: 42 | 
|  | format: | 
|  | field:unsigned short common_type;	offset:0;	size:2;	signed:0; | 
|  | field:unsigned char common_flags;	offset:2;	size:1;	signed:0; | 
|  | field:unsigned char common_preempt_count;	offset:3;	size:1;	signed:0; | 
|  | field:int common_pid;	offset:4;	size:4;	signed:1; | 
|  |  | 
|  | field:char client_name[64];	offset:8;	size:64;	signed:0; | 
|  | field:const char * heap_name;	offset:72;	size:4;	signed:0; | 
|  | field:size_t len;	offset:76;	size:4;	signed:0; | 
|  | field:unsigned int mask;	offset:80;	size:4;	signed:0; | 
|  | field:unsigned int flags;	offset:84;	size:4;	signed:0; | 
|  |  | 
|  | print fmt: "client_name=%s heap_name=%s len=%zu mask=0x%x flags=0x%x", REC->client_name, REC->heap_name, REC->len, REC->mask, REC->flags | 
|  | )"; | 
|  |  | 
|  | for (size_t i = 0; i < input.length(); i++) { | 
|  | for (size_t j = 1; j < 10 && i + j < input.length(); j++) { | 
|  | std::string copy = input; | 
|  | copy.erase(i, j); | 
|  | ParseFtraceEvent(copy); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST(FtraceEventParserTest, GetNameFromTypeAndName) { | 
|  | EXPECT_EQ(GetNameFromTypeAndName("int foo"), "foo"); | 
|  | EXPECT_EQ(GetNameFromTypeAndName("int foo_bar"), "foo_bar"); | 
|  | EXPECT_EQ(GetNameFromTypeAndName("const char * foo"), "foo"); | 
|  | EXPECT_EQ(GetNameFromTypeAndName("const char foo[64]"), "foo"); | 
|  | EXPECT_EQ(GetNameFromTypeAndName("char[] foo[16]"), "foo"); | 
|  | EXPECT_EQ(GetNameFromTypeAndName("u8 foo[(int)sizeof(struct blah)]"), "foo"); | 
|  |  | 
|  | EXPECT_EQ(GetNameFromTypeAndName(""), ""); | 
|  | EXPECT_EQ(GetNameFromTypeAndName("]"), ""); | 
|  | EXPECT_EQ(GetNameFromTypeAndName("["), ""); | 
|  | EXPECT_EQ(GetNameFromTypeAndName(" "), ""); | 
|  | EXPECT_EQ(GetNameFromTypeAndName(" []"), ""); | 
|  | EXPECT_EQ(GetNameFromTypeAndName(" ]["), ""); | 
|  | EXPECT_EQ(GetNameFromTypeAndName("char"), ""); | 
|  | EXPECT_EQ(GetNameFromTypeAndName("char *"), ""); | 
|  | EXPECT_EQ(GetNameFromTypeAndName("char 42"), ""); | 
|  | } | 
|  |  | 
|  | }  // namespace | 
|  | }  // namespace perfetto |