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