/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.avro.io; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.nio.ByteBuffer; import java.util.Random; import org.apache.avro.util.Utf8; import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; public class TestBinaryEncoderFidelity { static byte[] legacydata; static byte[] complexdata; EncoderFactory factory = EncoderFactory.get(); public static void generateData(Encoder e, boolean useReadOnlyByteBuffer) throws IOException { // generate a bunch of data that should test the bounds of a BinaryEncoder Random r = new Random(665321); e.writeNull(); e.writeBoolean(true); e.writeBoolean(false); byte[] bytes = new byte[10]; ByteBuffer bb; if (useReadOnlyByteBuffer) { bb = ByteBuffer.wrap(bytes, 4, 4).asReadOnlyBuffer(); } else { bb = ByteBuffer.wrap(bytes, 4, 4); } r.nextBytes(bytes); e.writeBytes(bytes); e.writeBytes(new byte[0]); e.writeBytes(bytes, 3, 3); e.writeBytes(new byte[0], 0, 0); e.writeBytes(ByteBuffer.wrap(bytes, 2, 2)); e.writeBytes(bb); e.writeBytes(bb); e.writeDouble(0.0); e.writeDouble(-0.0); e.writeDouble(Double.NaN); e.writeDouble(r.nextDouble()); e.writeDouble(Double.NEGATIVE_INFINITY); e.writeEnum(65); e.writeFixed(bytes); e.writeFixed(bytes, 7, 2); e.writeFloat(1.0f); e.writeFloat(r.nextFloat()); e.writeFloat(Float.POSITIVE_INFINITY); e.writeFloat(Float.MIN_NORMAL); e.writeIndex(-2); e.writeInt(0); e.writeInt(-1); e.writeInt(1); e.writeInt(0x40); e.writeInt(-0x41); e.writeInt(0x2000); e.writeInt(-0x2001); e.writeInt(0x80000); e.writeInt(-0x80001); e.writeInt(0x4000000); e.writeInt(-0x4000001); e.writeInt(r.nextInt()); e.writeInt(r.nextInt()); e.writeInt(Integer.MAX_VALUE); e.writeInt(Integer.MIN_VALUE); e.writeLong(0); e.writeLong(-1); e.writeLong(1); e.writeLong(0x40); e.writeLong(-0x41); e.writeLong(0x2000); e.writeLong(-0x2001); e.writeLong(0x80000); e.writeLong(-0x80001); e.writeLong(0x4000000); e.writeLong(-0x4000001); e.writeLong(0x200000000L); e.writeLong(-0x200000001L); e.writeLong(0x10000000000L); e.writeLong(-0x10000000001L); e.writeLong(0x800000000000L); e.writeLong(-0x800000000001L); e.writeLong(0x40000000000000L); e.writeLong(-0x40000000000001L); e.writeLong(0x2000000000000000L); e.writeLong(-0x2000000000000001L); e.writeLong(r.nextLong()); e.writeLong(r.nextLong()); e.writeLong(Long.MAX_VALUE); e.writeLong(Long.MIN_VALUE); e.writeString(new StringBuilder("StringBuilder\u00A2")); e.writeString("String\u20AC"); e.writeString(""); e.writeString(new Utf8("Utf8\uD834\uDD1E")); if (e instanceof BinaryEncoder) { int count = ((BinaryEncoder)e).bytesBuffered(); System.out.println(e.getClass().getSimpleName() + " buffered: " + count); } e.flush(); } static void generateComplexData(Encoder e) throws IOException { e.writeArrayStart(); e.setItemCount(1); e.startItem(); e.writeInt(1); e.writeArrayEnd(); e.writeMapStart(); e.setItemCount(2); e.startItem(); e.writeString("foo"); e.writeInt(-1); e.writeDouble(33.3); e.startItem(); e.writeString("bar"); e.writeInt(1); e.writeDouble(-33.3); e.writeMapEnd(); e.flush(); } @BeforeClass public static void generateLegacyData() throws IOException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); Encoder e = new LegacyBinaryEncoder(baos); generateData(e, false); legacydata = baos.toByteArray(); baos.reset(); generateComplexData(e); complexdata = baos.toByteArray(); } @Test public void testBinaryEncoder() throws IOException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); BinaryEncoder e = factory.binaryEncoder(baos, null); generateData(e, true); byte[] result = baos.toByteArray(); Assert.assertEquals(legacydata.length, result.length); Assert.assertArrayEquals(legacydata, result); baos.reset(); generateComplexData(e); byte[] result2 = baos.toByteArray(); Assert.assertEquals(complexdata.length, result2.length); Assert.assertArrayEquals(complexdata, result2); } @Test public void testDirectBinaryEncoder() throws IOException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); BinaryEncoder e = factory.directBinaryEncoder(baos, null); generateData(e, true); byte[] result = baos.toByteArray(); Assert.assertEquals(legacydata.length, result.length); Assert.assertArrayEquals(legacydata, result); baos.reset(); generateComplexData(e); byte[] result2 = baos.toByteArray(); Assert.assertEquals(complexdata.length, result2.length); Assert.assertArrayEquals(complexdata, result2); } @Test public void testBlockingBinaryEncoder() throws IOException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); BinaryEncoder e = factory.blockingBinaryEncoder(baos, null); generateData(e, true); byte[] result = baos.toByteArray(); Assert.assertEquals(legacydata.length, result.length); Assert.assertArrayEquals(legacydata, result); baos.reset(); generateComplexData(e); byte[] result2 = baos.toByteArray(); // blocking will cause different length, should be two bytes larger Assert.assertEquals(complexdata.length + 2, result2.length); // the first byte is the array start, with the count of items negative Assert.assertEquals(complexdata[0] >>> 1, result2[0]); } }