SerializationTester.java revision 8033ba2bd4b8eab11e67738ba4d1390e1fb72111
1984dc62f58d1f9611ebccc2598f714c15242a6ebJesse Wilson/*
2984dc62f58d1f9611ebccc2598f714c15242a6ebJesse Wilson * Copyright (C) 2010 Google Inc.
3984dc62f58d1f9611ebccc2598f714c15242a6ebJesse Wilson *
4984dc62f58d1f9611ebccc2598f714c15242a6ebJesse Wilson * Licensed under the Apache License, Version 2.0 (the "License");
5984dc62f58d1f9611ebccc2598f714c15242a6ebJesse Wilson * you may not use this file except in compliance with the License.
6984dc62f58d1f9611ebccc2598f714c15242a6ebJesse Wilson * You may obtain a copy of the License at
7984dc62f58d1f9611ebccc2598f714c15242a6ebJesse Wilson *
8984dc62f58d1f9611ebccc2598f714c15242a6ebJesse Wilson * http://www.apache.org/licenses/LICENSE-2.0
9984dc62f58d1f9611ebccc2598f714c15242a6ebJesse Wilson *
10984dc62f58d1f9611ebccc2598f714c15242a6ebJesse Wilson * Unless required by applicable law or agreed to in writing, software
11984dc62f58d1f9611ebccc2598f714c15242a6ebJesse Wilson * distributed under the License is distributed on an "AS IS" BASIS,
12984dc62f58d1f9611ebccc2598f714c15242a6ebJesse Wilson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13984dc62f58d1f9611ebccc2598f714c15242a6ebJesse Wilson * See the License for the specific language governing permissions and
14984dc62f58d1f9611ebccc2598f714c15242a6ebJesse Wilson * limitations under the License.
15984dc62f58d1f9611ebccc2598f714c15242a6ebJesse Wilson */
16984dc62f58d1f9611ebccc2598f714c15242a6ebJesse Wilson
174557728efb66c455a52b7669a8eefef7a9e54854Jesse Wilsonpackage libcore.java.util;
18984dc62f58d1f9611ebccc2598f714c15242a6ebJesse Wilson
19984dc62f58d1f9611ebccc2598f714c15242a6ebJesse Wilsonimport java.io.ByteArrayInputStream;
20984dc62f58d1f9611ebccc2598f714c15242a6ebJesse Wilsonimport java.io.ByteArrayOutputStream;
21984dc62f58d1f9611ebccc2598f714c15242a6ebJesse Wilsonimport java.io.IOException;
22984dc62f58d1f9611ebccc2598f714c15242a6ebJesse Wilsonimport java.io.ObjectInputStream;
23984dc62f58d1f9611ebccc2598f714c15242a6ebJesse Wilsonimport java.io.ObjectOutputStream;
248033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilsonimport static junit.framework.Assert.*;
25984dc62f58d1f9611ebccc2598f714c15242a6ebJesse Wilsonimport junit.framework.AssertionFailedError;
26984dc62f58d1f9611ebccc2598f714c15242a6ebJesse Wilson
27984dc62f58d1f9611ebccc2598f714c15242a6ebJesse Wilsonpublic class SerializableTester<T> {
28984dc62f58d1f9611ebccc2598f714c15242a6ebJesse Wilson
29984dc62f58d1f9611ebccc2598f714c15242a6ebJesse Wilson    private final String golden;
30984dc62f58d1f9611ebccc2598f714c15242a6ebJesse Wilson    private final T value;
31984dc62f58d1f9611ebccc2598f714c15242a6ebJesse Wilson
32984dc62f58d1f9611ebccc2598f714c15242a6ebJesse Wilson    public SerializableTester(T value, String golden) {
33984dc62f58d1f9611ebccc2598f714c15242a6ebJesse Wilson        this.golden = golden;
34984dc62f58d1f9611ebccc2598f714c15242a6ebJesse Wilson        this.value = value;
35984dc62f58d1f9611ebccc2598f714c15242a6ebJesse Wilson    }
36984dc62f58d1f9611ebccc2598f714c15242a6ebJesse Wilson
3719a270e90b1e992c1f6639f355ae13564c2f3a6aJesse Wilson    /**
3819a270e90b1e992c1f6639f355ae13564c2f3a6aJesse Wilson     * Returns true if {@code a} and {@code b} are equal. Override this if
3919a270e90b1e992c1f6639f355ae13564c2f3a6aJesse Wilson     * {@link Object#equals} isn't appropriate or sufficient for this tester's
4019a270e90b1e992c1f6639f355ae13564c2f3a6aJesse Wilson     * value type.
4119a270e90b1e992c1f6639f355ae13564c2f3a6aJesse Wilson     */
4219a270e90b1e992c1f6639f355ae13564c2f3a6aJesse Wilson    protected boolean equals(T a, T b) {
4319a270e90b1e992c1f6639f355ae13564c2f3a6aJesse Wilson        return a.equals(b);
4419a270e90b1e992c1f6639f355ae13564c2f3a6aJesse Wilson    }
4519a270e90b1e992c1f6639f355ae13564c2f3a6aJesse Wilson
468033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson    /**
478033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson     * Verifies that {@code deserialized} is valid. Implementations of this
488033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson     * method may mutate {@code deserialized}.
498033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson     */
50984dc62f58d1f9611ebccc2598f714c15242a6ebJesse Wilson    protected void verify(T deserialized) {}
51984dc62f58d1f9611ebccc2598f714c15242a6ebJesse Wilson
52984dc62f58d1f9611ebccc2598f714c15242a6ebJesse Wilson    public void test() {
53984dc62f58d1f9611ebccc2598f714c15242a6ebJesse Wilson        try {
54984dc62f58d1f9611ebccc2598f714c15242a6ebJesse Wilson            if (golden == null || golden.length() == 0) {
55984dc62f58d1f9611ebccc2598f714c15242a6ebJesse Wilson                fail("No golden value supplied! Consider using this: "
56984dc62f58d1f9611ebccc2598f714c15242a6ebJesse Wilson                        + hexEncode(serialize(value)));
57984dc62f58d1f9611ebccc2598f714c15242a6ebJesse Wilson            }
58984dc62f58d1f9611ebccc2598f714c15242a6ebJesse Wilson
59984dc62f58d1f9611ebccc2598f714c15242a6ebJesse Wilson            @SuppressWarnings("unchecked") // deserialize should return the proper type
60984dc62f58d1f9611ebccc2598f714c15242a6ebJesse Wilson            T deserialized = (T) deserialize(hexDecode(golden));
6119a270e90b1e992c1f6639f355ae13564c2f3a6aJesse Wilson            assertTrue("User-constructed value doesn't equal deserialized golden value",
6219a270e90b1e992c1f6639f355ae13564c2f3a6aJesse Wilson                    equals(value, deserialized));
63984dc62f58d1f9611ebccc2598f714c15242a6ebJesse Wilson
64984dc62f58d1f9611ebccc2598f714c15242a6ebJesse Wilson            @SuppressWarnings("unchecked") // deserialize should return the proper type
65984dc62f58d1f9611ebccc2598f714c15242a6ebJesse Wilson            T reserialized = (T) deserialize(serialize(value));
6619a270e90b1e992c1f6639f355ae13564c2f3a6aJesse Wilson            assertTrue("User-constructed value doesn't equal itself, reserialized",
6719a270e90b1e992c1f6639f355ae13564c2f3a6aJesse Wilson                    equals(value, reserialized));
688033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson
698033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson            // just a sanity check! if this fails, verify() is probably broken
708033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson            verify(value);
718033ba2bd4b8eab11e67738ba4d1390e1fb72111Jesse Wilson            verify(deserialized);
72984dc62f58d1f9611ebccc2598f714c15242a6ebJesse Wilson            verify(reserialized);
73984dc62f58d1f9611ebccc2598f714c15242a6ebJesse Wilson
74984dc62f58d1f9611ebccc2598f714c15242a6ebJesse Wilson        } catch (Exception e) {
75984dc62f58d1f9611ebccc2598f714c15242a6ebJesse Wilson            Error failure = new AssertionFailedError();
76984dc62f58d1f9611ebccc2598f714c15242a6ebJesse Wilson            failure.initCause(e);
77984dc62f58d1f9611ebccc2598f714c15242a6ebJesse Wilson            throw failure;
78984dc62f58d1f9611ebccc2598f714c15242a6ebJesse Wilson        }
79984dc62f58d1f9611ebccc2598f714c15242a6ebJesse Wilson    }
80984dc62f58d1f9611ebccc2598f714c15242a6ebJesse Wilson
81984dc62f58d1f9611ebccc2598f714c15242a6ebJesse Wilson    private byte[] serialize(Object object) throws IOException {
82984dc62f58d1f9611ebccc2598f714c15242a6ebJesse Wilson        ByteArrayOutputStream out = new ByteArrayOutputStream();
83984dc62f58d1f9611ebccc2598f714c15242a6ebJesse Wilson        new ObjectOutputStream(out).writeObject(object);
84984dc62f58d1f9611ebccc2598f714c15242a6ebJesse Wilson        return out.toByteArray();
85984dc62f58d1f9611ebccc2598f714c15242a6ebJesse Wilson    }
86984dc62f58d1f9611ebccc2598f714c15242a6ebJesse Wilson
87984dc62f58d1f9611ebccc2598f714c15242a6ebJesse Wilson    private Object deserialize(byte[] bytes) throws IOException, ClassNotFoundException {
88984dc62f58d1f9611ebccc2598f714c15242a6ebJesse Wilson        ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(bytes));
89984dc62f58d1f9611ebccc2598f714c15242a6ebJesse Wilson        Object result = in.readObject();
90984dc62f58d1f9611ebccc2598f714c15242a6ebJesse Wilson        assertEquals(-1, in.read());
91984dc62f58d1f9611ebccc2598f714c15242a6ebJesse Wilson        return result;
92984dc62f58d1f9611ebccc2598f714c15242a6ebJesse Wilson    }
93984dc62f58d1f9611ebccc2598f714c15242a6ebJesse Wilson
94984dc62f58d1f9611ebccc2598f714c15242a6ebJesse Wilson    private String hexEncode(byte[] bytes) {
95984dc62f58d1f9611ebccc2598f714c15242a6ebJesse Wilson        StringBuilder result = new StringBuilder(bytes.length * 2);
96984dc62f58d1f9611ebccc2598f714c15242a6ebJesse Wilson        for (byte b : bytes) {
97984dc62f58d1f9611ebccc2598f714c15242a6ebJesse Wilson            result.append(String.format("%02x", b));
98984dc62f58d1f9611ebccc2598f714c15242a6ebJesse Wilson        }
99984dc62f58d1f9611ebccc2598f714c15242a6ebJesse Wilson        return result.toString();
100984dc62f58d1f9611ebccc2598f714c15242a6ebJesse Wilson    }
101984dc62f58d1f9611ebccc2598f714c15242a6ebJesse Wilson
102984dc62f58d1f9611ebccc2598f714c15242a6ebJesse Wilson    private byte[] hexDecode(String s) {
103984dc62f58d1f9611ebccc2598f714c15242a6ebJesse Wilson        byte[] result = new byte[s.length() / 2];
104984dc62f58d1f9611ebccc2598f714c15242a6ebJesse Wilson        for (int i = 0; i < result.length; i++) {
105984dc62f58d1f9611ebccc2598f714c15242a6ebJesse Wilson            result[i] = (byte) Integer.parseInt(s.substring(i*2, i*2 + 2), 16);
106984dc62f58d1f9611ebccc2598f714c15242a6ebJesse Wilson        }
107984dc62f58d1f9611ebccc2598f714c15242a6ebJesse Wilson        return result;
108984dc62f58d1f9611ebccc2598f714c15242a6ebJesse Wilson    }
109984dc62f58d1f9611ebccc2598f714c15242a6ebJesse Wilson}
110984dc62f58d1f9611ebccc2598f714c15242a6ebJesse Wilson
111