/*
* Commons eID Project.
* Copyright (C) 2008-2013 FedICT.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License version
* 3.0 as published by the Free Software Foundation.
*
* This software 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.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, see
* http://www.gnu.org/licenses/.
*/
package test.unit.be.fedict.commons.eid.consumer.tlv;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.util.Calendar;
import java.util.GregorianCalendar;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.IOUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.junit.Test;
import be.fedict.commons.eid.consumer.Address;
import be.fedict.commons.eid.consumer.DocumentType;
import be.fedict.commons.eid.consumer.Gender;
import be.fedict.commons.eid.consumer.Identity;
import be.fedict.commons.eid.consumer.SpecialOrganisation;
import be.fedict.commons.eid.consumer.SpecialStatus;
import be.fedict.commons.eid.consumer.tlv.TlvField;
import be.fedict.commons.eid.consumer.tlv.TlvParser;
public class TlvParserTest {
private static final Log LOG = LogFactory.getLog(TlvParserTest.class);
@Test
public void parseIdentityFile() throws Exception {
// setup
final InputStream idInputStream = TlvParserTest.class
.getResourceAsStream("/id-alice.tlv");
final byte[] idFile = IOUtils.toByteArray(idInputStream);
// operate
final Identity identity = TlvParser.parse(idFile, Identity.class);
// verify
assertNotNull(identity);
LOG.debug("name: " + identity.name);
assertEquals("SPECIMEN", identity.name);
LOG.debug("first name: " + identity.firstName);
assertEquals("Alice Geldigekaart2266", identity.firstName);
LOG.debug("card number: " + identity.cardNumber);
assertEquals("000000226635", identity.cardNumber);
LOG.debug("card validity date begin: "
+ identity.cardValidityDateBegin.getTime());
assertEquals(new GregorianCalendar(2005, 7, 8),
identity.cardValidityDateBegin);
LOG.debug("card validity date end: "
+ identity.cardValidityDateEnd.getTime());
assertEquals(new GregorianCalendar(2010, 7, 8),
identity.cardValidityDateEnd);
LOG.debug("Card Delivery Municipality: "
+ identity.cardDeliveryMunicipality);
assertEquals("Certipost Specimen", identity.cardDeliveryMunicipality);
LOG.debug("national number: " + identity.nationalNumber);
assertEquals("71715100070", identity.nationalNumber);
LOG.debug("middle name: " + identity.middleName);
assertEquals("A", identity.middleName);
LOG.debug("nationality: " + identity.nationality);
assertEquals("Belg", identity.nationality);
LOG.debug("place of birth: " + identity.placeOfBirth);
assertEquals("Hamont-Achel", identity.placeOfBirth);
LOG.debug("gender: " + identity.gender);
assertEquals(Gender.FEMALE, identity.gender);
assertNotNull(identity.dateOfBirth);
LOG.debug("date of birth: " + identity.dateOfBirth.getTime());
assertEquals(new GregorianCalendar(1971, 0, 1), identity.dateOfBirth);
LOG.debug("special status: " + identity.specialStatus);
assertEquals(SpecialStatus.NO_STATUS, identity.specialStatus);
assertNull(identity.getSpecialOrganisation());
assertNotNull(identity.getData());
}
@Test
public void parseIdentityFile2() throws Exception {
// setup
final InputStream idInputStream = TlvParserTest.class
.getResourceAsStream("/id-alice-2.tlv");
final byte[] idFile = IOUtils.toByteArray(idInputStream);
// operate
final Identity identity = TlvParser.parse(idFile, Identity.class);
// verify
assertNotNull(identity);
LOG.debug("name: " + identity.name);
assertEquals("SPECIMEN", identity.name);
LOG.debug("first name: " + identity.firstName);
assertEquals("Alice Geldigekaart0126", identity.firstName);
LOG.debug("card number: " + identity.cardNumber);
assertEquals("000000012629", identity.cardNumber);
LOG.debug("card validity date begin: "
+ identity.cardValidityDateBegin.getTime());
assertEquals(new GregorianCalendar(2003, 9, 24),
identity.cardValidityDateBegin);
LOG.debug("card validity date end: "
+ identity.cardValidityDateEnd.getTime());
assertEquals(new GregorianCalendar(2008, 9, 24),
identity.cardValidityDateEnd);
LOG.debug("Card Delivery Municipality: "
+ identity.cardDeliveryMunicipality);
assertEquals("Certipost Specimen", identity.cardDeliveryMunicipality);
LOG.debug("national number: " + identity.nationalNumber);
assertEquals("71715100070", identity.nationalNumber);
LOG.debug("middle name: " + identity.middleName);
assertEquals("A", identity.middleName);
LOG.debug("nationality: " + identity.nationality);
assertEquals("Belg", identity.nationality);
LOG.debug("place of birth: " + identity.placeOfBirth);
assertEquals("Hamont-Achel", identity.placeOfBirth);
LOG.debug("gender: " + identity.gender);
assertEquals(Gender.FEMALE, identity.gender);
assertNotNull(identity.dateOfBirth);
LOG.debug("date of birth: " + identity.dateOfBirth.getTime());
assertEquals(new GregorianCalendar(1971, 0, 1), identity.dateOfBirth);
assertNull(identity.getSpecialOrganisation());
}
@Test
public void testYellowCane() throws Exception {
// setup
final byte[] idFile = IOUtils.toByteArray(TlvParserTest.class
.getResourceAsStream("/yellow-cane.tlv"));
// operate
final Identity identity = TlvParser.parse(idFile, Identity.class);
// verify
LOG.debug("special status: " + identity.specialStatus);
assertEquals(SpecialStatus.YELLOW_CANE, identity.specialStatus);
assertTrue(identity.specialStatus.hasBadSight());
assertTrue(identity.specialStatus.hasYellowCane());
assertFalse(identity.specialStatus.hasWhiteCane());
}
@Test
public void testWhiteCane() throws Exception {
// setup
final byte[] idFile = IOUtils.toByteArray(TlvParserTest.class
.getResourceAsStream("/white-cane.tlv"));
// operate
final Identity identity = TlvParser.parse(idFile, Identity.class);
// verify
LOG.debug("special status: " + identity.specialStatus);
assertEquals(SpecialStatus.WHITE_CANE, identity.specialStatus);
assertTrue(identity.specialStatus.hasBadSight());
assertTrue(identity.specialStatus.hasWhiteCane());
assertFalse(identity.specialStatus.hasYellowCane());
}
@Test
public void testExtendedMinority() throws Exception {
// setup
final byte[] idFile = IOUtils.toByteArray(TlvParserTest.class
.getResourceAsStream("/extended-minority.tlv"));
// operate
final Identity identity = TlvParser.parse(idFile, Identity.class);
// verify
LOG.debug("special status: " + identity.specialStatus);
assertEquals(SpecialStatus.EXTENDED_MINORITY, identity.specialStatus);
assertFalse(identity.specialStatus.hasBadSight());
assertTrue(identity.specialStatus.hasExtendedMinority());
LOG.debug("special organisation: \""
+ identity.getSpecialOrganisation() + "\"");
assertNull(identity.getSpecialOrganisation());
}
@Test
public void parseAddressFile() throws Exception {
// setup
final InputStream addressInputStream = TlvParserTest.class
.getResourceAsStream("/address-alice.tlv");
final byte[] addressFile = IOUtils.toByteArray(addressInputStream);
// operate
final Address address = TlvParser.parse(addressFile, Address.class);
// verify
assertNotNull(address);
LOG.debug("street and number: " + address.streetAndNumber);
assertEquals("Meirplaats 1 bus 1", address.streetAndNumber);
LOG.debug("zip: " + address.zip);
assertEquals("2000", address.zip);
LOG.debug("municipality: " + address.municipality);
assertEquals("Antwerpen", address.municipality);
assertNotNull(address.getData());
}
@Test
public void testYearOnlyDate() throws Exception {
final byte[] yearOnlyTLV = new byte[]{12, 4, '1', '9', '8', '4'};
final Identity identity = TlvParser.parse(yearOnlyTLV, Identity.class);
assertEquals(1984, identity.getDateOfBirth().get(Calendar.YEAR));
}
@Test
public void testInvalidDateTruncatedYear() throws Exception {
final byte[] yearOnlyTLV = new byte[]{12, 3, '9', '8', '4'};
try {
TlvParser.parse(yearOnlyTLV, Identity.class);
fail("Parser failed to throw exception at invalid date");
} catch (final RuntimeException rte) {
// expected
}
}
@Test
public void testInvalidDateUnknownMonth() throws Exception {
final byte[] yearOnlyTLV = new byte[]{12, 12, '2', '0', ' ', 'J', 'U',
'N', 'O', ' ', '1', '9', '6', '4'};
try {
TlvParser.parse(yearOnlyTLV, Identity.class);
fail("Parser failed to throw exception at invalid month");
} catch (final RuntimeException rte) {
// expected
}
}
@Test
public void testInvalidDateMissingDayOfMonth() throws Exception {
final byte[] yearOnlyTLV = new byte[]{12, 8, 'S', 'E', 'P', ' ', '1',
'9', '6', '4'};
try {
TlvParser.parse(yearOnlyTLV, Identity.class);
fail("Parser failed to throw exception at missing day of month");
} catch (final RuntimeException rte) {
// expected
}
}
public static class LargeField {
@TlvField(1)
public byte[] field1;
@TlvField(100)
public byte[] field2;
}
@Test
public void testLargeField() throws Exception {
// setup
final ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
// field length < 0x80
byteStream.write(1); // tag
byteStream.write(0x7f); // length
for (int i = 0; i < 0x7f; i++) {
byteStream.write(0x12); // data
}
// field length = 0x80
byteStream.write(2); // tag
byteStream.write(0x81); // length
byteStream.write(0x00);
for (int i = 0; i < 0x80; i++) {
byteStream.write(0x34); // data
}
// field length = 0x3fff
byteStream.write(3); // tag
byteStream.write(0xff); // length
byteStream.write(0x7f);
for (int i = 0; i < 0x3fff; i++) {
byteStream.write(0x56); // data
}
// field length = 0x4000
byteStream.write(4); // tag
byteStream.write(0x81); // length
byteStream.write(0x80);
byteStream.write(0x00);
for (int i = 0; i < 0x4000; i++) {
byteStream.write(0x78); // data
}
// our check field
byteStream.write(100);
byteStream.write(4);
byteStream.write(0xca);
byteStream.write(0xfe);
byteStream.write(0xba);
byteStream.write(0xbe);
final byte[] file = byteStream.toByteArray();
// operate
final LargeField largeField = TlvParser.parse(file, LargeField.class);
// verify
assertEquals(0x7f, largeField.field1.length);
assertArrayEquals(new byte[]{(byte) 0xca, (byte) 0xfe, (byte) 0xba,
(byte) 0xbe}, largeField.field2);
}
public static class MiddlewareEIDFile {
@TlvField(1)
public byte[] identityFile;
}
@Test
public void testParseMiddlewareEIDFile() throws Exception {
final byte[] eidFile = IOUtils.toByteArray(TlvParserTest.class
.getResourceAsStream("/71715100070.eid"));
final MiddlewareEIDFile middlewareEIDFile = TlvParser.parse(eidFile,
MiddlewareEIDFile.class);
final Identity identity = TlvParser.parse(
middlewareEIDFile.identityFile, Identity.class);
LOG.debug("identity: " + identity);
LOG.debug("identity NRN: " + identity.nationalNumber);
assertEquals("71715100070", identity.nationalNumber);
LOG.debug("special status: " + identity.specialStatus);
}
@Test
public void testForeignerIdentityFile() throws Exception {
// setup
final InputStream inputStream = TlvParserTest.class
.getResourceAsStream("/id-foreigner.tlv");
final byte[] identityData = IOUtils.toByteArray(inputStream);
// operate
final Identity identity = TlvParser.parse(identityData, Identity.class);
// verify
LOG.debug("name: " + identity.getName());
LOG.debug("first name: " + identity.getFirstName());
LOG.debug("document type: " + identity.getDocumentType());
assertEquals(DocumentType.FOREIGNER_E_PLUS, identity.getDocumentType());
assertNotNull(identity.getDuplicate());
LOG.debug("duplicate: " + identity.getDuplicate());
LOG.debug("special organisation: \""
+ identity.getSpecialOrganisation() + "\"");
assertEquals(SpecialOrganisation.UNSPECIFIED,
identity.getSpecialOrganisation());
}
@Test
public void testGermanIdentityFileDoB() throws Exception {
// setup
final byte[] idFileCaseInTheField = new byte[]{12, 12, '2', '3', '.',
'S', 'E', 'P', '.', ' ', '1', '9', '8', '2'};
// operate
final Identity identity = TlvParser.parse(idFileCaseInTheField,
Identity.class);
// verify
assertNotNull(identity.getDateOfBirth());
LOG.debug("date of birth: " + identity.getDateOfBirth().getTime());
final byte[] idFile = new byte[]{12, 11, '2', '3', '.', 'S', 'E', 'P',
'.', '1', '9', '8', '2'};
final Identity identity2 = TlvParser.parse(idFile, Identity.class);
assertEquals(identity.getDateOfBirth(), identity2.getDateOfBirth());
}
@Test
public void testIdentityFileDoBYearOnlyWithSpaces() throws Exception {
// setup
final byte[] idFile = new byte[]{12, 12, ' ', ' ', ' ', ' ', ' ', ' ',
' ', ' ', '1', '9', '6', '2'};
// operate
final Identity identity = TlvParser.parse(idFile, Identity.class);
// verify
assertNotNull(identity.getDateOfBirth());
LOG.debug("date of birth: " + identity.getDateOfBirth().getTime());
assertEquals(1962, identity.getDateOfBirth().get(Calendar.YEAR));
assertEquals(0, identity.getDateOfBirth().get(Calendar.MONTH));
assertEquals(1, identity.getDateOfBirth().get(Calendar.DAY_OF_MONTH));
}
@Test
public void testParseOldIdentityFile() throws Exception {
// setup
final InputStream inputStream = TlvParserTest.class
.getResourceAsStream("/old-eid.txt");
final byte[] base64IdentityData = IOUtils.toByteArray(inputStream);
final byte[] identityData = Base64.decodeBase64(base64IdentityData);
// operate
final Identity identity = TlvParser.parse(identityData, Identity.class);
// verify
LOG.debug("name: " + identity.getName());
LOG.debug("first name: " + identity.getFirstName());
LOG.debug("document type: " + identity.getDocumentType());
LOG.debug("card validity date begin: "
+ identity.getCardValidityDateBegin().getTime());
assertEquals(DocumentType.BELGIAN_CITIZEN, identity.getDocumentType());
}
@Test
public void testParseNewIdentityFile() throws Exception {
// setup
final InputStream inputStream = TlvParserTest.class
.getResourceAsStream("/new-eid.txt");
final byte[] base64IdentityData = IOUtils.toByteArray(inputStream);
final byte[] identityData = Base64.decodeBase64(base64IdentityData);
// operate
final Identity identity = TlvParser.parse(identityData, Identity.class);
// verify
LOG.debug("name: " + identity.getName());
LOG.debug("first name: " + identity.getFirstName());
LOG.debug("card validity date begin: "
+ identity.getCardValidityDateBegin().getTime());
LOG.debug("document type: " + identity.getDocumentType());
assertEquals(DocumentType.BELGIAN_CITIZEN, identity.getDocumentType());
assertNull(identity.getDuplicate());
assertFalse(identity.isMemberOfFamily());
}
@Test
public void testHCard() throws Exception {
// setup
final InputStream inputStream = TlvParserTest.class
.getResourceAsStream("/h-card.tlv");
final byte[] identityData = IOUtils.toByteArray(inputStream);
// operate
final Identity identity = TlvParser.parse(identityData, Identity.class);
// verify
LOG.debug("document type: " + identity.getDocumentType());
assertEquals(DocumentType.EUROPEAN_BLUE_CARD_H,
identity.getDocumentType());
LOG.debug("duplicate: " + identity.getDuplicate());
assertEquals("01", identity.getDuplicate());
assertTrue(identity.isMemberOfFamily());
LOG.debug("special organisation: \""
+ identity.getSpecialOrganisation() + "\"");
assertEquals(SpecialOrganisation.UNSPECIFIED,
identity.getSpecialOrganisation());
}
@Test
public void testDuplicate02() throws Exception {
// setup
final InputStream inputStream = TlvParserTest.class
.getResourceAsStream("/duplicate-02.tlv");
final byte[] identityData = IOUtils.toByteArray(inputStream);
// operate
final Identity identity = TlvParser.parse(identityData, Identity.class);
// verify
LOG.debug("document type: " + identity.getDocumentType());
assertEquals(DocumentType.FOREIGNER_A, identity.getDocumentType());
LOG.debug("duplicate: " + identity.getDuplicate());
assertEquals("02", identity.getDuplicate());
LOG.debug("member of family: " + identity.isMemberOfFamily());
assertTrue(identity.isMemberOfFamily());
LOG.debug("special organisation: \""
+ identity.getSpecialOrganisation() + "\"");
assertEquals(SpecialOrganisation.RESEARCHER,
identity.getSpecialOrganisation());
}
@Test
public void parseDateAndCountry() throws Exception {
// setup
final InputStream idInputStream = TlvParserTest.class
.getResourceAsStream("/dateandcountry.tlv");
final byte[] idFile = IOUtils.toByteArray(idInputStream);
// operate
final Identity identity = TlvParser.parse(idFile, Identity.class);
LOG.debug("date and country: "
+ identity.getDateAndCountryOfProtection());
assertEquals("13.08.2014-IT", identity.getDateAndCountryOfProtection());
}
}