blob: c6eb511e57b2d9307b2e7e2cff3bf07a3c66e37d [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 {}
Danil Chapovalov5286dcf2022-07-18 15:04:5636 void PostTask(absl::AnyInvocable<void() &&> task) override {}
37 void PostDelayedTask(absl::AnyInvocable<void() &&> task,
38 webrtc::TimeDelta delay) override {}
39 void PostDelayedHighPrecisionTask(absl::AnyInvocable<void() &&> task,
40 webrtc::TimeDelta delay) override {}
Tomas Gunnarsson64099bc2021-04-09 07:51:3741
42 private:
43 CurrentTaskQueueSetter task_queue_setter_;
44};
45} // namespace
Amit Hilbuchc63ddb22019-01-02 18:13:5846
47template <typename Generator>
48class UniqueIdGeneratorTest : public Test {};
49
50using test_types = ::testing::Types<UniqueNumberGenerator<uint8_t>,
51 UniqueNumberGenerator<uint16_t>,
52 UniqueNumberGenerator<uint32_t>,
Elad Alonefc9a142019-02-08 22:35:5953 UniqueNumberGenerator<int>,
Amit Hilbuchc63ddb22019-01-02 18:13:5854 UniqueRandomIdGenerator,
55 UniqueStringGenerator>;
56
Mirko Bonadeic84f6612019-01-31 11:20:5757TYPED_TEST_SUITE(UniqueIdGeneratorTest, test_types);
Amit Hilbuchc63ddb22019-01-02 18:13:5858
59TYPED_TEST(UniqueIdGeneratorTest, ElementsDoNotRepeat) {
60 typedef TypeParam Generator;
61 const size_t num_elements = 255;
62 Generator generator;
63 std::vector<typename Generator::value_type> values;
64 for (size_t i = 0; i < num_elements; i++) {
65 values.push_back(generator());
66 }
67
68 EXPECT_EQ(num_elements, values.size());
69 // Use a set to check uniqueness.
70 std::set<typename Generator::value_type> set(values.begin(), values.end());
71 EXPECT_EQ(values.size(), set.size()) << "Returned values were not unique.";
72}
73
74TYPED_TEST(UniqueIdGeneratorTest, KnownElementsAreNotGenerated) {
75 typedef TypeParam Generator;
76 const size_t num_elements = 100;
77 rtc::InitRandom(0);
78 Generator generator1;
79 std::vector<typename Generator::value_type> known_values;
80 for (size_t i = 0; i < num_elements; i++) {
81 known_values.push_back(generator1());
82 }
83 EXPECT_EQ(num_elements, known_values.size());
84
85 rtc::InitRandom(0);
86 Generator generator2(known_values);
87
88 std::vector<typename Generator::value_type> values;
89 for (size_t i = 0; i < num_elements; i++) {
90 values.push_back(generator2());
91 }
92 EXPECT_THAT(values, ::testing::SizeIs(num_elements));
Steve Anton2acd1632019-03-25 20:48:3093 absl::c_sort(values);
94 absl::c_sort(known_values);
Amit Hilbuchc63ddb22019-01-02 18:13:5895 std::vector<typename Generator::value_type> intersection;
Steve Anton2acd1632019-03-25 20:48:3096 absl::c_set_intersection(values, known_values,
97 std::back_inserter(intersection));
Amit Hilbuchc63ddb22019-01-02 18:13:5898 EXPECT_THAT(intersection, IsEmpty());
99}
100
Amit Hilbuchae3df542019-01-07 20:13:08101TYPED_TEST(UniqueIdGeneratorTest, AddedElementsAreNotGenerated) {
102 typedef TypeParam Generator;
103 const size_t num_elements = 100;
104 rtc::InitRandom(0);
105 Generator generator1;
106 std::vector<typename Generator::value_type> known_values;
107 for (size_t i = 0; i < num_elements; i++) {
108 known_values.push_back(generator1());
109 }
110 EXPECT_EQ(num_elements, known_values.size());
111
112 rtc::InitRandom(0);
113 Generator generator2;
114
Mirko Bonadei739baf02019-01-27 16:29:42115 for (const typename Generator::value_type& value : known_values) {
Amit Hilbuchae3df542019-01-07 20:13:08116 generator2.AddKnownId(value);
117 }
118
119 std::vector<typename Generator::value_type> values;
120 for (size_t i = 0; i < num_elements; i++) {
121 values.push_back(generator2());
122 }
123 EXPECT_THAT(values, ::testing::SizeIs(num_elements));
Steve Anton2acd1632019-03-25 20:48:30124 absl::c_sort(values);
125 absl::c_sort(known_values);
Amit Hilbuchae3df542019-01-07 20:13:08126 std::vector<typename Generator::value_type> intersection;
Steve Anton2acd1632019-03-25 20:48:30127 absl::c_set_intersection(values, known_values,
128 std::back_inserter(intersection));
Amit Hilbuchae3df542019-01-07 20:13:08129 EXPECT_THAT(intersection, IsEmpty());
130}
131
Elad Alonefc9a142019-02-08 22:35:59132TYPED_TEST(UniqueIdGeneratorTest, AddKnownIdOnNewIdReturnsTrue) {
133 typedef TypeParam Generator;
134
135 rtc::InitRandom(0);
136 Generator generator1;
137 const typename Generator::value_type id = generator1();
138
139 rtc::InitRandom(0);
140 Generator generator2;
141 EXPECT_TRUE(generator2.AddKnownId(id));
142}
143
144TYPED_TEST(UniqueIdGeneratorTest, AddKnownIdCalledAgainForSameIdReturnsFalse) {
145 typedef TypeParam Generator;
146
147 rtc::InitRandom(0);
148 Generator generator1;
149 const typename Generator::value_type id = generator1();
150
151 rtc::InitRandom(0);
152 Generator generator2;
153 ASSERT_TRUE(generator2.AddKnownId(id));
154 EXPECT_FALSE(generator2.AddKnownId(id));
155}
156
157TYPED_TEST(UniqueIdGeneratorTest,
158 AddKnownIdOnIdProvidedAsKnownToCtorReturnsFalse) {
159 typedef TypeParam Generator;
160
161 rtc::InitRandom(0);
162 Generator generator1;
163 const typename Generator::value_type id = generator1();
164 std::vector<typename Generator::value_type> known_values = {id};
165
166 rtc::InitRandom(0);
167 Generator generator2(known_values);
168 EXPECT_FALSE(generator2.AddKnownId(id));
169}
170
Tomas Gunnarsson64099bc2021-04-09 07:51:37171// Tests that it's OK to construct the generator in one execution environment
172// (thread/task queue) but use it in another.
173TEST(UniqueNumberGenerator, UsedOnSecondaryThread) {
174 const auto* current_tq = webrtc::TaskQueueBase::Current();
175 // Construct the generator before `fake_task_queue` to ensure that it is
176 // constructed in a different execution environment than what
177 // `fake_task_queue` will represent.
178 UniqueNumberGenerator<uint32_t> generator;
179
180 FakeTaskQueue fake_task_queue;
181 // Sanity check to make sure we're in a different runtime environment.
182 ASSERT_NE(current_tq, webrtc::TaskQueueBase::Current());
183
184 // Generating an id should be fine in this context.
185 generator.GenerateNumber();
186}
187
188#if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)
189TEST(UniqueNumberGeneratorDeathTest, FailsWhenUsedInWrongContext) {
190 // Instantiate the generator before the `loop`. This ensures that
191 // thread/sequence checkers will pick up a different thread environment than
192 // `fake_task_queue` will represent.
193 UniqueNumberGenerator<uint32_t> generator;
Harald Alvestrandb8f7ef12021-11-15 08:02:27194
195 // Instantiate a fake task queue that will register itself as the current tq.
196 FakeTaskQueue initial_fake_task_queue;
Tomas Gunnarsson64099bc2021-04-09 07:51:37197 // Generate an ID on the current thread. This causes the generator to attach
198 // to the current thread context.
199 generator.GenerateNumber();
200
201 // Instantiate a fake task queue that will register itself as the current tq.
202 FakeTaskQueue fake_task_queue;
203
204 // Attempting to generate an id should now trigger a dcheck.
205 EXPECT_DEATH(generator.GenerateNumber(), "");
206}
207#endif
208
Amit Hilbuchdbb49df2019-01-23 22:54:24209} // namespace rtc