/*
 * Copyright 2018 Scytl Secure Electronic Voting SA
 *
 * All rights reserved
 *
 * See our extended copyright notice in *file 'Copyright.txt' which is part of this source code package
 */
package com.scytl.cryptolib.scytl.keystore.factory;

import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertNull;

import java.nio.charset.StandardCharsets;

import org.junit.Before;
import org.junit.Test;

/**
 * Tests of {@link DerivedKeyCacheImpl}.
 */
public class DerivedKeyCacheImplTest {
    private static final String ALIAS1 = "alias1";
    
    private static final String ALIAS2 = "alias2";
    
    private static final char[] PASSWORD1 = "password1".toCharArray();

    private static final char[] PASSWORD2 = "password2".toCharArray();

    private static final byte[] KEY1 =
        "key1".getBytes(StandardCharsets.UTF_8);

    private static final byte[] KEY2 =
        "key2".getBytes(StandardCharsets.UTF_8);
    
    private DerivedKeyCache cache;

    @Before
    public void setUp() {
        cache = new DerivedKeyCacheImpl();
    }

    @Test
    public void testGetEmpty() {
        assertNull(cache.get(PASSWORD1));
    }

    @Test
    public void testPutForElGamalPrivatelKeyNew() {
        cache.putForElGamalPrivateKey(ALIAS1, PASSWORD1, KEY1);
        assertArrayEquals(KEY1, cache.get(PASSWORD1));
    }
    
    @Test
    public void testPutForElGamalPrivatelKeyTheSame() {
        cache.putForElGamalPrivateKey(ALIAS1, PASSWORD1, KEY1);
        cache.putForElGamalPrivateKey(ALIAS1, PASSWORD1, KEY1);
        assertArrayEquals(KEY1, cache.get(PASSWORD1));
    }
    
    @Test
    public void testPutForElGamalPrivatelKeyDifferent() {
        cache.putForElGamalPrivateKey(ALIAS1, PASSWORD1, KEY1);
        cache.putForElGamalPrivateKey(ALIAS1, PASSWORD2, KEY2);
        assertArrayEquals(KEY2, cache.get(PASSWORD2));
        assertNull(cache.get(PASSWORD1));
    }
    
    @Test
    public void testPutForElGamalPrivatelKeyTheShared() {
        cache.putForElGamalPrivateKey(ALIAS1, PASSWORD1, KEY1);
        cache.putForElGamalPrivateKey(ALIAS2, PASSWORD1, KEY1);
        cache.putForElGamalPrivateKey(ALIAS1, PASSWORD2, KEY2);
        assertArrayEquals(KEY1, cache.get(PASSWORD1));
    }

    @Test
    public void testPutForKeyStoreNew() {
        cache.putForKeyStore(PASSWORD1, KEY1);
        assertArrayEquals(KEY1, cache.get(PASSWORD1));
    }
    
    @Test
    public void testPutForKeyStoreShared() {
        cache.putForPrivateKey(ALIAS1, PASSWORD1, KEY1);
        cache.putForKeyStore(PASSWORD1, KEY1);
        cache.putForPrivateKey(ALIAS1, PASSWORD2, KEY2);
        assertArrayEquals(KEY1, cache.get(PASSWORD1));
    }
    
    @Test
    public void testPutForKeyStoreSame() {
        cache.putForKeyStore(PASSWORD1, KEY1);
        cache.putForKeyStore(PASSWORD1, KEY1);
        assertArrayEquals(KEY1, cache.get(PASSWORD1));
    }
    
    @Test
    public void testPutForKeyStoreDifferent() {
        cache.putForKeyStore(PASSWORD1, KEY1);
        cache.putForKeyStore(PASSWORD2, KEY2);
        assertArrayEquals(KEY2, cache.get(PASSWORD2));
        assertNull(cache.get(PASSWORD1));
    }

    @Test
    public void testPutForPrivateKeyNew() {
        cache.putForPrivateKey(ALIAS1, PASSWORD1, KEY1);
        assertArrayEquals(KEY1, cache.get(PASSWORD1));
    }
    
    @Test
    public void testPutForPrivateKeyShared() {
        cache.putForPrivateKey(ALIAS1, PASSWORD1, KEY1);
        cache.putForPrivateKey(ALIAS2, PASSWORD1, KEY1);
        cache.putForPrivateKey(ALIAS1, PASSWORD2, KEY2);
        assertArrayEquals(KEY1, cache.get(PASSWORD1));
    }
    
