package anoncard;

import static org.junit.Assert.*;
import javacard.framework.APDU;
import javacard.framework.ISO7816;
import mixconfig.tools.dataretention.smartcard.ApduConstants;

import org.junit.Test;

public class ANONCardAppletSubTest_ProcessAdminOperations extends AbtractANONCardAppletSubTest {

	public ANONCardAppletSubTest_ProcessAdminOperations() {
		super();
	}

	/**
	 * Test method for
	 * {@link anoncard.ANONCardApplet#process(javacard.framework.APDU)}.
	 */
	@Test
	public void testProcessTransactionBenignAbort() {
		assertFalse(getIsTansactionOpen());
		apduBuffer[ISO7816.OFFSET_INS] = ApduConstants.INSTRUCTION_START_TRANSACTION;
		assertProcessResponse(new byte[] {});
		assertTrue(getIsTansactionOpen());

		apduBuffer[ISO7816.OFFSET_INS] = ApduConstants.INSTRUCTION_ABORT_TRANSACTION;
		assertProcessResponse(new byte[] {});
		assertFalse(getIsTansactionOpen());
	}

	/**
	 * Test method for
	 * {@link anoncard.ANONCardApplet#process(javacard.framework.APDU)}.
	 */
	@Test
	public void testProcessTransactionBenignCommit_noChanges_singleApduLogin() {
		assertFalse(getIsTansactionOpen());
		apduBuffer[ISO7816.OFFSET_INS] = ApduConstants.INSTRUCTION_START_TRANSACTION;
		assertProcessResponse(new byte[] {});
		assertTrue(getIsTansactionOpen());

		byte[] adminsStream = getMinimalNumberOfValidAdminLogins();
		setAPDUData(adminsStream);
		assertTrue("Access should be granted", applet.checkAdminPermission(adminsStream, (short) 0, (short) adminsStream.length));
		assertTrue("Access should be granted", applet.checkAdminPermission(apduBuffer, ISO7816.OFFSET_CDATA, (short) adminsStream.length));

		apduBuffer[ISO7816.OFFSET_INS] = ApduConstants.INSTRUCTION_COMMIT_TRANSACTION;
		assertProcessResponse(new byte[] {});
		assertFalse(getIsTansactionOpen());
	}

	/**
	 * Test method for
	 * {@link anoncard.ANONCardApplet#process(javacard.framework.APDU)}.
	 */
	@Test
	public void testProcessTransactionBenignCommit_noChanges_dataTransmissionLogin() {
		byte[] adminsStream = getMinimalNumberOfValidAdminLogins();

		assertFalse(getIsTansactionOpen());
		apduBuffer[ISO7816.OFFSET_INS] = ApduConstants.INSTRUCTION_START_TRANSACTION;
		assertProcessResponse(new byte[] {});
		assertTrue(getIsTansactionOpen());

		apduBuffer[ISO7816.OFFSET_INS] = ApduConstants.INSTRUCTION_START_DATA_TRANSMISSION;
		apduBuffer[ISO7816.OFFSET_P1] = ApduConstants.INSTRUCTION_COMMIT_TRANSACTION; // instruction
		apduBuffer[ISO7816.OFFSET_P2] = (byte) 0x02; // packages
		setAPDUData(adminsStream);
		assertTrue("Access should be granted", applet.checkAdminPermission(adminsStream, (short) 0, (short) adminsStream.length));
		assertTrue("Access should be granted", applet.checkAdminPermission(apduBuffer, ISO7816.OFFSET_CDATA, (short) adminsStream.length));
		assertProcessResponse(new byte[] { ApduConstants.DATA_TRANSMISSION_PACKAGE_ACK_MAJOR, ApduConstants.DATA_TRANSMISSION_PACKAGE_ACK_MINOR });

		setAPDUData(new byte[] {});
		apduBuffer[ISO7816.OFFSET_INS] = ApduConstants.INSTRUCTION_DATA_TRANSMISSION;
		assertProcessResponse(new byte[] {});
		assertFalse(getIsTansactionOpen());
	}

