Java tutorial
/** * Copyright (c) Codice Foundation * <p> * This is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser * General Public License as published by the Free Software Foundation, either version 3 of the * License, or any later version. * <p> * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. A copy of the GNU Lesser General Public License * is distributed along with this program and can be found at * <http://www.gnu.org/licenses/lgpl.html>. */ package org.codice.ddf.libs.klv; import static org.codice.ddf.libs.klv.data.Klv.KeyLength; import static org.codice.ddf.libs.klv.data.Klv.LengthEncoding; import static org.hamcrest.CoreMatchers.instanceOf; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.collection.IsMapContaining.hasKey; import static org.hamcrest.number.IsCloseTo.closeTo; import static org.junit.Assert.assertThat; import static org.junit.Assert.fail; import java.io.InputStream; import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import org.apache.commons.io.IOUtils; import org.apache.commons.lang.ArrayUtils; import org.codice.ddf.libs.klv.data.numerical.KlvByte; import org.codice.ddf.libs.klv.data.numerical.KlvDouble; import org.codice.ddf.libs.klv.data.numerical.KlvFloat; import org.codice.ddf.libs.klv.data.numerical.KlvInt; import org.codice.ddf.libs.klv.data.numerical.KlvIntegerEncodedFloatingPoint; import org.codice.ddf.libs.klv.data.numerical.KlvLong; import org.codice.ddf.libs.klv.data.numerical.KlvShort; import org.codice.ddf.libs.klv.data.numerical.KlvUnsignedByte; import org.codice.ddf.libs.klv.data.numerical.KlvUnsignedShort; import org.codice.ddf.libs.klv.data.raw.KlvBytes; import org.codice.ddf.libs.klv.data.set.KlvLocalSet; import org.codice.ddf.libs.klv.data.text.KlvString; import org.junit.BeforeClass; import org.junit.Test; public class KlvDecoderTest { private static final String UAS_DATALINK_LOCAL_SET_UNIVERSAL_KEY = "UAS Datalink Local Set Universal Key"; private static final String TIMESTAMP = "timestamp"; private static final String UAS_LS_VERSION_NUMBER = "UAS LS Version Number"; private static final String PLATFORM_HEADING_ANGLE = "platform heading angle"; private static final String PLATFORM_PITCH_ANGLE = "platform pitch angle"; private static final String PLATFORM_ROLL_ANGLE = "platform roll angle"; private static final String IMAGE_SOURCE_SENSOR = "image source sensor"; private static final String IMAGE_COORDINATE_SYSTEM = "image coordinate system"; private static final String SENSOR_LATITUDE = "sensor latitude"; private static final String SENSOR_LONGITUDE = "sensor longitude"; private static final String SENSOR_TRUE_ALTITUDE = "sensor true altitude"; private static final String SENSOR_HORIZONTAL_FOV = "sensor horizontal fov"; private static final String SENSOR_VERTICAL_FOV = "sensor vertical fov"; private static final String SENSOR_RELATIVE_AZIMUTH_ANGLE = "sensor relative azimuth angle"; private static final String SENSOR_RELATIVE_ELEVATION_ANGLE = "sensor relative elevation angle"; private static final String SENSOR_RELATIVE_ROLL_ANGLE = "sensor relative roll angle"; private static final String SLANT_RANGE = "slant range"; private static final String TARGET_WIDTH = "target width"; private static final String FRAME_CENTER_LATITUDE = "frame center latitude"; private static final String FRAME_CENTER_LONGITUDE = "frame center longitude"; private static final String FRAME_CENTER_ELEVATION = "frame center elevation"; private static final String TARGET_LOCATION_LATITUDE = "target location latitude"; private static final String TARGET_LOCATION_LONGITUDE = "target location longitude"; private static final String TARGET_LOCATION_ELEVATION = "target location elevation"; private static final String PLATFORM_GROUND_SPEED = "platform ground speed"; private static final String GROUND_RANGE = "ground range"; private static final String CHECKSUM = "checksum"; private static final Map<String, Object> EXPECTED_VALUES = new HashMap<>(); private static final Set<KlvDataElement> DATA_ELEMENTS = new HashSet<>(); @BeforeClass public static void setUpClass() { // The test KLV is a UAS Datalink Local Set (MISB ST 0601). EXPECTED_VALUES.put(TIMESTAMP, 1245257585099653L); EXPECTED_VALUES.put(UAS_LS_VERSION_NUMBER, (byte) 1); EXPECTED_VALUES.put(PLATFORM_HEADING_ANGLE, 15675); EXPECTED_VALUES.put(PLATFORM_PITCH_ANGLE, (short) 5504); EXPECTED_VALUES.put(PLATFORM_ROLL_ANGLE, (short) 338); EXPECTED_VALUES.put(IMAGE_SOURCE_SENSOR, "EON"); EXPECTED_VALUES.put(IMAGE_COORDINATE_SYSTEM, "Geodetic WGS84"); EXPECTED_VALUES.put(SENSOR_LATITUDE, 1304747195); EXPECTED_VALUES.put(SENSOR_LONGITUDE, -1314362114); EXPECTED_VALUES.put(SENSOR_TRUE_ALTITUDE, 8010); EXPECTED_VALUES.put(SENSOR_HORIZONTAL_FOV, 133); EXPECTED_VALUES.put(SENSOR_VERTICAL_FOV, 75); EXPECTED_VALUES.put(SENSOR_RELATIVE_AZIMUTH_ANGLE, 550031997L); EXPECTED_VALUES.put(SENSOR_RELATIVE_ELEVATION_ANGLE, -52624680); EXPECTED_VALUES.put(SENSOR_RELATIVE_ROLL_ANGLE, 4273523553L); EXPECTED_VALUES.put(SLANT_RANGE, 9387617L); EXPECTED_VALUES.put(TARGET_WIDTH, 457); EXPECTED_VALUES.put(FRAME_CENTER_LATITUDE, 1306364970); EXPECTED_VALUES.put(FRAME_CENTER_LONGITUDE, -1312907532); EXPECTED_VALUES.put(FRAME_CENTER_ELEVATION, 2949); EXPECTED_VALUES.put(TARGET_LOCATION_LATITUDE, 1306364970); EXPECTED_VALUES.put(TARGET_LOCATION_LONGITUDE, -1312907532); EXPECTED_VALUES.put(TARGET_LOCATION_ELEVATION, 2949); EXPECTED_VALUES.put(PLATFORM_GROUND_SPEED, (short) 46); EXPECTED_VALUES.put(GROUND_RANGE, 9294889L); EXPECTED_VALUES.put(CHECKSUM, 7263); DATA_ELEMENTS.add(new KlvLong(new byte[] { 0x02 }, TIMESTAMP)); DATA_ELEMENTS.add(new KlvByte(new byte[] { 0x41 }, UAS_LS_VERSION_NUMBER)); DATA_ELEMENTS.add(new KlvUnsignedShort(new byte[] { 0x05 }, PLATFORM_HEADING_ANGLE)); DATA_ELEMENTS.add(new KlvShort(new byte[] { 0x06 }, PLATFORM_PITCH_ANGLE)); DATA_ELEMENTS.add(new KlvShort(new byte[] { 0x07 }, PLATFORM_ROLL_ANGLE)); DATA_ELEMENTS.add(new KlvString(new byte[] { 0x0b }, IMAGE_SOURCE_SENSOR)); DATA_ELEMENTS.add(new KlvString(new byte[] { 0x0c }, IMAGE_COORDINATE_SYSTEM)); DATA_ELEMENTS.add(new KlvInt(new byte[] { 0x0d }, SENSOR_LATITUDE)); DATA_ELEMENTS.add(new KlvInt(new byte[] { 0x0e }, SENSOR_LONGITUDE)); DATA_ELEMENTS.add(new KlvUnsignedShort(new byte[] { 0x0f }, SENSOR_TRUE_ALTITUDE)); DATA_ELEMENTS.add(new KlvUnsignedShort(new byte[] { 0x10 }, SENSOR_HORIZONTAL_FOV)); DATA_ELEMENTS.add(new KlvUnsignedShort(new byte[] { 0x11 }, SENSOR_VERTICAL_FOV)); DATA_ELEMENTS.add(new KlvLong(new byte[] { 0x12 }, SENSOR_RELATIVE_AZIMUTH_ANGLE)); DATA_ELEMENTS.add(new KlvInt(new byte[] { 0x13 }, SENSOR_RELATIVE_ELEVATION_ANGLE)); DATA_ELEMENTS.add(new KlvLong(new byte[] { 0x14 }, SENSOR_RELATIVE_ROLL_ANGLE)); DATA_ELEMENTS.add(new KlvLong(new byte[] { 0x15 }, SLANT_RANGE)); // Target width isn't actually a 32-bit int in the UAS Datalink Local Set; it's an unsigned // 16-bit int. However, this KLV encodes the target width using 4 bytes (for some reason). DATA_ELEMENTS.add(new KlvInt(new byte[] { 0x16 }, TARGET_WIDTH)); DATA_ELEMENTS.add(new KlvInt(new byte[] { 0x17 }, FRAME_CENTER_LATITUDE)); DATA_ELEMENTS.add(new KlvInt(new byte[] { 0x18 }, FRAME_CENTER_LONGITUDE)); DATA_ELEMENTS.add(new KlvUnsignedShort(new byte[] { 0x19 }, FRAME_CENTER_ELEVATION)); DATA_ELEMENTS.add(new KlvInt(new byte[] { 0x28 }, TARGET_LOCATION_LATITUDE)); DATA_ELEMENTS.add(new KlvInt(new byte[] { 0x29 }, TARGET_LOCATION_LONGITUDE)); DATA_ELEMENTS.add(new KlvUnsignedShort(new byte[] { 0x2a }, TARGET_LOCATION_ELEVATION)); DATA_ELEMENTS.add(new KlvUnsignedByte(new byte[] { 0x38 }, PLATFORM_GROUND_SPEED)); DATA_ELEMENTS.add(new KlvLong(new byte[] { 0x39 }, GROUND_RANGE)); DATA_ELEMENTS.add(new KlvUnsignedShort(new byte[] { 0x01 }, CHECKSUM)); } private KlvContext getKLVContext(final Set<? extends KlvDataElement> dataElements) { final KlvContext localSetContext = new KlvContext(KeyLength.OneByte, LengthEncoding.OneByte, dataElements); final KlvLocalSet outerSet = new KlvLocalSet(new byte[] { 0x06, 0x0E, 0x2B, 0x34, 0x02, 0x0B, 0x01, 0x01, 0x0E, 0x01, 0x03, 0x01, 0x01, 0x00, 0x00, 0x00 }, UAS_DATALINK_LOCAL_SET_UNIVERSAL_KEY, localSetContext); final Set<KlvDataElement> outerSetContext = Collections.singleton(outerSet); return new KlvContext(KeyLength.SixteenBytes, LengthEncoding.BER, outerSetContext); } @Test public void testKLVSet() throws Exception { byte[] klvBytes; try (final InputStream inputStream = getClass().getClassLoader().getResourceAsStream("testKLV.klv")) { klvBytes = IOUtils.toByteArray(inputStream); } final KlvContext klvContext = getKLVContext(DATA_ELEMENTS); final Map<String, KlvDataElement> decodedDataElements = new KlvDecoder(klvContext).decode(klvBytes) .getDataElements(); assertThat(decodedDataElements.size(), is(1)); assertThat(decodedDataElements, hasKey(UAS_DATALINK_LOCAL_SET_UNIVERSAL_KEY)); final KlvContext localSet = ((KlvLocalSet) decodedDataElements.get(UAS_DATALINK_LOCAL_SET_UNIVERSAL_KEY)) .getValue(); final Map<String, KlvDataElement> localSetDataElements = localSet.getDataElements(); assertThat(localSetDataElements.size(), is(DATA_ELEMENTS.size())); localSetDataElements.forEach((name, dataElement) -> { final Object expectedValue = EXPECTED_VALUES.get(name); assertThat(String.format("%s is not %s", name, expectedValue), dataElement.getValue(), is(expectedValue)); }); } private KlvContext decodeKLV(final KeyLength keyLength, final LengthEncoding lengthEncoding, final KlvDataElement dataElement, final byte[] encodedBytes) throws KlvDecodingException { final KlvContext klvContext = new KlvContext(keyLength, lengthEncoding); klvContext.addDataElement(dataElement); return new KlvDecoder(klvContext).decode(encodedBytes); } private byte[] getValueBytes(final KeyLength keyLength, final LengthEncoding lengthEncoding, final byte[] encodedBytes) throws KlvDecodingException { final byte[] key = Arrays.copyOf(encodedBytes, keyLength.value()); final KlvBytes dataElement = new KlvBytes(key, "test"); final KlvContext decodedKlvContext = decodeKLV(keyLength, lengthEncoding, dataElement, encodedBytes); return ((KlvBytes) decodedKlvContext.getDataElementByName("test")).getValue(); } @Test public void testOneByteKey() throws KlvDecodingException { final byte[] klvBytes = { 7, 3, 9, 8, 7 }; final byte[] value = getValueBytes(KeyLength.OneByte, LengthEncoding.OneByte, klvBytes); assertThat(value, is(new byte[] { 9, 8, 7 })); } @Test public void testTwoByteKey() throws KlvDecodingException { final byte[] klvBytes = { -14, 99, 3, -1, 0, 1 }; final byte[] value = getValueBytes(KeyLength.TwoBytes, LengthEncoding.OneByte, klvBytes); assertThat(value, is(new byte[] { -1, 0, 1 })); } @Test public void testFourByteKey() throws KlvDecodingException { final byte[] klvBytes = { -14, 99, -55, 101, 3, -1, 0, 1 }; final byte[] value = getValueBytes(KeyLength.FourBytes, LengthEncoding.OneByte, klvBytes); assertThat(value, is(new byte[] { -1, 0, 1 })); } @Test public void testSixteenByteKey() throws KlvDecodingException { final byte[] klvBytes = { -14, 99, -55, 101, 22, 0, -9, -45, -55, -1, 77, 89, 112, 17, 18, 19, 3, -1, 0, 1 }; final byte[] value = getValueBytes(KeyLength.SixteenBytes, LengthEncoding.OneByte, klvBytes); assertThat(value, is(new byte[] { -1, 0, 1 })); } @Test // One-byte length encoding has already been tested in all the key length tests. public void testTwoByteLengthEncoding() throws KlvDecodingException { final byte[] expectedValueBytes = new byte[256]; Arrays.fill(expectedValueBytes, (byte) 4); final byte[] klvBytes = ArrayUtils.addAll(new byte[] { 5, 1, 0 }, expectedValueBytes); final byte[] value = getValueBytes(KeyLength.OneByte, LengthEncoding.TwoBytes, klvBytes); assertThat(value, is(expectedValueBytes)); } @Test public void testFourByteLengthEncoding() throws KlvDecodingException { final byte[] expectedValueBytes = new byte[256]; Arrays.fill(expectedValueBytes, (byte) -2); final byte[] klvBytes = ArrayUtils.addAll(new byte[] { 5, 0, 0, 1, 0 }, expectedValueBytes); final byte[] value = getValueBytes(KeyLength.OneByte, LengthEncoding.FourBytes, klvBytes); assertThat(value, is(expectedValueBytes)); } @Test public void testBERLengthEncodingSingleByte() throws KlvDecodingException { final byte length = 100; final byte[] expectedValueBytes = new byte[length]; Arrays.fill(expectedValueBytes, (byte) 101); final byte[] klvBytes = ArrayUtils.addAll(new byte[] { 5, length }, expectedValueBytes); final byte[] value = getValueBytes(KeyLength.OneByte, LengthEncoding.BER, klvBytes); assertThat(value, is(expectedValueBytes)); } @Test public void testBERLengthEncodingMultipleBytes() throws KlvDecodingException { final byte length = 55; final byte[] expectedValueBytes = new byte[length]; Arrays.fill(expectedValueBytes, (byte) -25); final byte[] klvBytes = ArrayUtils.addAll(new byte[] { 5, (byte) 0b10000001, length }, expectedValueBytes); final byte[] value = getValueBytes(KeyLength.OneByte, LengthEncoding.BER, klvBytes); assertThat(value, is(expectedValueBytes)); } @Test public void testByteValue() throws KlvDecodingException { final byte[] klvBytes = { -8, 1, -128 }; final KlvByte klvByte = new KlvByte(new byte[] { -8 }, "test"); final KlvContext decodedKlvContext = decodeKLV(KeyLength.OneByte, LengthEncoding.OneByte, klvByte, klvBytes); final byte value = ((KlvByte) decodedKlvContext.getDataElementByName("test")).getValue(); assertThat(value, is((byte) -128)); } @Test public void testUnsignedByteValue() throws KlvDecodingException { final byte[] klvBytes = { -8, 1, -127 }; final KlvUnsignedByte klvUnsignedByte = new KlvUnsignedByte(new byte[] { -8 }, "test"); final KlvContext decodedKlvContext = decodeKLV(KeyLength.OneByte, LengthEncoding.OneByte, klvUnsignedByte, klvBytes); final short value = ((KlvUnsignedByte) decodedKlvContext.getDataElementByName("test")).getValue(); assertThat(value, is((short) 129)); } @Test public void testShortValue() throws KlvDecodingException { final byte[] klvBytes = { -8, 2, (byte) 0xB6, 0x1f }; final KlvShort klvShort = new KlvShort(new byte[] { -8 }, "test"); final KlvContext decodedKlvContext = decodeKLV(KeyLength.OneByte, LengthEncoding.OneByte, klvShort, klvBytes); final short value = ((KlvShort) decodedKlvContext.getDataElementByName("test")).getValue(); assertThat(value, is((short) -18913)); } @Test public void testUnsignedShortValue() throws KlvDecodingException { final byte[] klvBytes = { -8, 2, (byte) 0xB6, 0x1f }; final KlvUnsignedShort klvUnsignedShort = new KlvUnsignedShort(new byte[] { -8 }, "test"); final KlvContext decodedKlvContext = decodeKLV(KeyLength.OneByte, LengthEncoding.OneByte, klvUnsignedShort, klvBytes); final int value = ((KlvUnsignedShort) decodedKlvContext.getDataElementByName("test")).getValue(); assertThat(value, is(46623)); } @Test public void testIntValue() throws KlvDecodingException { final byte[] klvBytes = { -8, 4, (byte) 0xAF, 0x69, 0x1E, 0x0F }; final KlvInt klvInt = new KlvInt(new byte[] { -8 }, "test"); final KlvContext decodedKlvContext = decodeKLV(KeyLength.OneByte, LengthEncoding.OneByte, klvInt, klvBytes); final int value = ((KlvInt) decodedKlvContext.getDataElementByName("test")).getValue(); assertThat(value, is(-1352065521)); } @Test public void testUnsignedIntValue() throws KlvDecodingException { final byte[] klvBytes = { -8, 4, (byte) 0xAF, 0x69, 0x1E, 0x0F }; final KlvLong klvUnsignedInt = new KlvLong(new byte[] { -8 }, "test"); final KlvContext decodedKlvContext = decodeKLV(KeyLength.OneByte, LengthEncoding.OneByte, klvUnsignedInt, klvBytes); final long value = ((KlvLong) decodedKlvContext.getDataElementByName("test")).getValue(); assertThat(value, is(2942901775L)); } @Test public void testLongValue() throws KlvDecodingException { final byte[] klvBytes = { -8, 8, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, 0x50, (byte) 0x96, (byte) 0xE1, (byte) 0xF1 }; final KlvLong klvLong = new KlvLong(new byte[] { -8 }, "test"); final KlvContext decodedKlvContext = decodeKLV(KeyLength.OneByte, LengthEncoding.OneByte, klvLong, klvBytes); final long value = ((KlvLong) decodedKlvContext.getDataElementByName("test")).getValue(); assertThat(value, is(-2942901775L)); } @Test public void testFloatValue() throws KlvDecodingException { final byte[] klvBytes = { -8, 4, 0x46, (byte) 0xA8, 0x7E, 0x59 }; final KlvFloat klvFloat = new KlvFloat(new byte[] { -8 }, "test"); final KlvContext decodedKlvContext = decodeKLV(KeyLength.OneByte, LengthEncoding.OneByte, klvFloat, klvBytes); final float value = ((KlvFloat) decodedKlvContext.getDataElementByName("test")).getValue(); assertThat(value, is(21567.174f)); } @Test public void testDoubleValue() throws KlvDecodingException { final byte[] klvBytes = { -8, 8, 0x40, (byte) 0xD5, 0x0F, (byte) 0xCB, 0x21, 0x07, (byte) 0xB7, (byte) 0x84 }; final KlvDouble klvDouble = new KlvDouble(new byte[] { -8 }, "test"); final KlvContext decodedKlvContext = decodeKLV(KeyLength.OneByte, LengthEncoding.OneByte, klvDouble, klvBytes); final double value = ((KlvDouble) decodedKlvContext.getDataElementByName("test")).getValue(); assertThat(value, is(21567.173891)); } @Test public void testStringValue() throws KlvDecodingException { final byte[] klvBytes = { -8, 3, 0x4b, 0x4c, 0x56 }; final KlvString klvString = new KlvString(new byte[] { -8 }, "test", StandardCharsets.UTF_8.name()); final KlvContext decodedKlvContext = decodeKLV(KeyLength.OneByte, LengthEncoding.OneByte, klvString, klvBytes); final String value = ((KlvString) decodedKlvContext.getDataElementByName("test")).getValue(); assertThat(value, is("KLV")); } @Test // Example value taken from ST0601.8 Tag 36. public void testFloatingPointEncodedAsUnsignedByte() throws KlvDecodingException { final byte[] klvBytes = { -8, 1, (byte) 0xB2 }; final KlvUnsignedByte klvUnsignedByte = new KlvUnsignedByte(new byte[] { -8 }, "test"); final KlvIntegerEncodedFloatingPoint windSpeed = new KlvIntegerEncodedFloatingPoint(klvUnsignedByte, 0, (1 << 8) - 1, 0, 100); final KlvContext decodedKlvContext = decodeKLV(KeyLength.OneByte, LengthEncoding.OneByte, windSpeed, klvBytes); final double value = ((KlvIntegerEncodedFloatingPoint) decodedKlvContext.getDataElementByName("test")) .getValue(); assertThat(value, is(closeTo(69.80392, 1e-5))); } @Test // Example value taken from ST0601.8 Tag 5. public void testFloatingPointEncodedAsUnsignedShort() throws KlvDecodingException { final byte[] klvBytes = { -8, 2, 0x71, (byte) 0xC2 }; final KlvUnsignedShort klvUnsignedShort = new KlvUnsignedShort(new byte[] { -8 }, "test"); final KlvIntegerEncodedFloatingPoint platformHeadingAngle = new KlvIntegerEncodedFloatingPoint( klvUnsignedShort, 0, (1 << 16) - 1, 0, 360); final KlvContext decodedKlvContext = decodeKLV(KeyLength.OneByte, LengthEncoding.OneByte, platformHeadingAngle, klvBytes); final double value = ((KlvIntegerEncodedFloatingPoint) decodedKlvContext.getDataElementByName("test")) .getValue(); assertThat(value, is(closeTo(159.9744, 1e-4))); } @Test // Example value taken from ST0601.8 Tag 7, but for some reason their example value is 3.405814, // which is wrong. public void testFloatingPointEncodedAsShort() throws KlvDecodingException { final byte[] klvBytes = { -8, 2, (byte) 0x08, (byte) 0xB8 }; final KlvShort klvShort = new KlvShort(new byte[] { -8 }, "test"); final KlvIntegerEncodedFloatingPoint platformRollAngle = // Short.MIN_VALUE is an "out of range" indicator, so it is not included in the range. new KlvIntegerEncodedFloatingPoint(klvShort, Short.MIN_VALUE + 1, Short.MAX_VALUE, -50, 50); final KlvContext decodedKlvContext = decodeKLV(KeyLength.OneByte, LengthEncoding.OneByte, platformRollAngle, klvBytes); final double value = ((KlvIntegerEncodedFloatingPoint) decodedKlvContext.getDataElementByName("test")) .getValue(); assertThat(value, is(closeTo(3.405865, 1e-6))); } @Test // Example value taken from ST0601.8 Tag 18, but for some reason their example value is // 160.719211474396, which is wrong. public void testFloatingPointEncodedAsUnsignedInt() throws KlvDecodingException { final byte[] klvBytes = { -8, 4, 0x72, 0x4A, 0x0A, 0x20 }; final KlvLong klvUnsignedInt = new KlvLong(new byte[] { -8 }, "test"); final KlvIntegerEncodedFloatingPoint sensorRelativeAzimuth = new KlvIntegerEncodedFloatingPoint( klvUnsignedInt, 0, (1L << 32) - 1, 0, 360); final KlvContext decodedKlvContext = decodeKLV(KeyLength.OneByte, LengthEncoding.OneByte, sensorRelativeAzimuth, klvBytes); final double value = ((KlvIntegerEncodedFloatingPoint) decodedKlvContext.getDataElementByName("test")) .getValue(); assertThat(value, is(closeTo(160.719211436975, 1e-12))); } @Test // Example value taken from ST0601.8 Tag 19. public void testFloatingPointEncodedAsInt() throws KlvDecodingException { final byte[] klvBytes = { -8, 4, (byte) 0x87, (byte) 0xF8, 0x4B, (byte) 0x86 }; final KlvInt klvInt = new KlvInt(new byte[] { -8 }, "test"); final KlvIntegerEncodedFloatingPoint sensorRelativeElevationAngle = new KlvIntegerEncodedFloatingPoint( klvInt, // Short.MIN_VALUE is an "out of range" indicator, so it is not included in the range. Integer.MIN_VALUE + 1, Integer.MAX_VALUE, -180, 180); final KlvContext decodedKlvContext = decodeKLV(KeyLength.OneByte, LengthEncoding.OneByte, sensorRelativeElevationAngle, klvBytes); final double value = ((KlvIntegerEncodedFloatingPoint) decodedKlvContext.getDataElementByName("test")) .getValue(); assertThat(value, is(closeTo(-168.792324833941, 1e-12))); } @Test public void testMissingBytes() { final byte[] klvBytes = { -8, 4, (byte) 0x87, (byte) 0xF8, 0x4B }; final KlvInt klvInt = new KlvInt(new byte[] { -8 }, "test"); try { decodeKLV(KeyLength.OneByte, LengthEncoding.OneByte, klvInt, klvBytes); fail("Should have thrown a KlvDecodingException."); } catch (KlvDecodingException e) { assertThat(e.getCause(), instanceOf(IndexOutOfBoundsException.class)); } } }