/Users/deen/code/yugabyte-db/src/yb/util/pb_util-test.cc
Line | Count | Source (jump to first uncovered line) |
1 | | // Licensed to the Apache Software Foundation (ASF) under one |
2 | | // or more contributor license agreements. See the NOTICE file |
3 | | // distributed with this work for additional information |
4 | | // regarding copyright ownership. The ASF licenses this file |
5 | | // to you under the Apache License, Version 2.0 (the |
6 | | // "License"); you may not use this file except in compliance |
7 | | // with the License. You may obtain a copy of the License at |
8 | | // |
9 | | // http://www.apache.org/licenses/LICENSE-2.0 |
10 | | // |
11 | | // Unless required by applicable law or agreed to in writing, |
12 | | // software distributed under the License is distributed on an |
13 | | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
14 | | // KIND, either express or implied. See the License for the |
15 | | // specific language governing permissions and limitations |
16 | | // under the License. |
17 | | // |
18 | | // The following only applies to changes made to this file as part of YugaByte development. |
19 | | // |
20 | | // Portions Copyright (c) YugaByte, Inc. |
21 | | // |
22 | | // Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except |
23 | | // in compliance with the License. You may obtain a copy of the License at |
24 | | // |
25 | | // http://www.apache.org/licenses/LICENSE-2.0 |
26 | | // |
27 | | // Unless required by applicable law or agreed to in writing, software distributed under the License |
28 | | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
29 | | // or implied. See the License for the specific language governing permissions and limitations |
30 | | // under the License. |
31 | | // |
32 | | |
33 | | #include <memory> |
34 | | #include <sstream> |
35 | | #include <string> |
36 | | #include <vector> |
37 | | |
38 | | #include <google/protobuf/descriptor.pb.h> |
39 | | #include <gtest/gtest.h> |
40 | | |
41 | | #include "yb/util/env_util.h" |
42 | | #include "yb/util/memenv/memenv.h" |
43 | | #include "yb/util/pb_util-internal.h" |
44 | | #include "yb/util/pb_util.h" |
45 | | #include "yb/util/proto_container_test.pb.h" |
46 | | #include "yb/util/proto_container_test2.pb.h" |
47 | | #include "yb/util/proto_container_test3.pb.h" |
48 | | #include "yb/util/protobuf_util.h" |
49 | | #include "yb/util/result.h" |
50 | | #include "yb/util/status.h" |
51 | | #include "yb/util/test_macros.h" |
52 | | #include "yb/util/test_util.h" |
53 | | |
54 | | namespace yb { |
55 | | namespace pb_util { |
56 | | |
57 | | using google::protobuf::FileDescriptorSet; |
58 | | using internal::WritableFileOutputStream; |
59 | | using std::ostringstream; |
60 | | using std::shared_ptr; |
61 | | using std::string; |
62 | | using std::vector; |
63 | | |
64 | | static const char* kTestFileName = "pb_container.meta"; |
65 | | static const char* kTestKeyvalName = "my-key"; |
66 | | static const int kTestKeyvalValue = 1; |
67 | | static const std::string kTestString = "test-string"; |
68 | | |
69 | | class TestPBUtil : public YBTest { |
70 | | public: |
71 | 10 | void SetUp() override { |
72 | 10 | YBTest::SetUp(); |
73 | 10 | path_ = GetTestPath(kTestFileName); |
74 | 10 | } |
75 | | |
76 | | protected: |
77 | | // Create a container file with expected values. |
78 | | // Since this is a unit test class, and we want it to be fast, we do not |
79 | | // fsync by default. |
80 | | Status CreateKnownGoodContainerFile(CreateMode create = OVERWRITE, |
81 | | SyncMode sync = NO_SYNC); |
82 | | |
83 | | // XORs the data in the specified range of the file at the given path. |
84 | | Status BitFlipFileByteRange(const string& path, uint64_t offset, uint64_t length); |
85 | | |
86 | | void DumpPBCToString(const string& path, bool oneline_output, string* ret); |
87 | | |
88 | | // Output file name for most unit tests. |
89 | | string path_; |
90 | | }; |
91 | | |
92 | 12 | Status TestPBUtil::CreateKnownGoodContainerFile(CreateMode create, SyncMode sync) { |
93 | 12 | ProtoContainerTestPB test_pb; |
94 | 12 | test_pb.set_name(kTestKeyvalName); |
95 | 12 | test_pb.set_value(kTestKeyvalValue); |
96 | 12 | return WritePBContainerToPath(env_.get(), path_, test_pb, create, sync); |
97 | 12 | } |
98 | | |
99 | 5 | Status TestPBUtil::BitFlipFileByteRange(const string& path, uint64_t offset, uint64_t length) { |
100 | 5 | faststring buf; |
101 | | // Read the data from disk. |
102 | 5 | { |
103 | 5 | std::unique_ptr<RandomAccessFile> file; |
104 | 5 | RETURN_NOT_OK(env_->NewRandomAccessFile(path, &file)); |
105 | 5 | uint64_t size = VERIFY_RESULT(file->Size()); |
106 | 5 | Slice slice; |
107 | 5 | faststring scratch; |
108 | 5 | scratch.resize(size); |
109 | 5 | RETURN_NOT_OK(env_util::ReadFully(file.get(), 0, size, &slice, scratch.data())); |
110 | 5 | buf.append(slice.data(), slice.size()); |
111 | 5 | } |
112 | | |
113 | | // Flip the bits. |
114 | 15 | for (uint64_t i = 0; i < length; i++) { |
115 | 10 | uint8_t* addr = buf.data() + offset + i; |
116 | 10 | *addr = ~*addr; |
117 | 10 | } |
118 | | |
119 | | // Write the data back to disk. |
120 | 5 | std::unique_ptr<WritableFile> file; |
121 | 5 | RETURN_NOT_OK(env_->NewWritableFile(path, &file)); |
122 | 5 | RETURN_NOT_OK(file->Append(buf)); |
123 | 5 | RETURN_NOT_OK(file->Close()); |
124 | | |
125 | 5 | return Status::OK(); |
126 | 5 | } |
127 | | |
128 | 1 | TEST_F(TestPBUtil, TestWritableFileOutputStream) { |
129 | 1 | std::unique_ptr<Env> env(NewMemEnv(Env::Default())); |
130 | 1 | shared_ptr<WritableFile> file; |
131 | 1 | ASSERT_OK(env_util::OpenFileForWrite(env.get(), "/test", &file)); |
132 | | |
133 | 1 | WritableFileOutputStream stream(file.get(), 4096); |
134 | | |
135 | 1 | void* buf; |
136 | 1 | int size; |
137 | | |
138 | | // First call should yield the whole buffer. |
139 | 1 | ASSERT_TRUE(stream.Next(&buf, &size)); |
140 | 1 | ASSERT_EQ(4096, size); |
141 | 1 | ASSERT_EQ(4096, stream.ByteCount()); |
142 | | |
143 | | // Backup 1000 and the next call should yield 1000 |
144 | 1 | stream.BackUp(1000); |
145 | 1 | ASSERT_EQ(3096, stream.ByteCount()); |
146 | | |
147 | 1 | ASSERT_TRUE(stream.Next(&buf, &size)); |
148 | 1 | ASSERT_EQ(1000, size); |
149 | | |
150 | | // Another call should flush and yield a new buffer of 4096 |
151 | 1 | ASSERT_TRUE(stream.Next(&buf, &size)); |
152 | 1 | ASSERT_EQ(4096, size); |
153 | 1 | ASSERT_EQ(8192, stream.ByteCount()); |
154 | | |
155 | | // Should be able to backup to 7192 |
156 | 1 | stream.BackUp(1000); |
157 | 1 | ASSERT_EQ(7192, stream.ByteCount()); |
158 | | |
159 | | // Flushing shouldn't change written count. |
160 | 1 | ASSERT_TRUE(stream.Flush()); |
161 | 1 | ASSERT_EQ(7192, stream.ByteCount()); |
162 | | |
163 | | // Since we just flushed, we should get another full buffer. |
164 | 1 | ASSERT_TRUE(stream.Next(&buf, &size)); |
165 | 1 | ASSERT_EQ(4096, size); |
166 | 1 | ASSERT_EQ(7192 + 4096, stream.ByteCount()); |
167 | | |
168 | 1 | ASSERT_TRUE(stream.Flush()); |
169 | | |
170 | 1 | ASSERT_EQ(stream.ByteCount(), file->Size()); |
171 | 1 | } |
172 | | |
173 | | // Basic read/write test. |
174 | 1 | TEST_F(TestPBUtil, TestPBContainerSimple) { |
175 | | // Exercise both the SYNC and NO_SYNC codepaths, despite the fact that we |
176 | | // aren't able to observe a difference in the test. |
177 | 1 | vector<SyncMode> modes = { SYNC, NO_SYNC }; |
178 | 2 | for (SyncMode mode : modes) { |
179 | | |
180 | | // Write the file. |
181 | 2 | ASSERT_OK(CreateKnownGoodContainerFile(NO_OVERWRITE, mode)); |
182 | | |
183 | | // Read it back, should validate and contain the expected values. |
184 | 2 | ProtoContainerTestPB test_pb; |
185 | 2 | ASSERT_OK(ReadPBContainerFromPath(env_.get(), path_, &test_pb)); |
186 | 2 | ASSERT_EQ(kTestKeyvalName, test_pb.name()); |
187 | 2 | ASSERT_EQ(kTestKeyvalValue, test_pb.value()); |
188 | | |
189 | | // Delete the file. |
190 | 2 | ASSERT_OK(env_->DeleteFile(path_)); |
191 | 2 | } |
192 | 1 | } |
193 | | |
194 | | // Corruption / various failure mode test. |
195 | 1 | TEST_F(TestPBUtil, TestPBContainerCorruption) { |
196 | | // Test that we indicate when the file does not exist. |
197 | 1 | ProtoContainerTestPB test_pb; |
198 | 1 | Status s = ReadPBContainerFromPath(env_.get(), path_, &test_pb); |
199 | 2 | ASSERT_TRUE(s.IsNotFound()) << "Should not be found: " << path_ << ": " << s.ToString(); |
200 | | |
201 | | // Test that an empty file looks like corruption. |
202 | 1 | { |
203 | | // Create the empty file. |
204 | 1 | std::unique_ptr<WritableFile> file; |
205 | 1 | ASSERT_OK(env_->NewWritableFile(path_, &file)); |
206 | 1 | ASSERT_OK(file->Close()); |
207 | 1 | } |
208 | 1 | s = ReadPBContainerFromPath(env_.get(), path_, &test_pb); |
209 | 2 | ASSERT_TRUE(s.IsCorruption()) << "Should be zero length: " << path_ << ": " << s.ToString(); |
210 | 1 | ASSERT_STR_CONTAINS(s.ToString(), "File size not large enough to be valid"); |
211 | | |
212 | | // Test truncated file. |
213 | 1 | ASSERT_OK(CreateKnownGoodContainerFile()); |
214 | 1 | uint64_t known_good_size = ASSERT_RESULT(env_->GetFileSize(path_)); |
215 | 1 | int ret = truncate(path_.c_str(), known_good_size - 2); |
216 | 1 | if (ret != 0) { |
217 | 0 | PLOG(ERROR) << "truncate() of file " << path_ << " failed"; |
218 | 0 | FAIL(); |
219 | 0 | } |
220 | 1 | s = ReadPBContainerFromPath(env_.get(), path_, &test_pb); |
221 | 2 | ASSERT_TRUE(s.IsCorruption()) << "Should be incorrect size: " << path_ << ": " << s.ToString(); |
222 | 1 | ASSERT_STR_CONTAINS(s.ToString(), "File size not large enough to be valid"); |
223 | | |
224 | | // Test corrupted magic. |
225 | 1 | ASSERT_OK(CreateKnownGoodContainerFile()); |
226 | 1 | ASSERT_OK(BitFlipFileByteRange(path_, 0, 2)); |
227 | 1 | s = ReadPBContainerFromPath(env_.get(), path_, &test_pb); |
228 | 2 | ASSERT_TRUE(s.IsCorruption()) << "Should have invalid magic: " << path_ << ": " << s.ToString(); |
229 | 1 | ASSERT_STR_CONTAINS(s.ToString(), "Invalid magic number"); |
230 | | |
231 | | // Test corrupted version. |
232 | 1 | ASSERT_OK(CreateKnownGoodContainerFile()); |
233 | 1 | ASSERT_OK(BitFlipFileByteRange(path_, 8, 2)); |
234 | 1 | s = ReadPBContainerFromPath(env_.get(), path_, &test_pb); |
235 | 2 | ASSERT_TRUE(s.IsNotSupported()) << "Should have unsupported version number: " << path_ << ": " |
236 | 2 | << s.ToString(); |
237 | 1 | ASSERT_STR_CONTAINS(s.ToString(), "we only support version 1"); |
238 | | |
239 | | // Test corrupted size. |
240 | 1 | ASSERT_OK(CreateKnownGoodContainerFile()); |
241 | 1 | ASSERT_OK(BitFlipFileByteRange(path_, 12, 2)); |
242 | 1 | s = ReadPBContainerFromPath(env_.get(), path_, &test_pb); |
243 | 2 | ASSERT_TRUE(s.IsCorruption()) << "Should be incorrect size: " << path_ << ": " << s.ToString(); |
244 | 1 | ASSERT_STR_CONTAINS(s.ToString(), "File size not large enough to be valid"); |
245 | | |
246 | | // Test corrupted data (looks like bad checksum). |
247 | 1 | ASSERT_OK(CreateKnownGoodContainerFile()); |
248 | 1 | ASSERT_OK(BitFlipFileByteRange(path_, 16, 2)); |
249 | 1 | s = ReadPBContainerFromPath(env_.get(), path_, &test_pb); |
250 | 2 | ASSERT_TRUE(s.IsCorruption()) << "Should be incorrect checksum: " << path_ << ": " |
251 | 2 | << s.ToString(); |
252 | 1 | ASSERT_STR_CONTAINS(s.ToString(), "Incorrect checksum"); |
253 | | |
254 | | // Test corrupted checksum. |
255 | 1 | ASSERT_OK(CreateKnownGoodContainerFile()); |
256 | 1 | ASSERT_OK(BitFlipFileByteRange(path_, known_good_size - 4, 2)); |
257 | 1 | s = ReadPBContainerFromPath(env_.get(), path_, &test_pb); |
258 | 2 | ASSERT_TRUE(s.IsCorruption()) << "Should be incorrect checksum: " << path_ << ": " |
259 | 2 | << s.ToString(); |
260 | 1 | ASSERT_STR_CONTAINS(s.ToString(), "Incorrect checksum"); |
261 | 1 | } |
262 | | |
263 | 1 | TEST_F(TestPBUtil, TestMultipleMessages) { |
264 | 1 | ProtoContainerTestPB pb; |
265 | 1 | pb.set_name("foo"); |
266 | 1 | pb.set_note("bar"); |
267 | | |
268 | 1 | std::unique_ptr<WritableFile> writer; |
269 | 1 | ASSERT_OK(env_->NewWritableFile(path_, &writer)); |
270 | 1 | WritablePBContainerFile pb_writer(std::move(writer)); |
271 | 1 | ASSERT_OK(pb_writer.Init(pb)); |
272 | | |
273 | 11 | for (int i = 0; i < 10; i++) { |
274 | 10 | pb.set_value(i); |
275 | 10 | ASSERT_OK(pb_writer.Append(pb)); |
276 | 10 | } |
277 | 1 | ASSERT_OK(pb_writer.Close()); |
278 | | |
279 | 1 | int pbs_read = 0; |
280 | 1 | std::unique_ptr<RandomAccessFile> reader; |
281 | 1 | ASSERT_OK(env_->NewRandomAccessFile(path_, &reader)); |
282 | 1 | ReadablePBContainerFile pb_reader(std::move(reader)); |
283 | 1 | ASSERT_OK(pb_reader.Init()); |
284 | 11 | for (int i = 0;; i++) { |
285 | 11 | ProtoContainerTestPB read_pb; |
286 | 11 | Status s = pb_reader.ReadNextPB(&read_pb); |
287 | 11 | if (s.IsEndOfFile()) { |
288 | 1 | break; |
289 | 1 | } |
290 | 10 | ASSERT_OK(s); |
291 | 10 | ASSERT_EQ(pb.name(), read_pb.name()); |
292 | 10 | ASSERT_EQ(read_pb.value(), i); |
293 | 10 | ASSERT_EQ(pb.note(), read_pb.note()); |
294 | 10 | pbs_read++; |
295 | 10 | } |
296 | 1 | ASSERT_EQ(10, pbs_read); |
297 | 1 | ASSERT_OK(pb_reader.Close()); |
298 | 1 | } |
299 | | |
300 | 1 | TEST_F(TestPBUtil, TestInterleavedReadWrite) { |
301 | 1 | ProtoContainerTestPB pb; |
302 | 1 | pb.set_name("foo"); |
303 | 1 | pb.set_note("bar"); |
304 | | |
305 | | // Open the file for writing and reading. |
306 | 1 | std::unique_ptr<WritableFile> writer; |
307 | 1 | ASSERT_OK(env_->NewWritableFile(path_, &writer)); |
308 | 1 | WritablePBContainerFile pb_writer(std::move(writer)); |
309 | 1 | std::unique_ptr<RandomAccessFile> reader; |
310 | 1 | ASSERT_OK(env_->NewRandomAccessFile(path_, &reader)); |
311 | 1 | ReadablePBContainerFile pb_reader(std::move(reader)); |
312 | | |
313 | | // Write the header (writer) and validate it (reader). |
314 | 1 | ASSERT_OK(pb_writer.Init(pb)); |
315 | 1 | ASSERT_OK(pb_reader.Init()); |
316 | | |
317 | 11 | for (int i = 0; i < 10; i++) { |
318 | | // Write a message and read it back. |
319 | 10 | pb.set_value(i); |
320 | 10 | ASSERT_OK(pb_writer.Append(pb)); |
321 | 10 | ProtoContainerTestPB read_pb; |
322 | 10 | ASSERT_OK(pb_reader.ReadNextPB(&read_pb)); |
323 | 10 | ASSERT_EQ(pb.name(), read_pb.name()); |
324 | 10 | ASSERT_EQ(read_pb.value(), i); |
325 | 10 | ASSERT_EQ(pb.note(), read_pb.note()); |
326 | 10 | } |
327 | | |
328 | | // After closing the writer, the reader should be out of data. |
329 | 1 | ASSERT_OK(pb_writer.Close()); |
330 | 1 | ASSERT_TRUE(pb_reader.ReadNextPB(nullptr).IsEndOfFile()); |
331 | 1 | ASSERT_OK(pb_reader.Close()); |
332 | 1 | } |
333 | | |
334 | 1 | TEST_F(TestPBUtil, TestPopulateDescriptorSet) { |
335 | 1 | { |
336 | | // No dependencies --> just one proto. |
337 | 1 | ProtoContainerTestPB pb; |
338 | 1 | FileDescriptorSet protos; |
339 | 1 | WritablePBContainerFile::PopulateDescriptorSet( |
340 | 1 | pb.GetDescriptor()->file(), &protos); |
341 | 1 | ASSERT_EQ(1, protos.file_size()); |
342 | 1 | } |
343 | 1 | { |
344 | | // One direct dependency --> two protos. |
345 | 1 | ProtoContainerTest2PB pb; |
346 | 1 | FileDescriptorSet protos; |
347 | 1 | WritablePBContainerFile::PopulateDescriptorSet( |
348 | 1 | pb.GetDescriptor()->file(), &protos); |
349 | 1 | ASSERT_EQ(2, protos.file_size()); |
350 | 1 | } |
351 | 1 | { |
352 | | // One direct and one indirect dependency --> three protos. |
353 | 1 | ProtoContainerTest3PB pb; |
354 | 1 | FileDescriptorSet protos; |
355 | 1 | WritablePBContainerFile::PopulateDescriptorSet( |
356 | 1 | pb.GetDescriptor()->file(), &protos); |
357 | 1 | ASSERT_EQ(3, protos.file_size()); |
358 | 1 | } |
359 | 1 | } |
360 | | |
361 | | void TestPBUtil::DumpPBCToString(const string& path, bool oneline_output, |
362 | 2 | string* ret) { |
363 | 2 | std::unique_ptr<RandomAccessFile> reader; |
364 | 2 | ASSERT_OK(env_->NewRandomAccessFile(path, &reader)); |
365 | 2 | ReadablePBContainerFile pb_reader(std::move(reader)); |
366 | 2 | ASSERT_OK(pb_reader.Init()); |
367 | 2 | ostringstream oss; |
368 | 2 | ASSERT_OK(pb_reader.Dump(&oss, oneline_output)); |
369 | 2 | ASSERT_OK(pb_reader.Close()); |
370 | 2 | *ret = oss.str(); |
371 | 2 | } |
372 | | |
373 | 1 | TEST_F(TestPBUtil, TestDumpPBContainer) { |
374 | 1 | const char* kExpectedOutput = |
375 | 1 | "yb.ProtoContainerTest3PB 0\n" |
376 | 1 | "-------\n" |
377 | 1 | "record_one {\n" |
378 | 1 | " name: \"foo\"\n" |
379 | 1 | " value: 0\n" |
380 | 1 | "}\n" |
381 | 1 | "record_two {\n" |
382 | 1 | " record {\n" |
383 | 1 | " name: \"foo\"\n" |
384 | 1 | " value: 0\n" |
385 | 1 | " }\n" |
386 | 1 | "}\n" |
387 | 1 | "\n" |
388 | 1 | "yb.ProtoContainerTest3PB 1\n" |
389 | 1 | "-------\n" |
390 | 1 | "record_one {\n" |
391 | 1 | " name: \"foo\"\n" |
392 | 1 | " value: 1\n" |
393 | 1 | "}\n" |
394 | 1 | "record_two {\n" |
395 | 1 | " record {\n" |
396 | 1 | " name: \"foo\"\n" |
397 | 1 | " value: 2\n" |
398 | 1 | " }\n" |
399 | 1 | "}\n\n"; |
400 | | |
401 | 1 | const char* kExpectedOutputShort = |
402 | 1 | "0\trecord_one { name: \"foo\" value: 0 } record_two { record { name: \"foo\" value: 0 } }\n" |
403 | 1 | "1\trecord_one { name: \"foo\" value: 1 } record_two { record { name: \"foo\" value: 2 } }\n"; |
404 | | |
405 | 1 | ProtoContainerTest3PB pb; |
406 | 1 | pb.mutable_record_one()->set_name("foo"); |
407 | 1 | pb.mutable_record_two()->mutable_record()->set_name("foo"); |
408 | | |
409 | 1 | std::unique_ptr<WritableFile> writer; |
410 | 1 | ASSERT_OK(env_->NewWritableFile(path_, &writer)); |
411 | 1 | WritablePBContainerFile pb_writer(std::move(writer)); |
412 | 1 | ASSERT_OK(pb_writer.Init(pb)); |
413 | | |
414 | 3 | for (int i = 0; i < 2; i++) { |
415 | 2 | pb.mutable_record_one()->set_value(i); |
416 | 2 | pb.mutable_record_two()->mutable_record()->set_value(i*2); |
417 | 2 | ASSERT_OK(pb_writer.Append(pb)); |
418 | 2 | } |
419 | 1 | ASSERT_OK(pb_writer.Close()); |
420 | | |
421 | 1 | string output; |
422 | 1 | DumpPBCToString(path_, false, &output); |
423 | 1 | ASSERT_STREQ(kExpectedOutput, output.c_str()); |
424 | | |
425 | 1 | DumpPBCToString(path_, true, &output); |
426 | 1 | ASSERT_STREQ(kExpectedOutputShort, output.c_str()); |
427 | 1 | } |
428 | | |
429 | 1 | TEST_F(TestPBUtil, TestOverwriteExistingPB) { |
430 | 1 | ASSERT_OK(CreateKnownGoodContainerFile(NO_OVERWRITE)); |
431 | 1 | ASSERT_TRUE(CreateKnownGoodContainerFile(NO_OVERWRITE).IsAlreadyPresent()); |
432 | 1 | ASSERT_OK(CreateKnownGoodContainerFile(OVERWRITE)); |
433 | 1 | ASSERT_OK(CreateKnownGoodContainerFile(OVERWRITE)); |
434 | 1 | } |
435 | | |
436 | | PB_ENUM_FORMATTERS(TestPBEnum) |
437 | | |
438 | 1 | TEST_F(TestPBUtil, TestEnumToString) { |
439 | 1 | { |
440 | 1 | std::stringstream ss; |
441 | 1 | ss << TestPBEnum::FOO; |
442 | 1 | ASSERT_EQ("FOO", ss.str()); |
443 | 1 | ASSERT_EQ("FOO", PBEnumToString(TestPBEnum::FOO)); |
444 | 1 | ASSERT_EQ("FOO", ToString(TestPBEnum::FOO)); |
445 | 1 | } |
446 | | |
447 | 1 | #if !defined(ADDRESS_SANITIZER) |
448 | 1 | { |
449 | 1 | std::stringstream ss; |
450 | 1 | const auto kInvalidValue = static_cast<TestPBEnum>(10); |
451 | 1 | ss << kInvalidValue; |
452 | 1 | const char* kExpectedStr = "<unknown TestPBEnum : 10>"; |
453 | 1 | ASSERT_EQ(kExpectedStr, ss.str()); |
454 | 1 | ASSERT_EQ(kExpectedStr, PBEnumToString(kInvalidValue)); |
455 | 1 | ASSERT_EQ(kExpectedStr, ToString(kInvalidValue)); |
456 | 1 | } |
457 | 1 | #endif |
458 | 1 | } |
459 | | |
460 | 1 | TEST_F(TestPBUtil, TestPBRequiredToRepeated) { |
461 | | // Write the file with required fields. |
462 | 1 | { |
463 | 1 | TestObjectRequiredPB pb; |
464 | 1 | pb.set_string1(kTestString + "1"); |
465 | 1 | pb.set_string2(kTestString + "2"); |
466 | 1 | pb.mutable_record()->set_text(kTestString); |
467 | 1 | ASSERT_OK(WritePBContainerToPath(env_.get(), path_, pb, OVERWRITE, SYNC)); |
468 | 1 | } |
469 | | |
470 | | // Read it back as repeated fields, should validate and contain the expected values. |
471 | 1 | TestObjectRepeatedPB pb; |
472 | 1 | ASSERT_OK(ReadPBContainerFromPath(env_.get(), path_, &pb)); |
473 | 1 | ASSERT_EQ(1, pb.string1_size()); |
474 | 1 | ASSERT_EQ(1, pb.string2_size()); |
475 | 1 | ASSERT_EQ(1, pb.record_size()); |
476 | 1 | ASSERT_EQ(kTestString + "1", pb.string1()[0]); |
477 | 1 | ASSERT_EQ(kTestString + "2", pb.string2()[0]); |
478 | 1 | ASSERT_EQ(kTestString, pb.record()[0].text()[0]); |
479 | | |
480 | | // Delete the file. |
481 | 1 | ASSERT_OK(env_->DeleteFile(path_)); |
482 | 1 | } |
483 | | |
484 | | } // namespace pb_util |
485 | | } // namespace yb |