xref: /aosp_15_r20/external/cronet/net/third_party/quiche/src/quiche/quic/core/quic_interval_deque_test.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright (c) 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "quiche/quic/core/quic_interval_deque.h"
6 
7 #include <cstdint>
8 #include <ostream>
9 
10 #include "quiche/quic/core/quic_interval.h"
11 #include "quiche/quic/platform/api/quic_expect_bug.h"
12 #include "quiche/quic/platform/api/quic_test.h"
13 #include "quiche/quic/test_tools/quic_interval_deque_peer.h"
14 #include "quiche/quic/test_tools/quic_test_utils.h"
15 
16 namespace quic {
17 namespace test {
18 namespace {
19 
20 const int32_t kSize = 100;
21 const std::size_t kIntervalStep = 10;
22 
23 }  // namespace
24 
25 struct TestIntervalItem {
26   int32_t val;
27   std::size_t interval_start, interval_end;
intervalquic::test::TestIntervalItem28   QuicInterval<std::size_t> interval() const {
29     return QuicInterval<std::size_t>(interval_start, interval_end);
30   }
TestIntervalItemquic::test::TestIntervalItem31   TestIntervalItem(int32_t val, std::size_t interval_start,
32                    std::size_t interval_end)
33       : val(val), interval_start(interval_start), interval_end(interval_end) {}
34 };
35 
36 using QID = QuicIntervalDeque<TestIntervalItem>;
37 
38 class QuicIntervalDequeTest : public QuicTest {
39  public:
QuicIntervalDequeTest()40   QuicIntervalDequeTest() {
41     // Add items with intervals of |kIntervalStep| size.
42     for (int32_t i = 0; i < kSize; ++i) {
43       const std::size_t interval_begin = kIntervalStep * i;
44       const std::size_t interval_end = interval_begin + kIntervalStep;
45       qid_.PushBack(TestIntervalItem(i, interval_begin, interval_end));
46     }
47   }
48 
49   QID qid_;
50 };
51 
52 // The goal of this test is to show insertion/push_back, iteration, and and
53 // deletion/pop_front from the container.
TEST_F(QuicIntervalDequeTest,InsertRemoveSize)54 TEST_F(QuicIntervalDequeTest, InsertRemoveSize) {
55   QID qid;
56 
57   EXPECT_EQ(qid.Size(), std::size_t(0));
58   qid.PushBack(TestIntervalItem(0, 0, 10));
59   EXPECT_EQ(qid.Size(), std::size_t(1));
60   qid.PushBack(TestIntervalItem(1, 10, 20));
61   EXPECT_EQ(qid.Size(), std::size_t(2));
62   qid.PushBack(TestIntervalItem(2, 20, 30));
63   EXPECT_EQ(qid.Size(), std::size_t(3));
64   qid.PushBack(TestIntervalItem(3, 30, 40));
65   EXPECT_EQ(qid.Size(), std::size_t(4));
66 
67   // Advance the index all the way...
68   int32_t i = 0;
69   for (auto it = qid.DataAt(0); it != qid.DataEnd(); ++it, ++i) {
70     const int32_t index = QuicIntervalDequePeer::GetCachedIndex(&qid);
71     EXPECT_EQ(index, i);
72     EXPECT_EQ(it->val, i);
73   }
74   const int32_t index = QuicIntervalDequePeer::GetCachedIndex(&qid);
75   EXPECT_EQ(index, -1);
76 
77   qid.PopFront();
78   EXPECT_EQ(qid.Size(), std::size_t(3));
79   qid.PopFront();
80   EXPECT_EQ(qid.Size(), std::size_t(2));
81   qid.PopFront();
82   EXPECT_EQ(qid.Size(), std::size_t(1));
83   qid.PopFront();
84   EXPECT_EQ(qid.Size(), std::size_t(0));
85 
86   EXPECT_QUIC_BUG(qid.PopFront(), "Trying to pop from an empty container.");
87 }
88 
89 // The goal of this test is to push data into the container at specific
90 // intervals and show how the |DataAt| method can move the |cached_index| as the
91 // iterator moves through the data.
TEST_F(QuicIntervalDequeTest,InsertIterateWhole)92 TEST_F(QuicIntervalDequeTest, InsertIterateWhole) {
93   // The write index should point to the beginning of the container.
94   const int32_t cached_index = QuicIntervalDequePeer::GetCachedIndex(&qid_);
95   EXPECT_EQ(cached_index, 0);
96 
97   auto it = qid_.DataBegin();
98   auto end = qid_.DataEnd();
99   for (int32_t i = 0; i < kSize; ++i, ++it) {
100     EXPECT_EQ(it->val, i);
101     const std::size_t current_iteraval_begin = i * kIntervalStep;
102     // The |DataAt| method should find the correct interval.
103     auto lookup = qid_.DataAt(current_iteraval_begin);
104     EXPECT_EQ(i, lookup->val);
105     // Make sure the index hasn't changed just from using |DataAt|
106     const int32_t index_before = QuicIntervalDequePeer::GetCachedIndex(&qid_);
107     EXPECT_EQ(index_before, i);
108     // This increment should move the index forward.
109     lookup++;
110     // Check that the index has changed.
111     const int32_t index_after = QuicIntervalDequePeer::GetCachedIndex(&qid_);
112     const int32_t after_i = (i + 1) == kSize ? -1 : (i + 1);
113     EXPECT_EQ(index_after, after_i);
114     EXPECT_NE(it, end);
115   }
116 }
117 
118 // The goal of this test is to push data into the container at specific
119 // intervals and show how the |DataAt| method can move the |cached_index| using
120 // the off-by-one logic.
TEST_F(QuicIntervalDequeTest,OffByOne)121 TEST_F(QuicIntervalDequeTest, OffByOne) {
122   // The write index should point to the beginning of the container.
123   const int32_t cached_index = QuicIntervalDequePeer::GetCachedIndex(&qid_);
124   EXPECT_EQ(cached_index, 0);
125 
126   auto it = qid_.DataBegin();
127   auto end = qid_.DataEnd();
128   for (int32_t i = 0; i < kSize - 1; ++i, ++it) {
129     EXPECT_EQ(it->val, i);
130     const int32_t off_by_one_i = i + 1;
131     const std::size_t current_iteraval_begin = off_by_one_i * kIntervalStep;
132     // Make sure the index has changed just from using |DataAt|
133     const int32_t index_before = QuicIntervalDequePeer::GetCachedIndex(&qid_);
134     EXPECT_EQ(index_before, i);
135     // The |DataAt| method should find the correct interval.
136     auto lookup = qid_.DataAt(current_iteraval_begin);
137     EXPECT_EQ(off_by_one_i, lookup->val);
138     // Check that the index has changed.
139     const int32_t index_after = QuicIntervalDequePeer::GetCachedIndex(&qid_);
140     const int32_t after_i = off_by_one_i == kSize ? -1 : off_by_one_i;
141     EXPECT_EQ(index_after, after_i);
142     EXPECT_NE(it, end);
143   }
144 }
145 
146 // The goal of this test is to push data into the container at specific
147 // intervals and show modify the structure with a live iterator.
TEST_F(QuicIntervalDequeTest,IteratorInvalidation)148 TEST_F(QuicIntervalDequeTest, IteratorInvalidation) {
149   // The write index should point to the beginning of the container.
150   const int32_t cached_index = QuicIntervalDequePeer::GetCachedIndex(&qid_);
151   EXPECT_EQ(cached_index, 0);
152 
153   const std::size_t iteraval_begin = (kSize - 1) * kIntervalStep;
154   auto lookup = qid_.DataAt(iteraval_begin);
155   EXPECT_EQ((*lookup).val, (kSize - 1));
156   qid_.PopFront();
157   EXPECT_QUIC_BUG(lookup++, "Iterator out of bounds.");
158   auto lookup_end = qid_.DataAt(iteraval_begin + kIntervalStep);
159   EXPECT_EQ(lookup_end, qid_.DataEnd());
160 }
161 
162 // The goal of this test is the same as |InsertIterateWhole| but to
163 // skip certain intervals and show the |cached_index| is updated properly.
TEST_F(QuicIntervalDequeTest,InsertIterateSkip)164 TEST_F(QuicIntervalDequeTest, InsertIterateSkip) {
165   // The write index should point to the beginning of the container.
166   const int32_t cached_index = QuicIntervalDequePeer::GetCachedIndex(&qid_);
167   EXPECT_EQ(cached_index, 0);
168 
169   const std::size_t step = 4;
170   for (int32_t i = 0; i < kSize; i += 4) {
171     if (i != 0) {
172       const int32_t before_i = (i - (step - 1));
173       EXPECT_EQ(QuicIntervalDequePeer::GetCachedIndex(&qid_), before_i);
174     }
175     const std::size_t current_iteraval_begin = i * kIntervalStep;
176     // The |DataAt| method should find the correct interval.
177     auto lookup = qid_.DataAt(current_iteraval_begin);
178     EXPECT_EQ(i, lookup->val);
179     // Make sure the index _has_ changed just from using |DataAt| since we're
180     // skipping data.
181     const int32_t index_before = QuicIntervalDequePeer::GetCachedIndex(&qid_);
182     EXPECT_EQ(index_before, i);
183     // This increment should move the index forward.
184     lookup++;
185     // Check that the index has changed.
186     const int32_t index_after = QuicIntervalDequePeer::GetCachedIndex(&qid_);
187     const int32_t after_i = (i + 1) == kSize ? -1 : (i + 1);
188     EXPECT_EQ(index_after, after_i);
189   }
190 }
191 
192 // The goal of this test is the same as |InsertIterateWhole| but it has
193 // |PopFront| calls interleaved to show the |cached_index| updates correctly.
TEST_F(QuicIntervalDequeTest,InsertDeleteIterate)194 TEST_F(QuicIntervalDequeTest, InsertDeleteIterate) {
195   // The write index should point to the beginning of the container.
196   const int32_t index = QuicIntervalDequePeer::GetCachedIndex(&qid_);
197   EXPECT_EQ(index, 0);
198 
199   std::size_t limit = 0;
200   for (int32_t i = 0; limit < qid_.Size(); ++i, ++limit) {
201     // Always point to the beginning of the container.
202     auto it = qid_.DataBegin();
203     EXPECT_EQ(it->val, i);
204 
205     // Get an iterator.
206     const std::size_t current_iteraval_begin = i * kIntervalStep;
207     auto lookup = qid_.DataAt(current_iteraval_begin);
208     const int32_t index_before = QuicIntervalDequePeer::GetCachedIndex(&qid_);
209     // The index should always point to 0.
210     EXPECT_EQ(index_before, 0);
211     // This iterator increment should effect the index.
212     lookup++;
213     const int32_t index_after = QuicIntervalDequePeer::GetCachedIndex(&qid_);
214     EXPECT_EQ(index_after, 1);
215     // Decrement the |temp_size| and pop from the front.
216     qid_.PopFront();
217     // Show the index has been updated to point to 0 again (from 1).
218     const int32_t index_after_pop =
219         QuicIntervalDequePeer::GetCachedIndex(&qid_);
220     EXPECT_EQ(index_after_pop, 0);
221   }
222 }
223 
224 // The goal of this test is to move the index to the end and then add more data
225 // to show it can be reset to a valid index.
TEST_F(QuicIntervalDequeTest,InsertIterateInsert)226 TEST_F(QuicIntervalDequeTest, InsertIterateInsert) {
227   // The write index should point to the beginning of the container.
228   const int32_t index = QuicIntervalDequePeer::GetCachedIndex(&qid_);
229   EXPECT_EQ(index, 0);
230 
231   int32_t iterated_elements = 0;
232   for (int32_t i = 0; i < kSize; ++i, ++iterated_elements) {
233     // Get an iterator.
234     const std::size_t current_iteraval_begin = i * kIntervalStep;
235     auto lookup = qid_.DataAt(current_iteraval_begin);
236     const int32_t index_before = QuicIntervalDequePeer::GetCachedIndex(&qid_);
237     // The index should always point to i.
238     EXPECT_EQ(index_before, i);
239     // This iterator increment should effect the index.
240     lookup++;
241     // Show the index has been updated to point to i + 1 or -1 if at the end.
242     const int32_t index_after = QuicIntervalDequePeer::GetCachedIndex(&qid_);
243     const int32_t after_i = (i + 1) == kSize ? -1 : (i + 1);
244     EXPECT_EQ(index_after, after_i);
245   }
246   const int32_t invalid_index = QuicIntervalDequePeer::GetCachedIndex(&qid_);
247   EXPECT_EQ(invalid_index, -1);
248 
249   // Add more data to the container, making the index valid.
250   const std::size_t offset = qid_.Size();
251   for (int32_t i = 0; i < kSize; ++i) {
252     const std::size_t interval_begin = offset + (kIntervalStep * i);
253     const std::size_t interval_end = offset + interval_begin + kIntervalStep;
254     qid_.PushBack(TestIntervalItem(i + offset, interval_begin, interval_end));
255     const int32_t index_current = QuicIntervalDequePeer::GetCachedIndex(&qid_);
256     // Index should now be valid and equal to the size of the container before
257     // adding more items to it.
258     EXPECT_EQ(index_current, iterated_elements);
259   }
260   // Show the index is still valid and hasn't changed since the first iteration
261   // of the loop.
262   const int32_t index_after_add = QuicIntervalDequePeer::GetCachedIndex(&qid_);
263   EXPECT_EQ(index_after_add, iterated_elements);
264 
265   // Iterate over all the data in the container and eventually reset the index
266   // as we did before.
267   for (int32_t i = 0; i < kSize; ++i, ++iterated_elements) {
268     const std::size_t interval_begin = offset + (kIntervalStep * i);
269     const int32_t index_current = QuicIntervalDequePeer::GetCachedIndex(&qid_);
270     EXPECT_EQ(index_current, iterated_elements);
271     auto lookup = qid_.DataAt(interval_begin);
272     const int32_t expected_value = i + offset;
273     EXPECT_EQ(lookup->val, expected_value);
274     lookup++;
275     const int32_t after_inc =
276         (iterated_elements + 1) == (kSize * 2) ? -1 : (iterated_elements + 1);
277     const int32_t after_index = QuicIntervalDequePeer::GetCachedIndex(&qid_);
278     EXPECT_EQ(after_index, after_inc);
279   }
280   // Show the index is now invalid.
281   const int32_t invalid_index_again =
282       QuicIntervalDequePeer::GetCachedIndex(&qid_);
283   EXPECT_EQ(invalid_index_again, -1);
284 }
285 
286 // The goal of this test is to push data into the container at specific
287 // intervals and show how the |DataAt| can iterate over already scanned data.
TEST_F(QuicIntervalDequeTest,RescanData)288 TEST_F(QuicIntervalDequeTest, RescanData) {
289   // The write index should point to the beginning of the container.
290   const int32_t index = QuicIntervalDequePeer::GetCachedIndex(&qid_);
291   EXPECT_EQ(index, 0);
292 
293   auto it = qid_.DataBegin();
294   auto end = qid_.DataEnd();
295   for (int32_t i = 0; i < kSize - 1; ++i, ++it) {
296     EXPECT_EQ(it->val, i);
297     const std::size_t current_iteraval_begin = i * kIntervalStep;
298     // The |DataAt| method should find the correct interval.
299     auto lookup = qid_.DataAt(current_iteraval_begin);
300     EXPECT_EQ(i, lookup->val);
301     // Make sure the index has changed just from using |DataAt|
302     const int32_t cached_index_before =
303         QuicIntervalDequePeer::GetCachedIndex(&qid_);
304     EXPECT_EQ(cached_index_before, i);
305     // Ensure the real index has changed just from using |DataAt| and the
306     // off-by-one logic
307     const int32_t index_before = QuicIntervalDequePeer::GetCachedIndex(&qid_);
308     const int32_t before_i = i;
309     EXPECT_EQ(index_before, before_i);
310     // This increment should move the cached index forward.
311     lookup++;
312     // Check that the cached index has moved foward.
313     const int32_t cached_index_after =
314         QuicIntervalDequePeer::GetCachedIndex(&qid_);
315     const int32_t after_i = (i + 1);
316     EXPECT_EQ(cached_index_after, after_i);
317     EXPECT_NE(it, end);
318   }
319 
320   // Iterate over items which have been consumed before.
321   int32_t expected_index = static_cast<int32_t>(kSize - 1);
322   for (int32_t i = 0; i < kSize - 1; ++i) {
323     const std::size_t current_iteraval_begin = i * kIntervalStep;
324     // The |DataAt| method should find the correct interval.
325     auto lookup = qid_.DataAt(current_iteraval_begin);
326     EXPECT_EQ(i, lookup->val);
327     // This increment shouldn't move the index forward as the index is currently
328     // ahead.
329     lookup++;
330     // Check that the index hasn't moved foward.
331     const int32_t index_after = QuicIntervalDequePeer::GetCachedIndex(&qid_);
332     EXPECT_EQ(index_after, expected_index);
333     EXPECT_NE(it, end);
334   }
335 }
336 
337 // The goal of this test is to show that popping from an empty container is a
338 // bug.
TEST_F(QuicIntervalDequeTest,PopEmpty)339 TEST_F(QuicIntervalDequeTest, PopEmpty) {
340   QID qid;
341   EXPECT_TRUE(qid.Empty());
342   EXPECT_QUIC_BUG(qid.PopFront(), "Trying to pop from an empty container.");
343 }
344 
345 // The goal of this test is to show that adding a zero-sized interval is a bug.
TEST_F(QuicIntervalDequeTest,ZeroSizedInterval)346 TEST_F(QuicIntervalDequeTest, ZeroSizedInterval) {
347   QID qid;
348   EXPECT_QUIC_BUG(qid.PushBack(TestIntervalItem(0, 0, 0)),
349                   "Trying to save empty interval to .");
350 }
351 
352 // The goal of this test is to show that an iterator to an empty container
353 // returns |DataEnd|.
TEST_F(QuicIntervalDequeTest,IteratorEmpty)354 TEST_F(QuicIntervalDequeTest, IteratorEmpty) {
355   QID qid;
356   auto it = qid.DataAt(0);
357   EXPECT_EQ(it, qid.DataEnd());
358 }
359 
360 }  // namespace test
361 }  // namespace quic
362