• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "src/trace_processor/util/streaming_line_reader.h"
18 
19 #include <algorithm>
20 #include <functional>
21 #include <random>
22 #include <string>
23 #include <vector>
24 
25 #include "perfetto/ext/base/string_utils.h"
26 #include "perfetto/ext/base/sys_types.h"  // For ssize_t on Windows.
27 #include "test/gtest_and_gmock.h"
28 
29 namespace perfetto {
30 namespace trace_processor {
31 namespace util {
32 
33 namespace {
34 
35 using ::testing::ElementsAreArray;
36 
37 struct LineSink {
AppendLinesCallbackperfetto::trace_processor::util::__anonbcab78d60111::LineSink38   StreamingLineReader::LinesCallback AppendLinesCallback() {
39     return [&](const std::vector<base::StringView>& lines_parsed) {
40       for (const auto& sv : lines_parsed) {
41         lines_.emplace_back(sv.ToStdString());
42       }
43     };
44   }
45 
46   // Returns the lines received so far. Not idempotent, clears the vector.
GetLinesperfetto::trace_processor::util::__anonbcab78d60111::LineSink47   std::vector<std::string> GetLines() {
48     auto lines = std::move(lines_);
49     lines_.clear();
50     return lines;
51   }
52 
53   std::vector<std::string> lines_;
54 };
55 
TEST(StreamingLineReaderTest,Tokenize)56 TEST(StreamingLineReaderTest, Tokenize) {
57   LineSink sink;
58   StreamingLineReader slr(sink.AppendLinesCallback());
59 
60   slr.Tokenize("a12\nb3456\nc\nd78\n\ne12\nf3456\n");
61   ASSERT_THAT(sink.GetLines(), ElementsAreArray({"a12", "b3456", "c", "d78", "",
62                                                  "e12", "f3456"}));
63 }
64 
TEST(StreamingLineReaderTest,BeginEndWrite)65 TEST(StreamingLineReaderTest, BeginEndWrite) {
66   LineSink sink;
67   StreamingLineReader slr(sink.AppendLinesCallback());
68 
69   char* w = slr.BeginWrite(9);
70   slr.EndWrite(static_cast<size_t>(base::SprintfTrunc(w, 9, "a12\nb345")));
71   ASSERT_THAT(sink.GetLines(), ElementsAreArray({"a12"}));
72 
73   w = slr.BeginWrite(9);
74   slr.EndWrite(static_cast<size_t>(base::SprintfTrunc(w, 9, "6\nc\nd78\n")));
75   ASSERT_THAT(sink.GetLines(), ElementsAreArray({"b3456", "c", "d78"}));
76 
77   w = slr.BeginWrite(4);  // Deliberately over-sizing the `reserve_size`.
78   slr.EndWrite(static_cast<size_t>(base::SprintfTrunc(w, 4, "\n")));
79   ASSERT_THAT(sink.GetLines(), ElementsAreArray({""}));
80 
81   w = slr.BeginWrite(128);  // Deliberately over-sizing the `reserve_size`.
82   slr.EndWrite(static_cast<size_t>(base::SprintfTrunc(w, 128, "e12\nf3456\n")));
83   ASSERT_THAT(sink.GetLines(), ElementsAreArray({"e12", "f3456"}));
84 }
85 
86 // Creates a random text of 10000 chars which looks like the one below. Then
87 // feeds it into the SLR pushing chunks of random size. Checks that all the
88 // lines received match the original text.
TEST(StreamingLineReaderTest,RandomWrite)89 TEST(StreamingLineReaderTest, RandomWrite) {
90   LineSink sink;
91   StreamingLineReader slr(sink.AppendLinesCallback());
92   std::minstd_rand0 rnd(0);
93 
94   // Builds a random string with 10k char that looks like this:
95   // geoefss1hmwgp9r6i3hlmpejjv6c4u2tsgbrwp30arkyb8b13ntek09f\n
96   // t4q\n
97   // \n
98   // vr135li3m3330gy\n
99   // ...
100   std::string expected_txt(10000, '\0');
101   static const char kRandChars[] = "\n0123456789abcdefghijklmnopqrstuvwxyz";
102   for (size_t i = 0; i < expected_txt.size(); i++)
103     expected_txt[i] = kRandChars[rnd() % strlen(kRandChars)];
104   expected_txt[expected_txt.size() - 1] = '\n';
105 
106   // Push it in random chunks of max 1Kb.
107   for (auto it = expected_txt.begin(); it < expected_txt.end();) {
108     size_t wr_size = static_cast<size_t>(rnd()) % 1000ul;
109     auto avail = static_cast<size_t>(std::distance(it, expected_txt.end()));
110     wr_size = std::min(wr_size, avail);
111     memcpy(slr.BeginWrite(wr_size), &*it, wr_size);
112     slr.EndWrite(wr_size);
113     it += static_cast<ssize_t>(wr_size);
114   }
115 
116   // Merge the lines received and check they match the original text.
117   std::string actual_txt;
118   actual_txt.reserve(expected_txt.size());
119   std::vector<std::string> lines = sink.GetLines();
120   for (const std::string& line : lines) {
121     actual_txt.append(line);
122     actual_txt.append("\n");
123   }
124 
125   ASSERT_EQ(actual_txt, expected_txt);
126 }
127 
128 }  // namespace
129 }  // namespace util
130 }  // namespace trace_processor
131 }  // namespace perfetto
132