	/**
	 * Test method for
	 * {@link anoncard.ANONCardApplet#process(javacard.framework.APDU)} and
	 * {@link ANONCardApplet#setPermissionChangeSettings(APDU))}.
	 */
	@Test
	public void testProcessSetPermissionChangeSettings_uninitilized() {
		apduBuffer[ISO7816.OFFSET_INS] = ApduConstants.INSTRUCTION_SET_PERMISSION_CHANGE_SETTINGS;
		setAPDUData(new byte[] { ApduConstants.TRUE, ApduConstants.TRUE, ApduConstants.TRUE });
		assertExceptionResponse(ApduConstants.EXCEPTION_NO_OPEN_TRANSACTION);

		apduBuffer[ISO7816.OFFSET_INS] = ApduConstants.INSTRUCTION_START_TRANSACTION;
		assertProcessResponse(new byte[] {});

		apduBuffer[ISO7816.OFFSET_INS] = ApduConstants.INSTRUCTION_SET_PERMISSION_CHANGE_SETTINGS;
		byte invalidBooleanCode = 0x70;
		assertFalse("Stupid test data", ApduConstants.FALSE == invalidBooleanCode);
		assertFalse("Stupid test data", ApduConstants.TRUE == invalidBooleanCode);

		setAPDUData(new byte[] { ApduConstants.TRUE, ApduConstants.TRUE, ApduConstants.TRUE });
		assertProcessResponse(new byte[] {});
		assertTrue(getConfiguration().newConfiguration.isAllowedToModifyAdministrators);
		assertTrue(getConfiguration().newConfiguration.isAllowedToModifyOperators);
		assertTrue(getConfiguration().newConfiguration.isAllowedToModifyTimeservers);

		setAPDUData(new byte[] { ApduConstants.FALSE, ApduConstants.FALSE, ApduConstants.FALSE });
		assertProcessResponse(new byte[] {});
		assertFalse(getConfiguration().newConfiguration.isAllowedToModifyAdministrators);
		assertFalse(getConfiguration().newConfiguration.isAllowedToModifyOperators);
		assertFalse(getConfiguration().newConfiguration.isAllowedToModifyTimeservers);

		setAPDUData(new byte[] { ApduConstants.FALSE, ApduConstants.FALSE });
		assertExceptionResponse(ApduConstants.EXCEPTION_ILLEGAL_ARGUMENT);

		setAPDUData(new byte[] { ApduConstants.FALSE, ApduConstants.FALSE, ApduConstants.FALSE, ApduConstants.FALSE });
		assertExceptionResponse(ApduConstants.EXCEPTION_ILLEGAL_ARGUMENT);

		setAPDUData(new byte[] { invalidBooleanCode, ApduConstants.FALSE, ApduConstants.FALSE });
		assertExceptionResponse(ApduConstants.EXCEPTION_ILLEGAL_ARGUMENT);

		setAPDUData(new byte[] { ApduConstants.FALSE, invalidBooleanCode, ApduConstants.FALSE });
		assertExceptionResponse(ApduConstants.EXCEPTION_ILLEGAL_ARGUMENT);

		setAPDUData(new byte[] { ApduConstants.FALSE, ApduConstants.FALSE, invalidBooleanCode });
		assertExceptionResponse(ApduConstants.EXCEPTION_ILLEGAL_ARGUMENT);
	}

	/**
	 * Test method for
	 * {@link anoncard.ANONCardApplet#process(javacard.framework.APDU)} and
	 * {@link ANONCardApplet#addAdministrator(APDU)}.
	 */
	@Test
	public void testProcessAddAdministrator() {
		User[] oldUsers = getConfiguration().administrators;
		byte instruction = ApduConstants.INSTRUCTION_ADD_ADMINISTRATOR;
		short pin_length = ApduConstants.LENGTH_OF_ADMINISTRATOR_PIN;
		short max_users = ApduConstants.MAXIMAL_NUMBER_OF_ADMINISTRATORS;
		byte[] stefan0 = mixconfig.tools.dataretention.smartcard.Helpers.concatenate(mixconfig.tools.dataretention.smartcard.Helpers.stringToUtf8Bytes("Stefan"),
				new byte[] { 0x00 });
		byte[] pin = new byte[pin_length];
		byte[] noPin = new byte[pin_length + 1];
		for (int i = 0; i < pin_length; i++) {
			pin[i] = (byte) i;
		}

		addUserSubTest(oldUsers, instruction, max_users, stefan0, pin, noPin);

		// add some
		byte[] tmp;
		for (int i = oldUsers.length; i < max_users; i++) {
			tmp = Arrays.copyOf(stefan0);
			tmp[tmp.length - 1] = (byte) i;
			pin[pin.length - 1] = (byte) i;
			setAPDUData(userToBytes(new User(tmp, pin)));
			assertProcessResponse(new byte[] {});
			assertTrue("Admin is gone", exists(new User(tmp, pin), getConfiguration().newConfiguration.administrators));
		}

		// to many
		tmp = Arrays.copyOf(stefan0);
		tmp[tmp.length - 1] = (byte) (max_users + 1);
		setAPDUData(userToBytes(new User(tmp, pin)));
		assertExceptionResponse(ApduConstants.EXCEPTION_TO_MANY);
		// illegal operation
		apduBuffer[ISO7816.OFFSET_INS] = instruction;
		apduBuffer[ISO7816.OFFSET_INS] = ApduConstants.INSTRUCTION_COMMIT_TRANSACTION;
		assertProcessResponse(new byte[] {});

		getConfiguration().isAllowedToModifyAdministrators = false;
		apduBuffer[ISO7816.OFFSET_INS] = instruction;
		setAPDUData(userToBytes(new User(stefan0, pin)));
		assertExceptionResponse(ApduConstants.EXCEPTION_ILLEGAL_OPERATION);

		// check if all added admins are there
		for (int i = 0; i < oldUsers.length; i++) {
			assertTrue("old Admin_" + i + " missing", exists(oldUsers[i], getConfiguration().administrators));
		}
		for (int i = oldUsers.length; i < max_users; i++) {
			tmp = Arrays.copyOf(stefan0);
			tmp[tmp.length - 1] = (byte) i;
			pin[pin.length - 1] = (byte) i;
			assertTrue("Admin_" + i + " missing", exists(new User(tmp, pin), getConfiguration().administrators));
		}
		assertEquals(getConfiguration().administrators.length, max_users);
	}

