/*******************************************************************************
 * Copyright (c) 2012 VMware, Inc.
 * 
 * All rights reserved. 
 * This program and the accompanying materials are made available 
 * under the terms of the Eclipse Public License v1.0 
 * which accompanies this distribution and is available at 
 * http://www.eclipse.org/legal/epl-v10.html 
 *  
 * Contributors:
 *  Lyor Goldstein
 *******************************************************************************/

package org.aspectj.weaver.tools.cache;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Map;
import java.util.TreeMap;

import org.aspectj.weaver.tools.cache.AbstractIndexedFileCacheBacking.IndexEntry;

/**
 * @author Lyor Goldstein
 */
public class FlatFileCacheBackingTest extends AsynchronousFileCacheBackingTestSupport {
	public FlatFileCacheBackingTest() {
		super();
	}

	@Override
	protected FlatFileCacheBacking createFileBacking(File dir) {
		return new FlatFileCacheBacking(dir);
	}

	public void testReadIndex() throws IOException {
		IndexEntry[] entries = { createIgnoredEntry("ignored"), createIndexEntry("weaved", false, false, bytes, bytes),
				createIndexEntry("generated", true, false, bytes, bytes) };
		File indexFile = getIndexFile();
		writeIndex(indexFile, entries);
		Map<String, File> dataFiles = createDataFiles(entries);

		File cacheDir = getCacheDir();
		AsynchronousFileCacheBacking cache = createFileBacking(cacheDir);
		Map<String, IndexEntry> indexMap = cache.getIndexMap();
		assertEquals("Mismatched index size", entries.length, indexMap.size());

		Map<String, byte[]> bytesMap = cache.getBytesMap();
		assertEquals("Mismatched bytes size", dataFiles.size() /* the ignored one has no file */, bytesMap.size());

		for (IndexEntry entry : entries) {
			String key = entry.key;
			assertNotNull("Missing entry for key=" + key, indexMap.get(key));

			if (entry.ignored) {
				assertNull("Unexpected bytes for ignored key=" + key, bytesMap.get(key));
			} else {
				assertArrayEquals("Mismatched contents for key=" + key, bytes, bytesMap.get(key));
			}
		}
	}

	public void testIgnoredBadCrcDataFiles() throws Exception {
		IndexEntry[] entries = { createIndexEntry("weaved-goodData", false, false, bytes, bytes),
				createIndexEntry("badData-weaved", false, false, bytes, bytes),
				createIndexEntry("generated-goodData", true, false, bytes, bytes),
				createIndexEntry("badData-generated", true, false, bytes, bytes) };
		File indexFile = getIndexFile();
		writeIndex(indexFile, entries);

		Map<String, File> dataFiles = createDataFiles(entries);
		long newCrc = generateNewBytes();
		assertTrue("Bad new CRC", newCrc != (-1L));

		Map<String, File> badFiles = new TreeMap<String, File>();
		for (IndexEntry entry : entries) {
			String key = entry.key;
			if (key.startsWith("badData")) {
				File file = dataFiles.get(key);
				OutputStream out = new FileOutputStream(file);
				try {
					out.write(bytes);
				} finally {
					out.close();
				}
				dataFiles.remove(key);
				badFiles.put(key, file);
			}
		}

		File cacheDir = getCacheDir();
		FlatFileCacheBacking cache = createFileBacking(cacheDir);
		Map<String, IndexEntry> indexMap = cache.getIndexMap();
		assertEquals("Mismatched index size", dataFiles.size(), indexMap.size());

		Map<String, byte[]> bytesMap = cache.getBytesMap();
		assertEquals("Mismatched bytes size", dataFiles.size(), bytesMap.size());

		for (Map.Entry<String, File> badEntry : badFiles.entrySet()) {
			String key = badEntry.getKey();
			assertFalse("Unexpectedly indexed: " + key, indexMap.containsKey(key));
			assertFalse("Unexpectedly loaded: " + key, bytesMap.containsKey(key));

			File file = badEntry.getValue();
			assertFalse("Unexpectedly still readable: " + key, file.canRead());
		}
	}

	public void testSkipMissingDataFileOnReadIndex() throws IOException {
		IndexEntry[] entries = { createIndexEntry("weaved-noData", false, false, null, null),
				createIndexEntry("withData-weaved", false, false, bytes, bytes),
				createIndexEntry("generated-noData", true, false, null, null),
				createIndexEntry("withData-generated", true, false, bytes, bytes) };
		File indexFile = getIndexFile();
		writeIndex(indexFile, entries);

		Map<String, File> dataFiles = new TreeMap<String, File>();
		for (IndexEntry entry : entries) {
			String key = entry.key;
			if (key.startsWith("withData")) {
				dataFiles.put(key, createDataFile(entry, bytes));
			}
		}

		File cacheDir = getCacheDir();
		FlatFileCacheBacking cache = createFileBacking(cacheDir);
		Map<String, IndexEntry> indexMap = cache.getIndexMap();
		assertEquals("Mismatched index size", dataFiles.size(), indexMap.size());

		Map<String, byte[]> bytesMap = cache.getBytesMap();
		assertEquals("Mismatched bytes size", dataFiles.size(), bytesMap.size());

		for (IndexEntry entry : entries) {
			String key = entry.key;
			if (key.startsWith("withData")) {
				assertTrue("Not indexed: " + key, indexMap.containsKey(key));
				assertTrue("Not loaded: " + key, bytesMap.containsKey(key));
			} else {
				assertFalse("Unexpectedly indexed: " + key, indexMap.containsKey(key));
				assertFalse("Unexpectedly loaded: " + key, bytesMap.containsKey(key));
			}
		}
	}

}
