From 6c655321e6b04b8648802e296bb5ca11d290ae68 Mon Sep 17 00:00:00 2001 From: swurl Date: Sat, 31 May 2025 02:33:02 -0400 Subject: Move dead submodules in-tree Signed-off-by: swurl --- .../samples/RhythmGame/test/testLockFreeQueue.cpp | 210 +++++++++++++++++++++ 1 file changed, 210 insertions(+) create mode 100644 externals/oboe/samples/RhythmGame/test/testLockFreeQueue.cpp (limited to 'externals/oboe/samples/RhythmGame/test/testLockFreeQueue.cpp') diff --git a/externals/oboe/samples/RhythmGame/test/testLockFreeQueue.cpp b/externals/oboe/samples/RhythmGame/test/testLockFreeQueue.cpp new file mode 100644 index 0000000000..1dd3ac8f4c --- /dev/null +++ b/externals/oboe/samples/RhythmGame/test/testLockFreeQueue.cpp @@ -0,0 +1,210 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include +#include "utils/LockFreeQueue.h" + +/** + * Tests + * ===== + * + * READ/POP: + * - if queue is empty return false + * - if queue has elements return true + * - returns correct value once + * - returns correct value more than once + * + * WRITE/PUSH: + * - if queue is full return false + * - if queue has space return true + * + * WRAP: + * - read from full queue, then write one more element, then correct read + * + * PEEK: + * - peek once + * - peek twice + * + * SIZE: + * - correct zero + * - correct once + * - correct many + * + * MULTI-THREADED: + * - write and read concurrently, queue is empty at end and item order is maintained + * + * CANNOT TEST: + * - read/writes correct after wraparound (takes too long to run) + * - Constructing queue with non power of 2 capacity results in assert failure (needs death test) + * - Constructing queue with signed type results in assert failure (needs death test) + * + */ + +constexpr int kQueueCapacity = 2; + +class TestLockFreeQueue : public ::testing::Test { + +public: + + int result1; + int result2; + int result3; + LockFreeQueue q; +}; + +TEST_F(TestLockFreeQueue, PopReturnsFalseWhenEmpty){ + bool result = q.pop(result1); + ASSERT_EQ(result, false); +} + +TEST_F(TestLockFreeQueue, PopReturnsTrueWhenNotEmpty){ + q.push(123); + bool result = q.pop(result1); + ASSERT_EQ(result, true); +} + +TEST_F(TestLockFreeQueue, PopReturnsOneCorrectValue){ + q.push(123); + q.pop(result1); + ASSERT_EQ(result1, 123); +} + +TEST_F(TestLockFreeQueue, PopReturnsManyCorrectValues){ + q.push(123); + q.push(456); + q.pop(result1); + q.pop(result2); + ASSERT_EQ(result1, 123); + ASSERT_EQ(result2, 456); +} + +TEST_F(TestLockFreeQueue, PushWhenFullReturnsFalse){ + q.push(123); + q.push(123); + ASSERT_EQ(q.push(123), false); +} + +TEST_F(TestLockFreeQueue, PushWhenSpaceAvailableReturnsTrue){ + ASSERT_EQ(q.push(123), true); +} + +TEST_F(TestLockFreeQueue, PushHandlesWrapCorrectly){ + q.push(123); + q.push(234); + q.pop(result1); + q.push(999); + q.pop(result2); + ASSERT_EQ(result2, 234); + q.pop(result3); + ASSERT_EQ(result3, 999); +} + +TEST_F(TestLockFreeQueue, PeekWhenEmptyReturnsFalse){ + ASSERT_EQ(q.peek(result1), false); +} + +TEST_F(TestLockFreeQueue, PeekWhenNotEmptyReturnsTrue){ + q.push(123); + ASSERT_EQ(q.peek(result1), true); +} + +TEST_F(TestLockFreeQueue, PeekReturnsCorrectValueOnce){ + q.push(456); + q.peek(result1); + ASSERT_EQ(result1, 456); +} + +TEST_F(TestLockFreeQueue, PeekReturnsCorrectValueTwice){ + q.push(456); + q.peek(result1); + q.peek(result2); + ASSERT_EQ(result2, 456); +} + +TEST_F(TestLockFreeQueue, SizeReturnsZeroAfterInit){ + ASSERT_EQ(q.size(), 0); +} + +TEST_F(TestLockFreeQueue, SizeIsOneAfterPushOnce){ + q.push(321); + ASSERT_EQ(q.size(), 1); +} + +TEST_F(TestLockFreeQueue, SizeIsCorrectAfterPushingMaxItems){ + for (int i = 0; i < kQueueCapacity; ++i) { q.push(i); } + ASSERT_EQ(q.size(), kQueueCapacity); +} + +TEST_F(TestLockFreeQueue, SizeCorrectAfterWriteCounterWraps){ + + const uint32_t kCapacity = (uint32_t) 1 << 7; + LockFreeQueue myQ; + + for (int i = 0; i < UINT8_MAX; ++i) { + myQ.push(i); + myQ.pop(result1); + } + + myQ.push(1); + ASSERT_EQ(myQ.size(), 1); +} + +TEST_F(TestLockFreeQueue, MultiThreadedTest){ + + // Push and pop from the queue concurrently + // Check that the queue is empty + // Check that the order of the read values matches the order of the written values + + constexpr int kQueueCapacity = 2048; + LockFreeQueue myQ; + std::array sourceData; + std::array targetData { 0 }; + + // Populate the source data + for (int i = 0; i < kQueueCapacity; i++){ + sourceData[i] = i; + } + + std::thread writer([&myQ, &sourceData](){ + for (int i = 0; i < kQueueCapacity; i++){ + myQ.push(sourceData[i]); + } + }); + + std::thread reader([&myQ, &targetData](){ + for (int i = 0; i < kQueueCapacity; i++){ + // pop the latest element, or wait for it to become available + while (!myQ.pop(targetData[i])){ + std::cout << "Waiting for element at index " << i << " to be written" << std::endl; + usleep(500); + } + } + }); + + writer.join(); + reader.join(); + + int v; + ASSERT_FALSE(myQ.pop(v)); + + // Check that the target matches the source + for (int i = 0; i < kQueueCapacity; i++){ + ASSERT_EQ(sourceData[i], targetData[i]) << "Elements at index " << i << " did not match"; + } +} -- cgit v1.2.3