/** * Copyright (C) 2010 STMicroelectronics * * This file is part of "Mind Compiler" is free software: you can redistribute * it and/or modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * * Contact: mind@ow2.org * * Authors: Matthieu Leclercq * Contributors: */ package org.ow2.mind; import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertTrue; import java.io.File; import java.io.FileReader; import java.io.LineNumberReader; import java.io.PrintWriter; import java.net.URL; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.regex.Pattern; import org.objectweb.fractal.adl.ADLException; import org.ow2.mind.io.BasicOutputFileLocator; public abstract class AbstractIncrementalTest extends AbstractFunctionalTest { protected static final String SRC_ROOT = "incremental"; protected static File buildDir = new File( "target/build/incremental-test"); protected static void assertUnchanged(final String path, final Map<String, Long> timestamps1, final Map<String, Long> timestamps2) { final Long time1 = timestamps1.get(path); assertNotNull(time1, "missing timestamp of \"" + path + "\" in first map"); final Long time2 = timestamps2.get(path); assertNotNull(time2, "missing timestamp of \"" + path + "\" in second map"); assertTrue(time1.equals(time2), "Timestamp of \"" + path + "\" has changed"); timestamps1.remove(path); timestamps2.remove(path); } protected void pause() throws InterruptedException { // wait a second and half to be sure that timestamps are actually modified synchronized (this) { final long begin = System.currentTimeMillis(); long t = System.currentTimeMillis(); while (t - begin < 1500) { this.wait(begin - t + 1500); t = System.currentTimeMillis(); } } } protected Map<String, Long> recompileDefinition(final String adlName) throws ADLException, InterruptedException { initContext(false); runner.compileDefinition(adlName); return getBuildTimestamps(); } protected Map<String, Long> recompile(final String adlName) throws ADLException, InterruptedException { return recompile(adlName, null); } protected Map<String, Long> recompile(final String adlName, final String execName) throws ADLException, InterruptedException { initContext(false); runner.compile(adlName, execName); return getBuildTimestamps(); } protected static void assertUnchangedAll(final String pattern, final Map<String, Long> timestamps1, final Map<String, Long> timestamps2) { final Pattern p = Pattern.compile(pattern); boolean foundMatches = false; for (final Map.Entry<String, Long> t1 : new HashSet<Map.Entry<String, Long>>( timestamps1.entrySet())) { if (p.matcher(t1.getKey()).matches()) { final Long t2 = timestamps2.get(t1.getKey()); if (t2 != null) { foundMatches = true; assertUnchanged(t1.getKey(), timestamps1, timestamps2); } } } assertTrue(foundMatches, "No match found for pattern \"" + pattern + "\""); } protected static void assertChanged(final String path, final Map<String, Long> timestamps1, final Map<String, Long> timestamps2) { final Long time1 = timestamps1.get(path); assertNotNull(time1, "missing timestamp of \"" + path + "\" in first map"); final Long time2 = timestamps2.get(path); assertNotNull(time2, "missing timestamp of \"" + path + "\" in second map"); assertTrue(time1 < time2, "Timestamp of \"" + path + "\" is unchanged"); timestamps1.remove(path); timestamps2.remove(path); } protected static void assertChangedAll(final String pattern, final Map<String, Long> timestamps1, final Map<String, Long> timestamps2) { final Pattern p = Pattern.compile(pattern); boolean foundMatches = false; for (final Map.Entry<String, Long> t1 : new HashSet<Map.Entry<String, Long>>( timestamps1.entrySet())) { if (p.matcher(t1.getKey()).matches()) { final Long t2 = timestamps2.get(t1.getKey()); if (t2 != null) { foundMatches = true; assertChanged(t1.getKey(), timestamps1, timestamps2); } } } assertTrue(foundMatches, "No match found for pattern \"" + pattern + "\""); } protected void touchFile(final String path) throws Exception { final URL resource = getClass().getClassLoader().getResource( SRC_ROOT + "/" + path); assertNotNull(resource); final File file = new File(resource.toURI()); final long t1 = file.lastModified(); file.setLastModified(System.currentTimeMillis()); assertTrue(file.lastModified() > t1, "Touch of file \"" + path + "\" failed."); } protected void copyFile(final String path, final String newPath, final String[]... replacements) throws Exception { final URL resource = getClass().getClassLoader().getResource( SRC_ROOT + "/" + path); assertNotNull(resource); final File srcFile = new File(resource.toURI()); final File newFile = new File(srcFile.getPath().replace( path.replace('/', File.separatorChar), newPath)); LineNumberReader reader = null; PrintWriter writer = null; try { reader = new LineNumberReader(new FileReader(srcFile)); writer = new PrintWriter(newFile); String line = reader.readLine(); while (line != null) { if (replacements != null) { for (final String[] replacement : replacements) { assert replacement.length == 2; line = line.replaceAll(replacement[0], replacement[1]); } } writer.println(line); line = reader.readLine(); } } finally { if (reader != null) reader.close(); if (writer != null) writer.close(); } } protected void initContext(final boolean force) throws ADLException { // delete previous temporary directory. if (runner.context != null) { final File tempDir = (File) runner.context .get(BasicOutputFileLocator.TEMPORARY_OUTPUT_DIR_CONTEXT_KEY); if (tempDir != null) { deleteDir(tempDir); } } runner.initContext(); initPath(); if (!buildDir.exists()) { buildDir.mkdirs(); } runner.context.put(BasicOutputFileLocator.OUTPUT_DIR_CONTEXT_KEY, buildDir); ForceRegenContextHelper.setForceRegen(runner.context, force); ForceRegenContextHelper.setKeepTemp(runner.context, false); ForceRegenContextHelper.setNoBinaryAST(runner.context, false); } protected abstract void initPath(); protected void cleanBuildDir() { if (buildDir.exists()) deleteDir(buildDir); } protected HashMap<String, Long> getBuildTimestamps() { final HashMap<String, Long> timestamps = new HashMap<String, Long>(); for (final File subFile : buildDir.listFiles()) { getTimestamps(subFile, "", timestamps); } return timestamps; } protected void deleteDir(final File f) { if (f.isDirectory()) { for (final File subFile : f.listFiles()) deleteDir(subFile); } // f.delete(); assertTrue(f.delete(), "Can't delete \"" + f + "\"."); } protected void getTimestamps(final File f, final String path, final Map<String, Long> timestamps) { final String name = path + f.getName(); if (f.isDirectory()) { final String subPath = name + "/"; for (final File subFile : f.listFiles()) { getTimestamps(subFile, subPath, timestamps); } } else { timestamps.put(name, f.lastModified()); } } }