/******************************************************************************* * Copyright (c) 2012-2013 EclipseSource Muenchen 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: * JulianSommerfeldt ******************************************************************************/ package org.eclipse.emf.emfstore.fuzzy.emf.internal.diff; import java.io.IOException; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import org.eclipse.emf.common.util.EList; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.emf.emfstore.internal.fuzzy.emf.FuzzyUtil; import org.eclipse.emf.emfstore.internal.fuzzy.emf.config.ConfigFactory; import org.eclipse.emf.emfstore.internal.fuzzy.emf.config.DiffReport; import org.eclipse.emf.emfstore.internal.fuzzy.emf.config.TestConfig; import org.eclipse.emf.emfstore.internal.fuzzy.emf.config.TestDiff; import org.eclipse.emf.emfstore.internal.fuzzy.emf.config.TestResult; import org.eclipse.emf.emfstore.internal.fuzzy.emf.config.TestRun; /** * Generates {@link TestDiff}s out of {@link TestRun}. * * @author Julian Sommerfeldt * */ public class DiffGenerator { private final DiffReport diffReport; private final Resource diffResource; /** * A {@link DiffGenerator} with the standard diff file {@link FuzzyUtil#DIFF_FILE}. */ public DiffGenerator() { this(FuzzyUtil.DIFF_FILE); } /** * A {@link DiffGenerator} with using the diffPath. * * @param diffPath * The path to the Diff file. */ public DiffGenerator(String diffPath) { this(FuzzyUtil.createResource(diffPath)); } /** * A {@link DiffGenerator} using the diffResource. * * @param diffResource * The resource to use for the diff. */ public DiffGenerator(Resource diffResource) { this.diffResource = diffResource; if (FuzzyUtil.resourceExists(diffResource)) { try { diffResource.load(null); } catch (final IOException e) { throw new RuntimeException(Messages.DiffGenerator_Could_Not_Load_Resource + diffResource.getURI(), e); } } diffReport = getDiffReport(diffResource); } /** * Create a diff from two {@link TestRun}s. * * @param firstRun * The first {@link TestRun}. * @param secondRun * The second {@link TestRun}. * @throws IOException * If there is a saving/loading failure with resources. */ public void createDiff(TestRun firstRun, TestRun secondRun) throws IOException { TestConfig config = firstRun.getConfig(); // check if it already contains the config boolean containsConfig = false; // create map containing existing diffs // identified through testname + seedcount (e.g. test1) final Map<String, TestDiff> existingDiffs = new HashMap<String, TestDiff>(); final List<TestDiff> diffs = diffReport.getDiffs(); for (final TestDiff diff : diffs) { // add existing diffs final TestResult result = FuzzyUtil.getValidTestResult(diff); existingDiffs.put(getResultIdentifier(result), diff); // check for configs if (!containsConfig && diff.getConfig().getId().equals(config.getId())) { containsConfig = true; config = diff.getConfig(); } } // if the resource does not contain the config already add it if (!containsConfig) { diffResource.getContents().add(config); } // create diffs for the two testruns checkForDiffs(firstRun.getResults(), secondRun.getResults(), config, existingDiffs); checkForDiffs(secondRun.getResults(), firstRun.getResults(), config, existingDiffs); diffResource.getContents().add(diffReport); diffResource.save(null); } private void checkForDiffs(List<TestResult> firstResults, List<TestResult> secondResults, TestConfig config, Map<String, TestDiff> existingDiffs) { final EList<TestDiff> diffs = diffReport.getDiffs(); for (final TestResult result : new ArrayList<TestResult>(firstResults)) { final TestResult corrResult = getCorrespondingTestResult(result, secondResults); final TestDiff diff = getChangedTestDiff(result, corrResult); if (diff != null) { diff.setConfig(config); // remove diff if it already contains it diffs.remove(existingDiffs.get(getResultIdentifier(result))); diffs.add(diff); } } } private static String getResultIdentifier(TestResult result) { return result.getTestName() + result.getSeedCount(); } private static TestDiff getChangedTestDiff(TestResult fRes, TestResult sRes) { boolean changed = false; // check if a state switch occured // TODO test state switches if (fRes == null || sRes == null) { changed = true; } else if (changed(fRes.getFailure(), sRes.getFailure())) { changed = true; } else if (changed(fRes.getError(), sRes.getError())) { changed = true; } else if (fRes.getFailure() != null && sRes.getError() != null) { changed = true; } else if (fRes.getError() != null && sRes.getFailure() != null) { changed = true; } // if it changed, create a new TestDiff if (changed) { return createTestDiff(fRes, sRes); } return null; } private static boolean changed(Object o1, Object o2) { if (o1 == null && o2 != null) { return true; } if (o1 != null && o2 == null) { return true; } return false; } private static TestDiff createTestDiff(TestResult fRes, TestResult sRes) { final TestDiff diff = ConfigFactory.eINSTANCE.createTestDiff(); diff.setLastUpdate(new Date(System.currentTimeMillis())); diff.setOldResult(fRes); diff.setNewResult(sRes); return diff; } private static TestResult getCorrespondingTestResult(TestResult result, List<TestResult> results) { for (final TestResult res : results) { if (res.getSeedCount() == result.getSeedCount() && res.getTestName().equals(result.getTestName())) { return res; } } return null; } private static DiffReport getDiffReport(Resource resource) { for (final EObject obj : resource.getContents()) { if (obj instanceof DiffReport) { return (DiffReport) obj; } } return ConfigFactory.eINSTANCE.createDiffReport(); } }