package de.persosim.simulator.tlv;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotSame;
import mockit.Deencapsulation;
import org.junit.Test;
import de.persosim.simulator.exception.ISO7816Exception;
import de.persosim.simulator.utils.Utils;
public class PrimitiveTlvDataObjectTest {
/**
* Positive test case: Extract primitive TLV data object from a range out of
* a larger byte array. The range is smaller than the length of the byte
* array and larger than the minimum range required for the respective
* object
*/
@Test
public void testConstructorByteArrayIntInt_LargeRange() {
/* set arbitrary but valid primitive tag */
byte[] tagExpected = new byte[] { (byte) 0x80 };
/* set arbitrary but valid length matching actual length of value */
byte[] lengthExpected = new byte[] { (byte) 0x0A };
/* set arbitrary value */
byte[] valueExpected = new byte[] { (byte) 0x04, (byte) 0x00,
(byte) 0x7F, (byte) 0x00, (byte) 0x07, (byte) 0x02,
(byte) 0x02, (byte) 0x04, (byte) 0x03, (byte) 0x04 };
byte[] tlvExpected = Utils.concatByteArrays(tagExpected,
lengthExpected, valueExpected);
/* dummy data to prepend */
byte[] byteArrayPre = new byte[] { (byte) 0xFF, (byte) 0xFF };
/* dummy data to append */
byte[] byteArrayPost = new byte[] { (byte) 0xFF, (byte) 0xFF,
(byte) 0xFF, (byte) 0xFF };
/* build actual byte array */
byte[] byteArray = Utils.concatByteArrays(byteArrayPre, tlvExpected,
byteArrayPost);
PrimitiveTlvDataObject tlvObject = new PrimitiveTlvDataObject(
byteArray, byteArrayPre.length, byteArray.length);
assertArrayEquals("Equals expected byte array representation",
tlvObject.toByteArray(), tlvExpected);
}
/**
* Positive test case: Extract primitive TLV data object from a range out of
* a larger byte array. The range is smaller than the length of the byte
* array and matches the minimum range required for the respective object
*/
@Test
public void testConstructorByteArrayIntInt_MinRange() {
/* set arbitrary but valid primitive tag */
byte[] tagExpected = new byte[] { (byte) 0x80 };
/* set arbitrary but valid length matching actual length of value */
byte[] lengthExpected = new byte[] { (byte) 0x0A };
/* set arbitrary value */
byte[] valueExpected = new byte[] { (byte) 0x04, (byte) 0x00,
(byte) 0x7F, (byte) 0x00, (byte) 0x07, (byte) 0x02,
(byte) 0x02, (byte) 0x04, (byte) 0x03, (byte) 0x04 };
byte[] tlvExpected = Utils.concatByteArrays(tagExpected,
lengthExpected, valueExpected);
/* dummy data to prepend */
byte[] byteArrayPre = new byte[] { (byte) 0xFF, (byte) 0xFF };
/* dummy data to append */
byte[] byteArrayPost = new byte[] { (byte) 0xFF, (byte) 0xFF,
(byte) 0xFF, (byte) 0xFF };
/* build actual byte array */
byte[] byteArray = Utils.concatByteArrays(byteArrayPre, tlvExpected,
byteArrayPost);
PrimitiveTlvDataObject tlvObject = new PrimitiveTlvDataObject(
byteArray, byteArrayPre.length, byteArrayPre.length
+ tlvExpected.length);
assertArrayEquals("Equals expected byte array representation",
tlvObject.toByteArray(), tlvExpected);
}
/**
* Negative test case: Extract primitive TLV data object from a range out of
* a larger byte array. The range is smaller than the length of the byte
* array and is 1 byte smaller than the minimum range required for the
* respective object
*/
@Test(expected = ISO7816Exception.class)
public void testConstructorByteArrayIntInt_TooSmallRange() {
/* set arbitrary but valid primitive tag */
byte[] tagExpected = new byte[] { (byte) 0x80 };
/* set arbitrary but valid length matching actual length of value */
byte[] lengthExpected = new byte[] { (byte) 0x0A };
/* set arbitrary value */
byte[] valueExpected = new byte[] { (byte) 0x04, (byte) 0x00,
(byte) 0x7F, (byte) 0x00, (byte) 0x07, (byte) 0x02,
(byte) 0x02, (byte) 0x04, (byte) 0x03, (byte) 0x04 };
byte[] tlvExpected = Utils.concatByteArrays(tagExpected,
lengthExpected, valueExpected);
/* dummy data to prepend */
byte[] byteArrayPre = new byte[] { (byte) 0xFF, (byte) 0xFF };
/* dummy data to append */
byte[] byteArrayPost = new byte[] { (byte) 0xFF, (byte) 0xFF,
(byte) 0xFF, (byte) 0xFF };
/* build actual byte array */
byte[] byteArray = Utils.concatByteArrays(byteArrayPre, tlvExpected,
byteArrayPost);
new PrimitiveTlvDataObject(byteArray, byteArrayPre.length,
byteArrayPre.length + tlvExpected.length - 1);
}
/**
* Positive test case: Construct primitive TLV data object from basic T-L-V
* elements
*/
@Test
public void testConstructorTagLengthValueBasicTlvElements() {
/* set arbitrary but valid primitive tag */
byte[] tagExpected = new byte[] { (byte) 0x80 };
/* set arbitrary but valid length matching actual length of value */
byte[] lengthExpected = new byte[] { (byte) 0x0A };
/* set arbitrary value */
byte[] valueExpected = new byte[] { (byte) 0x04, (byte) 0x00,
(byte) 0x7F, (byte) 0x00, (byte) 0x07, (byte) 0x02,
(byte) 0x02, (byte) 0x04, (byte) 0x03, (byte) 0x04 };
byte[] tlvExpected = Utils.concatByteArrays(tagExpected,
lengthExpected, valueExpected);
TlvTag tag = new TlvTag(tagExpected);
TlvLength length = new TlvLength(lengthExpected);
TlvValuePlain value = new TlvValuePlain(valueExpected);
PrimitiveTlvDataObject tlvObject = new PrimitiveTlvDataObject(tag,
length, value);
assertArrayEquals("Equals expected byte array representation",
tlvObject.toByteArray(), tlvExpected);
}
/**
* Positive test case: Construct primitive TLV data object from basic T-V
* elements - L is to be set implicitly
*/
@Test
public void testConstructorTagLengthValueBasicTvElements() {
/* set arbitrary but valid primitive tag */
byte[] tagExpected = new byte[] { (byte) 0x80 };
/* set arbitrary but valid length matching actual length of value */
byte[] lengthExpected = new byte[] { (byte) 0x0A };
/* set arbitrary value */
byte[] valueExpected = new byte[] { (byte) 0x04, (byte) 0x00,
(byte) 0x7F, (byte) 0x00, (byte) 0x07, (byte) 0x02,
(byte) 0x02, (byte) 0x04, (byte) 0x03, (byte) 0x04 };
byte[] tlvExpected = Utils.concatByteArrays(tagExpected,
lengthExpected, valueExpected);
TlvTag tag = new TlvTag(tagExpected);
TlvValuePlain value = new TlvValuePlain(valueExpected);
PrimitiveTlvDataObject tlvObject = new PrimitiveTlvDataObject(tag,
value);
assertArrayEquals("Equals expected byte array representation",
tlvObject.toByteArray(), tlvExpected);
}
/**
* Negative test case: Construct primitive TLV data object from basic T-L-V
* elements, V not matching L
*/
@Test(expected = IllegalArgumentException.class)
public void testConstructorTagLengthValue_LengthMismatch() {
/* set arbitrary but valid primitive tag */
byte[] tagExpected = new byte[] { (byte) 0x80 };
/* set arbitrary but valid length greater than actual length of value */
byte[] lengthExpected = new byte[] { (byte) 0x0C };
/* set arbitrary value */
byte[] valueExpected = new byte[] { (byte) 0x04, (byte) 0x00,
(byte) 0x7F, (byte) 0x00, (byte) 0x07, (byte) 0x02,
(byte) 0x02, (byte) 0x04, (byte) 0x03, (byte) 0x04 };
TlvTag tag = new TlvTag(tagExpected);
TlvLength length = new TlvLength(lengthExpected);
TlvValuePlain value = new TlvValuePlain(valueExpected);
new PrimitiveTlvDataObject(tag, length, value);
}
/**
* Negative test case: Construct primitive TLV data object from basic T-L-V
* elements, T indicates constructed encoding
*/
@Test(expected = IllegalArgumentException.class)
public void testConstructorTagLengthValue_ConstructedTag() {
/* set arbitrary but "valid" constructed tag */
byte[] tagExpected = new byte[] { (byte) 0xA0 };
/* set arbitrary but valid length matching actual length of value */
byte[] lengthExpected = new byte[] { (byte) 0x0A };
/* set arbitrary value */
byte[] valueExpected = new byte[] { (byte) 0x04, (byte) 0x00,
(byte) 0x7F, (byte) 0x00, (byte) 0x07, (byte) 0x02,
(byte) 0x02, (byte) 0x04, (byte) 0x03, (byte) 0x04 };
TlvTag tag = new TlvTag(tagExpected);
TlvLength length = new TlvLength(lengthExpected);
TlvValuePlain value = new TlvValuePlain(valueExpected);
new PrimitiveTlvDataObject(tag, length, value);
}
/**
* Construct primitive TLV data object from basic T-L-V elements; returned T
* must not be the same object as provided T
*/
@Test
public void testGetTlvTag_DifferentFromConstructor() {
/* set arbitrary but valid primitive tag */
byte[] tagExpected = new byte[] { (byte) 0x80 };
/* set arbitrary but valid length matching actual length of value */
byte[] lengthExpected = new byte[] { (byte) 0x0A };
/* set arbitrary value */
byte[] valueExpected = new byte[] { (byte) 0x04, (byte) 0x00,
(byte) 0x7F, (byte) 0x00, (byte) 0x07, (byte) 0x02,
(byte) 0x02, (byte) 0x04, (byte) 0x03, (byte) 0x04 };
TlvTag tag = new TlvTag(tagExpected);
TlvLength length = new TlvLength(lengthExpected);
TlvValuePlain value = new TlvValuePlain(valueExpected);
PrimitiveTlvDataObject tlvObject = new PrimitiveTlvDataObject(tag,
length, value);
assertNotSame(tag, tlvObject.getTlvTag());
}
/**
* Construct primitive TLV data object from basic T-L-V elements; stored T
* must not be the same object as provided T, thus later modifications on
* the parameter T should NOT be reflected by the TlvDataObject
*/
@Test
public void testConstructorTagLengthValue_TagImmutableFromOutside() {
/* set arbitrary but valid primitive tag */
byte[] tagExpected = new byte[] { (byte) 0x80 };
/* set arbitrary but valid length matching actual length of value */
byte[] lengthExpected = new byte[] { (byte) 0x0A };
/* set arbitrary value */
byte[] valueExpected = new byte[] { (byte) 0x04, (byte) 0x00,
(byte) 0x7F, (byte) 0x00, (byte) 0x07, (byte) 0x02,
(byte) 0x02, (byte) 0x04, (byte) 0x03, (byte) 0x04 };
TlvTag tag = new TlvTag(tagExpected);
TlvLength length = new TlvLength(lengthExpected);
TlvValuePlain value = new TlvValuePlain(valueExpected);
PrimitiveTlvDataObject tlvObject = new PrimitiveTlvDataObject(tag,
length, value);
/*
* set arbitrary but valid primitive tag different than the one defined
* above
*/
byte[] tagExpectedNew = new byte[] { (byte) 0x08 };
Deencapsulation.setField(tag, "tagField", tagExpectedNew);
assertNotEquals(tag, tlvObject.getTlvTag());
}
/**
* After setting tag through setTlvTag() stored tag
* must not be the same object as provided parameter, thus later modifications on
* the parameter should NOT be reflected by the TlvDataObject
*/
@Test
public void testSetTag_TagImmutableFromOutside() {
/* set arbitrary but valid primitive tag */
byte[] tagExpected = new byte[] { (byte) 0x80 };
/* set arbitrary but valid length matching actual length of value */
byte[] lengthExpected = new byte[] { (byte) 0x0A };
/* set arbitrary value */
byte[] valueExpected = new byte[] { (byte) 0x04, (byte) 0x00,
(byte) 0x7F, (byte) 0x00, (byte) 0x07, (byte) 0x02,
(byte) 0x02, (byte) 0x04, (byte) 0x03, (byte) 0x04 };
TlvTag tag = new TlvTag(tagExpected);
TlvLength length = new TlvLength(lengthExpected);
TlvValuePlain value = new TlvValuePlain(valueExpected);
PrimitiveTlvDataObject tlvObject = new PrimitiveTlvDataObject(tag,
length, value);
TlvTag newTag = new TlvTag(new byte[] { (byte) 0x08 });
tlvObject.setTag(newTag);
/*
* set arbitrary but valid primitive tag different than the one defined
* above
*/
byte[] tagExpectedNew = new byte[] { (byte) 0x05 };
Deencapsulation.setField(newTag, "tagField", tagExpectedNew);
assertNotEquals(newTag, tlvObject.getTlvTag());
}
/**
* Negative test case: Set tag with a constructed tag
*/
@Test(expected = IllegalArgumentException.class)
public void testSetTag_ConstructedTag() {
/* set arbitrary but valid primitive tag */
byte[] tagExpected = new byte[] { (byte) 0x80 };
/* set arbitrary but valid length matching actual length of value */
byte[] lengthExpected = new byte[] { (byte) 0x0A };
/* set arbitrary value */
byte[] valueExpected = new byte[] { (byte) 0x04, (byte) 0x00,
(byte) 0x7F, (byte) 0x00, (byte) 0x07, (byte) 0x02,
(byte) 0x02, (byte) 0x04, (byte) 0x03, (byte) 0x04 };
TlvTag tag = new TlvTag(tagExpected);
TlvLength length = new TlvLength(lengthExpected);
TlvValuePlain value = new TlvValuePlain(valueExpected);
PrimitiveTlvDataObject tlvObject = new PrimitiveTlvDataObject(tag,
length, value);
/* set arbitrary but valid constructed tag */
byte[] tagExpectedNew = new byte[] { (byte) 0x28 };
TlvTag tag2 = new TlvTag(tagExpectedNew);
tlvObject.setTag(tag2);
}
/**
* Positive test case: TLV data objects equals itself and other objects
* generated with the same constructor arguments
*/
@Test
public void testEquals() {
/* set arbitrary but valid primitive tag */
byte[] tagExpected = new byte[] { (byte) 0x80 };
/* set arbitrary but valid length matching actual length of value */
byte[] lengthExpected = new byte[] { (byte) 0x0A };
/* set arbitrary value */
byte[] valueExpected = new byte[] { (byte) 0x04, (byte) 0x00,
(byte) 0x7F, (byte) 0x00, (byte) 0x07, (byte) 0x02,
(byte) 0x02, (byte) 0x04, (byte) 0x03, (byte) 0x04 };
byte[] tlvExpected = Utils.concatByteArrays(tagExpected,
lengthExpected, valueExpected);
PrimitiveTlvDataObject tlvObject1 = new PrimitiveTlvDataObject(
tlvExpected);
PrimitiveTlvDataObject tlvObject2 = new PrimitiveTlvDataObject(
tlvExpected);
assertEquals("Equals self", tlvObject1, tlvObject1);
assertEquals("Equals same constructor arguments", tlvObject1,
tlvObject2);
}
/**
* Positive test case: Set new value and have object automatically correct length
*/
@Test
public void testGetLength_ModifiedValueLength() {
/* set arbitrary but valid primitive tag */
byte[] tagExpected = new byte[] { (byte) 0x80 };
/* set arbitrary but valid length matching actual length of value */
byte[] lengthExpected1 = new byte[] { (byte) 0x0A };
/* set arbitrary value */
byte[] valueExpected1 = new byte[] { (byte) 0x04, (byte) 0x00,
(byte) 0x7F, (byte) 0x00, (byte) 0x07, (byte) 0x02,
(byte) 0x02, (byte) 0x04, (byte) 0x03, (byte) 0x04 };
byte[] tlvExpected1 = Utils.concatByteArrays(tagExpected,
lengthExpected1, valueExpected1);
PrimitiveTlvDataObject tlvObject = new PrimitiveTlvDataObject(
tlvExpected1);
/* set arbitrary but valid length matching actual length of value */
byte[] lengthExpected2 = new byte[] { (byte) 0x04 };
/* set arbitrary value */
byte[] valueExpected2 = new byte[] { (byte) 0x04, (byte) 0x00,
(byte) 0x7F, (byte) 0x00 };
TlvValuePlain tlvValue2 = new TlvValuePlain(valueExpected2);
tlvObject.setValue(tlvValue2);
byte[] tlvExpected2 = Utils.concatByteArrays(tagExpected,
lengthExpected2, valueExpected2);
assertArrayEquals("Equals expected byte array representation", tlvObject.toByteArray(),
tlvExpected2);
}
/**
* Positive test case: Set new length with alternative BER but non-DER encoding
*/
@Test
public void testSetLengthTlv_AlternateBerEncoding() {
/* set arbitrary but valid primitive tag */
byte[] tagExpected = new byte[] { (byte) 0x80 };
/* set arbitrary but valid length matching actual length of value */
byte[] lengthExpected1 = new byte[] { (byte) 0x0A };
/* set arbitrary value */
byte[] valueExpected = new byte[] { (byte) 0x04, (byte) 0x00,
(byte) 0x7F, (byte) 0x00, (byte) 0x07, (byte) 0x02,
(byte) 0x02, (byte) 0x04, (byte) 0x03, (byte) 0x04 };
byte[] tlvExpected1 = Utils.concatByteArrays(tagExpected,
lengthExpected1, valueExpected);
PrimitiveTlvDataObject tlvObject = new PrimitiveTlvDataObject(
tlvExpected1);
/* set arbitrary but valid length matching actual length of value */
byte[] lengthExpected2 = new byte[] { (byte) 0x81, (byte) 0x0A };
TlvLength tlvLength2 = new TlvLength(lengthExpected2);
tlvObject.setLength(tlvLength2);
byte[] tlvExpected2 = Utils.concatByteArrays(tagExpected,
lengthExpected2, valueExpected);
assertArrayEquals("Equals expected byte array representation", tlvObject.toByteArray(),
tlvExpected2);
}
/**
* Negative test case: In the setTag method the tlvtaginput must not be null.
*/
@Test(expected=NullPointerException.class)
public void testSetTag_TlvTagInput_Equals_Null()
{
TlvTag tag = null;
PrimitiveTlvDataObject tlv2Object = (PrimitiveTlvDataObject) TlvDataObjectFactory.createTLVDataObject("800A04007F00070202040304");
tlv2Object.setTag(tag);
}
/**
* Negative test case: In the setValue method the TlvValuePlainInput must
* not be null.
*/
@Test(expected = NullPointerException.class)
public void testSetValue_TlvValuePlainInput_Equals_Null()
{
TlvValuePlain value = null;
PrimitiveTlvDataObject tlv2Object = (PrimitiveTlvDataObject) TlvDataObjectFactory.createTLVDataObject("800A04007F00070202040304");
tlv2Object.setValue(value);
}
//TODO missing tests
// modification of value / update of length field (according to package doc this should also work if the existing value is modified and not only if a new value is set)
}