1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.lang3.util;
19
20 import static org.junit.jupiter.api.Assertions.assertEquals;
21 import static org.junit.jupiter.api.Assertions.assertInstanceOf;
22 import static org.junit.jupiter.api.Assertions.assertThrows;
23 import static org.junit.jupiter.api.Assertions.assertTrue;
24
25 import java.io.ByteArrayInputStream;
26 import java.io.ByteArrayOutputStream;
27 import java.io.IOException;
28 import java.io.InvalidObjectException;
29 import java.io.ObjectInputStream;
30 import java.io.ObjectOutputStream;
31 import java.io.ObjectStreamClass;
32 import java.io.Serializable;
33 import java.util.BitSet;
34
35 import org.apache.commons.lang3.SerializationException;
36 import org.apache.commons.lang3.SerializationUtils;
37 import org.junit.jupiter.api.Test;
38
39
40
41
42
43
44
45 class FluentBitSetReadObjectTest {
46
47
48
49
50
51 private static final class FluentBitSetForge implements Serializable {
52
53 private static final long serialVersionUID = 1L;
54
55
56 @SuppressWarnings("unused")
57 private final BitSet bitSet;
58
59 FluentBitSetForge(final BitSet bitSet) {
60 this.bitSet = bitSet;
61 }
62 }
63
64
65
66
67 private static Object deserialize(final byte[] bytes) throws IOException, ClassNotFoundException {
68 try (ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bytes))) {
69 return ois.readObject();
70 }
71 }
72
73
74
75
76 private static byte[] forgeNullBitSetStream() throws IOException {
77 final ByteArrayOutputStream baos = new ByteArrayOutputStream();
78 try (ObjectOutputStream oos = new ObjectOutputStream(baos) {
79
80 @Override
81 protected void writeClassDescriptor(final ObjectStreamClass desc) throws IOException {
82 if (desc.getName().equals(FluentBitSetForge.class.getName())) {
83
84 super.writeClassDescriptor(ObjectStreamClass.lookup(FluentBitSet.class));
85 } else {
86 super.writeClassDescriptor(desc);
87 }
88 }
89 }) {
90 oos.writeObject(new FluentBitSetForge(null));
91 }
92 return baos.toByteArray();
93 }
94
95
96
97
98 @Test
99 void testDeserializedInstanceIsMutable() {
100 final FluentBitSet original = new FluentBitSet().set(5);
101 final FluentBitSet roundtrip = SerializationUtils.roundtrip(original);
102 assertTrue(roundtrip.get(5));
103 roundtrip.set(6);
104 assertTrue(roundtrip.get(6), "Deserialized instance must remain mutable");
105
106 assertInstanceOf(FluentBitSet.class, roundtrip);
107 assertTrue(original.get(5));
108 }
109
110
111
112
113
114 @Test
115 void testNullBitSetRejectedByObjectInputStream() throws Exception {
116 final byte[] forged = forgeNullBitSetStream();
117 final Exception ex = assertThrows(InvalidObjectException.class, () -> deserialize(forged));
118 assertTrue(ex.getMessage().contains("bitSet null"));
119 }
120
121
122
123
124
125 @Test
126 void testNullBitSetRejectedBySerializationUtils() throws Exception {
127 final byte[] forged = forgeNullBitSetStream();
128 final SerializationException ex = assertThrows(SerializationException.class, () -> SerializationUtils.deserialize(forged));
129 assertInstanceOf(InvalidObjectException.class, ex.getCause());
130 assertTrue(ex.getCause().getMessage().contains("bitSet null"));
131 }
132
133
134
135
136 @Test
137 void testRoundTripEmptyBitSet() {
138 final FluentBitSet original = new FluentBitSet();
139 final FluentBitSet roundtrip = SerializationUtils.roundtrip(original);
140 assertEquals(original, roundtrip);
141 assertTrue(roundtrip.isEmpty());
142 }
143
144
145
146
147 @Test
148 void testRoundTripPreservesBits() {
149 final FluentBitSet original = new FluentBitSet().set(1, 3, 5, 7, 100);
150 final FluentBitSet roundtrip = SerializationUtils.roundtrip(original);
151 assertEquals(original, roundtrip);
152 assertEquals(original.bitSet(), roundtrip.bitSet());
153 }
154
155
156
157
158 @Test
159 void testRoundTripPreservesHashCode() {
160 final FluentBitSet original = new FluentBitSet().set(2, 4, 8, 16);
161 assertEquals(original.hashCode(), SerializationUtils.roundtrip(original).hashCode());
162 }
163
164
165
166
167 @Test
168 void testRoundTripWithBitSetValueOf() {
169 final BitSet bs = BitSet.valueOf(new long[] { 0b1010_1010L });
170 final FluentBitSet original = new FluentBitSet(bs);
171 assertEquals(original, SerializationUtils.roundtrip(original));
172 }
173
174
175
176
177 @Test
178 void testRoundTripWithHighBitIndex() {
179 final FluentBitSet original = new FluentBitSet(256).set(0, 127, 255);
180 final FluentBitSet roundtrip = SerializationUtils.roundtrip(original);
181 assertEquals(original, roundtrip);
182 assertTrue(roundtrip.get(0));
183 assertTrue(roundtrip.get(127));
184 assertTrue(roundtrip.get(255));
185 }
186
187
188
189
190
191 @Test
192 void testTwoDeserializedInstancesAreEqual() {
193 final FluentBitSet original = new FluentBitSet().set(10, 20, 30);
194 final byte[] bytes = SerializationUtils.serialize(original);
195 final FluentBitSet first = SerializationUtils.deserialize(bytes);
196 final FluentBitSet second = SerializationUtils.deserialize(bytes);
197 assertEquals(first, second);
198 assertEquals(first.bitSet(), second.bitSet());
199 }
200 }