	/**
	 * @param oldUsers
	 * @param instruction
	 * @param max_users
	 * @param stefan0
	 * @param pin
	 * @param noPin
	 */
	private void addUserSubTest(User[] oldUsers, byte instruction, short max_users, byte[] stefan0, byte[] pin, byte[] noPin) {
		apduBuffer[ISO7816.OFFSET_INS] = instruction;

		// no transaction
		setAPDUData(userToBytes(new User(stefan0, pin)));
		assertExceptionResponse(ApduConstants.EXCEPTION_NO_OPEN_TRANSACTION);

		apduBuffer[ISO7816.OFFSET_INS] = ApduConstants.INSTRUCTION_START_TRANSACTION;
		assertProcessResponse(new byte[] {});
		apduBuffer[ISO7816.OFFSET_INS] = instruction;

		// illegal argument (name exists, pin length wrong)
		setAPDUData(userToBytes(new User(stefan0, noPin)));
		assertExceptionResponse(ApduConstants.EXCEPTION_ILLEGAL_ARGUMENT);
		setAPDUData(userToBytes(new User(oldUsers[0].getUsername(), pin)));
		assertExceptionResponse(ApduConstants.EXCEPTION_ILLEGAL_ARGUMENT);
	}

	/**
	 * Test method for
	 * {@link anoncard.ANONCardApplet#process(javacard.framework.APDU)} and
	 * {@link ANONCardApplet#removeAdministrator(APDU)}.
	 */
	@Test
	public void testProcessRemoveAdministrator() {
		apduBuffer[ISO7816.OFFSET_INS] = ApduConstants.INSTRUCTION_REMOVE_ADMINISTRATOR;
		byte[] name = getConfiguration().administrators[0].getUsername();
		setAPDUData(name);

		// no transaction
		assertExceptionResponse(ApduConstants.EXCEPTION_NO_OPEN_TRANSACTION);

		// benign
		apduBuffer[ISO7816.OFFSET_INS] = ApduConstants.INSTRUCTION_START_TRANSACTION;
		assertProcessResponse(new byte[] {});
		apduBuffer[ISO7816.OFFSET_INS] = ApduConstants.INSTRUCTION_REMOVE_ADMINISTRATOR;
		assertProcessResponse(new byte[] {});

		// no such name (illegal argument)
		assertExceptionResponse(ApduConstants.EXCEPTION_ILLEGAL_ARGUMENT);

		// initialized and allowedToModify... false -> illegal operation
		applet.generateKeyPair();
		getConfiguration().isAllowedToModifyAdministrators = false;
		apduBuffer[ISO7816.OFFSET_INS] = ApduConstants.INSTRUCTION_REMOVE_ADMINISTRATOR;
		assertExceptionResponse(ApduConstants.EXCEPTION_ILLEGAL_OPERATION);
		getConfiguration().isAllowedToModifyAdministrators = true;

		// not enough
		int lastAdmin = getConfiguration().administrators.length - 1;
		for (int i = 1; i < lastAdmin; i++) {
			setAPDUData(getConfiguration().administrators[i].getUsername());
			assertProcessResponse(new byte[] {});
		}
		setAPDUData(getConfiguration().administrators[lastAdmin].getUsername());
		assertExceptionResponse(ApduConstants.EXCEPTION_ILLEGAL_OPERATION);

	}

	/**
	 * Test method for
	 * {@link anoncard.ANONCardApplet#process(javacard.framework.APDU)} and
	 * {@link ANONCardApplet#removeOperator(APDU)}.
	 */
	@Test
	public void testProcessRemoveOperator() {
		apduBuffer[ISO7816.OFFSET_INS] = ApduConstants.INSTRUCTION_REMOVE_OPERATOR;
		byte[] name = getConfiguration().operators[0].getUsername();
		setAPDUData(name);

		// no transaction
		assertExceptionResponse(ApduConstants.EXCEPTION_NO_OPEN_TRANSACTION);

		// benign
		apduBuffer[ISO7816.OFFSET_INS] = ApduConstants.INSTRUCTION_START_TRANSACTION;
		assertProcessResponse(new byte[] {});
		apduBuffer[ISO7816.OFFSET_INS] = ApduConstants.INSTRUCTION_REMOVE_OPERATOR;
		assertProcessResponse(new byte[] {});

		// no such name (illegal argument)
		assertExceptionResponse(ApduConstants.EXCEPTION_ILLEGAL_ARGUMENT);

		// initialized and allowedToModify... false -> illegal operation
		applet.generateKeyPair();
		getConfiguration().isAllowedToModifyOperators = false;
		apduBuffer[ISO7816.OFFSET_INS] = ApduConstants.INSTRUCTION_REMOVE_OPERATOR;
		assertExceptionResponse(ApduConstants.EXCEPTION_ILLEGAL_OPERATION);
		getConfiguration().isAllowedToModifyOperators = true;

		// not enough
		int lastOperator = getConfiguration().operators.length - 1;
		for (int i = 1; i < lastOperator; i++) {
			setAPDUData(getConfiguration().operators[i].getUsername());
			assertProcessResponse(new byte[] {});
		}
		setAPDUData(getConfiguration().operators[lastOperator].getUsername());
		assertExceptionResponse(ApduConstants.EXCEPTION_ILLEGAL_OPERATION);
	}

