1 /*
2  * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.
8  *
9  * This code is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * version 2 for more details (a copy is included in the LICENSE file that
13  * accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License version
16  * 2 along with this work; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  */
23 
24 /*
25  * @test
26  * @bug 4263142 4172661
27  * @summary First run verifies that objects serialize and deserialize
28  *          correctly against the current release.
29  *          Second run verifies that objects from previous releases
30  *          still deserialize correctly.  The serial_1_6.out file was
31  *          created using the "write" option under release 1.6.
32  *          The test was modified after fixing 4172661 to add testing
33  *          of Path2D serialization (and to recut the test file with
34  *          the new serialVersionUID of GeneralPath).
35  * @run main SerialTest
36  * @run main SerialTest read serial_1_6.out
37  */
38 
39 import java.awt.Shape;
40 import java.awt.geom.AffineTransform;
41 import java.awt.geom.Arc2D;
42 import java.awt.geom.CubicCurve2D;
43 import java.awt.geom.Ellipse2D;
44 import java.awt.geom.GeneralPath;
45 import java.awt.geom.Line2D;
46 import java.awt.geom.Path2D;
47 import java.awt.geom.PathIterator;
48 import java.awt.geom.Point2D;
49 import java.awt.geom.QuadCurve2D;
50 import java.awt.geom.Rectangle2D;
51 import java.awt.geom.RoundRectangle2D;
52 import java.io.ByteArrayInputStream;
53 import java.io.ByteArrayOutputStream;
54 import java.io.File;
55 import java.io.FileInputStream;
56 import java.io.FileOutputStream;
57 import java.io.IOException;
58 import java.io.InputStream;
59 import java.io.ObjectInputStream;
60 import java.io.ObjectOutputStream;
61 import java.io.OutputStream;
62 
63 public class SerialTest {
64     public static Object testobjects[] = {
65         // non-shapes...
66         new Point2D.Float(37, 42),
67         new Point2D.Double(85, 63),
68         new AffineTransform(10, 20, 30, 40, 50, 60),
69 
70         // shapes...
71         new QuadCurve2D.Float(10f, 10f, 50f, 50f, 100f, 10f),
72         new QuadCurve2D.Double(20f, 20f, 50f, 50f, 100f, 20f),
73         new CubicCurve2D.Float(10f, 10f, 50f, 10f, 10f, 50f, 50f, 50f),
74         new CubicCurve2D.Double(0.0, 0.0, 50.0, 0.0, 0.0, 50.0, 50.0, 50.0),
75         new GeneralPath(),
76         new GeneralPath(PathIterator.WIND_NON_ZERO),
77         new GeneralPath(PathIterator.WIND_EVEN_ODD),
78         makeGeneralPath(PathIterator.WIND_NON_ZERO, 5f),
79         makeGeneralPath(PathIterator.WIND_EVEN_ODD, 23f),
80         new Line2D.Float(20f, 20f, 25f, 50f),
81         new Line2D.Double(20.0, 20.0, 35.0, 50.0),
82         new Rectangle2D.Float(100f, 100f, 50f, 25f),
83         new Rectangle2D.Double(200.0, 200.0, 75.0, 35.0),
84         new RoundRectangle2D.Float(120f, 120f, 50f, 35f, 5f, 7f),
85         new RoundRectangle2D.Double(220.0, 220.0, 85.0, 45.0, 3.0, 9.0),
86         new Ellipse2D.Float(110f, 110f, 50f, 55f),
87         new Ellipse2D.Double(210.0, 210.0, 75.0, 45.0),
88         new Arc2D.Float(10f, 10f, 50f, 40f, 45f, 72f, Arc2D.OPEN),
89         new Arc2D.Float(10f, 10f, 40f, 50f, 135f, 72f, Arc2D.PIE),
90         new Arc2D.Float(10f, 10f, 40f, 60f, 225f, 72f, Arc2D.CHORD),
91         new Arc2D.Double(10.0, 20.0, 50.0, 40.0, 45.0, 72.0, Arc2D.OPEN),
92         new Arc2D.Double(10.0, 20.0, 40.0, 50.0, 135.0, 72.0, Arc2D.PIE),
93         new Arc2D.Double(10.0, 20.0, 40.0, 60.0, 225.0, 72.0, Arc2D.CHORD),
94 
95         // Paths
96         new Path2D.Float(),
97         new Path2D.Float(PathIterator.WIND_NON_ZERO),
98         new Path2D.Float(PathIterator.WIND_EVEN_ODD),
99         makePath2DFloat(PathIterator.WIND_NON_ZERO, 5f),
100         makePath2DFloat(PathIterator.WIND_EVEN_ODD, 23f),
101         new Path2D.Double(),
102         new Path2D.Double(PathIterator.WIND_NON_ZERO),
103         new Path2D.Double(PathIterator.WIND_EVEN_ODD),
104         makePath2DDouble(PathIterator.WIND_NON_ZERO, 5f),
105         makePath2DDouble(PathIterator.WIND_EVEN_ODD, 23f),
106     };
107 
makeGeneralPath(int winding, float off)108     public static Shape makeGeneralPath(int winding, float off) {
109         return fill(new GeneralPath(winding), off);
110     }
111 
makePath2DFloat(int winding, float off)112     public static Shape makePath2DFloat(int winding, float off) {
113         return fill(new Path2D.Float(winding), off);
114     }
115 
makePath2DDouble(int winding, float off)116     public static Shape makePath2DDouble(int winding, float off) {
117         return fill(new Path2D.Double(winding), off);
118     }
119 
fill(Path2D p2d, float off)120     public static Path2D fill(Path2D p2d, float off) {
121         p2d.moveTo(off+10, off+10);
122         p2d.lineTo(off+100, off+50);
123         p2d.quadTo(off+50, off+100, off+200, off+100);
124         p2d.curveTo(off+400, off+20, off+20, off+400, off+100, off+100);
125         p2d.closePath();
126         return p2d;
127     }
128 
129     static int numerrors;
130 
error(Object o1, Object o2, String reason)131     public static void error(Object o1, Object o2, String reason) {
132         System.err.println("Failed comparing: "+o1+" to "+o2);
133         System.err.println(reason);
134         numerrors++;
135     }
136 
usage(int exitcode)137     public static void usage(int exitcode) {
138         System.err.println("usage: java SerialTest [read|write] <filename>");
139         System.exit(exitcode);
140     }
141 
main(String argv[])142     public static void main(String argv[]) {
143         if (argv.length > 0) {
144             if (argv.length < 2) {
145                 usage(1);
146             }
147 
148             String arg = argv[0].toLowerCase();
149             if (arg.equals("write")) {
150                 serializeTo(argv[1]);
151             } else if (arg.equals("read")) {
152                 testFrom(argv[1]);
153             } else {
154                 usage(1);
155             }
156         } else {
157             testSerial();
158         }
159     }
160 
makeFile(String filename)161     public static File makeFile(String filename) {
162         return new File(System.getProperty("test.src", "."), filename);
163     }
164 
serializeTo(String filename)165     public static void serializeTo(String filename) {
166         FileOutputStream fos;
167         try {
168             fos = new FileOutputStream(makeFile(filename));
169         } catch (IOException ioe) {
170             throw new InternalError("bad output filename: "+filename);
171         }
172         serializeTo(fos);
173     }
174 
testFrom(String filename)175     public static void testFrom(String filename) {
176         FileInputStream fis;
177         try {
178             fis = new FileInputStream(makeFile(filename));
179         } catch (IOException ioe) {
180             throw new InternalError("bad input filename: "+filename);
181         }
182         testFrom(fis);
183     }
184 
testSerial()185     public static void testSerial() {
186         ByteArrayOutputStream baos = new ByteArrayOutputStream();
187         serializeTo(baos);
188 
189         byte buf[] = baos.toByteArray();
190         ByteArrayInputStream bais = new ByteArrayInputStream(buf);
191 
192         testFrom(bais);
193     }
194 
serializeTo(OutputStream os)195     public static void serializeTo(OutputStream os) {
196         try {
197             ObjectOutputStream oos = new ObjectOutputStream(os);
198 
199             for (Object o1: testobjects) {
200                 oos.writeObject(o1);
201             }
202 
203             oos.close();
204         } catch (IOException ioe) {
205             throw new RuntimeException(ioe);
206         }
207     }
208 
testFrom(InputStream is)209     public static void testFrom(InputStream is) {
210         try {
211             ObjectInputStream ois = new ObjectInputStream(is);
212 
213             for (Object o1: testobjects) {
214                 Object o2 = ois.readObject();
215                 if (o1 instanceof Shape) {
216                     compareShapes((Shape) o1, (Shape) o2);
217                 } else {
218                     if (!o1.equals(o2)) {
219                         error(o1, o2, "objects not equal");
220                     }
221                 }
222             }
223 
224             try {
225                 ois.readObject();
226                 throw new RuntimeException("extra data in stream");
227             } catch (IOException ioe2) {
228             }
229         } catch (IOException ioe) {
230             throw new RuntimeException(ioe);
231         } catch (ClassNotFoundException cnfe) {
232             throw new RuntimeException(cnfe);
233         }
234     }
235 
compareShapes(Shape s1, Shape s2)236     public static void compareShapes(Shape s1, Shape s2) {
237         PathIterator pi1 = s1.getPathIterator(null);
238         PathIterator pi2 = s2.getPathIterator(null);
239 
240         if (pi1.getWindingRule() != pi2.getWindingRule()) {
241             error(s1, s2, "winding rules are different");
242         }
243 
244         double coords1[] = new double[6];
245         double coords2[] = new double[6];
246 
247         while (!pi1.isDone()) {
248             if (pi2.isDone()) {
249                 error(s1, s2, "Shape 2 ended prematurely");
250                 return;
251             }
252 
253             int t1 = pi1.currentSegment(coords1);
254             int t2 = pi2.currentSegment(coords2);
255 
256             if (t1 != t2) {
257                 error(s1, s2, "different segment types");
258             }
259 
260             int ncoords;
261             switch (t1) {
262             case PathIterator.SEG_MOVETO:  ncoords = 2; break;
263             case PathIterator.SEG_LINETO:  ncoords = 2; break;
264             case PathIterator.SEG_QUADTO:  ncoords = 4; break;
265             case PathIterator.SEG_CUBICTO: ncoords = 6; break;
266             case PathIterator.SEG_CLOSE:   ncoords = 0; break;
267 
268             default:
269                 throw new RuntimeException("unknown segment type");
270             }
271 
272             for (int i = 0; i < ncoords; i++) {
273                 if (coords1[i] != coords2[i]) {
274                     error(s1, s2, "coordinates differ");
275                 }
276             }
277             pi1.next();
278             pi2.next();
279         }
280 
281         if (!pi2.isDone()) {
282             error(s1, s2, "Shape 1 ended prematurely");
283         }
284     }
285 }
286