/**
 * OWASP Enterprise Security API (ESAPI)
 * 
 * This file is part of the Open Web Application Security Project (OWASP)
 * Enterprise Security API (ESAPI) project. For details, please see
 * <a href="http://www.owasp.org/index.php/ESAPI">http://www.owasp.org/index.php/ESAPI</a>.
 *
 * Copyright (c) 2007 - The OWASP Foundation
 * 
 * The ESAPI is published by OWASP under the BSD license. You should read and accept the
 * LICENSE before you use, modify, and/or redistribute this software.
 * 
 * @author Jeff Williams <a href="http://www.aspectsecurity.com">Aspect Security</a>
 * @created 2007
 */
package org.owasp.esapi.reference.crypto;

import static org.junit.Assert.*;

import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.util.Properties;

import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.junit.rules.TestName;


/**
 * The Class EncryptedPropertiesTest.
 * 
 * @author August Detlefsen (augustd at codemagi dot com)
 *         <a href="http://www.codemagi.com">CodeMagi, Inc.</a>
 * @since October 8, 2010
 */
public class EncryptedPropertiesUtilsTest {

	private static final String KEY1	= "quick";
	private static final String VALUE1	= "brown fox";
	private static final String KEY2	= "jumps";
	private static final String VALUE2	= "lazy dog";
	private static final String KEY3	= "joe bob";
	private static final String VALUE3	= "jim bob";
	private static final String KEY4	= "sally sue";
	private static final String VALUE4	= "betty mae";

	
	/** Rule to acquire the running test's information at runtime.*/
	@Rule
	public TestName testName = new TestName();

	/** File management component for IO targets during test executions.*/
	@Rule
	public TemporaryFolder tempFolder = new TemporaryFolder();
	
	/** Counter used to track the number of files created for a single test to assist with creating unique file references.*/
	private int fileIndex = 0;
	
	/**
	 * Creates a new properties file reference for the active test which will be cleaned up upon test completion.
	 * @return File New unique file reference for the active test.
	 * @throws IOException If a new file could not be generated.
	 */
	private final File getTempPropertiesFile() throws IOException {
	    return tempFolder.newFile(String.format("%s_%2d.properties", testName.getMethodName(), fileIndex++));
	}
	/**
	 * Test of creating and storing a new EncryptedProperties from scratch,
	 * as if calling:
	 * <code>
	 *     EncryptedPropertiesUtils --out encrypted.properties
	 * </code>
	 *
	 * @throws Exception Any exception that occurs
	 */
	@Test public void testCreateNew() throws Exception {
	    File encryptedFile = getTempPropertiesFile();
	    
		//create a new properties with no input
		Properties props = EncryptedPropertiesUtils.loadProperties(null, null);
		
		//add some properties
		Object prop1 = EncryptedPropertiesUtils.addProperty(props, KEY1, VALUE1);
		assertNull("Expected null but returned: " + prop1, prop1);

		Object prop2 = EncryptedPropertiesUtils.addProperty(props, KEY2, VALUE2);
		assertNull("Expected null but returned: " + prop2, prop2);

		//store the file 
		EncryptedPropertiesUtils.storeProperties(encryptedFile.getAbsolutePath(), props, "Encrypted Properties File generated by EncryptedPropertiesUtilsTest");

		//try reading in the resulting file
		ReferenceEncryptedProperties loadedProps = new ReferenceEncryptedProperties();
		loadedProps.load(new FileReader(encryptedFile.getAbsolutePath()));
		
		assertEquals(VALUE1, loadedProps.getProperty(KEY1));
		assertEquals(VALUE2, loadedProps.getProperty(KEY2));
	}

	/**
	 * Test of loading a plaintext file and storing it as an encrypted properties file,
	 * as if calling:
	 * <code>
	 *     EncryptedPropertiesUtils --in plaintext.properties --out encrypted.properties --in-encrypted false
	 * </code>
	 *
	 * @throws Exception Any exception that occurs
	 */
	@Test public void testLoadPlaintextAndEncrypt() throws Exception {
	    File encryptedFile = getTempPropertiesFile();
	    File plainTextFile = getTempPropertiesFile();
	    
	  //write an initial plaintext properties file
        Properties props = new Properties();
        props.setProperty(KEY3, VALUE3);
        props.setProperty(KEY4, VALUE4);

        props.store(new FileOutputStream(plainTextFile.getAbsolutePath()), "Plaintext test file created by EncryptedPropertiesUtilsTest");
	    
		//load the plaintext properties file
		props = EncryptedPropertiesUtils.loadProperties(plainTextFile.getAbsolutePath(), false);

		//test some properties using getProperty
		assertEquals(VALUE3, props.getProperty(KEY3));
		assertEquals(VALUE4, props.getProperty(KEY4));

		//store the file
		EncryptedPropertiesUtils.storeProperties(encryptedFile.getAbsolutePath(), props, "Encrypted Properties File generated by EncryptedPropertiesUtilsTest");

		//try reading in the resulting file
		ReferenceEncryptedProperties loadedProps = new ReferenceEncryptedProperties();
		loadedProps.load(new FileReader(encryptedFile.getAbsolutePath()));

		assertEquals(VALUE3, loadedProps.getProperty(KEY3));
		assertEquals(VALUE4, loadedProps.getProperty(KEY4));
	}

	/**
	 * Test of loading an encrypted file, adding new properties and storing it as an encrypted properties file,
	 * as if calling:
	 * <code>
	 *     EncryptedPropertiesUtils --in encrypted.properties --out encrypted.2.properties
	 * </code>
	 *
	 * @throws Exception Any exception that occurs
	 */
	@Test public void testLoadEncryptedAndAdd() throws Exception {
	    File encryptedFile = getTempPropertiesFile();
	    File encryptedFile2 = getTempPropertiesFile();
		//load the plaintext properties file
		Properties props = EncryptedPropertiesUtils.loadProperties(encryptedFile.getAbsolutePath(), true);

		//add some new properties
		EncryptedPropertiesUtils.addProperty(props, KEY1, VALUE1);
		EncryptedPropertiesUtils.addProperty(props, KEY2, VALUE2);

		//test the newly added properties
		assertEquals(VALUE1, props.getProperty(KEY1));
		assertEquals(VALUE2, props.getProperty(KEY2));

		//store the file
		EncryptedPropertiesUtils.storeProperties(encryptedFile2.getAbsolutePath(), props, "Encrypted Properties File generated by EncryptedPropertiesUtilsTest");

		//try reading in the resulting file
		ReferenceEncryptedProperties loadedProps = new ReferenceEncryptedProperties();
		loadedProps.load(new FileReader(encryptedFile2.getAbsolutePath()));

		//test the values read in
		assertEquals(VALUE1, loadedProps.getProperty(KEY1));
		assertEquals(VALUE2, loadedProps.getProperty(KEY2));
	}

}