	/**
	 * Test method for
	 * {@link anoncard.ANONCardApplet#process(javacard.framework.APDU)} and
	 * {@link ANONCardApplet#addOperator(APDU)}.
	 */
	@Test
	public void testProcessAddOperator() {
		User[] oldUsers = getConfiguration().operators;
		byte instruction = ApduConstants.INSTRUCTION_ADD_OPERATOR;
		short pin_length = ApduConstants.LENGTH_OF_OPERATOR_PIN;
		short max_users = ApduConstants.MAXIMAL_NUMBER_OF_OPERATORS;
		byte[] stefan0 = mixconfig.tools.dataretention.smartcard.Helpers.concatenate(mixconfig.tools.dataretention.smartcard.Helpers.stringToUtf8Bytes("Stefan"),
				new byte[] { 0x00 });
		byte[] pin = new byte[pin_length];
		byte[] noPin = new byte[pin_length + 1];
		for (int i = 0; i < pin_length; i++) {
			pin[i] = (byte) i;
		}

		addUserSubTest(oldUsers, instruction, max_users, stefan0, pin, noPin);

		// add some
		byte[] tmp;
		for (int i = oldUsers.length; i < max_users; i++) {
			tmp = Arrays.copyOf(stefan0);
			tmp[tmp.length - 1] = (byte) i;
			pin[pin.length - 1] = (byte) i;
			setAPDUData(userToBytes(new User(tmp, pin)));
			assertProcessResponse(new byte[] {});
			assertTrue("Admin is gone", exists(new User(tmp, pin), getConfiguration().newConfiguration.operators));
		}

		// to many
		tmp = Arrays.copyOf(stefan0);
		tmp[tmp.length - 1] = (byte) (max_users + 1);
		setAPDUData(userToBytes(new User(tmp, pin)));
		assertExceptionResponse(ApduConstants.EXCEPTION_TO_MANY);
		// illegal operation
		apduBuffer[ISO7816.OFFSET_INS] = instruction;
		apduBuffer[ISO7816.OFFSET_INS] = ApduConstants.INSTRUCTION_COMMIT_TRANSACTION;
		assertProcessResponse(new byte[] {});

		getConfiguration().isAllowedToModifyOperators = false;
		apduBuffer[ISO7816.OFFSET_INS] = instruction;
		setAPDUData(userToBytes(new User(stefan0, pin)));
		assertExceptionResponse(ApduConstants.EXCEPTION_ILLEGAL_OPERATION);

		// check if all added admins are there
		for (int i = 0; i < oldUsers.length; i++) {
			assertTrue("old operator_" + i + " missing", exists(oldUsers[i], getConfiguration().operators));
		}
		for (int i = oldUsers.length; i < max_users; i++) {
			tmp = Arrays.copyOf(stefan0);
			tmp[tmp.length - 1] = (byte) i;
			pin[pin.length - 1] = (byte) i;
			assertTrue("Operator_" + i + " missing", exists(new User(tmp, pin), getConfiguration().operators));
		}
		assertEquals(getConfiguration().operators.length, max_users);

	}

	/**
	 * Test method for
	 * {@link anoncard.ANONCardApplet#setNeededNumberOfAdministrators(APDU)}.
	 */
	@Test
	public void testProcessSetNeededNumberOfAdministrators_benign() {
		apduBuffer[ISO7816.OFFSET_INS] = ApduConstants.INSTRUCTION_START_TRANSACTION;
		assertProcessResponse(new byte[] {});

		byte newNumberONeededAdministrators = (byte) getConfiguration().administrators.length;
		assertFalse("Stupid testdata", getConfiguration().neededNumberOfAdministrators == newNumberONeededAdministrators);

		apduBuffer[ISO7816.OFFSET_INS] = ApduConstants.INSTRUCTION_SET_NEEDED_NUMBER_OF_ADMINISTROTORS;
		apduBuffer[ISO7816.OFFSET_P1] = newNumberONeededAdministrators;
		assertProcessResponse(new byte[] {});

		apduBuffer[ISO7816.OFFSET_INS] = ApduConstants.INSTRUCTION_COMMIT_TRANSACTION;
		byte[] adminsStream = getMinimalNumberOfValidAdminLogins();
		setAPDUData(adminsStream);
		assertTrue("Access should be granted", applet.checkAdminPermission(adminsStream, (short) 0, (short) adminsStream.length));
		assertTrue("Access should be granted", applet.checkAdminPermission(apduBuffer, ISO7816.OFFSET_CDATA, (short) adminsStream.length));
		assertProcessResponse(new byte[] {});

		assertEquals(newNumberONeededAdministrators, getConfiguration().neededNumberOfAdministrators);
	}

	/**
	 * Test method for
	 * {@link anoncard.ANONCardApplet#setNeededNumberOfAdministrators(APDU)}.
	 */
	@Test
	public void testProcessSetNeededNumberOfAdministrators_noOpenTransactionException() {
		apduBuffer[ISO7816.OFFSET_INS] = ApduConstants.INSTRUCTION_SET_NEEDED_NUMBER_OF_ADMINISTROTORS;
		apduBuffer[ISO7816.OFFSET_P1] = (byte) getConfiguration().administrators.length;
		assertExceptionResponse(ApduConstants.EXCEPTION_NO_OPEN_TRANSACTION);
	}

