View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      https://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.commons.lang3;
19  
20  import static org.junit.jupiter.api.Assertions.assertEquals;
21  import static org.junit.jupiter.api.Assertions.assertFalse;
22  import static org.junit.jupiter.api.Assertions.assertThrows;
23  import static org.junit.jupiter.api.Assertions.assertTrue;
24  
25  import org.junit.jupiter.api.Test;
26  
27  /**
28   * Tests {@link BitField} constructed with int masks.
29   */
30  class BitFieldTest extends AbstractLangTest {
31  
32      private static final BitField BF_MULTI = new BitField(0x3F80);
33  
34      private static final BitField BF_SINGLE = new BitField(0x4000);
35  
36      private static final BitField BF_ZERO = new BitField(0);
37  
38      @Test
39      void testByteBoolean() {
40          assertEquals(0, new BitField(0).setByteBoolean((byte) 0, true));
41          assertEquals(1, new BitField(1).setByteBoolean((byte) 0, true));
42          assertEquals(2, new BitField(2).setByteBoolean((byte) 0, true));
43          assertEquals(4, new BitField(4).setByteBoolean((byte) 0, true));
44          assertEquals(8, new BitField(8).setByteBoolean((byte) 0, true));
45          assertEquals(16, new BitField(16).setByteBoolean((byte) 0, true));
46          assertEquals(32, new BitField(32).setByteBoolean((byte) 0, true));
47          assertEquals(64, new BitField(64).setByteBoolean((byte) 0, true));
48          assertEquals(-128, new BitField(128).setByteBoolean((byte) 0, true));
49          assertEquals(1, new BitField(0).setByteBoolean((byte) 1, false));
50          assertEquals(0, new BitField(1).setByteBoolean((byte) 1, false));
51          assertEquals(0, new BitField(2).setByteBoolean((byte) 2, false));
52          assertEquals(0, new BitField(4).setByteBoolean((byte) 4, false));
53          assertEquals(0, new BitField(8).setByteBoolean((byte) 8, false));
54          assertEquals(0, new BitField(16).setByteBoolean((byte) 16, false));
55          assertEquals(0, new BitField(32).setByteBoolean((byte) 32, false));
56          assertEquals(0, new BitField(64).setByteBoolean((byte) 64, false));
57          assertEquals(0, new BitField(128).setByteBoolean((byte) 128, false));
58          assertEquals(-2, new BitField(1).setByteBoolean((byte) 255, false));
59          final byte clearedBit = new BitField(0x40).setByteBoolean((byte) -63, false);
60          assertFalse(new BitField(0x40).isSet(clearedBit));
61      }
62  
63      /**
64       * Tests the {@link BitField#clear()} method.
65       */
66      @Test
67      void testClearInt() {
68          assertEquals(BF_MULTI.clear(-1), 0xFFFFC07F);
69          assertEquals(BF_SINGLE.clear(-1), 0xFFFFBFFF);
70          assertEquals(BF_ZERO.clear(-1), 0xFFFFFFFF);
71      }
72  
73      /**
74       * Tests the {@link BitField#clear()} method.
75       */
76      @Test
77      void testClearLong() {
78          assertEquals(BF_MULTI.clear(-1L), 0xFFFFC07F);
79          assertEquals(BF_SINGLE.clear(-1L), 0xFFFFBFFF);
80          assertEquals(BF_ZERO.clear(-1L), 0xFFFFFFFF);
81      }
82  
83      /**
84       * Tests the {@link BitField#clearShort()} method.
85       */
86      @Test
87      void testClearShort() {
88          assertEquals(BF_MULTI.clearShort((short) -1), (short) 0xC07F);
89          assertEquals(BF_SINGLE.clearShort((short) -1), (short) 0xBFFF);
90          assertEquals(BF_ZERO.clearShort((short) -1), (short) 0xFFFF);
91      }
92  
93      /**
94       * Tests the {@link BitField#getRawValue()} method.
95       */
96      @Test
97      void testGetRawValue() {
98          assertEquals(BF_MULTI.getRawValue(-1), 0x3F80);
99          assertEquals(BF_MULTI.getRawValue(0), 0);
100         assertEquals(BF_SINGLE.getRawValue(-1), 0x4000);
101         assertEquals(BF_SINGLE.getRawValue(0), 0);
102         assertEquals(BF_ZERO.getRawValue(-1), 0);
103         assertEquals(BF_ZERO.getRawValue(0), 0);
104     }
105 
106     /**
107      * Tests the {@link BitField#getShortRawValue()} method.
108      */
109     @Test
110     void testGetShortRawValue() {
111         assertEquals(BF_MULTI.getShortRawValue((short) -1), (short) 0x3F80);
112         assertEquals(BF_MULTI.getShortRawValue((short) 0), (short) 0);
113         assertEquals(BF_SINGLE.getShortRawValue((short) -1), (short) 0x4000);
114         assertEquals(BF_SINGLE.getShortRawValue((short) 0), (short) 0);
115         assertEquals(BF_ZERO.getShortRawValue((short) -1), (short) 0);
116         assertEquals(BF_ZERO.getShortRawValue((short) 0), (short) 0);
117     }
118 
119     /**
120      * Tests the {@link BitField#getShortValue()} method.
121      */
122     @Test
123     void testGetShortValue() {
124         assertEquals(BF_MULTI.getShortValue((short) -1), (short) 127);
125         assertEquals(BF_MULTI.getShortValue((short) 0), (short) 0);
126         assertEquals(BF_SINGLE.getShortValue((short) -1), (short) 1);
127         assertEquals(BF_SINGLE.getShortValue((short) 0), (short) 0);
128         assertEquals(BF_ZERO.getShortValue((short) -1), (short) 0);
129         assertEquals(BF_ZERO.getShortValue((short) 0), (short) 0);
130     }
131 
132     /**
133      * Tests the {@link BitField#getValue()} method.
134      */
135     @Test
136     void testGetValue() {
137         assertEquals(BF_MULTI.getValue(-1), 127);
138         assertEquals(BF_MULTI.getValue(0), 0);
139         assertEquals(BF_SINGLE.getValue(-1), 1);
140         assertEquals(BF_SINGLE.getValue(0), 0);
141         assertEquals(BF_ZERO.getValue(-1), 0);
142         assertEquals(BF_ZERO.getValue(0), 0);
143     }
144 
145     /**
146      * Tests that {@link BitField#getValue(int)} and {@link BitField#getValue(long)} shift the selected bits right without sign extension when the field occupies
147      * the top bit of the holder (bit 31 for int, bit 63 for long).
148      */
149     @Test
150     void testGetValueTopBit() {
151         final BitField bit31 = new BitField(0x80000000);
152         assertEquals(bit31.getValue(-1), 1);
153         assertEquals(bit31.getValue(0), 0);
154         final BitField topByte = new BitField(0xFF000000);
155         assertEquals(topByte.getValue(0xFF000000), 255);
156         // The int and long overloads must agree for the same field and holder.
157         assertEquals(topByte.getValue(0xFF000000L), 255L);
158         // Verify the int and long overloads agree for the same field and holder.
159         assertEquals(topByte.getValue(0xFF000000L), topByte.getValue(0xFF000000));
160         final BitField bit63 = new BitField(0x8000000000000000L);
161         assertEquals(bit63.getValue(0x8000000000000000L), 1L);
162         assertEquals(bit63.getValue(0L), 0L);
163         final BitField topNibble = new BitField(0xF000000000000000L);
164         assertEquals(topNibble.getValue(topNibble.setValue(0L, 15L)), 15L);
165     }
166 
167     /**
168      * Tests that an int mask with the high bit set is treated as 32 unsigned bits on the long methods, instead of being sign-extended into bits 32-63.
169      */
170     @Test
171     void testIntMaskHighBitOnLongHolder() {
172         final BitField bit31 = new BitField(0x80000000);
173         assertEquals(bit31.getRawValue(-1L), 0x80000000L);
174         assertEquals(bit31.getValue(-1L), 1L);
175         assertEquals(bit31.clear(-1L), 0xFFFFFFFF7FFFFFFFL);
176         assertEquals(bit31.set(0L), 0x80000000L);
177         assertTrue(bit31.isSet(0x80000000L));
178         assertTrue(bit31.isAllSet(0x80000000L));
179         final BitField topByte = new BitField(0xFF000000);
180         assertEquals(topByte.getRawValue(-1L), 0xFF000000L);
181         assertEquals(topByte.getValue(-1L), 0xFFL);
182         assertEquals(topByte.clear(-1L), 0xFFFFFFFF00FFFFFFL);
183     }
184 
185     /**
186      * Tests the {@link BitField#isAllSet()} method.
187      */
188     @Test
189     void testIsAllSet() {
190         for (int j = 0; j < 0x3F80; j += 0x80) {
191             assertFalse(BF_MULTI.isAllSet(j));
192             assertTrue(BF_ZERO.isAllSet(j));
193         }
194         assertTrue(BF_MULTI.isAllSet(0x3F80));
195         assertFalse(BF_SINGLE.isAllSet(0));
196         assertTrue(BF_SINGLE.isAllSet(0x4000));
197     }
198 
199     /**
200      * test the isSet() method.
201      */
202     @Test
203     void testIsSet() {
204         assertFalse(BF_MULTI.isSet(0));
205         assertFalse(BF_ZERO.isSet(0));
206         for (int j = 0x80; j <= 0x3F80; j += 0x80) {
207             assertTrue(BF_MULTI.isSet(j));
208         }
209         for (int j = 0x80; j <= 0x3F80; j += 0x80) {
210             assertFalse(BF_ZERO.isSet(j));
211         }
212         assertFalse(BF_SINGLE.isSet(0));
213         assertTrue(BF_SINGLE.isSet(0x4000));
214     }
215 
216     /**
217      * Tests the {@link BitField#set()} method.
218      */
219     @Test
220     void testSet() {
221         assertEquals(BF_MULTI.set(0), 0x3F80);
222         assertEquals(BF_SINGLE.set(0), 0x4000);
223         assertEquals(BF_ZERO.set(0), 0);
224     }
225 
226     /**
227      * Tests the {@link BitField#setBoolean()} method.
228      */
229     @Test
230     void testSetBoolean() {
231         assertEquals(BF_MULTI.set(0), BF_MULTI.setBoolean(0, true));
232         assertEquals(BF_SINGLE.set(0), BF_SINGLE.setBoolean(0, true));
233         assertEquals(BF_ZERO.set(0), BF_ZERO.setBoolean(0, true));
234         assertEquals(BF_MULTI.clear(-1), BF_MULTI.setBoolean(-1, false));
235         assertEquals(BF_SINGLE.clear(-1), BF_SINGLE.setBoolean(-1, false));
236         assertEquals(BF_ZERO.clear(-1), BF_ZERO.setBoolean(-1, false));
237     }
238 
239     /**
240      * Tests the {@link BitField#setShort()} method.
241      */
242     @Test
243     void testSetShort() {
244         assertEquals(BF_MULTI.setShort((short) 0), (short) 0x3F80);
245         assertEquals(BF_SINGLE.setShort((short) 0), (short) 0x4000);
246         assertEquals(BF_ZERO.setShort((short) 0), (short) 0);
247     }
248 
249     /**
250      * test the setShortBoolean() method
251      */
252     @Test
253     void testSetShortBoolean() {
254         assertEquals(BF_MULTI.setShort((short) 0), BF_MULTI.setShortBoolean((short) 0, true));
255         assertEquals(BF_SINGLE.setShort((short) 0), BF_SINGLE.setShortBoolean((short) 0, true));
256         assertEquals(BF_ZERO.setShort((short) 0), BF_ZERO.setShortBoolean((short) 0, true));
257         assertEquals(BF_MULTI.clearShort((short) -1), BF_MULTI.setShortBoolean((short) -1, false));
258         assertEquals(BF_SINGLE.clearShort((short) -1), BF_SINGLE.setShortBoolean((short) -1, false));
259         assertEquals(BF_ZERO.clearShort((short) -1), BF_ZERO.setShortBoolean((short) -1, false));
260     }
261 
262     /**
263      * test the setShortValue() method
264      */
265     @Test
266     void testSetShortValue() {
267         final int limit = 128;
268         for (int j = 0; j < limit; j++) {
269             assertEquals(BF_MULTI.getShortValue(BF_MULTI.setShortValue((short) 0, (short) j)), (short) j);
270             assertEquals(BF_MULTI.setShortValue((short) 0, (short) j), (short) (j << 7));
271         }
272         for (int j = 0; j < limit; j++) {
273             assertEquals(BF_ZERO.getShortValue(BF_ZERO.setShortValue((short) 0, (short) j)), (short) 0);
274             assertEquals(BF_ZERO.setShortValue((short) 0, (short) j), (short) 0);
275         }
276         // verify that excess bits are stripped off
277         assertEquals(BF_MULTI.setShortValue((short) 0x3f80, (short) 128), (short) 0);
278         for (int j = 0; j < 2; j++) {
279             assertEquals(BF_SINGLE.getShortValue(BF_SINGLE.setShortValue((short) 0, (short) j)), (short) j);
280             assertEquals(BF_SINGLE.setShortValue((short) 0, (short) j), (short) (j << 14));
281         }
282         // verify that excess bits are stripped off
283         assertEquals(BF_SINGLE.setShortValue((short) 0x4000, (short) 2), (short) 0);
284     }
285 
286     /**
287      * test the setValue() method
288      */
289     @Test
290     void testSetValue() {
291         final int limit = 128;
292         for (int j = 0; j < limit; j++) {
293             assertEquals(BF_MULTI.getValue(BF_MULTI.setValue(0, j)), j);
294             assertEquals(BF_MULTI.setValue(0, j), j << 7);
295         }
296         for (int j = 0; j < limit; j++) {
297             assertEquals(BF_ZERO.getValue(BF_ZERO.setValue(0, j)), 0);
298             assertEquals(BF_ZERO.setValue(0, j), 0);
299         }
300         // verify that excess bits are stripped off
301         assertEquals(BF_MULTI.setValue(0x3f80, 128), 0);
302         for (int j = 0; j < 2; j++) {
303             assertEquals(BF_SINGLE.getValue(BF_SINGLE.setValue(0, j)), j);
304             assertEquals(BF_SINGLE.setValue(0, j), j << 14);
305         }
306         // verify that excess bits are stripped off
307         assertEquals(BF_SINGLE.setValue(0x4000, 2), 0);
308     }
309 
310     /**
311      * Tests that a mask wider than 32 bits (only constructible via {@link BitField#BitField(long)}) makes every int/short/byte holder accessor fail loudly
312      * instead of silently answering wrongly, and that a long-constructed mask that fits in 32 bits keeps working with the narrow accessors.
313      */
314     @Test
315     void testWideMaskRejectsNarrowHolderAccessors() {
316         final BitField wide = new BitField(0x100000000L);
317         // Before the guard, sign extension made every above-bit-31 flag read as set on any negative int holder.
318         assertThrows(IllegalStateException.class, () -> wide.isSet(-1));
319         assertThrows(IllegalStateException.class, () -> wide.isAllSet(-1));
320         assertThrows(IllegalStateException.class, () -> wide.getValue(-1));
321         assertThrows(IllegalStateException.class, () -> wide.getRawValue(-1));
322         assertThrows(IllegalStateException.class, () -> wide.getShortValue((short) -1));
323         assertThrows(IllegalStateException.class, () -> wide.getShortRawValue((short) -1));
324         assertThrows(IllegalStateException.class, () -> wide.clear(-1));
325         assertThrows(IllegalStateException.class, () -> wide.clearByte((byte) -1));
326         assertThrows(IllegalStateException.class, () -> wide.clearShort((short) -1));
327         assertThrows(IllegalStateException.class, () -> wide.set(0));
328         assertThrows(IllegalStateException.class, () -> wide.setBoolean(0, true));
329         assertThrows(IllegalStateException.class, () -> wide.setByte((byte) 0));
330         assertThrows(IllegalStateException.class, () -> wide.setByteBoolean((byte) 0, true));
331         assertThrows(IllegalStateException.class, () -> wide.setShort((short) 0));
332         assertThrows(IllegalStateException.class, () -> wide.setShortBoolean((short) 0, true));
333         assertThrows(IllegalStateException.class, () -> wide.setShortValue((short) 0, (short) 1));
334         assertThrows(IllegalStateException.class, () -> wide.setValue(0, 1));
335         // The long accessors remain fully functional for the same field.
336         assertFalse(wide.isSet(0xFFFFFFFFL));
337         assertTrue(wide.isSet(0x100000000L));
338         assertEquals(1L, wide.getValue(0x100000000L));
339         assertEquals(0x100000000L, wide.set(0L));
340         // A long-constructed mask that fits in 32 bits keeps working with the narrow accessors.
341         final BitField narrow = new BitField(0x80000000L);
342         assertTrue(narrow.isSet(-1));
343         assertEquals(1, narrow.getValue(-1));
344         assertEquals(0x80000000, narrow.set(0));
345     }
346 }