package co.nstant.in.cbor.decoder; import static org.hamcrest.core.StringContains.containsString; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.List; import org.junit.Test; import co.nstant.in.cbor.CborBuilder; import co.nstant.in.cbor.CborDecoder; import co.nstant.in.cbor.CborEncoder; import co.nstant.in.cbor.CborException; import co.nstant.in.cbor.encoder.AbstractEncoder; import co.nstant.in.cbor.model.DataItem; import co.nstant.in.cbor.model.MajorType; import co.nstant.in.cbor.model.RationalNumber; import co.nstant.in.cbor.model.Tag; import co.nstant.in.cbor.model.UnsignedInteger; public class CborDecoderTest { @Test(expected = CborException.class) public void shouldThrowCborException() throws CborException { CborDecoder cborDecoder = new CborDecoder(new InputStream() { @Override public int read() throws IOException { throw new IOException(); } }); cborDecoder.decodeNext(); } @Test(expected = CborException.class) public void shouldThrowCborException2() throws CborException { CborDecoder cborDecoder = new CborDecoder(new InputStream() { @Override public int read() throws IOException { return (8 << 5); // invalid major type } }); cborDecoder.decodeNext(); } @Test public void shouldSetAutoDecodeInfinitiveMaps() { InputStream inputStream = new ByteArrayInputStream(new byte[] { 0, 1, 2 }); CborDecoder cborDecoder = new CborDecoder(inputStream); assertTrue(cborDecoder.isAutoDecodeInfinitiveMaps()); cborDecoder.setAutoDecodeInfinitiveMaps(false); assertFalse(cborDecoder.isAutoDecodeInfinitiveMaps()); } @Test public void shouldSetAutoDecodeRationalNumbers() { InputStream inputStream = new ByteArrayInputStream(new byte[] { 0, 1, 2 }); CborDecoder cborDecoder = new CborDecoder(inputStream); assertTrue(cborDecoder.isAutoDecodeRationalNumbers()); cborDecoder.setAutoDecodeRationalNumbers(false); assertFalse(cborDecoder.isAutoDecodeRationalNumbers()); } @Test public void shouldSetAutoDecodeLanguageTaggedStrings() { InputStream inputStream = new ByteArrayInputStream(new byte[] { 0, 1, 2 }); CborDecoder cborDecoder = new CborDecoder(inputStream); assertTrue(cborDecoder.isAutoDecodeLanguageTaggedStrings()); cborDecoder.setAutoDecodeLanguageTaggedStrings(false); assertFalse(cborDecoder.isAutoDecodeLanguageTaggedStrings()); } @Test(expected = CborException.class) public void shouldThrowOnRationalNumberDecode1() throws CborException { List<DataItem> items = new CborBuilder().addTag(30).add(true).build(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); CborEncoder encoder = new CborEncoder(baos); encoder.encode(items); ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); CborDecoder decoder = new CborDecoder(bais); decoder.decode(); } @Test(expected = CborException.class) public void shouldThrowOnRationalNumberDecode2() throws CborException { List<DataItem> items = new CborBuilder().addTag(30).addArray().add(true).end().build(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); CborEncoder encoder = new CborEncoder(baos); encoder.encode(items); ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); CborDecoder decoder = new CborDecoder(bais); decoder.decode(); } @Test(expected = CborException.class) public void shouldThrowOnRationalNumberDecode3() throws CborException { List<DataItem> items = new CborBuilder().addTag(30).addArray().add(true).add(true).end().build(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); CborEncoder encoder = new CborEncoder(baos); encoder.encode(items); ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); CborDecoder decoder = new CborDecoder(bais); decoder.decode(); } @Test(expected = CborException.class) public void shouldThrowOnRationalNumberDecode4() throws CborException { List<DataItem> items = new CborBuilder().addTag(30).addArray().add(1).add(true).end().build(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); CborEncoder encoder = new CborEncoder(baos); encoder.encode(items); ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); CborDecoder decoder = new CborDecoder(bais); decoder.decode(); } @Test public void shouldDecodeRationalNumber() throws CborException { List<DataItem> items = new CborBuilder().addTag(30).addArray().add(1).add(2).end().build(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); CborEncoder encoder = new CborEncoder(baos); encoder.encode(items); ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); CborDecoder decoder = new CborDecoder(bais); assertEquals(new RationalNumber(new UnsignedInteger(1), new UnsignedInteger(2)), decoder.decodeNext()); } @Test public void shouldDecodeTaggedTags() throws CborException { DataItem decoded = CborDecoder.decode(new byte[] { (byte) 0xC1, (byte) 0xC2, 0x02 }).get(0); Tag outer = new Tag(1); Tag inner = new Tag(2); UnsignedInteger expected = new UnsignedInteger(2); inner.setTag(outer); expected.setTag(inner); assertEquals(expected, decoded); } @Test public void shouldDecodeTaggedRationalNumber() throws CborException { List<DataItem> items = new CborBuilder().addTag(1).addTag(30).addArray().add(1).add(2).end().build(); ByteArrayOutputStream baos = new ByteArrayOutputStream(); CborEncoder encoder = new CborEncoder(baos); encoder.encode(items); ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); CborDecoder decoder = new CborDecoder(bais); RationalNumber expected = new RationalNumber(new UnsignedInteger(1), new UnsignedInteger(2)); expected.getTag().setTag(new Tag(1)); assertEquals(expected, decoder.decodeNext()); } @Test public void shouldThrowOnItemWithForgedLength() throws CborException { ByteArrayOutputStream buffer = new ByteArrayOutputStream(); AbstractEncoder<Long> maliciousEncoder = new AbstractEncoder<Long>(null, buffer) { @Override public void encode(Long length) throws CborException { encodeTypeAndLength(MajorType.UNICODE_STRING, length.longValue()); } }; maliciousEncoder.encode(Long.valueOf(Integer.MAX_VALUE + 1L)); byte[] maliciousString = buffer.toByteArray(); try { CborDecoder.decode(maliciousString); fail("Should have failed the huge allocation"); } catch (CborException e) { assertThat("Exception message", e.getMessage(), containsString("limited to INTMAX")); } buffer.reset(); maliciousEncoder.encode(Long.valueOf(Integer.MAX_VALUE - 1)); maliciousString = buffer.toByteArray(); try { CborDecoder.decode(maliciousString); fail("Should have failed the huge allocation"); } catch (OutOfMemoryError e) { // Expected without limit } CborDecoder decoder = new CborDecoder(new ByteArrayInputStream(maliciousString)); decoder.setMaxPreallocationSize(1024); try { decoder.decode(); fail("Should have failed with unexpected end of stream exception"); } catch (CborException e) { // Expected with limit } } }