• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2023 Google Inc.  All rights reserved.
3 //
4 // Use of this source code is governed by a BSD-style
5 // license that can be found in the LICENSE file or at
6 // https://developers.google.com/open-source/licenses/bsd
7 
8 #include "google/protobuf/io/test_zero_copy_stream.h"
9 
10 #include <memory>
11 #include <string>
12 #include <utility>
13 #include <vector>
14 
15 #include <gmock/gmock.h>
16 #include <gtest/gtest.h>
17 #include "absl/types/optional.h"
18 
19 namespace google {
20 namespace protobuf {
21 namespace io {
22 namespace internal {
23 namespace {
24 
25 using testing::ElementsAre;
26 using testing::Eq;
27 using testing::Optional;
28 
CallNext(ZeroCopyInputStream & stream)29 absl::optional<std::string> CallNext(ZeroCopyInputStream& stream) {
30   const void* data;
31   int size;
32   if (stream.Next(&data, &size)) {
33     return std::string(static_cast<const char*>(data),
34                        static_cast<size_t>(size));
35   }
36   return absl::nullopt;
37 }
38 
ReadLeftoverDoNotConsumeInput(TestZeroCopyInputStream copy)39 std::vector<std::string> ReadLeftoverDoNotConsumeInput(
40     TestZeroCopyInputStream copy) {
41   std::vector<std::string> out;
42   while (auto next = CallNext(copy)) {
43     out.push_back(*std::move(next));
44   }
45   return out;
46 }
47 
48 #if GTEST_HAS_DEATH_TEST
TEST(TestZeroCopyInputStreamTest,NextChecksPreconditions)49 TEST(TestZeroCopyInputStreamTest, NextChecksPreconditions) {
50   std::unique_ptr<ZeroCopyInputStream> stream =
51       std::make_unique<TestZeroCopyInputStream>(std::vector<std::string>{});
52   const void* data;
53   int size;
54   EXPECT_DEATH(stream->Next(nullptr, &size), "data must not be null");
55   EXPECT_DEATH(stream->Next(&data, nullptr), "size must not be null");
56 }
57 #endif  // GTEST_HAS_DEATH_TEST
58 
TEST(TestZeroCopyInputStreamTest,NextProvidesTheBuffersCorrectly)59 TEST(TestZeroCopyInputStreamTest, NextProvidesTheBuffersCorrectly) {
60   std::vector<std::string> expected = {"ABC", "D", "EFG", "", "", "HIJKLMN"};
61   std::unique_ptr<ZeroCopyInputStream> stream =
62       std::make_unique<TestZeroCopyInputStream>(expected);
63 
64   std::vector<std::string> found;
65   while (auto next = CallNext(*stream)) {
66     found.push_back(*std::move(next));
67   }
68 
69   EXPECT_EQ(found, expected);
70 }
71 
TEST(TestZeroCopyInputStreamTest,BackUpGivesBackABuffer)72 TEST(TestZeroCopyInputStreamTest, BackUpGivesBackABuffer) {
73   std::vector<std::string> expected = {"ABC", "D", "EFG", "", "", "HIJKLMN"};
74   std::unique_ptr<ZeroCopyInputStream> stream =
75       std::make_unique<TestZeroCopyInputStream>(expected);
76 
77   EXPECT_THAT(CallNext(*stream), Optional(Eq("ABC")));
78   stream->BackUp(3);
79   EXPECT_THAT(CallNext(*stream), Optional(Eq("ABC")));
80   stream->BackUp(2);
81   EXPECT_THAT(CallNext(*stream), Optional(Eq("BC")));
82   EXPECT_THAT(CallNext(*stream), Optional(Eq("D")));
83   stream->BackUp(1);
84   EXPECT_THAT(CallNext(*stream), Optional(Eq("D")));
85   stream->BackUp(0);
86   EXPECT_THAT(CallNext(*stream), Optional(Eq("")));
87   EXPECT_THAT(CallNext(*stream), Optional(Eq("EFG")));
88   EXPECT_THAT(CallNext(*stream), Optional(Eq("")));
89   EXPECT_THAT(CallNext(*stream), Optional(Eq("")));
90   EXPECT_THAT(CallNext(*stream), Optional(Eq("HIJKLMN")));
91   stream->BackUp(2);
92   EXPECT_THAT(CallNext(*stream), Optional(Eq("MN")));
93   EXPECT_THAT(CallNext(*stream), Eq(absl::nullopt));
94 }
95 
96 #if GTEST_HAS_DEATH_TEST
TEST(TestZeroCopyInputStreamTest,BackUpChecksPreconditions)97 TEST(TestZeroCopyInputStreamTest, BackUpChecksPreconditions) {
98   std::vector<std::string> expected = {"ABC", "D", "EFG", "", "", "HIJKLMN"};
99   std::unique_ptr<ZeroCopyInputStream> stream =
100       std::make_unique<TestZeroCopyInputStream>(expected);
101 
102   EXPECT_DEATH(stream->BackUp(0),
103                "The last call was not a successful Next\\(\\)");
104   EXPECT_THAT(CallNext(*stream), Optional(Eq("ABC")));
105   EXPECT_DEATH(stream->BackUp(-1), "count must not be negative");
106   stream->BackUp(1);
107   EXPECT_DEATH(stream->BackUp(0),
108                "The last call was not a successful Next\\(\\)");
109   EXPECT_THAT(CallNext(*stream), Optional(Eq("C")));
110   EXPECT_THAT(CallNext(*stream), Optional(Eq("D")));
111   stream->Skip(1);
112   EXPECT_DEATH(stream->BackUp(0),
113                "The last call was not a successful Next\\(\\)");
114   EXPECT_THAT(CallNext(*stream), Optional(Eq("FG")));
115   EXPECT_THAT(CallNext(*stream), Optional(Eq("")));
116   EXPECT_THAT(CallNext(*stream), Optional(Eq("")));
117   EXPECT_THAT(CallNext(*stream), Optional(Eq("HIJKLMN")));
118   EXPECT_DEATH(stream->BackUp(8), "count must be within bounds of last buffer");
119   EXPECT_THAT(CallNext(*stream), Eq(absl::nullopt));
120   EXPECT_DEATH(stream->BackUp(0),
121                "The last call was not a successful Next\\(\\)");
122 }
123 #endif  // GTEST_HAS_DEATH_TEST
124 
TEST(TestZeroCopyInputStreamTest,SkipWorks)125 TEST(TestZeroCopyInputStreamTest, SkipWorks) {
126   std::vector<std::string> expected = {"ABC", "D", "EFG", "", "", "HIJKLMN"};
127   TestZeroCopyInputStream stream(expected);
128 
129   EXPECT_THAT(ReadLeftoverDoNotConsumeInput(stream),
130               ElementsAre("ABC", "D", "EFG", "", "", "HIJKLMN"));
131   // Skip nothing
132   EXPECT_TRUE(stream.Skip(0));
133   EXPECT_THAT(ReadLeftoverDoNotConsumeInput(stream),
134               ElementsAre("ABC", "D", "EFG", "", "", "HIJKLMN"));
135   // Skip less than one chunk
136   EXPECT_TRUE(stream.Skip(1));
137   EXPECT_THAT(ReadLeftoverDoNotConsumeInput(stream),
138               ElementsAre("BC", "D", "EFG", "", "", "HIJKLMN"));
139   // Skip exactly one chunk
140   EXPECT_TRUE(stream.Skip(2));
141   EXPECT_THAT(ReadLeftoverDoNotConsumeInput(stream),
142               ElementsAre("D", "EFG", "", "", "HIJKLMN"));
143   // Skip cross chunks
144   EXPECT_TRUE(stream.Skip(3));
145   EXPECT_THAT(ReadLeftoverDoNotConsumeInput(stream),
146               ElementsAre("G", "", "", "HIJKLMN"));
147   // Skip the rest
148   EXPECT_TRUE(stream.Skip(8));
149   EXPECT_THAT(ReadLeftoverDoNotConsumeInput(stream), ElementsAre());
150   // Skipping zero works on empty
151   EXPECT_TRUE(stream.Skip(0));
152   // but skipping non-zero does not
153   EXPECT_FALSE(stream.Skip(1));
154 }
155 
156 #if GTEST_HAS_DEATH_TEST
TEST(TestZeroCopyInputStreamTest,SkipChecksPreconditions)157 TEST(TestZeroCopyInputStreamTest, SkipChecksPreconditions) {
158   std::unique_ptr<ZeroCopyInputStream> stream =
159       std::make_unique<TestZeroCopyInputStream>(std::vector<std::string>{});
160   EXPECT_DEATH(stream->Skip(-1), "count must not be negative");
161 }
162 #endif  // GTEST_HAS_DEATH_TEST
163 
TEST(TestZeroCopyInputStreamTest,ByteCountWorks)164 TEST(TestZeroCopyInputStreamTest, ByteCountWorks) {
165   std::vector<std::string> expected = {"ABC", "D", "EFG", "", "", "HIJKLMN"};
166   TestZeroCopyInputStream stream(expected);
167   EXPECT_EQ(stream.ByteCount(), 0);
168   EXPECT_TRUE(stream.Skip(0));
169   EXPECT_EQ(stream.ByteCount(), 0);
170   EXPECT_TRUE(stream.Skip(1));
171   EXPECT_EQ(stream.ByteCount(), 1);
172   EXPECT_THAT(CallNext(stream), Optional(Eq("BC")));
173   EXPECT_EQ(stream.ByteCount(), 3);
174   stream.BackUp(1);
175   EXPECT_EQ(stream.ByteCount(), 2);
176   EXPECT_THAT(CallNext(stream), Optional(Eq("C")));
177   EXPECT_EQ(stream.ByteCount(), 3);
178   EXPECT_THAT(CallNext(stream), Optional(Eq("D")));
179   EXPECT_EQ(stream.ByteCount(), 4);
180   EXPECT_THAT(CallNext(stream), Optional(Eq("EFG")));
181   EXPECT_EQ(stream.ByteCount(), 7);
182   EXPECT_THAT(CallNext(stream), Optional(Eq("")));
183   EXPECT_EQ(stream.ByteCount(), 7);
184   EXPECT_THAT(CallNext(stream), Optional(Eq("")));
185   EXPECT_EQ(stream.ByteCount(), 7);
186   EXPECT_TRUE(stream.Skip(3));
187   EXPECT_EQ(stream.ByteCount(), 10);
188   EXPECT_TRUE(stream.Skip(4));
189   EXPECT_EQ(stream.ByteCount(), 14);
190 }
191 
192 }  // namespace
193 }  // namespace internal
194 }  // namespace io
195 }  // namespace protobuf
196 }  // namespace google
197