1/*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <iostream>
18
19#include <gtest/gtest.h>
20#include <stdlib.h>
21
22#include "fifo/FifoBuffer.h"
23#include "fifo/FifoController.h"
24
25using android::fifo_frames_t;
26using android::FifoController;
27using android::FifoBuffer;
28using android::WrappingBuffer;
29
30//void foo() {
31TEST(test_fifi_controller, fifo_indices) {
32    // Values are arbitrary primes designed to trigger edge cases.
33    constexpr int capacity = 83;
34    constexpr int threshold = 47;
35    FifoController   fifoController(capacity, threshold);
36    ASSERT_EQ(capacity, fifoController.getCapacity());
37    ASSERT_EQ(threshold, fifoController.getThreshold());
38
39    ASSERT_EQ(0, fifoController.getReadCounter());
40    ASSERT_EQ(0, fifoController.getWriteCounter());
41    ASSERT_EQ(0, fifoController.getFullFramesAvailable());
42    ASSERT_EQ(threshold, fifoController.getEmptyFramesAvailable());
43
44    // Pretend to write some data.
45    constexpr int advance1 = 23;
46    fifoController.advanceWriteIndex(advance1);
47    int advanced = advance1;
48    ASSERT_EQ(0, fifoController.getReadCounter());
49    ASSERT_EQ(0, fifoController.getReadIndex());
50    ASSERT_EQ(advanced, fifoController.getWriteCounter());
51    ASSERT_EQ(advanced, fifoController.getWriteIndex());
52    ASSERT_EQ(advanced, fifoController.getFullFramesAvailable());
53    ASSERT_EQ(threshold - advanced, fifoController.getEmptyFramesAvailable());
54
55    // Pretend to read the data.
56    fifoController.advanceReadIndex(advance1);
57    ASSERT_EQ(advanced, fifoController.getReadCounter());
58    ASSERT_EQ(advanced, fifoController.getReadIndex());
59    ASSERT_EQ(advanced, fifoController.getWriteCounter());
60    ASSERT_EQ(advanced, fifoController.getWriteIndex());
61    ASSERT_EQ(0, fifoController.getFullFramesAvailable());
62    ASSERT_EQ(threshold, fifoController.getEmptyFramesAvailable());
63
64    // Write past end of buffer.
65    constexpr int advance2 = 13 + capacity - advance1;
66    fifoController.advanceWriteIndex(advance2);
67    advanced += advance2;
68    ASSERT_EQ(advance1, fifoController.getReadCounter());
69    ASSERT_EQ(advance1, fifoController.getReadIndex());
70    ASSERT_EQ(advanced, fifoController.getWriteCounter());
71    ASSERT_EQ(advanced - capacity, fifoController.getWriteIndex());
72    ASSERT_EQ(advance2, fifoController.getFullFramesAvailable());
73    ASSERT_EQ(threshold - advance2, fifoController.getEmptyFramesAvailable());
74}
75
76// TODO consider using a template for other data types.
77class TestFifoBuffer {
78public:
79    explicit TestFifoBuffer(fifo_frames_t capacity, fifo_frames_t threshold = 0)
80        : mFifoBuffer(sizeof(int16_t), capacity) {
81        // For reading and writing.
82        mData = new int16_t[capacity];
83        if (threshold <= 0) {
84            threshold = capacity;
85        }
86        mFifoBuffer.setThreshold(threshold);
87        mThreshold = threshold;
88    }
89
90    void checkMisc() {
91        ASSERT_EQ((int32_t)(2 * sizeof(int16_t)), mFifoBuffer.convertFramesToBytes(2));
92        ASSERT_EQ(mThreshold, mFifoBuffer.getThreshold());
93    }
94
95    // Verify that the available frames in each part add up correctly.
96    void checkWrappingBuffer() {
97        WrappingBuffer wrappingBuffer;
98        fifo_frames_t framesAvailable =
99                mFifoBuffer.getFifoControllerBase()->getEmptyFramesAvailable();
100        fifo_frames_t wrapAvailable = mFifoBuffer.getEmptyRoomAvailable(&wrappingBuffer);
101        EXPECT_EQ(framesAvailable, wrapAvailable);
102        fifo_frames_t bothAvailable = wrappingBuffer.numFrames[0] + wrappingBuffer.numFrames[1];
103        EXPECT_EQ(framesAvailable, bothAvailable);
104
105        framesAvailable =
106                mFifoBuffer.getFifoControllerBase()->getFullFramesAvailable();
107        wrapAvailable = mFifoBuffer.getFullDataAvailable(&wrappingBuffer);
108        EXPECT_EQ(framesAvailable, wrapAvailable);
109        bothAvailable = wrappingBuffer.numFrames[0] + wrappingBuffer.numFrames[1];
110        EXPECT_EQ(framesAvailable, bothAvailable);
111    }
112
113    // Write data but do not overflow.
114    void writeData(fifo_frames_t numFrames) {
115        fifo_frames_t framesAvailable =
116                mFifoBuffer.getFifoControllerBase()->getEmptyFramesAvailable();
117        fifo_frames_t framesToWrite = std::min(framesAvailable, numFrames);
118        for (int i = 0; i < framesToWrite; i++) {
119            mData[i] = mNextWriteIndex++;
120        }
121        fifo_frames_t actual = mFifoBuffer.write(mData, framesToWrite);
122        ASSERT_EQ(framesToWrite, actual);
123    }
124
125    // Read data but do not underflow.
126    void verifyData(fifo_frames_t numFrames) {
127        fifo_frames_t framesAvailable =
128                mFifoBuffer.getFifoControllerBase()->getFullFramesAvailable();
129        fifo_frames_t framesToRead = std::min(framesAvailable, numFrames);
130        fifo_frames_t actual = mFifoBuffer.read(mData, framesToRead);
131        ASSERT_EQ(framesToRead, actual);
132        for (int i = 0; i < framesToRead; i++) {
133            ASSERT_EQ(mNextVerifyIndex++, mData[i]);
134        }
135    }
136
137    // Wrap around the end of the buffer.
138    void checkWrappingWriteRead() {
139        constexpr int frames1 = 43;
140        constexpr int frames2 = 15;
141
142        writeData(frames1);
143        checkWrappingBuffer();
144        verifyData(frames1);
145        checkWrappingBuffer();
146
147        writeData(frames2);
148        checkWrappingBuffer();
149        verifyData(frames2);
150        checkWrappingBuffer();
151    }
152
153    // Write and Read a specific amount of data.
154    void checkWriteRead() {
155        const fifo_frames_t capacity = mFifoBuffer.getBufferCapacityInFrames();
156        // Wrap around with the smaller region in the second half.
157        const int frames1 = capacity - 4;
158        const int frames2 = 7; // arbitrary, small
159        writeData(frames1);
160        verifyData(frames1);
161        writeData(frames2);
162        verifyData(frames2);
163    }
164
165    // Write and Read a specific amount of data.
166    void checkWriteReadSmallLarge() {
167        const fifo_frames_t capacity = mFifoBuffer.getBufferCapacityInFrames();
168        // Wrap around with the larger region in the second half.
169        const int frames1 = capacity - 4;
170        const int frames2 = capacity - 9; // arbitrary, large
171        writeData(frames1);
172        verifyData(frames1);
173        writeData(frames2);
174        verifyData(frames2);
175    }
176
177    // Randomly read or write up to the maximum amount of data.
178    void checkRandomWriteRead() {
179        for (int i = 0; i < 20; i++) {
180            fifo_frames_t framesEmpty =
181                    mFifoBuffer.getFifoControllerBase()->getEmptyFramesAvailable();
182            fifo_frames_t numFrames = (fifo_frames_t)(drand48() * framesEmpty);
183            writeData(numFrames);
184
185            fifo_frames_t framesFull =
186                    mFifoBuffer.getFifoControllerBase()->getFullFramesAvailable();
187            numFrames = (fifo_frames_t)(drand48() * framesFull);
188            verifyData(numFrames);
189        }
190    }
191
192    FifoBuffer     mFifoBuffer;
193    int16_t       *mData;
194    fifo_frames_t  mNextWriteIndex = 0;
195    fifo_frames_t  mNextVerifyIndex = 0;
196    fifo_frames_t  mThreshold;
197};
198
199TEST(test_fifo_buffer, fifo_read_write) {
200    constexpr int capacity = 51; // arbitrary
201    TestFifoBuffer tester(capacity);
202    tester.checkMisc();
203    tester.checkWriteRead();
204}
205
206TEST(test_fifo_buffer, fifo_wrapping_read_write) {
207    constexpr int capacity = 59; // arbitrary, a little bigger this time
208    TestFifoBuffer tester(capacity);
209    tester.checkWrappingWriteRead();
210}
211
212TEST(test_fifo_buffer, fifo_read_write_small_large) {
213    constexpr int capacity = 51; // arbitrary
214    TestFifoBuffer tester(capacity);
215    tester.checkWriteReadSmallLarge();
216}
217
218TEST(test_fifo_buffer, fifo_random_read_write) {
219    constexpr int capacity = 51; // arbitrary
220    TestFifoBuffer tester(capacity);
221    tester.checkRandomWriteRead();
222}
223
224TEST(test_fifo_buffer, fifo_random_threshold) {
225    constexpr int capacity = 67; // arbitrary
226    constexpr int threshold = 37; // arbitrary
227    TestFifoBuffer tester(capacity, threshold);
228    tester.checkRandomWriteRead();
229}
230