    @Test
    public void testPutForPrivateKeySame() {
        cache.putForPrivateKey(ALIAS1, PASSWORD1, KEY1);
        cache.putForPrivateKey(ALIAS1, PASSWORD1, KEY1);
        assertArrayEquals(KEY1, cache.get(PASSWORD1));
    }
    
    @Test
    public void testPutForPrivateKeyDifferent() {
        cache.putForPrivateKey(ALIAS1, PASSWORD1, KEY1);
        cache.putForPrivateKey(ALIAS1, PASSWORD2, KEY2);
        assertArrayEquals(KEY2, cache.get(PASSWORD2));
        assertNull(cache.get(PASSWORD1));
    }

    @Test
    public void testPutForSecretKeyNew() {
        cache.putForSecretKey(ALIAS1, PASSWORD1, KEY1);
        assertArrayEquals(KEY1, cache.get(PASSWORD1));
    }
    
    @Test
    public void testPutForSecretKeyShared() {
        cache.putForSecretKey(ALIAS2, PASSWORD1, KEY1);
        cache.putForSecretKey(ALIAS1, PASSWORD1, KEY1);
        cache.putForSecretKey(ALIAS2, PASSWORD2, KEY2);
        assertArrayEquals(KEY1, cache.get(PASSWORD1));
    }
    
    @Test
    public void testPutForSecretKeyDifferent() {
        cache.putForSecretKey(ALIAS1, PASSWORD1, KEY1);
        cache.putForSecretKey(ALIAS1, PASSWORD2, KEY2);
        assertArrayEquals(KEY2, cache.get(PASSWORD2));
        assertNull(cache.get(PASSWORD1));
    }
    
    @Test
    public void testPutForSecretKeySame() {
        cache.putForSecretKey(ALIAS1, PASSWORD1, KEY1);
        cache.putForSecretKey(ALIAS1, PASSWORD1, KEY1);
        assertArrayEquals(KEY1, cache.get(PASSWORD1));
    }

    @Test
    public void testRemoveForElGamalPrivateKeyMissing() {
        cache.removeForElGamalPrivateKey(ALIAS1);
    }
    
    @Test
    public void testRemoveForElGamalPrivateKeyExisting() {
        cache.putForElGamalPrivateKey(ALIAS1, PASSWORD1, KEY1);
        cache.removeForElGamalPrivateKey(ALIAS1);
        assertNull(cache.get(PASSWORD1));
    }
    
    @Test
    public void testRemoveForElGamalPrivateKeyShared() {
        cache.putForElGamalPrivateKey(ALIAS1, PASSWORD1, KEY1);
        cache.putForElGamalPrivateKey(ALIAS2, PASSWORD1, KEY1);
        cache.removeForElGamalPrivateKey(ALIAS1);
        assertArrayEquals(KEY1, cache.get(PASSWORD1));
    }

    @Test
    public void testRemoveForPrivateKeyMissing() {
        cache.removeForPrivateKey(ALIAS1);
    }
    
    @Test
    public void testRemoveForPrivateKeyExisting() {
        cache.putForPrivateKey(ALIAS1, PASSWORD1, KEY1);
        cache.removeForPrivateKey(ALIAS1);
        assertNull(cache.get(PASSWORD1));
    }
    
    @Test
    public void testRemoveForPrivateKeyShared() {
        cache.putForPrivateKey(ALIAS1, PASSWORD1, KEY1);
        cache.putForPrivateKey(ALIAS2, PASSWORD1, KEY1);
        cache.removeForPrivateKey(ALIAS1);
        assertArrayEquals(KEY1, cache.get(PASSWORD1));
    }

    @Test
    public void testRemoveForSecretKeyMissing() {
        cache.removeForSecretKey(ALIAS1);
    }
    
    @Test
    public void testRemoveForSecretKeyExisting() {
        cache.putForSecretKey(ALIAS1, PASSWORD1, KEY1);
        cache.removeForSecretKey(ALIAS1);
        assertNull(cache.get(PASSWORD1));
    }
    
    @Test
    public void testRemoveForSecretKeyShared() {
        cache.putForSecretKey(ALIAS1, PASSWORD1, KEY1);
        cache.putForSecretKey(ALIAS2, PASSWORD1, KEY1);
        cache.removeForSecretKey(ALIAS1);
        assertArrayEquals(KEY1, cache.get(PASSWORD1));
    }
}
