1/*
2 * Copyright (C) 2015 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
17package android.databinding;
18
19import android.os.Parcel;
20import android.os.Parcelable;
21import android.test.AndroidTestCase;
22
23import java.io.ByteArrayInputStream;
24import java.io.ByteArrayOutputStream;
25import java.io.Closeable;
26import java.io.IOException;
27import java.io.ObjectInputStream;
28import java.io.ObjectOutputStream;
29import java.io.Serializable;
30import java.util.UUID;
31
32public class ObservableParcelTest extends AndroidTestCase {
33    public void testParcelInt() {
34        ObservableInt observableInt = new ObservableInt();
35        observableInt.set(Integer.MAX_VALUE - 1);
36        ObservableInt read = parcelAndUnparcel(observableInt, ObservableInt.class);
37        assertEquals(Integer.MAX_VALUE - 1, read.get());
38    }
39
40    public void testParcelBoolean() {
41        ObservableBoolean obj = new ObservableBoolean(false);
42        ObservableBoolean read = parcelAndUnparcel(obj, ObservableBoolean.class);
43        assertFalse(read.get());
44
45        ObservableBoolean obj2 = new ObservableBoolean(true);
46        ObservableBoolean read2 = parcelAndUnparcel(obj2, ObservableBoolean.class);
47        assertTrue(read2.get());
48    }
49
50    public void testParcelByte() {
51        ObservableByte obj = new ObservableByte((byte) 7);
52        ObservableByte read = parcelAndUnparcel(obj, ObservableByte.class);
53        assertEquals((byte) 7, read.get());
54    }
55
56    public void testParcelChar() {
57        ObservableChar obj = new ObservableChar('y');
58        ObservableChar read = parcelAndUnparcel(obj, ObservableChar.class);
59        assertEquals('y', read.get());
60    }
61
62    public void testParcelDouble() {
63        ObservableDouble obj = new ObservableDouble(Double.MAX_VALUE);
64        ObservableDouble read = parcelAndUnparcel(obj, ObservableDouble.class);
65        assertEquals(Double.MAX_VALUE, read.get());
66    }
67
68    public void testParcelFloat() {
69        ObservableFloat obj = new ObservableFloat(Float.MIN_VALUE);
70        ObservableFloat read = parcelAndUnparcel(obj, ObservableFloat.class);
71        assertEquals(Float.MIN_VALUE, read.get());
72    }
73
74    public void testParcelParcel() {
75        MyParcelable myParcelable = new MyParcelable(5, "foo");
76        ObservableParcelable<MyParcelable> obj = new ObservableParcelable<>(myParcelable);
77        ObservableParcelable read = parcelAndUnparcel(obj,
78                ObservableParcelable.class);
79        assertEquals(myParcelable, read.get());
80    }
81
82    public void testParcelLong() {
83        ObservableLong obj = new ObservableLong(Long.MAX_VALUE - 1);
84        ObservableLong read = parcelAndUnparcel(obj, ObservableLong.class);
85        assertEquals(Long.MAX_VALUE - 1, read.get());
86    }
87
88    public void testParcelShort() {
89        ObservableShort obj = new ObservableShort(Short.MIN_VALUE);
90        ObservableShort read = parcelAndUnparcel(obj, ObservableShort.class);
91        assertEquals(Short.MIN_VALUE, read.get());
92    }
93
94    public void testSerializeInt() throws IOException, ClassNotFoundException {
95        ObservableInt observableInt = new ObservableInt();
96        observableInt.set(Integer.MAX_VALUE - 1);
97        ObservableInt read = serializeAndDeserialize(observableInt, ObservableInt.class);
98        assertEquals(Integer.MAX_VALUE - 1, read.get());
99    }
100
101    public void testSerializeBoolean() throws IOException, ClassNotFoundException {
102        ObservableBoolean obj = new ObservableBoolean(false);
103        ObservableBoolean read = serializeAndDeserialize(obj, ObservableBoolean.class);
104        assertFalse(read.get());
105        ObservableBoolean obj2 = new ObservableBoolean(true);
106        ObservableBoolean read2 = serializeAndDeserialize(obj2, ObservableBoolean.class);
107        assertTrue(read2.get());
108    }
109
110    public void testSerializeByte() throws IOException, ClassNotFoundException {
111        ObservableByte obj = new ObservableByte((byte) 7);
112        ObservableByte read = serializeAndDeserialize(obj, ObservableByte.class);
113        assertEquals((byte) 7, read.get());
114    }
115
116    public void testSerializeChar() throws IOException, ClassNotFoundException {
117        ObservableChar obj = new ObservableChar('y');
118        ObservableChar read = serializeAndDeserialize(obj, ObservableChar.class);
119        assertEquals('y', read.get());
120    }
121
122    public void testSerializeDouble() throws IOException, ClassNotFoundException {
123        ObservableDouble obj = new ObservableDouble(Double.MAX_VALUE);
124        ObservableDouble read = serializeAndDeserialize(obj, ObservableDouble.class);
125        assertEquals(Double.MAX_VALUE, read.get());
126    }
127
128    public void testSerializeFloat() throws IOException, ClassNotFoundException {
129        ObservableFloat obj = new ObservableFloat(Float.MIN_VALUE);
130        ObservableFloat read = serializeAndDeserialize(obj, ObservableFloat.class);
131        assertEquals(Float.MIN_VALUE, read.get());
132    }
133
134    public void testSerializeParcel() throws IOException, ClassNotFoundException {
135        MyParcelable myParcelable = new MyParcelable(5, "foo");
136        ObservableParcelable<MyParcelable> obj = new ObservableParcelable<>(myParcelable);
137        ObservableParcelable read = serializeAndDeserialize(obj,
138                ObservableParcelable.class);
139        assertEquals(myParcelable, read.get());
140    }
141
142    public void testSerializeField() throws IOException, ClassNotFoundException {
143        MyParcelable myParcelable = new MyParcelable(5, "foo");
144        ObservableField<MyParcelable> obj = new ObservableField<>(myParcelable);
145        ObservableField read = serializeAndDeserialize(obj, ObservableField.class);
146        assertEquals(myParcelable, read.get());
147    }
148
149    public void testSerializeLong() throws IOException, ClassNotFoundException {
150        ObservableLong obj = new ObservableLong(Long.MAX_VALUE - 1);
151        ObservableLong read = serializeAndDeserialize(obj, ObservableLong.class);
152        assertEquals(Long.MAX_VALUE - 1, read.get());
153    }
154
155    public void testSerializeShort() throws IOException, ClassNotFoundException {
156        ObservableShort obj = new ObservableShort(Short.MIN_VALUE);
157        ObservableShort read = serializeAndDeserialize(obj, ObservableShort.class);
158        assertEquals(Short.MIN_VALUE, read.get());
159    }
160
161    private <T extends Parcelable> T parcelAndUnparcel(T t, Class<T> klass) {
162        Parcel parcel = Parcel.obtain();
163        parcel.writeParcelable(t, 0);
164        // we append a suffix to the parcelable to test out of bounds
165        String parcelSuffix = UUID.randomUUID().toString();
166        parcel.writeString(parcelSuffix);
167        // get ready to read
168        parcel.setDataPosition(0);
169        Parcelable parcelable = parcel.readParcelable(getClass().getClassLoader());
170        assertNotNull(parcelable);
171        assertEquals(klass, parcelable.getClass());
172        assertEquals(parcelSuffix, parcel.readString());
173        return (T) parcelable;
174    }
175
176    private <T> T serializeAndDeserialize(T t, Class<T> klass)
177            throws IOException, ClassNotFoundException {
178        ObjectOutputStream oos = null;
179        ByteArrayOutputStream bos = null;
180        String suffix = UUID.randomUUID().toString();
181        try {
182            bos = new ByteArrayOutputStream();
183            oos = new ObjectOutputStream(bos);
184            oos.writeObject(t);
185            oos.writeObject(suffix);
186        } finally {
187            closeQuietly(bos);
188            closeQuietly(oos);
189        }
190        ByteArrayInputStream bis = null;
191        ObjectInputStream ois = null;
192        try {
193            bis = new ByteArrayInputStream(bos.toByteArray());
194            ois = new ObjectInputStream(bis);
195            Object o = ois.readObject();
196            assertEquals(klass, o.getClass());
197            assertEquals(suffix, ois.readObject());
198            return (T) o;
199        } finally {
200            closeQuietly(bis);
201            closeQuietly(ois);
202        }
203    }
204
205    private static void closeQuietly(Closeable closeable) {
206        try {
207            if (closeable != null) {
208                closeable.close();
209            }
210        } catch (IOException ignored) {
211        }
212    }
213
214    public static class MyParcelable implements Parcelable, Serializable {
215        int x;
216        String y;
217
218        public MyParcelable() {
219        }
220
221        public MyParcelable(int x, String y) {
222            this.x = x;
223            this.y = y;
224        }
225
226        @Override
227        public int describeContents() {
228            return 0;
229        }
230
231        @Override
232        public void writeToParcel(Parcel dest, int flags) {
233            dest.writeInt(x);
234            dest.writeString(y);
235        }
236
237        @Override
238        public boolean equals(Object o) {
239            if (this == o) {
240                return true;
241            }
242            if (o == null || getClass() != o.getClass()) {
243                return false;
244            }
245
246            MyParcelable that = (MyParcelable) o;
247
248            if (x != that.x) {
249                return false;
250            }
251            if (y != null ? !y.equals(that.y) : that.y != null) {
252                return false;
253            }
254
255            return true;
256        }
257
258        @Override
259        public int hashCode() {
260            int result = x;
261            result = 31 * result + (y != null ? y.hashCode() : 0);
262            return result;
263        }
264
265        public static final Parcelable.Creator<MyParcelable> CREATOR
266                = new Parcelable.Creator<MyParcelable>() {
267
268            @Override
269            public MyParcelable createFromParcel(Parcel source) {
270                return new MyParcelable(source.readInt(), source.readString());
271            }
272
273            @Override
274            public MyParcelable[] newArray(int size) {
275                return new MyParcelable[size];
276            }
277        };
278    }
279}
280