	/**
	 * Test method for
	 * {@link anoncard.ANONCardApplet#setNeededNumberOfAdministrators(APDU)}.
	 */
	@Test
	public void testProcessSetNeededNumberOfAdministrators_notAllowed() {
		apduBuffer[ISO7816.OFFSET_INS] = ApduConstants.INSTRUCTION_SET_NEEDED_NUMBER_OF_ADMINISTROTORS;
		apduBuffer[ISO7816.OFFSET_P1] = (byte) getConfiguration().administrators.length;
		applet.generateKeyPair();
		getConfiguration().isAllowedToModifyAdministrators = false;
		assertExceptionResponse(ApduConstants.EXCEPTION_ILLEGAL_OPERATION);
	}

	/**
	 * Test method for
	 * {@link anoncard.ANONCardApplet#setNeededNumberOfAdministrators(APDU)}.
	 */
	@Test
	public void testProcessSetNeededNumberOfAdministrators_illegalArgument() {
		apduBuffer[ISO7816.OFFSET_INS] = ApduConstants.INSTRUCTION_START_TRANSACTION;
		assertProcessResponse(new byte[] {});

		byte newNumberONeededAdministrators = (byte) (getConfiguration().administrators.length + 1);
		byte oldNumberONeededAdministrators = (byte) getConfiguration().neededNumberOfAdministrators;
		assertFalse("Stupid testdata", getConfiguration().neededNumberOfAdministrators == newNumberONeededAdministrators);

		apduBuffer[ISO7816.OFFSET_INS] = ApduConstants.INSTRUCTION_SET_NEEDED_NUMBER_OF_ADMINISTROTORS;
		apduBuffer[ISO7816.OFFSET_P1] = newNumberONeededAdministrators;
		assertExceptionResponse(ApduConstants.EXCEPTION_ILLEGAL_ARGUMENT);

		apduBuffer[ISO7816.OFFSET_INS] = ApduConstants.INSTRUCTION_SET_NEEDED_NUMBER_OF_ADMINISTROTORS;
		apduBuffer[ISO7816.OFFSET_P1] = (byte) 0x00;
		assertExceptionResponse(ApduConstants.EXCEPTION_ILLEGAL_ARGUMENT);

		apduBuffer[ISO7816.OFFSET_INS] = ApduConstants.INSTRUCTION_SET_NEEDED_NUMBER_OF_ADMINISTROTORS;
		apduBuffer[ISO7816.OFFSET_P1] = (byte) 128;
		assertExceptionResponse(ApduConstants.EXCEPTION_ILLEGAL_ARGUMENT);

		apduBuffer[ISO7816.OFFSET_INS] = ApduConstants.INSTRUCTION_COMMIT_TRANSACTION;
		byte[] adminsStream = getMinimalNumberOfValidAdminLogins();
		setAPDUData(adminsStream);
		assertTrue("Access should be granted", applet.checkAdminPermission(adminsStream, (short) 0, (short) adminsStream.length));
		assertTrue("Access should be granted", applet.checkAdminPermission(apduBuffer, ISO7816.OFFSET_CDATA, (short) adminsStream.length));
		assertProcessResponse(new byte[] {});

		assertEquals(oldNumberONeededAdministrators, getConfiguration().neededNumberOfAdministrators);
	}

	/**
	 * Test method for
	 * {@link anoncard.ANONCardApplet#setNeededNumberOfAdministrators(APDU)}.
	 */
	@Test
	public void testProcessSetNeededNumberOfOperators_benign() {
		apduBuffer[ISO7816.OFFSET_INS] = ApduConstants.INSTRUCTION_START_TRANSACTION;
		assertProcessResponse(new byte[] {});

		byte newNumberONeededOperators = (byte) getConfiguration().operators.length;
		assertFalse("Stupid testdata", getConfiguration().neededNumberOfOperators == newNumberONeededOperators);

		apduBuffer[ISO7816.OFFSET_INS] = ApduConstants.INSTRUCTION_SET_NEEDED_NUMBER_OF_OPERATORS;
		apduBuffer[ISO7816.OFFSET_P1] = newNumberONeededOperators;
		assertProcessResponse(new byte[] {});

		apduBuffer[ISO7816.OFFSET_INS] = ApduConstants.INSTRUCTION_COMMIT_TRANSACTION;
		byte[] adminsStream = getMinimalNumberOfValidAdminLogins();
		setAPDUData(adminsStream);
		assertTrue("Access should be granted", applet.checkAdminPermission(adminsStream, (short) 0, (short) adminsStream.length));
		assertTrue("Access should be granted", applet.checkAdminPermission(apduBuffer, ISO7816.OFFSET_CDATA, (short) adminsStream.length));
		assertProcessResponse(new byte[] {});

		assertEquals(newNumberONeededOperators, getConfiguration().neededNumberOfOperators);
	}

	/**
	 * Test method for
	 * {@link anoncard.ANONCardApplet#setNeededNumberOfAdministrators(APDU)}.
	 */
	@Test
	public void testProcessSetNeededNumberOfOperators_noOpenTransactionException() {
		apduBuffer[ISO7816.OFFSET_INS] = ApduConstants.INSTRUCTION_SET_NEEDED_NUMBER_OF_OPERATORS;
		apduBuffer[ISO7816.OFFSET_P1] = (byte) getConfiguration().operators.length;
		assertExceptionResponse(ApduConstants.EXCEPTION_NO_OPEN_TRANSACTION);
	}

