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