/*******************************************************************************
* Copyright (c) 2005, 2009 eXXcellent solution gmbh and others.
* 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:
* Achim Demelt - initial API and implementation
*******************************************************************************/
package org.eclipse.xpand.incremental;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import junit.framework.TestCase;
import org.eclipse.emf.mwe.core.WorkflowFacade;
import org.eclipse.emf.mwe.core.issues.Issues;
import org.eclipse.emf.mwe.core.resources.ResourceLoader;
import org.eclipse.emf.mwe.core.resources.ResourceLoaderFactory;
import org.eclipse.emf.mwe.core.resources.ResourceLoaderImpl;
public abstract class AbstractIncrementalTest extends TestCase {
private static final String CLASS_WITH_REMOVED_SUPER_TYPE_JAVA = "ClassWithRemovedSuperType.java";
private static final String CLASS_WITH_NEW_SUPER_TYPE_JAVA = "ClassWithNewSuperType.java";
private static final String CLASS_WITH_REMOVED_ATTRIBUTE_JAVA = "ClassWithRemovedAttribute.java";
private static final String CLASS_WITH_NEW_ATTRIBUTE_JAVA = "ClassWithNewAttribute.java";
private static final String TEMP_PATH = "temp/";
private static final String MODEL_ECORE = "model.ecore";
private static final String UNCHANGED_CLASS_JAVA = "UnchangedClass.java";
private static final String THIRD_CLASS_JAVA = "ThirdClass.java";
private static final String FOURTH_CLASS_JAVA = "FourthClass.java";
private static final String SECOND_CLASS_JAVA = "SecondClass.java";
private static final String FIRST_CLASS_JAVA = "FirstClass.java";
private static final String DIFF_EMFDIFF = "diff.emfdiff";
private static final String TRACE_TRACE = "trace.trace";
private static final String OLDMODEL_ECORE = "oldmodel.ecore";
private ResourceLoader oldResourceLoader;
@Override
public void setUp() {
oldResourceLoader = ResourceLoaderFactory.getCurrentThreadResourceLoader();
ResourceLoaderFactory.setCurrentThreadResourceLoader(new ResourceLoaderImpl(getClass().getClassLoader()));
// prepare temp dir
File tempDir = new File(TEMP_PATH);
if (!tempDir.exists() || tempDir.isFile()) {
tempDir.delete();
tempDir.mkdir();
}
// clean results of previous tests
deleteFile(MODEL_ECORE);
deleteFile(OLDMODEL_ECORE);
deleteFile(TRACE_TRACE);
deleteFile(DIFF_EMFDIFF);
deleteFile(FIRST_CLASS_JAVA);
deleteFile(SECOND_CLASS_JAVA);
deleteFile(THIRD_CLASS_JAVA);
deleteFile(FOURTH_CLASS_JAVA);
deleteFile(UNCHANGED_CLASS_JAVA);
deleteFile(CLASS_WITH_NEW_ATTRIBUTE_JAVA);
deleteFile(CLASS_WITH_REMOVED_ATTRIBUTE_JAVA);
deleteFile(CLASS_WITH_NEW_SUPER_TYPE_JAVA);
deleteFile(CLASS_WITH_REMOVED_SUPER_TYPE_JAVA);
}
@Override
protected void tearDown() throws Exception {
ResourceLoaderFactory.setCurrentThreadResourceLoader(oldResourceLoader);
super.tearDown();
}
public void testInitialGeneration() throws Exception {
// old.ecore is to be our initial model
copyFile("/resources/model/old.ecore", new File(TEMP_PATH + MODEL_ECORE));
// now simply run workflow. remember date to check timestamps
WorkflowFacade workflow = new WorkflowFacade(getWorkflowFileName());
long timestamp = System.currentTimeMillis();
// have to wait a second because the filesystem may round down file modification timestamps
Thread.sleep(1000);
Issues issues = workflow.run();
// we must have no errors, but a couple of warnings because
// we neither have an old model nor a trace model
assertFalse("Found errors in workflow: " + issues, issues.hasErrors());
assertTrue(issues.hasWarnings());
// we must have created almost all files
assertFile(FIRST_CLASS_JAVA, true, timestamp);
assertFile(SECOND_CLASS_JAVA, true, timestamp);
assertFile(THIRD_CLASS_JAVA, true, timestamp);
assertFile(UNCHANGED_CLASS_JAVA, true, timestamp);
assertFile(CLASS_WITH_NEW_ATTRIBUTE_JAVA, true, timestamp);
assertFile(CLASS_WITH_NEW_SUPER_TYPE_JAVA, true, timestamp);
assertFile(CLASS_WITH_REMOVED_ATTRIBUTE_JAVA, true, timestamp);
assertFile(CLASS_WITH_REMOVED_SUPER_TYPE_JAVA, true, timestamp);
assertFile(TRACE_TRACE, true, timestamp);
assertFile(OLDMODEL_ECORE, true, timestamp);
// except for model.ecore. this must remain unchanged
assertFile(MODEL_ECORE, false, timestamp);
// and except for the diff snapshot and the fourth class
File diffFile = new File(TEMP_PATH + DIFF_EMFDIFF);
assertFalse(diffFile.exists());
File fourthClassFile = new File(TEMP_PATH + FOURTH_CLASS_JAVA);
assertFalse(fourthClassFile.exists());
}
public void testIncrementalGeneration() throws Exception {
// first perform initial generation
testInitialGeneration();
// now new.ecore is to become our updated model
copyFile("/resources/model/new.ecore", new File(TEMP_PATH + MODEL_ECORE));
// now simply run workflow. remember date to check timestamps
WorkflowFacade workflow = new WorkflowFacade(getWorkflowFileName());
long timestamp = System.currentTimeMillis();
// have to wait a second because the filesystem may round down file modification timestamps
Thread.sleep(1000);
Issues issues = workflow.run();
// we must have no errors and also no warnings this time
assertFalse("Found errors in workflow: " + issues, issues.hasErrors());
assertFalse("Found warnings in workflow: " + issues, issues.hasWarnings());
// now we must have regenerated these files
assertFile(FIRST_CLASS_JAVA, true, timestamp);
assertFile(SECOND_CLASS_JAVA, true, timestamp);
assertFile(CLASS_WITH_NEW_ATTRIBUTE_JAVA, true, timestamp);
assertFile(CLASS_WITH_NEW_SUPER_TYPE_JAVA, true, timestamp);
assertFile(CLASS_WITH_REMOVED_ATTRIBUTE_JAVA, true, timestamp);
assertFile(CLASS_WITH_REMOVED_SUPER_TYPE_JAVA, true, timestamp);
// and this one is new
assertFile(FOURTH_CLASS_JAVA, true, timestamp);
// but this must remain unchanged
assertFile(UNCHANGED_CLASS_JAVA, false, timestamp);
// this must have been deleted
File thirdClassFile = new File(TEMP_PATH + THIRD_CLASS_JAVA);
assertFalse(thirdClassFile.exists());
// finally, trace, diff snapshot and oldmodel must be updated as well
assertFile(TRACE_TRACE, true, timestamp);
assertFile(OLDMODEL_ECORE, true, timestamp);
if (writesDiff()) {
assertFile(DIFF_EMFDIFF, true, timestamp);
}
// as usual: model.ecore. this must remain unchanged
assertFile(MODEL_ECORE, false, timestamp);
}
private void assertFile(String name, boolean newerThan, long timestamp) {
File f = new File(TEMP_PATH + name);
assertTrue("File " + name + " does not exist", f.exists());
if (newerThan) {
// important to use "<=" instead of "<". I had cases when not a single millisecond(!)
// has passed between taking the timestamp and the file being written to disk...
assertTrue("File " + name + " is written at " + f.lastModified() + ", but should be after " + timestamp,
timestamp <= f.lastModified());
}
else {
assertTrue("File " + name + " is written at " + f.lastModified() + ", but should be before " + timestamp,
timestamp > f.lastModified());
}
}
private void deleteFile(String name) {
File f = new File(TEMP_PATH + name);
if (f.exists()) {
f.delete();
assertFalse(f.exists());
}
}
public void copyFile(String classpathResourceURI, File destFile) throws IOException {
if (!destFile.exists()) {
destFile.createNewFile();
}
InputStream sourceStream = getClass().getClassLoader().getResourceAsStream(classpathResourceURI);
OutputStream destination = null;
try {
destination = new BufferedOutputStream(new FileOutputStream(destFile));
byte[] buffer = new byte[1024];
int readBytes = -1;
while ((readBytes = sourceStream.read(buffer)) != -1) {
destination.write(buffer, 0, readBytes);
}
}
finally {
if (sourceStream != null) {
sourceStream.close();
}
if (destination != null) {
destination.close();
}
}
}
public abstract String getWorkflowFileName();
public abstract boolean writesDiff();
}