	/**
	 * Test method for
	 * {@link anoncard.ANONCardApplet#setNeededNumberOfOperators(APDU)}.
	 */
	@Test
	public void testProcessSetNeededNumberOfOperators_notAllowed() {
		apduBuffer[ISO7816.OFFSET_INS] = ApduConstants.INSTRUCTION_SET_NEEDED_NUMBER_OF_OPERATORS;
		apduBuffer[ISO7816.OFFSET_P1] = (byte) getConfiguration().operators.length;
		applet.generateKeyPair();
		getConfiguration().isAllowedToModifyOperators = false;
		assertExceptionResponse(ApduConstants.EXCEPTION_ILLEGAL_OPERATION);
	}

	/**
	 * Test method for
	 * {@link anoncard.ANONCardApplet#setNeededNumberOfAdministrators(APDU)}.
	 */
	@Test
	public void testProcessSetNeededNumberOfOperators_illegalArgument() {
		apduBuffer[ISO7816.OFFSET_INS] = ApduConstants.INSTRUCTION_START_TRANSACTION;
		assertProcessResponse(new byte[] {});

		byte newNumberONeededOperators = (byte) (getConfiguration().operators.length + 1);
		byte oldNumberONeededOperators = (byte) getConfiguration().neededNumberOfOperators;
		assertFalse("Stupid testdata", getConfiguration().neededNumberOfOperators == newNumberONeededOperators);

		apduBuffer[ISO7816.OFFSET_INS] = ApduConstants.INSTRUCTION_SET_NEEDED_NUMBER_OF_OPERATORS;
		apduBuffer[ISO7816.OFFSET_P1] = newNumberONeededOperators;
		assertExceptionResponse(ApduConstants.EXCEPTION_ILLEGAL_ARGUMENT);

		apduBuffer[ISO7816.OFFSET_INS] = ApduConstants.INSTRUCTION_SET_NEEDED_NUMBER_OF_OPERATORS;
		apduBuffer[ISO7816.OFFSET_P1] = (byte) 0x00;
		assertExceptionResponse(ApduConstants.EXCEPTION_ILLEGAL_ARGUMENT);

		apduBuffer[ISO7816.OFFSET_INS] = ApduConstants.INSTRUCTION_SET_NEEDED_NUMBER_OF_OPERATORS;
		apduBuffer[ISO7816.OFFSET_P1] = (byte) 128;
		assertExceptionResponse(ApduConstants.EXCEPTION_ILLEGAL_ARGUMENT);

		apduBuffer[ISO7816.OFFSET_INS] = ApduConstants.INSTRUCTION_COMMIT_TRANSACTION;
		byte[] adminsStream = getMinimalNumberOfValidAdminLogins();
		setAPDUData(adminsStream);
		assertTrue("Access should be granted", applet.checkAdminPermission(adminsStream, (short) 0, (short) adminsStream.length));
		assertTrue("Access should be granted", applet.checkAdminPermission(apduBuffer, ISO7816.OFFSET_CDATA, (short) adminsStream.length));
		assertProcessResponse(new byte[] {});

		assertEquals(oldNumberONeededOperators, getConfiguration().neededNumberOfOperators);
	}

	/**
	 * Test method for
	 * {@link anoncard.ANONCardApplet#process(javacard.framework.APDU)}.
	 */
	@Test
	public void testProcessTransactionCommit_benign() {
		apduBuffer[ISO7816.OFFSET_INS] = ApduConstants.INSTRUCTION_START_TRANSACTION;
		assertProcessResponse(new byte[] {});

		apduBuffer[ISO7816.OFFSET_INS] = ApduConstants.INSTRUCTION_COMMIT_TRANSACTION;
		byte[] adminsStream = getMinimalNumberOfValidAdminLogins();
		setAPDUData(adminsStream);
		assertTrue("Access should be granted", applet.checkAdminPermission(adminsStream, (short) 0, (short) adminsStream.length));
		assertTrue("Access should be granted", applet.checkAdminPermission(apduBuffer, ISO7816.OFFSET_CDATA, (short) adminsStream.length));
		assertProcessResponse(new byte[] {});
	}

	/**
	 * Test method for
	 * {@link anoncard.ANONCardApplet#process(javacard.framework.APDU)}.
	 */
	@Test
	public void testProcessTransactionCommit_PermissionDeniedException() {
		assertFalse(getIsTansactionOpen());
		applet.generateKeyPair();
		apduBuffer[ISO7816.OFFSET_INS] = ApduConstants.INSTRUCTION_START_TRANSACTION;
		assertProcessResponse(new byte[] {});
		assertTrue(getIsTansactionOpen());

		byte[] adminsStream = getMinimalNumberOfValidAdminLogins();
		adminsStream[adminsStream.length - 1]++;
		setAPDUData(adminsStream);
		assertFalse("Access should not be granted", applet.checkAdminPermission(adminsStream, (short) 0, (short) adminsStream.length));
		assertFalse("Access should not be granted", applet.checkAdminPermission(apduBuffer, ISO7816.OFFSET_CDATA, (short) adminsStream.length));

		apduBuffer[ISO7816.OFFSET_INS] = ApduConstants.INSTRUCTION_COMMIT_TRANSACTION;
		assertExceptionResponse(ApduConstants.EXCEPTION_ADMIN_PERMISSION_DENIED);
		assertFalse(getIsTansactionOpen());
	}

