xref: /aosp_15_r20/external/icing/icing/join/posting-list-join-data-serializer_test.cc (revision 8b6cd535a057e39b3b86660c4aa06c99747c2136)
1 // Copyright (C) 2022 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "icing/join/posting-list-join-data-serializer.h"
16 
17 #include <algorithm>
18 #include <iterator>
19 #include <vector>
20 
21 #include "icing/text_classifier/lib3/utils/base/status.h"
22 #include "gmock/gmock.h"
23 #include "gtest/gtest.h"
24 #include "icing/file/posting_list/posting-list-used.h"
25 #include "icing/join/document-id-to-join-info.h"
26 #include "icing/store/namespace-id-fingerprint.h"
27 #include "icing/testing/common-matchers.h"
28 
29 using testing::ElementsAre;
30 using testing::ElementsAreArray;
31 using testing::Eq;
32 using testing::IsEmpty;
33 using testing::SizeIs;
34 
35 namespace icing {
36 namespace lib {
37 
38 namespace {
39 
TEST(PostingListJoinDataSerializerTest,GetMinPostingListSizeToFitNotNull)40 TEST(PostingListJoinDataSerializerTest, GetMinPostingListSizeToFitNotNull) {
41   PostingListJoinDataSerializer<DocumentIdToJoinInfo<NamespaceIdFingerprint>>
42       serializer;
43 
44   int size = 2551 * sizeof(DocumentIdToJoinInfo<NamespaceIdFingerprint>);
45   ICING_ASSERT_OK_AND_ASSIGN(
46       PostingListUsed pl_used,
47       PostingListUsed::CreateFromUnitializedRegion(&serializer, size));
48 
49   ASSERT_THAT(serializer.PrependData(
50                   &pl_used, DocumentIdToJoinInfo<NamespaceIdFingerprint>(
51                                 /*document_id=*/0,
52                                 NamespaceIdFingerprint(/*namespace_id=*/1,
53                                                        /*fingerprint=*/2))),
54               IsOk());
55   EXPECT_THAT(serializer.GetMinPostingListSizeToFit(&pl_used),
56               Eq(2 * sizeof(DocumentIdToJoinInfo<NamespaceIdFingerprint>)));
57 
58   ASSERT_THAT(serializer.PrependData(
59                   &pl_used, DocumentIdToJoinInfo<NamespaceIdFingerprint>(
60                                 /*document_id=*/1,
61                                 NamespaceIdFingerprint(/*namespace_id=*/1,
62                                                        /*fingerprint=*/5))),
63               IsOk());
64   EXPECT_THAT(serializer.GetMinPostingListSizeToFit(&pl_used),
65               Eq(3 * sizeof(DocumentIdToJoinInfo<NamespaceIdFingerprint>)));
66 }
67 
TEST(PostingListJoinDataSerializerTest,GetMinPostingListSizeToFitAlmostFull)68 TEST(PostingListJoinDataSerializerTest, GetMinPostingListSizeToFitAlmostFull) {
69   PostingListJoinDataSerializer<DocumentIdToJoinInfo<NamespaceIdFingerprint>>
70       serializer;
71 
72   int size = 3 * sizeof(DocumentIdToJoinInfo<NamespaceIdFingerprint>);
73   ICING_ASSERT_OK_AND_ASSIGN(
74       PostingListUsed pl_used,
75       PostingListUsed::CreateFromUnitializedRegion(&serializer, size));
76 
77   ASSERT_THAT(serializer.PrependData(
78                   &pl_used, DocumentIdToJoinInfo<NamespaceIdFingerprint>(
79                                 /*document_id=*/0,
80                                 NamespaceIdFingerprint(/*namespace_id=*/1,
81                                                        /*fingerprint=*/2))),
82               IsOk());
83   ASSERT_THAT(serializer.PrependData(
84                   &pl_used, DocumentIdToJoinInfo<NamespaceIdFingerprint>(
85                                 /*document_id=*/1,
86                                 NamespaceIdFingerprint(/*namespace_id=*/1,
87                                                        /*fingerprint=*/5))),
88               IsOk());
89   EXPECT_THAT(serializer.GetMinPostingListSizeToFit(&pl_used), Eq(size));
90 }
91 
TEST(PostingListJoinDataSerializerTest,GetMinPostingListSizeToFitFull)92 TEST(PostingListJoinDataSerializerTest, GetMinPostingListSizeToFitFull) {
93   PostingListJoinDataSerializer<DocumentIdToJoinInfo<NamespaceIdFingerprint>>
94       serializer;
95 
96   int size = 3 * sizeof(DocumentIdToJoinInfo<NamespaceIdFingerprint>);
97   ICING_ASSERT_OK_AND_ASSIGN(
98       PostingListUsed pl_used,
99       PostingListUsed::CreateFromUnitializedRegion(&serializer, size));
100 
101   ASSERT_THAT(serializer.PrependData(
102                   &pl_used, DocumentIdToJoinInfo<NamespaceIdFingerprint>(
103                                 /*document_id=*/0,
104                                 NamespaceIdFingerprint(/*namespace_id=*/1,
105                                                        /*fingerprint=*/2))),
106               IsOk());
107   ASSERT_THAT(serializer.PrependData(
108                   &pl_used, DocumentIdToJoinInfo<NamespaceIdFingerprint>(
109                                 /*document_id=*/1,
110                                 NamespaceIdFingerprint(/*namespace_id=*/1,
111                                                        /*fingerprint=*/5))),
112               IsOk());
113   ASSERT_THAT(serializer.PrependData(
114                   &pl_used, DocumentIdToJoinInfo<NamespaceIdFingerprint>(
115                                 /*document_id=*/2,
116                                 NamespaceIdFingerprint(/*namespace_id=*/1,
117                                                        /*fingerprint=*/10))),
118               IsOk());
119   EXPECT_THAT(serializer.GetMinPostingListSizeToFit(&pl_used), Eq(size));
120 }
121 
TEST(PostingListJoinDataSerializerTest,PrependDataNotFull)122 TEST(PostingListJoinDataSerializerTest, PrependDataNotFull) {
123   PostingListJoinDataSerializer<DocumentIdToJoinInfo<NamespaceIdFingerprint>>
124       serializer;
125 
126   int size = 2551 * sizeof(DocumentIdToJoinInfo<NamespaceIdFingerprint>);
127   ICING_ASSERT_OK_AND_ASSIGN(
128       PostingListUsed pl_used,
129       PostingListUsed::CreateFromUnitializedRegion(&serializer, size));
130 
131   // Make used.
132   DocumentIdToJoinInfo<NamespaceIdFingerprint> data0(
133       /*document_id=*/0,
134       NamespaceIdFingerprint(/*namespace_id=*/1, /*fingerprint=*/2));
135   EXPECT_THAT(serializer.PrependData(&pl_used, data0), IsOk());
136   // Size = sizeof(uncompressed data0)
137   int expected_size = sizeof(DocumentIdToJoinInfo<NamespaceIdFingerprint>);
138   EXPECT_THAT(serializer.GetBytesUsed(&pl_used), Eq(expected_size));
139   EXPECT_THAT(serializer.GetData(&pl_used), IsOkAndHolds(ElementsAre(data0)));
140 
141   DocumentIdToJoinInfo<NamespaceIdFingerprint> data1(
142       /*document_id=*/1,
143       NamespaceIdFingerprint(/*namespace_id=*/1, /*fingerprint=*/5));
144   EXPECT_THAT(serializer.PrependData(&pl_used, data1), IsOk());
145   // Size = sizeof(uncompressed data1)
146   //        + sizeof(uncompressed data0)
147   expected_size += sizeof(DocumentIdToJoinInfo<NamespaceIdFingerprint>);
148   EXPECT_THAT(serializer.GetBytesUsed(&pl_used), Eq(expected_size));
149   EXPECT_THAT(serializer.GetData(&pl_used),
150               IsOkAndHolds(ElementsAre(data1, data0)));
151 
152   DocumentIdToJoinInfo<NamespaceIdFingerprint> data2(
153       /*document_id=*/2,
154       NamespaceIdFingerprint(/*namespace_id=*/1, /*fingerprint=*/10));
155   EXPECT_THAT(serializer.PrependData(&pl_used, data2), IsOk());
156   // Size = sizeof(uncompressed data2)
157   //        + sizeof(uncompressed data1)
158   //        + sizeof(uncompressed data0)
159   expected_size += sizeof(DocumentIdToJoinInfo<NamespaceIdFingerprint>);
160   EXPECT_THAT(serializer.GetBytesUsed(&pl_used), Eq(expected_size));
161   EXPECT_THAT(serializer.GetData(&pl_used),
162               IsOkAndHolds(ElementsAre(data2, data1, data0)));
163 }
164 
TEST(PostingListJoinDataSerializerTest,PrependDataAlmostFull)165 TEST(PostingListJoinDataSerializerTest, PrependDataAlmostFull) {
166   PostingListJoinDataSerializer<DocumentIdToJoinInfo<NamespaceIdFingerprint>>
167       serializer;
168 
169   int size = 4 * sizeof(DocumentIdToJoinInfo<NamespaceIdFingerprint>);
170   ICING_ASSERT_OK_AND_ASSIGN(
171       PostingListUsed pl_used,
172       PostingListUsed::CreateFromUnitializedRegion(&serializer, size));
173 
174   // Fill up the compressed region.
175   // Transitions:
176   // Adding data0: EMPTY -> NOT_FULL
177   // Adding data1: NOT_FULL -> NOT_FULL
178   DocumentIdToJoinInfo<NamespaceIdFingerprint> data0(
179       /*document_id=*/0,
180       NamespaceIdFingerprint(/*namespace_id=*/1, /*fingerprint=*/2));
181   DocumentIdToJoinInfo<NamespaceIdFingerprint> data1(
182       /*document_id=*/1,
183       NamespaceIdFingerprint(/*namespace_id=*/1, /*fingerprint=*/5));
184   EXPECT_THAT(serializer.PrependData(&pl_used, data0), IsOk());
185   EXPECT_THAT(serializer.PrependData(&pl_used, data1), IsOk());
186   int expected_size = 2 * sizeof(DocumentIdToJoinInfo<NamespaceIdFingerprint>);
187   EXPECT_THAT(serializer.GetBytesUsed(&pl_used), Eq(expected_size));
188   EXPECT_THAT(serializer.GetData(&pl_used),
189               IsOkAndHolds(ElementsAre(data1, data0)));
190 
191   // Add one more data to transition NOT_FULL -> ALMOST_FULL
192   DocumentIdToJoinInfo<NamespaceIdFingerprint> data2(
193       /*document_id=*/2,
194       NamespaceIdFingerprint(/*namespace_id=*/1, /*fingerprint=*/10));
195   EXPECT_THAT(serializer.PrependData(&pl_used, data2), IsOk());
196   expected_size = 3 * sizeof(DocumentIdToJoinInfo<NamespaceIdFingerprint>);
197   EXPECT_THAT(serializer.GetBytesUsed(&pl_used), Eq(expected_size));
198   EXPECT_THAT(serializer.GetData(&pl_used),
199               IsOkAndHolds(ElementsAre(data2, data1, data0)));
200 
201   // Add one more data to transition ALMOST_FULL -> FULL
202   DocumentIdToJoinInfo<NamespaceIdFingerprint> data3(
203       /*document_id=*/3,
204       NamespaceIdFingerprint(/*namespace_id=*/1, /*fingerprint=*/0));
205   EXPECT_THAT(serializer.PrependData(&pl_used, data3), IsOk());
206   EXPECT_THAT(serializer.GetBytesUsed(&pl_used), Eq(size));
207   EXPECT_THAT(serializer.GetData(&pl_used),
208               IsOkAndHolds(ElementsAre(data3, data2, data1, data0)));
209 
210   // The posting list is FULL. Adding another data should fail.
211   DocumentIdToJoinInfo<NamespaceIdFingerprint> data4(
212       /*document_id=*/4,
213       NamespaceIdFingerprint(/*namespace_id=*/0, /*fingerprint=*/1234));
214   EXPECT_THAT(serializer.PrependData(&pl_used, data4),
215               StatusIs(libtextclassifier3::StatusCode::RESOURCE_EXHAUSTED));
216 }
217 
TEST(PostingListJoinDataSerializerTest,PrependSmallerDataShouldFail)218 TEST(PostingListJoinDataSerializerTest, PrependSmallerDataShouldFail) {
219   PostingListJoinDataSerializer<DocumentIdToJoinInfo<NamespaceIdFingerprint>>
220       serializer;
221 
222   int size = 4 * sizeof(DocumentIdToJoinInfo<NamespaceIdFingerprint>);
223   ICING_ASSERT_OK_AND_ASSIGN(
224       PostingListUsed pl_used,
225       PostingListUsed::CreateFromUnitializedRegion(&serializer, size));
226 
227   DocumentIdToJoinInfo<NamespaceIdFingerprint> data(
228       /*document_id=*/100,
229       NamespaceIdFingerprint(/*namespace_id=*/1, /*fingerprint=*/2));
230   DocumentIdToJoinInfo<NamespaceIdFingerprint> smaller_data(
231       /*document_id=*/99,
232       NamespaceIdFingerprint(/*namespace_id=*/1, /*fingerprint=*/2));
233 
234   // NOT_FULL -> NOT_FULL
235   ASSERT_THAT(serializer.PrependData(&pl_used, data), IsOk());
236   EXPECT_THAT(serializer.PrependData(&pl_used, smaller_data),
237               StatusIs(libtextclassifier3::StatusCode::INVALID_ARGUMENT));
238 
239   // NOT_FULL -> ALMOST_FULL
240   ASSERT_THAT(serializer.PrependData(&pl_used, data), IsOk());
241   EXPECT_THAT(serializer.PrependData(&pl_used, smaller_data),
242               StatusIs(libtextclassifier3::StatusCode::INVALID_ARGUMENT));
243 
244   // ALMOST_FULL -> FULL
245   ASSERT_THAT(serializer.PrependData(&pl_used, data), IsOk());
246   EXPECT_THAT(serializer.PrependData(&pl_used, smaller_data),
247               StatusIs(libtextclassifier3::StatusCode::INVALID_ARGUMENT));
248 }
249 
TEST(PostingListJoinDataSerializerTest,PrependDataPostingListUsedMinSize)250 TEST(PostingListJoinDataSerializerTest, PrependDataPostingListUsedMinSize) {
251   PostingListJoinDataSerializer<DocumentIdToJoinInfo<NamespaceIdFingerprint>>
252       serializer;
253 
254   int size = serializer.GetMinPostingListSize();
255   ICING_ASSERT_OK_AND_ASSIGN(
256       PostingListUsed pl_used,
257       PostingListUsed::CreateFromUnitializedRegion(&serializer, size));
258 
259   // PL State: EMPTY
260   EXPECT_THAT(serializer.GetBytesUsed(&pl_used), Eq(0));
261   EXPECT_THAT(serializer.GetData(&pl_used), IsOkAndHolds(IsEmpty()));
262 
263   // Add a data. PL should shift to ALMOST_FULL state
264   DocumentIdToJoinInfo<NamespaceIdFingerprint> data0(
265       /*document_id=*/0,
266       NamespaceIdFingerprint(/*namespace_id=*/1, /*fingerprint=*/2));
267   EXPECT_THAT(serializer.PrependData(&pl_used, data0), IsOk());
268   // Size = sizeof(uncompressed data0)
269   int expected_size = sizeof(DocumentIdToJoinInfo<NamespaceIdFingerprint>);
270   EXPECT_THAT(serializer.GetBytesUsed(&pl_used), Eq(expected_size));
271   EXPECT_THAT(serializer.GetData(&pl_used), IsOkAndHolds(ElementsAre(data0)));
272 
273   // Add another data. PL should shift to FULL state.
274   DocumentIdToJoinInfo<NamespaceIdFingerprint> data1(
275       /*document_id=*/1,
276       NamespaceIdFingerprint(/*namespace_id=*/1, /*fingerprint=*/5));
277   EXPECT_THAT(serializer.PrependData(&pl_used, data1), IsOk());
278   // Size = sizeof(uncompressed data1) + sizeof(uncompressed data0)
279   expected_size += sizeof(DocumentIdToJoinInfo<NamespaceIdFingerprint>);
280   EXPECT_THAT(serializer.GetBytesUsed(&pl_used), Eq(expected_size));
281   EXPECT_THAT(serializer.GetData(&pl_used),
282               IsOkAndHolds(ElementsAre(data1, data0)));
283 
284   // The posting list is FULL. Adding another data should fail.
285   DocumentIdToJoinInfo<NamespaceIdFingerprint> data2(
286       /*document_id=*/2,
287       NamespaceIdFingerprint(/*namespace_id=*/1, /*fingerprint=*/10));
288   EXPECT_THAT(serializer.PrependData(&pl_used, data2),
289               StatusIs(libtextclassifier3::StatusCode::RESOURCE_EXHAUSTED));
290 }
291 
TEST(PostingListJoinDataSerializerTest,PrependDataArrayDoNotKeepPrepended)292 TEST(PostingListJoinDataSerializerTest, PrependDataArrayDoNotKeepPrepended) {
293   PostingListJoinDataSerializer<DocumentIdToJoinInfo<NamespaceIdFingerprint>>
294       serializer;
295 
296   int size = 6 * sizeof(DocumentIdToJoinInfo<NamespaceIdFingerprint>);
297   ICING_ASSERT_OK_AND_ASSIGN(
298       PostingListUsed pl_used,
299       PostingListUsed::CreateFromUnitializedRegion(&serializer, size));
300 
301   std::vector<DocumentIdToJoinInfo<NamespaceIdFingerprint>> data_in;
302   std::vector<DocumentIdToJoinInfo<NamespaceIdFingerprint>> data_pushed;
303 
304   // Add 3 data. The PL is in the empty state and should be able to fit all 3
305   // data without issue, transitioning the PL from EMPTY -> NOT_FULL.
306   data_in.push_back(DocumentIdToJoinInfo<NamespaceIdFingerprint>(
307       /*document_id=*/0,
308       NamespaceIdFingerprint(/*namespace_id=*/1, /*fingerprint=*/2)));
309   data_in.push_back(DocumentIdToJoinInfo<NamespaceIdFingerprint>(
310       /*document_id=*/1,
311       NamespaceIdFingerprint(/*namespace_id=*/1, /*fingerprint=*/5)));
312   data_in.push_back(DocumentIdToJoinInfo<NamespaceIdFingerprint>(
313       /*document_id=*/2,
314       NamespaceIdFingerprint(/*namespace_id=*/1, /*fingerprint=*/10)));
315   EXPECT_THAT(
316       serializer.PrependDataArray(&pl_used, data_in.data(), data_in.size(),
317                                   /*keep_prepended=*/false),
318       IsOkAndHolds(data_in.size()));
319   std::move(data_in.begin(), data_in.end(), std::back_inserter(data_pushed));
320   EXPECT_THAT(serializer.GetBytesUsed(&pl_used),
321               Eq(data_pushed.size() *
322                  sizeof(DocumentIdToJoinInfo<NamespaceIdFingerprint>)));
323   EXPECT_THAT(
324       serializer.GetData(&pl_used),
325       IsOkAndHolds(ElementsAreArray(data_pushed.rbegin(), data_pushed.rend())));
326 
327   // Add 2 data. The PL should transition from NOT_FULL to ALMOST_FULL.
328   data_in.clear();
329   data_in.push_back(DocumentIdToJoinInfo<NamespaceIdFingerprint>(
330       /*document_id=*/3,
331       NamespaceIdFingerprint(/*namespace_id=*/1, /*fingerprint=*/0)));
332   data_in.push_back(DocumentIdToJoinInfo<NamespaceIdFingerprint>(
333       /*document_id=*/4,
334       NamespaceIdFingerprint(/*namespace_id=*/0, /*fingerprint=*/1234)));
335   EXPECT_THAT(
336       serializer.PrependDataArray(&pl_used, data_in.data(), data_in.size(),
337                                   /*keep_prepended=*/false),
338       IsOkAndHolds(data_in.size()));
339   std::move(data_in.begin(), data_in.end(), std::back_inserter(data_pushed));
340   EXPECT_THAT(serializer.GetBytesUsed(&pl_used),
341               Eq(data_pushed.size() *
342                  sizeof(DocumentIdToJoinInfo<NamespaceIdFingerprint>)));
343   EXPECT_THAT(
344       serializer.GetData(&pl_used),
345       IsOkAndHolds(ElementsAreArray(data_pushed.rbegin(), data_pushed.rend())));
346 
347   // Add 2 data. The PL should remain ALMOST_FULL since the remaining space can
348   // only fit 1 data.
349   data_in.clear();
350   data_in.push_back(DocumentIdToJoinInfo<NamespaceIdFingerprint>(
351       /*document_id=*/5,
352       NamespaceIdFingerprint(/*namespace_id=*/2, /*fingerprint=*/99)));
353   data_in.push_back(DocumentIdToJoinInfo<NamespaceIdFingerprint>(
354       /*document_id=*/6,
355       NamespaceIdFingerprint(/*namespace_id=*/1, /*fingerprint=*/63)));
356   EXPECT_THAT(
357       serializer.PrependDataArray(&pl_used, data_in.data(), data_in.size(),
358                                   /*keep_prepended=*/false),
359       IsOkAndHolds(0));
360   EXPECT_THAT(serializer.GetBytesUsed(&pl_used),
361               Eq(data_pushed.size() *
362                  sizeof(DocumentIdToJoinInfo<NamespaceIdFingerprint>)));
363   EXPECT_THAT(
364       serializer.GetData(&pl_used),
365       IsOkAndHolds(ElementsAreArray(data_pushed.rbegin(), data_pushed.rend())));
366 
367   // Add 1 data. The PL should transition from ALMOST_FULL to FULL.
368   data_in.pop_back();
369   ASSERT_THAT(data_in, SizeIs(1));
370   EXPECT_THAT(
371       serializer.PrependDataArray(&pl_used, data_in.data(), data_in.size(),
372                                   /*keep_prepended=*/false),
373       IsOkAndHolds(data_in.size()));
374   std::move(data_in.begin(), data_in.end(), std::back_inserter(data_pushed));
375   EXPECT_THAT(serializer.GetBytesUsed(&pl_used),
376               Eq(data_pushed.size() *
377                  sizeof(DocumentIdToJoinInfo<NamespaceIdFingerprint>)));
378   EXPECT_THAT(
379       serializer.GetData(&pl_used),
380       IsOkAndHolds(ElementsAreArray(data_pushed.rbegin(), data_pushed.rend())));
381 }
382 
TEST(PostingListJoinDataSerializerTest,PrependDataArrayKeepPrepended)383 TEST(PostingListJoinDataSerializerTest, PrependDataArrayKeepPrepended) {
384   PostingListJoinDataSerializer<DocumentIdToJoinInfo<NamespaceIdFingerprint>>
385       serializer;
386 
387   int size = 6 * sizeof(DocumentIdToJoinInfo<NamespaceIdFingerprint>);
388   ICING_ASSERT_OK_AND_ASSIGN(
389       PostingListUsed pl_used,
390       PostingListUsed::CreateFromUnitializedRegion(&serializer, size));
391 
392   std::vector<DocumentIdToJoinInfo<NamespaceIdFingerprint>> data_in;
393   std::vector<DocumentIdToJoinInfo<NamespaceIdFingerprint>> data_pushed;
394 
395   // Add 3 data. The PL is in the empty state and should be able to fit all 3
396   // data without issue, transitioning the PL from EMPTY -> NOT_FULL.
397   data_in.push_back(DocumentIdToJoinInfo<NamespaceIdFingerprint>(
398       /*document_id=*/0,
399       NamespaceIdFingerprint(/*namespace_id=*/1, /*fingerprint=*/2)));
400   data_in.push_back(DocumentIdToJoinInfo<NamespaceIdFingerprint>(
401       /*document_id=*/1,
402       NamespaceIdFingerprint(/*namespace_id=*/1, /*fingerprint=*/5)));
403   data_in.push_back(DocumentIdToJoinInfo<NamespaceIdFingerprint>(
404       /*document_id=*/2,
405       NamespaceIdFingerprint(/*namespace_id=*/1, /*fingerprint=*/10)));
406   EXPECT_THAT(
407       serializer.PrependDataArray(&pl_used, data_in.data(), data_in.size(),
408                                   /*keep_prepended=*/true),
409       IsOkAndHolds(data_in.size()));
410   std::move(data_in.begin(), data_in.end(), std::back_inserter(data_pushed));
411   EXPECT_THAT(serializer.GetBytesUsed(&pl_used),
412               Eq(data_pushed.size() *
413                  sizeof(DocumentIdToJoinInfo<NamespaceIdFingerprint>)));
414   EXPECT_THAT(
415       serializer.GetData(&pl_used),
416       IsOkAndHolds(ElementsAreArray(data_pushed.rbegin(), data_pushed.rend())));
417 
418   // Add 4 data. The PL should prepend 3 data and transition from NOT_FULL to
419   // FULL.
420   data_in.clear();
421   data_in.push_back(DocumentIdToJoinInfo<NamespaceIdFingerprint>(
422       /*document_id=*/3,
423       NamespaceIdFingerprint(/*namespace_id=*/1, /*fingerprint=*/0)));
424   data_in.push_back(DocumentIdToJoinInfo<NamespaceIdFingerprint>(
425       /*document_id=*/4,
426       NamespaceIdFingerprint(/*namespace_id=*/0, /*fingerprint=*/1234)));
427   data_in.push_back(DocumentIdToJoinInfo<NamespaceIdFingerprint>(
428       /*document_id=*/5,
429       NamespaceIdFingerprint(/*namespace_id=*/2, /*fingerprint=*/99)));
430   data_in.push_back(DocumentIdToJoinInfo<NamespaceIdFingerprint>(
431       /*document_id=*/6,
432       NamespaceIdFingerprint(/*namespace_id=*/1, /*fingerprint=*/63)));
433   EXPECT_THAT(
434       serializer.PrependDataArray(&pl_used, data_in.data(), data_in.size(),
435                                   /*keep_prepended=*/true),
436       IsOkAndHolds(3));
437   data_in.pop_back();
438   ASSERT_THAT(data_in, SizeIs(3));
439   std::move(data_in.begin(), data_in.end(), std::back_inserter(data_pushed));
440   EXPECT_THAT(serializer.GetBytesUsed(&pl_used),
441               Eq(data_pushed.size() *
442                  sizeof(DocumentIdToJoinInfo<NamespaceIdFingerprint>)));
443   EXPECT_THAT(
444       serializer.GetData(&pl_used),
445       IsOkAndHolds(ElementsAreArray(data_pushed.rbegin(), data_pushed.rend())));
446 }
447 
TEST(PostingListJoinDataSerializerTest,MoveFrom)448 TEST(PostingListJoinDataSerializerTest, MoveFrom) {
449   PostingListJoinDataSerializer<DocumentIdToJoinInfo<NamespaceIdFingerprint>>
450       serializer;
451 
452   int size = 3 * serializer.GetMinPostingListSize();
453   ICING_ASSERT_OK_AND_ASSIGN(
454       PostingListUsed pl_used1,
455       PostingListUsed::CreateFromUnitializedRegion(&serializer, size));
456 
457   std::vector<DocumentIdToJoinInfo<NamespaceIdFingerprint>> data_arr1 = {
458       DocumentIdToJoinInfo<NamespaceIdFingerprint>(
459           /*document_id=*/0,
460           NamespaceIdFingerprint(/*namespace_id=*/1, /*fingerprint=*/2)),
461       DocumentIdToJoinInfo<NamespaceIdFingerprint>(
462           /*document_id=*/1,
463           NamespaceIdFingerprint(/*namespace_id=*/1, /*fingerprint=*/5))};
464   ASSERT_THAT(
465       serializer.PrependDataArray(&pl_used1, data_arr1.data(), data_arr1.size(),
466                                   /*keep_prepended=*/false),
467       IsOkAndHolds(data_arr1.size()));
468 
469   ICING_ASSERT_OK_AND_ASSIGN(
470       PostingListUsed pl_used2,
471       PostingListUsed::CreateFromUnitializedRegion(&serializer, size));
472   std::vector<DocumentIdToJoinInfo<NamespaceIdFingerprint>> data_arr2 = {
473       DocumentIdToJoinInfo<NamespaceIdFingerprint>(
474           /*document_id=*/2,
475           NamespaceIdFingerprint(/*namespace_id=*/1, /*fingerprint=*/10)),
476       DocumentIdToJoinInfo<NamespaceIdFingerprint>(
477           /*document_id=*/3,
478           NamespaceIdFingerprint(/*namespace_id=*/1, /*fingerprint=*/0)),
479       DocumentIdToJoinInfo<NamespaceIdFingerprint>(
480           /*document_id=*/4,
481           NamespaceIdFingerprint(/*namespace_id=*/0, /*fingerprint=*/1234)),
482       DocumentIdToJoinInfo<NamespaceIdFingerprint>(
483           /*document_id=*/5,
484           NamespaceIdFingerprint(/*namespace_id=*/2, /*fingerprint=*/99))};
485   ASSERT_THAT(
486       serializer.PrependDataArray(&pl_used2, data_arr2.data(), data_arr2.size(),
487                                   /*keep_prepended=*/false),
488       IsOkAndHolds(data_arr2.size()));
489 
490   EXPECT_THAT(serializer.MoveFrom(/*dst=*/&pl_used2, /*src=*/&pl_used1),
491               IsOk());
492   EXPECT_THAT(
493       serializer.GetData(&pl_used2),
494       IsOkAndHolds(ElementsAreArray(data_arr1.rbegin(), data_arr1.rend())));
495   EXPECT_THAT(serializer.GetData(&pl_used1), IsOkAndHolds(IsEmpty()));
496 }
497 
TEST(PostingListJoinDataSerializerTest,MoveToNullReturnsFailedPrecondition)498 TEST(PostingListJoinDataSerializerTest, MoveToNullReturnsFailedPrecondition) {
499   PostingListJoinDataSerializer<DocumentIdToJoinInfo<NamespaceIdFingerprint>>
500       serializer;
501 
502   int size = 3 * serializer.GetMinPostingListSize();
503   ICING_ASSERT_OK_AND_ASSIGN(
504       PostingListUsed pl_used,
505       PostingListUsed::CreateFromUnitializedRegion(&serializer, size));
506   std::vector<DocumentIdToJoinInfo<NamespaceIdFingerprint>> data_arr = {
507       DocumentIdToJoinInfo<NamespaceIdFingerprint>(
508           /*document_id=*/0,
509           NamespaceIdFingerprint(/*namespace_id=*/1, /*fingerprint=*/2)),
510       DocumentIdToJoinInfo<NamespaceIdFingerprint>(
511           /*document_id=*/1,
512           NamespaceIdFingerprint(/*namespace_id=*/1, /*fingerprint=*/5))};
513   ASSERT_THAT(
514       serializer.PrependDataArray(&pl_used, data_arr.data(), data_arr.size(),
515                                   /*keep_prepended=*/false),
516       IsOkAndHolds(data_arr.size()));
517 
518   EXPECT_THAT(serializer.MoveFrom(/*dst=*/&pl_used, /*src=*/nullptr),
519               StatusIs(libtextclassifier3::StatusCode::FAILED_PRECONDITION));
520   EXPECT_THAT(
521       serializer.GetData(&pl_used),
522       IsOkAndHolds(ElementsAreArray(data_arr.rbegin(), data_arr.rend())));
523 
524   EXPECT_THAT(serializer.MoveFrom(/*dst=*/nullptr, /*src=*/&pl_used),
525               StatusIs(libtextclassifier3::StatusCode::FAILED_PRECONDITION));
526   EXPECT_THAT(
527       serializer.GetData(&pl_used),
528       IsOkAndHolds(ElementsAreArray(data_arr.rbegin(), data_arr.rend())));
529 }
530 
TEST(PostingListJoinDataSerializerTest,MoveToPostingListTooSmall)531 TEST(PostingListJoinDataSerializerTest, MoveToPostingListTooSmall) {
532   PostingListJoinDataSerializer<DocumentIdToJoinInfo<NamespaceIdFingerprint>>
533       serializer;
534 
535   int size1 = 3 * serializer.GetMinPostingListSize();
536   ICING_ASSERT_OK_AND_ASSIGN(
537       PostingListUsed pl_used1,
538       PostingListUsed::CreateFromUnitializedRegion(&serializer, size1));
539   std::vector<DocumentIdToJoinInfo<NamespaceIdFingerprint>> data_arr1 = {
540       DocumentIdToJoinInfo<NamespaceIdFingerprint>(
541           /*document_id=*/0,
542           NamespaceIdFingerprint(/*namespace_id=*/1, /*fingerprint=*/2)),
543       DocumentIdToJoinInfo<NamespaceIdFingerprint>(
544           /*document_id=*/1,
545           NamespaceIdFingerprint(/*namespace_id=*/1, /*fingerprint=*/5)),
546       DocumentIdToJoinInfo<NamespaceIdFingerprint>(
547           /*document_id=*/2,
548           NamespaceIdFingerprint(/*namespace_id=*/1, /*fingerprint=*/10)),
549       DocumentIdToJoinInfo<NamespaceIdFingerprint>(
550           /*document_id=*/3,
551           NamespaceIdFingerprint(/*namespace_id=*/1, /*fingerprint=*/0)),
552       DocumentIdToJoinInfo<NamespaceIdFingerprint>(
553           /*document_id=*/4,
554           NamespaceIdFingerprint(/*namespace_id=*/0, /*fingerprint=*/1234))};
555   ASSERT_THAT(
556       serializer.PrependDataArray(&pl_used1, data_arr1.data(), data_arr1.size(),
557                                   /*keep_prepended=*/false),
558       IsOkAndHolds(data_arr1.size()));
559 
560   int size2 = serializer.GetMinPostingListSize();
561   ICING_ASSERT_OK_AND_ASSIGN(
562       PostingListUsed pl_used2,
563       PostingListUsed::CreateFromUnitializedRegion(&serializer, size2));
564   std::vector<DocumentIdToJoinInfo<NamespaceIdFingerprint>> data_arr2 = {
565       DocumentIdToJoinInfo<NamespaceIdFingerprint>(
566           /*document_id=*/5,
567           NamespaceIdFingerprint(/*namespace_id=*/2, /*fingerprint=*/99))};
568   ASSERT_THAT(
569       serializer.PrependDataArray(&pl_used2, data_arr2.data(), data_arr2.size(),
570                                   /*keep_prepended=*/false),
571       IsOkAndHolds(data_arr2.size()));
572 
573   EXPECT_THAT(serializer.MoveFrom(/*dst=*/&pl_used2, /*src=*/&pl_used1),
574               StatusIs(libtextclassifier3::StatusCode::INVALID_ARGUMENT));
575   EXPECT_THAT(
576       serializer.GetData(&pl_used1),
577       IsOkAndHolds(ElementsAreArray(data_arr1.rbegin(), data_arr1.rend())));
578   EXPECT_THAT(
579       serializer.GetData(&pl_used2),
580       IsOkAndHolds(ElementsAreArray(data_arr2.rbegin(), data_arr2.rend())));
581 }
582 
TEST(PostingListJoinDataSerializerTest,PopFrontData)583 TEST(PostingListJoinDataSerializerTest, PopFrontData) {
584   PostingListJoinDataSerializer<DocumentIdToJoinInfo<NamespaceIdFingerprint>>
585       serializer;
586 
587   int size = 2 * serializer.GetMinPostingListSize();
588   ICING_ASSERT_OK_AND_ASSIGN(
589       PostingListUsed pl_used,
590       PostingListUsed::CreateFromUnitializedRegion(&serializer, size));
591 
592   std::vector<DocumentIdToJoinInfo<NamespaceIdFingerprint>> data_arr = {
593       DocumentIdToJoinInfo<NamespaceIdFingerprint>(
594           /*document_id=*/0,
595           NamespaceIdFingerprint(/*namespace_id=*/1, /*fingerprint=*/2)),
596       DocumentIdToJoinInfo<NamespaceIdFingerprint>(
597           /*document_id=*/1,
598           NamespaceIdFingerprint(/*namespace_id=*/1, /*fingerprint=*/5)),
599       DocumentIdToJoinInfo<NamespaceIdFingerprint>(
600           /*document_id=*/2,
601           NamespaceIdFingerprint(/*namespace_id=*/1, /*fingerprint=*/10))};
602   ASSERT_THAT(
603       serializer.PrependDataArray(&pl_used, data_arr.data(), data_arr.size(),
604                                   /*keep_prepended=*/false),
605       IsOkAndHolds(data_arr.size()));
606   ASSERT_THAT(
607       serializer.GetData(&pl_used),
608       IsOkAndHolds(ElementsAreArray(data_arr.rbegin(), data_arr.rend())));
609 
610   // Now, pop the last data. The posting list should contain the first three
611   // data.
612   EXPECT_THAT(serializer.PopFrontData(&pl_used, /*num_data=*/1), IsOk());
613   data_arr.pop_back();
614   EXPECT_THAT(
615       serializer.GetData(&pl_used),
616       IsOkAndHolds(ElementsAreArray(data_arr.rbegin(), data_arr.rend())));
617 }
618 
619 }  // namespace
620 
621 }  // namespace lib
622 }  // namespace icing
623