blob: a6ae8ec9f5a5881cc695c28bc9e5f5168f7c540d [file] [log] [blame]
Amit Hilbuchc63ddb22019-01-02 18:13:581/*
2 * Copyright 2018 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
Jonas Olssona4d87372019-07-05 17:08:3311#include "rtc_base/unique_id_generator.h"
12
Steve Anton2acd1632019-03-25 20:48:3013#include <string>
14#include <vector>
Amit Hilbuchc63ddb22019-01-02 18:13:5815
Steve Anton2acd1632019-03-25 20:48:3016#include "absl/algorithm/container.h"
Danil Chapovalov5286dcf2022-07-18 15:04:5617#include "absl/functional/any_invocable.h"
Amit Hilbuchc63ddb22019-01-02 18:13:5818#include "api/array_view.h"
Tomas Gunnarsson64099bc2021-04-09 07:51:3719#include "api/task_queue/task_queue_base.h"
Danil Chapovalov5286dcf2022-07-18 15:04:5620#include "api/units/time_delta.h"
Amit Hilbuchc63ddb22019-01-02 18:13:5821#include "rtc_base/gunit.h"
22#include "rtc_base/helpers.h"
23#include "test/gmock.h"
24
25using ::testing::IsEmpty;
26using ::testing::Test;
27
Amit Hilbuchdbb49df2019-01-23 22:54:2428namespace rtc {
Tomas Gunnarsson64099bc2021-04-09 07:51:3729namespace {
30// Utility class that registers itself as the currently active task queue.
31class FakeTaskQueue : public webrtc::TaskQueueBase {
32 public:
33 FakeTaskQueue() : task_queue_setter_(this) {}
34
35 void Delete() override {}
Markus Handella1ceae22023-03-01 09:13:2836 void PostTaskImpl(absl::AnyInvocable<void() &&> task,
37 const PostTaskTraits& traits,
38 const webrtc::Location& location) override {}
39 void PostDelayedTaskImpl(absl::AnyInvocable<void() &&> task,
40 webrtc::TimeDelta delay,
41 const PostDelayedTaskTraits& traits,
42 const webrtc::Location& location) override {}
Tomas Gunnarsson64099bc2021-04-09 07:51:3743
44 private:
45 CurrentTaskQueueSetter task_queue_setter_;
46};
47} // namespace
Amit Hilbuchc63ddb22019-01-02 18:13:5848
49template <typename Generator>
50class UniqueIdGeneratorTest : public Test {};
51
52using test_types = ::testing::Types<UniqueNumberGenerator<uint8_t>,
53 UniqueNumberGenerator<uint16_t>,
54 UniqueNumberGenerator<uint32_t>,
Elad Alonefc9a142019-02-08 22:35:5955 UniqueNumberGenerator<int>,
Amit Hilbuchc63ddb22019-01-02 18:13:5856 UniqueRandomIdGenerator,
57 UniqueStringGenerator>;
58
Mirko Bonadeic84f6612019-01-31 11:20:5759TYPED_TEST_SUITE(UniqueIdGeneratorTest, test_types);
Amit Hilbuchc63ddb22019-01-02 18:13:5860
61TYPED_TEST(UniqueIdGeneratorTest, ElementsDoNotRepeat) {
62 typedef TypeParam Generator;
63 const size_t num_elements = 255;
64 Generator generator;
65 std::vector<typename Generator::value_type> values;
66 for (size_t i = 0; i < num_elements; i++) {
Harald Alvestrand5ad491e2023-02-10 11:28:0467 values.push_back(generator.Generate());
Amit Hilbuchc63ddb22019-01-02 18:13:5868 }
69
70 EXPECT_EQ(num_elements, values.size());
71 // Use a set to check uniqueness.
72 std::set<typename Generator::value_type> set(values.begin(), values.end());
73 EXPECT_EQ(values.size(), set.size()) << "Returned values were not unique.";
74}
75
76TYPED_TEST(UniqueIdGeneratorTest, KnownElementsAreNotGenerated) {
77 typedef TypeParam Generator;
78 const size_t num_elements = 100;
79 rtc::InitRandom(0);
80 Generator generator1;
81 std::vector<typename Generator::value_type> known_values;
82 for (size_t i = 0; i < num_elements; i++) {
Harald Alvestrand5ad491e2023-02-10 11:28:0483 known_values.push_back(generator1.Generate());
Amit Hilbuchc63ddb22019-01-02 18:13:5884 }
85 EXPECT_EQ(num_elements, known_values.size());
86
87 rtc::InitRandom(0);
88 Generator generator2(known_values);
89
90 std::vector<typename Generator::value_type> values;
91 for (size_t i = 0; i < num_elements; i++) {
Harald Alvestrand5ad491e2023-02-10 11:28:0492 values.push_back(generator2.Generate());
Amit Hilbuchc63ddb22019-01-02 18:13:5893 }
94 EXPECT_THAT(values, ::testing::SizeIs(num_elements));
Steve Anton2acd1632019-03-25 20:48:3095 absl::c_sort(values);
96 absl::c_sort(known_values);
Amit Hilbuchc63ddb22019-01-02 18:13:5897 std::vector<typename Generator::value_type> intersection;
Steve Anton2acd1632019-03-25 20:48:3098 absl::c_set_intersection(values, known_values,
99 std::back_inserter(intersection));
Amit Hilbuchc63ddb22019-01-02 18:13:58100 EXPECT_THAT(intersection, IsEmpty());
101}
102
Amit Hilbuchae3df542019-01-07 20:13:08103TYPED_TEST(UniqueIdGeneratorTest, AddedElementsAreNotGenerated) {
104 typedef TypeParam Generator;
105 const size_t num_elements = 100;
106 rtc::InitRandom(0);
107 Generator generator1;
108 std::vector<typename Generator::value_type> known_values;
109 for (size_t i = 0; i < num_elements; i++) {
Harald Alvestrand5ad491e2023-02-10 11:28:04110 known_values.push_back(generator1.Generate());
Amit Hilbuchae3df542019-01-07 20:13:08111 }
112 EXPECT_EQ(num_elements, known_values.size());
113
114 rtc::InitRandom(0);
115 Generator generator2;
116
Mirko Bonadei739baf02019-01-27 16:29:42117 for (const typename Generator::value_type& value : known_values) {
Amit Hilbuchae3df542019-01-07 20:13:08118 generator2.AddKnownId(value);
119 }
120
121 std::vector<typename Generator::value_type> values;
122 for (size_t i = 0; i < num_elements; i++) {
Harald Alvestrand5ad491e2023-02-10 11:28:04123 values.push_back(generator2.Generate());
Amit Hilbuchae3df542019-01-07 20:13:08124 }
125 EXPECT_THAT(values, ::testing::SizeIs(num_elements));
Steve Anton2acd1632019-03-25 20:48:30126 absl::c_sort(values);
127 absl::c_sort(known_values);
Amit Hilbuchae3df542019-01-07 20:13:08128 std::vector<typename Generator::value_type> intersection;
Steve Anton2acd1632019-03-25 20:48:30129 absl::c_set_intersection(values, known_values,
130 std::back_inserter(intersection));
Amit Hilbuchae3df542019-01-07 20:13:08131 EXPECT_THAT(intersection, IsEmpty());
132}
133
Elad Alonefc9a142019-02-08 22:35:59134TYPED_TEST(UniqueIdGeneratorTest, AddKnownIdOnNewIdReturnsTrue) {
135 typedef TypeParam Generator;
136
137 rtc::InitRandom(0);
138 Generator generator1;
Harald Alvestrand5ad491e2023-02-10 11:28:04139 const typename Generator::value_type id = generator1.Generate();
Elad Alonefc9a142019-02-08 22:35:59140
141 rtc::InitRandom(0);
142 Generator generator2;
143 EXPECT_TRUE(generator2.AddKnownId(id));
144}
145
146TYPED_TEST(UniqueIdGeneratorTest, AddKnownIdCalledAgainForSameIdReturnsFalse) {
147 typedef TypeParam Generator;
148
149 rtc::InitRandom(0);
150 Generator generator1;
Harald Alvestrand5ad491e2023-02-10 11:28:04151 const typename Generator::value_type id = generator1.Generate();
Elad Alonefc9a142019-02-08 22:35:59152
153 rtc::InitRandom(0);
154 Generator generator2;
155 ASSERT_TRUE(generator2.AddKnownId(id));
156 EXPECT_FALSE(generator2.AddKnownId(id));
157}
158
159TYPED_TEST(UniqueIdGeneratorTest,
160 AddKnownIdOnIdProvidedAsKnownToCtorReturnsFalse) {
161 typedef TypeParam Generator;
162
163 rtc::InitRandom(0);
164 Generator generator1;
Harald Alvestrand5ad491e2023-02-10 11:28:04165 const typename Generator::value_type id = generator1.Generate();
Elad Alonefc9a142019-02-08 22:35:59166 std::vector<typename Generator::value_type> known_values = {id};
167
168 rtc::InitRandom(0);
169 Generator generator2(known_values);
170 EXPECT_FALSE(generator2.AddKnownId(id));
171}
172
Tomas Gunnarsson64099bc2021-04-09 07:51:37173// Tests that it's OK to construct the generator in one execution environment
174// (thread/task queue) but use it in another.
175TEST(UniqueNumberGenerator, UsedOnSecondaryThread) {
176 const auto* current_tq = webrtc::TaskQueueBase::Current();
177 // Construct the generator before `fake_task_queue` to ensure that it is
178 // constructed in a different execution environment than what
179 // `fake_task_queue` will represent.
180 UniqueNumberGenerator<uint32_t> generator;
181
182 FakeTaskQueue fake_task_queue;
183 // Sanity check to make sure we're in a different runtime environment.
184 ASSERT_NE(current_tq, webrtc::TaskQueueBase::Current());
185
186 // Generating an id should be fine in this context.
Harald Alvestrand5ad491e2023-02-10 11:28:04187 generator.Generate();
Tomas Gunnarsson64099bc2021-04-09 07:51:37188}
189
190#if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
191TEST(UniqueNumberGeneratorDeathTest, FailsWhenUsedInWrongContext) {
192 // Instantiate the generator before the `loop`. This ensures that
193 // thread/sequence checkers will pick up a different thread environment than
194 // `fake_task_queue` will represent.
195 UniqueNumberGenerator<uint32_t> generator;
Harald Alvestrandb8f7ef12021-11-15 08:02:27196
197 // Instantiate a fake task queue that will register itself as the current tq.
198 FakeTaskQueue initial_fake_task_queue;
Tomas Gunnarsson64099bc2021-04-09 07:51:37199 // Generate an ID on the current thread. This causes the generator to attach
200 // to the current thread context.
Harald Alvestrand5ad491e2023-02-10 11:28:04201 generator.Generate();
Tomas Gunnarsson64099bc2021-04-09 07:51:37202
203 // Instantiate a fake task queue that will register itself as the current tq.
204 FakeTaskQueue fake_task_queue;
205
206 // Attempting to generate an id should now trigger a dcheck.
Harald Alvestrand5ad491e2023-02-10 11:28:04207 EXPECT_DEATH(generator.Generate(), "");
Tomas Gunnarsson64099bc2021-04-09 07:51:37208}
209#endif
210
Amit Hilbuchdbb49df2019-01-23 22:54:24211} // namespace rtc