	/**
	 * Test method for
	 * {@link anoncard.ANONCardApplet#process(javacard.framework.APDU)}.
	 */
	@Test
	public void testProcessTransactionAbort_NoOpenTransactionException() {
		apduBuffer[ISO7816.OFFSET_INS] = ApduConstants.INSTRUCTION_ABORT_TRANSACTION;
		applet.generateKeyPair();
		assertExceptionResponse(ApduConstants.EXCEPTION_NO_OPEN_TRANSACTION);
	}

	/**
	 * Test methiod for {@link ANONCardApplet#resetLog(APDU)}
	 */
	@Test
	public void testResetLog() {

		// null test
		byte[] adminsStream = new byte[] {};
		setAPDUData(adminsStream);
		assertFalse("Access should not be granted", applet.checkAdminPermission(adminsStream, (short) 0, (short) adminsStream.length));
		assertFalse("Access should not be granted", applet.checkAdminPermission(apduBuffer, ISO7816.OFFSET_CDATA, (short) adminsStream.length));
		apduBuffer[ISO7816.OFFSET_INS] = ApduConstants.INSTRUCTION_RESET_ANONCARDAPPLET_LOG;
		assertExceptionResponse(ApduConstants.EXCEPTION_ADMIN_PERMISSION_DENIED);

		// single APDU login
		// Permission denied
		adminsStream = getMinimalNumberOfValidAdminLogins();
		adminsStream[adminsStream.length - 1]++;
		setAPDUData(adminsStream);
		assertFalse("Access should not be granted", applet.checkAdminPermission(adminsStream, (short) 0, (short) adminsStream.length));
		assertFalse("Access should not be granted", applet.checkAdminPermission(apduBuffer, ISO7816.OFFSET_CDATA, (short) adminsStream.length));
		apduBuffer[ISO7816.OFFSET_INS] = ApduConstants.INSTRUCTION_RESET_ANONCARDAPPLET_LOG;
		assertExceptionResponse(ApduConstants.EXCEPTION_ADMIN_PERMISSION_DENIED);
		// Permission granted
		adminsStream = getMinimalNumberOfValidAdminLogins();
		setAPDUData(adminsStream);
		assertTrue("Access should be granted", applet.checkAdminPermission(adminsStream, (short) 0, (short) adminsStream.length));
		assertTrue("Access should be granted", applet.checkAdminPermission(apduBuffer, ISO7816.OFFSET_CDATA, (short) adminsStream.length));
		apduBuffer[ISO7816.OFFSET_INS] = ApduConstants.INSTRUCTION_RESET_ANONCARDAPPLET_LOG;
		assertProcessResponse(new byte[] {});
		assertEquals(1, getLog().size());
		assertEquals(ApduConstants.INSTRUCTION_RESET_ANONCARDAPPLET_LOG, getLog().getLogEntry((short) 0).getData()[0]);

		// dataReceiveChannel Login
		// Permission denied
		adminsStream = getMinimalNumberOfValidAdminLogins();
		adminsStream[adminsStream.length - 1]++;
		setAPDUData(adminsStream);
		assertFalse("Access should not be granted", applet.checkAdminPermission(adminsStream, (short) 0, (short) adminsStream.length));
		assertFalse("Access should not be granted", applet.checkAdminPermission(apduBuffer, ISO7816.OFFSET_CDATA, (short) adminsStream.length));
		apduBuffer[ISO7816.OFFSET_INS] = ApduConstants.INSTRUCTION_START_DATA_TRANSMISSION;
		apduBuffer[ISO7816.OFFSET_P1] = ApduConstants.INSTRUCTION_RESET_ANONCARDAPPLET_LOG;
		apduBuffer[ISO7816.OFFSET_P2] = 1;
		assertExceptionResponse(ApduConstants.EXCEPTION_ADMIN_PERMISSION_DENIED);
		// Permission granted
		adminsStream = getMinimalNumberOfValidAdminLogins();
		setAPDUData(adminsStream);
		assertTrue("Access should be granted", applet.checkAdminPermission(adminsStream, (short) 0, (short) adminsStream.length));
		assertTrue("Access should be granted", applet.checkAdminPermission(apduBuffer, ISO7816.OFFSET_CDATA, (short) adminsStream.length));
		apduBuffer[ISO7816.OFFSET_INS] = ApduConstants.INSTRUCTION_START_DATA_TRANSMISSION;
		apduBuffer[ISO7816.OFFSET_P1] = ApduConstants.INSTRUCTION_RESET_ANONCARDAPPLET_LOG;
		apduBuffer[ISO7816.OFFSET_P2] = 1;
		assertProcessResponse(new byte[] {});
		assertEquals(1, getLog().size());
		assertEquals(ApduConstants.INSTRUCTION_RESET_ANONCARDAPPLET_LOG, getLog().getLogEntry((short) 0).getData()[0]);
	}

