inlined_string_field_unittest.cc
Go to the documentation of this file.
1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc. All rights reserved.
3 // https://developers.google.com/protocol-buffers/
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are
7 // met:
8 //
9 // * Redistributions of source code must retain the above copyright
10 // notice, this list of conditions and the following disclaimer.
11 // * Redistributions in binary form must reproduce the above
12 // copyright notice, this list of conditions and the following disclaimer
13 // in the documentation and/or other materials provided with the
14 // distribution.
15 // * Neither the name of Google Inc. nor the names of its
16 // contributors may be used to endorse or promote products derived from
17 // this software without specific prior written permission.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 
31 #include <google/protobuf/inlined_string_field.h>
32 
33 #include <algorithm>
34 #include <cstdlib>
35 #include <cstring>
36 #include <memory>
37 #include <string>
38 #include <vector>
39 
40 #include <google/protobuf/stubs/logging.h>
41 #include <google/protobuf/stubs/common.h>
42 #include <google/protobuf/io/coded_stream.h>
43 #include <google/protobuf/io/zero_copy_stream_impl.h>
44 #include <google/protobuf/arenastring.h>
45 #include <gtest/gtest.h>
46 #include <google/protobuf/stubs/strutil.h>
47 
48 
49 namespace google {
50 namespace protobuf {
51 
52 using internal::ArenaStringPtr;
53 using internal::InlinedStringField;
54 
55 static std::string WrapString(const char* value) { return value; }
56 
57 namespace {
58 
59 const uint32 kMask = ~0x00000001u;
60 const uint32 kMask1 = ~0x00000004u;
61 const uint32 kMask2 = ~0x00000020u;
62 
63 TEST(InlinedStringFieldTest, SetOnHeap) {
64  InlinedStringField field;
65  uint32 donating_states = 0;
66  const std::string kDefaultValue = "default";
67  field.Set(&kDefaultValue, WrapString("Test short"), nullptr, false,
68  &donating_states, kMask);
69  EXPECT_EQ(std::string("Test short"), field.Get());
70  field.Set(&kDefaultValue, WrapString("Test long long long long value"),
71  nullptr, false, &donating_states, kMask);
72  EXPECT_EQ(std::string("Test long long long long value"), field.Get());
73 }
74 
75 TEST(InlinedStringFieldTest, SetRvalueOnHeap) {
76  InlinedStringField field;
77  uint32 donating_states = 0;
78  std::string string_moved = "Moved long long long long string 1";
79  field.Set(nullptr, std::move(string_moved), nullptr, false, &donating_states,
80  kMask);
81  EXPECT_EQ("Moved long long long long string 1", field.Get());
82  EXPECT_EQ(donating_states & ~kMask1, 0);
83 }
84 
85 TEST(InlinedStringFieldTest, UnsafeMutablePointerThenRelease) {
86  InlinedStringField field;
87  const std::string kDefaultValue = "default";
88  std::string* mut = field.UnsafeMutablePointer();
89  // The address of inlined string doesn't change behind the scene.
90  EXPECT_EQ(mut, field.UnsafeMutablePointer());
91  EXPECT_EQ(mut, &field.Get());
92  EXPECT_EQ(std::string(""), *mut);
93  *mut = "Test long long long long value"; // ensure string allocates
94  EXPECT_EQ(std::string("Test long long long long value"), field.Get());
95 
96  std::string* released = field.ReleaseNonDefaultNoArena(&kDefaultValue);
97  EXPECT_EQ("Test long long long long value", *released);
98  // Default value is ignored.
99  EXPECT_EQ("", field.Get());
100  delete released;
101 }
102 
103 // When donating mechanism is enabled:
104 // - Initially, the string is donated.
105 // - After lvalue Set: the string is still donated.
106 // - After Mutable: the string is undonated. The data buffer of the string is a
107 // new buffer on the heap.
108 TEST(InlinedStringFieldTest, ArenaSetThenMutable) {
109  Arena arena;
110  auto* field_arena = Arena::CreateMessage<InlinedStringField>(&arena);
111  uint32 donating_states = ~0u;
112  const std::string kDefaultValue = "default";
113  field_arena->Set(&kDefaultValue, WrapString("Test short"), &arena,
114  /*donated=*/true, &donating_states, kMask1);
115  EXPECT_EQ(std::string("Test short"), field_arena->Get());
116  field_arena->Set(&kDefaultValue, "Test long long long long value", &arena,
117  /*donated=*/(donating_states & ~kMask1) != 0,
118  &donating_states, kMask1);
119  EXPECT_EQ(std::string("Test long long long long value"), field_arena->Get());
120 #if GOOGLE_PROTOBUF_INTERNAL_DONATE_STEAL_INLINE
121  EXPECT_NE(donating_states & ~kMask1, 0); // donate.
122 #endif
123 
124  const std::string* old_string = &field_arena->Get();
125  const char* old_data = old_string->data();
126  (void)old_data;
127  std::string* mut = field_arena->Mutable(
129  /*donated=*/(donating_states & ~kMask1) != 0, &donating_states, kMask1);
130  EXPECT_EQ(old_string, mut);
131 #if GOOGLE_PROTOBUF_INTERNAL_DONATE_STEAL_INLINE
132  EXPECT_EQ(donating_states & ~kMask1, 0);
133  EXPECT_NE(old_data, mut->data()); // The data buffer of the mutated string is
134  // a new buffer on the heap.
135 #endif
136  *mut = "Test an even longer long long long long value";
137  EXPECT_EQ(std::string("Test an even longer long long long long value"),
138  field_arena->Get());
139  EXPECT_EQ(&field_arena->Get(), mut);
140 }
141 
142 // Release doesn't change the donating state.
143 // When donating mechanism is enabled:
144 // - Initially, the string is donated.
145 // - Then lvalue Set: the string is still donated.
146 // - Then Release: the string is cleared, and still donated.
147 // - Then Mutable: the string is undonated.
148 // - Then Release: the string is still undonated.
149 TEST(InlinedStringFieldTest, ArenaRelease) {
150  Arena arena;
151  auto* field_arena = Arena::CreateMessage<InlinedStringField>(&arena);
152  uint32 donating_states = ~0u;
153  const std::string kDefaultValue = "default";
154  field_arena->Set(&kDefaultValue, WrapString("Test short"), &arena,
155  /*donated=*/true, &donating_states, kMask1);
156  std::string* released = field_arena->Release(
157  &kDefaultValue, &arena, /*donated=*/(donating_states & ~kMask1) != 0);
158  EXPECT_EQ("Test short", *released);
159  EXPECT_EQ("", field_arena->Get());
160  EXPECT_NE(released, &field_arena->Get());
161 #if GOOGLE_PROTOBUF_INTERNAL_DONATE_STEAL_INLINE
162  EXPECT_NE(donating_states & ~kMask1, 0); // still donated.
163 #endif
164  delete released;
165 
166  std::string* mut = field_arena->Mutable(
168  /*donated=*/(donating_states & ~kMask1) != 0u, &donating_states, kMask1);
169  *mut = "Test long long long long value";
170  std::string* released2 =
171  field_arena->Release(&kDefaultValue, &arena,
172  /*donated=*/(donating_states & ~kMask1) != 0);
173  EXPECT_EQ("Test long long long long value", *released2);
174  EXPECT_EQ("", field_arena->Get());
175 #if GOOGLE_PROTOBUF_INTERNAL_DONATE_STEAL_INLINE
176  EXPECT_EQ(donating_states & ~kMask1, 0); // undonated.
177 #endif
178  delete released2;
179 }
180 
181 // Rvalue Set always undoantes a donated string.
182 TEST(InlinedStringFieldTest, SetRvalueArena) {
183  Arena arena;
184  auto* field1_arena = Arena::CreateMessage<InlinedStringField>(&arena);
185  auto* field2_arena = Arena::CreateMessage<InlinedStringField>(&arena);
186  uint32 donating_states = ~0u;
187  const std::string kDefaultValue = "default";
188 
189  std::string string_moved = "Moved long long long long string 1";
190  field1_arena->Set(nullptr, std::move(string_moved), &arena, true,
191  &donating_states, kMask1);
192  EXPECT_EQ("Moved long long long long string 1", field1_arena->Get());
193 #if GOOGLE_PROTOBUF_INTERNAL_DONATE_STEAL_INLINE
194  EXPECT_EQ(donating_states & ~kMask1, 0); // Undonate.
195 #endif
196 
197  field2_arena->Set(nullptr, std::string("string 2 on heap"), &arena, true,
198  &donating_states, kMask);
199  EXPECT_EQ("string 2 on heap", field2_arena->Get());
200 #if GOOGLE_PROTOBUF_INTERNAL_DONATE_STEAL_INLINE
201  EXPECT_EQ(donating_states & ~kMask, 0); // Undonated.
202 #endif
203 }
204 
205 // Tests SetAllocated for non-arena string fields and arena string fields.
206 TEST(InlinedStringFieldTest, SetAllocated) {
207  InlinedStringField field;
208  Arena arena;
209  auto* field1_arena = Arena::CreateMessage<InlinedStringField>(&arena);
210  auto* field2_arena = Arena::CreateMessage<InlinedStringField>(&arena);
211  uint32 donating_states = ~0u;
212  const std::string kDefaultValue = "default";
213 
214  // The string in field is on heap.
215  field.Set(&kDefaultValue, WrapString("String on heap"), nullptr, false,
216  &donating_states, kMask);
217  auto* allocated = new std::string("Allocated string on heap");
218  field.SetAllocatedNoArena(&kDefaultValue, allocated);
219  EXPECT_EQ("Allocated string on heap", field.Get());
220 
221  // The string in field1_arena is on arena (aka. donated).
222  field1_arena->Set(&kDefaultValue, WrapString("String 1 on arena"), &arena,
223  true, &donating_states, kMask1);
224  *field1_arena->Mutable(ArenaStringPtr::EmptyDefault{}, &arena,
225  (donating_states & ~kMask1) != 0, &donating_states,
226  kMask1) = "Mutated string 1 is now on heap long long";
227  // After Mutable, the string is undonated.
228  allocated = new std::string("Allocated string on heap long long long");
229  field1_arena->SetAllocated(&kDefaultValue, allocated, &arena,
230  (donating_states & ~kMask1) != 0, &donating_states,
231  kMask1);
232  EXPECT_EQ("Allocated string on heap long long long", field1_arena->Get());
233 #if GOOGLE_PROTOBUF_INTERNAL_DONATE_STEAL_INLINE
234  EXPECT_EQ(donating_states & ~kMask1, 0); // Still undonated.
235 #endif
236 
237  // The string in field2_arena is on arena (aka. donated).
238  field2_arena->Set(&kDefaultValue, WrapString("String 2 on arena long long"),
239  &arena, true, &donating_states,
240  kMask2); // Still donated.
241  allocated = new std::string("Allocated string on heap long long long 2");
242  field2_arena->SetAllocated(&kDefaultValue, allocated, &arena, true,
243  &donating_states, kMask2);
244  EXPECT_EQ("Allocated string on heap long long long 2", field2_arena->Get());
245 #if GOOGLE_PROTOBUF_INTERNAL_DONATE_STEAL_INLINE
246  EXPECT_EQ(donating_states & ~kMask2, 0); // Undonated.
247 #endif
248 }
249 
250 // Tests Swap for non-arena string fields and arena string fields.
251 TEST(InlinedStringFieldTest, Swap) {
252  // Swap should only be called when the from and to are on the same arena.
253  InlinedStringField field1;
254  InlinedStringField field2;
255  uint32 donating_states = 0;
256  Arena arena;
257  auto* field1_arena = Arena::CreateMessage<InlinedStringField>(&arena);
258  auto* field2_arena = Arena::CreateMessage<InlinedStringField>(&arena);
259  uint32 donating_states_1 = ~0u;
260  uint32 donating_states_2 = ~0u;
261  const std::string kDefaultValue = "default";
262 
263  const std::string& string1_heap = "String 1 on heap";
264  const std::string& string2_heap = "String 2 on heap long long long long";
265  const std::string& string1_arena = "String 1 on arena";
266  const std::string& string2_arena = "String 2 on arena long long long long";
267  field1.SetNoArena(&kDefaultValue, string1_heap);
268  field2.SetNoArena(&kDefaultValue, string2_heap);
269  field1_arena->Set(&kDefaultValue, string1_arena, &arena, true,
270  &donating_states_1, kMask1);
271  field2_arena->Set(&kDefaultValue, string2_arena, &arena, true,
272  &donating_states_2, kMask1);
273 
274  field1.Swap(&field2, &kDefaultValue, nullptr, false, false, &donating_states,
275  &donating_states_2, kMask);
276  field1_arena->Swap(field2_arena, &kDefaultValue, &arena, true, true,
277  &donating_states_1, &donating_states_2, kMask1);
278  EXPECT_EQ(field1.Get(), string2_heap);
279  EXPECT_EQ(field2.Get(), string1_heap);
280  EXPECT_EQ(field1_arena->Get(), string2_arena);
281  EXPECT_EQ(field2_arena->Get(), string1_arena);
282 }
283 
284 } // namespace
285 } // namespace protobuf
286 } // namespace google
absl::swap_internal::Swap
void Swap(T &lhs, T &rhs) noexcept(IsNothrowSwappable< T >::value)
Definition: abseil-cpp/absl/meta/type_traits.h:772
google::protobuf::value
const Descriptor::ReservedRange value
Definition: bloaty/third_party/protobuf/src/google/protobuf/descriptor.h:1954
google::protobuf::EmptyDefault
ArenaStringPtr::EmptyDefault EmptyDefault
Definition: protobuf/src/google/protobuf/arenastring_unittest.cc:57
Arena
Definition: arena.c:39
testing::internal::string
::std::string string
Definition: bloaty/third_party/protobuf/third_party/googletest/googletest/include/gtest/internal/gtest-port.h:881
google::protobuf::uint32
uint32_t uint32
Definition: third_party/bloaty/third_party/protobuf/src/google/protobuf/stubs/port.h:155
u
OPENSSL_EXPORT pem_password_cb void * u
Definition: pem.h:351
google::protobuf
Definition: bloaty/third_party/protobuf/benchmarks/util/data_proto2_to_proto3_util.h:12
arena
grpc_core::ScopedArenaPtr arena
Definition: binder_transport_test.cc:237
EXPECT_EQ
#define EXPECT_EQ(a, b)
Definition: iomgr/time_averaged_stats_test.cc:27
absl::move
constexpr absl::remove_reference_t< T > && move(T &&t) noexcept
Definition: abseil-cpp/absl/utility/utility.h:221
EXPECT_NE
#define EXPECT_NE(val1, val2)
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest.h:2028
google::protobuf::TEST
TEST(ArenaTest, ArenaConstructable)
Definition: bloaty/third_party/protobuf/src/google/protobuf/arena_unittest.cc:156
field
const FieldDescriptor * field
Definition: bloaty/third_party/protobuf/src/google/protobuf/compiler/parser_unittest.cc:2692
google::protobuf::WrapString
static std::string WrapString(const char *value)
Definition: bloaty/third_party/protobuf/src/google/protobuf/arenastring_unittest.cc:54
google
Definition: bloaty/third_party/protobuf/benchmarks/util/data_proto2_to_proto3_util.h:11


grpc
Author(s):
autogenerated on Fri May 16 2025 02:59:03