1 /*
2  * Copyright (C) 2017 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 package com.android.internal.util;
18 
19 import static org.junit.Assert.assertNull;
20 import static org.junit.Assert.fail;
21 
22 import androidx.test.filters.SmallTest;
23 import androidx.test.runner.AndroidJUnit4;
24 
25 import org.junit.Test;
26 import org.junit.runner.RunWith;
27 
28 import java.util.Arrays;
29 import java.util.Objects;
30 
31 @SmallTest
32 @RunWith(AndroidJUnit4.class)
33 public class RingBufferTest {
34 
35     @Test
testEmptyRingBuffer()36     public void testEmptyRingBuffer() {
37         RingBuffer<String> buffer = new RingBuffer<>(String.class, 100);
38 
39         assertArraysEqual(new String[0], buffer.toArray());
40     }
41 
42     @Test
testIncorrectConstructorArguments()43     public void testIncorrectConstructorArguments() {
44         try {
45             RingBuffer<String> buffer = new RingBuffer<>(String.class, -10);
46             fail("Should not be able to create a negative capacity RingBuffer");
47         } catch (IllegalArgumentException expected) {
48         }
49 
50         try {
51             RingBuffer<String> buffer = new RingBuffer<>(String.class, 0);
52             fail("Should not be able to create a 0 capacity RingBuffer");
53         } catch (IllegalArgumentException expected) {
54         }
55     }
56 
57     @Test
testRingBufferWithNoWrapping()58     public void testRingBufferWithNoWrapping() {
59         RingBuffer<String> buffer = new RingBuffer<>(String.class, 100);
60 
61         buffer.append("a");
62         buffer.append("b");
63         buffer.append("c");
64         buffer.append("d");
65         buffer.append("e");
66 
67         String[] expected = {"a", "b", "c", "d", "e"};
68         assertArraysEqual(expected, buffer.toArray());
69     }
70 
71     @Test
testRingBufferWithCapacity1()72     public void testRingBufferWithCapacity1() {
73         RingBuffer<String> buffer = new RingBuffer<>(String.class, 1);
74 
75         buffer.append("a");
76         assertArraysEqual(new String[]{"a"}, buffer.toArray());
77 
78         buffer.append("b");
79         assertArraysEqual(new String[]{"b"}, buffer.toArray());
80 
81         buffer.append("c");
82         assertArraysEqual(new String[]{"c"}, buffer.toArray());
83 
84         buffer.append("d");
85         assertArraysEqual(new String[]{"d"}, buffer.toArray());
86 
87         buffer.append("e");
88         assertArraysEqual(new String[]{"e"}, buffer.toArray());
89     }
90 
91     @Test
testRingBufferWithWrapping()92     public void testRingBufferWithWrapping() {
93         int capacity = 100;
94         RingBuffer<String> buffer = new RingBuffer<>(String.class, capacity);
95 
96         buffer.append("a");
97         buffer.append("b");
98         buffer.append("c");
99         buffer.append("d");
100         buffer.append("e");
101 
102         String[] expected1 = {"a", "b", "c", "d", "e"};
103         assertArraysEqual(expected1, buffer.toArray());
104 
105         String[] expected2 = new String[capacity];
106         int firstIndex = 0;
107         int lastIndex = capacity - 1;
108 
109         expected2[firstIndex] = "e";
110         for (int i = 1; i < capacity; i++) {
111             buffer.append("x");
112             expected2[i] = "x";
113         }
114         assertArraysEqual(expected2, buffer.toArray());
115 
116         buffer.append("x");
117         expected2[firstIndex] = "x";
118         assertArraysEqual(expected2, buffer.toArray());
119 
120         for (int i = 0; i < 10; i++) {
121             for (String s : expected2) {
122                 buffer.append(s);
123             }
124         }
125         assertArraysEqual(expected2, buffer.toArray());
126 
127         buffer.append("a");
128         expected2[lastIndex] = "a";
129         assertArraysEqual(expected2, buffer.toArray());
130     }
131 
132     @Test
testGetNextSlot()133     public void testGetNextSlot() {
134         int capacity = 100;
135         RingBuffer<DummyClass1> buffer = new RingBuffer<>(DummyClass1.class, capacity);
136 
137         final DummyClass1[] actual = new DummyClass1[capacity];
138         final DummyClass1[] expected = new DummyClass1[capacity];
139         for (int i = 0; i < capacity; ++i) {
140             final DummyClass1 obj = buffer.getNextSlot();
141             obj.x = capacity * i;
142             actual[i] = obj;
143             expected[i] = new DummyClass1();
144             expected[i].x = capacity * i;
145         }
146         assertArraysEqual(expected, buffer.toArray());
147 
148         for (int i = 0; i < capacity; ++i) {
149             if (actual[i] != buffer.getNextSlot()) {
150                 fail("getNextSlot() should re-use objects if available");
151             }
152         }
153 
154         RingBuffer<DummyClass2> buffer2 = new RingBuffer<>(DummyClass2.class, capacity);
155         assertNull("getNextSlot() should return null if the object can't be initiated "
156                 + "(No nullary constructor)", buffer2.getNextSlot());
157 
158         RingBuffer<DummyClass3> buffer3 = new RingBuffer<>(DummyClass3.class, capacity);
159         assertNull("getNextSlot() should return null if the object can't be initiated "
160                 + "(Inaccessible class)", buffer3.getNextSlot());
161     }
162 
163     public static final class DummyClass1 {
164         int x;
165 
equals(Object o)166         public boolean equals(Object o) {
167             if (o instanceof DummyClass1) {
168                 final DummyClass1 other = (DummyClass1) o;
169                 return other.x == this.x;
170             }
171             return false;
172         }
173     }
174 
175     public static final class DummyClass2 {
DummyClass2(int x)176         public DummyClass2(int x) {}
177     }
178 
179     private static final class DummyClass3 {}
180 
assertArraysEqual(T[] expected, T[] got)181     static <T> void assertArraysEqual(T[] expected, T[] got) {
182         if (expected.length != got.length) {
183             fail(Arrays.toString(expected) + " and " + Arrays.toString(got)
184                     + " did not have the same length");
185         }
186 
187         for (int i = 0; i < expected.length; i++) {
188             if (!Objects.equals(expected[i], got[i])) {
189                 fail(Arrays.toString(expected) + " and " + Arrays.toString(got)
190                         + " were not equal");
191             }
192         }
193     }
194 }
195