	/**
	 * 
	 */
	@Test
	public void testResetApplet_singleAPDULogin() {
		// null test
		byte[] adminsStream = new byte[] {};
		setAPDUData(adminsStream);
		assertFalse("Access should not be granted", applet.checkAdminPermission(adminsStream, (short) 0, (short) adminsStream.length));
		assertFalse("Access should not be granted", applet.checkAdminPermission(apduBuffer, ISO7816.OFFSET_CDATA, (short) adminsStream.length));
		apduBuffer[ISO7816.OFFSET_INS] = ApduConstants.INSTRUCTION_RESET_ANONCARDAPPLET_CARD;
		assertExceptionResponse(ApduConstants.EXCEPTION_ADMIN_PERMISSION_DENIED);

		// single APDU login
		// Permission denied
		adminsStream = getMinimalNumberOfValidAdminLogins();
		adminsStream[adminsStream.length - 1]++;
		setAPDUData(adminsStream);
		assertFalse("Access should not be granted", applet.checkAdminPermission(adminsStream, (short) 0, (short) adminsStream.length));
		assertFalse("Access should not be granted", applet.checkAdminPermission(apduBuffer, ISO7816.OFFSET_CDATA, (short) adminsStream.length));
		apduBuffer[ISO7816.OFFSET_INS] = ApduConstants.INSTRUCTION_RESET_ANONCARDAPPLET_CARD;
		assertExceptionResponse(ApduConstants.EXCEPTION_ADMIN_PERMISSION_DENIED);
		// Permission granted
		adminsStream = getMinimalNumberOfValidAdminLogins();
		setAPDUData(adminsStream);
		assertTrue("Access should be granted", applet.checkAdminPermission(adminsStream, (short) 0, (short) adminsStream.length));
		assertTrue("Access should be granted", applet.checkAdminPermission(apduBuffer, ISO7816.OFFSET_CDATA, (short) adminsStream.length));
		apduBuffer[ISO7816.OFFSET_INS] = ApduConstants.INSTRUCTION_RESET_ANONCARDAPPLET_CARD;
		assertProcessResponse(new byte[] {});
		isANONCardAppletReseted();
	}

	/**
	 * 
	 */
	@Test
	public void testResetApplet_DataReceiveChannelLogin() {
		// dataReceiveChannel Login
		// Permission denied
		byte[] adminsStream = getMinimalNumberOfValidAdminLogins();
		adminsStream[adminsStream.length - 1]++;
		setAPDUData(adminsStream);
		assertFalse("Access should not be granted", applet.checkAdminPermission(adminsStream, (short) 0, (short) adminsStream.length));
		assertFalse("Access should not be granted", applet.checkAdminPermission(apduBuffer, ISO7816.OFFSET_CDATA, (short) adminsStream.length));
		apduBuffer[ISO7816.OFFSET_INS] = ApduConstants.INSTRUCTION_START_DATA_TRANSMISSION;
		apduBuffer[ISO7816.OFFSET_P1] = ApduConstants.INSTRUCTION_RESET_ANONCARDAPPLET_CARD;
		apduBuffer[ISO7816.OFFSET_P2] = 1;
		assertExceptionResponse(ApduConstants.EXCEPTION_ADMIN_PERMISSION_DENIED);
		// Permission granted
		adminsStream = getMinimalNumberOfValidAdminLogins();
		setAPDUData(adminsStream);
		assertTrue("Access should be granted", applet.checkAdminPermission(adminsStream, (short) 0, (short) adminsStream.length));
		assertTrue("Access should be granted", applet.checkAdminPermission(apduBuffer, ISO7816.OFFSET_CDATA, (short) adminsStream.length));
		apduBuffer[ISO7816.OFFSET_INS] = ApduConstants.INSTRUCTION_START_DATA_TRANSMISSION;
		apduBuffer[ISO7816.OFFSET_P1] = ApduConstants.INSTRUCTION_RESET_ANONCARDAPPLET_CARD;
		apduBuffer[ISO7816.OFFSET_P2] = 1;
		assertProcessResponse(new byte[] {});
		isANONCardAppletReseted();
	}

	private void isANONCardAppletReseted() {
		assertFalse(getDataReceiveChannel().isOpen());
		assertFalse(getDataSendChannel().isOpen());
		assertFalse(applet.isInitialized());
		assertFalse(getIsTansactionOpen());
		assertFalse(getDate().isSet());
		ANONCardAppletConfiguration configuration = getConfiguration();
		isConfigurationReseted(configuration);
		configuration = getConfiguration().newConfiguration;
		isConfigurationReseted(configuration);
		assertEquals(1, getLog().size());
		assertEquals(ApduConstants.INSTRUCTION_RESET_ANONCARDAPPLET_CARD, getLog().getLogEntry((short) 0).getData()[0]);
	}

	private void isConfigurationReseted(ANONCardAppletConfiguration configuration) {
		assertArrayEquals(null, configuration.administrators);
		assertArrayEquals(null, configuration.operators);
		assertArrayEquals(null, configuration.timeservers);
		assertTrue(configuration.isAllowedToModifyAdministrators);
		assertTrue(configuration.isAllowedToModifyOperators);
		assertTrue(configuration.isAllowedToModifyTimeservers);
		assertEquals(1, configuration.neededNumberOfAdministrators);
		assertEquals(1, configuration.neededNumberOfOperators);
	}
}