From af87e71464bda3b867cea551d64f3015a8e5c50c Mon Sep 17 00:00:00 2001 From: AlpTorac Date: Sun, 27 Jul 2025 16:46:10 +0200 Subject: [PATCH 01/72] Create fitests plug-in Removed project-specific settings for fitests --- .../cipm.consistency.fitests/.classpath | 11 +++++++ .../cipm.consistency.fitests/.project | 28 +++++++++++++++++ .../META-INF/MANIFEST.MF | 30 +++++++++++++++++++ .../cipm.consistency.fitests/build.properties | 4 +++ 4 files changed, 73 insertions(+) create mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests/.classpath create mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests/.project create mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests/META-INF/MANIFEST.MF create mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests/build.properties diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/.classpath b/commit-based-cipm/fi-tests/cipm.consistency.fitests/.classpath new file mode 100644 index 0000000000..f0d0c735ff --- /dev/null +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/.classpath @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/.project b/commit-based-cipm/fi-tests/cipm.consistency.fitests/.project new file mode 100644 index 0000000000..5cc3244b6e --- /dev/null +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/.project @@ -0,0 +1,28 @@ + + + cipm.consistency.fitests + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/META-INF/MANIFEST.MF b/commit-based-cipm/fi-tests/cipm.consistency.fitests/META-INF/MANIFEST.MF new file mode 100644 index 0000000000..9e75e818f1 --- /dev/null +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/META-INF/MANIFEST.MF @@ -0,0 +1,30 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: cipm.consistency.fitests +Bundle-SymbolicName: cipm.consistency.fitests +Bundle-Version: 1.0.0.qualifier +Automatic-Module-Name: cipm.consistency.fitests +Bundle-RequiredExecutionEnvironment: JavaSE-11 +Require-Bundle: junit-jupiter-api, + junit-jupiter-engine, + junit-jupiter-params, + org.eclipse.emf.common, + org.eclipse.emf.ecore, + org.eclipse.emf.compare, + org.eclipse.emf.ecore.xmi, + org.splevo.diffing, + org.splevo.jamopp.diffing, + org.apache.log4j, + org.emftext.language.java, + cipm.consistency.commitintegration.diff.util, + jamopp.resolution, + jamopp.parser, + jamopp.parser.jdt.singlefile, + jamopp.resource, + org.apache.commons.lang, + com.google.gson +Export-Package: cipm.consistency.fitests.similarity, + cipm.consistency.fitests.similarity.eobject, + cipm.consistency.fitests.similarity.jamopp, + cipm.consistency.fitests.similarity.jamopp.parser + diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/build.properties b/commit-based-cipm/fi-tests/cipm.consistency.fitests/build.properties new file mode 100644 index 0000000000..34d2e4d2da --- /dev/null +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/build.properties @@ -0,0 +1,4 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + . From 486fe38a3af115c52434ad81f007595ddbd4b771 Mon Sep 17 00:00:00 2001 From: AlpTorac Date: Sun, 27 Jul 2025 16:42:37 +0200 Subject: [PATCH 02/72] Exclude parser test resources --- .gitignore | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 5224dec45a..1a4245103a 100644 --- a/.gitignore +++ b/.gitignore @@ -108,4 +108,9 @@ tmp/ .gradletasknamecache # polygot -*.polyglot.META-INF \ No newline at end of file +*.polyglot.META-INF + +# Parser tests under fitests +**/repo-clones +**/testmodel-cache +**/results-cache \ No newline at end of file From 1704802a53dcf09de8cbe79fa3f3645612671d7a Mon Sep 17 00:00:00 2001 From: AlpTorac Date: Sun, 27 Jul 2025 16:51:31 +0200 Subject: [PATCH 03/72] Add interface for containing SimilarityChecker --- .../ISimilarityCheckerContainer.java | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/ISimilarityCheckerContainer.java diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/ISimilarityCheckerContainer.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/ISimilarityCheckerContainer.java new file mode 100644 index 0000000000..a9ccffab2c --- /dev/null +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/ISimilarityCheckerContainer.java @@ -0,0 +1,46 @@ +package cipm.consistency.fitests.similarity; + +import java.util.Collection; + +/** + * An interface meant to be implemented by classes that store the similarity + * checker under test, in order to spare other test classes the need to add that + * similarity checker as a dependency.
+ *
+ * This interface contains dependencies to neither similarity checker interfaces + * nor to concrete implementations, because doing so would reduce the + * re-usability.
+ *
+ * The underlying similarity checking mechanism(s) can be reset by using the + * {@link #newSimilarityChecker()} method. The similarity checking mechanism(s) + * are not automatically re-created upon calling similarity checking methods in + * this interface, because it might be desirable to keep using them. + * + * @author Alp Torac Genc + */ +public interface ISimilarityCheckerContainer { + /** + * If there are no similarity checking mechanism(s) present, this method creates + * and sets them up. Otherwise, replaces the currently stored similarity + * checking mechanism(s) with new ones.
+ *
+ * The similarity checking mechanism(s) are not automatically re-created upon + * calling similarity checking methods, because it might be desirable to keep + * using the existing similarity checking mechanism(s). + */ + public void newSimilarityChecker(); + + /** + * Delegates similarity checking to the similarity checking mechanism(s) within. + * Calls {@link #newSimilarityChecker()} beforehand, if there are no similarity + * checking mechanism(s) present. + */ + public Boolean isSimilar(Object element1, Object element2); + + /** + * Delegates similarity checking to the similarity checking mechanism(s) within. + * Calls {@link #newSimilarityChecker()} beforehand, if there are no similarity + * checking mechanism(s) present. + */ + public Boolean areSimilar(Collection elements1, Collection elements2); +} From 17fd4b80c49ec64b244c5248863495cbce2567d1 Mon Sep 17 00:00:00 2001 From: AlpTorac Date: Sun, 27 Jul 2025 16:51:51 +0200 Subject: [PATCH 04/72] Add interface for logging --- .../fitests/similarity/ILoggable.java | 81 +++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/ILoggable.java diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/ILoggable.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/ILoggable.java new file mode 100644 index 0000000000..097bd3a9ec --- /dev/null +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/ILoggable.java @@ -0,0 +1,81 @@ +package cipm.consistency.fitests.similarity; + +import org.apache.log4j.ConsoleAppender; +import org.apache.log4j.Level; +import org.apache.log4j.Logger; +import org.apache.log4j.PatternLayout; + +/** + * An interface that encapsulates logging.
+ *
+ * Make sure to call {@link ILoggable#setUpLogger()} prior to other methods. + * + * @author Alp Torac Genc + */ +public interface ILoggable { + /** + * @return The Logger with the given name + */ + private static Logger getLoggerFor(String loggerName) { + return Logger.getLogger(loggerName); + } + + /** + * Sets up all loggers that have the {@code "cipm"} prefix in their name. + */ + public static void setUpLogger() { + /* + * Order of precedence in logging levels: + * + * OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL + */ + + Logger logger = getLoggerFor("cipm"); + logger.setLevel(Level.DEBUG); + + // logger = Logger.getLogger("jamopp"); + // logger.setLevel(Level.ALL); + + // TODO Re-think how logging should work + + logger = Logger.getRootLogger(); + logger.setLevel(Level.OFF); + logger.removeAllAppenders(); + ConsoleAppender ap = new ConsoleAppender(new PatternLayout("[%d{DATE}] %-5p: %c - %m%n"), + ConsoleAppender.SYSTEM_OUT); + logger.addAppender(ap); + } + + /** + * Logs the given message at {@link Level#DEBUG} level. + */ + public default void logDebugMsg(String msg) { + var logger = getLoggerFor("cipm." + this.getClass().getSimpleName()); + logger.debug(msg); + } + + /** + * Logs the given message at {@link Level#INFO} level. + */ + public default void logInfoMsg(String msg) { + var logger = getLoggerFor("cipm." + this.getClass().getSimpleName()); + logger.info(msg); + } + + /** + * Logs the given message at {@link Level#ERROR} level. + */ + public default void logErrorMsg(String msg) { + var logger = getLoggerFor("cipm." + this.getClass().getSimpleName()); + logger.error(msg); + } + + /** + * Logs the given message at the {@link Level} that corresponds to the given + * priority. + */ + public default void logMsg(String msg, int priority) { + var logger = getLoggerFor("cipm." + this.getClass().getSimpleName()); + logger.log(Level.toLevel(priority), msg); + } +} From 089a0a1d7ffd458f8a6d2c387e4fe85904d37b40 Mon Sep 17 00:00:00 2001 From: AlpTorac Date: Sun, 27 Jul 2025 16:53:18 +0200 Subject: [PATCH 05/72] Implement abstract test class --- .../similarity/AbstractSimilarityTest.java | 125 ++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/AbstractSimilarityTest.java diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/AbstractSimilarityTest.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/AbstractSimilarityTest.java new file mode 100644 index 0000000000..e07e4bd951 --- /dev/null +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/AbstractSimilarityTest.java @@ -0,0 +1,125 @@ +package cipm.consistency.fitests.similarity; + +import java.util.Collection; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; + +/** + * An abstract class for similarity checking tests to extend.
+ *
+ * Contains methods that provide information on the next test method to be run + * and various delegation methods that spare call chains. + * + * @author Alp Torac Genc + */ +public abstract class AbstractSimilarityTest implements ILoggable { + /** + * @see {@link #getSCC()} + */ + private ISimilarityCheckerContainer scc; + + /** + * Sets up the necessary variables before tests are run.
+ *
+ * It is suggested to have a call to {@code super.setUp()} as the FIRST + * statement in overriding implementations. Doing so circumvents potential + * errors caused by the order of set up operations.
+ *
+ * {@link AbstractSimilarityTest}: Sets up the underlying + * {@link ISimilarityCheckerContainer}, which will be used for + * {@link #isSimilar(Object, Object)} and + * {@link #areSimilar(Collection, Collection)}. + * + * @param info An object that contains information about the current test to be + * run (ex: the test method instance, test class, ...) + */ + @BeforeEach + public void setUp() { + ILoggable.setUpLogger(); + + this.setSCC(this.initSCC()); + } + + /** + * Cleans up the variables set up with {@link #setUp()} and performs other + * necessary clean up operations.
+ *
+ * It is suggested to have a call to {@code super.tearDown()} as the LAST + * statement in overriding implementations. Doing so circumvents potential + * errors caused by the order of clean up operations.
+ *
+ * {@link AbstractSimilarityTest}: Cleans up the underlying + * {@link ISimilarityCheckerContainer} + */ + @AfterEach + public void tearDown() { + this.cleanUpSCC(); + } + + /** + * Provides the implementors access to the underlying + * {@link ISimilarityCheckerContainer} (SCC). + * + * @return The {@link ISimilarityCheckerContainer} (SCC) that will be used to + * store the similarity checker under test. + */ + protected ISimilarityCheckerContainer getSCC() { + return this.scc; + } + + /** + * Sets the used {@link ISimilarityCheckerContainer} to null. Used by + * {@link #tearDown()}, in order to ensure that each test method starts with a + * fresh {@link ISimilarityCheckerContainer}. + */ + protected void cleanUpSCC() { + this.scc = null; + } + + /** + * Creates the concrete {@link ISimilarityCheckerContainer} that will be used to + * store the similarity checker under test.
+ *
+ * If necessary, it can be overridden in tests to change the said similarity + * checker during set up. + */ + protected abstract ISimilarityCheckerContainer initSCC(); + + /** + * Sets the used {@link ISimilarityCheckerContainer} to the given one.
+ *
+ * If necessary, it can be called in tests to change the used similarity checker + * container to the given one. + * + * @see {@link #initSCC()} for setting the {@link ISimilarityCheckerContainer} + * during set up. + */ + protected void setSCC(ISimilarityCheckerContainer scc) { + this.scc = scc; + } + + /** + * Delegates similarity checking to the underlying + * {@link ISimilarityCheckerContainer}. + */ + public Boolean isSimilar(Object element1, Object element2) { + return this.getSCC().isSimilar(element1, element2); + } + + /** + * Delegates similarity checking to the underlying + * {@link ISimilarityCheckerContainer}. + */ + public Boolean areSimilar(Collection elements1, Collection elements2) { + return this.getSCC().areSimilar(elements1, elements2); + } + + /** + * @return The prefix of the {@link Resource} file names created from within the + * current test class. Defaults to the name of the current test class. + */ + public String getCurrentTestClassName() { + return this.getClass().getSimpleName(); + } +} \ No newline at end of file From 1df64329a27f2ade208adccf7aac03cd127c40cf Mon Sep 17 00:00:00 2001 From: AlpTorac Date: Sun, 27 Jul 2025 16:54:51 +0200 Subject: [PATCH 06/72] Add Resource-related classes --- .../eobject/AbstractResourceHelper.java | 250 ++++++++++++++++++ .../AbstractResourceParsingStrategy.java | 91 +++++++ .../eobject/ResourceTestOptions.java | 59 +++++ 3 files changed, 400 insertions(+) create mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/eobject/AbstractResourceHelper.java create mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/eobject/AbstractResourceParsingStrategy.java create mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/eobject/ResourceTestOptions.java diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/eobject/AbstractResourceHelper.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/eobject/AbstractResourceHelper.java new file mode 100644 index 0000000000..37ea30a82b --- /dev/null +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/eobject/AbstractResourceHelper.java @@ -0,0 +1,250 @@ +package cipm.consistency.fitests.similarity.eobject; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Path; +import java.util.Collection; + +import org.eclipse.emf.common.util.URI; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.emf.ecore.resource.ResourceSet; +import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl; + +import cipm.consistency.fitests.similarity.ILoggable; + +/** + * An abstract class that is meant to be implemented by classes, which + * encapsulate basic operations on {@link Resource} instances. + * + * @author Alp Torac Genc + */ +public abstract class AbstractResourceHelper implements ILoggable { + /** + * The extension of {@link Resource} files, if they are saved. + */ + private String resourceFileExtension; + + /** + * Constructs an instance with the foreseen initial resource registry entries. + * + * @see {@link #setInitialResourceRegistries()} + */ + public AbstractResourceHelper() { + this.setInitialResourceRegistries(); + } + + /** + * @return The resource registry, which will be modified by this instance. + */ + private Resource.Factory.Registry getResourceRegistry() { + return Resource.Factory.Registry.INSTANCE; + } + + /** + * Sets all resource registries foreseen for this instance. + */ + public abstract void setInitialResourceRegistries(); + + /** + * Sets the extension of {@link Resource} files, if they are saved. + */ + public void setResourceFileExtension(String resourceFileExtension) { + this.resourceFileExtension = resourceFileExtension; + } + + /** + * @return The extension of the {@link Resource} files. + */ + public String getResourceFileExtension() { + return this.resourceFileExtension; + } + + /** + * @return An empty {@link ResourceSetImpl} + */ + public ResourceSet createResourceSet() { + return new ResourceSetImpl(); + } + + /** + * Creates a {@link Resource} instance within the given resource set rSet, for + * the given EObject instances eos (can be null), with the given URI resURI. + *
+ *
+ * !!! IMPORTANT !!!
+ *
+ * Using this method will cause the logger to log an error message, if some + * of the EObject instances (from eos) that are already in a Resource instance + * are attempted to be placed into another Resource. This should be avoided, + * since doing so will REMOVE the said EObject instances from their former + * Resource and cause side effects in tests. + */ + public Resource createResource(Collection eos, ResourceSet rSet, URI resURI) { + var res = rSet.createResource(resURI); + + if (eos != null) { + for (var eo : eos) { + + /* + * Make sure to not add an EObject, which has already been added to a Resource, + * to another Resource. Doing so will detach it from its former Resource and add + * it to the second one. + */ + if (eo.eResource() != null) { + this.logErrorMsg("An EObject's resource was set and shifted during resource creation"); + } + res.getContents().add(eo); + } + } + + return res; + } + + /** + * Adds the extension to factory mapping into + * {@link Resource.Factory.Registry}.
+ *
+ * Said entry denotes that resources with the given extension are saved using + * the given factory. + * + * @see {@link #setDefaultResourceRegistry()} + */ + public void setResourceRegistry(String extension, Object factory) { + this.getResourceRegistry().getExtensionToFactoryMap().put(extension, factory); + } + + /** + * Attempts to save the given resource instance. Instead of throwing exceptions, + * returns true/false to indicate success/failure. + */ + public boolean saveResource(Resource res) { + var uri = res.getURI(); + if (uri.isFile()) { + try { + res.save(null); + return this.resourceFileExists(uri); + } catch (IOException excep) { + excep.printStackTrace(); + return this.resourceFileExists(uri); + } + } + return this.resourceFileExists(uri); + } + + /** + * Attempts to save the given resource instance. Instead of throwing exceptions, + * returns true/false to indicate success/failure. + */ + public boolean saveResourceIfNotSaved(Resource res) { + var uri = res.getURI(); + if (uri.isFile() && !this.resourceFileExists(uri)) { + return this.saveResource(res); + } + return this.resourceFileExists(uri); + } + + /** + * Loads the given resource + */ + public void loadResource(Resource res) { + try { + this.logDebugMsg(String.format("Loading resource at: %s", res.getURI())); + res.load(null); + this.logDebugMsg(String.format("Loaded %s", res.getURI())); + } catch (IOException e) { + e.printStackTrace(); + this.logInfoMsg(String.format("Could not load resource at: %s", res.getURI())); + } + } + + /** + * @return A resource instance, which has the contents of the saved resource + * file at the given URI + */ + public Resource loadResource(URI resourceURI) { + Resource res = null; + + if (resourceURI.isFile() && new File(resourceURI.toFileString()).exists()) { + res = this.createResource(resourceURI); + this.loadResource(res); + } + + return res; + } + + /** + * @return The loaded resource located at the given path + */ + public Resource loadResource(Path resourcePath) { + return this.loadResource(URI.createFileURI(resourcePath.toString())); + } + + /** + * @param resSet The resource ste, which will contain the created resource + * @param resourceURI The URI, where the resource points at + * @return An empty resource inside the given resource set, with the given URI + */ + public Resource createResource(ResourceSet resSet, URI resourceURI) { + return this.createResource(null, resSet, resourceURI); + } + + /** + * @param resourceURI The URI, where the resource points at + * @return An empty resource, inside a freshly created resource set, with the + * given URI + */ + public Resource createResource(URI resourceURI) { + return this.createResource(this.createResourceSet(), resourceURI); + } + + /** + * Unloads the given {@link Resource} instance. + */ + public boolean unloadResource(Resource res) { + res.unload(); + return !res.isLoaded(); + } + + /** + * @param resURI The URI that points at the potentially existing resource file. + * @return Whether the resource file exists. Will return false if the given URI + * does not point at a file, regardless of whether the resource exists. + */ + public boolean resourceFileExists(URI resURI) { + return resURI.isFile() && new File(resURI.toFileString()).exists(); + } + + /** + * Deletes the given resource + * + * @return Whether the file of the given resource is deleted. + */ + public boolean deleteResource(Resource res) { + var uri = res.getURI(); + if (this.resourceFileExists(uri)) { + try { + res.delete(null); + return !this.resourceFileExists(uri); + } catch (IOException e) { + var isResourceDeleted = !this.resourceFileExists(uri); + this.logInfoMsg(String.format("Could not delete resource as expected: %s (is deleted: %s) %s %s", + res.getURI().toString(), isResourceDeleted, System.lineSeparator(), e.getMessage())); + return isResourceDeleted; + } + } + return !this.resourceFileExists(uri); + } + + /** + * Removes the entry matching to the given {@code resourceFileExtension} from + * the resource factory. + */ + public void removeFromRegistry(String resourceFileExtension) { + if (resourceFileExtension == null) + return; + + var regMap = this.getResourceRegistry().getExtensionToFactoryMap(); + regMap.remove(resourceFileExtension); + } +} diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/eobject/AbstractResourceParsingStrategy.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/eobject/AbstractResourceParsingStrategy.java new file mode 100644 index 0000000000..eb58c1f8bd --- /dev/null +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/eobject/AbstractResourceParsingStrategy.java @@ -0,0 +1,91 @@ +package cipm.consistency.fitests.similarity.eobject; + +import java.nio.file.Path; +import java.util.HashSet; +import java.util.Set; + +import org.eclipse.emf.ecore.resource.ResourceSet; + +/** + * An abstract class meant to be extended by classes that envelop the means to + * parse Resource instances from (original) model files.
+ *
+ * Implementors are expected to: + *
    + *
  • Have their ResourceSet set via {@link #setResourceSet(ResourceSet)} prior + * to any {@link #parseModelResource(Path)} calls + *
  • Parse models in form of {@link Resource} instances and place all those + * Resource instances into the same {@link ResourceSet} + *
  • Support exclusion patterns that can be used to exclude certain model + * files from being parsed + *
+ * + * @author Alp Torac Genc + */ +public abstract class AbstractResourceParsingStrategy { + /** + * @see {@link AbstractResourceParsingStrategy} + */ + private ResourceSet resourceSet; + /** + * @see {@link AbstractResourceParsingStrategy} + */ + private final Set exclusionPatterns = new HashSet<>(); + + /** + * Sets the ResourceSet used from within to the given one. + * + * @see {@link #getResourceSet()} + */ + public void setResourceSet(ResourceSet resourceSet) { + this.resourceSet = resourceSet; + } + + /** + * @return The ResourceSet inside this instance, which should contain all parsed + * model Resources. + */ + public ResourceSet getResourceSet() { + return this.resourceSet; + } + + /** + * Adds the given exclusion pattern to the set of exclusion patterns. Refer to + * the concrete implementation for more details on what kind of patterns are + * supported. + * + * @param pattern An exclusion pattern to add to the set + */ + public void addExclusionPattern(String pattern) { + this.exclusionPatterns.add(pattern); + } + + /** + * Removes the given exclusion pattern from the set of exclusion patterns. Refer + * to the concrete implementation for more details on what kind of patterns are + * supported. + * + * @param pattern An exclusion pattern to remove from the set + */ + public void removeExclusionPattern(String pattern) { + this.exclusionPatterns.remove(pattern); + } + + /** + * Clears all exclusion patterns from this instance. + */ + public void clearExclusionPatterns() { + this.exclusionPatterns.clear(); + } + + /** + * Parses a ResourceSet for the model at given path. + * + * @param modelDir The path to a given model. Refer to the concrete + * implementation for more information on where this path is + * supposed to point at. + * @return A ResourceSet that contains all parsed Resource instances for the + * given model path. + */ + public abstract ResourceSet parseModelResource(Path modelDir); +} diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/eobject/ResourceTestOptions.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/eobject/ResourceTestOptions.java new file mode 100644 index 0000000000..23be8b5a82 --- /dev/null +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/eobject/ResourceTestOptions.java @@ -0,0 +1,59 @@ +package cipm.consistency.fitests.similarity.eobject; + +/** + * A class that contains various options for test classes that use + * {@link Resource} instances: + *
    + *
  • shouldUnloadAllResources: Whether all created resource instances should + * be unloaded after each test + *
  • shouldDeleteAllResources: Whether all created resource files should be + * deleted after each test + *
+ * Note: This class is only responsible for containing Resource-related + * options. Giving these options meanings and applying them is not the concern + * of this class. + * + * @author Alp Torac Genc + */ +public class ResourceTestOptions { + private boolean shouldUnloadAllResources; + private boolean shouldDeleteAllResources; + + /** + * @see {@link ResourceTestOptions} + */ + public void setShouldUnloadAllResources(boolean shouldUnloadAllResources) { + this.shouldUnloadAllResources = shouldUnloadAllResources; + } + + /** + * @see {@link ResourceTestOptions} + */ + public void setShouldDeleteAllResources(boolean shouldDeleteAllResources) { + this.shouldDeleteAllResources = shouldDeleteAllResources; + } + + /** + * @see {@link ResourceTestOptions} + */ + public boolean shouldUnloadAllResources() { + return shouldUnloadAllResources; + } + + /** + * @see {@link ResourceTestOptions} + */ + public boolean shouldDeleteAllResources() { + return shouldDeleteAllResources; + } + + /** + * Copies all options from the given instance; i.e. after calling this method, + * all options inside the given instance will override the corresponding options + * in this. + */ + public void copyOptionsFrom(ResourceTestOptions opts) { + this.shouldUnloadAllResources = opts.shouldUnloadAllResources; + this.shouldDeleteAllResources = opts.shouldDeleteAllResources; + } +} From 302659a4be092c07a825a28907ffc074959af83e Mon Sep 17 00:00:00 2001 From: AlpTorac Date: Sun, 27 Jul 2025 16:55:09 +0200 Subject: [PATCH 07/72] Implement abstract test class --- .../AbstractEObjectSimilarityTest.java | 126 ++++++++++++++++++ 1 file changed, 126 insertions(+) create mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/eobject/AbstractEObjectSimilarityTest.java diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/eobject/AbstractEObjectSimilarityTest.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/eobject/AbstractEObjectSimilarityTest.java new file mode 100644 index 0000000000..ed18ef815e --- /dev/null +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/eobject/AbstractEObjectSimilarityTest.java @@ -0,0 +1,126 @@ +package cipm.consistency.fitests.similarity.eobject; + +import org.eclipse.emf.ecore.resource.Resource; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; + +import cipm.consistency.fitests.similarity.AbstractSimilarityTest; + +/** + * An abstract class meant to be implemented by EObject-related test classes. + * + * @author Alp Torac Genc + */ +public abstract class AbstractEObjectSimilarityTest extends AbstractSimilarityTest { + /** + * @see {@link #getResourceHelper()} + */ + private AbstractResourceHelper resHelper; + + /** + * @see {@link #getResourceParsingStrategy()} + */ + private AbstractResourceParsingStrategy parsingStrat; + + /** + * @see {@link #getResourceTestOptions()} + */ + private ResourceTestOptions resourceTestOptions; + + /** + * {@inheritDoc}
+ *
+ * {@link AbstractEObjectSimilarityTest}: Sets up Resource-related helper + * classes and options {@link AbstractResourceHelper}, + * {@link AbstractResourceParsingStrategy}, {@link ResourceTestOptions}. + */ + @BeforeEach + @Override + public void setUp() { + super.setUp(); + + this.setResourceHelper(this.initResourceHelper()); + + this.setResourceParsingStrategy(this.initResourceParsingStrategy()); + this.setResourceTestOptions(this.initResourceTestOptions()); + } + + /** + * {@inheritDoc}
+ *
+ * {@link AbstractEObjectSimilarityTest}: Sets {@link #getResourceHelper()}, + * {@link #getResourceParsingStrategy()} and {@link #getResourceTestOptions()} + * to null, in order to ensure that each test has freshly created instances. + */ + @AfterEach + @Override + public void tearDown() { + this.cleanUpResourceHelper(); + this.cleanUpResourceParsingStrategy(); + this.cleanUpResourceTestOptions(); + + super.tearDown(); + } + + /** + * The {@link AbstractResourceHelper} instance that can be used for creating + * {@link Resource} instances. + */ + protected AbstractResourceHelper getResourceHelper() { + return this.resHelper; + } + + /** + * Sets up the {@link AbstractResourceHelper} instance that will be used with + * the given one. + */ + protected void setResourceHelper(AbstractResourceHelper resHelper) { + this.resHelper = resHelper; + } + + protected AbstractResourceParsingStrategy getResourceParsingStrategy() { + return this.parsingStrat; + } + + protected void setResourceParsingStrategy(AbstractResourceParsingStrategy parsingStrat) { + this.parsingStrat = parsingStrat; + } + + /** + * @return The extension of the {@link Resource} files, if they are saved. + */ + public String getResourceFileExtension() { + return this.getResourceHelper().getResourceFileExtension(); + } + + protected ResourceTestOptions getResourceTestOptions() { + return this.resourceTestOptions; + } + + protected void setResourceTestOptions(ResourceTestOptions resourceTestOptions) { + this.resourceTestOptions = resourceTestOptions; + } + + protected void cleanUpResourceHelper() { + this.resHelper = null; + } + + protected void cleanUpResourceParsingStrategy() { + this.parsingStrat = null; + } + + protected void cleanUpResourceTestOptions() { + this.resourceTestOptions = null; + } + + /** + * Override in implementors to change the default value, if needed. + * + * @return The {@link AbstractResourceHelper} that will be initially used. + */ + protected abstract AbstractResourceHelper initResourceHelper(); + + protected abstract ResourceTestOptions initResourceTestOptions(); + + protected abstract AbstractResourceParsingStrategy initResourceParsingStrategy(); +} From a4a787d91f74d3ab88442529f43f13c2c0b24b3c Mon Sep 17 00:00:00 2001 From: AlpTorac Date: Sun, 27 Jul 2025 17:11:30 +0200 Subject: [PATCH 08/72] Implement concrete Resource-related classes --- .../jamopp/JaMoPPResourceHelper.java | 42 +++++++++ .../jamopp/JaMoPPResourceParsingStrategy.java | 92 +++++++++++++++++++ .../JaMoPPSimilarityCheckerContainer.java | 42 +++++++++ 3 files changed, 176 insertions(+) create mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/JaMoPPResourceHelper.java create mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/JaMoPPResourceParsingStrategy.java create mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/JaMoPPSimilarityCheckerContainer.java diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/JaMoPPResourceHelper.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/JaMoPPResourceHelper.java new file mode 100644 index 0000000000..9e0f5d7d7a --- /dev/null +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/JaMoPPResourceHelper.java @@ -0,0 +1,42 @@ +package cipm.consistency.fitests.similarity.jamopp; + +import org.eclipse.emf.ecore.resource.Resource; + +import cipm.consistency.fitests.similarity.eobject.AbstractResourceHelper; + +import jamopp.resource.JavaResource2Factory; + +/** + * A class that can be used for operations on Resource instances in JaMoPP + * context. + * + * @author Alp Torac Genc + */ +public class JaMoPPResourceHelper extends AbstractResourceHelper { + /** + * The extension of Java source code files. + */ + private static final String javaSrcExt = "java"; + /** + * The extension of the resource files created within tests, should they be + * saved. + */ + private static final String resFileExt = "javaxmi"; + + public JaMoPPResourceHelper() { + super(); + this.setResourceFileExtension(resFileExt); + this.setInitialResourceRegistries(); + } + + /** + * Adds the mapping into {@link Resource.Factory.Registry} for saving resources + * with the extension {@link #getResourceFileExtension()} using XMI format. + * + * @see {@link #setResourceRegistry(String, Object)} + */ + public void setInitialResourceRegistries() { + this.setResourceRegistry(javaSrcExt, new JavaResource2Factory()); + this.setResourceRegistry(resFileExt, new JavaResource2Factory()); + } +} diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/JaMoPPResourceParsingStrategy.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/JaMoPPResourceParsingStrategy.java new file mode 100644 index 0000000000..2bfd5b528d --- /dev/null +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/JaMoPPResourceParsingStrategy.java @@ -0,0 +1,92 @@ +package cipm.consistency.fitests.similarity.jamopp; + +import java.nio.file.Path; + +import org.eclipse.emf.ecore.resource.ResourceSet; + +import cipm.consistency.fitests.similarity.eobject.AbstractResourceParsingStrategy; +import jamopp.options.ParserOptions; +import jamopp.parser.jdt.singlefile.JaMoPPJDTSingleFileParser; +import jamopp.recovery.trivial.TrivialRecovery; + +/** + * A class that uses {@link JaMoPPJDTSingleFileParser} to parse Java model + * Resources. Provides methods for performing {@link TrivialRecovery} in cases, + * where bindings are used.
+ *
+ *
    + *
  • Given model paths should point at the top-most directory of the Java + * project + *
  • Supports Regex expressions for model paths as exclusion patterns + *
+ * + * @author Alp Torac Genc + */ +public class JaMoPPResourceParsingStrategy extends AbstractResourceParsingStrategy { + /** + * @see {@link #getParser()} + */ + private final JaMoPPJDTSingleFileParser parser; + + public JaMoPPResourceParsingStrategy() { + super(); + this.parser = new JaMoPPJDTSingleFileParser(); + this.setUpModelParser(); + } + + /** + * Declared as protected to allow sub-types to access the underlying parser. Not + * meant to be used in non-sub-types. + * + * @return The parser that is used for parsing Java model Resources. + */ + protected JaMoPPJDTSingleFileParser getParser() { + return parser; + } + + /** + * Prepares the parser for parsing model resources.
+ *
+ * Can be overridden in sub-types to modify if needed. + */ + protected void setUpModelParser() { + /* + * Default values of ParserOptions are: + * + * RESOLVE_ALL_BINDINGS = true + * + * RESOLVE_BINDINGS = true + * + * RESOLVE_BINDINGS_OF_INFERABLE_TYPES = true + * + * CREATE_LAYOUT_INFORMATION = true + * + * PREFER_BINDING_CONVERSION = true + */ + this.parser.setResourceSet(this.getResourceSet()); + + ParserOptions.CREATE_LAYOUT_INFORMATION.setValue(Boolean.FALSE); + ParserOptions.REGISTER_LOCAL.setValue(Boolean.TRUE); + ParserOptions.RESOLVE_EVERYTHING.setValue(Boolean.FALSE); + ParserOptions.RESOLVE_ALL_BINDINGS.setValue(Boolean.FALSE); + } + + @Override + public ResourceSet parseModelResource(Path modelDir) { + return parser.parseDirectory(modelDir); + } + + /** + * Performs {@link TrivialRecovery} on the current ResourceSet of this instance. + */ + public void performTrivialRecovery() { + this.performTrivialRecovery(this.getResourceSet()); + } + + /** + * Performs {@link TrivialRecovery} on the given ResourceSet. + */ + public void performTrivialRecovery(ResourceSet resourceSet) { + new TrivialRecovery(resourceSet).recover(); + } +} diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/JaMoPPSimilarityCheckerContainer.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/JaMoPPSimilarityCheckerContainer.java new file mode 100644 index 0000000000..32e108f755 --- /dev/null +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/JaMoPPSimilarityCheckerContainer.java @@ -0,0 +1,42 @@ +package cipm.consistency.fitests.similarity.jamopp; + +import java.util.Collection; +import java.util.List; + +import org.eclipse.emf.ecore.EObject; +import org.splevo.jamopp.diffing.similarity.SimilarityChecker; + +import cipm.consistency.fitests.similarity.ISimilarityCheckerContainer; + +/** + * A concrete implementation of {@link ISimilarityCheckerContainer} that creates + * and works with {@link SimilarityChecker} instances. + * + * @author Alp Torac Genc + */ +public class JaMoPPSimilarityCheckerContainer implements ISimilarityCheckerContainer { + private SimilarityChecker sc; + + private SimilarityChecker getSimilarityChecker() { + if (this.sc == null) { + this.newSimilarityChecker(); + } + return this.sc; + } + + @Override + public void newSimilarityChecker() { + this.sc = new SimilarityChecker(); + } + + @Override + public Boolean isSimilar(Object element1, Object element2) { + return this.getSimilarityChecker().isSimilar((EObject) element1, (EObject) element2); + } + + @SuppressWarnings("unchecked") + @Override + public Boolean areSimilar(Collection elements1, Collection elements2) { + return this.getSimilarityChecker().areSimilar((List) elements1, (List) elements2); + } +} From 5f9048a5a7db28ec611ee40caf3ef0aa8b3a131e Mon Sep 17 00:00:00 2001 From: AlpTorac Date: Sun, 27 Jul 2025 17:12:31 +0200 Subject: [PATCH 09/72] Implement abstract test class with default methods that are the standard JaMoPP tests --- .../jamopp/AbstractJaMoPPSimilarityTest.java | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/AbstractJaMoPPSimilarityTest.java diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/AbstractJaMoPPSimilarityTest.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/AbstractJaMoPPSimilarityTest.java new file mode 100644 index 0000000000..dae8b167ce --- /dev/null +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/AbstractJaMoPPSimilarityTest.java @@ -0,0 +1,34 @@ +package cipm.consistency.fitests.similarity.jamopp; + +import cipm.consistency.fitests.similarity.ISimilarityCheckerContainer; +import cipm.consistency.fitests.similarity.eobject.AbstractEObjectSimilarityTest; + +/** + * An abstract test class that extends {@link AbstractEObjectSimilarityTest} + * with concrete method implementations for JaMoPP context, as well as static + * methods that can be used in parameterised tests to generate initialiser + * instances. + * + * @author Alp Torac Genc + */ +public abstract class AbstractJaMoPPSimilarityTest extends AbstractEObjectSimilarityTest { + @Override + protected JaMoPPResourceHelper initResourceHelper() { + return new JaMoPPResourceHelper(); + } + + @Override + protected ISimilarityCheckerContainer initSCC() { + return new JaMoPPSimilarityCheckerContainer(); + } + + @Override + protected JaMoPPResourceParsingStrategy initResourceParsingStrategy() { + return new JaMoPPResourceParsingStrategy(); + } + + @Override + protected JaMoPPResourceParsingStrategy getResourceParsingStrategy() { + return (JaMoPPResourceParsingStrategy) super.getResourceParsingStrategy(); + } +} From 1d16afb8c95a84517d99c95d2b16776c1e3363a7 Mon Sep 17 00:00:00 2001 From: AlpTorac Date: Sun, 27 Jul 2025 17:13:46 +0200 Subject: [PATCH 10/72] Implement expected similarity result providers for parser tests --- .../IExpectedSimilarityResultProvider.java | 37 ++++++ ...sourceContentSimilarityResultProvider.java | 118 ++++++++++++++++++ ...renceEqualitySimilarityResultProvider.java | 22 ++++ 3 files changed, 177 insertions(+) create mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/IExpectedSimilarityResultProvider.java create mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ResourceContentSimilarityResultProvider.java create mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ResourceReferenceEqualitySimilarityResultProvider.java diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/IExpectedSimilarityResultProvider.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/IExpectedSimilarityResultProvider.java new file mode 100644 index 0000000000..5a9c2e21ba --- /dev/null +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/IExpectedSimilarityResultProvider.java @@ -0,0 +1,37 @@ +package cipm.consistency.fitests.similarity.jamopp.parser; + +import java.nio.file.Path; + +import org.eclipse.emf.ecore.resource.Resource; + +/** + * An interface for classes, which encapsulate the logic for providing expected + * similarity checking results to tests, where model resources are being + * compared.
+ *
+ * Concrete implementations of this interface may also nest + * {@link IExpectedSimilarityResultProvider}s or have certain ones override the + * expected similarity results of others. How the expected similarity results + * are derived and provided depends on the concrete implementor. + * + * @author Alp Torac Genc + */ +public interface IExpectedSimilarityResultProvider { + /** + * Model resources and their paths should be provided via separate parameters, + * as the original files that were parsed into model resources may reside under + * different paths, which cannot be determined from the model resource alone. + * + * @param lhsRes Left-hand side resource + * @param lhsResPath The path that the resource lhsRes was originally parsed + * from, i.e. the path to the files that were parsed into + * lhsRes. + * @param rhsRes Right-hand side resource + * @param rhsResPath The path that the resource rhsRes was originally parsed + * from, i.e. the path to the files that were parsed into + * rhsRes. + * @return The expected result of similarity checking the given resources, + * according to the concrete implementor. + */ + public boolean getExpectedSimilarityResultFor(Resource lhsRes, Path lhsResPath, Resource rhsRes, Path rhsResPath); +} diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ResourceContentSimilarityResultProvider.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ResourceContentSimilarityResultProvider.java new file mode 100644 index 0000000000..ffc0594c3f --- /dev/null +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ResourceContentSimilarityResultProvider.java @@ -0,0 +1,118 @@ +package cipm.consistency.fitests.similarity.jamopp.parser; + +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collection; + +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.resource.Resource; + +import cipm.consistency.fitests.similarity.ISimilarityCheckerContainer; + +/** + * Provides expected similarity results based on the similarity of model + * resources' contents. Meant for deep model comparison tests that compute the + * actual differences between model resources, as opposed to only computing + * whether 2 given model resources are similar. + * + * @author Alp Torac Genc + */ +public class ResourceContentSimilarityResultProvider implements IExpectedSimilarityResultProvider { + private ISimilarityCheckerContainer scc; + /** + * Whether the order of the contents of the model resources should be accounted + * for + */ + private boolean contentOrderMatters; + + /** + * @param scc The object that will be used to determine whether + * contents of model resources are similar + * @param contentOrderMatters Whether the order of the contents of the model + * resources should be accounted for + */ + public ResourceContentSimilarityResultProvider(ISimilarityCheckerContainer scc, boolean contentOrderMatters) { + this.scc = scc; + this.contentOrderMatters = contentOrderMatters; + } + + /** + * Checks if both sides' contents ({@code res.getAllContents()}) are similar, if + * their order does not matter. Makes sure that the result is the same as + * {@code allContentSimilar(rhs, lhs)}. + * + * @return Whether all contents of lhs and rhs are similar, i.e. if all contents + * of lhs have a corresponding similar content on rhs. + */ + private boolean contentwiseSimilar(Resource lhs, Resource rhs) { + var lhsContent = new ArrayList(); + lhs.getAllContents().forEachRemaining((e) -> lhsContent.add(e)); + var rhsContent = new ArrayList(); + rhs.getAllContents().forEachRemaining((e) -> rhsContent.add(e)); + + return this.contentwiseSimilar(lhsContent, rhsContent) && this.contentwiseSimilar(rhsContent, lhsContent); + } + + /** + * Checks if both sides' contents ({@code obj.eAllContents()}) are similar, if + * their order does not matter. Makes sure that the result is the same as + * {@code allContentSimilar(rhs, lhs)}. + * + * @return Whether all contents of lhs and rhs are similar, i.e. if all contents + * of lhs have a corresponding similar content on rhs. + */ + private boolean contentwiseSimilar(EObject lhs, EObject rhs) { + if (!this.scc.isSimilar(lhs, rhs) || !this.scc.isSimilar(rhs, lhs)) { + return false; + } + + var lhsContent = new ArrayList(); + lhs.eAllContents().forEachRemaining((e) -> lhsContent.add(e)); + var rhsContent = new ArrayList(); + rhs.eAllContents().forEachRemaining((e) -> rhsContent.add(e)); + + return this.contentwiseSimilar(lhsContent, rhsContent) && this.contentwiseSimilar(rhsContent, lhsContent); + } + + /** + * Variant of {@link #contentwiseSimilar(EObject, EObject)} for collections. + */ + private boolean contentwiseSimilar(Collection lhs, Collection rhs) { + var lhsContent = new ArrayList(lhs); + var rhsContent = new ArrayList(rhs); + + if (lhsContent.size() != rhsContent.size()) { + return false; + } + + while (!lhsContent.isEmpty() && !rhsContent.isEmpty()) { + var lhsElem = lhsContent.get(0); + final var rhsElem = new EObject[] { null }; + for (var e : rhsContent) { + if (this.contentwiseSimilar(lhsElem, e)) { + rhsElem[0] = e; + break; + } + } + if (rhsElem[0] != null) { + lhsContent.remove(lhsElem); + rhsContent.remove(rhsElem[0]); + } else { + return false; + } + } + return lhsContent.isEmpty() && rhsContent.isEmpty(); + } + + /** + * @implSpec Determines expected similarity results based on the given + * {@link ISimilarityCheckerContainer} and content order (if desired + * in + * {@link #ResourceContentSimilarityResultProvider(ISimilarityCheckerContainer, boolean)}). + */ + @Override + public boolean getExpectedSimilarityResultFor(Resource lhsRes, Path lhsResPath, Resource rhsRes, Path rhsResPath) { + var pathsEqual = lhsResPath.toString().equals(rhsResPath.toString()); + return pathsEqual || (!this.contentOrderMatters && this.contentwiseSimilar(lhsRes, rhsRes)); + } +} diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ResourceReferenceEqualitySimilarityResultProvider.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ResourceReferenceEqualitySimilarityResultProvider.java new file mode 100644 index 0000000000..26f6502bb2 --- /dev/null +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ResourceReferenceEqualitySimilarityResultProvider.java @@ -0,0 +1,22 @@ +package cipm.consistency.fitests.similarity.jamopp.parser; + +import java.nio.file.Path; + +import org.eclipse.emf.ecore.resource.Resource; + +/** + * Provides expected similarity results based on the reference equality of model + * resources. + * + * @author Alp Torac Genc + */ +public class ResourceReferenceEqualitySimilarityResultProvider implements IExpectedSimilarityResultProvider { + /** + * @implSpec Determines expected similarity results based on the reference + * equality of model resources. + */ + @Override + public boolean getExpectedSimilarityResultFor(Resource lhsRes, Path lhsResPath, Resource rhsRes, Path rhsResPath) { + return lhsRes == rhsRes; + } +} From ecee15b7cdd86f3b01eb218f9212e7d86fc1f853 Mon Sep 17 00:00:00 2001 From: AlpTorac Date: Sun, 27 Jul 2025 17:16:00 +0200 Subject: [PATCH 11/72] Implement utility class for file operations --- .../similarity/jamopp/parser/FileUtil.java | 154 ++++++++++++++++++ 1 file changed, 154 insertions(+) create mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/FileUtil.java diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/FileUtil.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/FileUtil.java new file mode 100644 index 0000000000..e1478da06a --- /dev/null +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/FileUtil.java @@ -0,0 +1,154 @@ +package cipm.consistency.fitests.similarity.jamopp.parser; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.TreeSet; + +import cipm.consistency.fitests.similarity.ILoggable; + +/** + * A utility class that contains file-related operations. + * + * @author Alp Torac Genc + */ +public class FileUtil implements ILoggable { + /** + * @return Whether the content of both dirs are similar. + * + * @see {@link #filesEqual(File, File)} + * @see {@link #dirsEqual(File, File)} + */ + public boolean areContentsEqual(Path path1, Path path2) { + return dirsEqual(path1.toFile(), path2.toFile()); + } + + /** + * Reads the given file and removes line breaks and whitespaces.
+ *
+ * If the given file cannot be read (due to IOException), returns an empty + * string. + */ + public String readEffectiveText(File f) { + var content = ""; + + try { + content = Files.readString(f.toPath()); + } catch (IOException e) { + this.logDebugMsg(String.format("Could not read: %s, returning empty string", f.toPath().toString())); + } + + return content.replaceAll("\\n", "").replaceAll("\\r", "").replaceAll("\\s", ""); + } + + /** + * Compares the equality of the given files based on their effective content, + * i.e. their content without whitespaces.
+ *
+ * If both files cannot be read, they are ignored and this method returns true. + * + * @see {@link #readEffectiveText(File)} + */ + public boolean filesEqual(File f1, File f2) { + var f1Content = readEffectiveText(f1); + var f2Content = readEffectiveText(f2); + + if (f1Content.isBlank() && f2Content.isBlank()) { + return true; + } + + return f1Content.equals(f2Content); + } + + /** + * Recursively checks the equality of the given directories, based on their + * effective content (i.e. the files/sub-directories they contain and the + * contents of those files without whitespaces). + * + * @see {@link #filesEqual(File, File)}, {@link #readEffectiveText(File)} + */ + public boolean dirsEqual(File dir1, File dir2) { + this.logDebugMsg("Comparing: " + dir1.getName() + " and " + dir2.getName()); + + // There cannot be 2 files with the same path, name and extension + // so using TreeSet, which sorts the files spares doing so here + var files1 = new TreeSet(); + var files2 = new TreeSet(); + + var dir1Files = dir1.listFiles(); + if (dir1Files != null) { + for (var f : dir1Files) { + files1.add(f); + } + } + + var dir2Files = dir2.listFiles(); + if (dir2Files != null) { + for (var f : dir2Files) { + files2.add(f); + } + } + + if (files1.size() != files2.size()) { + return false; + } + + var fileIter1 = files1.iterator(); + var fileIter2 = files2.iterator(); + + for (int i = 0; i < files1.size(); i++) { + var f1 = fileIter1.next(); + var f2 = fileIter2.next(); + + if (f1.isDirectory() && f2.isDirectory()) { + if (!dirsEqual(f1, f2)) { + this.logDebugMsg("Directories " + f1.getName() + " and " + f2.getName() + " are not equal"); + return false; + } + } else if (f1.isFile() && f2.isFile()) { + if (!filesEqual(f1, f2)) { + this.logDebugMsg("Files " + f1.getName() + " and " + f2.getName() + " are not equal"); + return false; + } + } else { + this.logErrorMsg("Unexpected case there is a file and a directory"); + return false; + } + } + + return true; + } + + /** + * Recursively cleans files. If a file or directory cannot be deleted, requests + * its deletion upon termination of JVM. + * + * @param file The file or directory to delete + * @see {@link File#deleteOnExit()} + */ + public void deleteAll(File file) { + if (file.exists()) { + if (file.isDirectory()) { + var children = file.listFiles(); + + if (children != null) { + for (var cf : children) { + this.deleteAll(cf); + } + } + } + + if (!file.delete()) { + file.deleteOnExit(); + } + } + } + + /** + * A variant of {@link #deleteAll(File)} that converts the given path to a file. + */ + public void deleteAll(Path path) { + this.deleteAll(path.toFile()); + } +} From 4edade7ee14d6422ee5b7896e2a60c02cb4cf99c Mon Sep 17 00:00:00 2001 From: AlpTorac Date: Sun, 27 Jul 2025 17:16:35 +0200 Subject: [PATCH 12/72] Implement expected similarity result provider that analyses Resource file content --- .../FileContentSimilarityResultProvider.java | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/FileContentSimilarityResultProvider.java diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/FileContentSimilarityResultProvider.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/FileContentSimilarityResultProvider.java new file mode 100644 index 0000000000..9b7210404a --- /dev/null +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/FileContentSimilarityResultProvider.java @@ -0,0 +1,26 @@ +package cipm.consistency.fitests.similarity.jamopp.parser; + +import java.nio.file.Path; + +import org.eclipse.emf.ecore.resource.Resource; + +/** + * Provides expected similarity results for model resources by comparing the + * file contents under their paths. + * + * @author Alp Torac Genc + */ +public class FileContentSimilarityResultProvider implements IExpectedSimilarityResultProvider { + private FileUtil fileUtil = new FileUtil(); + + /** + * @implSpec Determines the expected similarity result purely based on the given + * paths. Compares the contents of files under both given paths + * pairwise. If all files are present on both sides, and have the same + * content (up to whitespaces). + */ + @Override + public boolean getExpectedSimilarityResultFor(Resource lhsRes, Path lhsResPath, Resource rhsRes, Path rhsResPath) { + return fileUtil.areContentsEqual(lhsResPath, rhsResPath); + } +} From f2309053b6f0add4cd0410b6c2a975e94f7a1f6e Mon Sep 17 00:00:00 2001 From: AlpTorac Date: Sun, 27 Jul 2025 17:17:45 +0200 Subject: [PATCH 13/72] Implement wrapper for parsed model resources --- .../jamopp/parser/IModelResourceWrapper.java | 109 +++++ .../parser/JaMoPPModelResourceWrapper.java | 383 ++++++++++++++++++ 2 files changed, 492 insertions(+) create mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/IModelResourceWrapper.java create mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/JaMoPPModelResourceWrapper.java diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/IModelResourceWrapper.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/IModelResourceWrapper.java new file mode 100644 index 0000000000..efec033b6e --- /dev/null +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/IModelResourceWrapper.java @@ -0,0 +1,109 @@ +package cipm.consistency.fitests.similarity.jamopp.parser; + +import java.nio.file.Path; + +import org.eclipse.emf.common.util.URI; +import org.eclipse.emf.ecore.resource.Resource; + +/** + * An interface meant for classes that encapsulate resources parsed from models. + * The main purpose of such classes is to make operations on parsed model + * resources, and other resources parsed in the process, cleaner.
+ *
+ * Concrete implementors should consider only one primary model resource + * (referred as model resource in methods), which contains all direct contents + * of all model files, and grant access to it via {@link #getModelResource()}. + * They may, however, choose to split contents that are required by the model + * resource into separate Resources. Such Resources should also be parsed within + * {@link #parseModelResource(Path, URI)}. They are then loaded automatically on + * demand by the internals of EMF-Framework. Therefore, + * {@link #loadModelResource(URI)} should only load the model resource. + * + * @author Alp Torac Genc + */ +public interface IModelResourceWrapper { + /** + * Parses all Java-Model files under the given directory. The parsed model + * resource can be accessed via {@link #getModelResource()}. + * + * @param modelDir A directory that contains all files of a model + * @param modelResourceURI The URI that the parsed model resource will reside + * at, once saved + * @param parser The parser that will be used to parse the model + * resource and all other necessary resources + */ + public void parseModelResource(Path modelDir, URI modelResourceURI); + + /** + * Loads a model resource that was previously parsed. + * + * @param modelResourceURI The URI, at which a previously parsed model resource + * resides + */ + public void loadModelResource(URI modelResourceURI); + + /** + * Saves all parsed model resources. + * + * @return Whether all parsed resources have been saved. If no resources have + * been parsed, no resources will be saved and this method returns true. + */ + public boolean saveResources(); + + /** + * Deletes all parsed model resources. + * + * @return Whether all parsed resources have been deleted. If no resources have + * been parsed, no resource will be deleted and this method returns + * true. + */ + public boolean deleteResources(); + + /** + * Unloads all parsed model resources. + * + * @return Whether all parsed resources have been unloaded. If no resources have + * been parsed, no resource will be unloaded and this method returns + * true. + */ + public boolean unloadResources(); + + /** + * Only checks whether the model resource is loaded, which contains the direct + * contents of model files, because other resources will be automatically loaded + * on demand. + * + * @return Whether the model resource is loaded + */ + public boolean isModelResourceLoaded(); + + /** + * Loads all parsed model resources. + * + * @return Whether all parsed model resources have been loaded. If no resources + * have been parsed, no resource will be loaded. + */ + public boolean loadParsedResources(); + + /** + * Sets the URIs of all parsed resources with respect to the given URI, which + * will be assigned to the parsed model resource that contains all direct + * contents of the model files. + * + * @param newParsedModelResourceURI The new URI of the parsed model resource + * ({@link #getModelResource()} in this case) + */ + public void setModelResourcesURI(URI newParsedModelResourceURI); + + /** + * @return The model resource, which contains all contents of all (directly) + * parsed model files + */ + public Resource getModelResource(); + + /** + * @return Whether there is a parsed model resource + * ({@link #getModelResource()}) currently present in this instance. + */ + public boolean modelResourceExists(); +} diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/JaMoPPModelResourceWrapper.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/JaMoPPModelResourceWrapper.java new file mode 100644 index 0000000000..5c9338843d --- /dev/null +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/JaMoPPModelResourceWrapper.java @@ -0,0 +1,383 @@ +package cipm.consistency.fitests.similarity.jamopp.parser; + +import java.nio.file.Path; + +import org.eclipse.emf.common.util.URI; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.emf.ecore.util.EcoreUtil; + +import cipm.consistency.fitests.similarity.ILoggable; +import cipm.consistency.fitests.similarity.eobject.AbstractResourceHelper; +import cipm.consistency.fitests.similarity.jamopp.JaMoPPResourceParsingStrategy; + +/** + * A class that wraps a model resource, which is either already parsed or is to + * be parsed. It encapsulates the desired model resource, as well as all other + * resources it requires: + *
    + *
  • Merged model resource: Contains all direct contents of the model files + * (i.e. the Java code directly present in model files) + *
  • Artificial resource: Contains all contents that are required by the + * merged model resource, but are not directly present in model files, such as + * contents of native Java libraries and synthetic elements. + *
+ * The main purpose of this class is to make operations on parsed model + * resources, and other resources parsed in the process, tidier. + * + * @author Alp Torac Genc + */ +public class JaMoPPModelResourceWrapper implements IModelResourceWrapper, ILoggable { + private AbstractResourceHelper resHelper; + + /** + * The name of the ArtificialResource (i.e. the last segment of its URI) without + * file extension + */ + private static final String artificialResourceName = "ArtificialResource"; + + /** + * @see {@link #JaMoPPModelResourceWrapper(AbstractResourceHelper, JaMoPPResourceParsingStrategy)} + */ + private JaMoPPResourceParsingStrategy parsingStrat; + + /** + * @see {@link #getModelResource()} + */ + private Resource mergedModelResource; + /** + * The artificial resource, which contains all contents required by the merged + * model resource that were not directly present in the model files + */ + private Resource artificialResource; + + /** + * Constructs an instance. + * + * @param resHelper An object that helps with Resource-related operations + * @param parsingStrat The parser that will be used to parse the model resource + * and all other necessary resources + */ + public JaMoPPModelResourceWrapper(AbstractResourceHelper resHelper, JaMoPPResourceParsingStrategy parsingStrat) { + this.resHelper = resHelper; + this.parsingStrat = parsingStrat; + } + + /** + * Constructs an instance. + * + * @param resHelper An object that helps with Resource-related operations + */ + public JaMoPPModelResourceWrapper(AbstractResourceHelper resHelper) { + this(resHelper, null); + } + + /** + * @param correspondingResourceFileNameWithoutExt The name of the model + * resource, whose corresponding + * ArtificialResource's name + * (without file extension) is to + * be computed + * @return The name of the ArtificialResource corresponding to the model + * resource with the given name. + */ + protected String getArtificialResourceFileName(String correspondingResourceFileNameWithoutExt) { + return correspondingResourceFileNameWithoutExt + artificialResourceName + "." + + this.resHelper.getResourceFileExtension(); + } + + /** + * @param correspondingResourceURI The URI of the model resource, whose + * ArtificialResource's URI is to be computed + * @return The URI of the ArtificialResource of the model resource with the + * given URI + */ + protected URI getArtificialResourceURI(URI correspondingResourceURI) { + var fileNameWithoutExt = correspondingResourceURI.trimFileExtension().lastSegment(); + var arName = this.getArtificialResourceFileName(fileNameWithoutExt); + var arURI = correspondingResourceURI.trimSegments(1); + return arURI.appendSegment(arName); + } + + /** + * Creates and prepares the ArtificialResource of the given model resource, + * under the same ResourceSet (i.e. the ResourceSet of the given model + * resource). The created ArtificialResource will contain synthetic model + * elements for the proxy objects within the given model resource, as well as + * the native Java library resources that are needed by the given model + * resource.
+ *
+ * Separating said model elements from the model resource allows its actual + * contents (i.e. the code that is directly present in the model files) to be + * compared more efficiently, by excluding the imported dependencies, which are + * the same for each model resource. + * + * @param modelResource The model resource, for which an + * ArtificialResource should be created + * @param artificialResourceURI The URI, which the created ArtificialResource + * will have + * @return The created ArtificialResource + */ + protected Resource prepareArtificialResource(Resource modelResource, URI artificialResourceURI) { + var modelResourceSet = modelResource.getResourceSet(); + + // Create the ArtificialResource + parsingStrat.performTrivialRecovery(modelResourceSet); + + var artificialResource = modelResourceSet.getResources().stream() + .filter((r) -> r.getURI().toString().contains(artificialResourceName)).findFirst().orElse(null); + + if (artificialResource != null) { + artificialResource.setURI(artificialResourceURI); + + this.logDebugMsg(String.format("ArtificialResource is parsed and has its URI set to %s", + artificialResource.getURI())); + + // Use an array to avoid modifications while iterating, which lead to exceptions + var resArr = modelResourceSet.getResources().toArray(Resource[]::new); + + /* + * Iterate over all resources under modelResourceSet and look for resources of + * native Java libraries. Place each such resource's contents into the + * ArtificialResource and remove the native Java library resource from + * modelResourceSet (as it will be empty afterward). This moves all + * CompilationUnits housing the Classifiers required by the parsed model + * resource into ArtificialResource. + */ + for (int i = 0; i < resArr.length; i++) { + var r = resArr[i]; + if (!r.getURI().isFile() && r != artificialResource && r != modelResource) { + this.logDebugMsg(String.format("Adding Resource %s to ArtificialResource", r.getURI())); + artificialResource.getContents().addAll(r.getContents()); + this.logDebugMsg(String.format("Added Resource %s to ArtificialResource", r.getURI())); + modelResourceSet.getResources().remove(r); + this.logDebugMsg(String.format("Removed (empty) Resource %s from ResourceSet", r.getURI())); + } + } + + // "-2" to exclude modelResource and artificialResource from resource count + this.logDebugMsg(String.format("%d/%d resources have been added to ArtificialResource", + (resArr.length - modelResourceSet.getResources().size()) - 2, resArr.length - 2)); + + // Do not handle potential proxies in ArtificialResource, because they belong to + // internals of native classes, which are irrelevant for the model. Normally + // there should be no proxies, if the code represented in the model resource is + // valid. + } + + return artificialResource; + } + + /** + * Parses all Java-Model files under the given directory into a {@link Resource} + * instance (merged model resource). Uses no means of caching. The parsed merged + * model resource can be accessed via {@link #getModelResource()}.
+ *
+ * Note: This method will parse ALL such files. Therefore, the given model + * directory should only contain one Java-Model. + * + * @param modelDir A directory that contains all files of a model + * @param modelResourceURI The URI that the parsed model resource will reside + * at, once saved + */ + @Override + public void parseModelResource(Path modelDir, URI modelResourceURI) { + var modelResourceSet = this.resHelper.createResourceSet(); + + // Parser returns the same ResourceSet it was previously given + // via setResourceSet(...) + modelResourceSet = parsingStrat.parseModelResource(modelDir); + + var resCount = modelResourceSet.getResources().size(); + this.logDebugMsg(String.format("%d resources have been parsed under %s", resCount, modelDir)); + + // Find the model resource (i.e. the resource that contains the direct contents + // of model files) + var modelResource = modelResourceSet.getResources().stream() + .filter((r) -> r.getURI().toFileString().contains(modelDir.toString())).findFirst().get(); + + /* + * Attempt to resolve potential proxies that can be resolved prior to + * TrivialRecovery, so that it constructs less synthetic elements that are + * redundant. + * + * This is necessary, because synthetic elements' type can vary and can cause + * typing issues during similarity checking, as the (cached) model resource will + * use the synthetic elements, even though they are present directly in the + * model resource. + * + * Examples to this are LocalVariableStatements; which are declared within the + * model, are accessible and referenced by IdentifierReferences. Due to the + * absence of context information during parsing, they are considered Fields, + * unless they are resolved (via EcoreUtil.resolveAll(...) for instance) + * directly after being parsed. Not resolving them causes the + * IdentifierReferences to point at their synthetic element correspondents + * (Fields), as opposed to their declaration in the model resource. + */ + EcoreUtil.resolveAll(modelResource); + + mergedModelResource = this.resHelper.createResource(modelResourceURI); + + artificialResource = this.prepareArtificialResource(modelResource, + this.getArtificialResourceURI(modelResourceURI)); + + this.logDebugMsg(String.format("Merging non-ArtificialResources")); + + for (var r : modelResourceSet.getResources()) { + if (r != artificialResource) { + this.logDebugMsg(String.format("Including %s into the merged resource", r.getURI())); + mergedModelResource.getContents().addAll(r.getContents()); + this.logDebugMsg(String.format("Included %s into the merged resource", r.getURI())); + } + } + + this.logDebugMsg(String.format("Merged non-ArtificialResources")); + + this.logDebugMsg(String.format("%s parsed (uncached)", modelDir)); + + // Add ArtificialResource to mergedResource's resource set, so that it can be + // found by the model resource's contents that have been moved + if (artificialResource != null) { + mergedModelResource.getResourceSet().getResources().add(artificialResource); + } + } + + /** + * Loads the merged model resource that was previously parsed. + * + * @param modelResourceURI The URI, at which a previously parsed merged model + * resource resides + */ + public void loadModelResource(URI modelResourceURI) { + this.mergedModelResource = this.resHelper.loadResource(modelResourceURI); + } + + /** + * @return Whether all parsed resources have been saved. If no resources have + * been parsed, no resources will be saved. + */ + public boolean saveResources() { + var result = true; + if (mergedModelResource != null) { + this.logDebugMsg("Merged model resource exists, saving it now"); + result = this.resHelper.saveResourceIfNotSaved(mergedModelResource); + this.logDebugMsg(String.format("%s merged model resource at %s", result ? "Saved" : "Could not save", + mergedModelResource.getURI())); + } + if (artificialResource != null) { + this.logDebugMsg("Artificial resource exists, saving it now"); + result = result && this.resHelper.saveResourceIfNotSaved(artificialResource); + this.logDebugMsg(String.format("%s artificial resource at %s", result ? "Saved" : "Could not save", + artificialResource.getURI())); + } + return result; + } + + /** + * @return Whether all parsed resources have been deleted. If no resources have + * been parsed, no resource will be deleted. + */ + public boolean deleteResources() { + var result = false; + if (mergedModelResource != null) { + this.logDebugMsg("Merged model resource exists, deleting it now"); + result = this.resHelper.deleteResource(mergedModelResource); + this.logDebugMsg(String.format("%s merged model resource at %s", result ? "Deleted" : "Could not delete", + mergedModelResource.getURI())); + + } + if (artificialResource != null) { + this.logDebugMsg("Artificial resource exists, deleting it now"); + result = result && this.resHelper.deleteResource(artificialResource); + this.logDebugMsg(String.format("%s artificial resource at %s", result ? "Saved" : "Could not save", + artificialResource.getURI())); + } + return result; + } + + /** + * @return Whether all parsed resources have been unloaded. If no resources have + * been parsed, no resource will be unloaded. + */ + public boolean unloadResources() { + var result = false; + if (mergedModelResource != null) { + this.logDebugMsg("Merged model resource exists, unloading it now"); + result = this.resHelper.unloadResource(mergedModelResource); + this.logDebugMsg(String.format("%s merged model resource at %s", result ? "Unloaded" : "Could not unload", + mergedModelResource.getURI())); + + } + if (artificialResource != null) { + this.logDebugMsg("Artificial resource exists, unloading it now"); + result = result && this.resHelper.unloadResource(artificialResource); + this.logDebugMsg(String.format("%s artificial resource at %s", result ? "Unloaded" : "Could not unload", + artificialResource.getURI())); + } + return result; + } + + /** + * Only checks whether the merged model resource is loaded, because other + * resources will be automatically loaded on demand. + * + * @return Whether the merged model resource is loaded + */ + public boolean isModelResourceLoaded() { + return this.mergedModelResource != null && this.mergedModelResource.isLoaded(); + } + + /** + * @return Whether all parsed model resources have been loaded. If no resources + * have been parsed, no resource will be loaded. + */ + public boolean loadParsedResources() { + var result = true; + if (mergedModelResource != null && !this.mergedModelResource.isLoaded()) { + this.logDebugMsg("Merged model resource exists, loading it now"); + result = this.resHelper.unloadResource(mergedModelResource); + this.logDebugMsg(String.format("%s merged model resource at %s", result ? "Loaded" : "Could not load", + mergedModelResource.getURI())); + + } + if (artificialResource != null && !this.artificialResource.isLoaded()) { + this.logDebugMsg("Artificial resource exists, unloading it now"); + result = result && this.resHelper.unloadResource(artificialResource); + this.logDebugMsg(String.format("%s artificial resource at %s", result ? "Loaded" : "Could not load", + artificialResource.getURI())); + } + return result; + } + + /** + * Sets the URIs of all parsed resources with respect to the given URI, which + * will be assigned to the parsed model resource that contains all direct + * contents of the model files. + * + * @param newParsedModelResourceURI The new URI of the parsed model resource + * ({@link #getModelResource()} in this case) + */ + public void setModelResourcesURI(URI newParsedModelResourceURI) { + if (mergedModelResource != null) { + mergedModelResource.setURI(newParsedModelResourceURI); + } + if (artificialResource != null) { + artificialResource.setURI(this.getArtificialResourceURI(newParsedModelResourceURI)); + } + } + + /** + * @return The merged model resource, which contains all contents of all + * (directly) parsed model files + */ + public Resource getModelResource() { + return mergedModelResource; + } + + /** + * @return Whether there is a parsed model resource + * ({@link #getModelResource()}) saved in this instance. + */ + public boolean modelResourceExists() { + return this.getModelResource() != null; + } +} From 1b7ac816cd1eb7e3f73cebaa588347d47486bf37 Mon Sep 17 00:00:00 2001 From: AlpTorac Date: Sun, 27 Jul 2025 17:19:26 +0200 Subject: [PATCH 14/72] Implement class for time measurements in parser tests --- .../parser/GeneralTimeMeasurementTag.java | 86 ++++ .../jamopp/parser/ITimeMeasurementTag.java | 21 + .../jamopp/parser/ParserTestTimeMeasurer.java | 383 ++++++++++++++++++ 3 files changed, 490 insertions(+) create mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/GeneralTimeMeasurementTag.java create mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ITimeMeasurementTag.java create mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ParserTestTimeMeasurer.java diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/GeneralTimeMeasurementTag.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/GeneralTimeMeasurementTag.java new file mode 100644 index 0000000000..9f2861d740 --- /dev/null +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/GeneralTimeMeasurementTag.java @@ -0,0 +1,86 @@ +package cipm.consistency.fitests.similarity.jamopp.parser; + +/** + * An enum containing various general-purpose tags that can be used while taking + * time measurements. + * + * @author Alp Torac Genc + */ +public enum GeneralTimeMeasurementTag implements ITimeMeasurementTag { + /** + * A tag meant for time measurements from discovering model source files + */ + DISCOVER_MODEL_RESOURCES, + /** + * A tag meant for time measurements from parsing model resources from model + * source files + */ + PARSE_MODEL_RESOURCE, + /** + * A tag meant for time measurements from loading previously parsed model + * resource files + */ + LOAD_MODEL_RESOURCE, + /** + * A tag meant for time measurements from unloading model resources that are + * loaded + */ + UNLOAD_MODEL_RESOURCE, + /** + * A tag meant for time measurements from saving model resources to physical + * files + */ + SAVE_MODEL_RESOURCE, + /** + * A tag meant for time measurements from deleting previously parsed model + * resource files + */ + DELETE_MODEL_RESOURCE, + /** + * A tag meant for time measurements from accessing model resource instances + * from their cache, or making queries to their cache (such as checking if a + * particular model resource exists) + */ + MODEL_RESOURCE_CACHE_ACCESS, + + /** + * A tag meant for time measurements from the test methods annotated with + * {@link org.junit.jupiter.api.BeforeEach} + */ + TEST_BEFOREEACH, + /** + * A tag meant for time measurements from the test methods annotated with + * {@link org.junit.jupiter.api.AfterEach} + */ + TEST_AFTEREACH, + /** + * A tag meant for time measurements from creating dynamic tests (but not + * running them) + */ + DYNAMIC_TEST_CREATION, + /** + * A tag meant for time measurements from miscellaneous preparation operations + * (except those from {@link #TEST_BEFOREEACH} and {@link #TEST_AFTEREACH} ) in + * tests that cannot be reasonably assigned to a more accurate tag + */ + TEST_OVERHEAD, + + /** + * A tag meant for time measurements from similarity checking. Primarily + * intended for using a similarity checking mechanism on model resource + * instances + */ + SIMILARITY_CHECKING, + /** + * A tag meant for time measurements from comparing model resources, i.e. + * generating a {@link org.eclipse.emf.compare.Comparison} instance for 2 model + * resources. + */ + MODEL_RESOURCE_COMPARISON, + /** + * A tag meant for time measurements from computing expected similarity results + */ + EXPECTED_SIMILARITY_RESULT_COMPUTATION + + ; +} \ No newline at end of file diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ITimeMeasurementTag.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ITimeMeasurementTag.java new file mode 100644 index 0000000000..82bd59b9d8 --- /dev/null +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ITimeMeasurementTag.java @@ -0,0 +1,21 @@ +package cipm.consistency.fitests.similarity.jamopp.parser; + +/** + * A placeholder interface meant to be extended by enums that contain tags for + * taking time measurements.
+ *
+ * The entire purpose of this interface is to allow implementing further enums + * for such tags and to allow them to be integrated. Therefore, this interface + * provides no further functionality, it merely unifies all such tags under a + * super-type.
+ *
+ * It is important to provide this interface, as time measurements may include + * different operations that are important to analyse and may therefore require + * further tags. With the help of this interface, it becomes possible to + * implement user-defined tags for future time measurements and to integrate + * them, without having to modify any pre-existing tags' enums. + * + * @author Alp Torac Genc + */ +public interface ITimeMeasurementTag { +} diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ParserTestTimeMeasurer.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ParserTestTimeMeasurer.java new file mode 100644 index 0000000000..0baaa4155d --- /dev/null +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ParserTestTimeMeasurer.java @@ -0,0 +1,383 @@ +package cipm.consistency.fitests.similarity.jamopp.parser; + +import java.io.BufferedWriter; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.Stack; +import java.util.function.Function; + +import org.apache.commons.lang.time.StopWatch; + +import com.google.gson.GsonBuilder; +import com.google.gson.annotations.Expose; + +/** + * A class for taking time measurements using + * {@link org.apache.commons.lang.time.StopWatch}, and saving them.
+ *
+ * The time measurements taken here are contain no duplications; i.e. if another + * time measurement is taken while a previous time measurement continues (for + * instance, while a method's run time is measured, a new time measurement + * starts for one of its inner method calls), they will be separate.
+ *
+ * Also contains the means to save the time measurements to JSON files using the + * GSON library. While saving the time measurements, the (non-static) attributes + * of this class annotated with {@link com.google.gson.annotations.Expose} will + * be translated to JSON objects and then written to a JSON file. This way, only + * the desired attributes of this class are saved, as opposed to all of them. + * + * @author Alp Torac Genc + */ +public class ParserTestTimeMeasurer { + /** + * The pattern that will be used to transform a date to a string, which will be + * used in the name of the saved measurements file. + */ + private final static DateTimeFormatter filenameTimeFormatter = DateTimeFormatter.ofPattern("dd-MM-yyyy_HH-mm-ss"); + /** + * The pattern that will be used to transform a date to a string, which will be + * written into the saved measurements file. + */ + private final static DateTimeFormatter fileContentTimeFormatter = DateTimeFormatter.ISO_DATE_TIME; + /** + * The only instance of this class. + */ + private static ParserTestTimeMeasurer instance; + + /** + * The time, when the first time measurement starts via + * {@link #startTimeMeasurement(String, ITimeMeasurementTag)}. + */ + private LocalDateTime startTime; + + /** + * The time, when taking time measurements ends via + * {@link #finishTimeMeasuring()}. + */ + private LocalDateTime endTime; + + /** + * The string representation of {@link #startTime}, which will be written into + * the saved measurements file. + */ + @Expose + private String startTimeString; + + /** + * The string representation of {@link #endTime}, which will be written into the + * saved measurements file. + */ + @Expose + private String endTimeString; + + /** + * The name of the tool that is used for taking time measurements. Only declared + * in order to include it to the time measurement file. + */ + @Expose + private final String timeMeasurer = StopWatch.class.getName(); + /** + * The time unit in time measurements. Only declared in order to include it to + * the time measurement file. + */ + @Expose + private final String timeUnit = "Milliseconds (ms)"; + + /** + * The sum of all taken time measurements. + */ + @Expose + private Long overallRunTime; + + /** + * Contains the sum of time measurements for individual tags in + * {@link #overallRunTime}. Only declared in order to include it to the time + * measurement file. Should be reset after saving all time measurements, so that + * the values here are not duplicated. + */ + @Expose + private final Map measurementTagSummary = new HashMap(); + + /** + * Contains the proportion of time measurements with certain tags in + * {@link #overallRunTime} (in percentage). Only declared in order to include it + * to the time measurement file. Should be reset after saving all time + * measurements, so that the values here are not duplicated. + */ + @Expose + private final Map measurementTagPercentageSummary = new HashMap(); + + /** + * Contains all time measurements taken. + */ + @Expose + private final Collection measurements = new ArrayList(); + + /** + * A stack that contains all StopWatch instances that are used during + * performance measurement. The reason to use a stack here is, there are cases, + * where methods make calls to other methods and their run times overlap. By + * suspending the outer method's StopWatch and pushing a new StopWatch onto the + * stack, the inner methods' run times can be measured accurately. Then the new + * StopWatch can be popped and stopped to get the run time of the inner method. + * Finally, the outer method's StopWatch can be resumed to resume the time + * measurement. + */ + private final Stack watches = new Stack(); + + private ParserTestTimeMeasurer() { + } + + /** + * @return The only instance of this class. + */ + public static ParserTestTimeMeasurer getInstance() { + if (instance == null) + instance = new ParserTestTimeMeasurer(); + return instance; + } + + /** + * Starts measuring the time for a certain purpose given via the parameters. If + * another time measurement is ongoing (i.e. if this method is called multiple + * times without {@link #stopTimeMeasurement()} calls in between), the previous + * time measurement is paused until the new time measurement is stopped via + * {@link #stopTimeMeasurement()}.
+ *
+ * This method is to be seen as the opening bracket for the closing bracket + * {@link #stopTimeMeasurement()} such that the time elapsed while executing the + * lines between this method call and that method call is the time measurement. + * Not using them similar to brackets will result in problems.
+ *
+ * + * @param key The key of the taken time measurement, which describes what the + * time measurement is taken from + * @param tag The tag of the time measurement, which is used to group time + * measurements + */ + public void startTimeMeasurement(String key, ITimeMeasurementTag tag) { + if (this.startTime == null) { + this.startTime = LocalDateTime.now(); + this.startTimeString = fileContentTimeFormatter.format(this.startTime); + } + + /* + * Suspends the potential outer method's Stopwatch, so that time measurements do + * not overlap + */ + if (!watches.isEmpty()) { + var outerMethodWatch = watches.peek(); + outerMethodWatch.suspend(); + } + + var currentMethodWatch = new StopWatch(); + + this.measurements.add(new TimeMeasurementEntry(currentMethodWatch, key, tag)); + + watches.push(currentMethodWatch); + currentMethodWatch.start(); + } + + /** + * Stops the most recently started time measurement (via + * {@link #startTimeMeasurement(String, ITimeMeasurementTag)}). If the most + * recent time measurement paused a previous time measurement, it is resumed. + *
+ *
+ * This method is to be seen as the closing bracket for the opening bracket + * {@link #startTimeMeasurement(String, ITimeMeasurementTag)}, such that the + * time elapsed while executing the lines between that method call and this + * method call is the time measurement. Not using them similar to brackets will + * result in inaccurate measurements.
+ *
+ * If taking time measurements should end altogether, use + * {@link #finishTimeMeasuring()} instead. + */ + public void stopTimeMeasurement() { + var currentMethodWatch = watches.pop(); + currentMethodWatch.stop(); + + /* + * Resumes the potential outer method's Stopwatch, which was previously + * suspended + */ + if (!watches.isEmpty()) { + watches.peek().resume(); + } + } + + /** + * Signals that taking time measurements is over and the taken time measurements + * should be processed.
+ *
+ * If a singular time measurement should be stopped, use + * {@link #stopTimeMeasurement()} instead. + */ + public void finishTimeMeasuring() { + if (this.endTime == null) { + this.endTime = LocalDateTime.now(); + this.endTimeString = fileContentTimeFormatter.format(LocalDateTime.now()); + } + + this.measurements.forEach((m) -> m.computeTime()); + } + + /** + * Ends taking time measurements, if not already done, then processes all taken + * time measurements. Finally, saves all taken time measurements, as well as + * their summaries represented by certain attributes of this instance, at the + * given path, in a JSON file. + * + * @param measurementsSavePath The absolute path, at which all taken time + * measurements should be saved. + */ + public void save(Path measurementsSavePath) { + this.finishTimeMeasuring(); + this.summariseTimeMeasurements(); + + var filePath = measurementsSavePath.resolve(this.getFullFileName()); + + // Ensure that all necessary parent directories exist prior to saving + measurementsSavePath.toFile().mkdirs(); + + var gson = new GsonBuilder().setPrettyPrinting().excludeFieldsWithoutExposeAnnotation().create(); + try (BufferedWriter writer = Files.newBufferedWriter(filePath); var gsonWriter = gson.newJsonWriter(writer)) { + gson.toJson(this, this.getClass(), gsonWriter); + } catch (IOException e) { + e.printStackTrace(); + throw new IllegalArgumentException( + String.format("Could not save the expected similarity results at %s", filePath), e); + } + + /* + * Reset the summary maps after having saved, as the values of their entries + * will contain duplicated measurements otherwise. + */ + this.clearSummaryMaps(); + } + + /** + * @return The name (with file extension) of the measurements file that will be + * saved. + */ + private String getFullFileName() { + var fileExtension = ".json"; + return String.format("%s___%s%s", filenameTimeFormatter.format(this.startTime), + filenameTimeFormatter.format(this.endTime), fileExtension); + } + + /** + * Cleans all values derived from the taken time measurements, so that no time + * measurement is duplicated while computing them. + */ + private void clearSummaryMaps() { + measurementTagSummary.clear(); + measurementTagPercentageSummary.clear(); + } + + /** + * Summarises all taken time measurements by grouping them based on the given + * key, and then by summing all entries in each group. + * + * @param The type of the key, based on which taken time entries are + * to be grouped + * @param summaryMap A map, which will contain the summary of all taken time + * measurements based on the foreseen key + * @param keyAccess A function for deriving the key, which will be used to + * split taken time measurements, from their entries. + */ + private void summariseTimeMeasurements(Map summaryMap, Function keyAccess) { + for (var measurementEntry : this.measurements) { + var key = keyAccess.apply(measurementEntry); + var measurement = measurementEntry.getMillis(); + + if (summaryMap.containsKey(key)) { + var summaryEntry = summaryMap.get(key); + summaryMap.replace(key, summaryEntry + measurement); + } else { + summaryMap.put(key, measurement); + } + } + } + + /** + * Summarises all taken time measurements and puts the derived values into the + * foreseen Map-based attributes of this class. + */ + private void summariseTimeMeasurements() { + this.summariseTimeMeasurements(this.measurementTagSummary, TimeMeasurementEntry::getTag); + + this.overallRunTime = this.measurementTagSummary.values().stream().reduce(Long.valueOf(0), (t1, t2) -> t1 + t2); + + this.measurementTagSummary.entrySet().forEach((e) -> this.measurementTagPercentageSummary.put(e.getKey(), + String.format("%.2f", (e.getValue().doubleValue() / overallRunTime.doubleValue()) * 100))); + } + + /** + * A class that encapsulates singular time measurements. + * + * @author Alp Torac Genc + */ + private class TimeMeasurementEntry { + private StopWatch watch; + + @Expose + private Long millis; + + @Expose + private final String key; + @Expose + private final ITimeMeasurementTag tag; + + /** + * @param watch An object that keeps track of the start and end time of the time + * measurement. The start and end times of this time measurement + * are provided indirectly through this parameter, as it may be + * necessary to pause and resume this time measurement. + * @param key The key of the time measurement, which describes its purpose + * further + * @param tag The tag of the time measurement, which can be used for a + * high-level grouping of time measurements based on what they are + * taken from + */ + private TimeMeasurementEntry(StopWatch watch, String key, ITimeMeasurementTag tag) { + this.watch = watch; + this.tag = tag; + this.key = key; + } + + public Long getMillis() { + return millis; + } + + public String getKey() { + return key; + } + + public ITimeMeasurementTag getTag() { + return tag; + } + + public StopWatch getWatch() { + return watch; + } + + /** + * Computes the actual time value of this time measurement using + * {@link #getWatch()} + */ + public void computeTime() { + if (this.watch != null) { + this.millis = Long.valueOf(this.watch.getTime()); + this.watch = null; + } + } + } +} From e46019c2e14e7d644a296c16f4d2a65b7847b022 Mon Sep 17 00:00:00 2001 From: AlpTorac Date: Sun, 27 Jul 2025 17:20:19 +0200 Subject: [PATCH 15/72] Implement class for discovering model source file directories --- .../parser/IModelDirDiscoveryStrategy.java | 48 +++++++ .../parser/ModelDirDiscoveryStrategy.java | 117 ++++++++++++++++++ 2 files changed, 165 insertions(+) create mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/IModelDirDiscoveryStrategy.java create mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ModelDirDiscoveryStrategy.java diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/IModelDirDiscoveryStrategy.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/IModelDirDiscoveryStrategy.java new file mode 100644 index 0000000000..fcbe38f918 --- /dev/null +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/IModelDirDiscoveryStrategy.java @@ -0,0 +1,48 @@ +package cipm.consistency.fitests.similarity.jamopp.parser; + +import java.io.File; +import java.nio.file.Path; +import java.util.Collection; + +/** + * An interface for classes meant to find model directories. How models' source + * files' directories are discovered and filtered depends on the concrete + * implementor.
+ *
+ * Implemented minimally, as discovering model directories may span across + * multiple "root" directories, and may have to be adapted heavily for concrete + * scenarios. + * + * @author Alp Torac Genc + */ +public interface IModelDirDiscoveryStrategy { + /** + * Finds and returns paths to all parent directories, which have nested model + * source file directories. Use {@link #discoverModelSourceDirs(File)} on the + * directories found here to get the actual model source file directories. + * + * @param dirToDiscover The top-most directory, whose contents will be scanned + * + * @return All parent directories containing model source file directories that + * are found according to the concrete implementor. + */ + public Collection discoverModelSourceParentDirs(File dirToDiscover); + + /** + * Finds and returns paths to all model source file directories. + * + * @param dirToDiscover The top-most directory, whose contents will be scanned + * + * @return All model source file directories that are found according to the + * concrete implementor + */ + public Collection discoverModelSourceDirs(File dirToDiscover); + + /** + * @param dir A directory that potentially contains source files of one (and + * only one) model + * @return Whether the given directory is contains source files of one (and only + * one) model + */ + public boolean isModelSourceDirectory(File dir); +} diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ModelDirDiscoveryStrategy.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ModelDirDiscoveryStrategy.java new file mode 100644 index 0000000000..8a56793cee --- /dev/null +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ModelDirDiscoveryStrategy.java @@ -0,0 +1,117 @@ +package cipm.consistency.fitests.similarity.jamopp.parser; + +import java.io.File; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collection; +import java.util.function.Predicate; + +/** + * A model directory discovery strategy, which considers one top-most directory + * and discovers its contents for model directories, similar to depth first + * search but with a single start point. Uses a given filter to determine + * whether a given directory encompasses one (and only one) model. + * + * @author Alp Torac Genc + */ +public class ModelDirDiscoveryStrategy implements IModelDirDiscoveryStrategy { + private Predicate modelDirFilter; + + /** + * Constructs an instance. + * + * @param modelDirFilter A filter for determining whether a given directory + * encompasses one (and only one) model + */ + public ModelDirDiscoveryStrategy(Predicate modelDirFilter) { + this.modelDirFilter = modelDirFilter; + } + + /** + * @param modelParentDirPath A parent directory, which potentially contains + * model source file directories + * @return All model source file directories under the given path + * + * @see {@link #isModelSourceDirectory(File)} + */ + protected Collection getAllModelDirsUnder(Path modelParentDirPath) { + var result = new ArrayList(); + var dirs = modelParentDirPath.toFile().listFiles(); + for (var dir : dirs) { + if (this.isModelSourceDirectory(dir)) { + result.add(dir.toPath()); + } + } + return result; + } + + /** + * @implSpec Determines whether a discovered directory is a model source file + * directory using the filter from the constructor + * ({@link #ModelDirDiscoveryStrategy(Path, Predicate)}). Any + * directory that is considered a model source file directory is + * assumed to encapsulate one (and only one) model, even if it + * contains multiple models in reality. + */ + @Override + public boolean isModelSourceDirectory(File dir) { + if (this.modelDirFilter == null) { + return true; + } else { + return this.modelDirFilter.test(dir); + } + } + + /** + * Recursively searches for directories containing Java-Model files, starting + * from the given directory, and returns a list of all such directories. + */ + protected Collection discoverModels(File dirToDiscover) { + var foundModelDirs = new ArrayList(); + discoverModels(dirToDiscover, foundModelDirs); + return foundModelDirs; + } + + /** + * Recursively searches for directories that contain model source files. All + * directories containing models (determined via + * {@link #isModelSourceDirectory(File)}) will be added to foundModelDirs, if + * not already there. + * + * @param dirToDiscover The directory, where the recursive search will begin + * @param foundModelDirs A collection of model source file directories + */ + protected void discoverModels(File dirToDiscover, Collection foundModelDirs) { + if (dirToDiscover != null && dirToDiscover.isDirectory()) { + var discovered = new ArrayList(); + + for (var f : dirToDiscover.listFiles()) { + if (!this.isModelSourceDirectory(f)) { + discovered.add(f); + } else if (!foundModelDirs.contains(dirToDiscover.toPath())) { + foundModelDirs.add(dirToDiscover.toPath()); + } + } + + discovered.forEach((d) -> discoverModels(d, foundModelDirs)); + } + } + + /** + * @implSpec Check {@link #isModelSourceDirectory(File)} for more details on how + * model directories are filtered. + */ + @Override + public Collection discoverModelSourceDirs(File dirToDiscover) { + return this.getAllModelDirsUnder(dirToDiscover.toPath()); + } + + /** + * @implSpec Check {@link #isModelSourceDirectory(File)} for more details on how + * model directories are filtered. + */ + @Override + public Collection discoverModelSourceParentDirs(File dirToDiscover) { + return this.discoverModels(dirToDiscover); + } +} From b4f1c84fbbfb139bcf3c050360b9344a2a498c97 Mon Sep 17 00:00:00 2001 From: AlpTorac Date: Sun, 27 Jul 2025 17:21:27 +0200 Subject: [PATCH 16/72] Implement class for generating dynamic parser tests --- ...ractJaMoPPParserSimilarityTestFactory.java | 103 ++++++++++++++++++ .../EAllContentSimilarityTestFactory.java | 72 ++++++++++++ 2 files changed, 175 insertions(+) create mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/AbstractJaMoPPParserSimilarityTestFactory.java create mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/EAllContentSimilarityTestFactory.java diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/AbstractJaMoPPParserSimilarityTestFactory.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/AbstractJaMoPPParserSimilarityTestFactory.java new file mode 100644 index 0000000000..17a908184d --- /dev/null +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/AbstractJaMoPPParserSimilarityTestFactory.java @@ -0,0 +1,103 @@ +package cipm.consistency.fitests.similarity.jamopp.parser; + +import java.nio.file.Path; + +import org.eclipse.emf.ecore.resource.Resource; +import org.junit.jupiter.api.DynamicNode; + +/** + * An abstract class meant to be implemented by classes that encapsulate logic + * about dynamic test generation. + * + * @author Alp Torac Genc + */ +public abstract class AbstractJaMoPPParserSimilarityTestFactory { + /** + * Do not set it here (via {@code #getDefaultExpectedSimilarityResultProvider()} + * for instance), because the concrete implementor may need prior + * initialisation. + * + * @see {@link #getExpectedSimilarityResultProvider()} + */ + private IExpectedSimilarityResultProvider resultProvider; + + /** + * Since there should always be a way to determine the expected similarity + * results, this method is implemented to provide a default way to do so.
+ *
+ * Defaults to {@link ResourceReferenceEqualitySimilarityResultProvider}.
+ *
+ * Can be overridden in concrete implementors to better align the return value + * with their intents. + * + * @return The default object that provides expected similarity results to + * dynamic tests. + */ + public IExpectedSimilarityResultProvider getDefaultExpectedSimilarityResultProvider() { + return new ResourceReferenceEqualitySimilarityResultProvider(); + } + + /** + * @return The object that provides expected similarity results to dynamic + * tests. If it is currently not set (i.e. it is null), sets it to + * {@link #getDefaultExpectedSimilarityResultProvider()} and then + * returns. + */ + public IExpectedSimilarityResultProvider getExpectedSimilarityResultProvider() { + if (this.resultProvider == null) + this.resultProvider = this.getDefaultExpectedSimilarityResultProvider(); + + return this.resultProvider; + } + + /** + * Changes how this instance provides expected similarity values to the dynamic + * tests it generates.
+ *
+ * If the given provider is null, sets the current provider to + * {@link #getDefaultExpectedSimilarityResultProvider()} instead, as there must + * always be a way to determine expected similarity results. + */ + public void setExpectedSimilarityResultProvider(IExpectedSimilarityResultProvider resultProvider) { + this.resultProvider = resultProvider; + + if (this.resultProvider == null) + this.resultProvider = this.getDefaultExpectedSimilarityResultProvider(); + } + + /** + * Defaults to the name of the concrete implementing type. Can be overridden in + * concrete implementors for a more accurate description. + * + * @return A description for this test generation strategy, which may be added + * to test descriptions. + */ + public String getTestDescription() { + return this.getClass().getSimpleName(); + } + + /** + * Delegates computing the expected similarity result to the underlying + * provider. + * + * @see {@link #getExpectedSimilarityResultProvider()} + */ + public boolean getExpectedSimilarityResultFor(Resource lhsRes, Path lhsResPath, Resource rhsRes, Path rhsResPath) { + ParserTestTimeMeasurer.getInstance().startTimeMeasurement( + this.getExpectedSimilarityResultProvider().getClass().getSimpleName(), + GeneralTimeMeasurementTag.EXPECTED_SIMILARITY_RESULT_COMPUTATION); + var result = this.getExpectedSimilarityResultProvider().getExpectedSimilarityResultFor(lhsRes, lhsResPath, + rhsRes, rhsResPath); + ParserTestTimeMeasurer.getInstance().stopTimeMeasurement(); + return result; + } + + /** + * The provided model resources are not assumed to have a certain order here, + * because the concrete implementor could change what resources are checked for + * similarity in which order. + * + * @return Dynamic tests generated based on the concrete implementor. + */ + public abstract DynamicNode createTestsFor(Resource res1, Path path1, Resource res2, Path path2); +} diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/EAllContentSimilarityTestFactory.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/EAllContentSimilarityTestFactory.java new file mode 100644 index 0000000000..44ef9124a2 --- /dev/null +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/EAllContentSimilarityTestFactory.java @@ -0,0 +1,72 @@ +package cipm.consistency.fitests.similarity.jamopp.parser; + +import java.nio.file.Path; +import java.util.ArrayList; + +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.resource.Resource; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.DynamicNode; +import org.junit.jupiter.api.DynamicTest; + +import cipm.consistency.fitests.similarity.ISimilarityCheckerContainer; + +/** + * A test class factory, which generates dynamic tests that check the similarity + * of all contents ({@code res.getAllContents()}) of the given Resources + * {@code res1, res2} pairwise. + * + * @author Alp Torac Genc + */ +public class EAllContentSimilarityTestFactory extends AbstractJaMoPPParserSimilarityTestFactory { + private static final String description = "areSimilar on eAllContents"; + + private ISimilarityCheckerContainer scc; + + public EAllContentSimilarityTestFactory(ISimilarityCheckerContainer scc) { + this.scc = scc; + } + + /** + * Checks whether the given {@link Resource} instances are similar, based on + * {@code res_i.getAllContents()}. The order of the direct contents is also + * considered and will impact the result. + */ + protected void testSimilarityOfAllContents(Resource res1, Resource res2, Boolean expectedResult) { + ParserTestTimeMeasurer.getInstance().startTimeMeasurement(this.getClass().getSimpleName(), + GeneralTimeMeasurementTag.TEST_OVERHEAD); + var list1 = new ArrayList(); + var list2 = new ArrayList(); + + res1.getAllContents().forEachRemaining((o) -> list1.add(o)); + res2.getAllContents().forEachRemaining((o) -> list2.add(o)); + + ParserTestTimeMeasurer.getInstance().startTimeMeasurement(this.getClass().getSimpleName(), + GeneralTimeMeasurementTag.SIMILARITY_CHECKING); + Assertions.assertEquals(expectedResult, this.scc.areSimilar(list1, list2)); + ParserTestTimeMeasurer.getInstance().stopTimeMeasurement(); + ParserTestTimeMeasurer.getInstance().stopTimeMeasurement(); + } + + /** + * Ensures that all contents of the parsed models are only then similar + * (accounting for their order too), if the content of their source files are + * equal (in terms of code, not whitespace nor comments etc.). + */ + @Override + public DynamicNode createTestsFor(Resource res1, Path path1, Resource res2, Path path2) { + return DynamicTest.dynamicTest(String.format("%s vs %s", path1.getFileName(), path2.getFileName()), () -> { + this.testSimilarityOfAllContents(res1, res2, this.getExpectedSimilarityResultFor(res1, path1, res2, path2)); + }); + } + + @Override + public String getTestDescription() { + return description; + } + + @Override + public IExpectedSimilarityResultProvider getDefaultExpectedSimilarityResultProvider() { + return new FileContentSimilarityResultProvider(); + } +} From 3be533085bc5771452f72fa50579cf8cbf8a324e Mon Sep 17 00:00:00 2001 From: AlpTorac Date: Sun, 27 Jul 2025 17:22:48 +0200 Subject: [PATCH 17/72] Implement class for generating index sequences The idea is to spare multiple test classes for the same test repository. With this interface it is possible to just have a list of commits and then to iterate them in certain ways. --- .../IJaMoPPParserTestGenerationStrategy.java | 46 +++++++++++ ...metricIterationTestGenerationStrategy.java | 80 +++++++++++++++++++ 2 files changed, 126 insertions(+) create mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/IJaMoPPParserTestGenerationStrategy.java create mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ReflexiveSymmetricIterationTestGenerationStrategy.java diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/IJaMoPPParserTestGenerationStrategy.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/IJaMoPPParserTestGenerationStrategy.java new file mode 100644 index 0000000000..b92d7c0c8a --- /dev/null +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/IJaMoPPParserTestGenerationStrategy.java @@ -0,0 +1,46 @@ +package cipm.consistency.fitests.similarity.jamopp.parser; + +import java.util.Iterator; + +/** + * An interface meant for classes that encapsulate the logic on how to iterate + * through the given Resource array, while generating dynamic tests.
+ *
+ * Does not directly generate dynamic tests, because the order of elements may + * matter for other concerns as well. Therefore, implementors of this interface + * are meant to return an order via customised {@link Iterator}s, and not the + * desired dynamic tests. + * + * @author Alp Torac Genc + */ +public interface IJaMoPPParserTestGenerationStrategy { + /** + * Returns an iterator that denotes the order of dynamic test generation the + * concrete implementor uses. The returned iterator {@code it} will return an + * int array of size 2 upon {@code idxs = it.next()}, until all intended dynamic + * tests are generated. Ints stored in {@code idxs} stand for the indices of + * elements in resArr and pathArr, which are to be used in the current dynamic + * test. In other words, the current dynamic test will use the + * {@code idxs[0]}-th elements for the left hand side (lhs) and + * {@code idxs[1]}-th elements for the right hand side in the current dynamic + * test. + * + * @param testResourceCount The amount of test resources that are present. Used + * to mark when the returned iterator finishes, + * depending on its implementation. + * @return An iterator that denotes which test resources will be used in which + * order. + */ + public Iterator getTestResourceIterator(int testResourceCount); + + /** + * Defaults to the name of the concrete implementing type. Can be overridden in + * concrete implementors for a more accurate description. + * + * @return A description for this test generation strategy, which may be added + * to test descriptions. + */ + public default String getTestGenerationStrategyDescription() { + return this.getClass().getSimpleName(); + } +} diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ReflexiveSymmetricIterationTestGenerationStrategy.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ReflexiveSymmetricIterationTestGenerationStrategy.java new file mode 100644 index 0000000000..0856acef24 --- /dev/null +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ReflexiveSymmetricIterationTestGenerationStrategy.java @@ -0,0 +1,80 @@ +package cipm.consistency.fitests.similarity.jamopp.parser; + +import java.util.Iterator; + +/** + * An implementation of {@link IJaMoPPParserTestGenerationStrategy} that + * provides an iterator, which denotes a linear and symmetric index sequence for + * test resources. + * + * @author Alp Torac Genc + */ +public class ReflexiveSymmetricIterationTestGenerationStrategy implements IJaMoPPParserTestGenerationStrategy { + private final static String description = "reflexive symmetric iteration strategy"; + + /** + * @implSpec Returns an iterator that helps generate dynamic tests by using test + * resources in an iterative, reflexive, symmetric way. If + * {@code testResourceCount = 3}, then the order denoted by the + * returned iterator will be as follows, where {@code (i, j)} stands + * for the indices of test resources that will be used in the current + * test:
+ *
+ * {@code (0,0); (0,1); (1,0); (1,1); (1,2); (2,1); (2,2)} + * @implNote Assuming both arrays' length is {@code N}, then the returned + * iterator iterates {@code 3*N} times. As such, a maximum of + * {@code 3*N} dynamic tests can be generated. + */ + @Override + public Iterator getTestResourceIterator(int testResourceCount) { + return new Iterator() { + private int currentIdx = 0; + /** + * Denotes the elements' order:
+ *
+ *
    + *
  • 1: Forward iteration (currentIdx, currentIdx + 1) + *
  • 0: In-place (currentIdx, currentIdx) + *
  • -1: Reverse iteration (currentIdx + 1, currentIdx) + *
+ */ + private byte status = 0; + + @Override + public boolean hasNext() { + return (status == 0 && currentIdx < testResourceCount) || (currentIdx < testResourceCount - 1); + } + + @Override + public int[] next() { + int[] result = null; + + switch (status) { + case 0: + result = new int[] { currentIdx, currentIdx }; + status = 1; + break; + case 1: + result = new int[] { currentIdx, currentIdx + 1 }; + status = -1; + break; + case -1: + result = new int[] { currentIdx + 1, currentIdx }; + status = 0; + ++currentIdx; + break; + default: + throw new IllegalStateException("Undefined state reached"); + } + + return result; + } + + }; + } + + @Override + public String getTestGenerationStrategyDescription() { + return description; + } +} From e29d77bb4c370ba1bc8b3ee8f7d67fe2cfcd2110 Mon Sep 17 00:00:00 2001 From: AlpTorac Date: Sun, 27 Jul 2025 17:23:35 +0200 Subject: [PATCH 18/72] Implement class for storing parsed Resource instances --- .../similarity/jamopp/parser/CacheUtil.java | 99 +++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/CacheUtil.java diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/CacheUtil.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/CacheUtil.java new file mode 100644 index 0000000000..ed3836daec --- /dev/null +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/CacheUtil.java @@ -0,0 +1,99 @@ +package cipm.consistency.fitests.similarity.jamopp.parser; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.emf.ecore.resource.Resource; + +/** + * A utility object, which encapsulates caching logic (for parsed models) and + * can be used to hasten tests.
+ *
+ * Only used to contain {@link Resource} instances with String keys. Does not + * process the given resources in any other way, such as unloading or removing + * them. + * + * @author Alp Torac Genc + */ +public class CacheUtil { + private Map resourceCache; + + public CacheUtil() { + this.resourceCache = this.initResourceCache(); + } + + /** + * This is used from within the constructor. + * + * @return The underlying map, which will be used to store the parsed models. + */ + protected Map initResourceCache() { + return new HashMap<>(); + } + + /** + * Intended to be used from its future sub-classes (if any). + * + * @return The underlying data structure that is used for caching. + */ + protected Map getResourceCache() { + return this.resourceCache; + } + + /** + * Adds the given resource wrapper with the given key to the cache. Replaces the + * resource, if the key is already in the cache. + * + * @param key The key associated with the given resource wrapper + * @param res A given resource + */ + public void addToCache(String key, IModelResourceWrapper res) { + this.getResourceCache().put(key, res); + } + + /** + * @return Gets the wrapper of the resource associated with the given key from + * the cache. Null, if there is no such key in the cache. + */ + public IModelResourceWrapper getFromCache(String key) { + return this.getResourceCache().get(key); + } + + /** + * @return Wrappers of all cached resources, without their corresponding keys + */ + public Collection getCachedResources() { + return new ArrayList(this.getResourceCache().values()); + } + + /** + * @return All contents of the underlying cache (i.e. cached resources and their + * corresponding keys) + */ + public Map getAllCacheContent() { + return new HashMap(this.getResourceCache()); + } + + /** + * @return Whether the given key is present in the cache. + */ + public boolean isInCache(String key) { + return this.getResourceCache().containsKey(key); + } + + /** + * Removes the cached resource associated with the given key. + */ + public void removeFromCache(String key) { + this.getResourceCache().remove(key); + } + + /** + * Removes all entries from the cache. + */ + public void cleanCache() { + this.getResourceCache().clear(); + } +} From f8f20a4ec57f928f742d6c21c19a61716555b574 Mon Sep 17 00:00:00 2001 From: AlpTorac Date: Sun, 27 Jul 2025 17:24:10 +0200 Subject: [PATCH 19/72] Implement class for containing parser test options --- .../jamopp/parser/ParserTestOptions.java | 60 +++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ParserTestOptions.java diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ParserTestOptions.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ParserTestOptions.java new file mode 100644 index 0000000000..1128bd8067 --- /dev/null +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ParserTestOptions.java @@ -0,0 +1,60 @@ +package cipm.consistency.fitests.similarity.jamopp.parser; + +import cipm.consistency.fitests.similarity.eobject.ResourceTestOptions; + +/** + * A class that contains various options for test classes that parse + * {@link Resource} instances and cache them: + *
    + *
  • shouldSaveCachedResources: Whether the cached resources should be saved + * after tests + *
  • shouldRemoveResourcesFromCache: Whether cached resources should be + * removed after each test deleted after tests + *
+ * + * @see {@link ResourceTestOptions} for other options + * @author Alp Torac Genc + */ +public class ParserTestOptions extends ResourceTestOptions { + private boolean shouldSaveCachedResources; + private boolean shouldRemoveResourcesFromCache; + + /** + * @see {@link ParserTestOptions} + */ + public void setShouldSaveCachedResources(boolean shouldSaveCachedResources) { + this.shouldSaveCachedResources = shouldSaveCachedResources; + } + + /** + * @see {@link ParserTestOptions} + */ + public void setShouldRemoveResourcesFromCache(boolean shouldRemoveResourcesFromCache) { + this.shouldRemoveResourcesFromCache = shouldRemoveResourcesFromCache; + } + + /** + * @see {@link ParserTestOptions} + */ + public boolean shouldSaveCachedResources() { + return shouldSaveCachedResources; + } + + /** + * @see {@link ParserTestOptions} + */ + public boolean shouldRemoveResourcesFromCache() { + return shouldRemoveResourcesFromCache; + } + + /** + * Copies all options from the given instance; i.e. after calling this method, + * all options inside the given instance will override the corresponding options + * in this. + */ + public void copyOptionsFrom(ParserTestOptions opts) { + super.copyOptionsFrom(opts); + this.shouldSaveCachedResources = opts.shouldSaveCachedResources; + this.shouldRemoveResourcesFromCache = opts.shouldRemoveResourcesFromCache; + } +} From e69c31457330ae9b178b69deaeb3be1d0776de8d Mon Sep 17 00:00:00 2001 From: AlpTorac Date: Sun, 27 Jul 2025 17:24:42 +0200 Subject: [PATCH 20/72] Implement class for storing layout information for parser tests --- .../jamopp/parser/ParserTestFileLayout.java | 204 ++++++++++++++++++ 1 file changed, 204 insertions(+) create mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ParserTestFileLayout.java diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ParserTestFileLayout.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ParserTestFileLayout.java new file mode 100644 index 0000000000..4d0dac8dd0 --- /dev/null +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ParserTestFileLayout.java @@ -0,0 +1,204 @@ +package cipm.consistency.fitests.similarity.jamopp.parser; + +import java.io.File; +import java.nio.file.Path; + +import org.eclipse.emf.common.util.URI; + +/** + * Contains layout-related information for the corresponding parser test. + * + * @author Alp Torac Genc + */ +public class ParserTestFileLayout { + /** + * @see {@link #getModelSourceFileRootDirPath()} + */ + private Path modelSourceFileRootDirPath; + /** + * @see {@link #setTestModelResourceFilesSaveDirPath(Path)} + */ + private Path testModelResourceFilesSaveDirPath; + + /** + * @see {@link #setCacheSaveDirPath(Path)} + */ + private Path cacheSaveDirPath; + + /** + * @see {@link #getTimeMeasurementsFileSavePath()} + */ + private Path timeMeasurementsFileSavePath; + + /** + * @see {@link #getModelResourceFileExtension()} + */ + private String modelResourceFileExtension; + + public ParserTestFileLayout() { + } + + /** + * Constructs a new instance and copies the attributes of the given layout + * instance. + */ + public ParserTestFileLayout(ParserTestFileLayout layout) { + this.testModelResourceFilesSaveDirPath = layout.testModelResourceFilesSaveDirPath; + this.cacheSaveDirPath = layout.cacheSaveDirPath; + this.timeMeasurementsFileSavePath = layout.timeMeasurementsFileSavePath; + this.modelResourceFileExtension = layout.modelResourceFileExtension; + } + + /** + * Sets the path to the root folder of the model source file directories, under + * which all models' source file directories reside + */ + public void setModelSourceFileRootDirPath(Path modelSourceFileRootDirPath) { + this.modelSourceFileRootDirPath = modelSourceFileRootDirPath; + } + + /** + * Sets the file extension of the Resource files (if desired to be saved) + */ + public void setModelResourceFileExtension(String modelResourceFileExtension) { + this.modelResourceFileExtension = modelResourceFileExtension; + } + + /** + * @return The file extension of the Resource files (if desired to be saved) + */ + public String getModelResourceFileExtension() { + return this.modelResourceFileExtension; + } + + /** + * Sets the absolute path, at which taken time measurements are to be saved. + */ + public void setTimeMeasurementsFileSavePath(Path timeMeasurementsFileSavePath) { + this.timeMeasurementsFileSavePath = timeMeasurementsFileSavePath; + } + + /** + * Sets up the relative path to the directory, where the contents of the + * resource cache are to be saved (if desired). + * + * @see {@link CacheUtil} + */ + public void setCacheSaveDirPath(Path cacheSaveDirPath) { + this.cacheSaveDirPath = cacheSaveDirPath; + } + + /** + * Sets up the relative path to the {@link #getAbsoluteCurrentDirectory()} + * directory, where parsed model resource files are to be saved (if desired). + */ + public void setTestModelResourceFilesSaveDirPath(Path testModelResourceFilesSaveDirPath) { + this.testModelResourceFilesSaveDirPath = testModelResourceFilesSaveDirPath; + } + + /** + * @param modelDir The path to the model source file directory + * @return The key, with which the model resource parsed under the given path + * will be added to the cache. + */ + public String getCacheKeyForModelSourceFileDir(Path modelDir) { + return this.getAbsoluteCurrentDirectory().relativize(modelDir).toString(); + } + + /** + * @return The absolute path, at which taken time measurements are to be saved. + */ + public Path getTimeMeasurementsFileSavePath() { + return this.getAbsoluteCurrentDirectory().resolve(timeMeasurementsFileSavePath); + } + + /** + * @return The absolute path, at which all files generated througout the tests + * should be saved. + */ + public Path getTestFilesSavePath() { + return this.getAbsoluteCurrentDirectory().resolve(testModelResourceFilesSaveDirPath); + } + + /** + * @param modelDir The path to a directory, which has files for one (and only + * one) model + * @return The path (as String), where the parsed model resource (for the model + * under the given path) should be saved, if desired. + */ + public String getModelResourcePathFor(Path modelDir) { + var modelSubPath = this.getAbsoluteCurrentDirectory().relativize(modelDir); + var resPath = this.getModelResourceSaveRootDirectory().resolve(modelSubPath); + + var resPathString = resPath.toString(); + + // Check if the resource path has a file extension + // If not, append the file extension for it + if (!resPath.getFileName().toString().contains(".")) { + resPathString += "." + this.modelResourceFileExtension; + } + + return resPathString; + } + + /** + * @param modelDir The path to a directory, which has files for one (and only + * one) model + * @return The physical URI of the model resource parsed from the model at the + * given path. + */ + public URI getModelResourceURI(Path modelDir) { + return URI.createFileURI(this.getModelResourcePathFor(modelDir)); + } + + /** + * Defaults to {@link #getAbsoluteCurrentDirectory()}. + * + * @return Path to the root folder of the model source file directories, under + * which all models' source file directories reside + */ + public Path getModelSourceFileRootDirPath() { + return this.modelSourceFileRootDirPath; + } + + /** + * @return The root directory, under which generated test resources will be + * saved. + */ + public Path getModelResourceSaveRootDirectory() { + return this.getAbsoluteCurrentDirectory().resolve(cacheSaveDirPath); + } + + /** + * @return The relative path between the current directory and the root + * directory ({@link #getModelSourceFileRootDirPath()}). + * @see {@link #getModelSourceFileRootDirPath()} + */ + public Path getRelativeModelSourceFileRootDirPath() { + return this.getAbsoluteCurrentDirectory().relativize(this.getModelSourceFileRootDirPath()); + } + + /** + * @param modelParentDirPath The parent directory for a group of models, which + * contains other directories that contain model + * files. + * @return The relative path between ({@link #getModelSourceFileRootDirPath()}) + * and the given path. If both paths are the same, returns the file name + * (without extension) in the parameter. + */ + public Path getRelativeModelSourceParentDirPath(Path modelParentDirPath) { + var rootPath = this.getModelSourceFileRootDirPath(); + var relPath = rootPath.relativize(modelParentDirPath); + if (relPath.getParent() == null) { + return modelParentDirPath.getFileName(); + } + return relPath; + } + + /** + * @return The current (absolute) position within the file system. + */ + private Path getAbsoluteCurrentDirectory() { + return new File("").getAbsoluteFile().toPath(); + } +} From 5c38b390e4804198dc90ad001e817422885f24d2 Mon Sep 17 00:00:00 2001 From: AlpTorac Date: Sun, 27 Jul 2025 17:26:48 +0200 Subject: [PATCH 21/72] Implement abstract test class for parser tests It contains a template method @TestFactory createTests(...) for generating dynamic parser tests. This way, dynamic test generation can be re-used in future repository parser tests. --- .../AbstractJaMoPPParserSimilarityTest.java | 569 ++++++++++++++++++ 1 file changed, 569 insertions(+) create mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/AbstractJaMoPPParserSimilarityTest.java diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/AbstractJaMoPPParserSimilarityTest.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/AbstractJaMoPPParserSimilarityTest.java new file mode 100644 index 0000000000..afd596ecfe --- /dev/null +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/AbstractJaMoPPParserSimilarityTest.java @@ -0,0 +1,569 @@ +package cipm.consistency.fitests.similarity.jamopp.parser; + +import java.io.File; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; + +import org.eclipse.emf.common.util.URI; +import org.eclipse.emf.ecore.resource.Resource; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DynamicContainer; +import org.junit.jupiter.api.DynamicNode; +import org.junit.jupiter.api.TestFactory; + +import cipm.consistency.fitests.similarity.jamopp.AbstractJaMoPPSimilarityTest; + +/** + * An abstract test class, which can be used for implementing tests that involve + * parsing models from Java-related files and checking their similarity.
+ *
+ * It does not include any hard-coded model source file directory to allow + * models at different locations to be usable in tests. If there is a group of + * model source file directories, it is recommended to make an abstract test + * class for them, in order to store details about the common sub-path of those + * models and details on what directories contain model source files. + * + * @author Alp Torac Genc + * + * @see {@link #createTests()} + */ +public abstract class AbstractJaMoPPParserSimilarityTest extends AbstractJaMoPPSimilarityTest { + + /** + * An object that caches and grants access to the parsed models, which were + * cached after being parsed.
+ *
+ * Make sure that it persists throughout tests, which are supposed to make use + * of it. + * + * @see {@link #parseModelsDirWithoutCaching(Path)} + * @see {@link #parseModelsDirWithCaching(Path)} + */ + private static final CacheUtil resourceCache = new CacheUtil(); + + private ParserTestFileLayout layout; + + /** + * The relative path to the directory, where parsed model resource files are to + * be saved (if desired). + */ + private static final Path testModelResourceFilesSaveDirPath = Path.of("target", "testResources"); + + /** + * The relative path to the directory, where the contents of + * {@link #resourceCache} are to be saved (if desired). + */ + private static final Path cacheSaveDirPath = testModelResourceFilesSaveDirPath.resolve("testmodel-cache"); + + /** + * The relative path to the directory, where time measurements are to be saved + * (if desired). + */ + private static final Path timeMeasurementsFileSavePath = Path.of("target", "timeMeasurements"); + + /** + * {@inheritDoc}
+ *
+ * {@link AbstractJaMoPPParserSimilarityTest}: Sets up the file layout + * {@link ParserTestFileLayout} + */ + @BeforeEach + @Override + public void setUp() { + this.startTimeMeasurement(GeneralTimeMeasurementTag.TEST_BEFOREEACH); + super.setUp(); + + this.layout = this.initParserTestFileLayout(); + + this.stopTimeMeasurement(); + } + + /** + * {@inheritDoc}
+ *
+ * {@link AbstractJaMoPPParserSimilarityTest}: Performs various operations on + * the model resource files that were parsed in the dynamic tests, according to + * the preferences that are encoded in the methods of this test, such as + * {@link AbstractJaMoPPParserSimilarityTest#shouldSaveCachedResources()}. It + * then saves the time measurements taken during the tests. Note: Since + * dynamic tests are used here, this method will be triggered only once at the + * end of each test method annotated with + * {@link org.junit.jupiter.api.TestFactory}, as opposed to after each dynamic + * test. + */ + @AfterEach + @Override + public void tearDown() { + this.logDebugMsg("Tearing down after parser test"); + + this.startTimeMeasurement(GeneralTimeMeasurementTag.TEST_AFTEREACH); + var cachedResources = resourceCache.getCachedResources(); + + if (this.getResourceTestOptions().shouldSaveCachedResources()) { + this.logDebugMsg("Saving all cached resources after parser test"); + this.startTimeMeasurement(GeneralTimeMeasurementTag.SAVE_MODEL_RESOURCE); + cachedResources.forEach((res) -> res.saveResources()); + this.stopTimeMeasurement(); + this.logDebugMsg("Saved all cached resources after parser test"); + } + + if (this.getResourceTestOptions().shouldDeleteAllResources()) { + this.logDebugMsg("Deleting all cached resources after parser test"); + this.startTimeMeasurement(GeneralTimeMeasurementTag.DELETE_MODEL_RESOURCE); + cachedResources.forEach((res) -> res.deleteResources()); + this.stopTimeMeasurement(); + this.logDebugMsg("Deleted all cached resources after parser test"); + } else if (this.getResourceTestOptions().shouldUnloadAllResources()) { + this.logDebugMsg("Unloading all cached resources after parser test"); + this.startTimeMeasurement(GeneralTimeMeasurementTag.UNLOAD_MODEL_RESOURCE); + cachedResources.forEach((res) -> res.unloadResources()); + this.stopTimeMeasurement(); + this.logDebugMsg("Unloaded all cached resources after parser test"); + } + + if (this.getResourceTestOptions().shouldRemoveResourcesFromCache()) { + this.logDebugMsg("Removing all cached resources from cache after parser test"); + this.startTimeMeasurement(GeneralTimeMeasurementTag.MODEL_RESOURCE_CACHE_ACCESS); + resourceCache.cleanCache(); + this.stopTimeMeasurement(); + this.logDebugMsg("Removed all cached resources from cache after parser test"); + } + + super.tearDown(); + this.stopTimeMeasurement(); + + this.saveTimeMeasurements(); + + this.logDebugMsg("Tore down after parser test"); + } + + protected ParserTestFileLayout initParserTestFileLayout() { + var layout = new ParserTestFileLayout(); + layout.setModelSourceFileRootDirPath(new File("").getAbsoluteFile().toPath()); + layout.setTestModelResourceFilesSaveDirPath(testModelResourceFilesSaveDirPath); + layout.setCacheSaveDirPath(cacheSaveDirPath); + layout.setTimeMeasurementsFileSavePath(timeMeasurementsFileSavePath); + layout.setModelResourceFileExtension(this.getResourceFileExtension()); + return layout; + } + + protected ParserTestFileLayout getTestFileLayout() { + return this.layout; + } + + /** + * Saves the time measurements taken during tests via + * {@code startTimeMeasurement} and {@code stopTimeMeasurement} calls. + */ + protected void saveTimeMeasurements() { + this.logDebugMsg("Saving time measurements"); + ParserTestTimeMeasurer.getInstance().save(this.layout.getTimeMeasurementsFileSavePath()); + this.logDebugMsg("Saved time measurements"); + } + + /** + * A variant of {@link #startTimeMeasurement(String, ITimeMeasurementTag)} for + * individual model source file directories. + */ + protected void startTimeMeasurement(Path modelDir, ITimeMeasurementTag tag) { + this.startTimeMeasurement(modelDir != null ? this.layout.getCacheKeyForModelSourceFileDir(modelDir) : null, + tag); + } + + /** + * Delegates to the time measuring mechanism and signals that a time measurement + * with the given parameters should be started.
+ *
+ * Refer to the documentation of {@link ParserTestTimeMeasurer} for more + * information. + * + * @param key The key of the taken time measurement, which describes what the + * time measurement is taken from + * @param tag The tag of the time measurement, which is used to group time + * measurements + */ + protected void startTimeMeasurement(String key, ITimeMeasurementTag tag) { + ParserTestTimeMeasurer.getInstance().startTimeMeasurement(key, tag); + } + + /** + * A variant of {@link #startTimeMeasurement(String, ITimeMeasurementTag)} for + * the current concrete test class. + */ + protected void startTimeMeasurement(ITimeMeasurementTag tag) { + this.startTimeMeasurement(this.getCurrentTestClassName(), tag); + } + + /** + * Delegates to the time measuring mechanism and signals that the most recently + * started time measurement (via + * {@link #startTimeMeasurement(String, ITimeMeasurementTag)}) should be + * stopped.
+ *
+ * This method is to be seen as the closing bracket for the opening bracket + * {@link #startTimeMeasurement(String, ITimeMeasurementTag)}, such that the + * time elapsed while executing the lines between that method call and this + * method call is the time measurement. Not using them similar to brackets will + * result in inaccurate measurements.
+ *
+ * Refer to the documentation of {@link ParserTestTimeMeasurer} for more + * information. + */ + protected void stopTimeMeasurement() { + ParserTestTimeMeasurer.getInstance().stopTimeMeasurement(); + } + + /** + * @return A utility object that can be used to perform file operations. + */ + protected FileUtil getFileUtil() { + return new FileUtil(); + } + + /** + * @return A utility object, which encapsulates caching logic (for parsed + * models) and can be used to hasten tests. + */ + protected CacheUtil getCacheUtil() { + return resourceCache; + } + + /** + * Parses all Java-Model files under the given directory into a {@link Resource} + * instance. Uses no means of caching.
+ *
+ * Note: This method will parse ALL such files. Therefore, the given model + * directory should only contain one Java-Model. + * + * @param modelDir A directory that contains all files of a model + * + * @see {@link #isResourceRelevant()} + * @see {@link #prepareArtificialResource(Resource, URI)} + */ + protected IModelResourceWrapper parseModelsDirWithoutCaching(Path modelDir) { + this.startTimeMeasurement(GeneralTimeMeasurementTag.PARSE_MODEL_RESOURCE); + var wrapper = new JaMoPPModelResourceWrapper(this.getResourceHelper(), this.getResourceParsingStrategy()); + wrapper.parseModelResource(modelDir, this.layout.getModelResourceURI(modelDir)); + this.stopTimeMeasurement(); + return wrapper; + } + + /** + * A variant of {@link #parseModelsDirWithCaching(Path, URI, String)} that uses + * the given path as cache key (converts it to string via + * {@code path.toString()}) + */ + protected IModelResourceWrapper parseModelsDirWithCaching(Path modelDir) { + return this.parseModelsDirWithCaching(modelDir, modelDir.toString()); + } + + /** + * A variant of {@link #parseModelsDirWithCaching(Path, URI, String)} that uses + * {@code this.getModelResourceURI(modelDir)} as cached model URI. + */ + protected IModelResourceWrapper parseModelsDirWithCaching(Path modelDir, String cacheKey) { + return this.parseModelsDirWithCaching(modelDir, this.layout.getModelResourceURI(modelDir), cacheKey); + } + + /** + * Works similar to {@link #parseModelsDirWithCaching(Path)}, except for the + * caching part:
+ *
+ * Checks the cache first for previously parsed model resources, if cacheKey is + * not null. If a model resource from the given path was previously parsed and + * cached under cacheKey, returns the cached model resource (at cachedModelURI) + * instead. If there were no cached model resources for the given path, adds the + * parsed model resource to the cache under cacheKey. + */ + protected IModelResourceWrapper parseModelsDirWithCaching(Path modelDir, URI cachedModelURI, String cacheKey) { + this.startTimeMeasurement(GeneralTimeMeasurementTag.MODEL_RESOURCE_CACHE_ACCESS); + var cache = this.getCacheUtil(); + var modelName = this.getDisplayNameForModelDir(modelDir); + + IModelResourceWrapper resWrapper = null; + + /* + * If it exists, Loading the model resource alone is sufficient, because + * potentially required contents that are stored externally will be + * automatically loaded in the background when needed. + */ + + if (cacheKey != null) { + // Search for the resource in the cache + if (cache.isInCache(cacheKey)) { + this.logDebugMsg(String.format("%s is in cache, using cached version", modelName)); + resWrapper = cache.getFromCache(cacheKey); + if (!resWrapper.isModelResourceLoaded()) { + this.startTimeMeasurement(GeneralTimeMeasurementTag.LOAD_MODEL_RESOURCE); + resWrapper.loadParsedResources(); + this.stopTimeMeasurement(); + } + } + + // Search for the resource file in cache save location + if (resWrapper == null) { + resWrapper = new JaMoPPModelResourceWrapper(this.getResourceHelper()); + this.startTimeMeasurement(GeneralTimeMeasurementTag.LOAD_MODEL_RESOURCE); + resWrapper.loadModelResource(cachedModelURI); + this.stopTimeMeasurement(); + if (resWrapper.isModelResourceLoaded()) { + this.logDebugMsg(String.format("Loaded %s from its resource file", modelName)); + } + } + } + + // Resource is completely new, parse it from scratch + if (resWrapper == null || !resWrapper.isModelResourceLoaded()) { + resWrapper = this.parseModelsDirWithoutCaching(modelDir); + } + + var key = cacheKey != null ? cacheKey : modelDir.toString(); + cache.addToCache(key, resWrapper); + this.stopTimeMeasurement(); + + this.logDebugMsg(String.format("%s parsed (with caching)", this.getDisplayNameForModelDir(modelDir))); + return resWrapper; + } + + /** + * @param modelDir A directory that directly contains the Java-model files + * @return The test display name for the given modelPath + */ + protected String getDisplayNameForModelDir(Path modelPath) { + var nameCount = modelPath.getNameCount(); + + var startIndex = nameCount > 2 ? nameCount - 2 : nameCount - 1; + var endIndex = nameCount; + + return modelPath.subpath(startIndex, endIndex).toString(); + } + + /** + * Defaults to using {@link #isModelSourceFileDirectoryName(String)} on the file + * name. Check the concrete implementation for more details. + * + * @param f The file object representing the directory + * + * @return Whether a given directory contains any Java elements, from which a + * Java model can be parsed. + */ + protected boolean isModelSourceFileDirectory(File f) { + return this.isModelSourceFileDirectoryName(f.getName()); + } + + /** + * Derives the path to the model resources from their URI. + * + * @param resArr An array of parsed model resources + * @return Dynamic test instances for the given model resources + * @see {@link #createTests()} + */ + public Collection createTests(Resource[] resArr) { + var pathArr = new Path[resArr.length]; + + for (int i = 0; i < pathArr.length; i++) { + pathArr[i] = Path.of(resArr[i].getURI().path()); + } + + return this.createTests(pathArr, resArr); + } + + /** + * Parses model resources (with caching) for each given path. + * + * @param pathArr An array of paths to model directories + * @return Dynamic test instances for the models under the given paths + * @see {@link #createTests()} + */ + public Collection createTests(Path[] pathArr) { + var resArr = new Resource[pathArr.length]; + + for (int i = 0; i < resArr.length; i++) { + resArr[i] = this.parseModelsDirWithCaching(pathArr[i]).getModelResource(); + } + + return this.createTests(pathArr, resArr); + } + + /** + * @param pathArr An array of paths to model directories + * @param resArr An array of parsed model resources + * @return Dynamic test instances for the given model resources + * @see {@link #createTests()} + */ + public Collection createTests(Path[] pathArr, Resource[] resArr) { + if (pathArr.length != resArr.length) { + Assertions.fail("Lengths of path and resource arrays do not match"); + } + + var tests = new ArrayList(); + + this.getTestGenerationStrategies().forEach((testStrat) -> { + this.getTestFactories().forEach((tf) -> { + var testsForModelDirs = new ArrayList(); + testStrat.getTestResourceIterator(resArr.length).forEachRemaining((idxs) -> { + var path1 = pathArr[idxs[0]]; + var res1 = resArr[idxs[0]]; + var path2 = pathArr[idxs[1]]; + var res2 = resArr[idxs[1]]; + testsForModelDirs.add(tf.createTestsFor(res1, path1, res2, path2)); + }); + tests.add(DynamicContainer.dynamicContainer(String.format("%s (with %s)", tf.getTestDescription(), + testStrat.getTestGenerationStrategyDescription()), testsForModelDirs)); + }); + }); + + return tests; + } + + /** + * Generates dynamic tests for each model directories based on the registered + * {@link AbstractJaMoPPParserSimilarityTestFactory} instances. Implemented here + * in efforts to have a unified template for dynamic test generation.
+ *
+ * Can be overridden in implementors; in order to add preparatory actions, + * clean up actions or to change the default test generation. DUE TO HOW + * JUNIT WORKS, GENERATED TESTS WILL NOT REGISTER UNLESS ANNOTED AS + * {@code TestFactory} IN OVERRIDING VERSIONS TOO.
+ *
+ * Unless overridden in implementors, JUnit will detect this method as a + * {@link TestFactory}, which will run the tests generated here. + * + * @see {@link #discoverModelSourceFileDirsAt(Path)} and + * {@link #discoverModelSourceParentDirsAt(Path)} for locating model + * directories + * @see {@link TestFactory} for what tests are to be generated + */ + @TestFactory + public Collection createTests() { + this.startTimeMeasurement(GeneralTimeMeasurementTag.DYNAMIC_TEST_CREATION); + + var modelSourceFileRootDirPath = this.layout.getModelSourceFileRootDirPath(); + + var tests = new ArrayList(); + + var modelParentDirs = this.discoverModelSourceParentDirsAt(modelSourceFileRootDirPath); + var modelDirMap = new HashMap>(); + + for (var parentDir : modelParentDirs) { + modelDirMap.put(parentDir, this.discoverModelSourceFileDirsAt(parentDir)); + } + + var testsForModelParentDirs = new ArrayList(); + modelParentDirs.forEach((md) -> { + final var modelDirs = modelDirMap.get(md); + + var testsForModelDirs = this.createTests(modelDirs.toArray(Path[]::new)); + + testsForModelParentDirs.add(DynamicContainer.dynamicContainer( + String.format("model = %s", this.getTestFileLayout().getRelativeModelSourceParentDirPath(md)), + testsForModelDirs)); + }); + + tests.add(DynamicContainer.dynamicContainer( + String.format("root = %s", this.getTestFileLayout().getRelativeModelSourceFileRootDirPath()), + testsForModelParentDirs)); + + this.stopTimeMeasurement(); + return tests; + } + + /** + * Can be used to determine what kind of parser tests are to be generated in + * concrete implementors. + * + * @return Factories of tests that should be generated for each relevant model + * directories. + */ + protected abstract Collection getTestFactories(); + + /** + * @param rootPath The top-most directory, whose contents should be scanned for + * model directories + * @return A collection of model directory paths under rootPath + */ + protected Collection discoverModelSourceFileDirsAt(Path rootPath) { + this.startTimeMeasurement(GeneralTimeMeasurementTag.DISCOVER_MODEL_RESOURCES); + var result = new ModelDirDiscoveryStrategy((f) -> this.isModelSourceFileDirectory(f)) + .discoverModelSourceDirs(rootPath.toFile()); + this.stopTimeMeasurement(); + return result; + } + + /** + * @param rootPath The top-most directory, whose contents should be scanned for + * directories containing model directories. + * @return A collection of paths of directories containing model directory under + * rootPath + */ + protected Collection discoverModelSourceParentDirsAt(Path rootPath) { + this.startTimeMeasurement(GeneralTimeMeasurementTag.DISCOVER_MODEL_RESOURCES); + var result = new ModelDirDiscoveryStrategy((f) -> this.isModelSourceFileDirectory(f)) + .discoverModelSourceParentDirs(rootPath.toFile()); + this.stopTimeMeasurement(); + return result; + } + + /** + * Check the concrete implementation for more details. + * + * @param dirName The name of the directory, which potentially contains files of + * a model + * + * @return Whether a given directory contains any Java elements, from which a + * Java model can be parsed. + */ + protected abstract boolean isModelSourceFileDirectoryName(String dirName); + + /** + * Override to define how to iterate through model resources, while generating + * dynamic tests. One or more test generation strategies can be provided. + * Dynamic tests will be generated for each strategy in the returned collection, + * regardless of what dynamic tests where generated previously.
+ *
+ * This method allows splitting dynamic test generation; with respect to what + * model resources will be compared to which ones, and in what order. + * + * @return A collection of test generation strategies, which encapsulate how + * model resources are iterated and what dynamic tests are generated. + */ + protected abstract Collection getTestGenerationStrategies(); + + /** + * Defaults to true.
+ *
+ * Can be overridden in implementors, if necessary. + * + * @return Whether the order of model resource contents (i.e. all EObject + * instances nested directly or indirectly within) matters and should be + * accounted for in the expected results. + */ + public boolean doesContentOrderMatter() { + return true; + } + + @Override + protected ParserTestOptions initResourceTestOptions() { + var opts = new ParserTestOptions(); + + /* + * Parser tests require the created resource files to persist across tests, as + * they are cached. + */ + opts.setShouldDeleteAllResources(false); + opts.setShouldUnloadAllResources(false); + + opts.setShouldSaveCachedResources(true); + opts.setShouldRemoveResourcesFromCache(false); + return opts; + } + + @Override + protected ParserTestOptions getResourceTestOptions() { + return (ParserTestOptions) super.getResourceTestOptions(); + } +} From 9395aa1c7cd4f47b72c6dc62f6c1a8d9d7c5ca42 Mon Sep 17 00:00:00 2001 From: AlpTorac Date: Sun, 27 Jul 2025 17:27:15 +0200 Subject: [PATCH 22/72] Add package-info files --- .../fitests/similarity/eobject/package-info.java | 5 +++++ .../fitests/similarity/jamopp/package-info.java | 9 +++++++++ .../similarity/jamopp/parser/package-info.java | 5 +++++ .../consistency/fitests/similarity/package-info.java | 11 +++++++++++ 4 files changed, 30 insertions(+) create mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/eobject/package-info.java create mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/package-info.java create mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/package-info.java create mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/package-info.java diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/eobject/package-info.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/eobject/package-info.java new file mode 100644 index 0000000000..422e0aa10f --- /dev/null +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/eobject/package-info.java @@ -0,0 +1,5 @@ +/** + * Contains {@link EObject} and {@link Resource} extensions for + * {@link cipm.consistency.fitests.similarity}. + */ +package cipm.consistency.fitests.similarity.eobject; \ No newline at end of file diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/package-info.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/package-info.java new file mode 100644 index 0000000000..99370c6111 --- /dev/null +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/package-info.java @@ -0,0 +1,9 @@ +/** + * Contains test classes that can be used to test the similarity checking of + * Java-model elements, which are stored and represented by {@link EObject} + * implementors present in JaMoPP.
+ *
+ * Also contains some general tests, which do not target specific + * {@link EObject} types. + */ +package cipm.consistency.fitests.similarity.jamopp; \ No newline at end of file diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/package-info.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/package-info.java new file mode 100644 index 0000000000..993acb1350 --- /dev/null +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/package-info.java @@ -0,0 +1,5 @@ +/** + * Contains tests that involve small-scale Java projects, Java-elements and/or + * fragments thereof in form of concrete files. + */ +package cipm.consistency.fitests.similarity.jamopp.parser; \ No newline at end of file diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/package-info.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/package-info.java new file mode 100644 index 0000000000..f01efa969d --- /dev/null +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/package-info.java @@ -0,0 +1,11 @@ +/** + * This package contains classes and interfaces that can be used to test + * similarity checking, regardless of which objects are compared during + * similarity checking.
+ *
+ * Sub-packages contain tests and utility classes that test similarity checking. + * They are named and structured to minimise dependencies concerning the context + * of similarity checking (such as {@link EObject} or JaMoPP). This way, + * re-using the contents of sub-packages is easier. + */ +package cipm.consistency.fitests.similarity; \ No newline at end of file From 5a439a4b5ce712d3ad31e918b03c808f51e1ae03 Mon Sep 17 00:00:00 2001 From: AlpTorac Date: Sun, 27 Jul 2025 17:31:38 +0200 Subject: [PATCH 23/72] Create plug-in fitests.repositorytests for repository parser tests --- .../.classpath | 7 +++++ .../.project | 28 +++++++++++++++++++ .../META-INF/MANIFEST.MF | 26 +++++++++++++++++ .../build.properties | 4 +++ 4 files changed, 65 insertions(+) create mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/.classpath create mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/.project create mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/META-INF/MANIFEST.MF create mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/build.properties diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/.classpath b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/.classpath new file mode 100644 index 0000000000..e801ebfb46 --- /dev/null +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/.project b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/.project new file mode 100644 index 0000000000..359f09ccf7 --- /dev/null +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/.project @@ -0,0 +1,28 @@ + + + cipm.consistency.fitests.repositorytests + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/META-INF/MANIFEST.MF b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/META-INF/MANIFEST.MF new file mode 100644 index 0000000000..ef47bb6139 --- /dev/null +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/META-INF/MANIFEST.MF @@ -0,0 +1,26 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: cipm.consistency.fitests.repositorytests +Bundle-SymbolicName: cipm.consistency.fitests.repositorytests +Bundle-Version: 1.0.0.qualifier +Automatic-Module-Name: cipm.consistency.fitests.repositorytests +Bundle-RequiredExecutionEnvironment: JavaSE-11 +Require-Bundle: junit-jupiter-api, + junit-jupiter-engine, + junit-jupiter-params, + org.eclipse.emf.common, + org.eclipse.emf.ecore, + org.eclipse.emf.compare, + org.eclipse.emf.ecore.xmi, + org.splevo.diffing, + org.splevo.jamopp.diffing, + org.apache.log4j, + org.emftext.language.java, + jamopp.parser.jdt.singlefile, + jamopp.parser, + cipm.consistency.commitintegration, + cipm.consistency.commitintegration.diff.util, + org.eclipse.jgit, + jamopp.resolution, + cipm.consistency.fitests, + com.google.gson diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/build.properties b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/build.properties new file mode 100644 index 0000000000..34d2e4d2da --- /dev/null +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/build.properties @@ -0,0 +1,4 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + . From 822e93d782ddcf5002084c4b590e2ceeaea978fa Mon Sep 17 00:00:00 2001 From: AlpTorac Date: Sun, 27 Jul 2025 17:33:10 +0200 Subject: [PATCH 24/72] Implement class for filtering diff patches --- .../util/difffilter/DiffFilter.java | 193 ++++++ .../util/difffilter/DiffFilterTest.java | 627 ++++++++++++++++++ 2 files changed, 820 insertions(+) create mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/difffilter/DiffFilter.java create mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/difffilter/DiffFilterTest.java diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/difffilter/DiffFilter.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/difffilter/DiffFilter.java new file mode 100644 index 0000000000..1cd0d2b4ae --- /dev/null +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/difffilter/DiffFilter.java @@ -0,0 +1,193 @@ +package cipm.consistency.fitests.repositorytests.util.difffilter; + +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Pattern; + +/** + * A class that can filter out the non-script parts of a given diff patch. + * + * @author Alp Torac Genc + */ +public class DiffFilter { + /** + * Pattern for the beginning of a diff script line. + */ + private static final Pattern diffLineSignPattern = Pattern.compile("^(?:\\+|-)"); + /** + * Pattern for a diff script line, which only contains whitespace characters, + * i.e. an empty diff script line. + */ + private static final Pattern diffLineWhitespacePattern = Pattern + .compile(String.format("%s?\\s*$", diffLineSignPattern.pattern())); + + /** + * Pattern for a diff header, i.e. the line that contains the diff command. + */ + private static final Pattern diffHeaderPattern = Pattern.compile("^\\s*diff --git .*"); + /** + * Pattern for a hunk header in a diff patch, i.e. the part where a hunk is + * located. + */ + private static final Pattern diffHunkHeaderPattern = Pattern.compile("^@@ .* @@$"); + + /** + * Pattern for file metadata pattern in a diff patch. + */ + private static final Pattern diffFileMetadataPattern = Pattern.compile("^index .*"); + + /** + * Pattern for mode lines in a diff patch. + */ + private static final Pattern diffModePattern = Pattern.compile("^(?:old|new|new file|deleted file) mode .*"); + /** + * Pattern for rename lines in a diff patch. + */ + private static final Pattern diffRenamePattern = Pattern.compile("^rename (?:to|from) .*\\.\\w*"); + /** + * Pattern for copy lines in a diff patch. + */ + private static final Pattern diffCopyPattern = Pattern.compile("^copy (?:to|from) .*\\.\\w*"); + + /** + * Pattern for a new file state line in a diff patch. + */ + private static final Pattern diffNewFileStatePattern = Pattern.compile("^\\+\\+\\+ (?:.*\\.\\w*|/.*)"); + /** + * Pattern for an old file state line in a diff patch. + */ + private static final Pattern diffOldFileStatePattern = Pattern.compile("^--- (?:.*\\.\\w*|/.*)"); + + /** + * Pattern for similarity index line in a diff patch. + */ + private static final Pattern diffSimilarityIndexPattern = Pattern.compile("^similarity index \\d*\\.?\\d+%"); + /** + * Pattern for dissimilarity index line in a diff patch. + */ + private static final Pattern diffDissimilarityIndexPattern = Pattern.compile("^dissimilarity index \\d*\\.?\\d+%"); + + /** + * The line in a diff patch that indicates the absence of a newline character at + * the end of a file. + */ + private static final String diffNoNewLineMessage = "\\ No newline at end of file"; + + /** + * The line separator used by the current OS. + */ + private static final String lineSeparator = System.lineSeparator(); + + /** + * @return Splits the given (multi-line) text into its lines, where lines are + * separated via the line separator used by the system. + */ + public List splitLines(String text) { + var lines = new ArrayList(); + + // Do not use System.lineSeparator since GIT uses UNIX terminal + // UNIX terminal uses "\n" for new line + var diffLines = text.split(lineSeparator); + + for (var l : diffLines) { + lines.add(l); + } + + return lines; + } + + /** + * Concatenates the given lines into a single String by gluing them with the + * line separator used by the system. + * + * @return All lines as one String. Returns empty String if lines is null. + */ + public String concatLines(String... lines) { + var result = ""; + + if (lines == null) + return result; + + for (int i = 0; i < lines.length - 1; i++) + result += lines[i] + lineSeparator; + + result += lines[lines.length - 1]; + + return result; + } + + /** + * Concatenates the given lines into a single String by gluing them with the + * line separator used by the system. + * + * @return All lines as one String. Returns empty String if lines is null. + */ + public String concatLines(List lines) { + if (lines == null) + return ""; + + return this.concatLines(lines.toArray(String[]::new)); + } + + /** + * Modifies and returns the given list. + * + * @return The given list with only diff patch script lines. + */ + public List removeNonPatchScript(List lines) { + lines.removeIf((l) -> !isPatchScriptLine(l)); + return lines; + } + + /** + * Modifies and returns the given list. + * + * @return The given list without blank diff patch script lines. + */ + public List removeBlankLines(List lines) { + lines.removeIf((l) -> diffLineWhitespacePattern.matcher(l).matches()); + return lines; + } + + /** + * Modifies and returns the given list. + * + * @return The given list without context lines, i.e. lines in the diff patch + * script that are only there to provide context. + */ + public List removeContextLines(List lines) { + lines.removeIf((l) -> !diffLineSignPattern.matcher(l).find()); + return lines; + } + + /** + * @return Whether the given line is a part of the diff patch script. + */ + public boolean isPatchScriptLine(String line) { + if (diffHeaderPattern.matcher(line).find()) { + return false; + } else if (diffNewFileStatePattern.matcher(line).find()) { + return false; + } else if (diffOldFileStatePattern.matcher(line).find()) { + return false; + } else if (diffFileMetadataPattern.matcher(line).find()) { + return false; + } else if (diffHunkHeaderPattern.matcher(line).find()) { + return false; + } else if (diffModePattern.matcher(line).find()) { + return false; + } else if (diffSimilarityIndexPattern.matcher(line).find()) { + return false; + } else if (diffCopyPattern.matcher(line).find()) { + return false; + } else if (diffDissimilarityIndexPattern.matcher(line).find()) { + return false; + } else if (diffRenamePattern.matcher(line).find()) { + return false; + } else if (line.equals(diffNoNewLineMessage)) { + return false; + } else { + return true; + } + } +} diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/difffilter/DiffFilterTest.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/difffilter/DiffFilterTest.java new file mode 100644 index 0000000000..1fcb0f7e8d --- /dev/null +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/difffilter/DiffFilterTest.java @@ -0,0 +1,627 @@ +package cipm.consistency.fitests.repositorytests.util.difffilter; + +import java.util.List; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +/** + * Contains tests for filtering out non-patch-script lines from diffs.
+ *
+ * Each test method starts with the construction of an exemplary diff (as + * String) with some lines that should be removed. This diff is then processed + * via {@link DiffFilter} and the result is tested. + * + * @author Alp Torac Genc + */ +public class DiffFilterTest { + private static final DiffFilter filter = new DiffFilter(); + + @Test + public void testSplitLines_MultipleLines() { + var line1 = "a"; + var line2 = "b"; + var line3 = "c"; + + var text = String.format("%s%s%s%s%s", line1, System.lineSeparator(), line2, System.lineSeparator(), line3); + + var lines = filter.splitLines(text); + Assertions.assertEquals(3, lines.size()); + Assertions.assertEquals(line1, lines.get(0)); + Assertions.assertEquals(line2, lines.get(1)); + Assertions.assertEquals(line3, lines.get(2)); + } + + @Test + public void testSplitLines_SingleLine() { + var line = "a"; + + var lines = filter.splitLines(line); + Assertions.assertEquals(1, lines.size()); + Assertions.assertEquals(line, lines.get(0)); + } + + @Test + public void testConcatLines_MultipleLines() { + var line1 = "a"; + var line2 = "b"; + var line3 = "c"; + + Assertions.assertEquals( + String.format("%s%s%s%s%s", line1, System.lineSeparator(), line2, System.lineSeparator(), line3), + filter.concatLines(line1, line2, line3)); + Assertions.assertEquals( + String.format("%s%s%s%s%s", line1, System.lineSeparator(), line2, System.lineSeparator(), line3), + filter.concatLines(List.of(line1, line2, line3))); + Assertions.assertEquals(filter.concatLines(line1, line2, line3), + filter.concatLines(List.of(line1, line2, line3))); + } + + @Test + public void testConcatLines_SingleLine() { + var line = "a"; + + Assertions.assertEquals(line, filter.concatLines(line)); + Assertions.assertEquals(line, filter.concatLines(List.of(line))); + Assertions.assertEquals(filter.concatLines(line), filter.concatLines(List.of(line))); + } + + @Test + public void filterDiffHeader_IsolatedOnOneLine() { + var linePred = "someText"; + var cmdLine = "diff --git a/file1.txt b/file1.txt"; + var lineSucc = "someMoreText"; + + var text = filter.concatLines(linePred, cmdLine, lineSucc); + + var lines = filter.removeNonPatchScript(filter.splitLines(text)); + + Assertions.assertEquals(2, lines.size()); + Assertions.assertEquals(linePred, lines.get(0)); + Assertions.assertEquals(lineSucc, lines.get(1)); + } + + @Test + public void filterDiffHeader_NotLineStart() { + var linePred = "someText"; + var cmdLine = "abc diff --git a/file1.txt b/file1.txt"; + var lineSucc = "someMoreText"; + + var text = filter.concatLines(linePred, cmdLine, lineSucc); + + var lines = filter.removeNonPatchScript(filter.splitLines(text)); + + Assertions.assertEquals(3, lines.size()); + Assertions.assertEquals(linePred, lines.get(0)); + Assertions.assertEquals(cmdLine, lines.get(1)); + Assertions.assertEquals(lineSucc, lines.get(2)); + } + + @Test + public void filterFileMetadataMessage_IsolatedOnOneLine() { + var linePred = "someText"; + var cmdLine = "index f2ba8f8..4a89512 100644"; + var lineSucc = "someMoreText"; + + var text = filter.concatLines(linePred, cmdLine, lineSucc); + + var lines = filter.removeNonPatchScript(filter.splitLines(text)); + + Assertions.assertEquals(2, lines.size()); + Assertions.assertEquals(linePred, lines.get(0)); + Assertions.assertEquals(lineSucc, lines.get(1)); + } + + @Test + public void filterFileMetadataMessage_NotLineStart() { + var linePred = "someText"; + var cmdLine = "abc index f2ba8f8..4a89512 100644"; + var lineSucc = "someMoreText"; + + var text = filter.concatLines(linePred, cmdLine, lineSucc); + + var lines = filter.removeNonPatchScript(filter.splitLines(text)); + + Assertions.assertEquals(3, lines.size()); + Assertions.assertEquals(linePred, lines.get(0)); + Assertions.assertEquals(cmdLine, lines.get(1)); + Assertions.assertEquals(lineSucc, lines.get(2)); + } + + @Test + public void filterOldFileStateMessage_IsolatedOnOneLine() { + var linePred = "someText"; + var cmdLine = "+++ b/file1.txt"; + var lineSucc = "someMoreText"; + + var text = filter.concatLines(linePred, cmdLine, lineSucc); + + var lines = filter.removeNonPatchScript(filter.splitLines(text)); + + Assertions.assertEquals(2, lines.size()); + Assertions.assertEquals(linePred, lines.get(0)); + Assertions.assertEquals(lineSucc, lines.get(1)); + } + + @Test + public void filterOldFileStateMessage_NotLineStart() { + var linePred = "someText"; + var cmdLine = "abc +++ b/file1.txt"; + var lineSucc = "someMoreText"; + + var text = filter.concatLines(linePred, cmdLine, lineSucc); + + var lines = filter.removeNonPatchScript(filter.splitLines(text)); + + Assertions.assertEquals(3, lines.size()); + Assertions.assertEquals(linePred, lines.get(0)); + Assertions.assertEquals(cmdLine, lines.get(1)); + Assertions.assertEquals(lineSucc, lines.get(2)); + } + + @Test + public void filterOldFileStateMessage_DevNull_IsolatedOnOneLine() { + var linePred = "someText"; + var cmdLine = "+++ /dev/null"; + var lineSucc = "someMoreText"; + + var text = filter.concatLines(linePred, cmdLine, lineSucc); + + var lines = filter.removeNonPatchScript(filter.splitLines(text)); + + Assertions.assertEquals(2, lines.size()); + Assertions.assertEquals(linePred, lines.get(0)); + Assertions.assertEquals(lineSucc, lines.get(1)); + } + + @Test + public void filterOldFileStateMessage_DevNull_NotLineStart() { + var linePred = "someText"; + var cmdLine = "abc +++ /dev/null"; + var lineSucc = "someMoreText"; + + var text = filter.concatLines(linePred, cmdLine, lineSucc); + + var lines = filter.removeNonPatchScript(filter.splitLines(text)); + + Assertions.assertEquals(3, lines.size()); + Assertions.assertEquals(linePred, lines.get(0)); + Assertions.assertEquals(cmdLine, lines.get(1)); + Assertions.assertEquals(lineSucc, lines.get(2)); + } + + @Test + public void filterNewFileStateMessage_IsolatedOnOneLine() { + var linePred = "someText"; + var cmdLine = "--- a/file1.txt"; + var lineSucc = "someMoreText"; + + var text = filter.concatLines(linePred, cmdLine, lineSucc); + + var lines = filter.removeNonPatchScript(filter.splitLines(text)); + + Assertions.assertEquals(2, lines.size()); + Assertions.assertEquals(linePred, lines.get(0)); + Assertions.assertEquals(lineSucc, lines.get(1)); + } + + @Test + public void filterNewFileStateMessage_NotLineStart() { + var linePred = "someText"; + var cmdLine = "abc --- a/file1.txt"; + var lineSucc = "someMoreText"; + + var text = filter.concatLines(linePred, cmdLine, lineSucc); + + var lines = filter.removeNonPatchScript(filter.splitLines(text)); + + Assertions.assertEquals(3, lines.size()); + Assertions.assertEquals(linePred, lines.get(0)); + Assertions.assertEquals(cmdLine, lines.get(1)); + Assertions.assertEquals(lineSucc, lines.get(2)); + } + + @Test + public void filterHunkHeaderMessage_IsolatedOnOneLine() { + var linePred = "someText"; + var cmdLine = "@@ -1 +1,6 @@"; + var lineSucc = "someMoreText"; + + var text = filter.concatLines(linePred, cmdLine, lineSucc); + + var lines = filter.removeNonPatchScript(filter.splitLines(text)); + + Assertions.assertEquals(2, lines.size()); + Assertions.assertEquals(linePred, lines.get(0)); + Assertions.assertEquals(lineSucc, lines.get(1)); + } + + @Test + public void filterHunkHeaderMessage_NotLineStart() { + var linePred = "someText"; + var cmdLine = "abc @@ -1 +1,6 @@"; + var lineSucc = "someMoreText"; + + var text = filter.concatLines(linePred, cmdLine, lineSucc); + + var lines = filter.removeNonPatchScript(filter.splitLines(text)); + + Assertions.assertEquals(3, lines.size()); + Assertions.assertEquals(linePred, lines.get(0)); + Assertions.assertEquals(cmdLine, lines.get(1)); + Assertions.assertEquals(lineSucc, lines.get(2)); + } + + @Test + public void filterHunkHeaderMessage_NotLineEnd() { + var linePred = "someText"; + var cmdLine = "@@ -1 +1,6 @@ abc"; + var lineSucc = "someMoreText"; + + var text = filter.concatLines(linePred, cmdLine, lineSucc); + + var lines = filter.removeNonPatchScript(filter.splitLines(text)); + + Assertions.assertEquals(3, lines.size()); + Assertions.assertEquals(linePred, lines.get(0)); + Assertions.assertEquals(cmdLine, lines.get(1)); + Assertions.assertEquals(lineSucc, lines.get(2)); + } + + @Test + public void filterHunkHeaderMessage_SurroundedInLine() { + var linePred = "someText"; + var cmdLine = "def @@ -1 +1,6 @@ abc"; + var lineSucc = "someMoreText"; + + var text = filter.concatLines(linePred, cmdLine, lineSucc); + + var lines = filter.removeNonPatchScript(filter.splitLines(text)); + + Assertions.assertEquals(3, lines.size()); + Assertions.assertEquals(linePred, lines.get(0)); + Assertions.assertEquals(cmdLine, lines.get(1)); + Assertions.assertEquals(lineSucc, lines.get(2)); + } + + @Test + public void filterNoNewlineMessage_IsolatedOnOneLine() { + var linePred = "someText"; + var cmdLine = "\\ No newline at end of file"; + var lineSucc = "someMoreText"; + + var text = filter.concatLines(linePred, cmdLine, lineSucc); + + var lines = filter.removeNonPatchScript(filter.splitLines(text)); + + Assertions.assertEquals(2, lines.size()); + Assertions.assertEquals(linePred, lines.get(0)); + Assertions.assertEquals(lineSucc, lines.get(1)); + } + + @Test + public void filterNoNewlineMessage_NotLineStart() { + var linePred = "someText"; + var cmdLine = "abc \\ No newline at end of file"; + var lineSucc = "someMoreText"; + + var text = filter.concatLines(linePred, cmdLine, lineSucc); + + var lines = filter.removeNonPatchScript(filter.splitLines(text)); + + Assertions.assertEquals(3, lines.size()); + Assertions.assertEquals(linePred, lines.get(0)); + Assertions.assertEquals(cmdLine, lines.get(1)); + Assertions.assertEquals(lineSucc, lines.get(2)); + } + + @Test + public void filterDeletedFileModeMessage_IsolatedOnOneLine() { + var linePred = "someText"; + var cmdLine = "deleted file mode 100644"; + var lineSucc = "someMoreText"; + + var text = filter.concatLines(linePred, cmdLine, lineSucc); + + var lines = filter.removeNonPatchScript(filter.splitLines(text)); + + Assertions.assertEquals(2, lines.size()); + Assertions.assertEquals(linePred, lines.get(0)); + Assertions.assertEquals(lineSucc, lines.get(1)); + } + + @Test + public void filterDeletedFileModeMessage_NotLineStart() { + var linePred = "someText"; + var cmdLine = "abc deleted file mode 100644"; + var lineSucc = "someMoreText"; + + var text = filter.concatLines(linePred, cmdLine, lineSucc); + + var lines = filter.removeNonPatchScript(filter.splitLines(text)); + + Assertions.assertEquals(3, lines.size()); + Assertions.assertEquals(linePred, lines.get(0)); + Assertions.assertEquals(cmdLine, lines.get(1)); + Assertions.assertEquals(lineSucc, lines.get(2)); + } + + @Test + public void filterOldModeMessage_IsolatedOnOneLine() { + var linePred = "someText"; + var cmdLine = "old mode 100644"; + var lineSucc = "someMoreText"; + + var text = filter.concatLines(linePred, cmdLine, lineSucc); + + var lines = filter.removeNonPatchScript(filter.splitLines(text)); + + Assertions.assertEquals(2, lines.size()); + Assertions.assertEquals(linePred, lines.get(0)); + Assertions.assertEquals(lineSucc, lines.get(1)); + } + + @Test + public void filterOldModeMessage_NotLineStart() { + var linePred = "someText"; + var cmdLine = "abc old mode 100644"; + var lineSucc = "someMoreText"; + + var text = filter.concatLines(linePred, cmdLine, lineSucc); + + var lines = filter.removeNonPatchScript(filter.splitLines(text)); + + Assertions.assertEquals(3, lines.size()); + Assertions.assertEquals(linePred, lines.get(0)); + Assertions.assertEquals(cmdLine, lines.get(1)); + Assertions.assertEquals(lineSucc, lines.get(2)); + } + + @Test + public void filterNewModeMessage_IsolatedOnOneLine() { + var linePred = "someText"; + var cmdLine = "new mode 100644"; + var lineSucc = "someMoreText"; + + var text = filter.concatLines(linePred, cmdLine, lineSucc); + + var lines = filter.removeNonPatchScript(filter.splitLines(text)); + + Assertions.assertEquals(2, lines.size()); + Assertions.assertEquals(linePred, lines.get(0)); + Assertions.assertEquals(lineSucc, lines.get(1)); + } + + @Test + public void filterNewModeMessage_NotLineStart() { + var linePred = "someText"; + var cmdLine = "abc new mode 100644"; + var lineSucc = "someMoreText"; + + var text = filter.concatLines(linePred, cmdLine, lineSucc); + + var lines = filter.removeNonPatchScript(filter.splitLines(text)); + + Assertions.assertEquals(3, lines.size()); + Assertions.assertEquals(linePred, lines.get(0)); + Assertions.assertEquals(cmdLine, lines.get(1)); + Assertions.assertEquals(lineSucc, lines.get(2)); + } + + @Test + public void filterNewFileModeMessage_IsolatedOnOneLine() { + var linePred = "someText"; + var cmdLine = "new file mode 100644"; + var lineSucc = "someMoreText"; + + var text = filter.concatLines(linePred, cmdLine, lineSucc); + + var lines = filter.removeNonPatchScript(filter.splitLines(text)); + + Assertions.assertEquals(2, lines.size()); + Assertions.assertEquals(linePred, lines.get(0)); + Assertions.assertEquals(lineSucc, lines.get(1)); + } + + @Test + public void filterNewFileModeMessage_NotLineStart() { + var linePred = "someText"; + var cmdLine = "abc new file mode 100644"; + var lineSucc = "someMoreText"; + + var text = filter.concatLines(linePred, cmdLine, lineSucc); + + var lines = filter.removeNonPatchScript(filter.splitLines(text)); + + Assertions.assertEquals(3, lines.size()); + Assertions.assertEquals(linePred, lines.get(0)); + Assertions.assertEquals(cmdLine, lines.get(1)); + Assertions.assertEquals(lineSucc, lines.get(2)); + } + + @Test + public void filterSimilarityIndexMessage_IsolatedOnOneLine() { + var linePred = "someText"; + var cmdLine = "similarity index 10%"; + var lineSucc = "someMoreText"; + + var text = filter.concatLines(linePred, cmdLine, lineSucc); + + var lines = filter.removeNonPatchScript(filter.splitLines(text)); + + Assertions.assertEquals(2, lines.size()); + Assertions.assertEquals(linePred, lines.get(0)); + Assertions.assertEquals(lineSucc, lines.get(1)); + } + + @Test + public void filterSimilarityIndexMessage_NotLineStart() { + var linePred = "someText"; + var cmdLine = "abc similarity index 12.34%"; + var lineSucc = "someMoreText"; + + var text = filter.concatLines(linePred, cmdLine, lineSucc); + + var lines = filter.removeNonPatchScript(filter.splitLines(text)); + + Assertions.assertEquals(3, lines.size()); + Assertions.assertEquals(linePred, lines.get(0)); + Assertions.assertEquals(cmdLine, lines.get(1)); + Assertions.assertEquals(lineSucc, lines.get(2)); + } + + @Test + public void filterDissimilarityIndexMessage_IsolatedOnOneLine() { + var linePred = "someText"; + var cmdLine = "dissimilarity index 10%"; + var lineSucc = "someMoreText"; + + var text = filter.concatLines(linePred, cmdLine, lineSucc); + + var lines = filter.removeNonPatchScript(filter.splitLines(text)); + + Assertions.assertEquals(2, lines.size()); + Assertions.assertEquals(linePred, lines.get(0)); + Assertions.assertEquals(lineSucc, lines.get(1)); + } + + @Test + public void filterDissimilarityIndexMessage_NotLineStart() { + var linePred = "someText"; + var cmdLine = "abc dissimilarity index 12.34%"; + var lineSucc = "someMoreText"; + + var text = filter.concatLines(linePred, cmdLine, lineSucc); + + var lines = filter.removeNonPatchScript(filter.splitLines(text)); + + Assertions.assertEquals(3, lines.size()); + Assertions.assertEquals(linePred, lines.get(0)); + Assertions.assertEquals(cmdLine, lines.get(1)); + Assertions.assertEquals(lineSucc, lines.get(2)); + } + + @Test + public void filterRenamedToMessage_IsolatedOnOneLine() { + var linePred = "someText"; + var cmdLine = "rename to somefile.someext"; + var lineSucc = "someMoreText"; + + var text = filter.concatLines(linePred, cmdLine, lineSucc); + + var lines = filter.removeNonPatchScript(filter.splitLines(text)); + + Assertions.assertEquals(2, lines.size()); + Assertions.assertEquals(linePred, lines.get(0)); + Assertions.assertEquals(lineSucc, lines.get(1)); + } + + @Test + public void filterRenamedToMessage_NotLineStart() { + var linePred = "someText"; + var cmdLine = "abc rename to somefile.someext"; + var lineSucc = "someMoreText"; + + var text = filter.concatLines(linePred, cmdLine, lineSucc); + + var lines = filter.removeNonPatchScript(filter.splitLines(text)); + + Assertions.assertEquals(3, lines.size()); + Assertions.assertEquals(linePred, lines.get(0)); + Assertions.assertEquals(cmdLine, lines.get(1)); + Assertions.assertEquals(lineSucc, lines.get(2)); + } + + @Test + public void filterRenamedFromMessage_IsolatedOnOneLine() { + var linePred = "someText"; + var cmdLine = "rename from somefile.someext"; + var lineSucc = "someMoreText"; + + var text = filter.concatLines(linePred, cmdLine, lineSucc); + + var lines = filter.removeNonPatchScript(filter.splitLines(text)); + + Assertions.assertEquals(2, lines.size()); + Assertions.assertEquals(linePred, lines.get(0)); + Assertions.assertEquals(lineSucc, lines.get(1)); + } + + @Test + public void filterRenamedFromMessage_NotLineStart() { + var linePred = "someText"; + var cmdLine = "abc rename from somefile.someext"; + var lineSucc = "someMoreText"; + + var text = filter.concatLines(linePred, cmdLine, lineSucc); + + var lines = filter.removeNonPatchScript(filter.splitLines(text)); + + Assertions.assertEquals(3, lines.size()); + Assertions.assertEquals(linePred, lines.get(0)); + Assertions.assertEquals(cmdLine, lines.get(1)); + Assertions.assertEquals(lineSucc, lines.get(2)); + } + + @Test + public void filterCoppiedToMessage_IsolatedOnOneLine() { + var linePred = "someText"; + var cmdLine = "copy to somefile.someext"; + var lineSucc = "someMoreText"; + + var text = filter.concatLines(linePred, cmdLine, lineSucc); + + var lines = filter.removeNonPatchScript(filter.splitLines(text)); + + Assertions.assertEquals(2, lines.size()); + Assertions.assertEquals(linePred, lines.get(0)); + Assertions.assertEquals(lineSucc, lines.get(1)); + } + + @Test + public void filterCoppiedToMessage_NotLineStart() { + var linePred = "someText"; + var cmdLine = "abc copy to somefile.someext"; + var lineSucc = "someMoreText"; + + var text = filter.concatLines(linePred, cmdLine, lineSucc); + + var lines = filter.removeNonPatchScript(filter.splitLines(text)); + + Assertions.assertEquals(3, lines.size()); + Assertions.assertEquals(linePred, lines.get(0)); + Assertions.assertEquals(cmdLine, lines.get(1)); + Assertions.assertEquals(lineSucc, lines.get(2)); + } + + @Test + public void filterCoppiedFromMessage_IsolatedOnOneLine() { + var linePred = "someText"; + var cmdLine = "copy from somefile.someext"; + var lineSucc = "someMoreText"; + + var text = filter.concatLines(linePred, cmdLine, lineSucc); + + var lines = filter.removeNonPatchScript(filter.splitLines(text)); + + Assertions.assertEquals(2, lines.size()); + Assertions.assertEquals(linePred, lines.get(0)); + Assertions.assertEquals(lineSucc, lines.get(1)); + } + + @Test + public void filterCoppiedFromMessage_NotLineStart() { + var linePred = "someText"; + var cmdLine = "abc copy from somefile.someext"; + var lineSucc = "someMoreText"; + + var text = filter.concatLines(linePred, cmdLine, lineSucc); + + var lines = filter.removeNonPatchScript(filter.splitLines(text)); + + Assertions.assertEquals(3, lines.size()); + Assertions.assertEquals(linePred, lines.get(0)); + Assertions.assertEquals(cmdLine, lines.get(1)); + Assertions.assertEquals(lineSucc, lines.get(2)); + } +} From 2a47938d322043ce40f83a5fdae987040cbb6b92 Mon Sep 17 00:00:00 2001 From: AlpTorac Date: Sun, 27 Jul 2025 17:34:43 +0200 Subject: [PATCH 25/72] Implement class for removing commentaries in Java source files Note: Commentary removal is only an approximation --- .../commentremoval/BrokenCommentTest.java | 340 +++++++++++++++++ .../BrokenMultiLineStringTest.java | 90 +++++ .../util/commentremoval/ICommentRemover.java | 43 +++ .../util/commentremoval/JavaDocTest.java | 345 +++++++++++++++++ .../commentremoval/MultiLineCommentTest.java | 349 ++++++++++++++++++ .../commentremoval/MultiLineStringTest.java | 153 ++++++++ .../commentremoval/QuickCommentRemover.java | 269 ++++++++++++++ .../commentremoval/SingleLineCommentTest.java | 205 ++++++++++ .../commentremoval/SingleLineStringTest.java | 241 ++++++++++++ .../SurroundedMultiLineCommentTest.java | 171 +++++++++ 10 files changed, 2206 insertions(+) create mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/commentremoval/BrokenCommentTest.java create mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/commentremoval/BrokenMultiLineStringTest.java create mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/commentremoval/ICommentRemover.java create mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/commentremoval/JavaDocTest.java create mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/commentremoval/MultiLineCommentTest.java create mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/commentremoval/MultiLineStringTest.java create mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/commentremoval/QuickCommentRemover.java create mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/commentremoval/SingleLineCommentTest.java create mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/commentremoval/SingleLineStringTest.java create mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/commentremoval/SurroundedMultiLineCommentTest.java diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/commentremoval/BrokenCommentTest.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/commentremoval/BrokenCommentTest.java new file mode 100644 index 0000000000..48669e4ad5 --- /dev/null +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/commentremoval/BrokenCommentTest.java @@ -0,0 +1,340 @@ +package cipm.consistency.fitests.repositorytests.util.commentremoval; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import cipm.consistency.fitests.repositorytests.util.difffilter.DiffFilter; + +/** + * Contains tests for (approximative) commentary removal from code snippets that + * are provided in form of Strings.
+ *
+ * Tests within this class are supposed to simulate cases; where the text is + * only a snippet of the code containing commentary and string literals, some of + * which have been cut off. Since there are different ways to interpret the + * given code without having access to all of it, adaptations to test results + * may be necessary in the future.
+ *
+ * Each test method consists of a beginning, where the exemplary code snippet is + * constructed (in form of text), then processed with an {@link ICommentRemover} + * and tested. + * + * @author Alp Torac Genc + */ +public class BrokenCommentTest { + private static final String multiLineStringToken = "\"\"\""; + private static final DiffFilter filter = new DiffFilter(); + + private ICommentRemover cr = new QuickCommentRemover(); + + @Test + public void handleBlockComment_LeadingBrokenComment() { + var line1 = "abc"; + var line2 = "*/"; + + var text = filter.concatLines(line1, line2); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(0, filteredText.size()); + Assertions.assertTrue(cr.hasLeadingBrokenComment(text)); + Assertions.assertFalse(cr.hasTrailingBrokenComment(text)); + } + + @Test + public void handleBlockComment_LeadingBrokenComment_BeforeMultiLineStringLiteral() { + var line1 = "abc"; + var line2 = "*/"; + var line3 = multiLineStringToken; + + var text = filter.concatLines(line1, line2, line3); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(1, filteredText.size()); + Assertions.assertEquals(line3, filteredText.get(0)); + Assertions.assertTrue(cr.hasLeadingBrokenComment(text)); + Assertions.assertFalse(cr.hasTrailingBrokenComment(text)); + } + + @Test + public void handleBlockComment_LeadingBrokenComment_AfterMultiLineStringLiteral() { + var line1 = "abc"; + var line2 = multiLineStringToken; + var line3 = "*/"; + + var text = filter.concatLines(line1, line2, line3); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(0, filteredText.size()); + Assertions.assertTrue(cr.hasLeadingBrokenComment(text)); + Assertions.assertFalse(cr.hasTrailingBrokenComment(text)); + } + + @Test + public void handleBlockComment_LeadingBrokenComment_AfterFullMultiLineStringLiteral() { + var line1 = multiLineStringToken; + var line2 = "abc"; + var line3 = multiLineStringToken; + var line4 = "*/"; + + var text = filter.concatLines(line1, line2, line3, line4); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(0, filteredText.size()); + Assertions.assertTrue(cr.hasLeadingBrokenComment(text)); + Assertions.assertFalse(cr.hasTrailingBrokenComment(text)); + } + + @Test + public void handleBlockComment_LeadingBrokenComment_InMultiLineStringLiteral() { + var line1 = "abc"; + var line2 = multiLineStringToken; + var line3 = "*/"; + var line4 = multiLineStringToken; + + var text = filter.concatLines(line1, line2, line3, line4); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(1, filteredText.size()); + Assertions.assertEquals(line4, filteredText.get(0)); + Assertions.assertTrue(cr.hasLeadingBrokenComment(text)); + Assertions.assertFalse(cr.hasTrailingBrokenComment(text)); + } + + @Test + public void handleBlockComment_LeadingBrokenComment_MultiLineStringTokenCheck() { + var line1 = multiLineStringToken; + var line2 = "abc"; + var line3 = multiLineStringToken; + var line4 = "*/"; + var line5 = multiLineStringToken; + + var text = filter.concatLines(line1, line2, line3, line4, line5); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(1, filteredText.size()); + Assertions.assertEquals(line5, filteredText.get(0)); + Assertions.assertTrue(cr.hasLeadingBrokenComment(text)); + Assertions.assertFalse(cr.hasTrailingBrokenComment(text)); + } + + @Test + public void handleBlockComment_TrailingBrokenComment() { + var line1 = "/*"; + var line2 = "abc"; + + var text = filter.concatLines(line1, line2); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(0, filteredText.size()); + Assertions.assertFalse(cr.hasLeadingBrokenComment(text)); + Assertions.assertTrue(cr.hasTrailingBrokenComment(text)); + } + + @Test + public void handleBlockComment_TrailingBrokenComment_BeforeMultiLineStringLiteral() { + var line1 = "/*"; + var line2 = multiLineStringToken; + var line3 = "abc"; + + var text = filter.concatLines(line1, line2, line3); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(0, filteredText.size()); + Assertions.assertFalse(cr.hasLeadingBrokenComment(text)); + Assertions.assertTrue(cr.hasTrailingBrokenComment(text)); + } + + @Test + public void handleBlockComment_TrailingBrokenComment_BeforeFullMultiLineStringLiteral() { + var line1 = "/*"; + var line2 = multiLineStringToken; + var line3 = "abc"; + var line4 = multiLineStringToken; + + var text = filter.concatLines(line1, line2, line3, line4); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(0, filteredText.size()); + Assertions.assertFalse(cr.hasLeadingBrokenComment(text)); + Assertions.assertTrue(cr.hasTrailingBrokenComment(text)); + } + + @Test + public void handleBlockComment_TrailingBrokenComment_AfterMultiLineStringLiteral() { + var line1 = multiLineStringToken; + var line2 = "/*"; + var line3 = "abc"; + + var text = filter.concatLines(line1, line2, line3); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(1, filteredText.size()); + Assertions.assertEquals(line1, filteredText.get(0)); + Assertions.assertFalse(cr.hasLeadingBrokenComment(text)); + Assertions.assertTrue(cr.hasTrailingBrokenComment(text)); + } + + @Test + public void handleBlockComment_TrailingBrokenComment_InMultiLineStringLiteral() { + var line1 = multiLineStringToken; + var line2 = "/*"; + var line3 = multiLineStringToken; + var line4 = "abc"; + + var text = filter.concatLines(line1, line2, line3, line4); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(1, filteredText.size()); + Assertions.assertEquals(line1, filteredText.get(0)); + Assertions.assertFalse(cr.hasLeadingBrokenComment(text)); + Assertions.assertTrue(cr.hasTrailingBrokenComment(text)); + } + + @Test + public void handleBlockComment_TrailingBrokenComment_MultiLineStringLiteralTokenCheck() { + var line1 = multiLineStringToken; + var line2 = "/*"; + var line3 = multiLineStringToken; + var line4 = "abc"; + var line5 = multiLineStringToken; + + var text = filter.concatLines(line1, line2, line3, line4, line5); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(1, filteredText.size()); + Assertions.assertEquals(line1, filteredText.get(0)); + Assertions.assertFalse(cr.hasLeadingBrokenComment(text)); + Assertions.assertTrue(cr.hasTrailingBrokenComment(text)); + } + + @Test + public void handleBlockComment_LeadingAndTrailingBrokenComments() { + var line1 = "abc"; + var line2 = "*/"; + var line3 = "def"; + var line4 = "/*"; + var line5 = "hgf"; + + var text = filter.concatLines(line1, line2, line3, line4, line5); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(1, filteredText.size()); + Assertions.assertEquals(line3, filteredText.get(0)); + Assertions.assertTrue(cr.hasLeadingBrokenComment(text)); + Assertions.assertTrue(cr.hasTrailingBrokenComment(text)); + } + + @Test + public void handleBlockComment_LeadingAndTrailingBrokenComments_BeforeMultiLineStringLiteral() { + var line1 = "abc"; + var line2 = "*/"; + var line3 = "def"; + var line4 = "/*"; + var line5 = multiLineStringToken; + var line6 = "hgf"; + + var text = filter.concatLines(line1, line2, line3, line4, line5, line6); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(1, filteredText.size()); + Assertions.assertEquals(line3, filteredText.get(0)); + Assertions.assertTrue(cr.hasLeadingBrokenComment(text)); + Assertions.assertTrue(cr.hasTrailingBrokenComment(text)); + } + + @Test + public void handleBlockComment_LeadingAndTrailingBrokenComments_AfterMultiLineStringLiteral() { + var line1 = "abc"; + var line2 = multiLineStringToken; + var line3 = "*/"; + var line4 = "def"; + var line5 = "/*"; + var line6 = "hgf"; + + var text = filter.concatLines(line1, line2, line3, line4, line5, line6); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(1, filteredText.size()); + Assertions.assertEquals(line4, filteredText.get(0)); + Assertions.assertTrue(cr.hasLeadingBrokenComment(text)); + Assertions.assertTrue(cr.hasTrailingBrokenComment(text)); + } + + @Test + public void handleBlockComment_LeadingAndTrailingBrokenComments_AroundMultiLineStringLiteral() { + var line1 = "abc"; + var line2 = "*/"; + var line3 = "def"; + var line4 = multiLineStringToken; + var line5 = "/*"; + var line6 = "hgf"; + + var text = filter.concatLines(line1, line2, line3, line4, line5, line6); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(2, filteredText.size()); + Assertions.assertEquals(line3, filteredText.get(0)); + Assertions.assertEquals(line4, filteredText.get(1)); + Assertions.assertTrue(cr.hasLeadingBrokenComment(text)); + Assertions.assertTrue(cr.hasTrailingBrokenComment(text)); + } + + @Test + public void handleBlockComment_LeadingAndTrailingBrokenComments_LeadingCommentSurroundedByMultiLineStringLiteral() { + var line1 = "abc"; + var line2 = multiLineStringToken; + var line3 = "*/"; + var line4 = multiLineStringToken; + var line5 = "def"; + var line6 = "/*"; + var line7 = "hgf"; + + var text = filter.concatLines(line1, line2, line3, line4, line5, line6, line7); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(2, filteredText.size()); + Assertions.assertEquals(line4, filteredText.get(0)); + Assertions.assertEquals(line5, filteredText.get(1)); + Assertions.assertTrue(cr.hasLeadingBrokenComment(text)); + Assertions.assertTrue(cr.hasTrailingBrokenComment(text)); + } + + @Test + public void handleBlockComment_LeadingAndTrailingBrokenComments_TrailingCommentSurroundedByMultiLineStringLiteral() { + var line1 = "abc"; + var line2 = "*/"; + var line3 = "def"; + var line4 = multiLineStringToken; + var line5 = "/*"; + var line6 = multiLineStringToken; + var line7 = "hgf"; + + var text = filter.concatLines(line1, line2, line3, line4, line5, line6, line7); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(2, filteredText.size()); + Assertions.assertEquals(line3, filteredText.get(0)); + Assertions.assertEquals(line4, filteredText.get(1)); + Assertions.assertTrue(cr.hasLeadingBrokenComment(text)); + Assertions.assertTrue(cr.hasTrailingBrokenComment(text)); + } + + @Test + public void handleBlockComment_LeadingAndTrailingBrokenComments_AllCommentsSurroundedByMultiLineStringLiteral() { + var line1 = "abc"; + var line2 = multiLineStringToken; + var line3 = "*/"; + var line4 = "def"; + var line5 = "/*"; + var line6 = multiLineStringToken; + var line7 = "hgf"; + + var text = filter.concatLines(line1, line2, line3, line4, line5, line6, line7); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(1, filteredText.size()); + Assertions.assertEquals(line4, filteredText.get(0)); + Assertions.assertTrue(cr.hasLeadingBrokenComment(text)); + Assertions.assertTrue(cr.hasTrailingBrokenComment(text)); + } +} diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/commentremoval/BrokenMultiLineStringTest.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/commentremoval/BrokenMultiLineStringTest.java new file mode 100644 index 0000000000..7792a9857a --- /dev/null +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/commentremoval/BrokenMultiLineStringTest.java @@ -0,0 +1,90 @@ +package cipm.consistency.fitests.repositorytests.util.commentremoval; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import cipm.consistency.fitests.repositorytests.util.difffilter.DiffFilter; + +/** + * Contains tests for (approximative) commentary removal from code snippets that + * are provided in form of Strings.
+ *
+ * Tests within this class are supposed to simulate cases; where the text is + * only a snippet of the code containing commentary and string literals, some of + * which have been cut off. Since there are different ways to interpret the + * given code without having access to all of it, adaptations to test results + * may be necessary in the future.
+ *
+ * Each test method consists of a beginning, where the exemplary code snippet is + * constructed (in form of text), then processed with an {@link ICommentRemover} + * and tested. + * + * @author Alp Torac Genc + */ +public class BrokenMultiLineStringTest { + private static final String multiLineStringToken = "\"\"\""; + private static final DiffFilter filter = new DiffFilter(); + + private ICommentRemover cr = new QuickCommentRemover(); + + @Test + public void handleUnclosedMultiLineStringLiteral() { + var start = multiLineStringToken; + var line1 = start + "abc"; + + var text = filter.concatLines(line1); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(1, filteredText.size()); + Assertions.assertEquals(line1, filteredText.get(0)); + } + + @Test + public void handleUnclosedMultiLineStringLiteral_FaultyEnd() { + var start = multiLineStringToken; + var end = "\"\""; + var line1 = start + "abc" + end; + + var text = filter.concatLines(line1); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(1, filteredText.size()); + Assertions.assertEquals(line1, filteredText.get(0)); + } + + @Test + public void handleUnclosedStringLiteral_WithSingleLineComment() { + var start = multiLineStringToken; + var line1 = start + "//abc"; + + var text = filter.concatLines(line1); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(1, filteredText.size()); + Assertions.assertEquals(start, filteredText.get(0)); + } + + @Test + public void handleUnclosedStringLiteral_WithMultiLineComment() { + var start = multiLineStringToken; + var line1 = start + "/*abc*/"; + + var text = filter.concatLines(line1); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(1, filteredText.size()); + Assertions.assertEquals(start, filteredText.get(0)); + } + + @Test + public void handleUnclosedStringLiteral_WithJavaDoc() { + var start = multiLineStringToken; + var line1 = start + "/**abc*/"; + + var text = filter.concatLines(line1); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(1, filteredText.size()); + Assertions.assertEquals(start, filteredText.get(0)); + } +} diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/commentremoval/ICommentRemover.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/commentremoval/ICommentRemover.java new file mode 100644 index 0000000000..cf320003bd --- /dev/null +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/commentremoval/ICommentRemover.java @@ -0,0 +1,43 @@ +package cipm.consistency.fitests.repositorytests.util.commentremoval; + +/** + * An interface for classes that are meant to remove (Java) comments from code + * snippets.
+ *
+ * Since comments may break when splitting a piece of code, it is theoretically + * not possible to accurately remove all comments, without having access to the + * entirety of the code. Due to this being potentially performance and memory + * intensive, removing comments from a large code can mostly be done + * approximately. As such, how the comments are detected and removed depends on + * the concrete implementation. + * + * @author Alp Torac Genc + */ +public interface ICommentRemover { + /** + * Depending on the concrete implementor, the result may be an approximation. + * + * @return The given text without comments. + */ + public String removeComments(String text); + + /** + * Depending on the concrete implementor, the result may be an approximation. + * + * @return Whether a comment broke at the beginning of the text; i.e. if there + * is a token that ends a comment is present at the beginning of the + * text (i.e. {@code * /}), without a preceding token starting the + * comment (such as {@code /*} ). + */ + public boolean hasLeadingBrokenComment(String text); + + /** + * Depending on the concrete implementor, the result may be an approximation. + * + * @return Whether a comment broke at the end of the text; i.e. if there is a + * token that starts a comment is present at the end of the text (such + * as {@code /*}), without a following token ending the comment (i.e. + * {@code * /}). + */ + public boolean hasTrailingBrokenComment(String text); +} diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/commentremoval/JavaDocTest.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/commentremoval/JavaDocTest.java new file mode 100644 index 0000000000..3b9eb91600 --- /dev/null +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/commentremoval/JavaDocTest.java @@ -0,0 +1,345 @@ +package cipm.consistency.fitests.repositorytests.util.commentremoval; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import cipm.consistency.fitests.repositorytests.util.difffilter.DiffFilter; + +/** + * Contains tests for (approximative) commentary removal from code snippets that + * are provided in form of Strings.
+ *
+ * Tests within this class are supposed to simulate cases; where the text is + * only a snippet of the code containing JavaDoc commentary, which potentially + * contains string tokens. Since there are different ways to interpret the given + * code without having access to all of it (ex: the JavaDoc comment could in + * reality be a part of a preceding/proceeding string literal), adaptations to + * test results may be necessary in the future.
+ *
+ * Each test method consists of a beginning, where the exemplary code snippet is + * constructed (in form of text), then processed with an {@link ICommentRemover} + * and tested. + * + * @author Alp Torac Genc + */ +public class JavaDocTest { + private static final String multiLineStringToken = "\"\"\""; + + private static final DiffFilter filter = new DiffFilter(); + private ICommentRemover cr = new QuickCommentRemover(); + + @Test + public void removeJavaDoc_SingleLine_FollowingCode() { + var code = "def "; + + var line1 = "/** abc */" + code; + + var text = filter.concatLines(line1); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(1, filteredText.size()); + Assertions.assertEquals(code, filteredText.get(0)); + } + + @Test + public void removeJavaDoc_SingleLine_SurroundingCode() { + var code1 = "def "; + var code2 = "hgf "; + + var line1 = code1 + "/** abc */" + code2; + + var text = filter.concatLines(line1); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(1, filteredText.size()); + Assertions.assertEquals(code1 + code2, filteredText.get(0)); + } + + @Test + public void removeJavaDoc_SingleLine_NoContext() { + var line1 = "/** abc */"; + + var text = filter.concatLines(line1); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(0, filteredText.size()); + } + + @Test + public void removeJavaDoc_SingleLine_PrecedingContext() { + var line1 = "def "; + var line2 = "/** abc */"; + + var text = filter.concatLines(line1, line2); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(1, filteredText.size()); + Assertions.assertEquals(line1, filteredText.get(0)); + } + + @Test + public void removeJavaDoc_SingleLine_FollowingContext() { + var line1 = "/** abc */"; + var line2 = "def "; + + var text = filter.concatLines(line1, line2); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(1, filteredText.size()); + Assertions.assertEquals(line2, filteredText.get(0)); + } + + @Test + public void removeJavaDoc_SingleLine_SurroundingContext() { + var line1 = "def "; + var line2 = "/** abc */"; + var line3 = "hgf "; + + var text = filter.concatLines(line1, line2, line3); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + + Assertions.assertEquals(2, filteredText.size()); + Assertions.assertEquals(line1, filteredText.get(0)); + Assertions.assertEquals(line3, filteredText.get(1)); + } + + @Test + public void removeJavaDoc_MultipleLine_PrecedingCode() { + var code = "def "; + + var line1 = code + "/**"; + var line2 = "abc"; + var line3 = "*/"; + + var text = filter.concatLines(line1, line2, line3); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(1, filteredText.size()); + Assertions.assertEquals(code, filteredText.get(0)); + } + + @Test + public void removeJavaDoc_MultipleLine_FollowingCode() { + var code = "def "; + + var line1 = "/**"; + var line2 = "abc"; + var line3 = "*/" + code; + + var text = filter.concatLines(line1, line2, line3); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(1, filteredText.size()); + Assertions.assertEquals(code, filteredText.get(0)); + } + + @Test + public void removeJavaDoc_MultipleLine_SurroundingCode() { + var code1 = "def "; + var code2 = "hgf "; + + var line1 = code1 + "/**"; + var line2 = "abc"; + var line3 = "*/" + code2; + + var text = filter.concatLines(line1, line2, line3); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + + // New lines were inside the commentary + Assertions.assertEquals(1, filteredText.size()); + Assertions.assertEquals(code1 + code2, filteredText.get(0)); + } + + @Test + public void removeJavaDoc_MultipleLine_NoContext() { + var line1 = "/**"; + var line2 = "abc"; + var line3 = "*/"; + + var text = filter.concatLines(line1, line2, line3); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(0, filteredText.size()); + } + + @Test + public void removeJavaDoc_MultipleLine_PrecedingContext() { + var line1 = "def "; + var line2 = "/**"; + var line3 = "abc"; + var line4 = "*/"; + + var text = filter.concatLines(line1, line2, line3, line4); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(1, filteredText.size()); + Assertions.assertEquals(line1, filteredText.get(0)); + } + + @Test + public void removeJavaDoc_MultipleLine_FollowingContext() { + var line1 = "/**"; + var line2 = "abc"; + var line3 = "*/"; + var line4 = "def "; + + var text = filter.concatLines(line1, line2, line3, line4); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(1, filteredText.size()); + Assertions.assertEquals(line4, filteredText.get(0)); + } + + @Test + public void removeJavaDoc_MultipleLine_SurroundingContext() { + var line1 = "def "; + var line2 = "/**"; + var line3 = "abc"; + var line4 = "*/"; + var line5 = "hgf "; + + var text = filter.concatLines(line1, line2, line3, line4, line5); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + + Assertions.assertEquals(2, filteredText.size()); + Assertions.assertEquals(line1, filteredText.get(0)); + Assertions.assertEquals(line5, filteredText.get(1)); + } + + @Test + public void removeJavaDoc_SingleLine_PrecedingCode() { + var code = "def "; + + var line1 = code + "/** abc */"; + + var text = filter.concatLines(line1); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(1, filteredText.size()); + Assertions.assertEquals(code, filteredText.get(0)); + } + + @Test + public void removeJavaDoc_MultipleComments_BothSingleLine() { + var line1 = "/** abc */"; + var line2 = "/** def */"; + + var text = filter.concatLines(line1, line2); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + + Assertions.assertEquals(0, filteredText.size()); + } + + @Test + public void removeJavaDoc_MultipleComments_BothInSameLineNoSpace() { + var line1 = "/** abc *//** def */"; + + var text = filter.concatLines(line1); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + + Assertions.assertEquals(0, filteredText.size()); + } + + @Test + public void removeJavaDoc_MultipleComments_BothInSameLineWithSpace() { + var line1 = "/** abc */ /** def */"; + + var text = filter.concatLines(line1); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + + Assertions.assertEquals(0, filteredText.size()); + } + + @Test + public void removeJavaDoc_MultipleComments_OneSingleLineOneMultipleLine() { + var line1 = "/** abc */"; + var line2 = "/**"; + var line3 = "def"; + var line4 = " */"; + + var text = filter.concatLines(line1, line2, line3, line4); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + + Assertions.assertEquals(0, filteredText.size()); + } + + @Test + public void removeJavaDoc_MultipleComments_OneSingleLineOneMultipleLine_NoSpace() { + var line1 = "/** abc *//**"; + var line2 = "def"; + var line3 = " */"; + + var text = filter.concatLines(line1, line2, line3); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + + Assertions.assertEquals(0, filteredText.size()); + } + + @Test + public void removeJavaDoc_MultipleComments_OneSingleLineOneMultipleLine_WithSpace() { + var line1 = "/** abc */ /**"; + var line2 = "def"; + var line3 = " */"; + + var text = filter.concatLines(line1, line2, line3); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + + Assertions.assertEquals(0, filteredText.size()); + } + + @Test + public void removeJavaDoc_MultipleComments_BothMultipleLine() { + var line1 = "/**"; + var line2 = "abc"; + var line3 = " */"; + var line4 = "/**"; + var line5 = "def"; + var line6 = " */"; + + var text = filter.concatLines(line1, line2, line3, line4, line5, line6); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + + Assertions.assertEquals(0, filteredText.size()); + } + + @Test + public void handleStringLiteralInComment_SingleLineStringLiteral() { + var line1 = "/** \"abc\" */"; + + var text = filter.concatLines(line1); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(0, filteredText.size()); + } + + @Test + public void handleStringLiteralInComment_MultiLineStringLiteral() { + var line1 = "/** " + multiLineStringToken + "abc" + multiLineStringToken + " */"; + + var text = filter.concatLines(line1); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(0, filteredText.size()); + } + + @Test + public void handleStringLiteralInComment_MultiLineStringLiteral_Split() { + var line1 = "/** " + multiLineStringToken + "abc"; + var line2 = multiLineStringToken + " */"; + + var text = filter.concatLines(line1, line2); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(0, filteredText.size()); + } +} diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/commentremoval/MultiLineCommentTest.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/commentremoval/MultiLineCommentTest.java new file mode 100644 index 0000000000..314879419e --- /dev/null +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/commentremoval/MultiLineCommentTest.java @@ -0,0 +1,349 @@ +package cipm.consistency.fitests.repositorytests.util.commentremoval; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import cipm.consistency.fitests.repositorytests.util.difffilter.DiffFilter; + +/** + * Contains tests for (approximative) commentary removal from code snippets that + * are provided in form of Strings.
+ *
+ * Tests within this class are supposed to simulate cases; where the text is + * only a snippet of the code containing block commentary, which potentially + * contains string tokens. Since there are different ways to interpret the given + * code without having access to all of it (ex: the block comment could in + * reality be a part of a preceding/proceeding string literal), adaptations to + * test results may be necessary in the future.
+ *
+ * Each test method consists of a beginning, where the exemplary code snippet is + * constructed (in form of text), then processed with an {@link ICommentRemover} + * and tested. + * + * @author Alp Torac Genc + */ +public class MultiLineCommentTest { + private static final String multiLineStringToken = "\"\"\""; + + private static final DiffFilter filter = new DiffFilter(); + private ICommentRemover cr = new QuickCommentRemover(); + + @Test + public void removeBlockComment_SingleLine_PrecedingCode() { + var code = "def "; + var line1 = code + "/* abc */"; + + var text = filter.concatLines(line1); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(1, filteredText.size()); + Assertions.assertEquals(code, filteredText.get(0)); + } + + @Test + public void removeBlockComment_SingleLine_FollowingCode() { + var code = "def "; + var line1 = "/* abc */" + code; + + var text = filter.concatLines(line1); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(1, filteredText.size()); + Assertions.assertEquals(code, filteredText.get(0)); + } + + @Test + public void removeBlockComment_SingleLine_SurroundingCode() { + var code1 = "def "; + var code2 = "hgf "; + var line1 = code1 + "/* abc */" + code2; + + var text = filter.concatLines(line1); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(1, filteredText.size()); + Assertions.assertEquals(code1 + code2, filteredText.get(0)); + } + + @Test + public void removeBlockComment_SingleLine_NoContext() { + var line1 = "/* abc */"; + + var text = filter.concatLines(line1); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(0, filteredText.size()); + } + + @Test + public void removeBlockComment_SingleLine_PrecedingContext() { + var line1 = "def "; + var line2 = "/* abc */"; + + var text = filter.concatLines(line1, line2); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(1, filteredText.size()); + Assertions.assertEquals(line1, filteredText.get(0)); + } + + @Test + public void removeBlockComment_SingleLine_FollowingContext() { + var line1 = "/* abc */"; + var line2 = "def "; + + var text = filter.concatLines(line1, line2); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(1, filteredText.size()); + Assertions.assertEquals(line2, filteredText.get(0)); + } + + @Test + public void removeBlockComment_SingleLine_SurroundingContext() { + var line1 = "def "; + var line2 = "/* abc */"; + var line3 = "hgf "; + + var text = filter.concatLines(line1, line2, line3); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + + Assertions.assertEquals(2, filteredText.size()); + Assertions.assertEquals(line1, filteredText.get(0)); + Assertions.assertEquals(line3, filteredText.get(1)); + } + + @Test + public void removeBlockComment_MultipleLine_PrecedingCode() { + var code = "def "; + var line1 = code + "/*"; + var line2 = "abc */"; + + var text = filter.concatLines(line1, line2); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(1, filteredText.size()); + Assertions.assertEquals(code, filteredText.get(0)); + } + + @Test + public void removeBlockComment_MultipleLine_FollowingCode() { + var code = "def "; + var line1 = "/* abc "; + var line2 = "*/" + code; + + var text = filter.concatLines(line1, line2); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(1, filteredText.size()); + Assertions.assertEquals(code, filteredText.get(0)); + } + + @Test + public void removeBlockComment_MultipleLine_SurroundingCode() { + var code1 = "def "; + var code2 = "hgf "; + + var line1 = code1 + "/* "; + var line2 = "abc */" + code2; + + var text = filter.concatLines(line1, line2); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + + // New line was the part of the commentary + Assertions.assertEquals(1, filteredText.size()); + Assertions.assertEquals(code1 + code2, filteredText.get(0)); + } + + @Test + public void removeBlockComment_MultipleLine_NoContext() { + var line1 = "/* "; + var line2 = "abc"; + var line3 = "*/"; + + var text = filter.concatLines(line1, line2, line3); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(0, filteredText.size()); + } + + @Test + public void removeBlockComment_MultipleLine_NoContext_WithStarInBody() { + var line1 = "/*"; + var line2 = " * abc"; + var line3 = " */"; + + var text = filter.concatLines(line1, line2, line3); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(0, filteredText.size()); + } + + @Test + public void removeBlockComment_MultipleLine_PrecedingContext() { + var line1 = "def "; + var line2 = "/* "; + var line3 = "abc"; + var line4 = "*/"; + + var text = filter.concatLines(line1, line2, line3, line4); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(1, filteredText.size()); + Assertions.assertEquals(line1, filteredText.get(0)); + } + + @Test + public void removeBlockComment_MultipleLine_FollowingContext() { + var line1 = "/*"; + var line2 = "abc"; + var line3 = "*/"; + var line4 = "def "; + + var text = filter.concatLines(line1, line2, line3, line4); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(1, filteredText.size()); + Assertions.assertEquals(line4, filteredText.get(0)); + } + + @Test + public void removeBlockComment_MultipleLine_SurroundingContext() { + var line1 = "def "; + var line2 = "/*"; + var line3 = "abc"; + var line4 = " */"; + var line5 = "hgf "; + + var text = filter.concatLines(line1, line2, line3, line4, line5); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + + Assertions.assertEquals(2, filteredText.size()); + Assertions.assertEquals(line1, filteredText.get(0)); + Assertions.assertEquals(line5, filteredText.get(1)); + } + + @Test + public void removeBlockComment_MultipleComments_BothSingleLine() { + var line1 = "/* abc */"; + var line2 = "/* def */"; + + var text = filter.concatLines(line1, line2); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + + Assertions.assertEquals(0, filteredText.size()); + } + + @Test + public void removeBlockComment_MultipleComments_BothInSameLineNoSpace() { + var line1 = "/* abc *//* def */"; + + var text = filter.concatLines(line1); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + + Assertions.assertEquals(0, filteredText.size()); + } + + @Test + public void removeBlockComment_MultipleComments_BothInSameLineWithSpace() { + var line1 = "/* abc */ /* def */"; + + var text = filter.concatLines(line1); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + + Assertions.assertEquals(0, filteredText.size()); + } + + @Test + public void removeBlockComment_MultipleComments_OneSingleLineOneMultipleLine() { + var line1 = "/* abc */"; + var line2 = "/*"; + var line3 = "def"; + var line4 = " */"; + + var text = filter.concatLines(line1, line2, line3, line4); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + + Assertions.assertEquals(0, filteredText.size()); + } + + @Test + public void removeBlockComment_MultipleComments_OneSingleLineOneMultipleLine_NoSpace() { + var line1 = "/* abc *//*"; + var line2 = "def"; + var line3 = " */"; + + var text = filter.concatLines(line1, line2, line3); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + + Assertions.assertEquals(0, filteredText.size()); + } + + @Test + public void removeBlockComment_MultipleComments_OneSingleLineOneMultipleLine_WithSpace() { + var line1 = "/* abc */ /*"; + var line2 = "def"; + var line3 = " */"; + + var text = filter.concatLines(line1, line2, line3); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + + Assertions.assertEquals(0, filteredText.size()); + } + + @Test + public void removeBlockComment_MultipleComments_BothMultipleLine() { + var line1 = "/*"; + var line2 = "abc"; + var line3 = " */"; + var line4 = "/*"; + var line5 = "def"; + var line6 = " */"; + + var text = filter.concatLines(line1, line2, line3, line4, line5, line6); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + + Assertions.assertEquals(0, filteredText.size()); + } + + @Test + public void handleStringLiteralInComment_SingleLineStringLiteral() { + var line1 = "/* \"abc\" */"; + + var text = filter.concatLines(line1); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(0, filteredText.size()); + } + + @Test + public void handleStringLiteralInComment_MultiLineStringLiteral() { + var line1 = "/* " + multiLineStringToken + "abc" + multiLineStringToken + " */"; + + var text = filter.concatLines(line1); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(0, filteredText.size()); + } + + @Test + public void handleStringLiteralInComment_MultiLineStringLiteral_Split() { + var line1 = "/* " + multiLineStringToken + "abc"; + var line2 = multiLineStringToken + " */"; + + var text = filter.concatLines(line1, line2); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(0, filteredText.size()); + } +} diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/commentremoval/MultiLineStringTest.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/commentremoval/MultiLineStringTest.java new file mode 100644 index 0000000000..54411f08fb --- /dev/null +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/commentremoval/MultiLineStringTest.java @@ -0,0 +1,153 @@ +package cipm.consistency.fitests.repositorytests.util.commentremoval; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import cipm.consistency.fitests.repositorytests.util.difffilter.DiffFilter; + +/** + * Contains tests for (approximative) commentary removal from code snippets that + * are provided in form of Strings.
+ *
+ * Tests within this class are supposed to simulate cases; where the text is + * only a snippet of the code containing multi-line strings, which potentially + * contains commentary tokens. Since there are different ways to interpret the + * given code without having access to all of it (ex: string tokens could in + * reality be a part of a preceding/proceeding string literal, meaning that the + * commentary that is supposedly a part of a string literal is in fact outside + * the string literal), adaptations to test results may be necessary in the + * future.
+ *
+ * Each test method consists of a beginning, where the exemplary code snippet is + * constructed (in form of text), then processed with an {@link ICommentRemover} + * and tested. + * + * @author Alp Torac Genc + */ +public class MultiLineStringTest { + private ICommentRemover cr = new QuickCommentRemover(); + private static final DiffFilter filter = new DiffFilter(); + + @Test + public void handleStringLiteral_SingleLineString_OnSameLine() { + var line1 = "\"\"\"abc\"\"\""; + + var text = filter.concatLines(line1); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(1, filteredText.size()); + Assertions.assertEquals(line1, filteredText.get(0)); + } + + @Test + public void handleStringLiteral_SingleLineString_StartAndStringOnSameLine() { + var line1 = "\"\"\"abc"; + var line2 = "\"\"\""; + + var text = filter.concatLines(line1, line2); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(2, filteredText.size()); + Assertions.assertEquals(line1, filteredText.get(0)); + Assertions.assertEquals(line2, filteredText.get(1)); + } + + @Test + public void handleStringLiteral_SingleLineString_EndAndStringOnSameLine() { + var line1 = "\"\"\""; + var line2 = "abc\"\"\""; + + var text = filter.concatLines(line1, line2); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(2, filteredText.size()); + Assertions.assertEquals(line1, filteredText.get(0)); + Assertions.assertEquals(line2, filteredText.get(1)); + } + + @Test + public void handleStringLiteral_SingleLineString_SurroundingStartAndEnd() { + var line1 = "\"\"\""; + var line2 = "abc"; + var line3 = "\"\"\""; + + var text = filter.concatLines(line1, line2, line3); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(3, filteredText.size()); + Assertions.assertEquals(line1, filteredText.get(0)); + Assertions.assertEquals(line2, filteredText.get(1)); + Assertions.assertEquals(line3, filteredText.get(2)); + } + + @Test + public void handleStringLiteral_MultiLineString_OnSameLine() { + var line1 = "\"\"\"abc"; + var line2 = "def\"\"\""; + + var text = filter.concatLines(line1, line2); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(2, filteredText.size()); + Assertions.assertEquals(line1, filteredText.get(0)); + Assertions.assertEquals(line2, filteredText.get(1)); + } + + @Test + public void handleStringLiteral_MultiLineString_StartAndStringOnSameLine() { + var line1 = "\"\"\"abc"; + var line2 = "def"; + var line3 = "\"\"\""; + + var text = filter.concatLines(line1, line2, line3); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(3, filteredText.size()); + Assertions.assertEquals(line1, filteredText.get(0)); + Assertions.assertEquals(line2, filteredText.get(1)); + Assertions.assertEquals(line3, filteredText.get(2)); + } + + @Test + public void handleStringLiteral_MultiLineString_EndAndStringOnSameLine() { + var line1 = "\"\"\""; + var line2 = "abc"; + var line3 = "def\"\"\""; + + var text = filter.concatLines(line1, line2, line3); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(3, filteredText.size()); + Assertions.assertEquals(line1, filteredText.get(0)); + Assertions.assertEquals(line2, filteredText.get(1)); + Assertions.assertEquals(line3, filteredText.get(2)); + } + + @Test + public void handleStringLiteral_MultiLineString_SurroundingStartAndEnd() { + var line1 = "\"\"\""; + var line2 = "abc"; + var line3 = "def"; + var line4 = "\"\"\""; + + var text = filter.concatLines(line1, line2, line3, line4); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(4, filteredText.size()); + Assertions.assertEquals(line1, filteredText.get(0)); + Assertions.assertEquals(line2, filteredText.get(1)); + Assertions.assertEquals(line3, filteredText.get(2)); + Assertions.assertEquals(line4, filteredText.get(3)); + } + + @Test + public void handleStringLiteral_SingleLineComment_OnSameLine() { + var line1 = "\"\"\"//abc\"\"\""; + + var text = filter.concatLines(line1); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(1, filteredText.size()); + Assertions.assertEquals(line1, filteredText.get(0)); + } +} diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/commentremoval/QuickCommentRemover.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/commentremoval/QuickCommentRemover.java new file mode 100644 index 0000000000..d5bcf06485 --- /dev/null +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/commentremoval/QuickCommentRemover.java @@ -0,0 +1,269 @@ +package cipm.consistency.fitests.repositorytests.util.commentremoval; + +import java.util.regex.Pattern; + +/** + * A comment remover that gives precedence to block-comment tokens (such as + * {@code /*, * /}) over string tokens (i.e. {@code " and """}), unless the + * comment is guaranteed to be a part of a string literal. That means, all + * potentially broken block-comments are removed, even if they are a part of a + * string literal in reality. The comment removal offered by this class is + * an approximation.
+ *
+ * Note: Currently does not support parsing multi-line strings as + * is; due to them having the same token mark their start and end, as + * well as potentially spanning over multiple lines. This makes it so that one + * cannot determine whether a multi-line string token is supposed to mark the + * start or the end of the string literal better than guessing, unlike tokens + * from block commentaries that are different. Therefore; multi-line + * strings are interpreted as 3 consecutive, single-line strings, where the + * first and the last single-line strings are blank. + * + * @author Alp Torac Genc + */ +public class QuickCommentRemover implements ICommentRemover { + /** + * Pattern that matches a single line string literal's start or end, i.e. an + * unescaped quotation mark. + */ + private static final Pattern singleLineStringLiteralQuotation = Pattern.compile("(? + *
+ * Does not account for potential multi-line string declarations + * {@code """..."""}. Multi-line string declarations are handled, as if they + * were consecutive single line string literals. This means, multi-line + * strings that are declared on the same line are still detected as string + * literals. However, multi-line strings that are declared over multiple lines + * are detected as faulty string literals, i.e. this method returns -1. + * + * @param quotationIdx The index of the quotation mark, which starts the string + * literal. In {@code "abc"}, it is 0. + * @param text The text that should be analysed for single line string + * literals + * @return The first index at the end of the single line string literal. In + * {@code "abc"}, it is 4. Returns -1 if the string literal never ends. + */ + private int parseSingleLineStringLiteral(int quotationIdx, String text) { + var matcher = singleLineStringLiteralQuotation.matcher(text); + if (!matcher.find(quotationIdx) || matcher.start() != quotationIdx) + // quotationIdx does not mark the start of a single line string literal + return -1; + + /* + * If this line is not the last line of the text, limit the matcher's range to + * the index of the line separator, since single line string literals have to + * start and end on the same line. + */ + var newLineIdx = text.indexOf(lineSeparator, quotationIdx); + var rangeEnd = newLineIdx != -1 ? newLineIdx : text.length(); + + /* + * Start from quotationIdx + 1 to not re-match the starting quotation mark, + * since the starting and ending tokens (") are the same. + * + * Single line strings have to start and end on the same line, so only consider + * the char sequence between the starting quotation mark and the end of the line + * (either line break or end of text). + */ + return matcher.region(quotationIdx + 1, rangeEnd).find() ? + // End of the string literal found, return index after closing quotation mark + matcher.end() : + // Single line string literal is never closed => Problem with text + -1; + } + + /** + * Multi line string literals (such as {@code """abc"""}) cannot be nested. + * Start from quotationIdx and look for the end of the string literal. + * + * @param quotationIdx The starting index of the multi line string token + * {@code """}, which starts the string literal. In + * {@code """abc"""}, it is 0. + * @param text The text that should be analysed for multi line string + * literals + * @return The first index at the end of the multi line string literal. . In + * {@code """abc"""}, it is 8. Returns -1 if the string literal never + * ends. + */ + @SuppressWarnings("unused") + private int parseMultiLineStringLiteral(int quotationIdx, String text) { + var mlstLen = multiLineStringToken.length(); + + // Make sure that there are enough characters left for a multi-line string + if (text.length() < quotationIdx + mlstLen + || !text.substring(quotationIdx, quotationIdx + mlstLen).equals(multiLineStringToken)) + // quotationIdx does not mark the start of a multi line string literal + return -1; + + // Skip quotationIdx, since the starting and ending tokens (""") are the same + for (int i = quotationIdx + mlstLen; i <= text.length() - mlstLen; i++) { + if (text.substring(i, i + mlstLen).equals(multiLineStringToken)) { + // End of the multi-line string found, return index after multiLineStringToken + // (""") + return i + mlstLen; + } + } + + // Multi line string literal is never closed => Problem with text + return -1; + } + + /** + * Single line comments (such as {@code // abc}) cannot be nested. Start from + * doubleSlashIdx and look for the end of the line. + * + * @param doubleSlashIdx The starting index of the single line comment + * @param text The text that should be analysed for single line + * comments + * @return The first index at the end of the single line comment, i.e. the + * beginning of the next line. + */ + private int parseSingleLineComment(int doubleSlashIdx, String text) { + var matcher = singleLineComment.matcher(text); + + if (!matcher.find(doubleSlashIdx) || matcher.start() != doubleSlashIdx) { + return -1; + } + + var lineSepIdx = text.indexOf(lineSeparator, doubleSlashIdx); + if (lineSepIdx != -1) + return lineSepIdx; + + // No line break found, single line comment goes till the end of the text + return text.length(); + } + + /** + * Multi line comments (such as {@code // abc}) cannot be nested. Start from + * slashStarIdx and look for the end of the multi line comment.
+ *
+ * Accounts for both multi line comments (i.e. {@code /* ... * /} ) and JavaDoc + * (i.e. {@code /** .... * /}). + * + * @param slashStarIdx The starting index of the multi line comment + * @param text The text that should be analysed for multi line comments + * @return The first index at the end of the multi line comment. Returns -1 if + * the comment never ends. + */ + private int parseBlockComment(int slashStarIdx, String text) { + var startMatcher = multiLineBlockCommentStart.matcher(text); + + if (!startMatcher.find(slashStarIdx) || startMatcher.start() != slashStarIdx) { + return -1; + } + + var endMatcher = multiLineBlockCommentEnd.matcher(text); + if (endMatcher.find(startMatcher.end())) { + // Comment end found, return index after comment + return endMatcher.end(); + } + + // Block comment never closed => Problem with text + return -1; + } + + /** + * {@inheritDoc} + * + * @see {@link QuickCommentRemover} for more information. + */ + public String removeComments(String text) { + var result = ""; + + var currentCharIdx = 0; + while (currentCharIdx < text.length()) { + var parseEndIdx = -1; + + /* + * Check order: + * + * 1) Single line string literals: Can contain tokens of comments, which turns + * them into substrings as opposed to commentary tokens + * + * 2) Block comments: May start and end in a single line (can end before the end + * of the line), includes JavaDocs as well. Could contain single line comment + * token "//", which makes it a part of the block comment as opposed to making + * the rest of the line commentary. In this case, the commentary ends with the + * end of the block comment and not with the end of the line. + * + * 3) Single line comments (can only end with newline) + */ + + if ((parseEndIdx = this.parseSingleLineStringLiteral(currentCharIdx, text)) != -1) { + result += text.substring(currentCharIdx, parseEndIdx); + } else if ((parseEndIdx = this.parseBlockComment(currentCharIdx, text)) != -1) { + } else if ((parseEndIdx = this.parseSingleLineComment(currentCharIdx, text)) != -1) { + } else { + result += text.charAt(currentCharIdx); + } + + if (parseEndIdx != -1) { + currentCharIdx = parseEndIdx; + } else { + currentCharIdx++; + } + } + + if (this.hasLeadingBrokenComment(result)) { + // There is leading broken commentary, cut it out + var blockCommentEndIdx = result.indexOf(blockCommentEnd); + result = result.substring(blockCommentEndIdx + blockCommentEnd.length(), result.length()); + } + if (this.hasTrailingBrokenComment(result)) { + // There is trailing broken commentary, cut it out + result = result.substring(0, result.lastIndexOf(blockCommentStart)); + } + + return result; + } + + /** + * {@inheritDoc}
+ *
+ * Does not account for the broken comments to be a part of a multi-line string. + */ + public boolean hasLeadingBrokenComment(String text) { + var blockCommentStartIdx = text.indexOf(blockCommentStart); + var blockCommentEndIdx = text.indexOf(blockCommentEnd); + + return blockCommentEndIdx != -1 && (blockCommentStartIdx == -1 || blockCommentStartIdx > blockCommentEndIdx); + + } + + /** + * {@inheritDoc}
+ *
+ * Does not account for the broken comments to be a part of a multi-line string. + */ + public boolean hasTrailingBrokenComment(String text) { + var blockCommentStartIdx = text.lastIndexOf(blockCommentStart); + var blockCommentEndIdx = text.lastIndexOf(blockCommentEnd); + + return blockCommentStartIdx != -1 && (blockCommentEndIdx == -1 || blockCommentStartIdx > blockCommentEndIdx); + } +} diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/commentremoval/SingleLineCommentTest.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/commentremoval/SingleLineCommentTest.java new file mode 100644 index 0000000000..65e84c74e6 --- /dev/null +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/commentremoval/SingleLineCommentTest.java @@ -0,0 +1,205 @@ +package cipm.consistency.fitests.repositorytests.util.commentremoval; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import cipm.consistency.fitests.repositorytests.util.difffilter.DiffFilter; + +/** + * Contains tests for (approximative) commentary removal from code snippets that + * are provided in form of Strings.
+ *
+ * Tests within this class are supposed to simulate cases; where the text is + * only a snippet of the code containing commentary, some of which containing + * string tokens.
+ *
+ * Each test method consists of a beginning, where the exemplary code snippet is + * constructed (in form of text), then processed with an {@link ICommentRemover} + * and tested. + * + * @author Alp Torac Genc + */ +public class SingleLineCommentTest { + private static final String multiLineStringToken = "\"\"\""; + + private ICommentRemover cr = new QuickCommentRemover(); + private static final DiffFilter filter = new DiffFilter(); + + @Test + public void removeSingleLineComment_PrecedingCode() { + var code = "def "; + var line1 = code + "// abc"; + + var text = filter.concatLines(line1); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(1, filteredText.size()); + Assertions.assertEquals(code, filteredText.get(0)); + } + + @Test + public void removeSingleLineComment_NoContext() { + var line1 = "// abc"; + + var text = filter.concatLines(line1); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(0, filteredText.size()); + } + + @Test + public void removeSingleLineComment_PrecedingContext() { + var line1 = "def "; + var line2 = "// abc "; + + var text = filter.concatLines(line1, line2); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(1, filteredText.size()); + Assertions.assertEquals(line1, filteredText.get(0)); + } + + @Test + public void removeSingleLineComment_FollowingContext() { + var line1 = "// abc "; + var line2 = "def "; + + var text = filter.concatLines(line1, line2); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(1, filteredText.size()); + Assertions.assertEquals(line2, filteredText.get(0)); + } + + @Test + public void removeSingleLineComment_SurroundingContext() { + var line1 = "def "; + var line2 = "// abc "; + var line3 = "hgf "; + + var text = filter.concatLines(line1, line2, line3); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + + Assertions.assertEquals(2, filteredText.size()); + Assertions.assertEquals(line1, filteredText.get(0)); + Assertions.assertEquals(line3, filteredText.get(1)); + } + + @Test + public void removeSingleLineComment_MultipleComments_PrecedingCode() { + var code = "def "; + var line1 = code + "// abc"; + var line2 = "// hgf"; + + var text = filter.concatLines(line1, line2); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(1, filteredText.size()); + Assertions.assertEquals(code, filteredText.get(0)); + } + + @Test + public void removeSingleLineComment_MultipleComments_NoContext() { + var line1 = "// abc"; + var line2 = "// def"; + + var text = filter.concatLines(line1, line2); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(0, filteredText.size()); + } + + @Test + public void removeSingleLineComment_MultipleComments_PrecedingContext() { + var line1 = "def "; + var line2 = "// abc "; + var line3 = "// hgf "; + + var text = filter.concatLines(line1, line2, line3); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(1, filteredText.size()); + Assertions.assertEquals(line1, filteredText.get(0)); + } + + @Test + public void removeSingleLineComment_MultipleComments_FollowingContext() { + var line1 = "// abc "; + var line2 = "// hgf "; + var line3 = "def "; + + var text = filter.concatLines(line1, line2, line3); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(1, filteredText.size()); + Assertions.assertEquals(line3, filteredText.get(0)); + } + + @Test + public void removeSingleLineComment_MultipleComments_SurroundingContext() { + var line1 = "def "; + var line2 = "// abc "; + var line3 = "// jkl "; + var line4 = "hgf "; + + var text = filter.concatLines(line1, line2, line3, line4); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + + Assertions.assertEquals(2, filteredText.size()); + Assertions.assertEquals(line1, filteredText.get(0)); + Assertions.assertEquals(line4, filteredText.get(1)); + } + + @Test + public void removeSingleLineComment_RepeatingSlashes() { + var line1 = "// // abc"; + + var text = filter.concatLines(line1); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(0, filteredText.size()); + } + + @Test + public void removeSingleLineComment_SurroundingSlashes() { + var line1 = "// abc //"; + + var text = filter.concatLines(line1); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(0, filteredText.size()); + } + + @Test + public void handleStringLiteralInComment_SingleLineStringLiteral() { + var line1 = "// \"abc\""; + + var text = filter.concatLines(line1); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(0, filteredText.size()); + } + + @Test + public void handleStringLiteralInComment_MultiLineStringLiteral() { + var line1 = "// " + multiLineStringToken + "abc" + multiLineStringToken; + + var text = filter.concatLines(line1); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(0, filteredText.size()); + } + + @Test + public void handleStringLiteralInComment_MultiLineStringLiteral_Split() { + var line1 = "// " + multiLineStringToken + "abc"; + var line2 = "// " + multiLineStringToken; + + var text = filter.concatLines(line1, line2); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(0, filteredText.size()); + } +} diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/commentremoval/SingleLineStringTest.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/commentremoval/SingleLineStringTest.java new file mode 100644 index 0000000000..41a228c46b --- /dev/null +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/commentremoval/SingleLineStringTest.java @@ -0,0 +1,241 @@ +package cipm.consistency.fitests.repositorytests.util.commentremoval; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import cipm.consistency.fitests.repositorytests.util.difffilter.DiffFilter; + +/** + * Contains tests for (approximative) commentary removal from code snippets that + * are provided in form of Strings.
+ *
+ * Tests within this class are supposed to simulate cases; where the text is + * only a snippet of the code containing string literals, some of which + * containing commentary tokens.
+ *
+ * Each test method consists of a beginning, where the exemplary code snippet is + * constructed (in form of text), then processed with an {@link ICommentRemover} + * and tested. + * + * @author Alp Torac Genc + */ +public class SingleLineStringTest { + private static final String multiLineStringToken = "\"\"\""; + + private static final DiffFilter filter = new DiffFilter(); + private ICommentRemover cr = new QuickCommentRemover(); + + @Test + public void handleStringLiteral() { + var line1 = "\"abc\""; + + var text = filter.concatLines(line1); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(1, filteredText.size()); + Assertions.assertEquals(line1, filteredText.get(0)); + } + + @Test + public void handleStringLiteral_WithSingleEscapedQuotation() { + var line1 = "\"\\\"abc\""; + + var text = filter.concatLines(line1); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(1, filteredText.size()); + Assertions.assertEquals(line1, filteredText.get(0)); + } + + @Test + public void handleStringLiteral_WithMultipleEscapedQuotations() { + var line1 = "\"\\\"abc\\\"\""; + + var text = filter.concatLines(line1); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(1, filteredText.size()); + Assertions.assertEquals(line1, filteredText.get(0)); + } + + @Test + public void handleStringLiteral_MultiLineStringAsSingleLineString() { + var line1 = multiLineStringToken + "//abc" + multiLineStringToken; + + var text = filter.concatLines(line1); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(1, filteredText.size()); + Assertions.assertEquals(line1, filteredText.get(0)); + } + + @Test + public void handleSingleLineCommentInStringLiteral() { + var line1 = "\"// abc\""; + + var text = filter.concatLines(line1); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(1, filteredText.size()); + Assertions.assertEquals(line1, filteredText.get(0)); + } + + @Test + public void handleMultiLineCommentInStringLiteral() { + var line1 = "\"/* abc */\""; + + var text = filter.concatLines(line1); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(1, filteredText.size()); + Assertions.assertEquals(line1, filteredText.get(0)); + } + + @Test + public void handleJavaDocInStringLiteral() { + var line1 = "\"/** abc */\""; + + var text = filter.concatLines(line1); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(1, filteredText.size()); + Assertions.assertEquals(line1, filteredText.get(0)); + } + + @Test + public void handleSingleLineCommentInStringLiteral_WithEscapedQuotation() { + var line1 = "\"\\\"// abc\""; + + var text = filter.concatLines(line1); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(1, filteredText.size()); + Assertions.assertEquals(line1, filteredText.get(0)); + } + + @Test + public void handleMultiLineCommentInStringLiteral_WithEscapedQuotation() { + var line1 = "\"\\\"/* abc */\""; + + var text = filter.concatLines(line1); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(1, filteredText.size()); + Assertions.assertEquals(line1, filteredText.get(0)); + } + + @Test + public void handleJavaDocInStringLiteral_WithEscapedQuotation() { + var line1 = "\"\\\"/** abc */\""; + + var text = filter.concatLines(line1); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(1, filteredText.size()); + Assertions.assertEquals(line1, filteredText.get(0)); + } + + @Test + public void handleUnclosedStringLiteral() { + var code = "\"abc"; + var comment = "//def"; + var line1 = code + comment; + + var text = filter.concatLines(line1); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(1, filteredText.size()); + Assertions.assertEquals(code, filteredText.get(0)); + } + + @Test + public void handleUnclosedStringLiteral_WithEscapedQuotationStart() { + var code = "\\\"abc"; + var comment = "//def\""; + var line1 = code + comment; + + var text = filter.concatLines(line1); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(1, filteredText.size()); + Assertions.assertEquals(code, filteredText.get(0)); + } + + @Test + public void handleUnclosedStringLiteral_WithEscapedQuotationEnd() { + var code = "\"abc"; + var comment = "//def\\\""; + var line1 = code + comment; + + var text = filter.concatLines(line1); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(1, filteredText.size()); + Assertions.assertEquals(code, filteredText.get(0)); + } + + @Test + public void handleUnclosedStringLiteral_WithSingleLineComment() { + var start = "\""; + var line1 = start + "//abc"; + + var text = filter.concatLines(line1); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(1, filteredText.size()); + Assertions.assertEquals(start, filteredText.get(0)); + } + + @Test + public void handleUnclosedStringLiteral_WithMultiLineComment() { + var start = "\""; + var line1 = start + "/*abc*/"; + + var text = filter.concatLines(line1); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(1, filteredText.size()); + Assertions.assertEquals(start, filteredText.get(0)); + } + + @Test + public void handleUnclosedStringLiteral_WithJavaDoc() { + var start = "\""; + var line1 = start + "/**abc*/"; + + var text = filter.concatLines(line1); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(1, filteredText.size()); + Assertions.assertEquals(start, filteredText.get(0)); + } + + @Test + public void handleBrokenStringLiteral_SingleLineString_AcrossTwoLines() { + var comment = "//abc"; + + var line1 = "\"" + comment; + var line2 = "\""; + + var text = filter.concatLines(line1, line2); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(2, filteredText.size()); + Assertions.assertEquals("\"", filteredText.get(0)); + Assertions.assertEquals("\"", filteredText.get(1)); + } + + @Test + public void handleBrokenStringLiteral_SingleLineString_AcrossThreeLines() { + var line1 = "\""; + var line2 = "//abc"; + var line3 = "\""; + + var text = filter.concatLines(line1, line2, line3); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(2, filteredText.size()); + Assertions.assertEquals("\"", filteredText.get(0)); + Assertions.assertEquals("\"", filteredText.get(1)); + } +} diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/commentremoval/SurroundedMultiLineCommentTest.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/commentremoval/SurroundedMultiLineCommentTest.java new file mode 100644 index 0000000000..b24ebfb41a --- /dev/null +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/commentremoval/SurroundedMultiLineCommentTest.java @@ -0,0 +1,171 @@ +package cipm.consistency.fitests.repositorytests.util.commentremoval; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import cipm.consistency.fitests.repositorytests.util.difffilter.DiffFilter; + +/** + * Contains tests for (approximative) commentary removal from code snippets that + * are provided in form of Strings.
+ *
+ * Tests within this class are supposed to simulate cases; where the text is + * only a snippet of the code containing commentary, which is placed in a + * multi-line string literal. Since there are different ways to interpret the + * given code without having access to all of it (ex: the multi-line string + * tokens may belong to other preceding/proceeding string literals), adaptations + * to test results may be necessary in the future.
+ *
+ * Each test method consists of a beginning, where the exemplary code snippet is + * constructed (in form of text), then processed with an {@link ICommentRemover} + * and tested. + * + * @author Alp Torac Genc + */ +public class SurroundedMultiLineCommentTest { + private static final String multiLineStringToken = "\"\"\""; + + private static final DiffFilter filter = new DiffFilter(); + private ICommentRemover cr = new QuickCommentRemover(); + + @Test + public void handleStringLiteral_SingleLineComment_StartAndStringOnSameLine() { + var line1 = multiLineStringToken + "//abc"; + var line2 = multiLineStringToken; + + var text = filter.concatLines(line1, line2); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(2, filteredText.size()); + Assertions.assertEquals(multiLineStringToken, filteredText.get(0)); + Assertions.assertEquals(line2, filteredText.get(1)); + } + + @Test + public void handleStringLiteral_SingleLineComment_EndAndStringOnSameLine() { + var line1 = multiLineStringToken; + var line2 = "//abc" + multiLineStringToken; + + var text = filter.concatLines(line1, line2); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(1, filteredText.size()); + Assertions.assertEquals(line1, filteredText.get(0)); + } + + @Test + public void handleStringLiteral_SingleLineComment_SurroundingStartAndEnd() { + var line1 = multiLineStringToken; + var line2 = "//abc"; + var line3 = multiLineStringToken; + + var text = filter.concatLines(line1, line2, line3); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(2, filteredText.size()); + Assertions.assertEquals(line1, filteredText.get(0)); + Assertions.assertEquals(line3, filteredText.get(1)); + } + + @Test + public void handleStringLiteral_MultiLineComment_OnSameLine() { + var line1 = multiLineStringToken + "/*abc*/" + multiLineStringToken; + + var text = filter.concatLines(line1); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(1, filteredText.size()); + Assertions.assertEquals(line1, filteredText.get(0)); + } + + @Test + public void handleStringLiteral_MultiLineComment_StartAndStringOnSameLine() { + var line1 = multiLineStringToken + "/*abc*/"; + var line2 = multiLineStringToken; + + var text = filter.concatLines(line1, line2); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(2, filteredText.size()); + Assertions.assertEquals(multiLineStringToken, filteredText.get(0)); + Assertions.assertEquals(line2, filteredText.get(1)); + } + + @Test + public void handleStringLiteral_MultiLineComment_EndAndStringOnSameLine() { + var line1 = multiLineStringToken; + var line2 = "/*abc*/" + multiLineStringToken; + + var text = filter.concatLines(line1, line2); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(2, filteredText.size()); + Assertions.assertEquals(line1, filteredText.get(0)); + Assertions.assertEquals(multiLineStringToken, filteredText.get(1)); + } + + @Test + public void handleStringLiteral_MultiLineComment_SurroundingStartAndEnd() { + var line1 = multiLineStringToken; + var line2 = "/*abc*/"; + var line3 = multiLineStringToken; + + var text = filter.concatLines(line1, line2, line3); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(2, filteredText.size()); + Assertions.assertEquals(line1, filteredText.get(0)); + Assertions.assertEquals(line3, filteredText.get(1)); + } + + @Test + public void handleStringLiteral_JavaDoc_OnSameLine() { + var line1 = multiLineStringToken + "/**abc*/" + multiLineStringToken; + + var text = filter.concatLines(line1); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(1, filteredText.size()); + Assertions.assertEquals(line1, filteredText.get(0)); + } + + @Test + public void handleStringLiteral_JavaDoc_StartAndStringOnSameLine() { + var line1 = multiLineStringToken + "/**abc*/"; + var line2 = multiLineStringToken; + + var text = filter.concatLines(line1, line2); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(2, filteredText.size()); + Assertions.assertEquals(multiLineStringToken, filteredText.get(0)); + Assertions.assertEquals(line2, filteredText.get(1)); + } + + @Test + public void handleStringLiteral_JavaDoc_EndAndStringOnSameLine() { + var line1 = multiLineStringToken; + var line2 = "/**abc*/" + multiLineStringToken; + + var text = filter.concatLines(line1, line2); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(2, filteredText.size()); + Assertions.assertEquals(line1, filteredText.get(0)); + Assertions.assertEquals(multiLineStringToken, filteredText.get(1)); + } + + @Test + public void handleStringLiteral_JavaDoc_SurroundingStartAndEnd() { + var line1 = multiLineStringToken; + var line2 = "/**abc*/"; + var line3 = multiLineStringToken; + + var text = filter.concatLines(line1, line2, line3); + + var filteredText = filter.removeBlankLines(filter.splitLines(cr.removeComments(text))); + Assertions.assertEquals(2, filteredText.size()); + Assertions.assertEquals(line1, filteredText.get(0)); + Assertions.assertEquals(line3, filteredText.get(1)); + } +} From aeca8f4bad6f3117034a95092500921d090fb16b Mon Sep 17 00:00:00 2001 From: AlpTorac Date: Sun, 27 Jul 2025 17:35:51 +0200 Subject: [PATCH 26/72] Implement tests for diff processing realistic diff patches --- .../util/UtilityClassesRealCodeTest.java | 86 +++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/UtilityClassesRealCodeTest.java diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/UtilityClassesRealCodeTest.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/UtilityClassesRealCodeTest.java new file mode 100644 index 0000000000..46a0823781 --- /dev/null +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/UtilityClassesRealCodeTest.java @@ -0,0 +1,86 @@ +package cipm.consistency.fitests.repositorytests.util; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import cipm.consistency.fitests.repositorytests.util.commentremoval.QuickCommentRemover; +import cipm.consistency.fitests.repositorytests.util.difffilter.DiffFilter; + +/** + * A test class that tests {@link QuickCommentRemover} and {@link DiffFilter} on + * real GIT diff patches. + * + * @author Alp Torac Genc + */ +public class UtilityClassesRealCodeTest { + private static final QuickCommentRemover qr = new QuickCommentRemover(); + private static final DiffFilter filter = new DiffFilter(); + + @Test + public void parserTestRepo_Test1() { + var classDecl = "public class Cls1 {"; + var methodDecl = "public void met1() {"; + + var text = "diff --git a/Cls1.java b/Cls1.java\r\n" + // + + "index 921acbe..309f622 100644\r\n" + // + + "--- a/Cls1.java\r\n" + // + + "+++ b/Cls1.java\r\n" + // + + "@@ -1,3 +1,6 @@\r\n" + // + + "+/**\r\n" + // + + "+ * SomeCommentary\r\n" + // + + "+ */\r\n" + // + + classDecl + "\r\n" + // + + methodDecl + "\r\n" + // + + " \r\n"; + + var lines = filter.removeBlankLines(filter.removeNonPatchScript(filter.splitLines(qr.removeComments(text)))); + + Assertions.assertEquals(2, lines.size()); + Assertions.assertEquals(classDecl, lines.get(0)); + Assertions.assertEquals(methodDecl, lines.get(1)); + } + + @Test + public void parserTestRepo_Test2() { + var classDecl = "public class Cls1 {"; + var methodDecl = "public void met1() {"; + + var text = "diff --git a/Cls1.java b/Cls1.java\r\n" + // + + "index 309f622..921acbe 100644\r\n" + // + + "--- a/Cls1.java\r\n" + // + + "+++ b/Cls1.java\r\n" + // + + "@@ -1,6 +1,3 @@\r\n" + // + + "-/**\r\n" + // + + "- * SomeCommentary\r\n" + // + + "- */\r\n" + // + + classDecl + "\r\n" + // + + methodDecl + "\r\n" + // + + " \r\n"; + + var lines = filter.removeBlankLines(filter.removeNonPatchScript(filter.splitLines(qr.removeComments(text)))); + + Assertions.assertEquals(2, lines.size()); + Assertions.assertEquals(classDecl, lines.get(0)); + Assertions.assertEquals(methodDecl, lines.get(1)); + } +} From 1f08df570b9d2f9c0fece921b4c70f8f8294f0fd Mon Sep 17 00:00:00 2001 From: AlpTorac Date: Sun, 27 Jul 2025 17:37:55 +0200 Subject: [PATCH 27/72] Implement class for storing computed expected similarity results Assumes reflexivity, symmetry and transitivity properties (explained in RepoTestResultCache commentary) --- .../util/RepoTestResultCache.java | 426 ++++++++++++++++++ .../util/RepoTestResultCacheTest.java | 404 +++++++++++++++++ 2 files changed, 830 insertions(+) create mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/RepoTestResultCache.java create mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/RepoTestResultCacheTest.java diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/RepoTestResultCache.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/RepoTestResultCache.java new file mode 100644 index 0000000000..04b875fbc9 --- /dev/null +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/RepoTestResultCache.java @@ -0,0 +1,426 @@ +package cipm.consistency.fitests.repositorytests.util; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; +import java.util.Stack; + +/** + * A class that stores expected similarity checking results of the commits with + * the given IDs. + * + * Assumptions on similarity checking: + *
    + *
  • Reflexivity: Same commits are similar with respect to similarity checking + *
  • Symmetry: Similarity is symmetric (i.e. swapping commitID1 and commitID2 + * does not change the similarity result). + *
      + *
    • The expected similarity results stored here are also symmetric, i.e. the + * result for (commitID1, commitID2) is always the same as the result for + * (commitID2, commitID1). Therefore, there is only one result stored for + * (commitID1, commitID2) and (commitID2, commitID1). + *
    • This also implies that it does not matter on what side the 2 commits are. + *
    + *
  • Transitivity: Assuming C1, C2 and C3 are different commits; if C1 and C2 + * are similar, C2 and C3 are similar; then C1 and C3 should also be similar. + *
      + *
    • Assuming C1, C2, ..., CN is commit chain; where for each sequential + * commit pair {@code e_i = (C_i, C_i+1) = (C_i+1, C_i)} there are entries in + * this instance; if any entry {@code e_i} has the expected result false (i.e. + * non-similarity), the result computed via transitivity is considered invalid, + * as there is no easy way to determine whether non-similar commits were + * reverted at some point, so that similarity between C1 and CN is re-achieved. + *
    • It is further assumed that if an entry chain between 2 commits + * consists only of entries indicating similarity (i.e. expectedResult = true), + * all such entry chains will. If this is not fulfilled, expected result + * computation via transitivity may produce different results and not work as + * intended. It is the caller's responsibility to ensure this. + *
    + *
+ * + * It is possible to determine the expected similarity result for commits C_X + * and C_Y by using the assumptions above, without explicitly added expected + * similarity results, by utilising transitivity for instance. In such cases, + * there may not be an explicitly added expected similarity result for C_X and + * C_Y in this cache. + * + * @author Alp Torac Genc + */ +public class RepoTestResultCache { + private final Collection similarityResults = new ArrayList(); + + /** + * Constructs an instance with no similarity results. + */ + public RepoTestResultCache() { + } + + /** + * Constructs an instance and copies the contents of the given cache into this + * cache. + */ + public RepoTestResultCache(RepoTestResultCache cache) { + this.copyResultsOf(cache, true); + } + + /** + * Copies all expected similarity results into this cache. + * + * @param overrideResultIfPresent Whether the copied expected similarity results + * should override any potentially existing ones + */ + public void copyResultsOf(RepoTestResultCache cache, boolean overrideResultIfPresent) { + this.similarityResults.addAll(cache.similarityResults); + } + + /** + * Adds the expected similarity result denoted by the parameters: + * {@code isSimilar(commitID1, commitID2) = expectedResult} + * + * @param overrideResultIfPresent Whether the potentially existing result should + * be overridden. Note that the existing result + * could be stored in an entry, where the given + * commit IDs are swapped (due to symmetry + * assumption). + */ + public void addResult(String commitID1, String commitID2, boolean expectedResult, boolean overrideResultIfPresent) { + if (commitID1.equals(commitID2)) + return; + + // Check of there is a duplicated entry, override its content if desired + var duplEntry = this.getEntryFor(commitID1, commitID2); + if (overrideResultIfPresent && duplEntry != null) { + if (duplEntry.expectedResultEquals(expectedResult)) { + return; + } + this.similarityResults.remove(duplEntry); + } + + if (overrideResultIfPresent || duplEntry == null) { + this.similarityResults.add(new SimilarityResultEntry(commitID1, commitID2, expectedResult)); + } + } + + /** + * Adds the expected similarity result denoted by the parameters, overrides any + * potentially existing result. + * + * @see #addResult(String, String, boolean, boolean) + */ + public void addResult(String commitID1, String commitID2, boolean expectedResult) { + this.addResult(commitID1, commitID2, expectedResult, true); + } + + /** + * Uses the reflexivity, symmetry and transitivity assumptions in + * {@link RepoTestResultCache}. Transitivity property will be utilised last, + * i.e. entry chains will only be considered, if there are no direct entries in + * this instance or the given commit IDs are equal.
+ *
+ * This method can also be used to check, whether the results stored in this + * instance can be used to determine the expected similarity of the given + * commits. + * + * @return The expected similarity result of the commits with the given IDs + * (Boolean.TRUE or Boolean.FALSE). Returns null, if neither there is a + * result for the given commit IDs nor is it computable via + * transitivity. + */ + public Boolean getResult(String commitID1, String commitID2) { + // Reflexivity and symmetry + var result = this.getDirectResult(commitID1, commitID2); + if (result != null) { + return result; + } + + // Transitivity + if (this.getTransitiveResult(commitID1, commitID2) == Boolean.TRUE) { + return Boolean.TRUE; + } + + return null; + } + + /** + * Accounts for reflexivity and symmetry properties, does not account for + * transitivity.
+ *
+ * This method can also be used to check, whether the results directly stored in + * this instance can be used to determine the expected similarity of the given + * commits. + * + * @return The expected similarity result of the given commits (Boolean.TRUE or + * Boolean.FALSE), if it is directly present in this instance, i.e. if a + * result for (commitID1, commitID2) or (commitID2, commitID1) has been + * added. Returns null, if there is no added result for the given commit + * IDs. + */ + public Boolean getDirectResult(String commitID1, String commitID2) { + // Reflexivity + if (commitID1.equals(commitID2)) + return true; + + // Symmetry + var entry = this.getEntryFor(commitID1, commitID2); + if (entry != null) { + return entry.getExpectedResult(); + } + + return null; + } + + /** + * Attempts to compute the expected similarity result using the transitivity + * property. Accounts for there being a direct entry between the given commits. + * Account for reflexivity property.
+ *
+ * In particular, looks for an entry chain starting with commitID1 and ending + * with commitID2, such that each entry indicates similarity. Returns true + * upon finding any such entry chain, even if there are further chains, which + * include entries indicating non-similarity.
+ *
+ * Returns Boolean instead of boolean, because it is only possible to determine + * similarity by using transitivity. In case of non-similarity, this method + * returns NULL instead of FALSE, to signal that transitivity yields no accurate + * result. + * + * @return TRUE, if there exists a chain of entries between the given commits, + * such that all entries indicate similarity, or the given commits are + * equal. Said entry chain may also only consist of a single entry for + * the given commits. NULL, if there were no entry chains from commitID1 + * to commitID2, where all entries indicate similarity. + */ + public Boolean getTransitiveResult(String commitID1, String commitID2) { + if (commitID1.equals(commitID2)) { + return Boolean.TRUE; + } + + var entryChain = new Stack(); + var visitedElements = new HashSet(); + this.findTransitiveEntryChain(commitID1, commitID2, entryChain, visitedElements); + + if (entryChain.isEmpty() || !entryChain.peek().hasCommitID(commitID2)) { + // No entry chain found => Result cannot be determined via transitivity + return null; + } else { + return Boolean.TRUE; + } + } + + /** + * Attempts find an entry chain between commitID1 and commitID2, in order to + * make use of the transitivity property. Uses depth-first search starting from + * commitID1 to do so. Only includes entries to the chain, which indicate + * similarity. + * + * @param entryChain The stack, which will contain the entry chain, if + * present. THIS ATTRIBUTE WILL BE MODIFIED + * @param visitedElements The set, which will contain all visited entries, while + * computing entryChain. THIS ATTRIBUTE WILL BE MODIFIED + */ + private void findTransitiveEntryChain(String commitID1, String commitID2, + Stack currentEntryChain, Set visitedElements) { + + // Check if there are any direct entries for (ID1, ID2) or (ID2, ID1) + var entry = this.getEntryFor(commitID1, commitID2); + if (entry != null && !visitedElements.contains(entry)) { + if (entry.getExpectedResult()) { + currentEntryChain.add(entry); + visitedElements.add(entry); + } + // There is one such entry, which indicates non-similarity + // Transitivity cannot be used + return; + } + // There are no direct entries, try to find an entry chain + + for (var e : this.similarityResults) { + + // If e does not indicate similarity, it cannot be on the entry chain + if (!e.getExpectedResult()) { + continue; + } + + /* + * Since this resembles depth-first search, the resulting chain will always be + * cycle-free and lead from commitID1 to commitID2, if there is a transitive + * entry chain between them. Therefore, cycles indicate that e is the wrong + * entry in the chain. + */ + if (visitedElements.contains(e)) { + continue; + } + + // Check whether e and the top-most entry in currentEntryChain can be linked + // in order to continue building the entry chain. If currentEntryChain is empty, + // the entry chain has been reset, check if e contains commitID1 and + // re-try to reach commitID2 by trying to build another entry chain. + + var nextCommitID = !currentEntryChain.isEmpty() ? currentEntryChain.peek().getLinkingCommit(e) : null; + if (nextCommitID == null && e.hasCommitID(commitID1)) { + nextCommitID = commitID1; + } + + if (nextCommitID != null) { + currentEntryChain.add(e); + visitedElements.add(e); + this.findTransitiveEntryChain(e.getOtherCommitID(nextCommitID), commitID2, currentEntryChain, + visitedElements); + } + } + + // The end of the current recursion is reached, check if commitID2 has been + // reached. If not, pop currentEntryChain and look for another path to + // commitID2. + if (!currentEntryChain.isEmpty()) { + if (currentEntryChain.peek().hasCommitID(commitID2)) { + // An entry chain between commitID1 and commitID2 has been found + return; + } else { + /* + * The last entry does not lead to commitID2, so it cannot be a part of the + * transitive entry chain, per the definition of depth-first search. + * + * Remove it the last entry and try anew. + */ + currentEntryChain.pop(); + } + } + } + + /** + * Removes the expected similarity result for the given commit IDs. + */ + public void removeResult(String commitID1, String commitID2) { + var entry = this.getEntryFor(commitID1, commitID2); + if (entry != null) { + this.similarityResults.remove(entry); + } + } + + /** + * Replaces the expected similarity result for the given commit IDs with the + * given expectedResult. + */ + public void replaceResult(String commitID1, String commitID2, boolean expectedResult) { + this.addResult(commitID1, commitID2, expectedResult); + } + + /** + * See {@link RepoTestResultCache} for assumptions on expected similarity + * results. + * + * @return Whether the expected similarity result for the given commits can be + * determined by the direct contents of this cache. Therefore, this + * method will return false, even if the desired result can be computed + * using the transitivity or reflexivity assumptions. + */ + public boolean isInCache(String commitID1, String commitID2) { + return this.getEntryFor(commitID1, commitID2) != null; + } + + /** + * Removes all expected similarity results saved in this instance. + */ + public void clear() { + this.similarityResults.clear(); + } + + /** + * @return The entry for the commits with the given commit IDs. Accounts for + * symmetry property. + */ + protected SimilarityResultEntry getEntryFor(String commitID1, String commitID2) { + var entryOpt = this.similarityResults.stream().filter((e) -> e.isEntryFor(commitID1, commitID2)).findFirst(); + if (entryOpt.isPresent()) { + return entryOpt.get(); + } + entryOpt = this.similarityResults.stream().filter((e) -> e.isEntryFor(commitID2, commitID1)).findFirst(); + if (entryOpt.isPresent()) { + return entryOpt.get(); + } + return null; + } + + /** + * A class that encapsulates an expected similarity result added to the cache. + * Commits are not distinguished based on which side they are + * {@code isSimilar(commit1, commit2) = isSimilar(commit2, commit1)}. + * + * @author Alp Torac Genc + */ + private class SimilarityResultEntry { + private final String commitID1; + private final String commitID2; + private final boolean expectedResult; + + private SimilarityResultEntry(String commitID1, String commitID2, boolean expectedResult) { + this.commitID1 = commitID1; + this.commitID2 = commitID2; + this.expectedResult = expectedResult; + } + + public String getCommitID1() { + return commitID1; + } + + public String getCommitID2() { + return commitID2; + } + + public boolean getExpectedResult() { + return expectedResult; + } + + /** + * @return Whether this instance has the given commit + */ + public boolean hasCommitID(String commitID) { + return this.getCommitID1().equals(commitID) || this.getCommitID2().equals(commitID); + } + + /** + * @return The other commit ID inside this entry, i.e. the commit ID that is not + * equal to {@code commitID}. Returns null, if {@code commitID} is not + * in this entry. + */ + public String getOtherCommitID(String commitID) { + if (!this.hasCommitID(commitID)) + return null; + + return this.getCommitID1().equals(commitID) ? this.getCommitID2() : this.getCommitID1(); + } + + /** + * @return The commit, which potentially links this entry with the given one. + * One such commit is mutual in both entries. If there is no such + * commit, returns null. + */ + public String getLinkingCommit(SimilarityResultEntry entry) { + if (this.hasCommitID(entry.getCommitID1())) { + return entry.getCommitID1(); + } else if (this.hasCommitID(entry.getCommitID2())) { + return entry.getCommitID2(); + } else { + return null; + } + } + + /** + * @return Whether this entry contains both given commits, and therefore + * encapsulates an expected similarity result for them. + */ + public boolean isEntryFor(String commitID1, String commitID2) { + return this.getCommitID1().equals(commitID1) && this.getCommitID2().equals(commitID2); + } + + /** + * @return Whether the expected similarity result stored in this entry is the + * same as the given one. + */ + public boolean expectedResultEquals(boolean expectedResult) { + return expectedResult == this.expectedResult; + } + } +} diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/RepoTestResultCacheTest.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/RepoTestResultCacheTest.java new file mode 100644 index 0000000000..a2c19e5e7f --- /dev/null +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/RepoTestResultCacheTest.java @@ -0,0 +1,404 @@ +package cipm.consistency.fitests.repositorytests.util; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +/** + * A test class for {@link RepoTestResultCache}, which ensures that it works as + * expected and that its properties hold. + * + * @author Alp Torac Genc + */ +public class RepoTestResultCacheTest { + private static final String cID1 = "cID1"; + private static final String cID2 = "cID2"; + private static final String cID3 = "cID3"; + private static final String cID4 = "cID4"; + private static final String cID5 = "cID5"; + private static final String cID6 = "cID6"; + + private RepoTestResultCache cache; + + @BeforeEach + public void setUp() { + cache = new RepoTestResultCache(); + } + + /** + * Makes the necessary assertions for + * {@link RepoTestResultCache#getDirectResult(String, String)}. + */ + private void testDirectCacheResult(String commitID1, String commitID2, Boolean expectedSimilarityResult) { + Assertions.assertEquals(Boolean.TRUE, cache.getDirectResult(commitID1, commitID1)); + Assertions.assertEquals(Boolean.TRUE, cache.getDirectResult(commitID2, commitID2)); + + Assertions.assertEquals(expectedSimilarityResult, cache.getDirectResult(commitID1, commitID2)); + Assertions.assertEquals(expectedSimilarityResult, cache.getDirectResult(commitID2, commitID1)); + } + + /** + * Makes the necessary assertions for + * {@link RepoTestResultCache#isInCache(String, String)}. + */ + private void testIsInCache(String commitID1, String commitID2, boolean shouldBeInCache) { + Assertions.assertEquals(false, cache.isInCache(commitID1, commitID1)); + Assertions.assertEquals(false, cache.isInCache(commitID2, commitID2)); + + Assertions.assertEquals(shouldBeInCache, cache.isInCache(commitID1, commitID2)); + Assertions.assertEquals(shouldBeInCache, cache.isInCache(commitID2, commitID1)); + } + + /** + * Makes the necessary assertions for + * {@link RepoTestResultCache#getTransitiveResult(String, String)}. + */ + private void testTransitiveCacheResult(String commitID1, String commitID2, Boolean expectedTransitiveResult) { + Assertions.assertEquals(expectedTransitiveResult, cache.getTransitiveResult(commitID1, commitID2)); + Assertions.assertEquals(expectedTransitiveResult, cache.getTransitiveResult(commitID2, commitID1)); + } + + /** + * Makes the necessary assertions for + * {@link RepoTestResultCache#getDirectResult(String, String)}, + * {@link RepoTestResultCache#getTransitiveResult(String, String)} and + * {@link RepoTestResultCache#getResult(String, String)}. + */ + private void testCacheResult(String commitID1, String commitID2, Boolean expectedDirectSimilarityResult, + Boolean expectedTransitiveResult) { + this.testDirectCacheResult(commitID1, commitID2, expectedDirectSimilarityResult); + this.testTransitiveCacheResult(commitID1, commitID2, expectedTransitiveResult); + + var expectedResult = expectedDirectSimilarityResult; + if (expectedResult == null) + expectedResult = expectedTransitiveResult; + + Assertions.assertEquals(expectedResult, cache.getResult(commitID1, commitID2)); + } + + /** + * Ensures that entries indicating similarity are added as expected. + */ + @Test + public void addResultTest_True() { + cache.addResult(cID1, cID2, true); + this.testIsInCache(cID1, cID2, true); + this.testDirectCacheResult(cID1, cID2, true); + } + + /** + * Ensures that entries indicating non-similarity are added as expected. + */ + @Test + public void addResultTest_False() { + cache.addResult(cID1, cID2, false); + this.testIsInCache(cID1, cID2, true); + this.testDirectCacheResult(cID1, cID2, false); + } + + /** + * Ensures that existing entries are not overridden, if they are not supposed to + * be overridden. + */ + @Test + public void addResultTest_NoOverride() { + cache.addResult(cID1, cID2, true); + cache.addResult(cID1, cID2, false, false); + this.testIsInCache(cID1, cID2, true); + this.testDirectCacheResult(cID1, cID2, true); + } + + /** + * Ensures that existing symmetric entries are not overridden, if they are not + * supposed to be overridden. + */ + @Test + public void addResultTest_NoOverrideSymmetry() { + cache.addResult(cID1, cID2, true); + cache.addResult(cID2, cID1, false, false); + this.testIsInCache(cID1, cID2, true); + this.testDirectCacheResult(cID1, cID2, true); + } + + /** + * Ensures that existing entries are overridden, if they are supposed to be + * overridden. + */ + @Test + public void addResultTest_Override() { + cache.addResult(cID1, cID2, true); + cache.addResult(cID1, cID2, false); + this.testIsInCache(cID1, cID2, true); + this.testDirectCacheResult(cID1, cID2, false); + } + + /** + * Ensures that existing symmetric entries are overridden, if they are supposed + * to be overridden. + */ + @Test + public void addResultTest_OverrideSymmetry() { + cache.addResult(cID1, cID2, true); + cache.addResult(cID2, cID1, false); + this.testIsInCache(cID1, cID2, true); + this.testDirectCacheResult(cID1, cID2, false); + } + + /** + * Ensures that entries are removed as expected. + */ + @Test + public void removeResultTest() { + cache.addResult(cID1, cID2, true); + cache.removeResult(cID1, cID2); + this.testIsInCache(cID1, cID2, false); + this.testDirectCacheResult(cID1, cID2, null); + } + + /** + * Ensures that symmetric entries are removed as expected. + */ + @Test + public void removeResultTest_Symmetry() { + cache.addResult(cID1, cID2, true); + cache.removeResult(cID2, cID1); + this.testIsInCache(cID1, cID2, false); + this.testDirectCacheResult(cID1, cID2, null); + } + + /** + * Ensures that the reflexivity property is used, even if the desired entry is + * not present. + */ + @Test + public void reflexivityTest_NoEntries() { + this.testIsInCache(cID1, cID1, false); + this.testDirectCacheResult(cID1, cID1, true); + } + + /** + * Ensures that reflexive similarity results are not added, yet are handled + * according to reflexivity property. + */ + @Test + public void reflexivityTest_WithEntryAddAttempt() { + cache.addResult(cID1, cID1, true); + this.testIsInCache(cID1, cID1, false); + this.testDirectCacheResult(cID1, cID1, true); + } + + /** + * Ensures that faulty reflexive similarity results are neither added nor break + * the reflexivity property. + */ + @Test + public void reflexivityTest_WithWrongEntryAddAttempt() { + cache.addResult(cID1, cID1, false); + this.testIsInCache(cID1, cID1, false); + this.testDirectCacheResult(cID1, cID1, true); + } + + /** + * Ensures that removing (non-existent) reflexive similarity results does not + * break the reflexivity property. + */ + @Test + public void reflexivityTest_WithRemoveAttempt() { + cache.removeResult(cID1, cID1); + this.testIsInCache(cID1, cID1, false); + this.testDirectCacheResult(cID1, cID1, true); + } + + /** + * Ensures that transitive similarity results account for reflexivity property. + */ + @Test + public void transitivityTest_Reflexivity() { + this.testIsInCache(cID1, cID1, false); + Assertions.assertTrue(cache.getTransitiveResult(cID1, cID1)); + } + + /** + * Ensures that transitive similarity results for directly present entries are + * computed as expected, if the corresponding entry indicates similarity. + */ + @Test + public void transitivityTest_TwoCommits_Similar() { + cache.addResult(cID1, cID2, true); + this.testIsInCache(cID1, cID2, true); + this.testTransitiveCacheResult(cID1, cID2, Boolean.TRUE); + } + + /** + * Ensures that transitive similarity results for directly present entries are + * computed as expected, if the corresponding entry indicates non-similarity. + */ + @Test + public void transitivityTest_TwoCommits_NonSimilar() { + cache.addResult(cID1, cID2, false); + this.testIsInCache(cID1, cID2, true); + this.testTransitiveCacheResult(cID1, cID2, null); + } + + /** + * Ensures that direct and transitive similarity results for a chain of entries + * indicating similarity are computed as expected:
+ *
+ * cID1 -similar> cID2 -similar> cID3 -similar> cID4 -similar> cID5 + */ + @Test + public void transitivityTest_CommitChain_AllCommitsSimilar() { + var commitIDs = new String[] { cID1, cID2, cID3, cID4, cID5 }; + for (int i = 0; i < commitIDs.length - 1; i++) { + cache.addResult(commitIDs[i], commitIDs[i + 1], true); + } + + for (int i = 0; i < commitIDs.length; i++) { + for (int j = 0; j < commitIDs.length; j++) { + var areCommitIDsAdjadent = i == j + 1 || j == i + 1; + + this.testIsInCache(commitIDs[i], commitIDs[j], i == j + 1 || j == i + 1); + this.testCacheResult(commitIDs[i], commitIDs[j], (areCommitIDsAdjadent || i == j) ? Boolean.TRUE : null, + Boolean.TRUE); + } + } + } + + /** + * Ensures that direct and transitive similarity results for a broken chain of + * entries indicating similarity are computed as expected (i.e. one of the + * entries in the chain indicate non-similarity):
+ *
+ * cID1 -S_1> cID2 -S_2> cID3 -S_3> cID4 -S_4> cID5
+ *
+ * where S_x = non-similar for one index (1,2,3,4) and S_x = similar for the + * rest. + */ + @Test + public void transitivityTest_CommitChain_SimilarityBroken() { + var commitIDs = new String[] { cID1, cID2, cID3, cID4, cID5 }; + for (int brokenEntryIdx = 0; brokenEntryIdx < commitIDs.length - 1; brokenEntryIdx++) { + for (int i = 0; i < commitIDs.length - 1; i++) { + cache.addResult(commitIDs[i], commitIDs[i + 1], true); + } + + cache.addResult(commitIDs[brokenEntryIdx], commitIDs[brokenEntryIdx + 1], false); + + for (int i = 0; i < commitIDs.length; i++) { + for (int j = 0; j < commitIDs.length; j++) { + var brokenEntryReached = (i == brokenEntryIdx && j == brokenEntryIdx + 1) + || (i == brokenEntryIdx + 1 && j == brokenEntryIdx); + + var brokenEntryOutsideSubChain = (i < brokenEntryIdx + 1 && j < brokenEntryIdx + 1) + || (i > brokenEntryIdx && j > brokenEntryIdx); + + var areCommitIDsAdjadent = i == j + 1 || j == i + 1; + + this.testIsInCache(commitIDs[i], commitIDs[j], areCommitIDsAdjadent); + this.testCacheResult(commitIDs[i], commitIDs[j], + (areCommitIDsAdjadent || i == j) ? !brokenEntryReached : null, + (brokenEntryOutsideSubChain || i == j) ? Boolean.TRUE : null); + } + } + + cache.clear(); + } + } + + /** + * Ensures that transitive similarity result computing works as expected for + * forking and joining entry chains indicating similarity:
+ *
+ * + * cID1 -similar> cID2 -similar> cID3 -similar> cID6
+ * |
+ * ------similar> cID4 -similar> cID5 -similar> + */ + @Test + public void transitivityTest_Hexagon_AllSimilar() { + cache.addResult(cID1, cID2, true); + cache.addResult(cID2, cID3, true); + cache.addResult(cID3, cID6, true); + + cache.addResult(cID1, cID4, true); + cache.addResult(cID4, cID5, true); + cache.addResult(cID5, cID6, true); + + for (var id : new String[] { cID1, cID2, cID3, cID4, cID5, cID6 }) { + this.testTransitiveCacheResult(id, cID6, Boolean.TRUE); + } + } + + /** + * Ensures that transitive similarity result computing works as expected for + * forking and joining broken entry chains (i.e. all chains contain one entry + * indicating non-similarity).
+ *
+ * It is important to note that all chains have to contain at least one broken + * entry for the transitive similarity result to be null (i.e. unable to + * determine similarity via transitivity property). This is because of the + * symmetry property.
+ *
+ * + * cID1 -non-similar> cID2 -similar> cID3 -similar> cID6
+ * |
+ * ------similar> cID4 -non-similar> cID5 -similar> + */ + @Test + public void transitivityTest_Hexagon_SimilarityBroken() { + cache.addResult(cID1, cID2, false); + cache.addResult(cID2, cID3, true); + cache.addResult(cID3, cID6, true); + + cache.addResult(cID1, cID4, true); + cache.addResult(cID4, cID5, false); + cache.addResult(cID5, cID6, true); + + for (var id : new String[] { cID1, cID4 }) { + this.testTransitiveCacheResult(id, cID6, null); + } + } + + /** + * Ensures that transitive similarity result computing works as expected for + * forking and joining entry chains, where one of the chains is broken (i.e. it + * contains one entry indicating non-similarity).
+ *
+ * Note: This case should never appear in reality; because the similarity + * relation should be reflexive, symmetric and transitive.
+ *
+ * cID1 -non-similar> cID2 -similar> cID3 -similar> cID6
+ * |
+ * ------similar> cID4 -similar> cID5 -similar> + */ + @Test + public void transitivityTest_Hexagon_SimilarityBrokenOnOneSide() { + cache.addResult(cID1, cID2, false); + cache.addResult(cID2, cID3, true); + cache.addResult(cID3, cID6, true); + + cache.addResult(cID1, cID4, true); + cache.addResult(cID4, cID5, true); + cache.addResult(cID5, cID6, true); + + for (var id : new String[] { cID1, cID2, cID3, cID4, cID5, cID6 }) { + this.testTransitiveCacheResult(id, cID6, Boolean.TRUE); + } + } + + /** + * Ensures that cleaning all entries works as expected. + */ + @Test + public void cleanCacheTest() { + cache.addResult(cID1, cID2, true); + cache.addResult(cID2, cID3, false); + cache.clear(); + this.testIsInCache(cID1, cID2, false); + this.testIsInCache(cID2, cID3, false); + this.testIsInCache(cID3, cID4, false); + this.testDirectCacheResult(cID1, cID2, null); + this.testDirectCacheResult(cID2, cID3, null); + this.testDirectCacheResult(cID3, cID4, null); + } +} From 6c7694920f4ba8510527cfd966908d86e25a06f7 Mon Sep 17 00:00:00 2001 From: AlpTorac Date: Sun, 27 Jul 2025 17:38:41 +0200 Subject: [PATCH 28/72] Implement expected similarity result provider that provides cached expected similarity results --- .../RepoCacheSimilarityResultProvider.java | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/RepoCacheSimilarityResultProvider.java diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/RepoCacheSimilarityResultProvider.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/RepoCacheSimilarityResultProvider.java new file mode 100644 index 0000000000..ad2609f503 --- /dev/null +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/RepoCacheSimilarityResultProvider.java @@ -0,0 +1,40 @@ +package cipm.consistency.fitests.repositorytests.util; + +import java.nio.file.Path; + +import org.eclipse.emf.ecore.resource.Resource; + +import cipm.consistency.fitests.similarity.jamopp.parser.IExpectedSimilarityResultProvider; + +/** + * Provides expected similarity results based on a result cache. + * + * @author Alp Torac Genc + */ +public class RepoCacheSimilarityResultProvider implements IExpectedSimilarityResultProvider { + private final RepoTestResultCache cache; + + public RepoCacheSimilarityResultProvider(RepoTestResultCache cache) { + this.cache = cache; + } + + /** + * @return The (expected) key of the given resource in the cache, i.e. the + * commit ID. + */ + private String getCacheKeyForResource(Resource res) { + // The last segment of the resource URI is: commitID.ext + // Remove the extension to get the commitID + return res.getURI().trimFileExtension().lastSegment(); + } + + /** + * @implSpec Determines the expected similarity result based on the given result + * cache. + */ + @Override + public boolean getExpectedSimilarityResultFor(Resource lhsRes, Path lhsResPath, Resource rhsRes, Path rhsResPath) { + var result = cache.getResult(this.getCacheKeyForResource(lhsRes), this.getCacheKeyForResource(rhsRes)); + return result != null ? result : false; + } +} From cc4bce339cc80321d2a4d6e86478ce0efb25def0 Mon Sep 17 00:00:00 2001 From: AlpTorac Date: Sun, 27 Jul 2025 17:39:25 +0200 Subject: [PATCH 29/72] Implement class for computing expected similarity results --- .../RepoTestSimilarityValueEstimator.java | 190 ++++++++++++++++++ 1 file changed, 190 insertions(+) create mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/RepoTestSimilarityValueEstimator.java diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/RepoTestSimilarityValueEstimator.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/RepoTestSimilarityValueEstimator.java new file mode 100644 index 0000000000..f5153bcf1d --- /dev/null +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/RepoTestSimilarityValueEstimator.java @@ -0,0 +1,190 @@ +package cipm.consistency.fitests.repositorytests.util; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.jgit.api.Git; +import org.eclipse.jgit.diff.DiffEntry; +import org.eclipse.jgit.diff.DiffFormatter; +import org.eclipse.jgit.treewalk.AbstractTreeIterator; +import org.eclipse.jgit.treewalk.CanonicalTreeParser; +import org.eclipse.jgit.treewalk.filter.PathSuffixFilter; + +import cipm.consistency.fitests.repositorytests.util.commentremoval.QuickCommentRemover; +import cipm.consistency.fitests.repositorytests.util.difffilter.DiffFilter; + +/** + * A class that computes expected similarity checking results (or expected + * similarity values) based on the given GIT-Diffs. Provides numerous variants + * of its computation method to allow re-using various GIT elements.
+ *
+ * Uses {@link QuickCommentRemover}, which removes commentaries in an + * approximative fashion. Therefore, the computed results may be + * misleading. + * + * @author Alp Torac Genc + */ +public class RepoTestSimilarityValueEstimator { + private static final int defaultContextLineCount = 3; + private int contextLineCount = defaultContextLineCount; + + /** + * @param os The {@link OutputStream} used by df + * @param df The {@link DiffFormatter} that created diffEntries + * @param diffEntries A list of {@link DiffEntry} instances from diffing 2 + * commits C1 and C2 + * @return Whether model resources parsed from C1 and C2 are similar + */ + public boolean getExpectedSimilarityValueFor(OutputStream os, DiffFormatter df, List diffEntries) { + try (var outputStream = os; var diffFormatter = df) { + for (var e : diffEntries) { + diffFormatter.format(e); + // Adapt all UNIX new lines to the current system + var code = this.getEffectiveLines(outputStream.toString().replaceAll("\\n", System.lineSeparator())); + var expectedSimVal = this.computeExpectedSimilarityValue(code); + if (!expectedSimVal) + return false; + } + } catch (IOException e) { + e.printStackTrace(); + throw new IllegalStateException("IOException occured while computing expected similarity value", e); + } + + return true; + } + + /** + * @param diffEntries A list of {@link DiffEntry} instances from diffing 2 + * commits C1 and C2 + * @return Whether model resources parsed from C1 and C2 are similar + */ + public boolean getExpectedSimilarityValueFor(List diffEntries) { + try (var os = new ByteArrayOutputStream()) { + return this.getExpectedSimilarityValueFor(os, new DiffFormatter(os), diffEntries); + } catch (IOException e) { + e.printStackTrace(); + throw new IllegalStateException("IOException occured while computing expected similarity value", e); + } + } + + /** + * A variant of {@link #getExpectedSimilarityValueFor(Git, String, String)}, + * where the commit parameters are replaced with their corresponding + * {@link AbstractTreeIterator}. + * + * @param git The object enclosing the GIT-repository that contains the + * given commits + * @param oldTreeIter A tree iterator from a commit from git + * @param newTreeIter A tree iterator from another commit from git + */ + public boolean getExpectedSimilarityValueFor(Git git, AbstractTreeIterator oldTreeIter, + AbstractTreeIterator newTreeIter) { + try (var os = new ByteArrayOutputStream(); var df = new DiffFormatter(os)) { + df.setRepository(git.getRepository()); + df.setContext(this.getContextLineCount()); + df.setPathFilter(PathSuffixFilter.create(".java")); + + var entries = df.scan(oldTreeIter, newTreeIter); + + return this.getExpectedSimilarityValueFor(os, df, entries); + } catch (IOException e) { + e.printStackTrace(); + throw new IllegalStateException("IOException occured while computing expected similarity value", e); + } + } + + /** + * @param git The object enclosing the GIT-repository that contains the + * given commits + * @param commitID1 A commit from git + * @param commitID2 Another commit from git + * @return Whether model resources parsed from the given commits are similar. + */ + public boolean getExpectedSimilarityValueFor(Git git, String commitID1, String commitID2) { + try (var reader = git.getRepository().newObjectReader()) { + var oldTreeIter = new CanonicalTreeParser(); + var oldTree = git.getRepository().resolve(commitID1 + "^{tree}"); + oldTreeIter.reset(reader, oldTree); + + var newTreeIter = new CanonicalTreeParser(); + var newTree = git.getRepository().resolve(commitID2 + "^{tree}"); + newTreeIter.reset(reader, newTree); + + return this.getExpectedSimilarityValueFor(git, oldTreeIter, newTreeIter); + } catch (IOException e) { + e.printStackTrace(); + throw new IllegalStateException("IOException occured while computing expected similarity value", e); + } + } + + /** + * @param text A diff patch (or a snippet thereof) as string + * @return All non-blank lines from the given diff patch, which contain actual + * changes to the text. + */ + public List getEffectiveLines(String text) { + var filter = new DiffFilter(); + var cr = new QuickCommentRemover(); + + var result = cr.removeComments(text); + var lines = filter.splitLines(result); + lines = filter.removeContextLines(lines); + lines = filter.removeNonPatchScript(lines); + lines = filter.removeBlankLines(lines); + + return lines; + } + + /** + * Computes whether applying the changes in the given diff DOES NOT introduce + * any changes to the effective code. Assuming the given diff is computed by + * comparing the commits oldCommit and newCommit: + *
    + *
  • true: oldCommit is still similar to newCommit, without applying the diff + * patch script on oldCommit + *
  • false: The diff patch introduces changes to the effective code, meaning + * that oldCommit and newCommit are not similar + *
+ * + * @param lines The lines from a given diff patch script, without any metadata + */ + public boolean computeExpectedSimilarityValue(List lines) { + var added = new ArrayList(); + var removed = new ArrayList(); + + lines.stream().forEach((l) -> { + if (l.startsWith("+")) + added.add(l.substring(1).replaceAll("\\s", "")); + if (l.startsWith("-")) + removed.add(l.substring(1).replaceAll("\\s", "")); + }); + + var allAdded = added.stream().reduce("", (t1, t2) -> t1 + t2); + var allRemoved = removed.stream().reduce("", (t1, t2) -> t1 + t2); + + return allAdded.equals(allRemoved); + } + + /** + * @return The number of context lines that will be considered while diffing, if + * no {@link DiffFormatter} is explicitly provided. Defaults to + * {@value #defaultContextLineCount}, unless re-set via + * {@link #setContextLineCount(int)}. + */ + public int getContextLineCount() { + return this.contextLineCount; + } + + /** + * Sets the number of context lines that will be considered while diffing, if no + * {@link DiffFormatter} is explicitly provided. Defaults to + * {@value #defaultContextLineCount}, unless re-set via + * {@link #setContextLineCount(int)}. + */ + public void setContextLineCount(int contextLineCount) { + this.contextLineCount = contextLineCount; + } +} From e39e4880180fa60b2bec0e1339c314433f502673 Mon Sep 17 00:00:00 2001 From: AlpTorac Date: Sun, 27 Jul 2025 17:39:53 +0200 Subject: [PATCH 30/72] Add time measurement tags for repository parser tests --- .../RepoTimeMeasurementTag.java | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/RepoTimeMeasurementTag.java diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/RepoTimeMeasurementTag.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/RepoTimeMeasurementTag.java new file mode 100644 index 0000000000..5f42a7d38b --- /dev/null +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/RepoTimeMeasurementTag.java @@ -0,0 +1,43 @@ +package cipm.consistency.fitests.repositorytests; + +import cipm.consistency.fitests.similarity.jamopp.parser.ITimeMeasurementTag; + +/** + * An enum containing various GIT-Repository-related tags that can be used while + * taking time measurements. + * + * @author Alp Torac Genc + */ +public enum RepoTimeMeasurementTag implements ITimeMeasurementTag { + /** + * A tag meant for time measurements from cloning repositories + */ + CLONE_REPOSITORY, + /** + * A tag meant for time measurements from performing checkout operations on + * commits + */ + CHECKOUT_TO_COMMIT, + /** + * A tag meant for time measurements from releasing (ex: via close() and similar + * methods) resources associated with in-memory representation of repositories + */ + CLOSE_REPOSITORY, + /** + * A tag meant for time measurements from deleting local repository clones + */ + DELETE_LOCAL_REPO_CLONE, + + /** + * A tag meant for time measurements from loading expected similarity results + * for similarity checking commits + */ + LOAD_EXPECTED_SIMILARITY_RESULTS, + /** + * A tag meant for time measurements from saving expected similarity results for + * similarity checking commits + */ + SAVE_EXPECTED_SIMILARITY_RESULTS, + + ; +} From e597ab5a335b91032747d910edf8b2b4341f1e17 Mon Sep 17 00:00:00 2001 From: AlpTorac Date: Sun, 27 Jul 2025 17:40:16 +0200 Subject: [PATCH 31/72] Add options for repository parser tests --- .../RepoParserTestOptions.java | 78 +++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/RepoParserTestOptions.java diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/RepoParserTestOptions.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/RepoParserTestOptions.java new file mode 100644 index 0000000000..d16e49fa54 --- /dev/null +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/RepoParserTestOptions.java @@ -0,0 +1,78 @@ +package cipm.consistency.fitests.repositorytests; + +import cipm.consistency.fitests.similarity.jamopp.parser.ParserTestOptions; + +/** + * A class that contains various options for test classes that parse + * {@link Resource} instances from GIT repositories, cache those resource + * instances, as well as compute and cache expected similarity results: + *
    + *
  • shouldDeleteRepositoryClones: Whether all cloned repositories should be + * removed after tests + *
  • shouldSaveCachedExpectedSimilarityResults: Whether the cached expected + * similarity results should be saved after tests + *
  • shouldUseCachedExpectedSimilarityResults: Whether the cached expected + * similarity results should actually be used in tests + *
+ * + * @author Alp Torac Genc + */ +public class RepoParserTestOptions extends ParserTestOptions { + private boolean shouldDeleteRepositoryClones; + private boolean shouldSaveCachedExpectedSimilarityResults; + private boolean shouldUseCachedExpectedSimilarityResults; + + /** + * @see {@link RepoParserTestOptions} + */ + public void setShouldDeleteRepositoryClones(boolean shouldDeleteRepositoryClones) { + this.shouldDeleteRepositoryClones = shouldDeleteRepositoryClones; + } + + /** + * @see {@link RepoParserTestOptions} + */ + public void setShouldSaveCachedExpectedSimilarityResults(boolean shouldSaveCachedExpectedSimilarityResults) { + this.shouldSaveCachedExpectedSimilarityResults = shouldSaveCachedExpectedSimilarityResults; + } + + /** + * @see {@link RepoParserTestOptions} + */ + public void setShouldUseCachedExpectedSimilarityResults(boolean shouldUseCachedExpectedSimilarityResults) { + this.shouldUseCachedExpectedSimilarityResults = shouldUseCachedExpectedSimilarityResults; + } + + /** + * @see {@link RepoParserTestOptions} + */ + public boolean shouldDeleteRepositoryClones() { + return shouldDeleteRepositoryClones; + } + + /** + * @see {@link RepoParserTestOptions} + */ + public boolean shouldSaveCachedExpectedSimilarityResults() { + return shouldSaveCachedExpectedSimilarityResults; + } + + /** + * @see {@link RepoParserTestOptions} + */ + public boolean shouldUseCachedExpectedSimilarityResults() { + return shouldUseCachedExpectedSimilarityResults; + } + + /** + * Copies all options from the given instance; i.e. after calling this method, + * all options inside the given instance will override the corresponding options + * in this. + */ + public void copyOptionsFrom(RepoParserTestOptions opts) { + super.copyOptionsFrom(opts); + this.shouldDeleteRepositoryClones = opts.shouldDeleteRepositoryClones; + this.shouldSaveCachedExpectedSimilarityResults = opts.shouldSaveCachedExpectedSimilarityResults; + this.shouldUseCachedExpectedSimilarityResults = opts.shouldUseCachedExpectedSimilarityResults; + } +} From a188c6f18a1b43c5c0713ed02450ebcfd8fbab73 Mon Sep 17 00:00:00 2001 From: AlpTorac Date: Sun, 27 Jul 2025 17:40:53 +0200 Subject: [PATCH 32/72] Add layout class for repository parser tests --- .../RepoParserTestFileLayout.java | 125 ++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/RepoParserTestFileLayout.java diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/RepoParserTestFileLayout.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/RepoParserTestFileLayout.java new file mode 100644 index 0000000000..592d07d50e --- /dev/null +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/RepoParserTestFileLayout.java @@ -0,0 +1,125 @@ +package cipm.consistency.fitests.repositorytests; + +import java.nio.file.Path; + +import org.eclipse.emf.common.util.URI; + +import cipm.consistency.fitests.similarity.jamopp.parser.ParserTestFileLayout; + +/** + * Extension of {@link ParserTestFileLayout} with GIT-Repository-related + * options. + * + * @author Alp Torac Genc + */ +public class RepoParserTestFileLayout extends ParserTestFileLayout { + /** + * @see {@link #setRepoModelImplDirName(String)} + */ + private String repoModelImplDirName; + + /** + * @see {@link #setExpectedSimilarityResultCacheDirName(String)} + */ + private String expectedSimilarityResultCacheDirName; + + /** + * @see {@link #setExpectedSimilarityResultCacheFileName(String)} + */ + private String expectedSimilarityResultCacheFileName; + + /** + * @see {@link #setRepoName(String)} + */ + private String repoName; + + public RepoParserTestFileLayout() { + super(); + } + + public RepoParserTestFileLayout(ParserTestFileLayout layout) { + super(layout); + } + + /** + * Sets the name of the repository + */ + public void setRepoName(String repoName) { + this.repoName = repoName; + } + + /** + * Sets the name of the root directory of the models + */ + public void setRepoModelImplDirName(String repoModelImplDirName) { + this.repoModelImplDirName = repoModelImplDirName; + } + + /** + * Sets the name of the folder, where contents of {@link #resultCache} should be + * saved. Note: This folder does not have to directly contain the contents of + * {@link RepoTestResultCache}. They may be saved in sub-directories as well. + */ + public void setExpectedSimilarityResultCacheDirName(String expectedSimilarityResultCacheDirName) { + this.expectedSimilarityResultCacheDirName = expectedSimilarityResultCacheDirName; + } + + /** + * Sets the name of the file (with extension), where contents of + * {@link RepoTestResultCache} should be saved. + */ + public void setExpectedSimilarityResultCacheFileName(String expectedSimilarityResultCacheFileName) { + this.expectedSimilarityResultCacheFileName = expectedSimilarityResultCacheFileName; + } + + /** + * @return The path to the saved contents of {@link RepoTestResultCache} + */ + public Path getExpectedSimilarityResultCachePath() { + return this.getTestFilesSavePath().resolve(expectedSimilarityResultCacheDirName).resolve(this.repoName) + .resolve(expectedSimilarityResultCacheFileName); + } + + /** + * @return The URI, at which the parsed commit's resource will point at. + */ + public URI getModelResourceSaveURIForCommit(String commitID) { + return URI.createFileURI(this.getModelResourceSaveRootDirectory().toString()).appendSegment(this.repoName) + .appendSegment(commitID).appendFileExtension(this.getModelResourceFileExtension()); + } + + /** + * @return The path, where the given commit should be cloned + */ + public Path getRepoClonePathForCommit(String commitID) { + return this.getModelSourceFileRootDirPath().resolve(commitID); + } + + /** + * @return The URI to the folder, where the given commit should be cloned + */ + public URI getRepoCloneURIForCommit(String commitID) { + return URI.createFileURI(this.getRepoClonePathForCommit(commitID).toString()); + } + + /** + * Use this method for root directory, so that the top-most folder of the + * repository is not duplicated. + * + * @return The top-most directory, where the repositories will be cloned to + */ + public Path getRepoClonesDirPath() { + return this.getTestFilesSavePath().resolve(repoModelImplDirName); + } + + /** + * @implSpec Returns The path, at which the repository clone resides. Meant to + * be used for accessing the local repository clone. Use + * {@link #getRepoClonesDirPath()} while cloning instead, so that the + * top-most folder of the repository is not duplicated. + */ + @Override + public Path getModelSourceFileRootDirPath() { + return this.getRepoClonesDirPath().resolve(this.repoName); + } +} From 34c3c6e7cee7ff64cd81b92f2fd6542750d2ea1f Mon Sep 17 00:00:00 2001 From: AlpTorac Date: Sun, 27 Jul 2025 17:41:17 +0200 Subject: [PATCH 33/72] Add abstract test class for repository parser tests --- .../AbstractJaMoPPParserRepoTest.java | 550 ++++++++++++++++++ 1 file changed, 550 insertions(+) create mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/AbstractJaMoPPParserRepoTest.java diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/AbstractJaMoPPParserRepoTest.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/AbstractJaMoPPParserRepoTest.java new file mode 100644 index 0000000000..3055c0986a --- /dev/null +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/AbstractJaMoPPParserRepoTest.java @@ -0,0 +1,550 @@ +package cipm.consistency.fitests.repositorytests; + +import cipm.consistency.fitests.repositorytests.util.RepoCacheSimilarityResultProvider; +import cipm.consistency.fitests.repositorytests.util.RepoTestResultCache; +import cipm.consistency.fitests.repositorytests.util.RepoTestSimilarityValueEstimator; +import cipm.consistency.fitests.similarity.jamopp.JaMoPPResourceParsingStrategy; +import cipm.consistency.fitests.similarity.jamopp.parser.AbstractJaMoPPParserSimilarityTest; +import cipm.consistency.fitests.similarity.jamopp.parser.GeneralTimeMeasurementTag; +import cipm.consistency.fitests.similarity.jamopp.parser.IExpectedSimilarityResultProvider; +import cipm.consistency.fitests.similarity.jamopp.parser.IJaMoPPParserTestGenerationStrategy; +import cipm.consistency.fitests.similarity.jamopp.parser.IModelResourceWrapper; +import cipm.consistency.fitests.similarity.jamopp.parser.ReflexiveSymmetricIterationTestGenerationStrategy; +import cipm.consistency.fitests.similarity.jamopp.parser.JaMoPPModelResourceWrapper; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.eclipse.emf.common.util.URI; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.jgit.api.Git; +import org.eclipse.jgit.api.errors.GitAPIException; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DynamicNode; +import org.junit.jupiter.api.TestFactory; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; + +/** + * An abstract test class, which can be used for implementing tests that involve + * parsing models from GIT repositories and checking their similarity. + * + * @author Alp Torac Genc + * + * @see {@link AbstractJaMoPPParserSimilarityTest#createTests()} + */ +public abstract class AbstractJaMoPPParserRepoTest extends AbstractJaMoPPParserSimilarityTest { + + /** + * Contains expected results of comparing model resources + */ + private static RepoTestResultCache resultCache = new RepoTestResultCache(); + + /** + * The pattern of "gradle-wrapper.jar" file path, which should be excluded when + * parsing model resources to avoid IOExceptions. + */ + private static final String gradleWrapperJarPathPattern = ".*?/gradle-wrapper\\.jar"; + + /** + * The name of the root directory of the models + */ + private static final String repoModelImplDirName = "repo-clones"; + + /** + * The segment in remote GIT repository URLs, which are followed by the commit + * hash + */ + private static final String repoURICommitSegment = "commit"; + + /** + * The name of the folder, where contents of {@link #resultCache} should be + * saved.
+ *
+ * Note: This folder does not have to directly contain the contents of + * {@link #resultCache}. They may be saved in sub-directories as well. + */ + private static final String expectedSimilarityResultCacheDirName = "results-cache"; + + /** + * The name of the file (with extension), where contents of {@link #resultCache} + * should be saved. + */ + private static final String expectedSimilarityResultCacheFileName = "resultsCache.json"; + + /** + * {@inheritDoc}
+ *
+ * {@link AbstractJaMoPPParserRepoTest}: Loads expected similarity checking + * results, if their file exists. + */ + @BeforeEach + @Override + public void setUp() { + this.startTimeMeasurement(GeneralTimeMeasurementTag.TEST_BEFOREEACH); + super.setUp(); + + var resultCachePath = this.getTestFileLayout().getExpectedSimilarityResultCachePath(); + if (this.getResourceTestOptions().shouldUseCachedExpectedSimilarityResults()) { + this.startTimeMeasurement(RepoTimeMeasurementTag.LOAD_EXPECTED_SIMILARITY_RESULTS); + this.logDebugMsg(String.format("Checking for cached expected similarity results for %s at %s", + this.getCurrentTestClassName(), resultCachePath)); + if (resultCachePath.toFile().exists()) { + this.logDebugMsg(String.format("Cached expected similarity results exist")); + try (BufferedReader reader = Files.newBufferedReader(resultCachePath)) { + this.logDebugMsg(String.format("Reading cached expected similarity results")); + resultCache = new RepoTestResultCache(new Gson().fromJson(reader, resultCache.getClass())); + this.logDebugMsg(String.format("Read cached expected similarity results")); + } catch (IOException e) { + this.logDebugMsg(String.format("Could not read cached expected similarity results for %s at %s", + this.getCurrentTestClassName(), resultCachePath)); + } + } + this.stopTimeMeasurement(); + } else { + this.logDebugMsg(String.format("No saved expected similarity results found for %s at %s", + this.getCurrentTestClassName(), resultCachePath)); + } + this.stopTimeMeasurement(); + } + + /** + * {@inheritDoc}
+ *
+ * {@link AbstractJaMoPPParserRepoTest}: Saves the computed expected similarity + * results and deletes the local repository clone, if desired. + */ + @AfterEach + @Override + public void tearDown() { + this.startTimeMeasurement(GeneralTimeMeasurementTag.TEST_AFTEREACH); + if (this.getResourceTestOptions().shouldSaveCachedExpectedSimilarityResults()) { + this.startTimeMeasurement(RepoTimeMeasurementTag.SAVE_EXPECTED_SIMILARITY_RESULTS); + var gson = new GsonBuilder().setPrettyPrinting().create(); + + var resultCachePath = this.getTestFileLayout().getExpectedSimilarityResultCachePath(); + var resultCacheFile = resultCachePath.toFile(); + + this.logDebugMsg(String.format("Saving cached expected similarity results for %s at %s", + this.getCurrentTestClassName(), resultCachePath)); + + // Re-write expected similarity results + + if (resultCacheFile.exists()) { + resultCacheFile.delete(); + } + resultCacheFile.getParentFile().mkdirs(); + try { + resultCacheFile.createNewFile(); + } catch (IOException e) { + Assertions.fail(String.format("Could not create a file for result cache at %s", resultCachePath), e); + } + + try (BufferedWriter writer = Files.newBufferedWriter(resultCachePath); + var gsonWriter = gson.newJsonWriter(writer)) { + gson.toJson(resultCache, resultCache.getClass(), gsonWriter); + } catch (IOException e) { + Assertions.fail(String.format("Could not save the expected similarity results at %s", resultCachePath), + e); + } + + this.logDebugMsg(String.format("Saved cached expected similarity results for %s at %s", + this.getCurrentTestClassName(), resultCachePath)); + this.stopTimeMeasurement(); + } + + if (this.getResourceTestOptions().shouldDeleteRepositoryClones()) { + this.startTimeMeasurement(RepoTimeMeasurementTag.DELETE_LOCAL_REPO_CLONE); + this.getFileUtil().deleteAll(this.getTestFileLayout().getModelSourceFileRootDirPath()); + this.stopTimeMeasurement(); + } + + this.stopTimeMeasurement(); + super.tearDown(); + } + + @Override + protected RepoParserTestFileLayout initParserTestFileLayout() { + var parserTestLayout = super.initParserTestFileLayout(); + var layout = new RepoParserTestFileLayout(parserTestLayout); + layout.setRepoName(this.getRepoName()); + layout.setExpectedSimilarityResultCacheDirName(expectedSimilarityResultCacheDirName); + layout.setExpectedSimilarityResultCacheFileName(expectedSimilarityResultCacheFileName); + layout.setRepoModelImplDirName(repoModelImplDirName); + return layout; + } + + @Override + protected RepoParserTestFileLayout getTestFileLayout() { + return (RepoParserTestFileLayout) super.getTestFileLayout(); + } + + /** + * @return The expected similarity checking result for the given commits. Note + * that similarity checking is symmetric, meaning that swapping lhs and + * rhs commits should not change the return value. + */ + protected Boolean getExpectedResult(String lhsCommit, String rhsCommit) { + return resultCache.getResult(lhsCommit, rhsCommit); + } + + /** + * Adds model resources to {@link #resultCache} for all commits relevant for + * this test. Must be executed before all tests. + * + * @see {@link #getCommitIDs()} + */ + protected Collection cacheCommitResources() { + var commitResources = new ArrayList(); + var commitResourcesExist = true; + final var expectedResultsExist = new boolean[] { true }; + + var commitIDList = this.getCommitIDs(); + var testStrats = this.getTestGenerationStrategies(); + + /* + * Determine whether all required expected results are in the cache based on + * what commits are compared to one another in the tests + */ + testStrats.forEach((ts) -> ts.getTestResourceIterator(commitIDList.size()).forEachRemaining((idxs) -> { + var commitID1 = commitIDList.get(idxs[0]); + var commitID2 = commitIDList.get(idxs[1]); + if (resultCache.getResult(commitID1, commitID2) == null) { + this.logDebugMsg( + String.format("Expected similarity result missing for: %s vs %s", commitID1, commitID2)); + expectedResultsExist[0] = false; + // Check for the other ones as well, for debugging purposes + } + })); + + for (var cID : commitIDList) { + if (!this.getResourceHelper() + .resourceFileExists(this.getTestFileLayout().getModelResourceSaveURIForCommit(cID))) { + this.logDebugMsg(String.format("Model resource missing for: %s", cID)); + commitResourcesExist = false; + // Check for the other ones as well, for debugging purposes + } + } + + Git git = null; + + if (!expectedResultsExist[0] || !commitResourcesExist) { + this.logDebugMsg("Remote repository must be cloned due to missing resources / expected similarity results"); + git = this.cloneRepo(); + } + + if (!expectedResultsExist[0]) { + this.logDebugMsg(String.format("Computing missing expected similarity results")); + + this.computeExpectedSimilarityResults(git, commitIDList); + + this.logDebugMsg(String.format("Computed missing similarity results")); + } + + if (!commitResourcesExist) { + this.logDebugMsg(String.format("Preparing missing model resources")); + + commitResources.addAll(this.prepareReposForCommits(commitIDList, git)); + + this.logDebugMsg(String.format("Prepared missing model resources")); + } else { + for (var cID : commitIDList) { + var cachedCommitURI = this.getTestFileLayout().getModelResourceSaveURIForCommit(cID); + var res = new JaMoPPModelResourceWrapper(this.getResourceHelper()); + this.startTimeMeasurement(GeneralTimeMeasurementTag.LOAD_MODEL_RESOURCE); + res.loadModelResource(cachedCommitURI); + this.stopTimeMeasurement(); + this.getCacheUtil().addToCache(cachedCommitURI.toString(), res); + commitResources.add(this.getCacheUtil().getFromCache(cachedCommitURI.toString()).getModelResource()); + } + } + + if (git != null) { + this.logDebugMsg("Closing repository wrapper"); + + this.startTimeMeasurement(RepoTimeMeasurementTag.CLOSE_REPOSITORY); + git.getRepository().close(); + git.close(); + this.stopTimeMeasurement(); + + this.logDebugMsg(String.format("Closed repository wrapper")); + } + + var mainLocalClonePath = this.getTestFileLayout().getModelSourceFileRootDirPath(); + + this.logDebugMsg( + String.format("Cleaning main local repository clone under: %s", mainLocalClonePath.toString())); + + this.startTimeMeasurement(RepoTimeMeasurementTag.DELETE_LOCAL_REPO_CLONE); + this.getFileUtil().deleteAll(mainLocalClonePath); + this.stopTimeMeasurement(); + + this.logDebugMsg("Cleaned main local repository clone"); + + this.logDebugMsg(String.format("Repository model resources are cached")); + + return commitResources; + } + + /** + * + * @param git The GIT object associated with the in-memory + * representation of the GIT repository + * @param commitIDList A list of commit hashes, for which expected similarity + * results should be computed. + */ + protected void computeExpectedSimilarityResults(Git git, List commitIDList) { + this.startTimeMeasurement(GeneralTimeMeasurementTag.EXPECTED_SIMILARITY_RESULT_COMPUTATION); + var testStrats = this.getTestGenerationStrategies(); + var expectedValueEstimator = new RepoTestSimilarityValueEstimator(); + + /* + * Determine whether all required expected results are in the cache based on + * what commits are compared to one another in the tests + */ + testStrats.forEach((ts) -> ts.getTestResourceIterator(commitIDList.size()).forEachRemaining((idxs) -> { + var commitID1 = commitIDList.get(idxs[0]); + var commitID2 = commitIDList.get(idxs[1]); + if (resultCache.getResult(commitID1, commitID2) == null) { + this.logDebugMsg( + String.format("Computing expected similarity result for: %s vs %s", commitID1, commitID2)); + var result = expectedValueEstimator.getExpectedSimilarityValueFor(git, commitID1, commitID2); + + resultCache.addResult(commitID1, commitID2, result); + + this.logDebugMsg(String.format("Computed expected similarity result (%s) for: %s vs %s", result, + commitID1, commitID2)); + } + })); + this.stopTimeMeasurement(); + } + + /** + * Clones the repository desired by this test. + * + * @param repoToCloneURI URI to the repository, which should be cloned (local or + * remote) + * @param clonePath The path to the folder, where the repository under + * repoToCloneURI will be cloned + * + * @return An object that can be used to perform GIT operations on the + * repository clone. + */ + protected Git cloneRepo(String repoToCloneURI, Path clonePath) { + this.startTimeMeasurement(RepoTimeMeasurementTag.CLONE_REPOSITORY); + Git git = null; + + // Repository clone does not exist, clone it + if (!clonePath.toFile().exists() || clonePath.toFile().list() == null + || clonePath.toFile().list().length == 0) { + try { + this.logDebugMsg( + String.format("Cloning remote repository (%s) to: %s", repoToCloneURI, clonePath.toString())); + git = Git.cloneRepository().setURI(repoToCloneURI).setDirectory(clonePath.toFile()) + .setCloneAllBranches(true).call(); + this.logDebugMsg(String.format("Cloning successful")); + } catch (GitAPIException e) { + e.printStackTrace(); + Assertions.fail("Could not clone repository"); + } + } + // Repository clone folder exists, try to open it + // If it does not open, delete it and re-try + else { + try { + git = Git.open(clonePath.toFile()); + } catch (IOException e) { + // Faulty repository clone, delete and re-try + this.logDebugMsg("Could not open existing repository, deleting it and re-cloning"); + this.getFileUtil().deleteAll(clonePath); + if (clonePath.toFile().exists() && clonePath.toFile().list().length != 0) { + throw new IllegalStateException("Could not delete faulty repository clone"); + } + git = this.cloneRepo(repoToCloneURI, clonePath); + } + } + + this.stopTimeMeasurement(); + return git; + } + + /** + * Calls {@link #cloneRepo()} with default parameters. + * + * @see {@link #cloneRepo()} + */ + protected Git cloneRepo() { + // Do not explicitly add a folder for this repository, since GIT will do that + // implicitly + return this.cloneRepo(this.getRepoURI().toString(), this.getTestFileLayout().getModelSourceFileRootDirPath()); + } + + /** + * @return The cache key for the model resource parsed from the given commit + * hash of the repository, when its model resource is inserted into the + * cache via {@link #parseModelsDirWithCaching(Path, URI, String)}. + */ + protected String getCacheKeyForCommit(URI repoURI, String commitID) { + return repoURI.appendSegment(repoURICommitSegment).appendSegment(commitID).toString(); + } + + /** + * Adds model resources to cache model resources for each given commit. Requires + * the remote repository to be cloned first (see parameter descriptions).
+ *
+ * MODIFIES THE URI OF THE PARSED MODEL RESOURCES + * + * @param commits Commits for which a model resource will be parsed + * @param gitWrapper The object that can be used to perform GIT operations on + * the "main" repository clone, which should be created with + * {@link #cloneRepo()}. + */ + protected Collection prepareReposForCommits(List commits, Git git) { + + var commitResources = new ArrayList(); + + // Checkout and copy local repository clone for each + // commit except the last one. For the last one, just checkout to that commit to + // spare 1 copy operation + this.logDebugMsg("Caching model resources for commits"); + var commitCount = commits.size(); + for (int i = 0; i < commitCount; i++) { + var commitID = commits.get(i); + var commitResURI = this.getTestFileLayout().getModelResourceSaveURIForCommit(commitID); + + this.logDebugMsg(String.format("Checking out: %s", commitID)); + + this.startTimeMeasurement(RepoTimeMeasurementTag.CHECKOUT_TO_COMMIT); + try { + git.checkout().setName(commitID).call(); + } catch (GitAPIException e) { + this.logDebugMsg(String.format("Error while checking out: %s", commitID)); + throw new IllegalArgumentException(e); + } + this.stopTimeMeasurement(); + + this.logDebugMsg(String.format("Checked out: %s", commitID)); + + this.logDebugMsg(String.format("Caching resource for: %s", commitID)); + + var targetPath = this.getTestFileLayout().getRepoClonePathForCommit(commitID); + IModelResourceWrapper commitRes = null; + + /* + * Load the cached model resource for the commit, if it exists. Otherwise parse + * it. + */ + if (targetPath.toFile().exists()) { + commitRes = this.parseModelsDirWithCaching(targetPath, commitResURI, + getCacheKeyForCommit(this.getRepoURI(), commitID)); + } else { + commitRes = this.parseModelsDirWithCaching(git.getRepository().getDirectory().getParentFile().toPath(), + commitResURI, getCacheKeyForCommit(this.getRepoURI(), commitID)); + commitRes.setModelResourcesURI(commitResURI); + } + + commitResources.add(commitRes.getModelResource()); + this.logDebugMsg(String.format("Cached resource for: %s", commitID)); + } + this.logDebugMsg(String.format("Prepared model resources for commits")); + return commitResources; + } + + /** + * @implSpec Checks whether the given directory name matches any of the commit + * hashes featured in tests. + */ + @Override + protected boolean isModelSourceFileDirectoryName(String dirName) { + return this.getCommitIDs().stream().anyMatch((c) -> dirName.equals(c)); + } + + /** + * @implSpec Adds {@value #gradleWrapperJarPathPattern} to exclusion patterns of + * the given parser, in order for that file to not be locked during + * tests. If it were locked, trying to delete it (while deleting the + * local repository clone) does not work and may lead to IOExceptions. + */ + @Override + protected JaMoPPResourceParsingStrategy initResourceParsingStrategy() { + var strat = super.initResourceParsingStrategy(); + strat.addExclusionPattern(gradleWrapperJarPathPattern); + return strat; + } + + /** + * @return A list of all commits from the repository of this test, which are + * relevant. + */ + protected abstract List getCommitIDs(); + + /** + * @return The URI to the repository, which will be used in tests. + */ + protected abstract URI getRepoURI(); + + /** + * @return The name of the repository that is used in this test. + */ + protected String getRepoName() { + return this.getRepoURI().lastSegment(); + } + + /** + * @return An object that provides expected similarity results for parsed + * commits in tests. + */ + protected IExpectedSimilarityResultProvider getExpectedSimilarityResultProviderForCommits() { + return new RepoCacheSimilarityResultProvider(resultCache); + } + + @Override + protected Collection getTestGenerationStrategies() { + var strats = new ArrayList(); + strats.add(new ReflexiveSymmetricIterationTestGenerationStrategy()); + return strats; + } + + /** + * Extends the super method by preparing repository clones before generating + * dynamic tests.
+ *
+ * {@inheritDoc} + */ + @TestFactory + @Override + public Collection createTests() { + this.startTimeMeasurement(GeneralTimeMeasurementTag.TEST_OVERHEAD); + var resArr = this.cacheCommitResources().toArray(Resource[]::new); + var tests = super.createTests(resArr); + this.stopTimeMeasurement(); + return tests; + } + + @Override + protected RepoParserTestOptions getResourceTestOptions() { + return (RepoParserTestOptions) super.getResourceTestOptions(); + } + + @Override + protected RepoParserTestOptions initResourceTestOptions() { + var superOpts = super.initResourceTestOptions(); + var opts = new RepoParserTestOptions(); + + opts.copyOptionsFrom(superOpts); + + opts.setShouldDeleteRepositoryClones(true); + opts.setShouldSaveCachedExpectedSimilarityResults(true); + opts.setShouldUseCachedExpectedSimilarityResults(true); + return opts; + } +} From c5528ac42272eec98c0046d8856776660e83f71b Mon Sep 17 00:00:00 2001 From: AlpTorac Date: Sun, 27 Jul 2025 17:41:46 +0200 Subject: [PATCH 34/72] Implement repository parser tests for Teammates --- .../repositorytests/TeammatesRepoTest.java | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/TeammatesRepoTest.java diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/TeammatesRepoTest.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/TeammatesRepoTest.java new file mode 100644 index 0000000000..2633ab3a9c --- /dev/null +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/TeammatesRepoTest.java @@ -0,0 +1,38 @@ +package cipm.consistency.fitests.repositorytests; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.eclipse.emf.common.util.URI; + +import cipm.consistency.fitests.similarity.jamopp.parser.AbstractJaMoPPParserSimilarityTestFactory; +import cipm.consistency.fitests.similarity.jamopp.parser.EAllContentSimilarityTestFactory; + +/** + * Contains repository parser tests for the "Teammates" repository + * + * @author Alp Torac Genc + */ +public class TeammatesRepoTest extends AbstractJaMoPPParserRepoTest { + private static final List commitIDs = List.of("648425746bb9434051647c8266dfab50a8f2d6a3", + "48b67bae03babf5a5e578aefce47f0285e8de8b4"); + + @Override + protected List getCommitIDs() { + return commitIDs; + } + + @Override + protected URI getRepoURI() { + return URI.createURI("https://github.com/TEAMMATES/teammates"); + } + + @Override + protected Collection getTestFactories() { + var res = new ArrayList(); + res.add(new EAllContentSimilarityTestFactory(this.getSCC())); + res.forEach((tf) -> tf.setExpectedSimilarityResultProvider(getExpectedSimilarityResultProviderForCommits())); + return res; + } +} From b2ea7ff649b8b1d6a6319d22edf75fc17f1713c4 Mon Sep 17 00:00:00 2001 From: AlpTorac Date: Tue, 29 Jul 2025 11:57:35 +0200 Subject: [PATCH 35/72] Add more Teammates commits to corresponding repository parser test --- .../fitests/repositorytests/TeammatesRepoTest.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/TeammatesRepoTest.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/TeammatesRepoTest.java index 2633ab3a9c..5b6a395a2d 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/TeammatesRepoTest.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/TeammatesRepoTest.java @@ -15,8 +15,14 @@ * @author Alp Torac Genc */ public class TeammatesRepoTest extends AbstractJaMoPPParserRepoTest { + /** + * The list of commits that will be parsed and compared to one another. All of + * them are pairwise different, i.e. all of them introduce code changes that + * break similarity (assuming test code is included). + */ private static final List commitIDs = List.of("648425746bb9434051647c8266dfab50a8f2d6a3", - "48b67bae03babf5a5e578aefce47f0285e8de8b4"); + "48b67bae03babf5a5e578aefce47f0285e8de8b4", "83f518e279807dc7eb7023d008a4d1ab290fefee", + "f33d0bcd5843678b832efd8ee2963e72a95ecfc9", "ce4463a8741840fd25a41b14801eab9193c7ed18"); @Override protected List getCommitIDs() { From a29064fe96a5e46bb56f69d3a4d0f7a26e0bdb69 Mon Sep 17 00:00:00 2001 From: AlpTorac Date: Tue, 29 Jul 2025 11:58:13 +0200 Subject: [PATCH 36/72] Implement repository parser test for CWA-Server --- .../fitests/repositorytests/CWARepoTest.java | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/CWARepoTest.java diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/CWARepoTest.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/CWARepoTest.java new file mode 100644 index 0000000000..9faa731a9f --- /dev/null +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/CWARepoTest.java @@ -0,0 +1,50 @@ +package cipm.consistency.fitests.repositorytests; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.eclipse.emf.common.util.URI; + +import cipm.consistency.fitests.similarity.jamopp.parser.AbstractJaMoPPParserSimilarityTestFactory; +import cipm.consistency.fitests.similarity.jamopp.parser.EAllContentSimilarityTestFactory; + +/** + * Contains repository parser tests for the "cwa-server" repository + * + * @author Alp Torac Genc + */ +public class CWARepoTest extends AbstractJaMoPPParserRepoTest { + /** + * The list of commits that will be parsed and compared to one another. All of + * them are pairwise different, i.e. all of them introduce code changes that + * break similarity (assuming test code is included). + */ + private static final List commitIDs = List.of("7e1b610aa3334afb770eebef79ba60120e2169bc", // Version 2.25.0 + "6e97024a789fa4b68dd3a779ae81dadb3a67ab57", // Version 2.26.0 + "c22f9321075eb1a6754afe1917e149380243c835", // Version 2.27.0 + "33d1c90d58ddc25d9b596547acdf8246b51c4287", // Version 2.27.1 + "9323b87169bd54e5fb0015dcc7791d2fb70aa786", // Version 2.28.0 + "206e8c3b5aa25a99694bd157e0856b7d218ac65d", // Version 3.0.0 + "3977e6b06f72aa9585dee36025df9387eb5e9a7e", // Version 3.1.0 + "94bca6a6cf595ba0c9116d7fe1318fdc495a719f" // Version 3.2.0 + ); + + @Override + protected List getCommitIDs() { + return commitIDs; + } + + @Override + protected URI getRepoURI() { + return URI.createURI("https://github.com/corona-warn-app/cwa-server"); + } + + @Override + protected Collection getTestFactories() { + var res = new ArrayList(); + res.add(new EAllContentSimilarityTestFactory(this.getSCC())); + res.forEach((tf) -> tf.setExpectedSimilarityResultProvider(getExpectedSimilarityResultProviderForCommits())); + return res; + } +} From 7ab16c9e6361c9976ece742e3456f5dd68cf09fa Mon Sep 17 00:00:00 2001 From: AlpTorac Date: Mon, 11 Aug 2025 14:09:23 +0200 Subject: [PATCH 37/72] Add options regarding proxy resolution and resource splitting Now EcoreUtil.resolveAll(...) is guarded by an option, which is set to false by default. This means, proxy objects in the repository parser tests will not be resolved. TrivialRecovery is still performed after parsing the model resource. --- .../parser/JaMoPPModelResourceWrapper.java | 179 ++++++++++++------ 1 file changed, 116 insertions(+), 63 deletions(-) diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/JaMoPPModelResourceWrapper.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/JaMoPPModelResourceWrapper.java index 5c9338843d..186a14cb6e 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/JaMoPPModelResourceWrapper.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/JaMoPPModelResourceWrapper.java @@ -1,9 +1,12 @@ package cipm.consistency.fitests.similarity.jamopp.parser; import java.nio.file.Path; +import java.util.List; +import java.util.stream.Collectors; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.emf.ecore.resource.ResourceSet; import org.eclipse.emf.ecore.util.EcoreUtil; import cipm.consistency.fitests.similarity.ILoggable; @@ -27,6 +30,15 @@ * @author Alp Torac Genc */ public class JaMoPPModelResourceWrapper implements IModelResourceWrapper, ILoggable { + /** + * @see {@link #isResolveAllProxies()} + */ + private boolean resolveAllProxies = false; + /** + * @see {@link #isSplitArtificialResource()} + */ + private boolean splitArtificialResource = false; + private AbstractResourceHelper resHelper; /** @@ -117,54 +129,58 @@ protected URI getArtificialResourceURI(URI correspondingResourceURI) { * will have * @return The created ArtificialResource */ - protected Resource prepareArtificialResource(Resource modelResource, URI artificialResourceURI) { - var modelResourceSet = modelResource.getResourceSet(); - + protected Resource prepareArtificialResource(ResourceSet modelResourceSet, List directModelResources, + URI artificialResourceURI) { // Create the ArtificialResource parsingStrat.performTrivialRecovery(modelResourceSet); - var artificialResource = modelResourceSet.getResources().stream() - .filter((r) -> r.getURI().toString().contains(artificialResourceName)).findFirst().orElse(null); - - if (artificialResource != null) { - artificialResource.setURI(artificialResourceURI); - - this.logDebugMsg(String.format("ArtificialResource is parsed and has its URI set to %s", - artificialResource.getURI())); - - // Use an array to avoid modifications while iterating, which lead to exceptions - var resArr = modelResourceSet.getResources().toArray(Resource[]::new); - - /* - * Iterate over all resources under modelResourceSet and look for resources of - * native Java libraries. Place each such resource's contents into the - * ArtificialResource and remove the native Java library resource from - * modelResourceSet (as it will be empty afterward). This moves all - * CompilationUnits housing the Classifiers required by the parsed model - * resource into ArtificialResource. - */ - for (int i = 0; i < resArr.length; i++) { - var r = resArr[i]; - if (!r.getURI().isFile() && r != artificialResource && r != modelResource) { - this.logDebugMsg(String.format("Adding Resource %s to ArtificialResource", r.getURI())); - artificialResource.getContents().addAll(r.getContents()); - this.logDebugMsg(String.format("Added Resource %s to ArtificialResource", r.getURI())); - modelResourceSet.getResources().remove(r); - this.logDebugMsg(String.format("Removed (empty) Resource %s from ResourceSet", r.getURI())); + Resource artificialResourceForModelResSet = null; + + if (isSplitArtificialResource()) { + artificialResourceForModelResSet = modelResourceSet.getResources().stream() + .filter((r) -> r.getURI().toString().contains(artificialResourceName)).findFirst().orElse(null); + + if (artificialResourceForModelResSet != null) { + artificialResourceForModelResSet.setURI(artificialResourceURI); + + this.logDebugMsg(String.format("ArtificialResource is parsed and has its URI set to %s", + artificialResourceForModelResSet.getURI())); + + // Use an array to avoid modifications while iterating, which lead to exceptions + var resArr = modelResourceSet.getResources().toArray(Resource[]::new); + + /* + * Iterate over all resources under modelResourceSet and look for resources of + * native Java libraries. Place each such resource's contents into the + * ArtificialResource and remove the native Java library resource from + * modelResourceSet (as it will be empty afterward). This moves all + * CompilationUnits housing the Classifiers required by the parsed model + * resource into ArtificialResource. + */ + for (int i = 0; i < resArr.length; i++) { + var r = resArr[i]; + if (!r.getURI().isFile() && r != artificialResourceForModelResSet + && !directModelResources.contains(r)) { + this.logDebugMsg(String.format("Adding Resource %s to ArtificialResource", r.getURI())); + artificialResourceForModelResSet.getContents().addAll(r.getContents()); + this.logDebugMsg(String.format("Added Resource %s to ArtificialResource", r.getURI())); + modelResourceSet.getResources().remove(r); + this.logDebugMsg(String.format("Removed (empty) Resource %s from ResourceSet", r.getURI())); + } } - } - // "-2" to exclude modelResource and artificialResource from resource count - this.logDebugMsg(String.format("%d/%d resources have been added to ArtificialResource", - (resArr.length - modelResourceSet.getResources().size()) - 2, resArr.length - 2)); + // "-2" to exclude modelResource and artificialResource from resource count + this.logDebugMsg(String.format("%d/%d resources have been added to ArtificialResource", + (resArr.length - modelResourceSet.getResources().size()) - 2, resArr.length - 2)); - // Do not handle potential proxies in ArtificialResource, because they belong to - // internals of native classes, which are irrelevant for the model. Normally - // there should be no proxies, if the code represented in the model resource is - // valid. + // Do not handle potential proxies in ArtificialResource, because they belong to + // internals of native classes, which are irrelevant for the model. Normally + // there should be no proxies, if the code represented in the model resource is + // valid. + } } - return artificialResource; + return artificialResourceForModelResSet; } /** @@ -192,32 +208,37 @@ public void parseModelResource(Path modelDir, URI modelResourceURI) { // Find the model resource (i.e. the resource that contains the direct contents // of model files) - var modelResource = modelResourceSet.getResources().stream() - .filter((r) -> r.getURI().toFileString().contains(modelDir.toString())).findFirst().get(); - - /* - * Attempt to resolve potential proxies that can be resolved prior to - * TrivialRecovery, so that it constructs less synthetic elements that are - * redundant. - * - * This is necessary, because synthetic elements' type can vary and can cause - * typing issues during similarity checking, as the (cached) model resource will - * use the synthetic elements, even though they are present directly in the - * model resource. - * - * Examples to this are LocalVariableStatements; which are declared within the - * model, are accessible and referenced by IdentifierReferences. Due to the - * absence of context information during parsing, they are considered Fields, - * unless they are resolved (via EcoreUtil.resolveAll(...) for instance) - * directly after being parsed. Not resolving them causes the - * IdentifierReferences to point at their synthetic element correspondents - * (Fields), as opposed to their declaration in the model resource. - */ - EcoreUtil.resolveAll(modelResource); + var directModelResources = modelResourceSet.getResources().stream() + .filter((r) -> r.getURI().isFile() && r.getURI().toFileString().contains(modelDir.toString())) + .collect(Collectors.toList()); + + if (isResolveAllProxies()) { + /* + * Attempt to resolve potential proxies that can be resolved prior to + * TrivialRecovery, so that it constructs less synthetic elements that are + * redundant. + * + * This is necessary, because synthetic elements' type can vary and can cause + * typing issues during similarity checking, as the (cached) model resource will + * use the synthetic elements, even though they are present directly in the + * model resource. + * + * Examples to this are LocalVariableStatements; which are declared within the + * model, are accessible and referenced by IdentifierReferences. Due to the + * absence of context information during parsing, they are considered Fields, + * unless they are resolved (via EcoreUtil.resolveAll(...) for instance) + * directly after being parsed. Not resolving them causes the + * IdentifierReferences to point at their synthetic element correspondents + * (Fields), as opposed to their declaration in the model resource. + */ + for (var r : directModelResources) { + EcoreUtil.resolveAll(r); + } + } mergedModelResource = this.resHelper.createResource(modelResourceURI); - artificialResource = this.prepareArtificialResource(modelResource, + artificialResource = this.prepareArtificialResource(modelResourceSet, directModelResources, this.getArtificialResourceURI(modelResourceURI)); this.logDebugMsg(String.format("Merging non-ArtificialResources")); @@ -380,4 +401,36 @@ public Resource getModelResource() { public boolean modelResourceExists() { return this.getModelResource() != null; } + + /** + * @return Whether all proxies should be resolved after a model is parsed inside + * {@link #parseModelResource(Path, URI)}. Set to false by default. + */ + public boolean isResolveAllProxies() { + return resolveAllProxies; + } + + /** + * @see {@link #isResolveAllProxies()} + */ + public void setResolveAllProxies(boolean resolveAllProxies) { + this.resolveAllProxies = resolveAllProxies; + } + + /** + * @return Whether the synthetic contents, which were created while parsing the + * model, should be split into a separate Resource. Set to false by + * default. + * @see {@link JaMoPPResourceParsingStrategy#performTrivialRecovery()} + */ + public boolean isSplitArtificialResource() { + return splitArtificialResource; + } + + /** + * @see {@link #isSplitArtificialResource()} + */ + public void setSplitArtificialResource(boolean splitArtificialResource) { + this.splitArtificialResource = splitArtificialResource; + } } From 2d097ed0902e0aacb0ec8d10611381f009e2ab2b Mon Sep 17 00:00:00 2001 From: AlpTorac Date: Mon, 11 Aug 2025 15:35:17 +0200 Subject: [PATCH 38/72] Add test factory for model comparison Implemented an alternative test factory, which resembles how CIPM works while determining the similarity of 2 parsed models --- .../parser/ModelComparisonTestFactory.java | 105 ++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ModelComparisonTestFactory.java diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ModelComparisonTestFactory.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ModelComparisonTestFactory.java new file mode 100644 index 0000000000..c091f64b0f --- /dev/null +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ModelComparisonTestFactory.java @@ -0,0 +1,105 @@ +package cipm.consistency.fitests.similarity.jamopp.parser; + +import java.nio.file.Path; + +import org.eclipse.emf.compare.Comparison; +import org.eclipse.emf.ecore.resource.Resource; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.DynamicNode; +import org.junit.jupiter.api.DynamicTest; + +import cipm.consistency.commitintegration.diff.util.JavaModelComparator; +import cipm.consistency.fitests.similarity.jamopp.JaMoPPSimilarityCheckerContainer; + +/** + * A test class factory, which generates dynamic tests that performs + * hierarchical similarity checking on the given Resources {@code res1, res2} + * and returns the result in form of {@link Comparison} objects.
+ *
+ * The difference between this and {@link EAllContentSimilarityTestFactory} is + * that the comparison here is much more detailed. + * + * @author Alp Torac Genc + */ +public class ModelComparisonTestFactory extends AbstractJaMoPPParserSimilarityTestFactory { + private static final String description = "Java model comparison on both sides"; + private boolean contentOrderMatters; + + public ModelComparisonTestFactory() { + this(true); + } + + public ModelComparisonTestFactory(boolean contentOrderMatters) { + this.contentOrderMatters = contentOrderMatters; + } + + /** + * Compares the given {@link Resource} instances representing Java models. Uses + * the underlying similarity checking mechanisms for identifying changes.
+ *
+ * Note that the order of the given parameters matters and will influence the + * result, since reaching from one side to the other will require "opposite" + * operations. + * + * @param res1 The new state + * @param res2 The old state + * @return Result of comparing {@code res2} to {@code res1}, i.e. what needs to + * be done to {@code res2} to get to {@code res1}. + * + * @see {@link #getSCC()} + */ + protected Comparison compareModels(Resource res1, Resource res2) { + ParserTestTimeMeasurer.getInstance().startTimeMeasurement(this.getClass().getSimpleName(), + GeneralTimeMeasurementTag.MODEL_RESOURCE_COMPARISON); + // TODO Integrate "this.scc" into the model comparator + var result = JavaModelComparator.compareJavaModels(res1, res2, null, null, null); + ParserTestTimeMeasurer.getInstance().stopTimeMeasurement(); + return result; + } + + /** + * Asserts that the result of similarity checking via model comparison results + * in differences or not (denoted by expectedResult).
+ *
+ * Compares res1 and res2, as well as res2 and res1; in order to ensure that the + * comparison is symmetric. + */ + protected void testSimilarityWithModelComparison(Resource res1, Resource res2, Boolean expectedResult) { + ParserTestTimeMeasurer.getInstance().startTimeMeasurement(this.getClass().getSimpleName(), + GeneralTimeMeasurementTag.TEST_OVERHEAD); + + var cmp1To2 = this.compareModels(res1, res2); + var cmp2To1 = this.compareModels(res2, res1); + Assertions.assertEquals(expectedResult, cmp1To2.getDifferences().size() == 0); + Assertions.assertEquals(expectedResult, cmp2To1.getDifferences().size() == 0); + + ParserTestTimeMeasurer.getInstance().stopTimeMeasurement(); + } + + /** + * Checks if parsed {@link Resource} instances are detected as similar. Checks + * the similarity of res1 with res2. + */ + @Override + public DynamicNode createTestsFor(Resource res1, Path path1, Resource res2, Path path2) { + return DynamicTest.dynamicTest(String.format("%s vs %s", path1.getFileName(), path2.getFileName()), () -> { + this.testSimilarityWithModelComparison(res1, res2, + this.getExpectedSimilarityResultFor(res1, path1, res2, path2)); + }); + } + + @Override + public String getTestDescription() { + return description; + } + + @Override + public IExpectedSimilarityResultProvider getDefaultExpectedSimilarityResultProvider() { + // TODO Extract the ISimilarityCheckerContainer as a private variable, which + // should be acquired through the constructor. Since currently + // JavaModelComparator is used, using any other ISimilarityCheckerContainer + // could change test results. Hence it is currently not configurable + return new ResourceContentSimilarityResultProvider(new JaMoPPSimilarityCheckerContainer(), + this.contentOrderMatters); + } +} \ No newline at end of file From a0f914bbebcba90459d582144c70866d88ad00dd Mon Sep 17 00:00:00 2001 From: AlpTorac Date: Mon, 11 Aug 2025 15:35:49 +0200 Subject: [PATCH 39/72] Swap test factory for Teammates and CWA Now the corresponding repository parser tests will perform hierarchical similarity checking over models (similar to CIPM) --- .../consistency/fitests/repositorytests/CWARepoTest.java | 7 +++++-- .../fitests/repositorytests/TeammatesRepoTest.java | 7 +++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/CWARepoTest.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/CWARepoTest.java index 9faa731a9f..85510a5467 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/CWARepoTest.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/CWARepoTest.java @@ -7,7 +7,7 @@ import org.eclipse.emf.common.util.URI; import cipm.consistency.fitests.similarity.jamopp.parser.AbstractJaMoPPParserSimilarityTestFactory; -import cipm.consistency.fitests.similarity.jamopp.parser.EAllContentSimilarityTestFactory; +import cipm.consistency.fitests.similarity.jamopp.parser.ModelComparisonTestFactory; /** * Contains repository parser tests for the "cwa-server" repository @@ -43,7 +43,10 @@ protected URI getRepoURI() { @Override protected Collection getTestFactories() { var res = new ArrayList(); - res.add(new EAllContentSimilarityTestFactory(this.getSCC())); + // TODO Determine whether the order of Resource contents should matter + // Especially important due to synthetic elements from TrivialRecovery + // Use ModelComparisonTestFactory(boolean) to set it (true by default) + res.add(new ModelComparisonTestFactory()); res.forEach((tf) -> tf.setExpectedSimilarityResultProvider(getExpectedSimilarityResultProviderForCommits())); return res; } diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/TeammatesRepoTest.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/TeammatesRepoTest.java index 5b6a395a2d..7af4f3f9a9 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/TeammatesRepoTest.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/TeammatesRepoTest.java @@ -7,7 +7,7 @@ import org.eclipse.emf.common.util.URI; import cipm.consistency.fitests.similarity.jamopp.parser.AbstractJaMoPPParserSimilarityTestFactory; -import cipm.consistency.fitests.similarity.jamopp.parser.EAllContentSimilarityTestFactory; +import cipm.consistency.fitests.similarity.jamopp.parser.ModelComparisonTestFactory; /** * Contains repository parser tests for the "Teammates" repository @@ -37,7 +37,10 @@ protected URI getRepoURI() { @Override protected Collection getTestFactories() { var res = new ArrayList(); - res.add(new EAllContentSimilarityTestFactory(this.getSCC())); + // TODO Determine whether the order of Resource contents should matter + // Especially important due to synthetic elements from TrivialRecovery + // Use ModelComparisonTestFactory(boolean) to set it (true by default) + res.add(new ModelComparisonTestFactory()); res.forEach((tf) -> tf.setExpectedSimilarityResultProvider(getExpectedSimilarityResultProviderForCommits())); return res; } From 1cdf8e68c7b91ed76fd693b4185f2824503336c1 Mon Sep 17 00:00:00 2001 From: AlpTorac Date: Mon, 11 Aug 2025 19:51:35 +0200 Subject: [PATCH 40/72] Work on time measurement keys Replaced the string-based time measurement keys with a key class, which can encapsulate various information about time measurements. They follow a similar construction pattern as the builder pattern. Note: Currently, some important information (such as commit IDs) are not directly available in all time measurement entries. They can, however, be derived from the "(Left/Right)ParsedModelLocation" keys, as they currently contain the URI of the parsed model resources, whose last 2 segments are the repository name and "commitID.javaxmi". --- .../AbstractJaMoPPParserRepoTest.java | 26 +- .../AbstractJaMoPPParserSimilarityTest.java | 85 +++--- ...ractJaMoPPParserSimilarityTestFactory.java | 39 ++- .../EAllContentSimilarityTestFactory.java | 4 +- .../parser/ModelComparisonTestFactory.java | 14 +- .../parser/ParserTestTimeMeasurementKey.java | 278 ++++++++++++++++++ .../jamopp/parser/ParserTestTimeMeasurer.java | 14 +- 7 files changed, 411 insertions(+), 49 deletions(-) create mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ParserTestTimeMeasurementKey.java diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/AbstractJaMoPPParserRepoTest.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/AbstractJaMoPPParserRepoTest.java index 3055c0986a..9a81b2cd21 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/AbstractJaMoPPParserRepoTest.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/AbstractJaMoPPParserRepoTest.java @@ -9,8 +9,10 @@ import cipm.consistency.fitests.similarity.jamopp.parser.IExpectedSimilarityResultProvider; import cipm.consistency.fitests.similarity.jamopp.parser.IJaMoPPParserTestGenerationStrategy; import cipm.consistency.fitests.similarity.jamopp.parser.IModelResourceWrapper; +import cipm.consistency.fitests.similarity.jamopp.parser.ITimeMeasurementTag; import cipm.consistency.fitests.similarity.jamopp.parser.ReflexiveSymmetricIterationTestGenerationStrategy; import cipm.consistency.fitests.similarity.jamopp.parser.JaMoPPModelResourceWrapper; +import cipm.consistency.fitests.similarity.jamopp.parser.ParserTestTimeMeasurementKey; import java.io.BufferedReader; import java.io.BufferedWriter; @@ -172,6 +174,17 @@ public void tearDown() { super.tearDown(); } + @Override + protected void startTimeMeasurement(ParserTestTimeMeasurementKey key, ITimeMeasurementTag tag) { + super.startTimeMeasurement( + key.withRepositoryName(getRepoName()).withRepositoryURI(this.getRepoURI().toString()), tag); + } + + @Override + protected ParserTestTimeMeasurementKey createTimeMeasurementKey() { + return new ParserTestTimeMeasurementKey(); + } + @Override protected RepoParserTestFileLayout initParserTestFileLayout() { var parserTestLayout = super.initParserTestFileLayout(); @@ -260,7 +273,9 @@ protected Collection cacheCommitResources() { for (var cID : commitIDList) { var cachedCommitURI = this.getTestFileLayout().getModelResourceSaveURIForCommit(cID); var res = new JaMoPPModelResourceWrapper(this.getResourceHelper()); - this.startTimeMeasurement(GeneralTimeMeasurementTag.LOAD_MODEL_RESOURCE); + this.startTimeMeasurement( + this.createTimeMeasurementKey().withParsedModelLocation(cachedCommitURI.toString()), + GeneralTimeMeasurementTag.LOAD_MODEL_RESOURCE); res.loadModelResource(cachedCommitURI); this.stopTimeMeasurement(); this.getCacheUtil().addToCache(cachedCommitURI.toString(), res); @@ -303,7 +318,6 @@ protected Collection cacheCommitResources() { * results should be computed. */ protected void computeExpectedSimilarityResults(Git git, List commitIDList) { - this.startTimeMeasurement(GeneralTimeMeasurementTag.EXPECTED_SIMILARITY_RESULT_COMPUTATION); var testStrats = this.getTestGenerationStrategies(); var expectedValueEstimator = new RepoTestSimilarityValueEstimator(); @@ -317,15 +331,18 @@ protected void computeExpectedSimilarityResults(Git git, List commitIDLi if (resultCache.getResult(commitID1, commitID2) == null) { this.logDebugMsg( String.format("Computing expected similarity result for: %s vs %s", commitID1, commitID2)); + this.startTimeMeasurement( + this.createTimeMeasurementKey().withLeftCommitID(commitID1).withRightCommitID(commitID2), + GeneralTimeMeasurementTag.EXPECTED_SIMILARITY_RESULT_COMPUTATION); var result = expectedValueEstimator.getExpectedSimilarityValueFor(git, commitID1, commitID2); resultCache.addResult(commitID1, commitID2, result); + this.stopTimeMeasurement(); this.logDebugMsg(String.format("Computed expected similarity result (%s) for: %s vs %s", result, commitID1, commitID2)); } })); - this.stopTimeMeasurement(); } /** @@ -423,7 +440,8 @@ protected Collection prepareReposForCommits(List commits, Git this.logDebugMsg(String.format("Checking out: %s", commitID)); - this.startTimeMeasurement(RepoTimeMeasurementTag.CHECKOUT_TO_COMMIT); + this.startTimeMeasurement(this.createTimeMeasurementKey().withCommitID(commitID), + RepoTimeMeasurementTag.CHECKOUT_TO_COMMIT); try { git.checkout().setName(commitID).call(); } catch (GitAPIException e) { diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/AbstractJaMoPPParserSimilarityTest.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/AbstractJaMoPPParserSimilarityTest.java index afd596ecfe..ceb6f31bc0 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/AbstractJaMoPPParserSimilarityTest.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/AbstractJaMoPPParserSimilarityTest.java @@ -105,23 +105,35 @@ public void tearDown() { if (this.getResourceTestOptions().shouldSaveCachedResources()) { this.logDebugMsg("Saving all cached resources after parser test"); - this.startTimeMeasurement(GeneralTimeMeasurementTag.SAVE_MODEL_RESOURCE); - cachedResources.forEach((res) -> res.saveResources()); - this.stopTimeMeasurement(); + cachedResources.forEach((res) -> { + this.startTimeMeasurement( + createTimeMeasurementKey().withParsedModelLocation(res.getModelResource().getURI().toString()), + GeneralTimeMeasurementTag.SAVE_MODEL_RESOURCE); + res.saveResources(); + this.stopTimeMeasurement(); + }); this.logDebugMsg("Saved all cached resources after parser test"); } if (this.getResourceTestOptions().shouldDeleteAllResources()) { this.logDebugMsg("Deleting all cached resources after parser test"); - this.startTimeMeasurement(GeneralTimeMeasurementTag.DELETE_MODEL_RESOURCE); - cachedResources.forEach((res) -> res.deleteResources()); - this.stopTimeMeasurement(); + cachedResources.forEach((res) -> { + this.startTimeMeasurement( + createTimeMeasurementKey().withParsedModelLocation(res.getModelResource().getURI().toString()), + GeneralTimeMeasurementTag.DELETE_MODEL_RESOURCE); + res.deleteResources(); + this.stopTimeMeasurement(); + }); this.logDebugMsg("Deleted all cached resources after parser test"); } else if (this.getResourceTestOptions().shouldUnloadAllResources()) { this.logDebugMsg("Unloading all cached resources after parser test"); - this.startTimeMeasurement(GeneralTimeMeasurementTag.UNLOAD_MODEL_RESOURCE); - cachedResources.forEach((res) -> res.unloadResources()); - this.stopTimeMeasurement(); + cachedResources.forEach((res) -> { + this.startTimeMeasurement( + createTimeMeasurementKey().withParsedModelLocation(res.getModelResource().getURI().toString()), + GeneralTimeMeasurementTag.UNLOAD_MODEL_RESOURCE); + res.unloadResources(); + this.stopTimeMeasurement(); + }); this.logDebugMsg("Unloaded all cached resources after parser test"); } @@ -165,15 +177,6 @@ protected void saveTimeMeasurements() { this.logDebugMsg("Saved time measurements"); } - /** - * A variant of {@link #startTimeMeasurement(String, ITimeMeasurementTag)} for - * individual model source file directories. - */ - protected void startTimeMeasurement(Path modelDir, ITimeMeasurementTag tag) { - this.startTimeMeasurement(modelDir != null ? this.layout.getCacheKeyForModelSourceFileDir(modelDir) : null, - tag); - } - /** * Delegates to the time measuring mechanism and signals that a time measurement * with the given parameters should be started.
@@ -186,16 +189,22 @@ protected void startTimeMeasurement(Path modelDir, ITimeMeasurementTag tag) { * @param tag The tag of the time measurement, which is used to group time * measurements */ - protected void startTimeMeasurement(String key, ITimeMeasurementTag tag) { - ParserTestTimeMeasurer.getInstance().startTimeMeasurement(key, tag); + protected void startTimeMeasurement(ParserTestTimeMeasurementKey key, ITimeMeasurementTag tag) { + ParserTestTimeMeasurer.getInstance().startTimeMeasurement(key.withTestClassName(getCurrentTestClassName()), + tag); } /** - * A variant of {@link #startTimeMeasurement(String, ITimeMeasurementTag)} for - * the current concrete test class. + * A variant of + * {@link #startTimeMeasurement(ParserTestTimeMeasurementKey, ITimeMeasurementTag)} + * for the current concrete test class. */ protected void startTimeMeasurement(ITimeMeasurementTag tag) { - this.startTimeMeasurement(this.getCurrentTestClassName(), tag); + startTimeMeasurement(createTimeMeasurementKey(), tag); + } + + protected ParserTestTimeMeasurementKey createTimeMeasurementKey() { + return new ParserTestTimeMeasurementKey(); } /** @@ -245,7 +254,10 @@ protected CacheUtil getCacheUtil() { * @see {@link #prepareArtificialResource(Resource, URI)} */ protected IModelResourceWrapper parseModelsDirWithoutCaching(Path modelDir) { - this.startTimeMeasurement(GeneralTimeMeasurementTag.PARSE_MODEL_RESOURCE); + this.startTimeMeasurement( + createTimeMeasurementKey().withOriginalModelLocation(modelDir.toString()) + .withResourceParsingStrategyClassName(this.getResourceParsingStrategy().getClass().getSimpleName()), + GeneralTimeMeasurementTag.PARSE_MODEL_RESOURCE); var wrapper = new JaMoPPModelResourceWrapper(this.getResourceHelper(), this.getResourceParsingStrategy()); wrapper.parseModelResource(modelDir, this.layout.getModelResourceURI(modelDir)); this.stopTimeMeasurement(); @@ -280,7 +292,8 @@ protected IModelResourceWrapper parseModelsDirWithCaching(Path modelDir, String * parsed model resource to the cache under cacheKey. */ protected IModelResourceWrapper parseModelsDirWithCaching(Path modelDir, URI cachedModelURI, String cacheKey) { - this.startTimeMeasurement(GeneralTimeMeasurementTag.MODEL_RESOURCE_CACHE_ACCESS); + this.startTimeMeasurement(createTimeMeasurementKey().withOriginalModelLocation(modelDir.toString()) + .withParsedModelLocation(cachedModelURI.toString()), GeneralTimeMeasurementTag.MODEL_RESOURCE_CACHE_ACCESS); var cache = this.getCacheUtil(); var modelName = this.getDisplayNameForModelDir(modelDir); @@ -298,7 +311,8 @@ protected IModelResourceWrapper parseModelsDirWithCaching(Path modelDir, URI cac this.logDebugMsg(String.format("%s is in cache, using cached version", modelName)); resWrapper = cache.getFromCache(cacheKey); if (!resWrapper.isModelResourceLoaded()) { - this.startTimeMeasurement(GeneralTimeMeasurementTag.LOAD_MODEL_RESOURCE); + this.startTimeMeasurement(createTimeMeasurementKey().withOriginalModelLocation(modelDir.toString()) + .withParsedModelLocation(cachedModelURI.toString()), GeneralTimeMeasurementTag.LOAD_MODEL_RESOURCE); resWrapper.loadParsedResources(); this.stopTimeMeasurement(); } @@ -307,7 +321,8 @@ protected IModelResourceWrapper parseModelsDirWithCaching(Path modelDir, URI cac // Search for the resource file in cache save location if (resWrapper == null) { resWrapper = new JaMoPPModelResourceWrapper(this.getResourceHelper()); - this.startTimeMeasurement(GeneralTimeMeasurementTag.LOAD_MODEL_RESOURCE); + this.startTimeMeasurement(createTimeMeasurementKey().withOriginalModelLocation(modelDir.toString()) + .withParsedModelLocation(cachedModelURI.toString()), GeneralTimeMeasurementTag.LOAD_MODEL_RESOURCE); resWrapper.loadModelResource(cachedModelURI); this.stopTimeMeasurement(); if (resWrapper.isModelResourceLoaded()) { @@ -487,9 +502,11 @@ public Collection createTests() { * @return A collection of model directory paths under rootPath */ protected Collection discoverModelSourceFileDirsAt(Path rootPath) { - this.startTimeMeasurement(GeneralTimeMeasurementTag.DISCOVER_MODEL_RESOURCES); - var result = new ModelDirDiscoveryStrategy((f) -> this.isModelSourceFileDirectory(f)) - .discoverModelSourceDirs(rootPath.toFile()); + var discoveryStrat = new ModelDirDiscoveryStrategy((f) -> this.isModelSourceFileDirectory(f)); + this.startTimeMeasurement(createTimeMeasurementKey().withModelDiscoveryPath(rootPath.toString()) + .withModelDiscoveryClassName(discoveryStrat.getClass().getSimpleName()), + GeneralTimeMeasurementTag.DISCOVER_MODEL_RESOURCES); + var result = discoveryStrat.discoverModelSourceDirs(rootPath.toFile()); this.stopTimeMeasurement(); return result; } @@ -501,9 +518,11 @@ protected Collection discoverModelSourceFileDirsAt(Path rootPath) { * rootPath */ protected Collection discoverModelSourceParentDirsAt(Path rootPath) { - this.startTimeMeasurement(GeneralTimeMeasurementTag.DISCOVER_MODEL_RESOURCES); - var result = new ModelDirDiscoveryStrategy((f) -> this.isModelSourceFileDirectory(f)) - .discoverModelSourceParentDirs(rootPath.toFile()); + var discoveryStrat = new ModelDirDiscoveryStrategy((f) -> this.isModelSourceFileDirectory(f)); + this.startTimeMeasurement(createTimeMeasurementKey().withModelDiscoveryPath(rootPath.toString()) + .withModelDiscoveryClassName(discoveryStrat.getClass().getSimpleName()), + GeneralTimeMeasurementTag.DISCOVER_MODEL_RESOURCES); + var result = discoveryStrat.discoverModelSourceParentDirs(rootPath.toFile()); this.stopTimeMeasurement(); return result; } diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/AbstractJaMoPPParserSimilarityTestFactory.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/AbstractJaMoPPParserSimilarityTestFactory.java index 17a908184d..d2960a542b 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/AbstractJaMoPPParserSimilarityTestFactory.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/AbstractJaMoPPParserSimilarityTestFactory.java @@ -84,7 +84,7 @@ public String getTestDescription() { */ public boolean getExpectedSimilarityResultFor(Resource lhsRes, Path lhsResPath, Resource rhsRes, Path rhsResPath) { ParserTestTimeMeasurer.getInstance().startTimeMeasurement( - this.getExpectedSimilarityResultProvider().getClass().getSimpleName(), + this.getTimeMeasurementKeyFor(lhsRes, lhsResPath, rhsRes, rhsResPath), GeneralTimeMeasurementTag.EXPECTED_SIMILARITY_RESULT_COMPUTATION); var result = this.getExpectedSimilarityResultProvider().getExpectedSimilarityResultFor(lhsRes, lhsResPath, rhsRes, rhsResPath); @@ -92,6 +92,43 @@ public boolean getExpectedSimilarityResultFor(Resource lhsRes, Path lhsResPath, return result; } + /** + * @return Generates a time measurement key for the given parameters + */ + protected ParserTestTimeMeasurementKey getTimeMeasurementKeyFor(Resource lhsRes, Path lhsResPath, Resource rhsRes, + Path rhsResPath) { + var key = new ParserTestTimeMeasurementKey(); + + key.withTestFactoryClassName(this.getClass().getSimpleName()); + key.withExpectedSimilarityResultProviderClassName(this.getExpectedSimilarityResultProvider().getClass().getSimpleName()); + + // TODO Clean up or fix to set the repository name and commitID fields + // It is currently possible to derive them from the model resource URIs: + // modelRes.getURI() = ".../repositoryName/commitID.javaxmi" + + if (lhsRes != null) { + key.withParsedLeftModelLocation(lhsRes.getURI().toString()); +// .withLeftRepositoryName(lhsRes.getURI().segment(lhsRes.getURI().segmentCount() - 2)) +// .withLeftCommitID(lhsRes.getURI().lastSegment().split("\\.")[0]) + } + + if (lhsResPath != null) { + key.withOriginalLeftModelLocation(lhsResPath.toString()); + } + + if (rhsRes != null) { + key.withParsedRightModelLocation(rhsRes.getURI().toString()); +// .withRightRepositoryName(rhsRes.getURI().segment(rhsRes.getURI().segmentCount() - 2)) +// .withRightCommitID(rhsRes.getURI().lastSegment().split("\\.")[0]) + } + + if (rhsResPath != null) { + key.withOriginalRightModelLocation(rhsResPath.toString()); + } + + return key; + } + /** * The provided model resources are not assumed to have a certain order here, * because the concrete implementor could change what resources are checked for diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/EAllContentSimilarityTestFactory.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/EAllContentSimilarityTestFactory.java index 44ef9124a2..5bcf864470 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/EAllContentSimilarityTestFactory.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/EAllContentSimilarityTestFactory.java @@ -33,7 +33,7 @@ public EAllContentSimilarityTestFactory(ISimilarityCheckerContainer scc) { * considered and will impact the result. */ protected void testSimilarityOfAllContents(Resource res1, Resource res2, Boolean expectedResult) { - ParserTestTimeMeasurer.getInstance().startTimeMeasurement(this.getClass().getSimpleName(), + ParserTestTimeMeasurer.getInstance().startTimeMeasurement(this.getTimeMeasurementKeyFor(res1, null, res2, null), GeneralTimeMeasurementTag.TEST_OVERHEAD); var list1 = new ArrayList(); var list2 = new ArrayList(); @@ -41,7 +41,7 @@ protected void testSimilarityOfAllContents(Resource res1, Resource res2, Boolean res1.getAllContents().forEachRemaining((o) -> list1.add(o)); res2.getAllContents().forEachRemaining((o) -> list2.add(o)); - ParserTestTimeMeasurer.getInstance().startTimeMeasurement(this.getClass().getSimpleName(), + ParserTestTimeMeasurer.getInstance().startTimeMeasurement(this.getTimeMeasurementKeyFor(res1, null, res2, null), GeneralTimeMeasurementTag.SIMILARITY_CHECKING); Assertions.assertEquals(expectedResult, this.scc.areSimilar(list1, list2)); ParserTestTimeMeasurer.getInstance().stopTimeMeasurement(); diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ModelComparisonTestFactory.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ModelComparisonTestFactory.java index c091f64b0f..7790004a36 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ModelComparisonTestFactory.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ModelComparisonTestFactory.java @@ -49,7 +49,9 @@ public ModelComparisonTestFactory(boolean contentOrderMatters) { * @see {@link #getSCC()} */ protected Comparison compareModels(Resource res1, Resource res2) { - ParserTestTimeMeasurer.getInstance().startTimeMeasurement(this.getClass().getSimpleName(), + ParserTestTimeMeasurer.getInstance().startTimeMeasurement( + this.getTimeMeasurementKeyFor(res1, null, res2, null) + .withModelComparisonClassName(JavaModelComparator.class.getSimpleName()), GeneralTimeMeasurementTag.MODEL_RESOURCE_COMPARISON); // TODO Integrate "this.scc" into the model comparator var result = JavaModelComparator.compareJavaModels(res1, res2, null, null, null); @@ -65,12 +67,18 @@ protected Comparison compareModels(Resource res1, Resource res2) { * comparison is symmetric. */ protected void testSimilarityWithModelComparison(Resource res1, Resource res2, Boolean expectedResult) { - ParserTestTimeMeasurer.getInstance().startTimeMeasurement(this.getClass().getSimpleName(), + ParserTestTimeMeasurer.getInstance().startTimeMeasurement(this.getTimeMeasurementKeyFor(res1, null, res2, null), GeneralTimeMeasurementTag.TEST_OVERHEAD); var cmp1To2 = this.compareModels(res1, res2); - var cmp2To1 = this.compareModels(res2, res1); Assertions.assertEquals(expectedResult, cmp1To2.getDifferences().size() == 0); + + ParserTestTimeMeasurer.getInstance().stopTimeMeasurement(); + + ParserTestTimeMeasurer.getInstance().startTimeMeasurement(this.getTimeMeasurementKeyFor(res2, null, res1, null), + GeneralTimeMeasurementTag.TEST_OVERHEAD); + + var cmp2To1 = this.compareModels(res2, res1); Assertions.assertEquals(expectedResult, cmp2To1.getDifferences().size() == 0); ParserTestTimeMeasurer.getInstance().stopTimeMeasurement(); diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ParserTestTimeMeasurementKey.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ParserTestTimeMeasurementKey.java new file mode 100644 index 0000000000..53025cbf70 --- /dev/null +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ParserTestTimeMeasurementKey.java @@ -0,0 +1,278 @@ +package cipm.consistency.fitests.similarity.jamopp.parser; + +import java.util.HashMap; +import java.util.Map; + +import com.google.gson.annotations.Expose; + +/** + * A class that contains information about time measurements. Instances of this + * class can be filled in by using the {@code with...(...)} methods it offers. + * For convenience, those methods return this instance.
+ *
+ * There is no mandatory information that should be given to this class. + * + * @author Alp Torac Genc + */ +public class ParserTestTimeMeasurementKey { + @Expose + private final Map keyMap = new HashMap(); + + /** + * The class name of the instance, which is used for hierarchical model + * comparison (ex: JavaModelComparator) + */ + public ParserTestTimeMeasurementKey withModelComparisonClassName(String modelComparisonClassName) { + this.keyMap.put(ParserTestTimeMeasurerKeyType.MODEL_COMPARISON_CLASS_NAME, modelComparisonClassName); + return this; + } + + /** + * The path, from which original model files are explored. Model resources will + * then be parsed from them. + */ + public ParserTestTimeMeasurementKey withModelDiscoveryPath(String modelDiscoveryPath) { + this.keyMap.put(ParserTestTimeMeasurerKeyType.MODEL_DISCOVERY_PATH, modelDiscoveryPath); + return this; + } + + /** + * The class name of the instance, which is used for discovering original model + * files (ex: ModelDirDiscoveryStrategy) + */ + public ParserTestTimeMeasurementKey withModelDiscoveryClassName(String modelDiscoveryClassName) { + this.keyMap.put(ParserTestTimeMeasurerKeyType.MODEL_DISCOVERY_CLASS_NAME, modelDiscoveryClassName); + return this; + } + + /** + * The class name of the instance, which is used to parse model resources (ex: + * JaMoPPResourceParsingStrategy) + */ + public ParserTestTimeMeasurementKey withResourceParsingStrategyClassName(String resourceParsingStrategyClassName) { + this.keyMap.put(ParserTestTimeMeasurerKeyType.RESOURCE_PARSING_STRATEGY_CLASS_NAME, + resourceParsingStrategyClassName); + return this; + } + + /** + * The location, under which all original model files can be found. These files + * were parsed to create the corresponding model resource. The location can be + * any form of String that can be used to navigate (ex: Path.toString() or + * URI.toString()).
+ *
+ * Use this, if only one model is considered. + */ + public ParserTestTimeMeasurementKey withOriginalModelLocation(String originalModelLocation) { + this.keyMap.put(ParserTestTimeMeasurerKeyType.ORIGINAL_MODEL_LOCATION, originalModelLocation); + return this; + } + + /** + * The location, under which the parsed model resource can be found. The + * location can be any form of String that can be used to navigate (ex: + * Path.toString() or URI.toString()).
+ *
+ * Use this, if only one model is considered. + */ + public ParserTestTimeMeasurementKey withParsedModelLocation(String parsedModelLocation) { + this.keyMap.put(ParserTestTimeMeasurerKeyType.PARSED_MODEL_LOCATION, parsedModelLocation); + return this; + } + + /** + * The path, under which all (left hand side) original model files can be found. + * These files were parsed to create the corresponding model resource. The + * location can be any form of String that can be used to navigate (ex: + * Path.toString() or URI.toString()).
+ *
+ * Use this, if two models are considered. + */ + public ParserTestTimeMeasurementKey withOriginalLeftModelLocation(String originalModelLocation) { + this.keyMap.put(ParserTestTimeMeasurerKeyType.ORIGINAL_LEFT_MODEL_LOCATION, originalModelLocation); + return this; + } + + /** + * The location, under which the (left hand side) parsed model resource can be + * found. The location can be any form of String that can be used to navigate + * (ex: Path.toString() or URI.toString()).
+ *
+ * Use this, if two models are considered. + */ + public ParserTestTimeMeasurementKey withParsedLeftModelLocation(String parsedModelLocation) { + this.keyMap.put(ParserTestTimeMeasurerKeyType.PARSED_LEFT_MODEL_LOCATION, parsedModelLocation); + return this; + } + + /** + * The path, under which all (right hand side) original model files can be + * found. These files were parsed to create the corresponding model resource.The + * location can be any form of String that can be used to navigate (ex: + * Path.toString() or URI.toString()).
+ *
+ *
+ * Use this, if two models are considered. + */ + public ParserTestTimeMeasurementKey withOriginalRightModelLocation(String originalModelLocation) { + this.keyMap.put(ParserTestTimeMeasurerKeyType.ORIGINAL_RIGHT_MODEL_LOCATION, originalModelLocation); + return this; + } + + /** + * The location, under which the (right hand side) parsed model resource can be + * found. The location can be any form of String that can be used to navigate + * (ex: Path.toString() or URI.toString()).
+ *
+ * Use this, if two models are considered. + */ + public ParserTestTimeMeasurementKey withParsedRightModelLocation(String parsedModelLocation) { + this.keyMap.put(ParserTestTimeMeasurerKeyType.PARSED_RIGHT_MODEL_LOCATION, parsedModelLocation); + return this; + } + + /** + * The name of the test class (ex: CWARepoTest) + */ + public ParserTestTimeMeasurementKey withTestClassName(String testClassName) { + this.keyMap.put(ParserTestTimeMeasurerKeyType.TEST_CLASS_NAME, testClassName); + return this; + } + + /** + * The name of the test factory class, which was used to create the dynamic + * tests (ex: ModelComparisonTestFactory) + */ + public ParserTestTimeMeasurementKey withTestFactoryClassName(String testFactoryClassName) { + this.keyMap.put(ParserTestTimeMeasurerKeyType.TEST_FACTORY_CLASS_NAME, testFactoryClassName); + return this; + } + + /** + * The class name of the instance, which provides expected similarity results to + * dynamic tests (ex: ResourceReferenceEqualitySimilarityResultProvider) + */ + public ParserTestTimeMeasurementKey withExpectedSimilarityResultProviderClassName( + String expectedSimilarityResultProviderClassName) { + this.keyMap.put(ParserTestTimeMeasurerKeyType.EXPECTED_SIMILARITY_RESULT_PROVIDER_CLASS_NAME, + expectedSimilarityResultProviderClassName); + return this; + } + + /** + * The name of the repository that is considered in the test class.
+ *
+ * Use this, if only one repository/commit is considered. + */ + public ParserTestTimeMeasurementKey withRepositoryName(String repositoryName) { + this.keyMap.put(ParserTestTimeMeasurerKeyType.REPOSITORY_NAME, repositoryName); + return this; + } + + /** + * The URI to the repository that is considered in the test class.
+ *
+ * Use this, if only one repository/commit is considered. + */ + public ParserTestTimeMeasurementKey withRepositoryURI(String repositoryURI) { + this.keyMap.put(ParserTestTimeMeasurerKeyType.REPOSITORY_URI, repositoryURI); + return this; + } + + /** + * The hash of the commit that is currently considered.
+ *
+ * Use this, if only one commit is considered. + */ + public ParserTestTimeMeasurementKey withCommitID(String commitID) { + this.keyMap.put(ParserTestTimeMeasurerKeyType.COMMIT_ID, commitID); + return this; + } + + /** + * The name of the (left-hand-side) repository.
+ *
+ * Use this, if two repositories/commits are considered. + */ + public ParserTestTimeMeasurementKey withLeftRepositoryName(String leftRepositoryName) { + this.keyMap.put(ParserTestTimeMeasurerKeyType.LEFT_REPOSITORY_NAME, leftRepositoryName); + return this; + } + + /** + * The URI to the (left-hand-side) repository.
+ *
+ * Use this, if two repositories/commits are considered. + */ + public ParserTestTimeMeasurementKey withLeftRepositoryURI(String leftRepositoryURI) { + this.keyMap.put(ParserTestTimeMeasurerKeyType.LEFT_REPOSITORY_URI, leftRepositoryURI); + return this; + } + + /** + * The name of the (right-hand-side) repository.
+ *
+ * Use this, if two repositories/commits are considered. + */ + public ParserTestTimeMeasurementKey withRightRepositoryName(String rightRepositoryName) { + this.keyMap.put(ParserTestTimeMeasurerKeyType.RIGHT_REPOSITORY_NAME, rightRepositoryName); + return this; + } + + /** + * The URI to the (right-hand-side) repository.
+ *
+ * Use this, if two repositories/commits are considered. + */ + public ParserTestTimeMeasurementKey withRightRepositoryURI(String rightRepositoryURI) { + this.keyMap.put(ParserTestTimeMeasurerKeyType.RIGHT_REPOSITORY_URI, rightRepositoryURI); + return this; + } + + /** + * The hash of the (left-hand-side) commit that is currently considered.
+ *
+ * Use this, if two commits are considered. + */ + public ParserTestTimeMeasurementKey withLeftCommitID(String leftCommitID) { + this.keyMap.put(ParserTestTimeMeasurerKeyType.LEFT_COMMIT_ID, leftCommitID); + return this; + } + + /** + * The hash of the (right-hand-side) commit that is currently considered.
+ *
+ * Use this, if two commits are considered. + */ + public ParserTestTimeMeasurementKey withRightCommitID(String rightCommitID) { + this.keyMap.put(ParserTestTimeMeasurerKeyType.RIGHT_COMMIT_ID, rightCommitID); + return this; + } + + public enum ParserTestTimeMeasurerKeyType { + MODEL_DISCOVERY_PATH, + + MODEL_DISCOVERY_CLASS_NAME, + + ORIGINAL_MODEL_LOCATION, PARSED_MODEL_LOCATION, + + ORIGINAL_LEFT_MODEL_LOCATION, PARSED_LEFT_MODEL_LOCATION, ORIGINAL_RIGHT_MODEL_LOCATION, + PARSED_RIGHT_MODEL_LOCATION, + + RESOURCE_PARSING_STRATEGY_CLASS_NAME, + + MODEL_COMPARISON_CLASS_NAME, + + TEST_CLASS_NAME, TEST_FACTORY_CLASS_NAME, + + EXPECTED_SIMILARITY_RESULT_PROVIDER_CLASS_NAME, + + REPOSITORY_NAME, REPOSITORY_URI, COMMIT_ID, + + LEFT_REPOSITORY_NAME, LEFT_REPOSITORY_URI, + + RIGHT_REPOSITORY_NAME, RIGHT_REPOSITORY_URI, + + LEFT_COMMIT_ID, RIGHT_COMMIT_ID; + } +} diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ParserTestTimeMeasurer.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ParserTestTimeMeasurer.java index 0baaa4155d..1c86f6c185 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ParserTestTimeMeasurer.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ParserTestTimeMeasurer.java @@ -162,7 +162,7 @@ public static ParserTestTimeMeasurer getInstance() { * @param tag The tag of the time measurement, which is used to group time * measurements */ - public void startTimeMeasurement(String key, ITimeMeasurementTag tag) { + public void startTimeMeasurement(ParserTestTimeMeasurementKey key, ITimeMeasurementTag tag) { if (this.startTime == null) { this.startTime = LocalDateTime.now(); this.startTimeString = fileContentTimeFormatter.format(this.startTime); @@ -332,7 +332,7 @@ private class TimeMeasurementEntry { private Long millis; @Expose - private final String key; + private final ParserTestTimeMeasurementKey key; @Expose private final ITimeMeasurementTag tag; @@ -341,13 +341,13 @@ private class TimeMeasurementEntry { * measurement. The start and end times of this time measurement * are provided indirectly through this parameter, as it may be * necessary to pause and resume this time measurement. - * @param key The key of the time measurement, which describes its purpose - * further + * @param key Keys associated with the time measurement, which describe what + * was measured * @param tag The tag of the time measurement, which can be used for a * high-level grouping of time measurements based on what they are * taken from */ - private TimeMeasurementEntry(StopWatch watch, String key, ITimeMeasurementTag tag) { + private TimeMeasurementEntry(StopWatch watch, ParserTestTimeMeasurementKey key, ITimeMeasurementTag tag) { this.watch = watch; this.tag = tag; this.key = key; @@ -357,7 +357,8 @@ public Long getMillis() { return millis; } - public String getKey() { + @SuppressWarnings("unused") + public ParserTestTimeMeasurementKey getKey() { return key; } @@ -365,6 +366,7 @@ public ITimeMeasurementTag getTag() { return tag; } + @SuppressWarnings("unused") public StopWatch getWatch() { return watch; } From 2b3f48796195c348d3bde1fc29eaa8749df1baaa Mon Sep 17 00:00:00 2001 From: AlpTorac Date: Mon, 11 Aug 2025 20:08:07 +0200 Subject: [PATCH 41/72] Fix exclusion patterns in model parsing strategies Exclusion patterns of the underlying parsing mechanisms should now be updated after each modification --- .../AbstractResourceParsingStrategy.java | 21 +++++++++++++++++++ .../jamopp/JaMoPPResourceParsingStrategy.java | 14 +++++++++++++ 2 files changed, 35 insertions(+) diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/eobject/AbstractResourceParsingStrategy.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/eobject/AbstractResourceParsingStrategy.java index eb58c1f8bd..2175dea906 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/eobject/AbstractResourceParsingStrategy.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/eobject/AbstractResourceParsingStrategy.java @@ -58,6 +58,7 @@ public ResourceSet getResourceSet() { */ public void addExclusionPattern(String pattern) { this.exclusionPatterns.add(pattern); + this.exclusionPatternsChanged(); } /** @@ -69,6 +70,7 @@ public void addExclusionPattern(String pattern) { */ public void removeExclusionPattern(String pattern) { this.exclusionPatterns.remove(pattern); + this.exclusionPatternsChanged(); } /** @@ -76,8 +78,27 @@ public void removeExclusionPattern(String pattern) { */ public void clearExclusionPatterns() { this.exclusionPatterns.clear(); + this.exclusionPatternsChanged(); } + /** + * Modifications on the return value will not affect this class. + * + * @return All exclusion patterns of this instance. + */ + public Set getExclusionPatterns() { + return new HashSet(this.exclusionPatterns); + } + + /** + * Performs any implementation-specific operations needed to adapt the + * underlying model parsing mechanisms.
+ *
+ * This method should be called by each method, which modifies the exclusion + * patterns stored in this instance. + */ + protected abstract void exclusionPatternsChanged(); + /** * Parses a ResourceSet for the model at given path. * diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/JaMoPPResourceParsingStrategy.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/JaMoPPResourceParsingStrategy.java index 2bfd5b528d..f7d94818fd 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/JaMoPPResourceParsingStrategy.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/JaMoPPResourceParsingStrategy.java @@ -89,4 +89,18 @@ public void performTrivialRecovery() { public void performTrivialRecovery(ResourceSet resourceSet) { new TrivialRecovery(resourceSet).recover(); } + + @Override + protected void exclusionPatternsChanged() { + var exclusionPatternSet = this.getExclusionPatterns(); + String[] exclusionPatterns = null; + + if (exclusionPatternSet == null || exclusionPatternSet.isEmpty()) { + exclusionPatterns = new String[] {}; + } else { + exclusionPatterns = exclusionPatternSet.toArray(String[]::new); + } + + this.getParser().setExclusionPatterns(exclusionPatterns); + } } From f304cc25856ad2a65b3322b31df0725b4ead7f72 Mon Sep 17 00:00:00 2001 From: AlpTorac Date: Mon, 11 Aug 2025 20:12:39 +0200 Subject: [PATCH 42/72] Fix DiffFilter.splitLines Now it should actually be compatible with LINUX --- .../fitests/repositorytests/util/difffilter/DiffFilter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/difffilter/DiffFilter.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/difffilter/DiffFilter.java index 1cd0d2b4ae..3bc9c70de8 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/difffilter/DiffFilter.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/difffilter/DiffFilter.java @@ -87,7 +87,7 @@ public List splitLines(String text) { // Do not use System.lineSeparator since GIT uses UNIX terminal // UNIX terminal uses "\n" for new line - var diffLines = text.split(lineSeparator); + var diffLines = text.split("\\r?\\n"); for (var l : diffLines) { lines.add(l); From 7f02ba430794fae78878d8757df1be4ba001f609 Mon Sep 17 00:00:00 2001 From: AlpTorac Date: Mon, 11 Aug 2025 20:18:39 +0200 Subject: [PATCH 43/72] Disable deleting cloned repositories as default The concrete test classes override the corresponding option method and still delete the cloned repositories --- .../repositorytests/AbstractJaMoPPParserRepoTest.java | 2 +- .../consistency/fitests/repositorytests/CWARepoTest.java | 7 +++++++ .../fitests/repositorytests/TeammatesRepoTest.java | 7 +++++++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/AbstractJaMoPPParserRepoTest.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/AbstractJaMoPPParserRepoTest.java index 9a81b2cd21..533cfe2f1a 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/AbstractJaMoPPParserRepoTest.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/AbstractJaMoPPParserRepoTest.java @@ -560,7 +560,7 @@ protected RepoParserTestOptions initResourceTestOptions() { opts.copyOptionsFrom(superOpts); - opts.setShouldDeleteRepositoryClones(true); + opts.setShouldDeleteRepositoryClones(false); opts.setShouldSaveCachedExpectedSimilarityResults(true); opts.setShouldUseCachedExpectedSimilarityResults(true); return opts; diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/CWARepoTest.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/CWARepoTest.java index 85510a5467..05c8bdf11c 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/CWARepoTest.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/CWARepoTest.java @@ -50,4 +50,11 @@ protected Collection getTestFactories res.forEach((tf) -> tf.setExpectedSimilarityResultProvider(getExpectedSimilarityResultProviderForCommits())); return res; } + + @Override + protected RepoParserTestOptions initResourceTestOptions() { + var opts = super.initResourceTestOptions(); + opts.setShouldDeleteRepositoryClones(true); + return opts; + } } diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/TeammatesRepoTest.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/TeammatesRepoTest.java index 7af4f3f9a9..9a096b26ba 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/TeammatesRepoTest.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/TeammatesRepoTest.java @@ -44,4 +44,11 @@ protected Collection getTestFactories res.forEach((tf) -> tf.setExpectedSimilarityResultProvider(getExpectedSimilarityResultProviderForCommits())); return res; } + + @Override + protected RepoParserTestOptions initResourceTestOptions() { + var opts = super.initResourceTestOptions(); + opts.setShouldDeleteRepositoryClones(true); + return opts; + } } From e0df1d2a9c3e17cbce7da6031de5734604bfe894 Mon Sep 17 00:00:00 2001 From: AlpTorac Date: Mon, 25 Aug 2025 14:32:39 +0200 Subject: [PATCH 44/72] Rename method --- .../fitests/similarity/ISimilarityCheckerContainer.java | 8 ++++---- .../jamopp/JaMoPPSimilarityCheckerContainer.java | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/ISimilarityCheckerContainer.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/ISimilarityCheckerContainer.java index a9ccffab2c..fb0b5b61bd 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/ISimilarityCheckerContainer.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/ISimilarityCheckerContainer.java @@ -12,7 +12,7 @@ * re-usability.
*
* The underlying similarity checking mechanism(s) can be reset by using the - * {@link #newSimilarityChecker()} method. The similarity checking mechanism(s) + * {@link #resetSimilarityChecker()} method. The similarity checking mechanism(s) * are not automatically re-created upon calling similarity checking methods in * this interface, because it might be desirable to keep using them. * @@ -28,18 +28,18 @@ public interface ISimilarityCheckerContainer { * calling similarity checking methods, because it might be desirable to keep * using the existing similarity checking mechanism(s). */ - public void newSimilarityChecker(); + public void resetSimilarityChecker(); /** * Delegates similarity checking to the similarity checking mechanism(s) within. - * Calls {@link #newSimilarityChecker()} beforehand, if there are no similarity + * Calls {@link #resetSimilarityChecker()} beforehand, if there are no similarity * checking mechanism(s) present. */ public Boolean isSimilar(Object element1, Object element2); /** * Delegates similarity checking to the similarity checking mechanism(s) within. - * Calls {@link #newSimilarityChecker()} beforehand, if there are no similarity + * Calls {@link #resetSimilarityChecker()} beforehand, if there are no similarity * checking mechanism(s) present. */ public Boolean areSimilar(Collection elements1, Collection elements2); diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/JaMoPPSimilarityCheckerContainer.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/JaMoPPSimilarityCheckerContainer.java index 32e108f755..0445c30a27 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/JaMoPPSimilarityCheckerContainer.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/JaMoPPSimilarityCheckerContainer.java @@ -19,13 +19,13 @@ public class JaMoPPSimilarityCheckerContainer implements ISimilarityCheckerConta private SimilarityChecker getSimilarityChecker() { if (this.sc == null) { - this.newSimilarityChecker(); + this.resetSimilarityChecker(); } return this.sc; } @Override - public void newSimilarityChecker() { + public void resetSimilarityChecker() { this.sc = new SimilarityChecker(); } From 70dd1459d35c907a4cf2302745a5610e3a0651b2 Mon Sep 17 00:00:00 2001 From: AlpTorac Date: Mon, 25 Aug 2025 14:33:40 +0200 Subject: [PATCH 45/72] Edit commentary --- .../similarity/AbstractSimilarityTest.java | 6 +-- .../parser/JaMoPPModelResourceWrapper.java | 42 ++++++++++++------- 2 files changed, 27 insertions(+), 21 deletions(-) diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/AbstractSimilarityTest.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/AbstractSimilarityTest.java index e07e4bd951..51c4e71634 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/AbstractSimilarityTest.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/AbstractSimilarityTest.java @@ -30,9 +30,6 @@ public abstract class AbstractSimilarityTest implements ILoggable { * {@link ISimilarityCheckerContainer}, which will be used for * {@link #isSimilar(Object, Object)} and * {@link #areSimilar(Collection, Collection)}. - * - * @param info An object that contains information about the current test to be - * run (ex: the test method instance, test class, ...) */ @BeforeEach public void setUp() { @@ -116,8 +113,7 @@ public Boolean areSimilar(Collection elements1, Collection elements2) { } /** - * @return The prefix of the {@link Resource} file names created from within the - * current test class. Defaults to the name of the current test class. + * @return The name of the currently running test class. */ public String getCurrentTestClassName() { return this.getClass().getSimpleName(); diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/JaMoPPModelResourceWrapper.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/JaMoPPModelResourceWrapper.java index 186a14cb6e..3f752a5f83 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/JaMoPPModelResourceWrapper.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/JaMoPPModelResourceWrapper.java @@ -111,23 +111,31 @@ protected URI getArtificialResourceURI(URI correspondingResourceURI) { } /** - * Creates and prepares the ArtificialResource of the given model resource, - * under the same ResourceSet (i.e. the ResourceSet of the given model - * resource). The created ArtificialResource will contain synthetic model - * elements for the proxy objects within the given model resource, as well as - * the native Java library resources that are needed by the given model - * resource.
+ * Creates and prepares an ArtificialResource for modelResourceSet, according to + * {@link JaMoPPResourceParsingStrategy#performTrivialRecovery(ResourceSet)}. + * The created ArtificialResource will contain synthetic model elements for the + * proxy objects within directModelResources, as well as the native Java library + * resources that are needed by modelResourceSet.
*
- * Separating said model elements from the model resource allows its actual - * contents (i.e. the code that is directly present in the model files) to be - * compared more efficiently, by excluding the imported dependencies, which are - * the same for each model resource. + * If {@link #isSplitArtificialResource()}, moves all non-direct model resources + * (i.e. model resources that are not a part of directModelResources), into the + * created ArtificialResource. This way, direct model elements inside + * directModelResources can be compared more efficiently, since the non-direct + * model resources will likely be excluded from the comparison. * - * @param modelResource The model resource, for which an - * ArtificialResource should be created + * @param modelResourceSet The model resource set that was the result of + * parsing a model. An ArtificialResource will be + * created for this ResourceSet, within this + * ResourceSet. + * @param directModelResources A list of model resources, which were directly + * parsed from the contents of the model source + * files. This list should not include any + * dependency, which is not a direct part of the + * model (such as Java native libraries). * @param artificialResourceURI The URI, which the created ArtificialResource - * will have - * @return The created ArtificialResource + * will have. ArtificialResource will be saved at + * that URI, if desired. + * @return The created ArtificialResource for modelResourceSet */ protected Resource prepareArtificialResource(ResourceSet modelResourceSet, List directModelResources, URI artificialResourceURI) { @@ -404,7 +412,8 @@ public boolean modelResourceExists() { /** * @return Whether all proxies should be resolved after a model is parsed inside - * {@link #parseModelResource(Path, URI)}. Set to false by default. + * {@link #parseModelResource(Path, URI)}. Set to false by default, can + * be changed via {@link #setResolveAllProxies(boolean)}. */ public boolean isResolveAllProxies() { return resolveAllProxies; @@ -420,7 +429,8 @@ public void setResolveAllProxies(boolean resolveAllProxies) { /** * @return Whether the synthetic contents, which were created while parsing the * model, should be split into a separate Resource. Set to false by - * default. + * default, can be changed via + * {@link #setSplitArtificialResource(boolean)}. * @see {@link JaMoPPResourceParsingStrategy#performTrivialRecovery()} */ public boolean isSplitArtificialResource() { From 9f4e9ec53cbef1eb895736b9e554f98cff38e750 Mon Sep 17 00:00:00 2001 From: AlpTorac Date: Mon, 25 Aug 2025 14:48:53 +0200 Subject: [PATCH 46/72] Add missing condition to local repository clone removal --- .../repositorytests/AbstractJaMoPPParserRepoTest.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/AbstractJaMoPPParserRepoTest.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/AbstractJaMoPPParserRepoTest.java index 533cfe2f1a..0dd9ebf907 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/AbstractJaMoPPParserRepoTest.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/AbstractJaMoPPParserRepoTest.java @@ -164,9 +164,10 @@ public void tearDown() { this.stopTimeMeasurement(); } - if (this.getResourceTestOptions().shouldDeleteRepositoryClones()) { + var localRepoPath = this.getTestFileLayout().getModelSourceFileRootDirPath(); + if (this.getResourceTestOptions().shouldDeleteRepositoryClones() && localRepoPath.toFile().exists()) { this.startTimeMeasurement(RepoTimeMeasurementTag.DELETE_LOCAL_REPO_CLONE); - this.getFileUtil().deleteAll(this.getTestFileLayout().getModelSourceFileRootDirPath()); + this.getFileUtil().deleteAll(localRepoPath); this.stopTimeMeasurement(); } From d0474e4e40dbe033c5507d3ad01c91ff5ae06286 Mon Sep 17 00:00:00 2001 From: AlpTorac Date: Mon, 25 Aug 2025 15:39:58 +0200 Subject: [PATCH 47/72] Move logging to utility class Remove ILoggable --- .../AbstractJaMoPPParserRepoTest.java | 99 +++++++++++-------- .../similarity/AbstractSimilarityTest.java | 4 +- ...oggable.java => SimilarityTestLogger.java} | 36 ++++--- .../eobject/AbstractResourceHelper.java | 20 ++-- .../AbstractJaMoPPParserSimilarityTest.java | 56 ++++++----- .../similarity/jamopp/parser/FileUtil.java | 18 ++-- .../parser/JaMoPPModelResourceWrapper.java | 87 ++++++++-------- 7 files changed, 183 insertions(+), 137 deletions(-) rename commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/{ILoggable.java => SimilarityTestLogger.java} (60%) diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/AbstractJaMoPPParserRepoTest.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/AbstractJaMoPPParserRepoTest.java index 0dd9ebf907..231b253111 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/AbstractJaMoPPParserRepoTest.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/AbstractJaMoPPParserRepoTest.java @@ -3,6 +3,7 @@ import cipm.consistency.fitests.repositorytests.util.RepoCacheSimilarityResultProvider; import cipm.consistency.fitests.repositorytests.util.RepoTestResultCache; import cipm.consistency.fitests.repositorytests.util.RepoTestSimilarityValueEstimator; +import cipm.consistency.fitests.similarity.SimilarityTestLogger; import cipm.consistency.fitests.similarity.jamopp.JaMoPPResourceParsingStrategy; import cipm.consistency.fitests.similarity.jamopp.parser.AbstractJaMoPPParserSimilarityTest; import cipm.consistency.fitests.similarity.jamopp.parser.GeneralTimeMeasurementTag; @@ -98,23 +99,28 @@ public void setUp() { var resultCachePath = this.getTestFileLayout().getExpectedSimilarityResultCachePath(); if (this.getResourceTestOptions().shouldUseCachedExpectedSimilarityResults()) { this.startTimeMeasurement(RepoTimeMeasurementTag.LOAD_EXPECTED_SIMILARITY_RESULTS); - this.logDebugMsg(String.format("Checking for cached expected similarity results for %s at %s", - this.getCurrentTestClassName(), resultCachePath)); + SimilarityTestLogger + .logDebugMsg(String.format("Checking for cached expected similarity results for %s at %s", + this.getCurrentTestClassName(), resultCachePath), this.getClass()); if (resultCachePath.toFile().exists()) { - this.logDebugMsg(String.format("Cached expected similarity results exist")); + SimilarityTestLogger.logDebugMsg(String.format("Cached expected similarity results exist"), + this.getClass()); try (BufferedReader reader = Files.newBufferedReader(resultCachePath)) { - this.logDebugMsg(String.format("Reading cached expected similarity results")); + SimilarityTestLogger.logDebugMsg(String.format("Reading cached expected similarity results"), + this.getClass()); resultCache = new RepoTestResultCache(new Gson().fromJson(reader, resultCache.getClass())); - this.logDebugMsg(String.format("Read cached expected similarity results")); + SimilarityTestLogger.logDebugMsg(String.format("Read cached expected similarity results"), + this.getClass()); } catch (IOException e) { - this.logDebugMsg(String.format("Could not read cached expected similarity results for %s at %s", - this.getCurrentTestClassName(), resultCachePath)); + SimilarityTestLogger + .logDebugMsg(String.format("Could not read cached expected similarity results for %s at %s", + this.getCurrentTestClassName(), resultCachePath), this.getClass()); } } this.stopTimeMeasurement(); } else { - this.logDebugMsg(String.format("No saved expected similarity results found for %s at %s", - this.getCurrentTestClassName(), resultCachePath)); + SimilarityTestLogger.logDebugMsg(String.format("No saved expected similarity results found for %s at %s", + this.getCurrentTestClassName(), resultCachePath), this.getClass()); } this.stopTimeMeasurement(); } @@ -136,8 +142,8 @@ public void tearDown() { var resultCachePath = this.getTestFileLayout().getExpectedSimilarityResultCachePath(); var resultCacheFile = resultCachePath.toFile(); - this.logDebugMsg(String.format("Saving cached expected similarity results for %s at %s", - this.getCurrentTestClassName(), resultCachePath)); + SimilarityTestLogger.logDebugMsg(String.format("Saving cached expected similarity results for %s at %s", + this.getCurrentTestClassName(), resultCachePath), this.getClass()); // Re-write expected similarity results @@ -159,8 +165,8 @@ public void tearDown() { e); } - this.logDebugMsg(String.format("Saved cached expected similarity results for %s at %s", - this.getCurrentTestClassName(), resultCachePath)); + SimilarityTestLogger.logDebugMsg(String.format("Saved cached expected similarity results for %s at %s", + this.getCurrentTestClassName(), resultCachePath), this.getClass()); this.stopTimeMeasurement(); } @@ -233,8 +239,9 @@ protected Collection cacheCommitResources() { var commitID1 = commitIDList.get(idxs[0]); var commitID2 = commitIDList.get(idxs[1]); if (resultCache.getResult(commitID1, commitID2) == null) { - this.logDebugMsg( - String.format("Expected similarity result missing for: %s vs %s", commitID1, commitID2)); + SimilarityTestLogger.logDebugMsg( + String.format("Expected similarity result missing for: %s vs %s", commitID1, commitID2), + this.getClass()); expectedResultsExist[0] = false; // Check for the other ones as well, for debugging purposes } @@ -243,7 +250,7 @@ protected Collection cacheCommitResources() { for (var cID : commitIDList) { if (!this.getResourceHelper() .resourceFileExists(this.getTestFileLayout().getModelResourceSaveURIForCommit(cID))) { - this.logDebugMsg(String.format("Model resource missing for: %s", cID)); + SimilarityTestLogger.logDebugMsg(String.format("Model resource missing for: %s", cID), this.getClass()); commitResourcesExist = false; // Check for the other ones as well, for debugging purposes } @@ -252,24 +259,27 @@ protected Collection cacheCommitResources() { Git git = null; if (!expectedResultsExist[0] || !commitResourcesExist) { - this.logDebugMsg("Remote repository must be cloned due to missing resources / expected similarity results"); + SimilarityTestLogger.logDebugMsg( + "Remote repository must be cloned due to missing resources / expected similarity results", + this.getClass()); git = this.cloneRepo(); } if (!expectedResultsExist[0]) { - this.logDebugMsg(String.format("Computing missing expected similarity results")); + SimilarityTestLogger.logDebugMsg(String.format("Computing missing expected similarity results"), + this.getClass()); this.computeExpectedSimilarityResults(git, commitIDList); - this.logDebugMsg(String.format("Computed missing similarity results")); + SimilarityTestLogger.logDebugMsg(String.format("Computed missing similarity results"), this.getClass()); } if (!commitResourcesExist) { - this.logDebugMsg(String.format("Preparing missing model resources")); + SimilarityTestLogger.logDebugMsg(String.format("Preparing missing model resources"), this.getClass()); commitResources.addAll(this.prepareReposForCommits(commitIDList, git)); - this.logDebugMsg(String.format("Prepared missing model resources")); + SimilarityTestLogger.logDebugMsg(String.format("Prepared missing model resources"), this.getClass()); } else { for (var cID : commitIDList) { var cachedCommitURI = this.getTestFileLayout().getModelResourceSaveURIForCommit(cID); @@ -285,28 +295,29 @@ protected Collection cacheCommitResources() { } if (git != null) { - this.logDebugMsg("Closing repository wrapper"); + SimilarityTestLogger.logDebugMsg("Closing repository wrapper", this.getClass()); this.startTimeMeasurement(RepoTimeMeasurementTag.CLOSE_REPOSITORY); git.getRepository().close(); git.close(); this.stopTimeMeasurement(); - this.logDebugMsg(String.format("Closed repository wrapper")); + SimilarityTestLogger.logDebugMsg(String.format("Closed repository wrapper"), this.getClass()); } var mainLocalClonePath = this.getTestFileLayout().getModelSourceFileRootDirPath(); - this.logDebugMsg( - String.format("Cleaning main local repository clone under: %s", mainLocalClonePath.toString())); + SimilarityTestLogger.logDebugMsg( + String.format("Cleaning main local repository clone under: %s", mainLocalClonePath.toString()), + this.getClass()); this.startTimeMeasurement(RepoTimeMeasurementTag.DELETE_LOCAL_REPO_CLONE); this.getFileUtil().deleteAll(mainLocalClonePath); this.stopTimeMeasurement(); - this.logDebugMsg("Cleaned main local repository clone"); + SimilarityTestLogger.logDebugMsg("Cleaned main local repository clone", this.getClass()); - this.logDebugMsg(String.format("Repository model resources are cached")); + SimilarityTestLogger.logDebugMsg(String.format("Repository model resources are cached"), this.getClass()); return commitResources; } @@ -330,8 +341,9 @@ protected void computeExpectedSimilarityResults(Git git, List commitIDLi var commitID1 = commitIDList.get(idxs[0]); var commitID2 = commitIDList.get(idxs[1]); if (resultCache.getResult(commitID1, commitID2) == null) { - this.logDebugMsg( - String.format("Computing expected similarity result for: %s vs %s", commitID1, commitID2)); + SimilarityTestLogger.logDebugMsg( + String.format("Computing expected similarity result for: %s vs %s", commitID1, commitID2), + this.getClass()); this.startTimeMeasurement( this.createTimeMeasurementKey().withLeftCommitID(commitID1).withRightCommitID(commitID2), GeneralTimeMeasurementTag.EXPECTED_SIMILARITY_RESULT_COMPUTATION); @@ -340,8 +352,8 @@ protected void computeExpectedSimilarityResults(Git git, List commitIDLi resultCache.addResult(commitID1, commitID2, result); this.stopTimeMeasurement(); - this.logDebugMsg(String.format("Computed expected similarity result (%s) for: %s vs %s", result, - commitID1, commitID2)); + SimilarityTestLogger.logDebugMsg(String.format("Computed expected similarity result (%s) for: %s vs %s", + result, commitID1, commitID2), this.getClass()); } })); } @@ -365,11 +377,12 @@ protected Git cloneRepo(String repoToCloneURI, Path clonePath) { if (!clonePath.toFile().exists() || clonePath.toFile().list() == null || clonePath.toFile().list().length == 0) { try { - this.logDebugMsg( - String.format("Cloning remote repository (%s) to: %s", repoToCloneURI, clonePath.toString())); + SimilarityTestLogger.logDebugMsg( + String.format("Cloning remote repository (%s) to: %s", repoToCloneURI, clonePath.toString()), + this.getClass()); git = Git.cloneRepository().setURI(repoToCloneURI).setDirectory(clonePath.toFile()) .setCloneAllBranches(true).call(); - this.logDebugMsg(String.format("Cloning successful")); + SimilarityTestLogger.logDebugMsg(String.format("Cloning successful"), this.getClass()); } catch (GitAPIException e) { e.printStackTrace(); Assertions.fail("Could not clone repository"); @@ -382,7 +395,8 @@ protected Git cloneRepo(String repoToCloneURI, Path clonePath) { git = Git.open(clonePath.toFile()); } catch (IOException e) { // Faulty repository clone, delete and re-try - this.logDebugMsg("Could not open existing repository, deleting it and re-cloning"); + SimilarityTestLogger.logDebugMsg("Could not open existing repository, deleting it and re-cloning", + this.getClass()); this.getFileUtil().deleteAll(clonePath); if (clonePath.toFile().exists() && clonePath.toFile().list().length != 0) { throw new IllegalStateException("Could not delete faulty repository clone"); @@ -433,27 +447,28 @@ protected Collection prepareReposForCommits(List commits, Git // Checkout and copy local repository clone for each // commit except the last one. For the last one, just checkout to that commit to // spare 1 copy operation - this.logDebugMsg("Caching model resources for commits"); + SimilarityTestLogger.logDebugMsg("Caching model resources for commits", this.getClass()); var commitCount = commits.size(); for (int i = 0; i < commitCount; i++) { var commitID = commits.get(i); var commitResURI = this.getTestFileLayout().getModelResourceSaveURIForCommit(commitID); - this.logDebugMsg(String.format("Checking out: %s", commitID)); + SimilarityTestLogger.logDebugMsg(String.format("Checking out: %s", commitID), this.getClass()); this.startTimeMeasurement(this.createTimeMeasurementKey().withCommitID(commitID), RepoTimeMeasurementTag.CHECKOUT_TO_COMMIT); try { git.checkout().setName(commitID).call(); } catch (GitAPIException e) { - this.logDebugMsg(String.format("Error while checking out: %s", commitID)); + SimilarityTestLogger.logDebugMsg(String.format("Error while checking out: %s", commitID), + this.getClass()); throw new IllegalArgumentException(e); } this.stopTimeMeasurement(); - this.logDebugMsg(String.format("Checked out: %s", commitID)); + SimilarityTestLogger.logDebugMsg(String.format("Checked out: %s", commitID), this.getClass()); - this.logDebugMsg(String.format("Caching resource for: %s", commitID)); + SimilarityTestLogger.logDebugMsg(String.format("Caching resource for: %s", commitID), this.getClass()); var targetPath = this.getTestFileLayout().getRepoClonePathForCommit(commitID); IModelResourceWrapper commitRes = null; @@ -472,9 +487,9 @@ protected Collection prepareReposForCommits(List commits, Git } commitResources.add(commitRes.getModelResource()); - this.logDebugMsg(String.format("Cached resource for: %s", commitID)); + SimilarityTestLogger.logDebugMsg(String.format("Cached resource for: %s", commitID), this.getClass()); } - this.logDebugMsg(String.format("Prepared model resources for commits")); + SimilarityTestLogger.logDebugMsg(String.format("Prepared model resources for commits"), this.getClass()); return commitResources; } diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/AbstractSimilarityTest.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/AbstractSimilarityTest.java index 51c4e71634..a2d31a2d46 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/AbstractSimilarityTest.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/AbstractSimilarityTest.java @@ -13,7 +13,7 @@ * * @author Alp Torac Genc */ -public abstract class AbstractSimilarityTest implements ILoggable { +public abstract class AbstractSimilarityTest { /** * @see {@link #getSCC()} */ @@ -33,7 +33,7 @@ public abstract class AbstractSimilarityTest implements ILoggable { */ @BeforeEach public void setUp() { - ILoggable.setUpLogger(); + SimilarityTestLogger.setUpLogger(); this.setSCC(this.initSCC()); } diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/ILoggable.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/SimilarityTestLogger.java similarity index 60% rename from commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/ILoggable.java rename to commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/SimilarityTestLogger.java index 097bd3a9ec..adeaa3ee1b 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/ILoggable.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/SimilarityTestLogger.java @@ -6,13 +6,17 @@ import org.apache.log4j.PatternLayout; /** - * An interface that encapsulates logging.
+ * A utility class that encapsulates logging.
*
- * Make sure to call {@link ILoggable#setUpLogger()} prior to other methods. + * Make sure to call {@link SimilarityTestLogger#setUpLogger()} prior to other + * methods. * * @author Alp Torac Genc */ -public interface ILoggable { +public class SimilarityTestLogger { + private final static String cipmRootLoggerName = "cipm"; + private final static String cipmLoggerNamePrefix = cipmRootLoggerName + "."; + /** * @return The Logger with the given name */ @@ -20,6 +24,10 @@ private static Logger getLoggerFor(String loggerName) { return Logger.getLogger(loggerName); } + private static Logger getLoggerFor(Class cls) { + return getLoggerFor(cipmLoggerNamePrefix + cls.getSimpleName()); + } + /** * Sets up all loggers that have the {@code "cipm"} prefix in their name. */ @@ -30,7 +38,7 @@ public static void setUpLogger() { * OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL */ - Logger logger = getLoggerFor("cipm"); + Logger logger = getLoggerFor(cipmRootLoggerName); logger.setLevel(Level.DEBUG); // logger = Logger.getLogger("jamopp"); @@ -49,33 +57,29 @@ public static void setUpLogger() { /** * Logs the given message at {@link Level#DEBUG} level. */ - public default void logDebugMsg(String msg) { - var logger = getLoggerFor("cipm." + this.getClass().getSimpleName()); - logger.debug(msg); + public static void logDebugMsg(String msg, Class cls) { + getLoggerFor(cls).debug(msg); } /** * Logs the given message at {@link Level#INFO} level. */ - public default void logInfoMsg(String msg) { - var logger = getLoggerFor("cipm." + this.getClass().getSimpleName()); - logger.info(msg); + public static void logInfoMsg(String msg, Class cls) { + getLoggerFor(cls).info(msg); } /** * Logs the given message at {@link Level#ERROR} level. */ - public default void logErrorMsg(String msg) { - var logger = getLoggerFor("cipm." + this.getClass().getSimpleName()); - logger.error(msg); + public static void logErrorMsg(String msg, Class cls) { + getLoggerFor(cls).error(msg); } /** * Logs the given message at the {@link Level} that corresponds to the given * priority. */ - public default void logMsg(String msg, int priority) { - var logger = getLoggerFor("cipm." + this.getClass().getSimpleName()); - logger.log(Level.toLevel(priority), msg); + public static void logMsg(String msg, int priority, Class cls) { + getLoggerFor(cls).log(Level.toLevel(priority), msg); } } diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/eobject/AbstractResourceHelper.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/eobject/AbstractResourceHelper.java index 37ea30a82b..65381dfefb 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/eobject/AbstractResourceHelper.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/eobject/AbstractResourceHelper.java @@ -11,7 +11,7 @@ import org.eclipse.emf.ecore.resource.ResourceSet; import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl; -import cipm.consistency.fitests.similarity.ILoggable; +import cipm.consistency.fitests.similarity.SimilarityTestLogger; /** * An abstract class that is meant to be implemented by classes, which @@ -19,7 +19,7 @@ * * @author Alp Torac Genc */ -public abstract class AbstractResourceHelper implements ILoggable { +public abstract class AbstractResourceHelper { /** * The extension of {@link Resource} files, if they are saved. */ @@ -92,7 +92,8 @@ public Resource createResource(Collection eos, ResourceSet rS * it to the second one. */ if (eo.eResource() != null) { - this.logErrorMsg("An EObject's resource was set and shifted during resource creation"); + SimilarityTestLogger.logErrorMsg( + "An EObject's resource was set and shifted during resource creation", this.getClass()); } res.getContents().add(eo); } @@ -149,12 +150,13 @@ public boolean saveResourceIfNotSaved(Resource res) { */ public void loadResource(Resource res) { try { - this.logDebugMsg(String.format("Loading resource at: %s", res.getURI())); + SimilarityTestLogger.logDebugMsg(String.format("Loading resource at: %s", res.getURI()), this.getClass()); res.load(null); - this.logDebugMsg(String.format("Loaded %s", res.getURI())); + SimilarityTestLogger.logDebugMsg(String.format("Loaded %s", res.getURI()), this.getClass()); } catch (IOException e) { e.printStackTrace(); - this.logInfoMsg(String.format("Could not load resource at: %s", res.getURI())); + SimilarityTestLogger.logInfoMsg(String.format("Could not load resource at: %s", res.getURI()), + this.getClass()); } } @@ -228,8 +230,10 @@ public boolean deleteResource(Resource res) { return !this.resourceFileExists(uri); } catch (IOException e) { var isResourceDeleted = !this.resourceFileExists(uri); - this.logInfoMsg(String.format("Could not delete resource as expected: %s (is deleted: %s) %s %s", - res.getURI().toString(), isResourceDeleted, System.lineSeparator(), e.getMessage())); + SimilarityTestLogger.logInfoMsg( + String.format("Could not delete resource as expected: %s (is deleted: %s) %s %s", + res.getURI().toString(), isResourceDeleted, System.lineSeparator(), e.getMessage()), + this.getClass()); return isResourceDeleted; } } diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/AbstractJaMoPPParserSimilarityTest.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/AbstractJaMoPPParserSimilarityTest.java index ceb6f31bc0..bfca7e7be5 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/AbstractJaMoPPParserSimilarityTest.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/AbstractJaMoPPParserSimilarityTest.java @@ -15,6 +15,7 @@ import org.junit.jupiter.api.DynamicNode; import org.junit.jupiter.api.TestFactory; +import cipm.consistency.fitests.similarity.SimilarityTestLogger; import cipm.consistency.fitests.similarity.jamopp.AbstractJaMoPPSimilarityTest; /** @@ -98,13 +99,13 @@ public void setUp() { @AfterEach @Override public void tearDown() { - this.logDebugMsg("Tearing down after parser test"); + SimilarityTestLogger.logDebugMsg("Tearing down after parser test", this.getClass()); this.startTimeMeasurement(GeneralTimeMeasurementTag.TEST_AFTEREACH); var cachedResources = resourceCache.getCachedResources(); if (this.getResourceTestOptions().shouldSaveCachedResources()) { - this.logDebugMsg("Saving all cached resources after parser test"); + SimilarityTestLogger.logDebugMsg("Saving all cached resources after parser test", this.getClass()); cachedResources.forEach((res) -> { this.startTimeMeasurement( createTimeMeasurementKey().withParsedModelLocation(res.getModelResource().getURI().toString()), @@ -112,11 +113,11 @@ public void tearDown() { res.saveResources(); this.stopTimeMeasurement(); }); - this.logDebugMsg("Saved all cached resources after parser test"); + SimilarityTestLogger.logDebugMsg("Saved all cached resources after parser test", this.getClass()); } if (this.getResourceTestOptions().shouldDeleteAllResources()) { - this.logDebugMsg("Deleting all cached resources after parser test"); + SimilarityTestLogger.logDebugMsg("Deleting all cached resources after parser test", this.getClass()); cachedResources.forEach((res) -> { this.startTimeMeasurement( createTimeMeasurementKey().withParsedModelLocation(res.getModelResource().getURI().toString()), @@ -124,9 +125,9 @@ public void tearDown() { res.deleteResources(); this.stopTimeMeasurement(); }); - this.logDebugMsg("Deleted all cached resources after parser test"); + SimilarityTestLogger.logDebugMsg("Deleted all cached resources after parser test", this.getClass()); } else if (this.getResourceTestOptions().shouldUnloadAllResources()) { - this.logDebugMsg("Unloading all cached resources after parser test"); + SimilarityTestLogger.logDebugMsg("Unloading all cached resources after parser test", this.getClass()); cachedResources.forEach((res) -> { this.startTimeMeasurement( createTimeMeasurementKey().withParsedModelLocation(res.getModelResource().getURI().toString()), @@ -134,15 +135,17 @@ public void tearDown() { res.unloadResources(); this.stopTimeMeasurement(); }); - this.logDebugMsg("Unloaded all cached resources after parser test"); + SimilarityTestLogger.logDebugMsg("Unloaded all cached resources after parser test", this.getClass()); } if (this.getResourceTestOptions().shouldRemoveResourcesFromCache()) { - this.logDebugMsg("Removing all cached resources from cache after parser test"); + SimilarityTestLogger.logDebugMsg("Removing all cached resources from cache after parser test", + this.getClass()); this.startTimeMeasurement(GeneralTimeMeasurementTag.MODEL_RESOURCE_CACHE_ACCESS); resourceCache.cleanCache(); this.stopTimeMeasurement(); - this.logDebugMsg("Removed all cached resources from cache after parser test"); + SimilarityTestLogger.logDebugMsg("Removed all cached resources from cache after parser test", + this.getClass()); } super.tearDown(); @@ -150,7 +153,7 @@ public void tearDown() { this.saveTimeMeasurements(); - this.logDebugMsg("Tore down after parser test"); + SimilarityTestLogger.logDebugMsg("Tore down after parser test", this.getClass()); } protected ParserTestFileLayout initParserTestFileLayout() { @@ -172,9 +175,9 @@ protected ParserTestFileLayout getTestFileLayout() { * {@code startTimeMeasurement} and {@code stopTimeMeasurement} calls. */ protected void saveTimeMeasurements() { - this.logDebugMsg("Saving time measurements"); + SimilarityTestLogger.logDebugMsg("Saving time measurements", this.getClass()); ParserTestTimeMeasurer.getInstance().save(this.layout.getTimeMeasurementsFileSavePath()); - this.logDebugMsg("Saved time measurements"); + SimilarityTestLogger.logDebugMsg("Saved time measurements", this.getClass()); } /** @@ -254,9 +257,8 @@ protected CacheUtil getCacheUtil() { * @see {@link #prepareArtificialResource(Resource, URI)} */ protected IModelResourceWrapper parseModelsDirWithoutCaching(Path modelDir) { - this.startTimeMeasurement( - createTimeMeasurementKey().withOriginalModelLocation(modelDir.toString()) - .withResourceParsingStrategyClassName(this.getResourceParsingStrategy().getClass().getSimpleName()), + this.startTimeMeasurement(createTimeMeasurementKey().withOriginalModelLocation(modelDir.toString()) + .withResourceParsingStrategyClassName(this.getResourceParsingStrategy().getClass().getSimpleName()), GeneralTimeMeasurementTag.PARSE_MODEL_RESOURCE); var wrapper = new JaMoPPModelResourceWrapper(this.getResourceHelper(), this.getResourceParsingStrategy()); wrapper.parseModelResource(modelDir, this.layout.getModelResourceURI(modelDir)); @@ -293,7 +295,8 @@ protected IModelResourceWrapper parseModelsDirWithCaching(Path modelDir, String */ protected IModelResourceWrapper parseModelsDirWithCaching(Path modelDir, URI cachedModelURI, String cacheKey) { this.startTimeMeasurement(createTimeMeasurementKey().withOriginalModelLocation(modelDir.toString()) - .withParsedModelLocation(cachedModelURI.toString()), GeneralTimeMeasurementTag.MODEL_RESOURCE_CACHE_ACCESS); + .withParsedModelLocation(cachedModelURI.toString()), + GeneralTimeMeasurementTag.MODEL_RESOURCE_CACHE_ACCESS); var cache = this.getCacheUtil(); var modelName = this.getDisplayNameForModelDir(modelDir); @@ -308,11 +311,14 @@ protected IModelResourceWrapper parseModelsDirWithCaching(Path modelDir, URI cac if (cacheKey != null) { // Search for the resource in the cache if (cache.isInCache(cacheKey)) { - this.logDebugMsg(String.format("%s is in cache, using cached version", modelName)); + SimilarityTestLogger.logDebugMsg(String.format("%s is in cache, using cached version", modelName), + this.getClass()); resWrapper = cache.getFromCache(cacheKey); if (!resWrapper.isModelResourceLoaded()) { - this.startTimeMeasurement(createTimeMeasurementKey().withOriginalModelLocation(modelDir.toString()) - .withParsedModelLocation(cachedModelURI.toString()), GeneralTimeMeasurementTag.LOAD_MODEL_RESOURCE); + this.startTimeMeasurement( + createTimeMeasurementKey().withOriginalModelLocation(modelDir.toString()) + .withParsedModelLocation(cachedModelURI.toString()), + GeneralTimeMeasurementTag.LOAD_MODEL_RESOURCE); resWrapper.loadParsedResources(); this.stopTimeMeasurement(); } @@ -321,12 +327,15 @@ protected IModelResourceWrapper parseModelsDirWithCaching(Path modelDir, URI cac // Search for the resource file in cache save location if (resWrapper == null) { resWrapper = new JaMoPPModelResourceWrapper(this.getResourceHelper()); - this.startTimeMeasurement(createTimeMeasurementKey().withOriginalModelLocation(modelDir.toString()) - .withParsedModelLocation(cachedModelURI.toString()), GeneralTimeMeasurementTag.LOAD_MODEL_RESOURCE); + this.startTimeMeasurement( + createTimeMeasurementKey().withOriginalModelLocation(modelDir.toString()) + .withParsedModelLocation(cachedModelURI.toString()), + GeneralTimeMeasurementTag.LOAD_MODEL_RESOURCE); resWrapper.loadModelResource(cachedModelURI); this.stopTimeMeasurement(); if (resWrapper.isModelResourceLoaded()) { - this.logDebugMsg(String.format("Loaded %s from its resource file", modelName)); + SimilarityTestLogger.logDebugMsg(String.format("Loaded %s from its resource file", modelName), + this.getClass()); } } } @@ -340,7 +349,8 @@ protected IModelResourceWrapper parseModelsDirWithCaching(Path modelDir, URI cac cache.addToCache(key, resWrapper); this.stopTimeMeasurement(); - this.logDebugMsg(String.format("%s parsed (with caching)", this.getDisplayNameForModelDir(modelDir))); + SimilarityTestLogger.logDebugMsg( + String.format("%s parsed (with caching)", this.getDisplayNameForModelDir(modelDir)), this.getClass()); return resWrapper; } diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/FileUtil.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/FileUtil.java index e1478da06a..f52ab299cd 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/FileUtil.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/FileUtil.java @@ -6,14 +6,14 @@ import java.nio.file.Path; import java.util.TreeSet; -import cipm.consistency.fitests.similarity.ILoggable; +import cipm.consistency.fitests.similarity.SimilarityTestLogger; /** * A utility class that contains file-related operations. * * @author Alp Torac Genc */ -public class FileUtil implements ILoggable { +public class FileUtil { /** * @return Whether the content of both dirs are similar. * @@ -36,7 +36,9 @@ public String readEffectiveText(File f) { try { content = Files.readString(f.toPath()); } catch (IOException e) { - this.logDebugMsg(String.format("Could not read: %s, returning empty string", f.toPath().toString())); + SimilarityTestLogger.logDebugMsg( + String.format("Could not read: %s, returning empty string", f.toPath().toString()), + this.getClass()); } return content.replaceAll("\\n", "").replaceAll("\\r", "").replaceAll("\\s", ""); @@ -69,7 +71,7 @@ public boolean filesEqual(File f1, File f2) { * @see {@link #filesEqual(File, File)}, {@link #readEffectiveText(File)} */ public boolean dirsEqual(File dir1, File dir2) { - this.logDebugMsg("Comparing: " + dir1.getName() + " and " + dir2.getName()); + SimilarityTestLogger.logDebugMsg("Comparing: " + dir1.getName() + " and " + dir2.getName(), this.getClass()); // There cannot be 2 files with the same path, name and extension // so using TreeSet, which sorts the files spares doing so here @@ -103,16 +105,18 @@ public boolean dirsEqual(File dir1, File dir2) { if (f1.isDirectory() && f2.isDirectory()) { if (!dirsEqual(f1, f2)) { - this.logDebugMsg("Directories " + f1.getName() + " and " + f2.getName() + " are not equal"); + SimilarityTestLogger.logDebugMsg( + "Directories " + f1.getName() + " and " + f2.getName() + " are not equal", this.getClass()); return false; } } else if (f1.isFile() && f2.isFile()) { if (!filesEqual(f1, f2)) { - this.logDebugMsg("Files " + f1.getName() + " and " + f2.getName() + " are not equal"); + SimilarityTestLogger.logDebugMsg( + "Files " + f1.getName() + " and " + f2.getName() + " are not equal", this.getClass()); return false; } } else { - this.logErrorMsg("Unexpected case there is a file and a directory"); + SimilarityTestLogger.logErrorMsg("Unexpected case there is a file and a directory", this.getClass()); return false; } } diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/JaMoPPModelResourceWrapper.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/JaMoPPModelResourceWrapper.java index 3f752a5f83..f5eb7f5c21 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/JaMoPPModelResourceWrapper.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/JaMoPPModelResourceWrapper.java @@ -9,7 +9,7 @@ import org.eclipse.emf.ecore.resource.ResourceSet; import org.eclipse.emf.ecore.util.EcoreUtil; -import cipm.consistency.fitests.similarity.ILoggable; +import cipm.consistency.fitests.similarity.SimilarityTestLogger; import cipm.consistency.fitests.similarity.eobject.AbstractResourceHelper; import cipm.consistency.fitests.similarity.jamopp.JaMoPPResourceParsingStrategy; @@ -29,7 +29,7 @@ * * @author Alp Torac Genc */ -public class JaMoPPModelResourceWrapper implements IModelResourceWrapper, ILoggable { +public class JaMoPPModelResourceWrapper implements IModelResourceWrapper { /** * @see {@link #isResolveAllProxies()} */ @@ -151,8 +151,8 @@ protected Resource prepareArtificialResource(ResourceSet modelResourceSet, List< if (artificialResourceForModelResSet != null) { artificialResourceForModelResSet.setURI(artificialResourceURI); - this.logDebugMsg(String.format("ArtificialResource is parsed and has its URI set to %s", - artificialResourceForModelResSet.getURI())); + SimilarityTestLogger.logDebugMsg(String.format("ArtificialResource is parsed and has its URI set to %s", + artificialResourceForModelResSet.getURI()), this.getClass()); // Use an array to avoid modifications while iterating, which lead to exceptions var resArr = modelResourceSet.getResources().toArray(Resource[]::new); @@ -169,17 +169,23 @@ protected Resource prepareArtificialResource(ResourceSet modelResourceSet, List< var r = resArr[i]; if (!r.getURI().isFile() && r != artificialResourceForModelResSet && !directModelResources.contains(r)) { - this.logDebugMsg(String.format("Adding Resource %s to ArtificialResource", r.getURI())); + SimilarityTestLogger.logDebugMsg( + String.format("Adding Resource %s to ArtificialResource", r.getURI()), this.getClass()); artificialResourceForModelResSet.getContents().addAll(r.getContents()); - this.logDebugMsg(String.format("Added Resource %s to ArtificialResource", r.getURI())); + SimilarityTestLogger.logDebugMsg( + String.format("Added Resource %s to ArtificialResource", r.getURI()), this.getClass()); modelResourceSet.getResources().remove(r); - this.logDebugMsg(String.format("Removed (empty) Resource %s from ResourceSet", r.getURI())); + SimilarityTestLogger.logDebugMsg( + String.format("Removed (empty) Resource %s from ResourceSet", r.getURI()), + this.getClass()); } } // "-2" to exclude modelResource and artificialResource from resource count - this.logDebugMsg(String.format("%d/%d resources have been added to ArtificialResource", - (resArr.length - modelResourceSet.getResources().size()) - 2, resArr.length - 2)); + SimilarityTestLogger.logDebugMsg( + String.format("%d/%d resources have been added to ArtificialResource", + (resArr.length - modelResourceSet.getResources().size()) - 2, resArr.length - 2), + this.getClass()); // Do not handle potential proxies in ArtificialResource, because they belong to // internals of native classes, which are irrelevant for the model. Normally @@ -212,7 +218,8 @@ public void parseModelResource(Path modelDir, URI modelResourceURI) { modelResourceSet = parsingStrat.parseModelResource(modelDir); var resCount = modelResourceSet.getResources().size(); - this.logDebugMsg(String.format("%d resources have been parsed under %s", resCount, modelDir)); + SimilarityTestLogger.logDebugMsg(String.format("%d resources have been parsed under %s", resCount, modelDir), + this.getClass()); // Find the model resource (i.e. the resource that contains the direct contents // of model files) @@ -249,19 +256,21 @@ public void parseModelResource(Path modelDir, URI modelResourceURI) { artificialResource = this.prepareArtificialResource(modelResourceSet, directModelResources, this.getArtificialResourceURI(modelResourceURI)); - this.logDebugMsg(String.format("Merging non-ArtificialResources")); + SimilarityTestLogger.logDebugMsg(String.format("Merging non-ArtificialResources"), this.getClass()); for (var r : modelResourceSet.getResources()) { if (r != artificialResource) { - this.logDebugMsg(String.format("Including %s into the merged resource", r.getURI())); + SimilarityTestLogger.logDebugMsg(String.format("Including %s into the merged resource", r.getURI()), + this.getClass()); mergedModelResource.getContents().addAll(r.getContents()); - this.logDebugMsg(String.format("Included %s into the merged resource", r.getURI())); + SimilarityTestLogger.logDebugMsg(String.format("Included %s into the merged resource", r.getURI()), + this.getClass()); } } - this.logDebugMsg(String.format("Merged non-ArtificialResources")); + SimilarityTestLogger.logDebugMsg(String.format("Merged non-ArtificialResources"), this.getClass()); - this.logDebugMsg(String.format("%s parsed (uncached)", modelDir)); + SimilarityTestLogger.logDebugMsg(String.format("%s parsed (uncached)", modelDir), this.getClass()); // Add ArtificialResource to mergedResource's resource set, so that it can be // found by the model resource's contents that have been moved @@ -287,16 +296,16 @@ public void loadModelResource(URI modelResourceURI) { public boolean saveResources() { var result = true; if (mergedModelResource != null) { - this.logDebugMsg("Merged model resource exists, saving it now"); + SimilarityTestLogger.logDebugMsg("Merged model resource exists, saving it now", this.getClass()); result = this.resHelper.saveResourceIfNotSaved(mergedModelResource); - this.logDebugMsg(String.format("%s merged model resource at %s", result ? "Saved" : "Could not save", - mergedModelResource.getURI())); + SimilarityTestLogger.logDebugMsg(String.format("%s merged model resource at %s", + result ? "Saved" : "Could not save", mergedModelResource.getURI()), this.getClass()); } if (artificialResource != null) { - this.logDebugMsg("Artificial resource exists, saving it now"); + SimilarityTestLogger.logDebugMsg("Artificial resource exists, saving it now", this.getClass()); result = result && this.resHelper.saveResourceIfNotSaved(artificialResource); - this.logDebugMsg(String.format("%s artificial resource at %s", result ? "Saved" : "Could not save", - artificialResource.getURI())); + SimilarityTestLogger.logDebugMsg(String.format("%s artificial resource at %s", + result ? "Saved" : "Could not save", artificialResource.getURI()), this.getClass()); } return result; } @@ -308,17 +317,17 @@ public boolean saveResources() { public boolean deleteResources() { var result = false; if (mergedModelResource != null) { - this.logDebugMsg("Merged model resource exists, deleting it now"); + SimilarityTestLogger.logDebugMsg("Merged model resource exists, deleting it now", this.getClass()); result = this.resHelper.deleteResource(mergedModelResource); - this.logDebugMsg(String.format("%s merged model resource at %s", result ? "Deleted" : "Could not delete", - mergedModelResource.getURI())); + SimilarityTestLogger.logDebugMsg(String.format("%s merged model resource at %s", + result ? "Deleted" : "Could not delete", mergedModelResource.getURI()), this.getClass()); } if (artificialResource != null) { - this.logDebugMsg("Artificial resource exists, deleting it now"); + SimilarityTestLogger.logDebugMsg("Artificial resource exists, deleting it now", this.getClass()); result = result && this.resHelper.deleteResource(artificialResource); - this.logDebugMsg(String.format("%s artificial resource at %s", result ? "Saved" : "Could not save", - artificialResource.getURI())); + SimilarityTestLogger.logDebugMsg(String.format("%s artificial resource at %s", + result ? "Saved" : "Could not save", artificialResource.getURI()), this.getClass()); } return result; } @@ -330,17 +339,17 @@ public boolean deleteResources() { public boolean unloadResources() { var result = false; if (mergedModelResource != null) { - this.logDebugMsg("Merged model resource exists, unloading it now"); + SimilarityTestLogger.logDebugMsg("Merged model resource exists, unloading it now", this.getClass()); result = this.resHelper.unloadResource(mergedModelResource); - this.logDebugMsg(String.format("%s merged model resource at %s", result ? "Unloaded" : "Could not unload", - mergedModelResource.getURI())); + SimilarityTestLogger.logDebugMsg(String.format("%s merged model resource at %s", + result ? "Unloaded" : "Could not unload", mergedModelResource.getURI()), this.getClass()); } if (artificialResource != null) { - this.logDebugMsg("Artificial resource exists, unloading it now"); + SimilarityTestLogger.logDebugMsg("Artificial resource exists, unloading it now", this.getClass()); result = result && this.resHelper.unloadResource(artificialResource); - this.logDebugMsg(String.format("%s artificial resource at %s", result ? "Unloaded" : "Could not unload", - artificialResource.getURI())); + SimilarityTestLogger.logDebugMsg(String.format("%s artificial resource at %s", + result ? "Unloaded" : "Could not unload", artificialResource.getURI()), this.getClass()); } return result; } @@ -362,17 +371,17 @@ public boolean isModelResourceLoaded() { public boolean loadParsedResources() { var result = true; if (mergedModelResource != null && !this.mergedModelResource.isLoaded()) { - this.logDebugMsg("Merged model resource exists, loading it now"); + SimilarityTestLogger.logDebugMsg("Merged model resource exists, loading it now", this.getClass()); result = this.resHelper.unloadResource(mergedModelResource); - this.logDebugMsg(String.format("%s merged model resource at %s", result ? "Loaded" : "Could not load", - mergedModelResource.getURI())); + SimilarityTestLogger.logDebugMsg(String.format("%s merged model resource at %s", + result ? "Loaded" : "Could not load", mergedModelResource.getURI()), this.getClass()); } if (artificialResource != null && !this.artificialResource.isLoaded()) { - this.logDebugMsg("Artificial resource exists, unloading it now"); + SimilarityTestLogger.logDebugMsg("Artificial resource exists, unloading it now", this.getClass()); result = result && this.resHelper.unloadResource(artificialResource); - this.logDebugMsg(String.format("%s artificial resource at %s", result ? "Loaded" : "Could not load", - artificialResource.getURI())); + SimilarityTestLogger.logDebugMsg(String.format("%s artificial resource at %s", + result ? "Loaded" : "Could not load", artificialResource.getURI()), this.getClass()); } return result; } From 5747bdc22a6e89b62a7a77578898649107d0494e Mon Sep 17 00:00:00 2001 From: AlpTorac Date: Wed, 27 Aug 2025 12:47:31 +0200 Subject: [PATCH 48/72] Implement and use utility class instead of AbstractResourceHelper Move Resource factory registry setup to resource parsing strategy --- .../AbstractJaMoPPParserRepoTest.java | 6 +- .../AbstractEObjectSimilarityTest.java | 49 +------- .../AbstractResourceParsingStrategy.java | 35 ++++++ ...esourceHelper.java => ResourceHelper.java} | 113 +++++++----------- .../jamopp/AbstractJaMoPPSimilarityTest.java | 5 - .../jamopp/JaMoPPResourceHelper.java | 42 ------- .../jamopp/JaMoPPResourceParsingStrategy.java | 39 ++++++ .../AbstractJaMoPPParserSimilarityTest.java | 6 +- .../parser/JaMoPPModelResourceWrapper.java | 38 +++--- 9 files changed, 139 insertions(+), 194 deletions(-) rename commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/eobject/{AbstractResourceHelper.java => ResourceHelper.java} (62%) delete mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/JaMoPPResourceHelper.java diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/AbstractJaMoPPParserRepoTest.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/AbstractJaMoPPParserRepoTest.java index 231b253111..c64006f553 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/AbstractJaMoPPParserRepoTest.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/AbstractJaMoPPParserRepoTest.java @@ -4,6 +4,7 @@ import cipm.consistency.fitests.repositorytests.util.RepoTestResultCache; import cipm.consistency.fitests.repositorytests.util.RepoTestSimilarityValueEstimator; import cipm.consistency.fitests.similarity.SimilarityTestLogger; +import cipm.consistency.fitests.similarity.eobject.ResourceHelper; import cipm.consistency.fitests.similarity.jamopp.JaMoPPResourceParsingStrategy; import cipm.consistency.fitests.similarity.jamopp.parser.AbstractJaMoPPParserSimilarityTest; import cipm.consistency.fitests.similarity.jamopp.parser.GeneralTimeMeasurementTag; @@ -248,8 +249,7 @@ protected Collection cacheCommitResources() { })); for (var cID : commitIDList) { - if (!this.getResourceHelper() - .resourceFileExists(this.getTestFileLayout().getModelResourceSaveURIForCommit(cID))) { + if (!ResourceHelper.resourceFileExists(this.getTestFileLayout().getModelResourceSaveURIForCommit(cID))) { SimilarityTestLogger.logDebugMsg(String.format("Model resource missing for: %s", cID), this.getClass()); commitResourcesExist = false; // Check for the other ones as well, for debugging purposes @@ -283,7 +283,7 @@ protected Collection cacheCommitResources() { } else { for (var cID : commitIDList) { var cachedCommitURI = this.getTestFileLayout().getModelResourceSaveURIForCommit(cID); - var res = new JaMoPPModelResourceWrapper(this.getResourceHelper()); + var res = new JaMoPPModelResourceWrapper(); this.startTimeMeasurement( this.createTimeMeasurementKey().withParsedModelLocation(cachedCommitURI.toString()), GeneralTimeMeasurementTag.LOAD_MODEL_RESOURCE); diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/eobject/AbstractEObjectSimilarityTest.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/eobject/AbstractEObjectSimilarityTest.java index ed18ef815e..273f6f2c31 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/eobject/AbstractEObjectSimilarityTest.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/eobject/AbstractEObjectSimilarityTest.java @@ -1,6 +1,5 @@ package cipm.consistency.fitests.similarity.eobject; -import org.eclipse.emf.ecore.resource.Resource; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; @@ -12,11 +11,6 @@ * @author Alp Torac Genc */ public abstract class AbstractEObjectSimilarityTest extends AbstractSimilarityTest { - /** - * @see {@link #getResourceHelper()} - */ - private AbstractResourceHelper resHelper; - /** * @see {@link #getResourceParsingStrategy()} */ @@ -30,17 +24,15 @@ public abstract class AbstractEObjectSimilarityTest extends AbstractSimilarityTe /** * {@inheritDoc}
*
- * {@link AbstractEObjectSimilarityTest}: Sets up Resource-related helper - * classes and options {@link AbstractResourceHelper}, - * {@link AbstractResourceParsingStrategy}, {@link ResourceTestOptions}. + * {@link AbstractEObjectSimilarityTest}: Sets up Resource parsing strategy + * {@link AbstractResourceParsingStrategy} and Resource-related test options + * {@link ResourceTestOptions}. */ @BeforeEach @Override public void setUp() { super.setUp(); - this.setResourceHelper(this.initResourceHelper()); - this.setResourceParsingStrategy(this.initResourceParsingStrategy()); this.setResourceTestOptions(this.initResourceTestOptions()); } @@ -55,29 +47,12 @@ public void setUp() { @AfterEach @Override public void tearDown() { - this.cleanUpResourceHelper(); this.cleanUpResourceParsingStrategy(); this.cleanUpResourceTestOptions(); super.tearDown(); } - /** - * The {@link AbstractResourceHelper} instance that can be used for creating - * {@link Resource} instances. - */ - protected AbstractResourceHelper getResourceHelper() { - return this.resHelper; - } - - /** - * Sets up the {@link AbstractResourceHelper} instance that will be used with - * the given one. - */ - protected void setResourceHelper(AbstractResourceHelper resHelper) { - this.resHelper = resHelper; - } - protected AbstractResourceParsingStrategy getResourceParsingStrategy() { return this.parsingStrat; } @@ -86,13 +61,6 @@ protected void setResourceParsingStrategy(AbstractResourceParsingStrategy parsin this.parsingStrat = parsingStrat; } - /** - * @return The extension of the {@link Resource} files, if they are saved. - */ - public String getResourceFileExtension() { - return this.getResourceHelper().getResourceFileExtension(); - } - protected ResourceTestOptions getResourceTestOptions() { return this.resourceTestOptions; } @@ -101,10 +69,6 @@ protected void setResourceTestOptions(ResourceTestOptions resourceTestOptions) { this.resourceTestOptions = resourceTestOptions; } - protected void cleanUpResourceHelper() { - this.resHelper = null; - } - protected void cleanUpResourceParsingStrategy() { this.parsingStrat = null; } @@ -113,13 +77,6 @@ protected void cleanUpResourceTestOptions() { this.resourceTestOptions = null; } - /** - * Override in implementors to change the default value, if needed. - * - * @return The {@link AbstractResourceHelper} that will be initially used. - */ - protected abstract AbstractResourceHelper initResourceHelper(); - protected abstract ResourceTestOptions initResourceTestOptions(); protected abstract AbstractResourceParsingStrategy initResourceParsingStrategy(); diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/eobject/AbstractResourceParsingStrategy.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/eobject/AbstractResourceParsingStrategy.java index 2175dea906..0457d10ae7 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/eobject/AbstractResourceParsingStrategy.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/eobject/AbstractResourceParsingStrategy.java @@ -4,7 +4,9 @@ import java.util.HashSet; import java.util.Set; +import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.emf.ecore.resource.ResourceSet; +import org.eclipse.emf.ecore.xmi.impl.XMIResourceFactoryImpl; /** * An abstract class meant to be extended by classes that envelop the means to @@ -32,6 +34,16 @@ public abstract class AbstractResourceParsingStrategy { */ private final Set exclusionPatterns = new HashSet<>(); + /** + * Performs any preparation necessary prior to the construction of an instance. + * Then constructs an instance. + * + * @see {@link #preConstructionSetup()} + */ + public AbstractResourceParsingStrategy() { + this.preConstructionSetup(); + } + /** * Sets the ResourceSet used from within to the given one. * @@ -99,6 +111,24 @@ public Set getExclusionPatterns() { */ protected abstract void exclusionPatternsChanged(); + /** + * Performs any necessary preparation prior to the construction of an instance + * of this class. This includes setting up the necessary + * {@link Resource.Factory.Registry} and other preparation steps, which do not + * involve the members of this class.
+ *
+ * If this method is to be overridden in the concrete implementations, it is + * recommended to check the implementation of the super method, as there could + * be conflicts.
+ *
+ * Note: This is the first step in the constructor. Therefore, there should be + * no references to class members that are initialised within the constructor, + * as that might cause NullPointerExceptions. + */ + protected void preConstructionSetup() { + ResourceHelper.setResourceRegistry("*", new XMIResourceFactoryImpl()); + } + /** * Parses a ResourceSet for the model at given path. * @@ -109,4 +139,9 @@ public Set getExclusionPatterns() { * given model path. */ public abstract ResourceSet parseModelResource(Path modelDir); + + /** + * @return The extension of the {@link Resource} files, if they are saved. + */ + public abstract String getResourceFileExtension(); } diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/eobject/AbstractResourceHelper.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/eobject/ResourceHelper.java similarity index 62% rename from commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/eobject/AbstractResourceHelper.java rename to commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/eobject/ResourceHelper.java index 65381dfefb..c6f5a3cb6a 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/eobject/AbstractResourceHelper.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/eobject/ResourceHelper.java @@ -14,56 +14,22 @@ import cipm.consistency.fitests.similarity.SimilarityTestLogger; /** - * An abstract class that is meant to be implemented by classes, which - * encapsulate basic operations on {@link Resource} instances. + * A utility class that provides basic operations on {@link Resource} instances. * * @author Alp Torac Genc */ -public abstract class AbstractResourceHelper { - /** - * The extension of {@link Resource} files, if they are saved. - */ - private String resourceFileExtension; - - /** - * Constructs an instance with the foreseen initial resource registry entries. - * - * @see {@link #setInitialResourceRegistries()} - */ - public AbstractResourceHelper() { - this.setInitialResourceRegistries(); - } - +public class ResourceHelper { /** * @return The resource registry, which will be modified by this instance. */ - private Resource.Factory.Registry getResourceRegistry() { + private static Resource.Factory.Registry getResourceRegistry() { return Resource.Factory.Registry.INSTANCE; } - /** - * Sets all resource registries foreseen for this instance. - */ - public abstract void setInitialResourceRegistries(); - - /** - * Sets the extension of {@link Resource} files, if they are saved. - */ - public void setResourceFileExtension(String resourceFileExtension) { - this.resourceFileExtension = resourceFileExtension; - } - - /** - * @return The extension of the {@link Resource} files. - */ - public String getResourceFileExtension() { - return this.resourceFileExtension; - } - /** * @return An empty {@link ResourceSetImpl} */ - public ResourceSet createResourceSet() { + public static ResourceSet createResourceSet() { return new ResourceSetImpl(); } @@ -80,7 +46,7 @@ public ResourceSet createResourceSet() { * since doing so will REMOVE the said EObject instances from their former * Resource and cause side effects in tests. */ - public Resource createResource(Collection eos, ResourceSet rSet, URI resURI) { + public static Resource createResource(Collection eos, ResourceSet rSet, URI resURI) { var res = rSet.createResource(resURI); if (eos != null) { @@ -93,7 +59,7 @@ public Resource createResource(Collection eos, ResourceSet rS */ if (eo.eResource() != null) { SimilarityTestLogger.logErrorMsg( - "An EObject's resource was set and shifted during resource creation", this.getClass()); + "An EObject's resource was set and shifted during resource creation", ResourceHelper.class); } res.getContents().add(eo); } @@ -111,52 +77,53 @@ public Resource createResource(Collection eos, ResourceSet rS * * @see {@link #setDefaultResourceRegistry()} */ - public void setResourceRegistry(String extension, Object factory) { - this.getResourceRegistry().getExtensionToFactoryMap().put(extension, factory); + public static void setResourceRegistry(String extension, Object factory) { + getResourceRegistry().getExtensionToFactoryMap().put(extension, factory); } /** * Attempts to save the given resource instance. Instead of throwing exceptions, * returns true/false to indicate success/failure. */ - public boolean saveResource(Resource res) { + public static boolean saveResource(Resource res) { var uri = res.getURI(); if (uri.isFile()) { try { res.save(null); - return this.resourceFileExists(uri); + return resourceFileExists(uri); } catch (IOException excep) { excep.printStackTrace(); - return this.resourceFileExists(uri); + return resourceFileExists(uri); } } - return this.resourceFileExists(uri); + return resourceFileExists(uri); } /** * Attempts to save the given resource instance. Instead of throwing exceptions, * returns true/false to indicate success/failure. */ - public boolean saveResourceIfNotSaved(Resource res) { + public static boolean saveResourceIfNotSaved(Resource res) { var uri = res.getURI(); - if (uri.isFile() && !this.resourceFileExists(uri)) { - return this.saveResource(res); + if (uri.isFile() && !resourceFileExists(uri)) { + return saveResource(res); } - return this.resourceFileExists(uri); + return resourceFileExists(uri); } /** * Loads the given resource */ - public void loadResource(Resource res) { + public static void loadResource(Resource res) { try { - SimilarityTestLogger.logDebugMsg(String.format("Loading resource at: %s", res.getURI()), this.getClass()); + SimilarityTestLogger.logDebugMsg(String.format("Loading resource at: %s", res.getURI()), + ResourceHelper.class); res.load(null); - SimilarityTestLogger.logDebugMsg(String.format("Loaded %s", res.getURI()), this.getClass()); + SimilarityTestLogger.logDebugMsg(String.format("Loaded %s", res.getURI()), ResourceHelper.class); } catch (IOException e) { e.printStackTrace(); SimilarityTestLogger.logInfoMsg(String.format("Could not load resource at: %s", res.getURI()), - this.getClass()); + ResourceHelper.class); } } @@ -164,12 +131,12 @@ public void loadResource(Resource res) { * @return A resource instance, which has the contents of the saved resource * file at the given URI */ - public Resource loadResource(URI resourceURI) { + public static Resource loadResource(URI resourceURI) { Resource res = null; if (resourceURI.isFile() && new File(resourceURI.toFileString()).exists()) { - res = this.createResource(resourceURI); - this.loadResource(res); + res = createResource(resourceURI); + loadResource(res); } return res; @@ -178,8 +145,8 @@ public Resource loadResource(URI resourceURI) { /** * @return The loaded resource located at the given path */ - public Resource loadResource(Path resourcePath) { - return this.loadResource(URI.createFileURI(resourcePath.toString())); + public static Resource loadResource(Path resourcePath) { + return loadResource(URI.createFileURI(resourcePath.toString())); } /** @@ -187,8 +154,8 @@ public Resource loadResource(Path resourcePath) { * @param resourceURI The URI, where the resource points at * @return An empty resource inside the given resource set, with the given URI */ - public Resource createResource(ResourceSet resSet, URI resourceURI) { - return this.createResource(null, resSet, resourceURI); + public static Resource createResource(ResourceSet resSet, URI resourceURI) { + return createResource(null, resSet, resourceURI); } /** @@ -196,14 +163,14 @@ public Resource createResource(ResourceSet resSet, URI resourceURI) { * @return An empty resource, inside a freshly created resource set, with the * given URI */ - public Resource createResource(URI resourceURI) { - return this.createResource(this.createResourceSet(), resourceURI); + public static Resource createResource(URI resourceURI) { + return createResource(createResourceSet(), resourceURI); } /** * Unloads the given {@link Resource} instance. */ - public boolean unloadResource(Resource res) { + public static boolean unloadResource(Resource res) { res.unload(); return !res.isLoaded(); } @@ -213,7 +180,7 @@ public boolean unloadResource(Resource res) { * @return Whether the resource file exists. Will return false if the given URI * does not point at a file, regardless of whether the resource exists. */ - public boolean resourceFileExists(URI resURI) { + public static boolean resourceFileExists(URI resURI) { return resURI.isFile() && new File(resURI.toFileString()).exists(); } @@ -222,33 +189,33 @@ public boolean resourceFileExists(URI resURI) { * * @return Whether the file of the given resource is deleted. */ - public boolean deleteResource(Resource res) { + public static boolean deleteResource(Resource res) { var uri = res.getURI(); - if (this.resourceFileExists(uri)) { + if (resourceFileExists(uri)) { try { res.delete(null); - return !this.resourceFileExists(uri); + return !resourceFileExists(uri); } catch (IOException e) { - var isResourceDeleted = !this.resourceFileExists(uri); + var isResourceDeleted = !resourceFileExists(uri); SimilarityTestLogger.logInfoMsg( String.format("Could not delete resource as expected: %s (is deleted: %s) %s %s", res.getURI().toString(), isResourceDeleted, System.lineSeparator(), e.getMessage()), - this.getClass()); + ResourceHelper.class); return isResourceDeleted; } } - return !this.resourceFileExists(uri); + return !resourceFileExists(uri); } /** * Removes the entry matching to the given {@code resourceFileExtension} from * the resource factory. */ - public void removeFromRegistry(String resourceFileExtension) { + public static void removeFromRegistry(String resourceFileExtension) { if (resourceFileExtension == null) return; - var regMap = this.getResourceRegistry().getExtensionToFactoryMap(); + var regMap = getResourceRegistry().getExtensionToFactoryMap(); regMap.remove(resourceFileExtension); } } diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/AbstractJaMoPPSimilarityTest.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/AbstractJaMoPPSimilarityTest.java index dae8b167ce..913185e881 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/AbstractJaMoPPSimilarityTest.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/AbstractJaMoPPSimilarityTest.java @@ -12,11 +12,6 @@ * @author Alp Torac Genc */ public abstract class AbstractJaMoPPSimilarityTest extends AbstractEObjectSimilarityTest { - @Override - protected JaMoPPResourceHelper initResourceHelper() { - return new JaMoPPResourceHelper(); - } - @Override protected ISimilarityCheckerContainer initSCC() { return new JaMoPPSimilarityCheckerContainer(); diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/JaMoPPResourceHelper.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/JaMoPPResourceHelper.java deleted file mode 100644 index 9e0f5d7d7a..0000000000 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/JaMoPPResourceHelper.java +++ /dev/null @@ -1,42 +0,0 @@ -package cipm.consistency.fitests.similarity.jamopp; - -import org.eclipse.emf.ecore.resource.Resource; - -import cipm.consistency.fitests.similarity.eobject.AbstractResourceHelper; - -import jamopp.resource.JavaResource2Factory; - -/** - * A class that can be used for operations on Resource instances in JaMoPP - * context. - * - * @author Alp Torac Genc - */ -public class JaMoPPResourceHelper extends AbstractResourceHelper { - /** - * The extension of Java source code files. - */ - private static final String javaSrcExt = "java"; - /** - * The extension of the resource files created within tests, should they be - * saved. - */ - private static final String resFileExt = "javaxmi"; - - public JaMoPPResourceHelper() { - super(); - this.setResourceFileExtension(resFileExt); - this.setInitialResourceRegistries(); - } - - /** - * Adds the mapping into {@link Resource.Factory.Registry} for saving resources - * with the extension {@link #getResourceFileExtension()} using XMI format. - * - * @see {@link #setResourceRegistry(String, Object)} - */ - public void setInitialResourceRegistries() { - this.setResourceRegistry(javaSrcExt, new JavaResource2Factory()); - this.setResourceRegistry(resFileExt, new JavaResource2Factory()); - } -} diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/JaMoPPResourceParsingStrategy.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/JaMoPPResourceParsingStrategy.java index f7d94818fd..9349f7539a 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/JaMoPPResourceParsingStrategy.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/JaMoPPResourceParsingStrategy.java @@ -5,9 +5,11 @@ import org.eclipse.emf.ecore.resource.ResourceSet; import cipm.consistency.fitests.similarity.eobject.AbstractResourceParsingStrategy; +import cipm.consistency.fitests.similarity.eobject.ResourceHelper; import jamopp.options.ParserOptions; import jamopp.parser.jdt.singlefile.JaMoPPJDTSingleFileParser; import jamopp.recovery.trivial.TrivialRecovery; +import jamopp.resource.JavaResource2Factory; /** * A class that uses {@link JaMoPPJDTSingleFileParser} to parse Java model @@ -23,11 +25,27 @@ * @author Alp Torac Genc */ public class JaMoPPResourceParsingStrategy extends AbstractResourceParsingStrategy { + /** + * @see {@link #preConstructionSetup()} + */ + private static final String javaSrcExt = "java"; + /** + * @see {@link #preConstructionSetup()} + * @see {@link #getResourceFileExtension()} + */ + private static final String resFileExt = "javaxmi"; + /** * @see {@link #getParser()} */ private final JaMoPPJDTSingleFileParser parser; + /** + * Performs any preparation necessary prior to the construction of an instance. + * Then constructs an instance, as well as the underlying parser it uses. + * + * @see {@link #preConstructionSetup()} + */ public JaMoPPResourceParsingStrategy() { super(); this.parser = new JaMoPPJDTSingleFileParser(); @@ -71,6 +89,18 @@ protected void setUpModelParser() { ParserOptions.RESOLVE_ALL_BINDINGS.setValue(Boolean.FALSE); } + /** + * @implSpec Sets the resource factory registry for the file extension of + * JaMoPP-related Resource instances ({@value #resFileExt}). + * Additionally sets the resource factory registry for Resource + * instances with the file extension {@value #javaSrcExt}. + */ + @Override + protected void preConstructionSetup() { + ResourceHelper.setResourceRegistry(javaSrcExt, new JavaResource2Factory()); + ResourceHelper.setResourceRegistry(resFileExt, new JavaResource2Factory()); + } + @Override public ResourceSet parseModelResource(Path modelDir) { return parser.parseDirectory(modelDir); @@ -103,4 +133,13 @@ protected void exclusionPatternsChanged() { this.getParser().setExclusionPatterns(exclusionPatterns); } + + /** + * @return The extension of the resource files created within tests, should they + * be saved. + */ + @Override + public String getResourceFileExtension() { + return resFileExt; + } } diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/AbstractJaMoPPParserSimilarityTest.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/AbstractJaMoPPParserSimilarityTest.java index bfca7e7be5..67257b5d6b 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/AbstractJaMoPPParserSimilarityTest.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/AbstractJaMoPPParserSimilarityTest.java @@ -162,7 +162,7 @@ protected ParserTestFileLayout initParserTestFileLayout() { layout.setTestModelResourceFilesSaveDirPath(testModelResourceFilesSaveDirPath); layout.setCacheSaveDirPath(cacheSaveDirPath); layout.setTimeMeasurementsFileSavePath(timeMeasurementsFileSavePath); - layout.setModelResourceFileExtension(this.getResourceFileExtension()); + layout.setModelResourceFileExtension(this.getResourceParsingStrategy().getResourceFileExtension()); return layout; } @@ -260,7 +260,7 @@ protected IModelResourceWrapper parseModelsDirWithoutCaching(Path modelDir) { this.startTimeMeasurement(createTimeMeasurementKey().withOriginalModelLocation(modelDir.toString()) .withResourceParsingStrategyClassName(this.getResourceParsingStrategy().getClass().getSimpleName()), GeneralTimeMeasurementTag.PARSE_MODEL_RESOURCE); - var wrapper = new JaMoPPModelResourceWrapper(this.getResourceHelper(), this.getResourceParsingStrategy()); + var wrapper = new JaMoPPModelResourceWrapper(this.getResourceParsingStrategy()); wrapper.parseModelResource(modelDir, this.layout.getModelResourceURI(modelDir)); this.stopTimeMeasurement(); return wrapper; @@ -326,7 +326,7 @@ protected IModelResourceWrapper parseModelsDirWithCaching(Path modelDir, URI cac // Search for the resource file in cache save location if (resWrapper == null) { - resWrapper = new JaMoPPModelResourceWrapper(this.getResourceHelper()); + resWrapper = new JaMoPPModelResourceWrapper(); this.startTimeMeasurement( createTimeMeasurementKey().withOriginalModelLocation(modelDir.toString()) .withParsedModelLocation(cachedModelURI.toString()), diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/JaMoPPModelResourceWrapper.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/JaMoPPModelResourceWrapper.java index f5eb7f5c21..c51e5bd2dc 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/JaMoPPModelResourceWrapper.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/JaMoPPModelResourceWrapper.java @@ -10,7 +10,7 @@ import org.eclipse.emf.ecore.util.EcoreUtil; import cipm.consistency.fitests.similarity.SimilarityTestLogger; -import cipm.consistency.fitests.similarity.eobject.AbstractResourceHelper; +import cipm.consistency.fitests.similarity.eobject.ResourceHelper; import cipm.consistency.fitests.similarity.jamopp.JaMoPPResourceParsingStrategy; /** @@ -39,8 +39,6 @@ public class JaMoPPModelResourceWrapper implements IModelResourceWrapper { */ private boolean splitArtificialResource = false; - private AbstractResourceHelper resHelper; - /** * The name of the ArtificialResource (i.e. the last segment of its URI) without * file extension @@ -65,22 +63,18 @@ public class JaMoPPModelResourceWrapper implements IModelResourceWrapper { /** * Constructs an instance. * - * @param resHelper An object that helps with Resource-related operations * @param parsingStrat The parser that will be used to parse the model resource * and all other necessary resources */ - public JaMoPPModelResourceWrapper(AbstractResourceHelper resHelper, JaMoPPResourceParsingStrategy parsingStrat) { - this.resHelper = resHelper; + public JaMoPPModelResourceWrapper(JaMoPPResourceParsingStrategy parsingStrat) { this.parsingStrat = parsingStrat; } /** * Constructs an instance. - * - * @param resHelper An object that helps with Resource-related operations */ - public JaMoPPModelResourceWrapper(AbstractResourceHelper resHelper) { - this(resHelper, null); + public JaMoPPModelResourceWrapper() { + this(null); } /** @@ -94,7 +88,7 @@ public JaMoPPModelResourceWrapper(AbstractResourceHelper resHelper) { */ protected String getArtificialResourceFileName(String correspondingResourceFileNameWithoutExt) { return correspondingResourceFileNameWithoutExt + artificialResourceName + "." - + this.resHelper.getResourceFileExtension(); + + this.parsingStrat.getResourceFileExtension(); } /** @@ -211,7 +205,7 @@ protected Resource prepareArtificialResource(ResourceSet modelResourceSet, List< */ @Override public void parseModelResource(Path modelDir, URI modelResourceURI) { - var modelResourceSet = this.resHelper.createResourceSet(); + var modelResourceSet = ResourceHelper.createResourceSet(); // Parser returns the same ResourceSet it was previously given // via setResourceSet(...) @@ -251,7 +245,7 @@ public void parseModelResource(Path modelDir, URI modelResourceURI) { } } - mergedModelResource = this.resHelper.createResource(modelResourceURI); + mergedModelResource = ResourceHelper.createResource(modelResourceURI); artificialResource = this.prepareArtificialResource(modelResourceSet, directModelResources, this.getArtificialResourceURI(modelResourceURI)); @@ -286,7 +280,7 @@ public void parseModelResource(Path modelDir, URI modelResourceURI) { * resource resides */ public void loadModelResource(URI modelResourceURI) { - this.mergedModelResource = this.resHelper.loadResource(modelResourceURI); + this.mergedModelResource = ResourceHelper.loadResource(modelResourceURI); } /** @@ -297,13 +291,13 @@ public boolean saveResources() { var result = true; if (mergedModelResource != null) { SimilarityTestLogger.logDebugMsg("Merged model resource exists, saving it now", this.getClass()); - result = this.resHelper.saveResourceIfNotSaved(mergedModelResource); + result = ResourceHelper.saveResourceIfNotSaved(mergedModelResource); SimilarityTestLogger.logDebugMsg(String.format("%s merged model resource at %s", result ? "Saved" : "Could not save", mergedModelResource.getURI()), this.getClass()); } if (artificialResource != null) { SimilarityTestLogger.logDebugMsg("Artificial resource exists, saving it now", this.getClass()); - result = result && this.resHelper.saveResourceIfNotSaved(artificialResource); + result = result && ResourceHelper.saveResourceIfNotSaved(artificialResource); SimilarityTestLogger.logDebugMsg(String.format("%s artificial resource at %s", result ? "Saved" : "Could not save", artificialResource.getURI()), this.getClass()); } @@ -318,14 +312,14 @@ public boolean deleteResources() { var result = false; if (mergedModelResource != null) { SimilarityTestLogger.logDebugMsg("Merged model resource exists, deleting it now", this.getClass()); - result = this.resHelper.deleteResource(mergedModelResource); + result = ResourceHelper.deleteResource(mergedModelResource); SimilarityTestLogger.logDebugMsg(String.format("%s merged model resource at %s", result ? "Deleted" : "Could not delete", mergedModelResource.getURI()), this.getClass()); } if (artificialResource != null) { SimilarityTestLogger.logDebugMsg("Artificial resource exists, deleting it now", this.getClass()); - result = result && this.resHelper.deleteResource(artificialResource); + result = result && ResourceHelper.deleteResource(artificialResource); SimilarityTestLogger.logDebugMsg(String.format("%s artificial resource at %s", result ? "Saved" : "Could not save", artificialResource.getURI()), this.getClass()); } @@ -340,14 +334,14 @@ public boolean unloadResources() { var result = false; if (mergedModelResource != null) { SimilarityTestLogger.logDebugMsg("Merged model resource exists, unloading it now", this.getClass()); - result = this.resHelper.unloadResource(mergedModelResource); + result = ResourceHelper.unloadResource(mergedModelResource); SimilarityTestLogger.logDebugMsg(String.format("%s merged model resource at %s", result ? "Unloaded" : "Could not unload", mergedModelResource.getURI()), this.getClass()); } if (artificialResource != null) { SimilarityTestLogger.logDebugMsg("Artificial resource exists, unloading it now", this.getClass()); - result = result && this.resHelper.unloadResource(artificialResource); + result = result && ResourceHelper.unloadResource(artificialResource); SimilarityTestLogger.logDebugMsg(String.format("%s artificial resource at %s", result ? "Unloaded" : "Could not unload", artificialResource.getURI()), this.getClass()); } @@ -372,14 +366,14 @@ public boolean loadParsedResources() { var result = true; if (mergedModelResource != null && !this.mergedModelResource.isLoaded()) { SimilarityTestLogger.logDebugMsg("Merged model resource exists, loading it now", this.getClass()); - result = this.resHelper.unloadResource(mergedModelResource); + result = ResourceHelper.unloadResource(mergedModelResource); SimilarityTestLogger.logDebugMsg(String.format("%s merged model resource at %s", result ? "Loaded" : "Could not load", mergedModelResource.getURI()), this.getClass()); } if (artificialResource != null && !this.artificialResource.isLoaded()) { SimilarityTestLogger.logDebugMsg("Artificial resource exists, unloading it now", this.getClass()); - result = result && this.resHelper.unloadResource(artificialResource); + result = result && ResourceHelper.unloadResource(artificialResource); SimilarityTestLogger.logDebugMsg(String.format("%s artificial resource at %s", result ? "Loaded" : "Could not load", artificialResource.getURI()), this.getClass()); } From 41115bbe2da04a521e3272a59ba57b1f89ef71a6 Mon Sep 17 00:00:00 2001 From: AlpTorac Date: Wed, 27 Aug 2025 12:58:32 +0200 Subject: [PATCH 49/72] Split *.similarity.jamopp.parser package --- .../AbstractJaMoPPParserRepoTest.java | 12 ++++++------ .../fitests/repositorytests/CWARepoTest.java | 4 ++-- .../repositorytests/RepoTimeMeasurementTag.java | 2 +- .../fitests/repositorytests/TeammatesRepoTest.java | 4 ++-- .../util/RepoCacheSimilarityResultProvider.java | 2 +- .../cipm.consistency.fitests/META-INF/MANIFEST.MF | 6 ++++-- .../parser/AbstractJaMoPPParserSimilarityTest.java | 6 ++++++ .../FileContentSimilarityResultProvider.java | 4 +++- .../IExpectedSimilarityResultProvider.java | 2 +- .../ResourceContentSimilarityResultProvider.java | 2 +- ...rceReferenceEqualitySimilarityResultProvider.java | 2 +- .../jamopp/parser/resultprovider/package-info.java | 1 + .../AbstractJaMoPPParserSimilarityTestFactory.java | 8 +++++++- .../EAllContentSimilarityTestFactory.java | 6 +++++- .../IJaMoPPParserTestGenerationStrategy.java | 2 +- .../ModelComparisonTestFactory.java | 6 +++++- ...xiveSymmetricIterationTestGenerationStrategy.java | 2 +- .../jamopp/parser/testfactory/package-info.java | 1 + .../GeneralTimeMeasurementTag.java | 2 +- .../{ => timemeasurement}/ITimeMeasurementTag.java | 2 +- .../ParserTestTimeMeasurementKey.java | 2 +- .../ParserTestTimeMeasurer.java | 2 +- .../jamopp/parser/timemeasurement/package-info.java | 1 + 23 files changed, 54 insertions(+), 27 deletions(-) rename commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/{ => resultprovider}/FileContentSimilarityResultProvider.java (85%) rename commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/{ => resultprovider}/IExpectedSimilarityResultProvider.java (95%) rename commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/{ => resultprovider}/ResourceContentSimilarityResultProvider.java (98%) rename commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/{ => resultprovider}/ResourceReferenceEqualitySimilarityResultProvider.java (89%) create mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/resultprovider/package-info.java rename commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/{ => testfactory}/AbstractJaMoPPParserSimilarityTestFactory.java (89%) rename commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/{ => testfactory}/EAllContentSimilarityTestFactory.java (84%) rename commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/{ => testfactory}/IJaMoPPParserTestGenerationStrategy.java (96%) rename commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/{ => testfactory}/ModelComparisonTestFactory.java (90%) rename commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/{ => testfactory}/ReflexiveSymmetricIterationTestGenerationStrategy.java (97%) create mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/testfactory/package-info.java rename commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/{ => timemeasurement}/GeneralTimeMeasurementTag.java (96%) rename commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/{ => timemeasurement}/ITimeMeasurementTag.java (91%) rename commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/{ => timemeasurement}/ParserTestTimeMeasurementKey.java (99%) rename commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/{ => timemeasurement}/ParserTestTimeMeasurer.java (99%) create mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/package-info.java diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/AbstractJaMoPPParserRepoTest.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/AbstractJaMoPPParserRepoTest.java index c64006f553..61c3c739a1 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/AbstractJaMoPPParserRepoTest.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/AbstractJaMoPPParserRepoTest.java @@ -7,14 +7,14 @@ import cipm.consistency.fitests.similarity.eobject.ResourceHelper; import cipm.consistency.fitests.similarity.jamopp.JaMoPPResourceParsingStrategy; import cipm.consistency.fitests.similarity.jamopp.parser.AbstractJaMoPPParserSimilarityTest; -import cipm.consistency.fitests.similarity.jamopp.parser.GeneralTimeMeasurementTag; -import cipm.consistency.fitests.similarity.jamopp.parser.IExpectedSimilarityResultProvider; -import cipm.consistency.fitests.similarity.jamopp.parser.IJaMoPPParserTestGenerationStrategy; import cipm.consistency.fitests.similarity.jamopp.parser.IModelResourceWrapper; -import cipm.consistency.fitests.similarity.jamopp.parser.ITimeMeasurementTag; -import cipm.consistency.fitests.similarity.jamopp.parser.ReflexiveSymmetricIterationTestGenerationStrategy; +import cipm.consistency.fitests.similarity.jamopp.parser.resultprovider.IExpectedSimilarityResultProvider; +import cipm.consistency.fitests.similarity.jamopp.parser.testfactory.IJaMoPPParserTestGenerationStrategy; +import cipm.consistency.fitests.similarity.jamopp.parser.testfactory.ReflexiveSymmetricIterationTestGenerationStrategy; +import cipm.consistency.fitests.similarity.jamopp.parser.timemeasurement.GeneralTimeMeasurementTag; +import cipm.consistency.fitests.similarity.jamopp.parser.timemeasurement.ITimeMeasurementTag; +import cipm.consistency.fitests.similarity.jamopp.parser.timemeasurement.ParserTestTimeMeasurementKey; import cipm.consistency.fitests.similarity.jamopp.parser.JaMoPPModelResourceWrapper; -import cipm.consistency.fitests.similarity.jamopp.parser.ParserTestTimeMeasurementKey; import java.io.BufferedReader; import java.io.BufferedWriter; diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/CWARepoTest.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/CWARepoTest.java index 05c8bdf11c..2b7931847d 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/CWARepoTest.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/CWARepoTest.java @@ -6,8 +6,8 @@ import org.eclipse.emf.common.util.URI; -import cipm.consistency.fitests.similarity.jamopp.parser.AbstractJaMoPPParserSimilarityTestFactory; -import cipm.consistency.fitests.similarity.jamopp.parser.ModelComparisonTestFactory; +import cipm.consistency.fitests.similarity.jamopp.parser.testfactory.AbstractJaMoPPParserSimilarityTestFactory; +import cipm.consistency.fitests.similarity.jamopp.parser.testfactory.ModelComparisonTestFactory; /** * Contains repository parser tests for the "cwa-server" repository diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/RepoTimeMeasurementTag.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/RepoTimeMeasurementTag.java index 5f42a7d38b..d72460355b 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/RepoTimeMeasurementTag.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/RepoTimeMeasurementTag.java @@ -1,6 +1,6 @@ package cipm.consistency.fitests.repositorytests; -import cipm.consistency.fitests.similarity.jamopp.parser.ITimeMeasurementTag; +import cipm.consistency.fitests.similarity.jamopp.parser.timemeasurement.ITimeMeasurementTag; /** * An enum containing various GIT-Repository-related tags that can be used while diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/TeammatesRepoTest.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/TeammatesRepoTest.java index 9a096b26ba..1b7edffef7 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/TeammatesRepoTest.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/TeammatesRepoTest.java @@ -6,8 +6,8 @@ import org.eclipse.emf.common.util.URI; -import cipm.consistency.fitests.similarity.jamopp.parser.AbstractJaMoPPParserSimilarityTestFactory; -import cipm.consistency.fitests.similarity.jamopp.parser.ModelComparisonTestFactory; +import cipm.consistency.fitests.similarity.jamopp.parser.testfactory.AbstractJaMoPPParserSimilarityTestFactory; +import cipm.consistency.fitests.similarity.jamopp.parser.testfactory.ModelComparisonTestFactory; /** * Contains repository parser tests for the "Teammates" repository diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/RepoCacheSimilarityResultProvider.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/RepoCacheSimilarityResultProvider.java index ad2609f503..625ad1b24a 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/RepoCacheSimilarityResultProvider.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/RepoCacheSimilarityResultProvider.java @@ -4,7 +4,7 @@ import org.eclipse.emf.ecore.resource.Resource; -import cipm.consistency.fitests.similarity.jamopp.parser.IExpectedSimilarityResultProvider; +import cipm.consistency.fitests.similarity.jamopp.parser.resultprovider.IExpectedSimilarityResultProvider; /** * Provides expected similarity results based on a result cache. diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/META-INF/MANIFEST.MF b/commit-based-cipm/fi-tests/cipm.consistency.fitests/META-INF/MANIFEST.MF index 9e75e818f1..2d2add94e1 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/META-INF/MANIFEST.MF +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/META-INF/MANIFEST.MF @@ -26,5 +26,7 @@ Require-Bundle: junit-jupiter-api, Export-Package: cipm.consistency.fitests.similarity, cipm.consistency.fitests.similarity.eobject, cipm.consistency.fitests.similarity.jamopp, - cipm.consistency.fitests.similarity.jamopp.parser - + cipm.consistency.fitests.similarity.jamopp.parser, + cipm.consistency.fitests.similarity.jamopp.parser.resultprovider, + cipm.consistency.fitests.similarity.jamopp.parser.testfactory, + cipm.consistency.fitests.similarity.jamopp.parser.timemeasurement diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/AbstractJaMoPPParserSimilarityTest.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/AbstractJaMoPPParserSimilarityTest.java index 67257b5d6b..1bf38da832 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/AbstractJaMoPPParserSimilarityTest.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/AbstractJaMoPPParserSimilarityTest.java @@ -17,6 +17,12 @@ import cipm.consistency.fitests.similarity.SimilarityTestLogger; import cipm.consistency.fitests.similarity.jamopp.AbstractJaMoPPSimilarityTest; +import cipm.consistency.fitests.similarity.jamopp.parser.testfactory.AbstractJaMoPPParserSimilarityTestFactory; +import cipm.consistency.fitests.similarity.jamopp.parser.testfactory.IJaMoPPParserTestGenerationStrategy; +import cipm.consistency.fitests.similarity.jamopp.parser.timemeasurement.GeneralTimeMeasurementTag; +import cipm.consistency.fitests.similarity.jamopp.parser.timemeasurement.ITimeMeasurementTag; +import cipm.consistency.fitests.similarity.jamopp.parser.timemeasurement.ParserTestTimeMeasurementKey; +import cipm.consistency.fitests.similarity.jamopp.parser.timemeasurement.ParserTestTimeMeasurer; /** * An abstract test class, which can be used for implementing tests that involve diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/FileContentSimilarityResultProvider.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/resultprovider/FileContentSimilarityResultProvider.java similarity index 85% rename from commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/FileContentSimilarityResultProvider.java rename to commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/resultprovider/FileContentSimilarityResultProvider.java index 9b7210404a..9d752f5bc5 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/FileContentSimilarityResultProvider.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/resultprovider/FileContentSimilarityResultProvider.java @@ -1,9 +1,11 @@ -package cipm.consistency.fitests.similarity.jamopp.parser; +package cipm.consistency.fitests.similarity.jamopp.parser.resultprovider; import java.nio.file.Path; import org.eclipse.emf.ecore.resource.Resource; +import cipm.consistency.fitests.similarity.jamopp.parser.FileUtil; + /** * Provides expected similarity results for model resources by comparing the * file contents under their paths. diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/IExpectedSimilarityResultProvider.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/resultprovider/IExpectedSimilarityResultProvider.java similarity index 95% rename from commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/IExpectedSimilarityResultProvider.java rename to commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/resultprovider/IExpectedSimilarityResultProvider.java index 5a9c2e21ba..7aa185d8c6 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/IExpectedSimilarityResultProvider.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/resultprovider/IExpectedSimilarityResultProvider.java @@ -1,4 +1,4 @@ -package cipm.consistency.fitests.similarity.jamopp.parser; +package cipm.consistency.fitests.similarity.jamopp.parser.resultprovider; import java.nio.file.Path; diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ResourceContentSimilarityResultProvider.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/resultprovider/ResourceContentSimilarityResultProvider.java similarity index 98% rename from commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ResourceContentSimilarityResultProvider.java rename to commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/resultprovider/ResourceContentSimilarityResultProvider.java index ffc0594c3f..1133bd5700 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ResourceContentSimilarityResultProvider.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/resultprovider/ResourceContentSimilarityResultProvider.java @@ -1,4 +1,4 @@ -package cipm.consistency.fitests.similarity.jamopp.parser; +package cipm.consistency.fitests.similarity.jamopp.parser.resultprovider; import java.nio.file.Path; import java.util.ArrayList; diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ResourceReferenceEqualitySimilarityResultProvider.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/resultprovider/ResourceReferenceEqualitySimilarityResultProvider.java similarity index 89% rename from commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ResourceReferenceEqualitySimilarityResultProvider.java rename to commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/resultprovider/ResourceReferenceEqualitySimilarityResultProvider.java index 26f6502bb2..f9612a5c72 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ResourceReferenceEqualitySimilarityResultProvider.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/resultprovider/ResourceReferenceEqualitySimilarityResultProvider.java @@ -1,4 +1,4 @@ -package cipm.consistency.fitests.similarity.jamopp.parser; +package cipm.consistency.fitests.similarity.jamopp.parser.resultprovider; import java.nio.file.Path; diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/resultprovider/package-info.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/resultprovider/package-info.java new file mode 100644 index 0000000000..6310f36518 --- /dev/null +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/resultprovider/package-info.java @@ -0,0 +1 @@ +package cipm.consistency.fitests.similarity.jamopp.parser.resultprovider; \ No newline at end of file diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/AbstractJaMoPPParserSimilarityTestFactory.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/testfactory/AbstractJaMoPPParserSimilarityTestFactory.java similarity index 89% rename from commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/AbstractJaMoPPParserSimilarityTestFactory.java rename to commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/testfactory/AbstractJaMoPPParserSimilarityTestFactory.java index d2960a542b..77308896e3 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/AbstractJaMoPPParserSimilarityTestFactory.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/testfactory/AbstractJaMoPPParserSimilarityTestFactory.java @@ -1,10 +1,16 @@ -package cipm.consistency.fitests.similarity.jamopp.parser; +package cipm.consistency.fitests.similarity.jamopp.parser.testfactory; import java.nio.file.Path; import org.eclipse.emf.ecore.resource.Resource; import org.junit.jupiter.api.DynamicNode; +import cipm.consistency.fitests.similarity.jamopp.parser.resultprovider.IExpectedSimilarityResultProvider; +import cipm.consistency.fitests.similarity.jamopp.parser.resultprovider.ResourceReferenceEqualitySimilarityResultProvider; +import cipm.consistency.fitests.similarity.jamopp.parser.timemeasurement.GeneralTimeMeasurementTag; +import cipm.consistency.fitests.similarity.jamopp.parser.timemeasurement.ParserTestTimeMeasurementKey; +import cipm.consistency.fitests.similarity.jamopp.parser.timemeasurement.ParserTestTimeMeasurer; + /** * An abstract class meant to be implemented by classes that encapsulate logic * about dynamic test generation. diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/EAllContentSimilarityTestFactory.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/testfactory/EAllContentSimilarityTestFactory.java similarity index 84% rename from commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/EAllContentSimilarityTestFactory.java rename to commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/testfactory/EAllContentSimilarityTestFactory.java index 5bcf864470..040c1d7e5b 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/EAllContentSimilarityTestFactory.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/testfactory/EAllContentSimilarityTestFactory.java @@ -1,4 +1,4 @@ -package cipm.consistency.fitests.similarity.jamopp.parser; +package cipm.consistency.fitests.similarity.jamopp.parser.testfactory; import java.nio.file.Path; import java.util.ArrayList; @@ -10,6 +10,10 @@ import org.junit.jupiter.api.DynamicTest; import cipm.consistency.fitests.similarity.ISimilarityCheckerContainer; +import cipm.consistency.fitests.similarity.jamopp.parser.resultprovider.FileContentSimilarityResultProvider; +import cipm.consistency.fitests.similarity.jamopp.parser.resultprovider.IExpectedSimilarityResultProvider; +import cipm.consistency.fitests.similarity.jamopp.parser.timemeasurement.GeneralTimeMeasurementTag; +import cipm.consistency.fitests.similarity.jamopp.parser.timemeasurement.ParserTestTimeMeasurer; /** * A test class factory, which generates dynamic tests that check the similarity diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/IJaMoPPParserTestGenerationStrategy.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/testfactory/IJaMoPPParserTestGenerationStrategy.java similarity index 96% rename from commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/IJaMoPPParserTestGenerationStrategy.java rename to commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/testfactory/IJaMoPPParserTestGenerationStrategy.java index b92d7c0c8a..d9f75061dd 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/IJaMoPPParserTestGenerationStrategy.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/testfactory/IJaMoPPParserTestGenerationStrategy.java @@ -1,4 +1,4 @@ -package cipm.consistency.fitests.similarity.jamopp.parser; +package cipm.consistency.fitests.similarity.jamopp.parser.testfactory; import java.util.Iterator; diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ModelComparisonTestFactory.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/testfactory/ModelComparisonTestFactory.java similarity index 90% rename from commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ModelComparisonTestFactory.java rename to commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/testfactory/ModelComparisonTestFactory.java index 7790004a36..a96ebd4fe6 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ModelComparisonTestFactory.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/testfactory/ModelComparisonTestFactory.java @@ -1,4 +1,4 @@ -package cipm.consistency.fitests.similarity.jamopp.parser; +package cipm.consistency.fitests.similarity.jamopp.parser.testfactory; import java.nio.file.Path; @@ -10,6 +10,10 @@ import cipm.consistency.commitintegration.diff.util.JavaModelComparator; import cipm.consistency.fitests.similarity.jamopp.JaMoPPSimilarityCheckerContainer; +import cipm.consistency.fitests.similarity.jamopp.parser.resultprovider.IExpectedSimilarityResultProvider; +import cipm.consistency.fitests.similarity.jamopp.parser.resultprovider.ResourceContentSimilarityResultProvider; +import cipm.consistency.fitests.similarity.jamopp.parser.timemeasurement.GeneralTimeMeasurementTag; +import cipm.consistency.fitests.similarity.jamopp.parser.timemeasurement.ParserTestTimeMeasurer; /** * A test class factory, which generates dynamic tests that performs diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ReflexiveSymmetricIterationTestGenerationStrategy.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/testfactory/ReflexiveSymmetricIterationTestGenerationStrategy.java similarity index 97% rename from commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ReflexiveSymmetricIterationTestGenerationStrategy.java rename to commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/testfactory/ReflexiveSymmetricIterationTestGenerationStrategy.java index 0856acef24..5a8d045394 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ReflexiveSymmetricIterationTestGenerationStrategy.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/testfactory/ReflexiveSymmetricIterationTestGenerationStrategy.java @@ -1,4 +1,4 @@ -package cipm.consistency.fitests.similarity.jamopp.parser; +package cipm.consistency.fitests.similarity.jamopp.parser.testfactory; import java.util.Iterator; diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/testfactory/package-info.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/testfactory/package-info.java new file mode 100644 index 0000000000..5187110705 --- /dev/null +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/testfactory/package-info.java @@ -0,0 +1 @@ +package cipm.consistency.fitests.similarity.jamopp.parser.testfactory; \ No newline at end of file diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/GeneralTimeMeasurementTag.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/GeneralTimeMeasurementTag.java similarity index 96% rename from commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/GeneralTimeMeasurementTag.java rename to commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/GeneralTimeMeasurementTag.java index 9f2861d740..4853baaeab 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/GeneralTimeMeasurementTag.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/GeneralTimeMeasurementTag.java @@ -1,4 +1,4 @@ -package cipm.consistency.fitests.similarity.jamopp.parser; +package cipm.consistency.fitests.similarity.jamopp.parser.timemeasurement; /** * An enum containing various general-purpose tags that can be used while taking diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ITimeMeasurementTag.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/ITimeMeasurementTag.java similarity index 91% rename from commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ITimeMeasurementTag.java rename to commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/ITimeMeasurementTag.java index 82bd59b9d8..7e77e2c87f 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ITimeMeasurementTag.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/ITimeMeasurementTag.java @@ -1,4 +1,4 @@ -package cipm.consistency.fitests.similarity.jamopp.parser; +package cipm.consistency.fitests.similarity.jamopp.parser.timemeasurement; /** * A placeholder interface meant to be extended by enums that contain tags for diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ParserTestTimeMeasurementKey.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/ParserTestTimeMeasurementKey.java similarity index 99% rename from commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ParserTestTimeMeasurementKey.java rename to commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/ParserTestTimeMeasurementKey.java index 53025cbf70..e946c8720f 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ParserTestTimeMeasurementKey.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/ParserTestTimeMeasurementKey.java @@ -1,4 +1,4 @@ -package cipm.consistency.fitests.similarity.jamopp.parser; +package cipm.consistency.fitests.similarity.jamopp.parser.timemeasurement; import java.util.HashMap; import java.util.Map; diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ParserTestTimeMeasurer.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/ParserTestTimeMeasurer.java similarity index 99% rename from commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ParserTestTimeMeasurer.java rename to commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/ParserTestTimeMeasurer.java index 1c86f6c185..28aac7abd0 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ParserTestTimeMeasurer.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/ParserTestTimeMeasurer.java @@ -1,4 +1,4 @@ -package cipm.consistency.fitests.similarity.jamopp.parser; +package cipm.consistency.fitests.similarity.jamopp.parser.timemeasurement; import java.io.BufferedWriter; import java.io.IOException; diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/package-info.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/package-info.java new file mode 100644 index 0000000000..340fa6b9f0 --- /dev/null +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/package-info.java @@ -0,0 +1 @@ +package cipm.consistency.fitests.similarity.jamopp.parser.timemeasurement; \ No newline at end of file From f84c706a0e1fba4439bff9e9f1ca226b4029fe93 Mon Sep 17 00:00:00 2001 From: AlpTorac Date: Sun, 14 Sep 2025 13:53:42 +0200 Subject: [PATCH 50/72] Refactor time measurement --- .../AbstractJaMoPPParserRepoTest.java | 19 +- .../AbstractJaMoPPParserSimilarityTest.java | 73 +++- ...ractJaMoPPParserSimilarityTestFactory.java | 41 +- .../EAllContentSimilarityTestFactory.java | 6 +- .../ModelComparisonTestFactory.java | 10 +- .../DefaultTimeMeasurementDataStructure.java | 201 ++++++++++ .../timemeasurement/GSONLoadingStrategy.java | 159 ++++++++ .../GSONPersistingStrategy.java | 73 ++++ .../ITimeMeasurementDataStructure.java | 94 +++++ .../ITimeMeasurementLoadingStrategy.java | 27 ++ .../ITimeMeasurementPersistingStrategy.java | 24 ++ .../ITimeMeasuringStrategy.java | 95 +++++ .../ParserTestTimeMeasurementKey.java | 294 ++------------ .../ParserTestTimeMeasurementKeyBuilder.java | 304 ++++++++++++++ .../ParserTestTimeMeasurer.java | 379 ++++-------------- .../ParserTestTimeMeasurerKeyType.java | 36 ++ .../timemeasurement/StopwatchStrategy.java | 185 +++++++++ .../timemeasurement/TimeMeasurementEntry.java | 65 +++ 18 files changed, 1475 insertions(+), 610 deletions(-) create mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/DefaultTimeMeasurementDataStructure.java create mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/GSONLoadingStrategy.java create mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/GSONPersistingStrategy.java create mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/ITimeMeasurementDataStructure.java create mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/ITimeMeasurementLoadingStrategy.java create mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/ITimeMeasurementPersistingStrategy.java create mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/ITimeMeasuringStrategy.java create mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/ParserTestTimeMeasurementKeyBuilder.java create mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/ParserTestTimeMeasurerKeyType.java create mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/StopwatchStrategy.java create mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/TimeMeasurementEntry.java diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/AbstractJaMoPPParserRepoTest.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/AbstractJaMoPPParserRepoTest.java index 61c3c739a1..f5b7ce226e 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/AbstractJaMoPPParserRepoTest.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/AbstractJaMoPPParserRepoTest.java @@ -13,7 +13,7 @@ import cipm.consistency.fitests.similarity.jamopp.parser.testfactory.ReflexiveSymmetricIterationTestGenerationStrategy; import cipm.consistency.fitests.similarity.jamopp.parser.timemeasurement.GeneralTimeMeasurementTag; import cipm.consistency.fitests.similarity.jamopp.parser.timemeasurement.ITimeMeasurementTag; -import cipm.consistency.fitests.similarity.jamopp.parser.timemeasurement.ParserTestTimeMeasurementKey; +import cipm.consistency.fitests.similarity.jamopp.parser.timemeasurement.ParserTestTimeMeasurementKeyBuilder; import cipm.consistency.fitests.similarity.jamopp.parser.JaMoPPModelResourceWrapper; import java.io.BufferedReader; @@ -94,7 +94,6 @@ public abstract class AbstractJaMoPPParserRepoTest extends AbstractJaMoPPParserS @BeforeEach @Override public void setUp() { - this.startTimeMeasurement(GeneralTimeMeasurementTag.TEST_BEFOREEACH); super.setUp(); var resultCachePath = this.getTestFileLayout().getExpectedSimilarityResultCachePath(); @@ -123,7 +122,6 @@ public void setUp() { SimilarityTestLogger.logDebugMsg(String.format("No saved expected similarity results found for %s at %s", this.getCurrentTestClassName(), resultCachePath), this.getClass()); } - this.stopTimeMeasurement(); } /** @@ -183,14 +181,9 @@ public void tearDown() { } @Override - protected void startTimeMeasurement(ParserTestTimeMeasurementKey key, ITimeMeasurementTag tag) { + protected void startTimeMeasurement(ParserTestTimeMeasurementKeyBuilder keyBuilder, ITimeMeasurementTag tag) { super.startTimeMeasurement( - key.withRepositoryName(getRepoName()).withRepositoryURI(this.getRepoURI().toString()), tag); - } - - @Override - protected ParserTestTimeMeasurementKey createTimeMeasurementKey() { - return new ParserTestTimeMeasurementKey(); + keyBuilder.withRepositoryName(getRepoName()).withRepositoryURI(this.getRepoURI().toString()), tag); } @Override @@ -285,7 +278,7 @@ protected Collection cacheCommitResources() { var cachedCommitURI = this.getTestFileLayout().getModelResourceSaveURIForCommit(cID); var res = new JaMoPPModelResourceWrapper(); this.startTimeMeasurement( - this.createTimeMeasurementKey().withParsedModelLocation(cachedCommitURI.toString()), + getTimeMeasurementKeyBuilder().withParsedModelLocation(cachedCommitURI.toString()), GeneralTimeMeasurementTag.LOAD_MODEL_RESOURCE); res.loadModelResource(cachedCommitURI); this.stopTimeMeasurement(); @@ -345,7 +338,7 @@ protected void computeExpectedSimilarityResults(Git git, List commitIDLi String.format("Computing expected similarity result for: %s vs %s", commitID1, commitID2), this.getClass()); this.startTimeMeasurement( - this.createTimeMeasurementKey().withLeftCommitID(commitID1).withRightCommitID(commitID2), + getTimeMeasurementKeyBuilder().withLeftCommitID(commitID1).withRightCommitID(commitID2), GeneralTimeMeasurementTag.EXPECTED_SIMILARITY_RESULT_COMPUTATION); var result = expectedValueEstimator.getExpectedSimilarityValueFor(git, commitID1, commitID2); @@ -455,7 +448,7 @@ protected Collection prepareReposForCommits(List commits, Git SimilarityTestLogger.logDebugMsg(String.format("Checking out: %s", commitID), this.getClass()); - this.startTimeMeasurement(this.createTimeMeasurementKey().withCommitID(commitID), + this.startTimeMeasurement(getTimeMeasurementKeyBuilder().withCommitID(commitID), RepoTimeMeasurementTag.CHECKOUT_TO_COMMIT); try { git.checkout().setName(commitID).call(); diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/AbstractJaMoPPParserSimilarityTest.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/AbstractJaMoPPParserSimilarityTest.java index 1bf38da832..898516c36e 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/AbstractJaMoPPParserSimilarityTest.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/AbstractJaMoPPParserSimilarityTest.java @@ -2,6 +2,7 @@ import java.io.File; import java.nio.file.Path; +import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; @@ -19,10 +20,14 @@ import cipm.consistency.fitests.similarity.jamopp.AbstractJaMoPPSimilarityTest; import cipm.consistency.fitests.similarity.jamopp.parser.testfactory.AbstractJaMoPPParserSimilarityTestFactory; import cipm.consistency.fitests.similarity.jamopp.parser.testfactory.IJaMoPPParserTestGenerationStrategy; +import cipm.consistency.fitests.similarity.jamopp.parser.timemeasurement.DefaultTimeMeasurementDataStructure; +import cipm.consistency.fitests.similarity.jamopp.parser.timemeasurement.GSONPersistingStrategy; import cipm.consistency.fitests.similarity.jamopp.parser.timemeasurement.GeneralTimeMeasurementTag; import cipm.consistency.fitests.similarity.jamopp.parser.timemeasurement.ITimeMeasurementTag; import cipm.consistency.fitests.similarity.jamopp.parser.timemeasurement.ParserTestTimeMeasurementKey; +import cipm.consistency.fitests.similarity.jamopp.parser.timemeasurement.ParserTestTimeMeasurementKeyBuilder; import cipm.consistency.fitests.similarity.jamopp.parser.timemeasurement.ParserTestTimeMeasurer; +import cipm.consistency.fitests.similarity.jamopp.parser.timemeasurement.StopwatchStrategy; /** * An abstract test class, which can be used for implementing tests that involve @@ -39,7 +44,6 @@ * @see {@link #createTests()} */ public abstract class AbstractJaMoPPParserSimilarityTest extends AbstractJaMoPPSimilarityTest { - /** * An object that caches and grants access to the parsed models, which were * cached after being parsed.
@@ -81,6 +85,8 @@ public abstract class AbstractJaMoPPParserSimilarityTest extends AbstractJaMoPPS @BeforeEach @Override public void setUp() { + this.setupForTimeMeasurements(); + ParserTestTimeMeasurer.getInstance().startTimeMeasuring(); this.startTimeMeasurement(GeneralTimeMeasurementTag.TEST_BEFOREEACH); super.setUp(); @@ -114,7 +120,8 @@ public void tearDown() { SimilarityTestLogger.logDebugMsg("Saving all cached resources after parser test", this.getClass()); cachedResources.forEach((res) -> { this.startTimeMeasurement( - createTimeMeasurementKey().withParsedModelLocation(res.getModelResource().getURI().toString()), + getTimeMeasurementKeyBuilder() + .withParsedModelLocation(res.getModelResource().getURI().toString()), GeneralTimeMeasurementTag.SAVE_MODEL_RESOURCE); res.saveResources(); this.stopTimeMeasurement(); @@ -126,7 +133,8 @@ public void tearDown() { SimilarityTestLogger.logDebugMsg("Deleting all cached resources after parser test", this.getClass()); cachedResources.forEach((res) -> { this.startTimeMeasurement( - createTimeMeasurementKey().withParsedModelLocation(res.getModelResource().getURI().toString()), + getTimeMeasurementKeyBuilder() + .withParsedModelLocation(res.getModelResource().getURI().toString()), GeneralTimeMeasurementTag.DELETE_MODEL_RESOURCE); res.deleteResources(); this.stopTimeMeasurement(); @@ -136,7 +144,8 @@ public void tearDown() { SimilarityTestLogger.logDebugMsg("Unloading all cached resources after parser test", this.getClass()); cachedResources.forEach((res) -> { this.startTimeMeasurement( - createTimeMeasurementKey().withParsedModelLocation(res.getModelResource().getURI().toString()), + getTimeMeasurementKeyBuilder() + .withParsedModelLocation(res.getModelResource().getURI().toString()), GeneralTimeMeasurementTag.UNLOAD_MODEL_RESOURCE); res.unloadResources(); this.stopTimeMeasurement(); @@ -156,12 +165,16 @@ public void tearDown() { super.tearDown(); this.stopTimeMeasurement(); + ParserTestTimeMeasurer.getInstance().finishTimeMeasuring(); this.saveTimeMeasurements(); - SimilarityTestLogger.logDebugMsg("Tore down after parser test", this.getClass()); } + protected ParserTestTimeMeasurementKeyBuilder getTimeMeasurementKeyBuilder() { + return new ParserTestTimeMeasurementKeyBuilder(); + } + protected ParserTestFileLayout initParserTestFileLayout() { var layout = new ParserTestFileLayout(); layout.setModelSourceFileRootDirPath(new File("").getAbsoluteFile().toPath()); @@ -176,13 +189,37 @@ protected ParserTestFileLayout getTestFileLayout() { return this.layout; } + /** + * Can be overridden in sub-classes. + * + * @return The path, at which time measurements of the currently running test + * class will be saved. + */ + protected Path getTimeMeasurementSavePathForCurrentTestClass() { + var dateFormatInFileName = DateTimeFormatter.ofPattern("dd-MM-yyyy_HH-mm-ss"); + var startTime = ParserTestTimeMeasurer.getInstance().getDataStructure().getStartTime(); + var endTime = ParserTestTimeMeasurer.getInstance().getDataStructure().getEndTime(); + + var fileName = String.format("%s___%s-%s.%s", dateFormatInFileName.format(startTime), + dateFormatInFileName.format(endTime), this.getCurrentTestClassName(), "json"); + return this.getTestFileLayout().getTimeMeasurementsFileSavePath().resolve(fileName); + } + + protected void setupForTimeMeasurements() { + ParserTestTimeMeasurer.getInstance().setDataStructure(new DefaultTimeMeasurementDataStructure()); + ParserTestTimeMeasurer.getInstance().setMeasuringStrat(new StopwatchStrategy()); + ParserTestTimeMeasurer.getInstance() + .setPersistingStrat(new GSONPersistingStrategy(DateTimeFormatter.ISO_DATE_TIME)); + } + /** * Saves the time measurements taken during tests via * {@code startTimeMeasurement} and {@code stopTimeMeasurement} calls. */ protected void saveTimeMeasurements() { SimilarityTestLogger.logDebugMsg("Saving time measurements", this.getClass()); - ParserTestTimeMeasurer.getInstance().save(this.layout.getTimeMeasurementsFileSavePath()); + ParserTestTimeMeasurer.getInstance().save(this.getTimeMeasurementSavePathForCurrentTestClass()); + ParserTestTimeMeasurer.getInstance().reset(); SimilarityTestLogger.logDebugMsg("Saved time measurements", this.getClass()); } @@ -198,9 +235,9 @@ protected void saveTimeMeasurements() { * @param tag The tag of the time measurement, which is used to group time * measurements */ - protected void startTimeMeasurement(ParserTestTimeMeasurementKey key, ITimeMeasurementTag tag) { - ParserTestTimeMeasurer.getInstance().startTimeMeasurement(key.withTestClassName(getCurrentTestClassName()), - tag); + protected void startTimeMeasurement(ParserTestTimeMeasurementKeyBuilder keyBuilder, ITimeMeasurementTag tag) { + ParserTestTimeMeasurer.getInstance() + .startTimeMeasurement(keyBuilder.withTestClassName(getCurrentTestClassName()).createKey(), tag); } /** @@ -209,11 +246,7 @@ protected void startTimeMeasurement(ParserTestTimeMeasurementKey key, ITimeMeasu * for the current concrete test class. */ protected void startTimeMeasurement(ITimeMeasurementTag tag) { - startTimeMeasurement(createTimeMeasurementKey(), tag); - } - - protected ParserTestTimeMeasurementKey createTimeMeasurementKey() { - return new ParserTestTimeMeasurementKey(); + startTimeMeasurement(getTimeMeasurementKeyBuilder(), tag); } /** @@ -263,7 +296,7 @@ protected CacheUtil getCacheUtil() { * @see {@link #prepareArtificialResource(Resource, URI)} */ protected IModelResourceWrapper parseModelsDirWithoutCaching(Path modelDir) { - this.startTimeMeasurement(createTimeMeasurementKey().withOriginalModelLocation(modelDir.toString()) + this.startTimeMeasurement(getTimeMeasurementKeyBuilder().withOriginalModelLocation(modelDir.toString()) .withResourceParsingStrategyClassName(this.getResourceParsingStrategy().getClass().getSimpleName()), GeneralTimeMeasurementTag.PARSE_MODEL_RESOURCE); var wrapper = new JaMoPPModelResourceWrapper(this.getResourceParsingStrategy()); @@ -300,7 +333,7 @@ protected IModelResourceWrapper parseModelsDirWithCaching(Path modelDir, String * parsed model resource to the cache under cacheKey. */ protected IModelResourceWrapper parseModelsDirWithCaching(Path modelDir, URI cachedModelURI, String cacheKey) { - this.startTimeMeasurement(createTimeMeasurementKey().withOriginalModelLocation(modelDir.toString()) + this.startTimeMeasurement(getTimeMeasurementKeyBuilder().withOriginalModelLocation(modelDir.toString()) .withParsedModelLocation(cachedModelURI.toString()), GeneralTimeMeasurementTag.MODEL_RESOURCE_CACHE_ACCESS); var cache = this.getCacheUtil(); @@ -322,7 +355,7 @@ protected IModelResourceWrapper parseModelsDirWithCaching(Path modelDir, URI cac resWrapper = cache.getFromCache(cacheKey); if (!resWrapper.isModelResourceLoaded()) { this.startTimeMeasurement( - createTimeMeasurementKey().withOriginalModelLocation(modelDir.toString()) + getTimeMeasurementKeyBuilder().withOriginalModelLocation(modelDir.toString()) .withParsedModelLocation(cachedModelURI.toString()), GeneralTimeMeasurementTag.LOAD_MODEL_RESOURCE); resWrapper.loadParsedResources(); @@ -334,7 +367,7 @@ protected IModelResourceWrapper parseModelsDirWithCaching(Path modelDir, URI cac if (resWrapper == null) { resWrapper = new JaMoPPModelResourceWrapper(); this.startTimeMeasurement( - createTimeMeasurementKey().withOriginalModelLocation(modelDir.toString()) + getTimeMeasurementKeyBuilder().withOriginalModelLocation(modelDir.toString()) .withParsedModelLocation(cachedModelURI.toString()), GeneralTimeMeasurementTag.LOAD_MODEL_RESOURCE); resWrapper.loadModelResource(cachedModelURI); @@ -519,7 +552,7 @@ public Collection createTests() { */ protected Collection discoverModelSourceFileDirsAt(Path rootPath) { var discoveryStrat = new ModelDirDiscoveryStrategy((f) -> this.isModelSourceFileDirectory(f)); - this.startTimeMeasurement(createTimeMeasurementKey().withModelDiscoveryPath(rootPath.toString()) + this.startTimeMeasurement(getTimeMeasurementKeyBuilder().withModelDiscoveryPath(rootPath.toString()) .withModelDiscoveryClassName(discoveryStrat.getClass().getSimpleName()), GeneralTimeMeasurementTag.DISCOVER_MODEL_RESOURCES); var result = discoveryStrat.discoverModelSourceDirs(rootPath.toFile()); @@ -535,7 +568,7 @@ protected Collection discoverModelSourceFileDirsAt(Path rootPath) { */ protected Collection discoverModelSourceParentDirsAt(Path rootPath) { var discoveryStrat = new ModelDirDiscoveryStrategy((f) -> this.isModelSourceFileDirectory(f)); - this.startTimeMeasurement(createTimeMeasurementKey().withModelDiscoveryPath(rootPath.toString()) + this.startTimeMeasurement(getTimeMeasurementKeyBuilder().withModelDiscoveryPath(rootPath.toString()) .withModelDiscoveryClassName(discoveryStrat.getClass().getSimpleName()), GeneralTimeMeasurementTag.DISCOVER_MODEL_RESOURCES); var result = discoveryStrat.discoverModelSourceParentDirs(rootPath.toFile()); diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/testfactory/AbstractJaMoPPParserSimilarityTestFactory.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/testfactory/AbstractJaMoPPParserSimilarityTestFactory.java index 77308896e3..375ae9e583 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/testfactory/AbstractJaMoPPParserSimilarityTestFactory.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/testfactory/AbstractJaMoPPParserSimilarityTestFactory.java @@ -8,7 +8,7 @@ import cipm.consistency.fitests.similarity.jamopp.parser.resultprovider.IExpectedSimilarityResultProvider; import cipm.consistency.fitests.similarity.jamopp.parser.resultprovider.ResourceReferenceEqualitySimilarityResultProvider; import cipm.consistency.fitests.similarity.jamopp.parser.timemeasurement.GeneralTimeMeasurementTag; -import cipm.consistency.fitests.similarity.jamopp.parser.timemeasurement.ParserTestTimeMeasurementKey; +import cipm.consistency.fitests.similarity.jamopp.parser.timemeasurement.ParserTestTimeMeasurementKeyBuilder; import cipm.consistency.fitests.similarity.jamopp.parser.timemeasurement.ParserTestTimeMeasurer; /** @@ -90,7 +90,7 @@ public String getTestDescription() { */ public boolean getExpectedSimilarityResultFor(Resource lhsRes, Path lhsResPath, Resource rhsRes, Path rhsResPath) { ParserTestTimeMeasurer.getInstance().startTimeMeasurement( - this.getTimeMeasurementKeyFor(lhsRes, lhsResPath, rhsRes, rhsResPath), + this.getTimeMeasurementKeyBuilderFor(lhsRes, lhsResPath, rhsRes, rhsResPath).createKey(), GeneralTimeMeasurementTag.EXPECTED_SIMILARITY_RESULT_COMPUTATION); var result = this.getExpectedSimilarityResultProvider().getExpectedSimilarityResultFor(lhsRes, lhsResPath, rhsRes, rhsResPath); @@ -99,40 +99,39 @@ public boolean getExpectedSimilarityResultFor(Resource lhsRes, Path lhsResPath, } /** - * @return Generates a time measurement key for the given parameters + * The returned builder contains the preliminary key, which can be further built + * upon. In the end, call + * {@link ParserTestTimeMeasurementKeyBuilder#createKey()} to get the final key. + * + * @return A {@link ParserTestTimeMeasurementKeyBuilder} that contains all the + * information regarding the time measurement, which is derivable from + * the given parameters. */ - protected ParserTestTimeMeasurementKey getTimeMeasurementKeyFor(Resource lhsRes, Path lhsResPath, Resource rhsRes, - Path rhsResPath) { - var key = new ParserTestTimeMeasurementKey(); - - key.withTestFactoryClassName(this.getClass().getSimpleName()); - key.withExpectedSimilarityResultProviderClassName(this.getExpectedSimilarityResultProvider().getClass().getSimpleName()); + protected ParserTestTimeMeasurementKeyBuilder getTimeMeasurementKeyBuilderFor(Resource lhsRes, Path lhsResPath, + Resource rhsRes, Path rhsResPath) { + var keyBuilder = new ParserTestTimeMeasurementKeyBuilder(); - // TODO Clean up or fix to set the repository name and commitID fields - // It is currently possible to derive them from the model resource URIs: - // modelRes.getURI() = ".../repositoryName/commitID.javaxmi" + keyBuilder.withTestFactoryClassName(this.getClass().getSimpleName()); + keyBuilder.withExpectedSimilarityResultProviderClassName( + this.getExpectedSimilarityResultProvider().getClass().getSimpleName()); if (lhsRes != null) { - key.withParsedLeftModelLocation(lhsRes.getURI().toString()); -// .withLeftRepositoryName(lhsRes.getURI().segment(lhsRes.getURI().segmentCount() - 2)) -// .withLeftCommitID(lhsRes.getURI().lastSegment().split("\\.")[0]) + keyBuilder.withParsedLeftModelLocation(lhsRes.getURI().toString()); } if (lhsResPath != null) { - key.withOriginalLeftModelLocation(lhsResPath.toString()); + keyBuilder.withOriginalLeftModelLocation(lhsResPath.toString()); } if (rhsRes != null) { - key.withParsedRightModelLocation(rhsRes.getURI().toString()); -// .withRightRepositoryName(rhsRes.getURI().segment(rhsRes.getURI().segmentCount() - 2)) -// .withRightCommitID(rhsRes.getURI().lastSegment().split("\\.")[0]) + keyBuilder.withParsedRightModelLocation(rhsRes.getURI().toString()); } if (rhsResPath != null) { - key.withOriginalRightModelLocation(rhsResPath.toString()); + keyBuilder.withOriginalRightModelLocation(rhsResPath.toString()); } - return key; + return keyBuilder; } /** diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/testfactory/EAllContentSimilarityTestFactory.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/testfactory/EAllContentSimilarityTestFactory.java index 040c1d7e5b..4980a38f8e 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/testfactory/EAllContentSimilarityTestFactory.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/testfactory/EAllContentSimilarityTestFactory.java @@ -37,7 +37,8 @@ public EAllContentSimilarityTestFactory(ISimilarityCheckerContainer scc) { * considered and will impact the result. */ protected void testSimilarityOfAllContents(Resource res1, Resource res2, Boolean expectedResult) { - ParserTestTimeMeasurer.getInstance().startTimeMeasurement(this.getTimeMeasurementKeyFor(res1, null, res2, null), + ParserTestTimeMeasurer.getInstance().startTimeMeasurement( + this.getTimeMeasurementKeyBuilderFor(res1, null, res2, null).createKey(), GeneralTimeMeasurementTag.TEST_OVERHEAD); var list1 = new ArrayList(); var list2 = new ArrayList(); @@ -45,7 +46,8 @@ protected void testSimilarityOfAllContents(Resource res1, Resource res2, Boolean res1.getAllContents().forEachRemaining((o) -> list1.add(o)); res2.getAllContents().forEachRemaining((o) -> list2.add(o)); - ParserTestTimeMeasurer.getInstance().startTimeMeasurement(this.getTimeMeasurementKeyFor(res1, null, res2, null), + ParserTestTimeMeasurer.getInstance().startTimeMeasurement( + this.getTimeMeasurementKeyBuilderFor(res1, null, res2, null).createKey(), GeneralTimeMeasurementTag.SIMILARITY_CHECKING); Assertions.assertEquals(expectedResult, this.scc.areSimilar(list1, list2)); ParserTestTimeMeasurer.getInstance().stopTimeMeasurement(); diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/testfactory/ModelComparisonTestFactory.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/testfactory/ModelComparisonTestFactory.java index a96ebd4fe6..981a2b11ce 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/testfactory/ModelComparisonTestFactory.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/testfactory/ModelComparisonTestFactory.java @@ -54,8 +54,8 @@ public ModelComparisonTestFactory(boolean contentOrderMatters) { */ protected Comparison compareModels(Resource res1, Resource res2) { ParserTestTimeMeasurer.getInstance().startTimeMeasurement( - this.getTimeMeasurementKeyFor(res1, null, res2, null) - .withModelComparisonClassName(JavaModelComparator.class.getSimpleName()), + this.getTimeMeasurementKeyBuilderFor(res1, null, res2, null) + .withModelComparisonClassName(JavaModelComparator.class.getSimpleName()).createKey(), GeneralTimeMeasurementTag.MODEL_RESOURCE_COMPARISON); // TODO Integrate "this.scc" into the model comparator var result = JavaModelComparator.compareJavaModels(res1, res2, null, null, null); @@ -71,7 +71,8 @@ protected Comparison compareModels(Resource res1, Resource res2) { * comparison is symmetric. */ protected void testSimilarityWithModelComparison(Resource res1, Resource res2, Boolean expectedResult) { - ParserTestTimeMeasurer.getInstance().startTimeMeasurement(this.getTimeMeasurementKeyFor(res1, null, res2, null), + ParserTestTimeMeasurer.getInstance().startTimeMeasurement( + this.getTimeMeasurementKeyBuilderFor(res1, null, res2, null).createKey(), GeneralTimeMeasurementTag.TEST_OVERHEAD); var cmp1To2 = this.compareModels(res1, res2); @@ -79,7 +80,8 @@ protected void testSimilarityWithModelComparison(Resource res1, Resource res2, B ParserTestTimeMeasurer.getInstance().stopTimeMeasurement(); - ParserTestTimeMeasurer.getInstance().startTimeMeasurement(this.getTimeMeasurementKeyFor(res2, null, res1, null), + ParserTestTimeMeasurer.getInstance().startTimeMeasurement( + this.getTimeMeasurementKeyBuilderFor(res2, null, res1, null).createKey(), GeneralTimeMeasurementTag.TEST_OVERHEAD); var cmp2To1 = this.compareModels(res2, res1); diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/DefaultTimeMeasurementDataStructure.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/DefaultTimeMeasurementDataStructure.java new file mode 100644 index 0000000000..4fe3b62fd9 --- /dev/null +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/DefaultTimeMeasurementDataStructure.java @@ -0,0 +1,201 @@ +package cipm.consistency.fitests.similarity.jamopp.parser.timemeasurement; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.TimeUnit; +import java.util.function.Function; + +/** + * A class that can store various information on time measurements taken from + * tests. The redundant attributes of this class are only declared for + * persisting technologies to serialise and save them in data files. + * + * @author Alp Torac Genc + */ +public class DefaultTimeMeasurementDataStructure implements ITimeMeasurementDataStructure { + /** + * @see {@link #getEndTime()} + */ + private LocalDateTime startTime; + /** + * @see {@link #getStartTime()} + */ + private LocalDateTime endTime; + /** + * The description of the tool that is used for taking time measurements. Only + * declared in order to include it to the time measurement file. + */ + private String timeMeasurerDescription; + /** + * The time unit in time measurements. Only declared in order to include it to + * the time measurement file. + */ + private TimeUnit timeUnit; + /** + * The sum of all taken time measurements. + */ + private Long overallRunTime; + + /** + * Contains the sum of time measurements for individual tags in + * {@link #overallRunTime}. Only declared in order to include it to the time + * measurement file. Should be reset after saving all time measurements, so that + * the values here are not duplicated. + */ + private final Map measurementTagSummary = new HashMap(); + + /** + * Contains the proportion of time measurements with certain tags in + * {@link #overallRunTime} (in percentage). Only declared in order to include it + * to the time measurement file. Should be reset after saving all time + * measurements, so that the values here are not duplicated. + */ + private final Map measurementTagPercentageSummary = new HashMap(); + + /** + * Contains all time measurements taken. + */ + private final Collection measurements = new ArrayList(); + + @Override + public void timeMeasuringStarted(LocalDateTime startTime) { + if (this.getStartTime() == null) { + this.startTime = startTime; + } + } + + @Override + public void timeMeasuringFinished(LocalDateTime endTime) { + if (this.getStartTime() != null && this.getEndTime() == null) { + this.endTime = endTime; + this.summariseTimeMeasurements(); + } + } + + @Override + public void reset() { + this.startTime = null; + + this.endTime = null; + + this.overallRunTime = null; + this.timeMeasurerDescription = null; + this.timeUnit = null; + + this.clearSummaryMaps(); + this.measurements.clear(); + } + + /** + * Reset the summary maps after having saved, as the values of their entries + * will contain duplicated measurements otherwise. + */ + public void dataStructureSaved() { + this.clearSummaryMaps(); + } + + /** + * Cleans all values derived from the taken time measurements, so that no time + * measurement is duplicated while computing them. + */ + private void clearSummaryMaps() { + measurementTagSummary.clear(); + measurementTagPercentageSummary.clear(); + } + + /** + * Summarises all taken time measurements by grouping them based on the given + * key, and then by summing all entries in each group. + * + * @param The type of the key, based on which taken time entries are + * to be grouped + * @param summaryMap A map, which will contain the summary of all taken time + * measurements based on the foreseen key + * @param keyAccess A function for deriving the key, which will be used to + * split taken time measurements, from their entries. + */ + private void summariseTimeMeasurements(Map summaryMap, Function keyAccess) { + for (var measurementEntry : this.measurements) { + var key = keyAccess.apply(measurementEntry); + var measurement = measurementEntry.getTimeElapsed(); + + if (summaryMap.containsKey(key)) { + var summaryEntry = summaryMap.get(key); + summaryMap.replace(key, summaryEntry + measurement); + } else { + summaryMap.put(key, measurement); + } + } + } + + /** + * Summarises all taken time measurements and puts the derived values into the + * foreseen Map-based attributes of this class. + */ + private void summariseTimeMeasurements() { + this.summariseTimeMeasurements(this.measurementTagSummary, TimeMeasurementEntry::getTag); + + this.overallRunTime = this.measurementTagSummary.values().stream().reduce(Long.valueOf(0), (t1, t2) -> t1 + t2); + + this.measurementTagSummary.entrySet().forEach((e) -> this.measurementTagPercentageSummary.put(e.getKey(), + String.format("%.2f", (e.getValue().doubleValue() / overallRunTime.doubleValue()) * 100))); + } + + @Override + public void addTimeMeasurement(TimeMeasurementEntry entry) { + this.measurements.add(entry); + } + + @Override + public LocalDateTime getStartTime() { + return this.startTime; + } + + @Override + public LocalDateTime getEndTime() { + return this.endTime; + } + + @Override + public String getTimeMeasurerDescription() { + return this.timeMeasurerDescription; + } + + @Override + public void setTimeMeasurerDescription(String description) { + this.timeMeasurerDescription = description; + } + + @Override + public TimeUnit getTimeUnit() { + return this.timeUnit; + } + + @Override + public void setTimeUnit(TimeUnit unit) { + this.timeUnit = unit; + } + + @Override + public Collection getTimeMeasurementEntries() { + return new ArrayList(this.measurements); + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof DefaultTimeMeasurementDataStructure)) { + return false; + } + + var castedO = (DefaultTimeMeasurementDataStructure) obj; + + return this.getStartTime().isEqual(castedO.getStartTime()) && this.getEndTime().isEqual(castedO.getEndTime()) + && this.getTimeUnit().equals(castedO.getTimeUnit()) + && this.getTimeMeasurerDescription().equals(castedO.getTimeMeasurerDescription()) + && this.getTimeMeasurementEntries().size() == castedO.getTimeMeasurementEntries().size() + && this.getTimeMeasurementEntries().containsAll(castedO.getTimeMeasurementEntries()); + } +} diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/GSONLoadingStrategy.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/GSONLoadingStrategy.java new file mode 100644 index 0000000000..25557db821 --- /dev/null +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/GSONLoadingStrategy.java @@ -0,0 +1,159 @@ +package cipm.consistency.fitests.similarity.jamopp.parser.timemeasurement; + +import java.io.FileReader; +import java.io.IOException; +import java.lang.reflect.Type; +import java.nio.file.Path; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.HashSet; +import java.util.Set; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonParseException; + +/** + * Contains the means to parse JSON files using {@link Gson}. The used Gson + * instance is able to parse {@link DefaultTimeMeasurementDataStructure} + * instances. Whether it can parse further data structures depends on their + * structure.
+ *
+ * Note: {@link Gson} may require type adapters (especially + * {@link JsonDeserializer}) for cases, where the data structure to be parsed + * internally declares attributes with non-constructible types (abstract classes + * or interfaces). In such cases, this class has to be extended. Without the + * necessary type adapters, parse attempt may result in exceptions. + * + * @author Alp Torac Genc + */ +public class GSONLoadingStrategy implements ITimeMeasurementLoadingStrategy { + /** + * @see {@link #GSONLoadingStrategy(DateTimeFormatter, Class[])} + */ + private final DateTimeFormatter fileContentDateFormatter; + /** + * @see {@link #GSONLoadingStrategy(DateTimeFormatter, Class[])} + */ + private final Set possibleTags = new HashSet(); + /** + * @see {@link #getDataStructureClassToParse()} + */ + private final Class dataStructureClassToParse; + + public GSONLoadingStrategy(DateTimeFormatter fileContentDateFormatter, + Class dataStructureClassToParse) { + this(fileContentDateFormatter, dataStructureClassToParse, null); + } + + /** + * @param fileContentDateFormatter {@link #getFileContentDateFormatter()} + * @param dataStructureClassToParse {@link #getDataStructureClassToParse()} + * @param possibleTagSubclasses {@link #addTagSubclass(Class)} + */ + public GSONLoadingStrategy(DateTimeFormatter fileContentDateFormatter, + Class dataStructureClassToParse, + Class[] possibleTagSubclasses) { + this.fileContentDateFormatter = fileContentDateFormatter; + this.dataStructureClassToParse = dataStructureClassToParse; + + if (possibleTagSubclasses != null) { + for (var ts : possibleTagSubclasses) { + this.addTagSubclass(ts); + } + } + } + + /** + * @return The {@link Gson} instance to use while parsing the data structure + */ + protected Gson buildGSON() { + return new GsonBuilder().registerTypeHierarchyAdapter(LocalDateTime.class, this.getDateDeserializer()) + .registerTypeHierarchyAdapter(ITimeMeasurementTag.class, this.getTagDeserializer()).create(); + } + + /** + * + * @param possibleTagSubclass A concrete (enum) sub-class of + * {@link ITimeMeasurementTag} that should be + * considered, while parsing the data structure. + * These sub-classes have to be provided manually, as + * there is no clean way to access all sub-types of a + * given type programmatically + */ + public void addTagSubclass(Class possibleTagSubclass) { + if (possibleTagSubclass != null) { + for (var ec : possibleTagSubclass.getEnumConstants()) { + this.possibleTags.add(ec); + } + } + } + + /** + * @implSpec Attempts to parse an instance of + * {@link #getDataStructureClassToParse()} from the file at the given + * absolute path. Throws {@link IllegalArgumentException} if an + * {@link IOException} occurs in the process. + */ + @Override + public ITimeMeasurementDataStructure load(Path pathToDataStructureFile) { + var gson = this.buildGSON(); + ITimeMeasurementDataStructure result = null; + try (var r = new FileReader(pathToDataStructureFile.toFile())) { + result = gson.fromJson(gson.newJsonReader(r), this.getDataStructureClassToParse()); + } catch (IOException e) { + throw new IllegalArgumentException("Could not read the file at: " + pathToDataStructureFile.toString(), e); + } + return result; + } + + /** + * @return The date format, which will be used while parsing dates + */ + public DateTimeFormatter getFileContentDateFormatter() { + return this.fileContentDateFormatter; + } + + /** + * {@link Gson} must know the type of the instance it is attempting to parse, + * hence the need for the underlying attribute. + * + * @return A concrete sub-type of {@link ITimeMeasurementDataStructure} that + * will be attempted to be parsed from its file. + */ + public Class getDataStructureClassToParse() { + return this.dataStructureClassToParse; + } + + private JsonDeserializer getDateDeserializer() { + return new JsonDeserializer() { + @Override + public LocalDateTime deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) + throws JsonParseException { + var date = json.getAsString(); + return LocalDateTime.from(getFileContentDateFormatter().parse(date)); + } + }; + } + + private JsonDeserializer getTagDeserializer() { + return new JsonDeserializer() { + @Override + public ITimeMeasurementTag deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) + throws JsonParseException { + var tagString = json.getAsString(); + ITimeMeasurementTag tag = null; + for (var tagEnum : possibleTags) { + if (tagString.equals(tagEnum.toString())) { + tag = tagEnum; + break; + } + } + return tag; + } + }; + } +} diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/GSONPersistingStrategy.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/GSONPersistingStrategy.java new file mode 100644 index 0000000000..a86900a93e --- /dev/null +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/GSONPersistingStrategy.java @@ -0,0 +1,73 @@ +package cipm.consistency.fitests.similarity.jamopp.parser.timemeasurement; + +import java.io.BufferedWriter; +import java.io.IOException; +import java.lang.reflect.Type; +import java.nio.file.Files; +import java.nio.file.Path; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonElement; +import com.google.gson.JsonPrimitive; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; + +/** + * Contains the means to save the time measurements to JSON files using + * {@link Gson}. While saving the time measurements, all (non-static) attributes + * of {@link ITimeMeasurementDataStructure} containing time measurements will be + * translated to JSON objects and then written to a file.
+ *
+ * It can be used in conjunction with concrete sub-types of + * {@link ITimeMeasurementDataStructure}, as long as {@link Gson} can parse them + * without further assistance. + * + * @author Alp Torac Genc + */ +public class GSONPersistingStrategy implements ITimeMeasurementPersistingStrategy { + /** + * @see {@link #GSONPersistingStrategy(String, DateTimeFormatter)} + */ + private DateTimeFormatter fileContentTimePattern; + + /** + * @param fileContentTimePattern The pattern that will be used to transform a + * date to a string, which will be written into + * the saved measurements file. + */ + public GSONPersistingStrategy(DateTimeFormatter fileContentTimePattern) { + this.fileContentTimePattern = fileContentTimePattern; + } + + public void save(ITimeMeasurementDataStructure dataStructure, Path measurementsSavePath) { + // Ensure that all necessary parent directories exist prior to saving + var measurementsFile = measurementsSavePath.toFile(); + var measurementsFileParent = measurementsFile.getParentFile(); + if (measurementsFileParent != null) { + measurementsFileParent.mkdirs(); + } + + var gson = new GsonBuilder().setPrettyPrinting() + .registerTypeHierarchyAdapter(LocalDateTime.class, this.getDateAdapter()).create(); + try (BufferedWriter writer = Files.newBufferedWriter(measurementsSavePath); + var gsonWriter = gson.newJsonWriter(writer)) { + gson.toJson(dataStructure, dataStructure.getClass(), gsonWriter); + } catch (IOException e) { + e.printStackTrace(); + throw new IllegalArgumentException( + String.format("Could not save the expected similarity results at %s", measurementsSavePath), e); + } + } + + private JsonSerializer getDateAdapter() { + return new JsonSerializer() { + @Override + public JsonElement serialize(LocalDateTime src, Type typeOfSrc, JsonSerializationContext context) { + return new JsonPrimitive(fileContentTimePattern.format(src)); + } + }; + } +} diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/ITimeMeasurementDataStructure.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/ITimeMeasurementDataStructure.java new file mode 100644 index 0000000000..91481faa51 --- /dev/null +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/ITimeMeasurementDataStructure.java @@ -0,0 +1,94 @@ +package cipm.consistency.fitests.similarity.jamopp.parser.timemeasurement; + +import java.time.LocalDateTime; +import java.util.Collection; +import java.util.concurrent.TimeUnit; + +/** + * An interface for classes that encapsulate the means to store time + * measurements within {@link TimeMeasurementEntry} instances, which were taken + * via {@link ITimeMeasuringStrategy}. + * + * @author Alp Torac Genc + */ +public interface ITimeMeasurementDataStructure { + /** + * @return {@link ITimeMeasuringStrategy#getTimeMeasurerDescription()} + */ + public String getTimeMeasurerDescription(); + + /** + * @param description {@link ITimeMeasuringStrategy#getTimeMeasurerDescription()} + */ + public void setTimeMeasurerDescription(String description); + + /** + * @return {@link ITimeMeasuringStrategy#getTimeUnit()} + */ + public TimeUnit getTimeUnit(); + + /** + * @param unit {@link ITimeMeasuringStrategy#getTimeUnit()} + */ + public void setTimeUnit(TimeUnit unit); + + /** + * Use {@link #timeMeasuringStarted(LocalDateTime)} to set the start time, reset + * it via {@link #reset()}. + * + * @return {@link ITimeMeasuringStrategy#getStartTime()} + */ + public LocalDateTime getStartTime(); + + /** + * Use {@link #timeMeasuringFinished(LocalDateTime)} to set the end time, reset + * it via {@link #reset()}. + * + * @return {@link ITimeMeasuringStrategy#getEndTime()} + */ + public LocalDateTime getEndTime(); + + /** + * Signals the data structure that time measuring started. Calling this method + * multiple times before calling {@link #timeMeasuringFinished(LocalDateTime)} + * or {@link #reset()} should have no effect. + */ + public void timeMeasuringStarted(LocalDateTime startTime); + + /** + * Signals the data structure that time measuring is over. This method should be + * called after {@link #timeMeasuringStarted(LocalDateTime)} but before + * {@link #reset()} for it to have any effect. In any other case, this method + * should do nothing. + */ + public void timeMeasuringFinished(LocalDateTime endTime); + + /** + * Resets all current information within this instance. + */ + public void reset(); + + /** + * Signals the data structure that it has been saved.
+ *
+ * If time measuring is to start anew and the current time measurements should + * be reset, an additional call to {@link #reset()} is necessary. + */ + public void dataStructureSaved(); + + /** + * Adds the given time measurement entry (as {@link TimeMeasurementEntry} + * instance) to this data structure. + */ + public void addTimeMeasurement(TimeMeasurementEntry entry); + + /** + * The underlying collection, which stores all entries, should not be returned + * as is, since that may result in unforeseen modifications from outside. + * However, the entries within are allowed to be the original ones, so that no + * unnecessary copies are made. + * + * @return All time measurement entries added to this instance. + */ + public Collection getTimeMeasurementEntries(); +} diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/ITimeMeasurementLoadingStrategy.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/ITimeMeasurementLoadingStrategy.java new file mode 100644 index 0000000000..e5582d4fcc --- /dev/null +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/ITimeMeasurementLoadingStrategy.java @@ -0,0 +1,27 @@ +package cipm.consistency.fitests.similarity.jamopp.parser.timemeasurement; + +import java.nio.file.Path; + +/** + * An interface for classes encapsulating the means to load + * {@link ITimeMeasurementDataStructure} from files.
+ *
+ * There is no obligation for the concrete implementors to support all data + * structures. Therefore, it is advised to check the documentation of the + * concrete implementation before use. + * + * @author Alp Torac Genc + */ +public interface ITimeMeasurementLoadingStrategy { + /** + * Arbitrary concrete implementors may not be able to parse all types of + * {@link ITimeMeasurementDataStructure} from their files. Refer to the concrete + * implementor for more details about the return type. + * + * @param pathToDataStructureFile The absolute path to the file, which contains + * the serialised contents of a + * {@link ITimeMeasurementDataStructure} instance + * @return The data structure stored inside the file at the given path + */ + public ITimeMeasurementDataStructure load(Path pathToDataStructureFile); +} diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/ITimeMeasurementPersistingStrategy.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/ITimeMeasurementPersistingStrategy.java new file mode 100644 index 0000000000..2cab693238 --- /dev/null +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/ITimeMeasurementPersistingStrategy.java @@ -0,0 +1,24 @@ +package cipm.consistency.fitests.similarity.jamopp.parser.timemeasurement; + +import java.nio.file.Path; + +/** + * An interface for classes that encapsulate the means to persist + * {@link ITimeMeasurementDataStructure} instances.
+ *
+ * There is no obligation for the concrete implementors to support all data + * structures. Therefore, it is advised to check the documentation of the + * concrete implementation before use. + * + * @author Alp Torac Genc + */ +public interface ITimeMeasurementPersistingStrategy { + /** + * Saves the given dataStructure according to the concrete implementation. + * + * @param dataStructure The data structure to be persisted + * @param measurementsSavePath The absolute path, at which the given data + * structure should be persisted + */ + public void save(ITimeMeasurementDataStructure dataStructure, Path measurementsSavePath); +} diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/ITimeMeasuringStrategy.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/ITimeMeasuringStrategy.java new file mode 100644 index 0000000000..6cc8fa7c8c --- /dev/null +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/ITimeMeasuringStrategy.java @@ -0,0 +1,95 @@ +package cipm.consistency.fitests.similarity.jamopp.parser.timemeasurement; + +import java.time.LocalDateTime; +import java.util.concurrent.TimeUnit; + +/** + * An interface for classes that encapsulate the means to measure time. + * + * @author Alp Torac Genc + */ +public interface ITimeMeasuringStrategy { + /** + * Starts measuring the time using the underlying time measuring strategy for a + * certain purpose denoted in the parameters.
+ *
+ * Time measuring should have been started via {@link #timeMeasuringStarted()} + * prior to calling this method. + * + * @param key The key of the taken time measurement, which describes what the + * time measurement is taken from + * @param tag The tag of the time measurement, which is used to group time + * measurements + */ + public void startTimeMeasurement(ParserTestTimeMeasurementKey key, ITimeMeasurementTag tag); + + /** + * Stops the most recently started time measurement (via + * {@link #startTimeMeasurement(String, ITimeMeasurementTag)}). Refer to the + * concrete implementor for more information.
+ *
+ * If taking time measurements should end altogether, use + * {@link #timeMeasuringFinished()} instead. + * + * @return The time measurement entry that is generated for the stopped time + * measurement. + */ + public TimeMeasurementEntry stopTimeMeasurement(); + + /** + * Signals to the concrete implementor that time measuring has started. Calling + * this multiple times before calling {@link #timeMeasuringFinished()} should + * have no effect past the first call.
+ *
+ * Use {@link #timeMeasuringFinished()} for ending time measuring. Re-call this + * method to start anew. + */ + public void timeMeasuringStarted(); + + /** + * Signals to the concrete implementor that time measuring has ended. Calling + * this before calling {@link #timeMeasuringStarted()} should have no + * effect.
+ *
+ * If taking time measurements is to start anew, call + * {@link #timeMeasuringStarted()} before + * {@link #startTimeMeasurement(ParserTestTimeMeasurementKey, ITimeMeasurementTag)}. + */ + public void timeMeasuringFinished(); + + /** + * @return Whether time measurements are currently being taken. + */ + public boolean hasTimeMeasurementStarted(); + + /** + * @return Whether time measurement taking is currently over. + */ + public boolean hasTimeMeasurementFinished(); + + /** + * Can be used to acquire information on how time is measured. Check the + * concrete implementor for more information on the returned value. + * + * @return The description of the underlying tool that is used for taking time + * measurements. + */ + public String getTimeMeasurerDescription(); + + /** + * @return The time unit used while taking measurements. + */ + public TimeUnit getTimeUnit(); + + /** + * @return The time when time measuring has begun via + * {@link #timeMeasuringStarted()} + */ + public LocalDateTime getStartTime(); + + /** + * @return The time when time measuring has ended via + * {@link #timeMeasuringFinished()} + */ + public LocalDateTime getEndTime(); +} diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/ParserTestTimeMeasurementKey.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/ParserTestTimeMeasurementKey.java index e946c8720f..d6a5f90bd1 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/ParserTestTimeMeasurementKey.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/ParserTestTimeMeasurementKey.java @@ -3,276 +3,66 @@ import java.util.HashMap; import java.util.Map; -import com.google.gson.annotations.Expose; - /** - * A class that contains information about time measurements. Instances of this - * class can be filled in by using the {@code with...(...)} methods it offers. - * For convenience, those methods return this instance.
+ * A class that contains information about time measurements. There is no + * mandatory information that should be given to this class.
*
- * There is no mandatory information that should be given to this class. + * For convenience and clarity, instances should be constructed via builder + * classes such as {@link ParserTestTimeMeasurementKeyBuilder}. Its constructor + * is left public to allow parsing instances of this class from data files. * * @author Alp Torac Genc */ public class ParserTestTimeMeasurementKey { - @Expose - private final Map keyMap = new HashMap(); - - /** - * The class name of the instance, which is used for hierarchical model - * comparison (ex: JavaModelComparator) - */ - public ParserTestTimeMeasurementKey withModelComparisonClassName(String modelComparisonClassName) { - this.keyMap.put(ParserTestTimeMeasurerKeyType.MODEL_COMPARISON_CLASS_NAME, modelComparisonClassName); - return this; - } - - /** - * The path, from which original model files are explored. Model resources will - * then be parsed from them. - */ - public ParserTestTimeMeasurementKey withModelDiscoveryPath(String modelDiscoveryPath) { - this.keyMap.put(ParserTestTimeMeasurerKeyType.MODEL_DISCOVERY_PATH, modelDiscoveryPath); - return this; - } - - /** - * The class name of the instance, which is used for discovering original model - * files (ex: ModelDirDiscoveryStrategy) - */ - public ParserTestTimeMeasurementKey withModelDiscoveryClassName(String modelDiscoveryClassName) { - this.keyMap.put(ParserTestTimeMeasurerKeyType.MODEL_DISCOVERY_CLASS_NAME, modelDiscoveryClassName); - return this; - } - - /** - * The class name of the instance, which is used to parse model resources (ex: - * JaMoPPResourceParsingStrategy) - */ - public ParserTestTimeMeasurementKey withResourceParsingStrategyClassName(String resourceParsingStrategyClassName) { - this.keyMap.put(ParserTestTimeMeasurerKeyType.RESOURCE_PARSING_STRATEGY_CLASS_NAME, - resourceParsingStrategyClassName); - return this; - } - - /** - * The location, under which all original model files can be found. These files - * were parsed to create the corresponding model resource. The location can be - * any form of String that can be used to navigate (ex: Path.toString() or - * URI.toString()).
- *
- * Use this, if only one model is considered. - */ - public ParserTestTimeMeasurementKey withOriginalModelLocation(String originalModelLocation) { - this.keyMap.put(ParserTestTimeMeasurerKeyType.ORIGINAL_MODEL_LOCATION, originalModelLocation); - return this; - } - - /** - * The location, under which the parsed model resource can be found. The - * location can be any form of String that can be used to navigate (ex: - * Path.toString() or URI.toString()).
- *
- * Use this, if only one model is considered. - */ - public ParserTestTimeMeasurementKey withParsedModelLocation(String parsedModelLocation) { - this.keyMap.put(ParserTestTimeMeasurerKeyType.PARSED_MODEL_LOCATION, parsedModelLocation); - return this; - } - - /** - * The path, under which all (left hand side) original model files can be found. - * These files were parsed to create the corresponding model resource. The - * location can be any form of String that can be used to navigate (ex: - * Path.toString() or URI.toString()).
- *
- * Use this, if two models are considered. - */ - public ParserTestTimeMeasurementKey withOriginalLeftModelLocation(String originalModelLocation) { - this.keyMap.put(ParserTestTimeMeasurerKeyType.ORIGINAL_LEFT_MODEL_LOCATION, originalModelLocation); - return this; - } - - /** - * The location, under which the (left hand side) parsed model resource can be - * found. The location can be any form of String that can be used to navigate - * (ex: Path.toString() or URI.toString()).
- *
- * Use this, if two models are considered. - */ - public ParserTestTimeMeasurementKey withParsedLeftModelLocation(String parsedModelLocation) { - this.keyMap.put(ParserTestTimeMeasurerKeyType.PARSED_LEFT_MODEL_LOCATION, parsedModelLocation); - return this; - } - - /** - * The path, under which all (right hand side) original model files can be - * found. These files were parsed to create the corresponding model resource.The - * location can be any form of String that can be used to navigate (ex: - * Path.toString() or URI.toString()).
- *
- *
- * Use this, if two models are considered. - */ - public ParserTestTimeMeasurementKey withOriginalRightModelLocation(String originalModelLocation) { - this.keyMap.put(ParserTestTimeMeasurerKeyType.ORIGINAL_RIGHT_MODEL_LOCATION, originalModelLocation); - return this; - } - - /** - * The location, under which the (right hand side) parsed model resource can be - * found. The location can be any form of String that can be used to navigate - * (ex: Path.toString() or URI.toString()).
- *
- * Use this, if two models are considered. - */ - public ParserTestTimeMeasurementKey withParsedRightModelLocation(String parsedModelLocation) { - this.keyMap.put(ParserTestTimeMeasurerKeyType.PARSED_RIGHT_MODEL_LOCATION, parsedModelLocation); - return this; - } - - /** - * The name of the test class (ex: CWARepoTest) - */ - public ParserTestTimeMeasurementKey withTestClassName(String testClassName) { - this.keyMap.put(ParserTestTimeMeasurerKeyType.TEST_CLASS_NAME, testClassName); - return this; - } - - /** - * The name of the test factory class, which was used to create the dynamic - * tests (ex: ModelComparisonTestFactory) - */ - public ParserTestTimeMeasurementKey withTestFactoryClassName(String testFactoryClassName) { - this.keyMap.put(ParserTestTimeMeasurerKeyType.TEST_FACTORY_CLASS_NAME, testFactoryClassName); - return this; - } - - /** - * The class name of the instance, which provides expected similarity results to - * dynamic tests (ex: ResourceReferenceEqualitySimilarityResultProvider) - */ - public ParserTestTimeMeasurementKey withExpectedSimilarityResultProviderClassName( - String expectedSimilarityResultProviderClassName) { - this.keyMap.put(ParserTestTimeMeasurerKeyType.EXPECTED_SIMILARITY_RESULT_PROVIDER_CLASS_NAME, - expectedSimilarityResultProviderClassName); - return this; - } - - /** - * The name of the repository that is considered in the test class.
- *
- * Use this, if only one repository/commit is considered. - */ - public ParserTestTimeMeasurementKey withRepositoryName(String repositoryName) { - this.keyMap.put(ParserTestTimeMeasurerKeyType.REPOSITORY_NAME, repositoryName); - return this; - } - - /** - * The URI to the repository that is considered in the test class.
- *
- * Use this, if only one repository/commit is considered. - */ - public ParserTestTimeMeasurementKey withRepositoryURI(String repositoryURI) { - this.keyMap.put(ParserTestTimeMeasurerKeyType.REPOSITORY_URI, repositoryURI); - return this; - } - - /** - * The hash of the commit that is currently considered.
- *
- * Use this, if only one commit is considered. - */ - public ParserTestTimeMeasurementKey withCommitID(String commitID) { - this.keyMap.put(ParserTestTimeMeasurerKeyType.COMMIT_ID, commitID); - return this; - } - - /** - * The name of the (left-hand-side) repository.
- *
- * Use this, if two repositories/commits are considered. - */ - public ParserTestTimeMeasurementKey withLeftRepositoryName(String leftRepositoryName) { - this.keyMap.put(ParserTestTimeMeasurerKeyType.LEFT_REPOSITORY_NAME, leftRepositoryName); - return this; - } - - /** - * The URI to the (left-hand-side) repository.
- *
- * Use this, if two repositories/commits are considered. - */ - public ParserTestTimeMeasurementKey withLeftRepositoryURI(String leftRepositoryURI) { - this.keyMap.put(ParserTestTimeMeasurerKeyType.LEFT_REPOSITORY_URI, leftRepositoryURI); - return this; - } - - /** - * The name of the (right-hand-side) repository.
- *
- * Use this, if two repositories/commits are considered. - */ - public ParserTestTimeMeasurementKey withRightRepositoryName(String rightRepositoryName) { - this.keyMap.put(ParserTestTimeMeasurerKeyType.RIGHT_REPOSITORY_NAME, rightRepositoryName); - return this; - } + private final Map keyMap; /** - * The URI to the (right-hand-side) repository.
- *
- * Use this, if two repositories/commits are considered. + * Constructs an instance with the given (key, value) pairs in keyMap. For + * performance reasons, keyMap will not be copied. It will be directly assigned + * to this instance, meaning that modifications to keyMap from outside will be + * reflected to this instance. + * + * @param keyMap (key, value) pairs that this class should store. Although it is + * allowed to be null, passing null here will most likely render + * this instance useless */ - public ParserTestTimeMeasurementKey withRightRepositoryURI(String rightRepositoryURI) { - this.keyMap.put(ParserTestTimeMeasurerKeyType.RIGHT_REPOSITORY_URI, rightRepositoryURI); - return this; + public ParserTestTimeMeasurementKey(Map keyMap) { + this.keyMap = keyMap; } /** - * The hash of the (left-hand-side) commit that is currently considered.
- *
- * Use this, if two commits are considered. + * Can be used to copy the contents of this instance (while creating a clone for + * instance). + * + * @return A copy of all added keys and their values. Modifying the return value + * will not affect this instance. */ - public ParserTestTimeMeasurementKey withLeftCommitID(String leftCommitID) { - this.keyMap.put(ParserTestTimeMeasurerKeyType.LEFT_COMMIT_ID, leftCommitID); - return this; + public Map getKeys() { + if (keyMap == null) { + return new HashMap(); + } + return new HashMap(keyMap); } /** - * The hash of the (right-hand-side) commit that is currently considered.
- *
- * Use this, if two commits are considered. + * Two instances of this class are similar, if their contents + * ({@link #getKeys()} in this case) are equal. */ - public ParserTestTimeMeasurementKey withRightCommitID(String rightCommitID) { - this.keyMap.put(ParserTestTimeMeasurerKeyType.RIGHT_COMMIT_ID, rightCommitID); - return this; - } - - public enum ParserTestTimeMeasurerKeyType { - MODEL_DISCOVERY_PATH, - - MODEL_DISCOVERY_CLASS_NAME, - - ORIGINAL_MODEL_LOCATION, PARSED_MODEL_LOCATION, - - ORIGINAL_LEFT_MODEL_LOCATION, PARSED_LEFT_MODEL_LOCATION, ORIGINAL_RIGHT_MODEL_LOCATION, - PARSED_RIGHT_MODEL_LOCATION, - - RESOURCE_PARSING_STRATEGY_CLASS_NAME, - - MODEL_COMPARISON_CLASS_NAME, - - TEST_CLASS_NAME, TEST_FACTORY_CLASS_NAME, - - EXPECTED_SIMILARITY_RESULT_PROVIDER_CLASS_NAME, - - REPOSITORY_NAME, REPOSITORY_URI, COMMIT_ID, - - LEFT_REPOSITORY_NAME, LEFT_REPOSITORY_URI, + @Override + public boolean equals(Object obj) { + if (!(obj instanceof ParserTestTimeMeasurementKey)) { + return false; + } + var castedO = (ParserTestTimeMeasurementKey) obj; - RIGHT_REPOSITORY_NAME, RIGHT_REPOSITORY_URI, + // Avoid NullPointerExceptions + if (this.keyMap == null && castedO.keyMap == null) { + return true; + } else if (this.keyMap == null ^ castedO.keyMap == null) { + return false; + } - LEFT_COMMIT_ID, RIGHT_COMMIT_ID; + return this.keyMap.size() == castedO.keyMap.size() + && this.keyMap.entrySet().containsAll(castedO.keyMap.entrySet()); } } diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/ParserTestTimeMeasurementKeyBuilder.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/ParserTestTimeMeasurementKeyBuilder.java new file mode 100644 index 0000000000..3cbeddeaa8 --- /dev/null +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/ParserTestTimeMeasurementKeyBuilder.java @@ -0,0 +1,304 @@ +package cipm.consistency.fitests.similarity.jamopp.parser.timemeasurement; + +import java.util.HashMap; +import java.util.Map; + +/** + * A builder for {@link ParserTestTimeMeasurementKey}.
+ *
+ * Use the provided methods to build the key instance. For convenience and + * copying existing keys, {@link #fromKeyMap(Map)} and + * {@link #fromStringKeyMap(Map)} can be used. Calling {@link #createKey()} will + * return the key instance that was being built and reset all status information + * within this class. + * + * @author Alp Torac Genc + */ +public class ParserTestTimeMeasurementKeyBuilder { + private Map keyMap; + + public ParserTestTimeMeasurementKeyBuilder() { + this.reset(); + } + + /** + * Includes all pairs from the given map to the key to be created + */ + public ParserTestTimeMeasurementKeyBuilder fromKeyMap(Map anotherKeyMap) { + this.keyMap.putAll(anotherKeyMap); + return this; + } + + /** + * A variant of {@link #fromKeyMap(Map)} that parses the + * {@link ParserTestTimeMeasurerKeyType} values before including all pairs from + * the given map to the key to be created + */ + public ParserTestTimeMeasurementKeyBuilder fromStringKeyMap(Map anotherKeyMap) { + for (var e : anotherKeyMap.entrySet()) { + this.keyMap.put(ParserTestTimeMeasurerKeyType.valueOf(e.getKey()), e.getValue()); + } + return this; + } + + /** + * The class name of the instance, which is used for hierarchical model + * comparison (ex: JavaModelComparator) + */ + public ParserTestTimeMeasurementKeyBuilder withModelComparisonClassName(String modelComparisonClassName) { + this.keyMap.put(ParserTestTimeMeasurerKeyType.MODEL_COMPARISON_CLASS_NAME, modelComparisonClassName); + return this; + } + + /** + * The path, from which original model files are explored. Model resources will + * then be parsed from them. + */ + public ParserTestTimeMeasurementKeyBuilder withModelDiscoveryPath(String modelDiscoveryPath) { + this.keyMap.put(ParserTestTimeMeasurerKeyType.MODEL_DISCOVERY_PATH, modelDiscoveryPath); + return this; + } + + /** + * The class name of the instance, which is used for discovering original model + * files (ex: ModelDirDiscoveryStrategy) + */ + public ParserTestTimeMeasurementKeyBuilder withModelDiscoveryClassName(String modelDiscoveryClassName) { + this.keyMap.put(ParserTestTimeMeasurerKeyType.MODEL_DISCOVERY_CLASS_NAME, modelDiscoveryClassName); + return this; + } + + /** + * The class name of the instance, which is used to parse model resources (ex: + * JaMoPPResourceParsingStrategy) + */ + public ParserTestTimeMeasurementKeyBuilder withResourceParsingStrategyClassName( + String resourceParsingStrategyClassName) { + this.keyMap.put(ParserTestTimeMeasurerKeyType.RESOURCE_PARSING_STRATEGY_CLASS_NAME, + resourceParsingStrategyClassName); + return this; + } + + /** + * The location, under which all original model files can be found. These files + * were parsed to create the corresponding model resource. The location can be + * any form of String that can be used to navigate (ex: Path.toString() or + * URI.toString()).
+ *
+ * Use this, if only one model is considered. + */ + public ParserTestTimeMeasurementKeyBuilder withOriginalModelLocation(String originalModelLocation) { + this.keyMap.put(ParserTestTimeMeasurerKeyType.ORIGINAL_MODEL_LOCATION, originalModelLocation); + return this; + } + + /** + * The location, under which the parsed model resource can be found. The + * location can be any form of String that can be used to navigate (ex: + * Path.toString() or URI.toString()).
+ *
+ * Use this, if only one model is considered. + */ + public ParserTestTimeMeasurementKeyBuilder withParsedModelLocation(String parsedModelLocation) { + this.keyMap.put(ParserTestTimeMeasurerKeyType.PARSED_MODEL_LOCATION, parsedModelLocation); + return this; + } + + /** + * The path, under which all (left hand side) original model files can be found. + * These files were parsed to create the corresponding model resource. The + * location can be any form of String that can be used to navigate (ex: + * Path.toString() or URI.toString()).
+ *
+ * Use this, if two models are considered. + */ + public ParserTestTimeMeasurementKeyBuilder withOriginalLeftModelLocation(String originalModelLocation) { + this.keyMap.put(ParserTestTimeMeasurerKeyType.ORIGINAL_LEFT_MODEL_LOCATION, originalModelLocation); + return this; + } + + /** + * The location, under which the (left hand side) parsed model resource can be + * found. The location can be any form of String that can be used to navigate + * (ex: Path.toString() or URI.toString()).
+ *
+ * Use this, if two models are considered. + */ + public ParserTestTimeMeasurementKeyBuilder withParsedLeftModelLocation(String parsedModelLocation) { + this.keyMap.put(ParserTestTimeMeasurerKeyType.PARSED_LEFT_MODEL_LOCATION, parsedModelLocation); + return this; + } + + /** + * The path, under which all (right hand side) original model files can be + * found. These files were parsed to create the corresponding model resource.The + * location can be any form of String that can be used to navigate (ex: + * Path.toString() or URI.toString()).
+ *
+ *
+ * Use this, if two models are considered. + */ + public ParserTestTimeMeasurementKeyBuilder withOriginalRightModelLocation(String originalModelLocation) { + this.keyMap.put(ParserTestTimeMeasurerKeyType.ORIGINAL_RIGHT_MODEL_LOCATION, originalModelLocation); + return this; + } + + /** + * The location, under which the (right hand side) parsed model resource can be + * found. The location can be any form of String that can be used to navigate + * (ex: Path.toString() or URI.toString()).
+ *
+ * Use this, if two models are considered. + */ + public ParserTestTimeMeasurementKeyBuilder withParsedRightModelLocation(String parsedModelLocation) { + this.keyMap.put(ParserTestTimeMeasurerKeyType.PARSED_RIGHT_MODEL_LOCATION, parsedModelLocation); + return this; + } + + /** + * The name of the test class (ex: CWARepoTest) + */ + public ParserTestTimeMeasurementKeyBuilder withTestClassName(String testClassName) { + this.keyMap.put(ParserTestTimeMeasurerKeyType.TEST_CLASS_NAME, testClassName); + return this; + } + + /** + * The name of the test factory class, which was used to create the dynamic + * tests (ex: ModelComparisonTestFactory) + */ + public ParserTestTimeMeasurementKeyBuilder withTestFactoryClassName(String testFactoryClassName) { + this.keyMap.put(ParserTestTimeMeasurerKeyType.TEST_FACTORY_CLASS_NAME, testFactoryClassName); + return this; + } + + /** + * The class name of the instance, which provides expected similarity results to + * dynamic tests (ex: ResourceReferenceEqualitySimilarityResultProvider) + */ + public ParserTestTimeMeasurementKeyBuilder withExpectedSimilarityResultProviderClassName( + String expectedSimilarityResultProviderClassName) { + this.keyMap.put(ParserTestTimeMeasurerKeyType.EXPECTED_SIMILARITY_RESULT_PROVIDER_CLASS_NAME, + expectedSimilarityResultProviderClassName); + return this; + } + + /** + * The name of the repository that is considered in the test class.
+ *
+ * Use this, if only one repository/commit is considered. + */ + public ParserTestTimeMeasurementKeyBuilder withRepositoryName(String repositoryName) { + this.keyMap.put(ParserTestTimeMeasurerKeyType.REPOSITORY_NAME, repositoryName); + return this; + } + + /** + * The URI to the repository that is considered in the test class.
+ *
+ * Use this, if only one repository/commit is considered. + */ + public ParserTestTimeMeasurementKeyBuilder withRepositoryURI(String repositoryURI) { + this.keyMap.put(ParserTestTimeMeasurerKeyType.REPOSITORY_URI, repositoryURI); + return this; + } + + /** + * The hash of the commit that is currently considered.
+ *
+ * Use this, if only one commit is considered. + */ + public ParserTestTimeMeasurementKeyBuilder withCommitID(String commitID) { + this.keyMap.put(ParserTestTimeMeasurerKeyType.COMMIT_ID, commitID); + return this; + } + + /** + * The name of the (left-hand-side) repository.
+ *
+ * Use this, if two repositories/commits are considered. + */ + public ParserTestTimeMeasurementKeyBuilder withLeftRepositoryName(String leftRepositoryName) { + this.keyMap.put(ParserTestTimeMeasurerKeyType.LEFT_REPOSITORY_NAME, leftRepositoryName); + return this; + } + + /** + * The URI to the (left-hand-side) repository.
+ *
+ * Use this, if two repositories/commits are considered. + */ + public ParserTestTimeMeasurementKeyBuilder withLeftRepositoryURI(String leftRepositoryURI) { + this.keyMap.put(ParserTestTimeMeasurerKeyType.LEFT_REPOSITORY_URI, leftRepositoryURI); + return this; + } + + /** + * The name of the (right-hand-side) repository.
+ *
+ * Use this, if two repositories/commits are considered. + */ + public ParserTestTimeMeasurementKeyBuilder withRightRepositoryName(String rightRepositoryName) { + this.keyMap.put(ParserTestTimeMeasurerKeyType.RIGHT_REPOSITORY_NAME, rightRepositoryName); + return this; + } + + /** + * The URI to the (right-hand-side) repository.
+ *
+ * Use this, if two repositories/commits are considered. + */ + public ParserTestTimeMeasurementKeyBuilder withRightRepositoryURI(String rightRepositoryURI) { + this.keyMap.put(ParserTestTimeMeasurerKeyType.RIGHT_REPOSITORY_URI, rightRepositoryURI); + return this; + } + + /** + * The hash of the (left-hand-side) commit that is currently considered.
+ *
+ * Use this, if two commits are considered. + */ + public ParserTestTimeMeasurementKeyBuilder withLeftCommitID(String leftCommitID) { + this.keyMap.put(ParserTestTimeMeasurerKeyType.LEFT_COMMIT_ID, leftCommitID); + return this; + } + + /** + * The hash of the (right-hand-side) commit that is currently considered.
+ *
+ * Use this, if two commits are considered. + */ + public ParserTestTimeMeasurementKeyBuilder withRightCommitID(String rightCommitID) { + this.keyMap.put(ParserTestTimeMeasurerKeyType.RIGHT_COMMIT_ID, rightCommitID); + return this; + } + + /** + * Resets the building process of a {@link ParserTestTimeMeasurementKey} + * instance by initialising all status information of this instance, effectively + * resetting them.
+ *
+ * If this method is called before {@link #createKey()}, the building process + * will be reset and must be started anew. + */ + public ParserTestTimeMeasurementKeyBuilder reset() { + this.keyMap = new HashMap(); + return this; + } + + /** + * Finalises the current building process by actually creating the + * {@link ParserTestTimeMeasurementKey} instance. Resets (via {@link #reset()}) + * all status information in this instance afterward.
+ *
+ * If this method is overridden, {@link #reset()} should be called after the key + * instance is created. + * + * @return The built {@link ParserTestTimeMeasurementKey} instance + */ + public ParserTestTimeMeasurementKey createKey() { + var key = new ParserTestTimeMeasurementKey(this.keyMap); + this.reset(); + return key; + } +} diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/ParserTestTimeMeasurer.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/ParserTestTimeMeasurer.java index 28aac7abd0..35c958bf7c 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/ParserTestTimeMeasurer.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/ParserTestTimeMeasurer.java @@ -1,137 +1,22 @@ package cipm.consistency.fitests.similarity.jamopp.parser.timemeasurement; -import java.io.BufferedWriter; -import java.io.IOException; -import java.nio.file.Files; import java.nio.file.Path; -import java.time.LocalDateTime; -import java.time.format.DateTimeFormatter; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; -import java.util.Stack; -import java.util.function.Function; - -import org.apache.commons.lang.time.StopWatch; - -import com.google.gson.GsonBuilder; -import com.google.gson.annotations.Expose; /** - * A class for taking time measurements using - * {@link org.apache.commons.lang.time.StopWatch}, and saving them.
- *
- * The time measurements taken here are contain no duplications; i.e. if another - * time measurement is taken while a previous time measurement continues (for - * instance, while a method's run time is measured, a new time measurement - * starts for one of its inner method calls), they will be separate.
- *
- * Also contains the means to save the time measurements to JSON files using the - * GSON library. While saving the time measurements, the (non-static) attributes - * of this class annotated with {@link com.google.gson.annotations.Expose} will - * be translated to JSON objects and then written to a JSON file. This way, only - * the desired attributes of this class are saved, as opposed to all of them. + * A utility class for taking time measurements during tests. * * @author Alp Torac Genc */ public class ParserTestTimeMeasurer { - /** - * The pattern that will be used to transform a date to a string, which will be - * used in the name of the saved measurements file. - */ - private final static DateTimeFormatter filenameTimeFormatter = DateTimeFormatter.ofPattern("dd-MM-yyyy_HH-mm-ss"); - /** - * The pattern that will be used to transform a date to a string, which will be - * written into the saved measurements file. - */ - private final static DateTimeFormatter fileContentTimeFormatter = DateTimeFormatter.ISO_DATE_TIME; + private ITimeMeasurementDataStructure dataStructure; + private ITimeMeasurementPersistingStrategy persistingStrat; + private ITimeMeasuringStrategy measuringStrat; + /** * The only instance of this class. */ private static ParserTestTimeMeasurer instance; - /** - * The time, when the first time measurement starts via - * {@link #startTimeMeasurement(String, ITimeMeasurementTag)}. - */ - private LocalDateTime startTime; - - /** - * The time, when taking time measurements ends via - * {@link #finishTimeMeasuring()}. - */ - private LocalDateTime endTime; - - /** - * The string representation of {@link #startTime}, which will be written into - * the saved measurements file. - */ - @Expose - private String startTimeString; - - /** - * The string representation of {@link #endTime}, which will be written into the - * saved measurements file. - */ - @Expose - private String endTimeString; - - /** - * The name of the tool that is used for taking time measurements. Only declared - * in order to include it to the time measurement file. - */ - @Expose - private final String timeMeasurer = StopWatch.class.getName(); - /** - * The time unit in time measurements. Only declared in order to include it to - * the time measurement file. - */ - @Expose - private final String timeUnit = "Milliseconds (ms)"; - - /** - * The sum of all taken time measurements. - */ - @Expose - private Long overallRunTime; - - /** - * Contains the sum of time measurements for individual tags in - * {@link #overallRunTime}. Only declared in order to include it to the time - * measurement file. Should be reset after saving all time measurements, so that - * the values here are not duplicated. - */ - @Expose - private final Map measurementTagSummary = new HashMap(); - - /** - * Contains the proportion of time measurements with certain tags in - * {@link #overallRunTime} (in percentage). Only declared in order to include it - * to the time measurement file. Should be reset after saving all time - * measurements, so that the values here are not duplicated. - */ - @Expose - private final Map measurementTagPercentageSummary = new HashMap(); - - /** - * Contains all time measurements taken. - */ - @Expose - private final Collection measurements = new ArrayList(); - - /** - * A stack that contains all StopWatch instances that are used during - * performance measurement. The reason to use a stack here is, there are cases, - * where methods make calls to other methods and their run times overlap. By - * suspending the outer method's StopWatch and pushing a new StopWatch onto the - * stack, the inner methods' run times can be measured accurately. Then the new - * StopWatch can be popped and stopped to get the run time of the inner method. - * Finally, the outer method's StopWatch can be resumed to resume the time - * measurement. - */ - private final Stack watches = new Stack(); - private ParserTestTimeMeasurer() { } @@ -145,241 +30,139 @@ public static ParserTestTimeMeasurer getInstance() { } /** - * Starts measuring the time for a certain purpose given via the parameters. If - * another time measurement is ongoing (i.e. if this method is called multiple - * times without {@link #stopTimeMeasurement()} calls in between), the previous - * time measurement is paused until the new time measurement is stopped via - * {@link #stopTimeMeasurement()}.
- *
- * This method is to be seen as the opening bracket for the closing bracket - * {@link #stopTimeMeasurement()} such that the time elapsed while executing the - * lines between this method call and that method call is the time measurement. - * Not using them similar to brackets will result in problems.
+ * Starts measuring the time using the underlying time measuring strategy for a + * certain purpose denoted in the parameters.
*
+ * Time measuring should have been started via {@link #startTimeMeasuring()} + * prior to calling this method. * * @param key The key of the taken time measurement, which describes what the * time measurement is taken from * @param tag The tag of the time measurement, which is used to group time * measurements + * + * @see {@link #getMeasuringStrat()} */ public void startTimeMeasurement(ParserTestTimeMeasurementKey key, ITimeMeasurementTag tag) { - if (this.startTime == null) { - this.startTime = LocalDateTime.now(); - this.startTimeString = fileContentTimeFormatter.format(this.startTime); - } - - /* - * Suspends the potential outer method's Stopwatch, so that time measurements do - * not overlap - */ - if (!watches.isEmpty()) { - var outerMethodWatch = watches.peek(); - outerMethodWatch.suspend(); - } - - var currentMethodWatch = new StopWatch(); - - this.measurements.add(new TimeMeasurementEntry(currentMethodWatch, key, tag)); - - watches.push(currentMethodWatch); - currentMethodWatch.start(); + this.measuringStrat.startTimeMeasurement(key, tag); } /** * Stops the most recently started time measurement (via - * {@link #startTimeMeasurement(String, ITimeMeasurementTag)}). If the most - * recent time measurement paused a previous time measurement, it is resumed. - *
- *
- * This method is to be seen as the closing bracket for the opening bracket - * {@link #startTimeMeasurement(String, ITimeMeasurementTag)}, such that the - * time elapsed while executing the lines between that method call and this - * method call is the time measurement. Not using them similar to brackets will - * result in inaccurate measurements.
+ * {@link #startTimeMeasurement(String, ITimeMeasurementTag)}) and saves it in + * the underlying data structure.
*
* If taking time measurements should end altogether, use * {@link #finishTimeMeasuring()} instead. + * + * @see {@link #getMeasuringStrat()} + * @see {@link #getDataStructure()} */ public void stopTimeMeasurement() { - var currentMethodWatch = watches.pop(); - currentMethodWatch.stop(); + this.dataStructure.addTimeMeasurement(this.measuringStrat.stopTimeMeasurement()); + } - /* - * Resumes the potential outer method's Stopwatch, which was previously - * suspended - */ - if (!watches.isEmpty()) { - watches.peek().resume(); - } + /** + * Signals that taking time measurements should start and prepares the + * underlying mechanisms for time measuring.
+ *
+ * Use {@link #finishTimeMeasuring()} for ending time measuring. Re-call this + * method to start anew. + * + * @see {@link #getDataStructure()} + * @see {@link #getMeasuringStrat()} + */ + public void startTimeMeasuring() { + this.measuringStrat.timeMeasuringStarted(); + + this.dataStructure.setTimeMeasurerDescription(this.measuringStrat.getTimeMeasurerDescription()); + this.dataStructure.setTimeUnit(this.measuringStrat.getTimeUnit()); + this.dataStructure.timeMeasuringStarted(this.measuringStrat.getStartTime()); } /** * Signals that taking time measurements is over and the taken time measurements - * should be processed.
+ * should be processed.
*
- * If a singular time measurement should be stopped, use - * {@link #stopTimeMeasurement()} instead. + * If taking time measurements is to start anew, call + * {@link #startTimeMeasuring()} before + * {@link #startTimeMeasurement(ParserTestTimeMeasurementKey, ITimeMeasurementTag)}. + * + * @see {@link #getDataStructure()} + * @see {@link #getMeasuringStrat()} */ public void finishTimeMeasuring() { - if (this.endTime == null) { - this.endTime = LocalDateTime.now(); - this.endTimeString = fileContentTimeFormatter.format(LocalDateTime.now()); - } - - this.measurements.forEach((m) -> m.computeTime()); + this.measuringStrat.timeMeasuringFinished(); + var time = this.measuringStrat.getEndTime(); + this.dataStructure.timeMeasuringFinished(time); } /** - * Ends taking time measurements, if not already done, then processes all taken - * time measurements. Finally, saves all taken time measurements, as well as - * their summaries represented by certain attributes of this instance, at the - * given path, in a JSON file. + * Ends taking time measurements (if not already done), then processes all taken + * time measurements. Finally, saves the underlying data structure that was + * collecting all time measurements according to the underlying persisting + * strategy. * * @param measurementsSavePath The absolute path, at which all taken time * measurements should be saved. + * + * @see {@link #getDataStructure()} + * @see {@link #getPersistingStrat()} */ public void save(Path measurementsSavePath) { this.finishTimeMeasuring(); - this.summariseTimeMeasurements(); - var filePath = measurementsSavePath.resolve(this.getFullFileName()); + this.persistingStrat.save(dataStructure, measurementsSavePath); - // Ensure that all necessary parent directories exist prior to saving - measurementsSavePath.toFile().mkdirs(); - - var gson = new GsonBuilder().setPrettyPrinting().excludeFieldsWithoutExposeAnnotation().create(); - try (BufferedWriter writer = Files.newBufferedWriter(filePath); var gsonWriter = gson.newJsonWriter(writer)) { - gson.toJson(this, this.getClass(), gsonWriter); - } catch (IOException e) { - e.printStackTrace(); - throw new IllegalArgumentException( - String.format("Could not save the expected similarity results at %s", filePath), e); - } - - /* - * Reset the summary maps after having saved, as the values of their entries - * will contain duplicated measurements otherwise. - */ - this.clearSummaryMaps(); + this.dataStructure.dataStructureSaved(); } /** - * @return The name (with file extension) of the measurements file that will be - * saved. + * Resets all collected time measurements. */ - private String getFullFileName() { - var fileExtension = ".json"; - return String.format("%s___%s%s", filenameTimeFormatter.format(this.startTime), - filenameTimeFormatter.format(this.endTime), fileExtension); + public void reset() { + this.dataStructure.reset(); } /** - * Cleans all values derived from the taken time measurements, so that no time - * measurement is duplicated while computing them. + * @return The data structure that will collect all time measurements taken */ - private void clearSummaryMaps() { - measurementTagSummary.clear(); - measurementTagPercentageSummary.clear(); + public ITimeMeasurementDataStructure getDataStructure() { + return dataStructure; } /** - * Summarises all taken time measurements by grouping them based on the given - * key, and then by summing all entries in each group. - * - * @param The type of the key, based on which taken time entries are - * to be grouped - * @param summaryMap A map, which will contain the summary of all taken time - * measurements based on the foreseen key - * @param keyAccess A function for deriving the key, which will be used to - * split taken time measurements, from their entries. + * @param dataStructure {@link #getDataStructure()} */ - private void summariseTimeMeasurements(Map summaryMap, Function keyAccess) { - for (var measurementEntry : this.measurements) { - var key = keyAccess.apply(measurementEntry); - var measurement = measurementEntry.getMillis(); - - if (summaryMap.containsKey(key)) { - var summaryEntry = summaryMap.get(key); - summaryMap.replace(key, summaryEntry + measurement); - } else { - summaryMap.put(key, measurement); - } - } + public void setDataStructure(ITimeMeasurementDataStructure dataStructure) { + this.dataStructure = dataStructure; } /** - * Summarises all taken time measurements and puts the derived values into the - * foreseen Map-based attributes of this class. + * @return The strategy for persisting all time measurements */ - private void summariseTimeMeasurements() { - this.summariseTimeMeasurements(this.measurementTagSummary, TimeMeasurementEntry::getTag); - - this.overallRunTime = this.measurementTagSummary.values().stream().reduce(Long.valueOf(0), (t1, t2) -> t1 + t2); - - this.measurementTagSummary.entrySet().forEach((e) -> this.measurementTagPercentageSummary.put(e.getKey(), - String.format("%.2f", (e.getValue().doubleValue() / overallRunTime.doubleValue()) * 100))); + public ITimeMeasurementPersistingStrategy getPersistingStrat() { + return persistingStrat; } /** - * A class that encapsulates singular time measurements. - * - * @author Alp Torac Genc + * @param persistingStrat {@link #getPersistingStrat()} */ - private class TimeMeasurementEntry { - private StopWatch watch; - - @Expose - private Long millis; - - @Expose - private final ParserTestTimeMeasurementKey key; - @Expose - private final ITimeMeasurementTag tag; - - /** - * @param watch An object that keeps track of the start and end time of the time - * measurement. The start and end times of this time measurement - * are provided indirectly through this parameter, as it may be - * necessary to pause and resume this time measurement. - * @param key Keys associated with the time measurement, which describe what - * was measured - * @param tag The tag of the time measurement, which can be used for a - * high-level grouping of time measurements based on what they are - * taken from - */ - private TimeMeasurementEntry(StopWatch watch, ParserTestTimeMeasurementKey key, ITimeMeasurementTag tag) { - this.watch = watch; - this.tag = tag; - this.key = key; - } - - public Long getMillis() { - return millis; - } - - @SuppressWarnings("unused") - public ParserTestTimeMeasurementKey getKey() { - return key; - } - - public ITimeMeasurementTag getTag() { - return tag; - } + public void setPersistingStrat(ITimeMeasurementPersistingStrategy persistingStrat) { + this.persistingStrat = persistingStrat; + } - @SuppressWarnings("unused") - public StopWatch getWatch() { - return watch; - } + /** + * @return The mechanism that will be used to take time measurements + */ + public ITimeMeasuringStrategy getMeasuringStrat() { + return measuringStrat; + } - /** - * Computes the actual time value of this time measurement using - * {@link #getWatch()} - */ - public void computeTime() { - if (this.watch != null) { - this.millis = Long.valueOf(this.watch.getTime()); - this.watch = null; - } - } + /** + * @param measuringStrat {@link #getMeasuringStrat()} + */ + public void setMeasuringStrat(ITimeMeasuringStrategy measuringStrat) { + this.measuringStrat = measuringStrat; } } diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/ParserTestTimeMeasurerKeyType.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/ParserTestTimeMeasurerKeyType.java new file mode 100644 index 0000000000..2036946640 --- /dev/null +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/ParserTestTimeMeasurerKeyType.java @@ -0,0 +1,36 @@ +package cipm.consistency.fitests.similarity.jamopp.parser.timemeasurement; + +/** + * An enum that can be used to associate time measurement related information + * with descriptions, in form of enum constants. + * + * TODO Decide whether all enum constants require commentary + * + * @author Alp Torac Genc + */ +public enum ParserTestTimeMeasurerKeyType { + MODEL_DISCOVERY_PATH, + + MODEL_DISCOVERY_CLASS_NAME, + + ORIGINAL_MODEL_LOCATION, PARSED_MODEL_LOCATION, + + ORIGINAL_LEFT_MODEL_LOCATION, PARSED_LEFT_MODEL_LOCATION, ORIGINAL_RIGHT_MODEL_LOCATION, + PARSED_RIGHT_MODEL_LOCATION, + + RESOURCE_PARSING_STRATEGY_CLASS_NAME, + + MODEL_COMPARISON_CLASS_NAME, + + TEST_CLASS_NAME, TEST_FACTORY_CLASS_NAME, + + EXPECTED_SIMILARITY_RESULT_PROVIDER_CLASS_NAME, + + REPOSITORY_NAME, REPOSITORY_URI, COMMIT_ID, + + LEFT_REPOSITORY_NAME, LEFT_REPOSITORY_URI, + + RIGHT_REPOSITORY_NAME, RIGHT_REPOSITORY_URI, + + LEFT_COMMIT_ID, RIGHT_COMMIT_ID; +} \ No newline at end of file diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/StopwatchStrategy.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/StopwatchStrategy.java new file mode 100644 index 0000000000..8ca18edc05 --- /dev/null +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/StopwatchStrategy.java @@ -0,0 +1,185 @@ +package cipm.consistency.fitests.similarity.jamopp.parser.timemeasurement; + +import java.time.LocalDateTime; +import java.util.Stack; +import java.util.concurrent.TimeUnit; + +import org.apache.commons.lang.time.StopWatch; + +/** + * A class for taking time measurements using + * {@link org.apache.commons.lang.time.StopWatch}, and saving them.
+ *
+ * The time measurements taken here are contain no duplications; i.e. if another + * time measurement is taken while a previous time measurement continues (for + * instance, while a method's run time is measured, a new time measurement + * starts for one of its inner method calls), they will be separate. + * + * @author Alp Torac Genc + */ +public class StopwatchStrategy implements ITimeMeasuringStrategy { + + /** + * {@link #getStartTime()} + */ + private LocalDateTime startTime; + /** + * {@link #getEndTime()} + */ + private LocalDateTime endTime; + + /** + * A stack that contains all StopWatch instances that are used during + * performance measurement. The reason to use a stack here is, there are cases, + * where methods make calls to other methods and their run times overlap. By + * suspending the outer method's StopWatch and pushing a new StopWatch onto the + * stack, the inner methods' run times can be measured accurately. Then the new + * StopWatch can be popped and stopped to get the run time of the inner method. + * Finally, the outer method's StopWatch can be resumed to resume the time + * measurement.
+ *
+ * All StopWatch are accompanied by an entry, along which they were created. + * This way, the StopWatch instances and their corresponding entries are easier + * to access. + */ + private final Stack watchEntryPairs = new Stack(); + + /** + * @implSpec If another time measurement is ongoing (i.e. if this method is + * called multiple times without {@link #stopTimeMeasurement()} calls + * in between), the previous time measurement is paused until the new + * time measurement is stopped via {@link #stopTimeMeasurement()}. + *
+ *
+ * This method is to be seen as the opening bracket for the closing + * bracket {@link #stopTimeMeasurement()} such that the time elapsed + * while executing the lines between this method call and that method + * call is the time measurement. Not using them similar to brackets + * will result in problems. + */ + public void startTimeMeasurement(ParserTestTimeMeasurementKey key, ITimeMeasurementTag tag) { + /* + * Suspends the potential outer method's Stopwatch, so that time measurements do + * not overlap + */ + if (!watchEntryPairs.isEmpty()) { + var outerMethodPair = watchEntryPairs.peek(); + outerMethodPair.getWatch().suspend(); + } + + var currentMethodWatch = new StopWatch(); + + var entry = new TimeMeasurementEntry(key, tag); + + watchEntryPairs.push(new StopWatchEntryPair(currentMethodWatch, entry)); + currentMethodWatch.start(); + } + + /** + * @implSpec If the most recent time measurement paused a previous time + * measurement, it is resumed.
+ *
+ * This method is to be seen as the closing bracket for the opening + * bracket {@link #startTimeMeasurement(String, ITimeMeasurementTag)}, + * such that the time elapsed while executing the lines between that + * method call and this method call is the time measurement. Not using + * them similar to brackets will result in inaccurate measurements. + */ + public TimeMeasurementEntry stopTimeMeasurement() { + var currentMethodPair = watchEntryPairs.pop(); + var watch = currentMethodPair.getWatch(); + var entry = currentMethodPair.getEntry(); + + watch.stop(); + entry.setTimeElapsed(watch.getTime()); + + /* + * Resumes the potential outer method's Stopwatch, which was previously + * suspended + */ + if (!watchEntryPairs.isEmpty()) { + watchEntryPairs.peek().getWatch().resume(); + } + return entry; + } + + @Override + public void timeMeasuringFinished() { + if (this.hasTimeMeasurementStarted() && !this.hasTimeMeasurementFinished()) { + this.endTime = LocalDateTime.now(); + } + } + + @Override + public void timeMeasuringStarted() { + if (!this.hasTimeMeasurementStarted()) { + this.startTime = LocalDateTime.now(); + + // Reset the end time, since time measuring just started + this.endTime = null; + } + } + + /** + * Time measurement is assumed to have started, if + * {@link #timeMeasuringStarted()} has been called but + * {@link #timeMeasuringFinished()} is not called yet. + */ + @Override + public boolean hasTimeMeasurementStarted() { + return this.getStartTime() != null && this.getEndTime() == null; + } + + /** + * Time measurement is assumed to have finished, if both + * {@link #timeMeasuringStarted()} and {@link #timeMeasuringFinished()} have + * been called. + */ + @Override + public boolean hasTimeMeasurementFinished() { + return this.getStartTime() != null && this.getEndTime() != null; + } + + /** + * Since {@link StopWatch} is used, the used time unit is milliseconds (ms). + * + * @return {@link TimeUnit#MILLISECONDS} + */ + @Override + public TimeUnit getTimeUnit() { + return TimeUnit.MILLISECONDS; + } + + @Override + public String getTimeMeasurerDescription() { + return StopWatch.class.getName(); + } + + @Override + public LocalDateTime getStartTime() { + return this.startTime; + } + + @Override + public LocalDateTime getEndTime() { + return this.endTime; + } + + private class StopWatchEntryPair { + private final StopWatch watch; + private final TimeMeasurementEntry entry; + + private StopWatchEntryPair(StopWatch watch, TimeMeasurementEntry entry) { + this.watch = watch; + this.entry = entry; + } + + private StopWatch getWatch() { + return watch; + } + + private TimeMeasurementEntry getEntry() { + return entry; + } + } +} diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/TimeMeasurementEntry.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/TimeMeasurementEntry.java new file mode 100644 index 0000000000..e51e7676b8 --- /dev/null +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/TimeMeasurementEntry.java @@ -0,0 +1,65 @@ +package cipm.consistency.fitests.similarity.jamopp.parser.timemeasurement; + +/** + * A class that encapsulates singular time measurements. + * + * @author Alp Torac Genc + */ +public class TimeMeasurementEntry { + private long timeElapsed; + private final ParserTestTimeMeasurementKey key; + private final ITimeMeasurementTag tag; + + /** + * @param key {@link #getKey()} + * @param tag {@link #getTag()} + */ + public TimeMeasurementEntry(ParserTestTimeMeasurementKey key, ITimeMeasurementTag tag) { + this.tag = tag; + this.key = key; + } + + /** + * The concrete time unit should be specified within the + * {@link ITimeMeasurementDataStructure} that stores this instance + * + * @return The amount of time units associated with the time measurement + */ + public long getTimeElapsed() { + return timeElapsed; + } + + /** + * @param timeElapsed {@link #getTimeElapsed()} + */ + public void setTimeElapsed(long timeElapsed) { + this.timeElapsed = timeElapsed; + } + + /** + * @return Information associated with the time measurement, which describe what + * was measured + */ + public ParserTestTimeMeasurementKey getKey() { + return key; + } + + /** + * @return The tag of the time measurement, which can be used for a high-level + * grouping of time measurements based on what they are taken from + */ + public ITimeMeasurementTag getTag() { + return tag; + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof TimeMeasurementEntry)) { + return false; + } + var castedO = (TimeMeasurementEntry) obj; + + return this.getTag().equals(castedO.getTag()) && this.getKey().equals(castedO.getKey()) + && this.getTimeElapsed() == castedO.getTimeElapsed(); + } +} \ No newline at end of file From 72cf3eda68f6a2b7bf3160723ac98e1ccf39bbdc Mon Sep 17 00:00:00 2001 From: AlpTorac Date: Thu, 28 Aug 2025 19:14:59 +0200 Subject: [PATCH 51/72] Use getter instead --- .../jamopp/parser/AbstractJaMoPPParserSimilarityTest.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/AbstractJaMoPPParserSimilarityTest.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/AbstractJaMoPPParserSimilarityTest.java index 898516c36e..2fd174488f 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/AbstractJaMoPPParserSimilarityTest.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/AbstractJaMoPPParserSimilarityTest.java @@ -300,7 +300,7 @@ protected IModelResourceWrapper parseModelsDirWithoutCaching(Path modelDir) { .withResourceParsingStrategyClassName(this.getResourceParsingStrategy().getClass().getSimpleName()), GeneralTimeMeasurementTag.PARSE_MODEL_RESOURCE); var wrapper = new JaMoPPModelResourceWrapper(this.getResourceParsingStrategy()); - wrapper.parseModelResource(modelDir, this.layout.getModelResourceURI(modelDir)); + wrapper.parseModelResource(modelDir, this.getTestFileLayout().getModelResourceURI(modelDir)); this.stopTimeMeasurement(); return wrapper; } @@ -319,7 +319,8 @@ protected IModelResourceWrapper parseModelsDirWithCaching(Path modelDir) { * {@code this.getModelResourceURI(modelDir)} as cached model URI. */ protected IModelResourceWrapper parseModelsDirWithCaching(Path modelDir, String cacheKey) { - return this.parseModelsDirWithCaching(modelDir, this.layout.getModelResourceURI(modelDir), cacheKey); + return this.parseModelsDirWithCaching(modelDir, this.getTestFileLayout().getModelResourceURI(modelDir), + cacheKey); } /** @@ -506,7 +507,7 @@ public Collection createTests(Path[] pathArr, Resource[] resArr) { public Collection createTests() { this.startTimeMeasurement(GeneralTimeMeasurementTag.DYNAMIC_TEST_CREATION); - var modelSourceFileRootDirPath = this.layout.getModelSourceFileRootDirPath(); + var modelSourceFileRootDirPath = this.getTestFileLayout().getModelSourceFileRootDirPath(); var tests = new ArrayList(); From dcd7379ffcf9f9325be169d8001ad651926e5b64 Mon Sep 17 00:00:00 2001 From: AlpTorac Date: Sun, 14 Sep 2025 13:48:31 +0200 Subject: [PATCH 52/72] Edit exception message Edit commentary --- .../util/RepoTestSimilarityValueEstimator.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/RepoTestSimilarityValueEstimator.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/RepoTestSimilarityValueEstimator.java index f5153bcf1d..168f517f1d 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/RepoTestSimilarityValueEstimator.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/RepoTestSimilarityValueEstimator.java @@ -17,9 +17,9 @@ import cipm.consistency.fitests.repositorytests.util.difffilter.DiffFilter; /** - * A class that computes expected similarity checking results (or expected - * similarity values) based on the given GIT-Diffs. Provides numerous variants - * of its computation method to allow re-using various GIT elements.
+ * A class that computes expected similarity checking results based on the given + * GIT-Diffs. Provides numerous variants of its computation method to allow + * re-using various GIT elements.
*
* Uses {@link QuickCommentRemover}, which removes commentaries in an * approximative fashion. Therefore, the computed results may be @@ -50,7 +50,7 @@ public boolean getExpectedSimilarityValueFor(OutputStream os, DiffFormatter df, } } catch (IOException e) { e.printStackTrace(); - throw new IllegalStateException("IOException occured while computing expected similarity value", e); + throw new IllegalStateException("IOException occured while computing expected similarity result", e); } return true; @@ -66,7 +66,7 @@ public boolean getExpectedSimilarityValueFor(List diffEntries) { return this.getExpectedSimilarityValueFor(os, new DiffFormatter(os), diffEntries); } catch (IOException e) { e.printStackTrace(); - throw new IllegalStateException("IOException occured while computing expected similarity value", e); + throw new IllegalStateException("IOException occured while computing expected similarity result", e); } } @@ -92,7 +92,7 @@ public boolean getExpectedSimilarityValueFor(Git git, AbstractTreeIterator oldTr return this.getExpectedSimilarityValueFor(os, df, entries); } catch (IOException e) { e.printStackTrace(); - throw new IllegalStateException("IOException occured while computing expected similarity value", e); + throw new IllegalStateException("IOException occured while computing expected similarity result", e); } } @@ -116,7 +116,7 @@ public boolean getExpectedSimilarityValueFor(Git git, String commitID1, String c return this.getExpectedSimilarityValueFor(git, oldTreeIter, newTreeIter); } catch (IOException e) { e.printStackTrace(); - throw new IllegalStateException("IOException occured while computing expected similarity value", e); + throw new IllegalStateException("IOException occured while computing expected similarity result", e); } } From 43f80e1db29649b17757adf59841e1a14a4ebc4f Mon Sep 17 00:00:00 2001 From: AlpTorac Date: Sun, 14 Sep 2025 13:49:08 +0200 Subject: [PATCH 53/72] Edit commentary --- .../AbstractJaMoPPParserRepoTest.java | 57 ++++--- .../fitests/repositorytests/CWARepoTest.java | 2 +- .../RepoParserTestFileLayout.java | 22 +-- .../RepoParserTestOptions.java | 10 +- .../RepoTimeMeasurementTag.java | 4 +- .../repositorytests/TeammatesRepoTest.java | 2 +- .../fitests/repositorytests/package-info.java | 9 + .../RepoCacheSimilarityResultProvider.java | 3 +- .../util/RepoTestResultCache.java | 19 ++- .../RepoTestSimilarityValueEstimator.java | 31 ++-- .../similarity/AbstractSimilarityTest.java | 12 +- .../AbstractEObjectSimilarityTest.java | 30 +++- .../AbstractResourceParsingStrategy.java | 12 +- .../similarity/eobject/ResourceHelper.java | 12 +- .../similarity/eobject/package-info.java | 3 +- .../jamopp/AbstractJaMoPPSimilarityTest.java | 4 +- .../jamopp/JaMoPPResourceParsingStrategy.java | 7 +- .../similarity/jamopp/package-info.java | 7 +- .../AbstractJaMoPPParserSimilarityTest.java | 157 ++++++++++-------- .../similarity/jamopp/parser/CacheUtil.java | 31 ++-- .../similarity/jamopp/parser/FileUtil.java | 4 + .../parser/IModelDirDiscoveryStrategy.java | 31 ++-- .../jamopp/parser/IModelResourceWrapper.java | 28 ++-- .../parser/JaMoPPModelResourceWrapper.java | 36 ++-- .../parser/ModelDirDiscoveryStrategy.java | 40 +++-- .../jamopp/parser/ParserTestFileLayout.java | 33 ++-- .../jamopp/parser/ParserTestOptions.java | 8 +- .../jamopp/parser/package-info.java | 15 +- .../FileContentSimilarityResultProvider.java | 14 +- .../IExpectedSimilarityResultProvider.java | 15 +- ...sourceContentSimilarityResultProvider.java | 13 +- ...renceEqualitySimilarityResultProvider.java | 2 +- .../parser/resultprovider/package-info.java | 5 + ...ractJaMoPPParserSimilarityTestFactory.java | 12 +- .../EAllContentSimilarityTestFactory.java | 5 - .../IJaMoPPParserTestGenerationStrategy.java | 6 +- .../ModelComparisonTestFactory.java | 4 - ...metricIterationTestGenerationStrategy.java | 32 +++- .../parser/testfactory/package-info.java | 10 ++ .../GeneralTimeMeasurementTag.java | 16 +- .../ParserTestTimeMeasurementKey.java | 4 +- .../parser/timemeasurement/package-info.java | 33 ++++ 42 files changed, 484 insertions(+), 316 deletions(-) create mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/package-info.java diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/AbstractJaMoPPParserRepoTest.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/AbstractJaMoPPParserRepoTest.java index f5b7ce226e..f32e8f578f 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/AbstractJaMoPPParserRepoTest.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/AbstractJaMoPPParserRepoTest.java @@ -40,16 +40,24 @@ /** * An abstract test class, which can be used for implementing tests that involve - * parsing models from GIT repositories and checking their similarity. + * parsing models from GIT repositories and checking their similarity.
+ *
+ * Note: Since dynamic tests are used here, the + * {@link org.junit.jupiter.api.BeforeEach} and + * {@link org.junit.jupiter.api.AfterEach} methods will be triggered only + * once at the start / end of each test method annotated with + * {@link org.junit.jupiter.api.TestFactory} , as opposed to before / + * after each dynamic test. In that sense, they are similar to their static + * versions {@link org.junit.jupiter.api.BeforeAll} and + * {@link org.junit.jupiter.api.AfterAll} method. * * @author Alp Torac Genc * * @see {@link AbstractJaMoPPParserSimilarityTest#createTests()} */ public abstract class AbstractJaMoPPParserRepoTest extends AbstractJaMoPPParserSimilarityTest { - /** - * Contains expected results of comparing model resources + * Contains expected similarity results needed by tests */ private static RepoTestResultCache resultCache = new RepoTestResultCache(); @@ -60,7 +68,7 @@ public abstract class AbstractJaMoPPParserRepoTest extends AbstractJaMoPPParserS private static final String gradleWrapperJarPathPattern = ".*?/gradle-wrapper\\.jar"; /** - * The name of the root directory of the models + * @see {@link RepoParserTestFileLayout#setRepoModelImplDirName(String)} */ private static final String repoModelImplDirName = "repo-clones"; @@ -71,25 +79,21 @@ public abstract class AbstractJaMoPPParserRepoTest extends AbstractJaMoPPParserS private static final String repoURICommitSegment = "commit"; /** - * The name of the folder, where contents of {@link #resultCache} should be - * saved.
- *
- * Note: This folder does not have to directly contain the contents of - * {@link #resultCache}. They may be saved in sub-directories as well. + * @see {@link RepoParserTestFileLayout#setExpectedSimilarityResultCacheDirName(String)} */ private static final String expectedSimilarityResultCacheDirName = "results-cache"; /** - * The name of the file (with extension), where contents of {@link #resultCache} - * should be saved. + * @see {@link RepoParserTestFileLayout#setExpectedSimilarityResultCacheFileName(String)} */ private static final String expectedSimilarityResultCacheFileName = "resultsCache.json"; /** * {@inheritDoc}
*
- * {@link AbstractJaMoPPParserRepoTest}: Loads expected similarity checking - * results, if their file exists. + * {@link AbstractJaMoPPParserRepoTest}: Loads expected similarity results + * needed by tests, if their file exists. See + * {@link AbstractJaMoPPParserRepoTest} for more information. */ @BeforeEach @Override @@ -128,7 +132,8 @@ public void setUp() { * {@inheritDoc}
*
* {@link AbstractJaMoPPParserRepoTest}: Saves the computed expected similarity - * results and deletes the local repository clone, if desired. + * results needed by tests and deletes the local repository clone, if desired. + * See {@link AbstractJaMoPPParserRepoTest} for more information. */ @AfterEach @Override @@ -203,17 +208,20 @@ protected RepoParserTestFileLayout getTestFileLayout() { } /** - * @return The expected similarity checking result for the given commits. Note - * that similarity checking is symmetric, meaning that swapping lhs and - * rhs commits should not change the return value. + * Refer to {@link RepoTestResultCache} for more information on expected + * similarity results. + * + * @return The expected similarity checking result for the given commits. */ protected Boolean getExpectedResult(String lhsCommit, String rhsCommit) { return resultCache.getResult(lhsCommit, rhsCommit); } /** - * Adds model resources to {@link #resultCache} for all commits relevant for - * this test. Must be executed before all tests. + * TODO Rename to prepareTestResources or something similar + * + * Prepares model resources and expected similarity results needed by tests and + * caches them. Must be executed before all tests. * * @see {@link #getCommitIDs()} */ @@ -316,6 +324,7 @@ protected Collection cacheCommitResources() { } /** + * Computes and caches expected similarity results necessary for the tests. * * @param git The GIT object associated with the in-memory * representation of the GIT repository @@ -515,20 +524,22 @@ protected JaMoPPResourceParsingStrategy initResourceParsingStrategy() { protected abstract List getCommitIDs(); /** - * @return The URI to the repository, which will be used in tests. + * @return The URI to the (remote) repository, which will be locally cloned and + * used in tests. */ protected abstract URI getRepoURI(); /** - * @return The name of the repository that is used in this test. + * @return The name of the (remote) repository, which will be locally cloned and + * used in tests. */ protected String getRepoName() { return this.getRepoURI().lastSegment(); } /** - * @return An object that provides expected similarity results for parsed - * commits in tests. + * @return An object that provides expected similarity results for model + * resources parsed from commits in tests. */ protected IExpectedSimilarityResultProvider getExpectedSimilarityResultProviderForCommits() { return new RepoCacheSimilarityResultProvider(resultCache); diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/CWARepoTest.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/CWARepoTest.java index 2b7931847d..fb095a7d42 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/CWARepoTest.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/CWARepoTest.java @@ -17,7 +17,7 @@ public class CWARepoTest extends AbstractJaMoPPParserRepoTest { /** * The list of commits that will be parsed and compared to one another. All of - * them are pairwise different, i.e. all of them introduce code changes that + * them are pairwise non-similar, i.e. all of them introduce code changes that * break similarity (assuming test code is included). */ private static final List commitIDs = List.of("7e1b610aa3334afb770eebef79ba60120e2169bc", // Version 2.25.0 diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/RepoParserTestFileLayout.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/RepoParserTestFileLayout.java index 592d07d50e..7b25749611 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/RepoParserTestFileLayout.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/RepoParserTestFileLayout.java @@ -42,38 +42,38 @@ public RepoParserTestFileLayout(ParserTestFileLayout layout) { } /** - * Sets the name of the repository + * Sets the name of the repository that will be locally cloned and used in tests */ public void setRepoName(String repoName) { this.repoName = repoName; } /** - * Sets the name of the root directory of the models + * Sets the name of the root directory of local repository clones that will be + * used in tests */ public void setRepoModelImplDirName(String repoModelImplDirName) { this.repoModelImplDirName = repoModelImplDirName; } /** - * Sets the name of the folder, where contents of {@link #resultCache} should be - * saved. Note: This folder does not have to directly contain the contents of - * {@link RepoTestResultCache}. They may be saved in sub-directories as well. + * Sets the name of the folder, where cached expected similarity results should + * be saved. Cached expected similarity results may be saved in sub-directories. */ public void setExpectedSimilarityResultCacheDirName(String expectedSimilarityResultCacheDirName) { this.expectedSimilarityResultCacheDirName = expectedSimilarityResultCacheDirName; } /** - * Sets the name of the file (with extension), where contents of - * {@link RepoTestResultCache} should be saved. + * Sets the name of the file (with extension), where cached expected similarity + * results should be saved. */ public void setExpectedSimilarityResultCacheFileName(String expectedSimilarityResultCacheFileName) { this.expectedSimilarityResultCacheFileName = expectedSimilarityResultCacheFileName; } /** - * @return The path to the saved contents of {@link RepoTestResultCache} + * @return The path, where cached expected similarity results should be saved */ public Path getExpectedSimilarityResultCachePath() { return this.getTestFilesSavePath().resolve(expectedSimilarityResultCacheDirName).resolve(this.repoName) @@ -81,7 +81,7 @@ public Path getExpectedSimilarityResultCachePath() { } /** - * @return The URI, at which the parsed commit's resource will point at. + * @return The URI, at which the parsed commit's model resource will point at. */ public URI getModelResourceSaveURIForCommit(String commitID) { return URI.createFileURI(this.getModelResourceSaveRootDirectory().toString()).appendSegment(this.repoName) @@ -113,8 +113,8 @@ public Path getRepoClonesDirPath() { } /** - * @implSpec Returns The path, at which the repository clone resides. Meant to - * be used for accessing the local repository clone. Use + * @implSpec Returns The path, at which the local repository clone resides. + * Meant to be used for accessing the local repository clone. Use * {@link #getRepoClonesDirPath()} while cloning instead, so that the * top-most folder of the repository is not duplicated. */ diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/RepoParserTestOptions.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/RepoParserTestOptions.java index d16e49fa54..6b60d5aa95 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/RepoParserTestOptions.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/RepoParserTestOptions.java @@ -3,12 +3,12 @@ import cipm.consistency.fitests.similarity.jamopp.parser.ParserTestOptions; /** - * A class that contains various options for test classes that parse - * {@link Resource} instances from GIT repositories, cache those resource - * instances, as well as compute and cache expected similarity results: + * A class that contains various options for test classes that parse model + * resources from GIT repositories, cache those model resource instances, as + * well as compute and cache expected similarity results: *
    - *
  • shouldDeleteRepositoryClones: Whether all cloned repositories should be - * removed after tests + *
  • shouldDeleteRepositoryClones: Whether all locally cloned repositories + * should be removed after tests *
  • shouldSaveCachedExpectedSimilarityResults: Whether the cached expected * similarity results should be saved after tests *
  • shouldUseCachedExpectedSimilarityResults: Whether the cached expected diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/RepoTimeMeasurementTag.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/RepoTimeMeasurementTag.java index d72460355b..30be6e38c4 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/RepoTimeMeasurementTag.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/RepoTimeMeasurementTag.java @@ -30,12 +30,12 @@ public enum RepoTimeMeasurementTag implements ITimeMeasurementTag { /** * A tag meant for time measurements from loading expected similarity results - * for similarity checking commits + * for similarity checking model resources of commits */ LOAD_EXPECTED_SIMILARITY_RESULTS, /** * A tag meant for time measurements from saving expected similarity results for - * similarity checking commits + * similarity checking model resources of commits */ SAVE_EXPECTED_SIMILARITY_RESULTS, diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/TeammatesRepoTest.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/TeammatesRepoTest.java index 1b7edffef7..fe46420780 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/TeammatesRepoTest.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/TeammatesRepoTest.java @@ -17,7 +17,7 @@ public class TeammatesRepoTest extends AbstractJaMoPPParserRepoTest { /** * The list of commits that will be parsed and compared to one another. All of - * them are pairwise different, i.e. all of them introduce code changes that + * them are pairwise non-similar, i.e. all of them introduce code changes that * break similarity (assuming test code is included). */ private static final List commitIDs = List.of("648425746bb9434051647c8266dfab50a8f2d6a3", diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/package-info.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/package-info.java new file mode 100644 index 0000000000..ecb0a913c3 --- /dev/null +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/package-info.java @@ -0,0 +1,9 @@ +/** + * Contains the means to parse Java models in form of {@link Resource} and + * {@link ResourceSet} instances from GIT repositories, along with an abstract + * test class {@link AbstractJaMoPPParserRepoTest} that integrates them.
    + *
    + * {@link cipm.consistency.fitests.repositorytests.util} package and + * sub-packages contains various utility constructs that are necessary in tests. + */ +package cipm.consistency.fitests.repositorytests; \ No newline at end of file diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/RepoCacheSimilarityResultProvider.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/RepoCacheSimilarityResultProvider.java index 625ad1b24a..800ad1d93a 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/RepoCacheSimilarityResultProvider.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/RepoCacheSimilarityResultProvider.java @@ -29,8 +29,7 @@ private String getCacheKeyForResource(Resource res) { } /** - * @implSpec Determines the expected similarity result based on the given result - * cache. + * @implSpec Determines the expected similarity result based on the given cache. */ @Override public boolean getExpectedSimilarityResultFor(Resource lhsRes, Path lhsResPath, Resource rhsRes, Path rhsResPath) { diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/RepoTestResultCache.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/RepoTestResultCache.java index 04b875fbc9..32c3818c79 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/RepoTestResultCache.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/RepoTestResultCache.java @@ -25,12 +25,13 @@ *
  • Transitivity: Assuming C1, C2 and C3 are different commits; if C1 and C2 * are similar, C2 and C3 are similar; then C1 and C3 should also be similar. *
      - *
    • Assuming C1, C2, ..., CN is commit chain; where for each sequential + *
    • Assuming C1, C2, ..., CN is commit chain, where for each sequential * commit pair {@code e_i = (C_i, C_i+1) = (C_i+1, C_i)} there are entries in * this instance; if any entry {@code e_i} has the expected result false (i.e. * non-similarity), the result computed via transitivity is considered invalid, * as there is no easy way to determine whether non-similar commits were - * reverted at some point, so that similarity between C1 and CN is re-achieved. + * effectively reverted at some point, so that similarity between C1 and CN is + * re-achieved. *
    • It is further assumed that if an entry chain between 2 commits * consists only of entries indicating similarity (i.e. expectedResult = true), * all such entry chains will. If this is not fulfilled, expected result @@ -180,16 +181,16 @@ public Boolean getDirectResult(String commitID1, String commitID2) { * upon finding any such entry chain, even if there are further chains, which * include entries indicating non-similarity.
      *
      - * Returns Boolean instead of boolean, because it is only possible to determine - * similarity by using transitivity. In case of non-similarity, this method + * Returns Boolean instead of boolean, because transitivity may only be used to + * detect similarity, not non-similarity. In case of non-similarity, this method * returns NULL instead of FALSE, to signal that transitivity yields no accurate * result. * * @return TRUE, if there exists a chain of entries between the given commits, * such that all entries indicate similarity, or the given commits are - * equal. Said entry chain may also only consist of a single entry for - * the given commits. NULL, if there were no entry chains from commitID1 - * to commitID2, where all entries indicate similarity. + * equal. Said entry chain may also only consist of a single, direct + * entry for the given commits. NULL, if there were no entry chains from + * commitID1 to commitID2, where all entries indicate similarity. */ public Boolean getTransitiveResult(String commitID1, String commitID2) { if (commitID1.equals(commitID2)) { @@ -328,8 +329,8 @@ public void clear() { } /** - * @return The entry for the commits with the given commit IDs. Accounts for - * symmetry property. + * @return The entry for the commits with the given commit IDs. Accounts only + * for the symmetry property. */ protected SimilarityResultEntry getEntryFor(String commitID1, String commitID2) { var entryOpt = this.similarityResults.stream().filter((e) -> e.isEntryFor(commitID1, commitID2)).findFirst(); diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/RepoTestSimilarityValueEstimator.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/RepoTestSimilarityValueEstimator.java index 168f517f1d..2a2dd73cda 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/RepoTestSimilarityValueEstimator.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/RepoTestSimilarityValueEstimator.java @@ -22,8 +22,7 @@ * re-using various GIT elements.
      *
      * Uses {@link QuickCommentRemover}, which removes commentaries in an - * approximative fashion. Therefore, the computed results may be - * misleading. + * approximative fashion. Therefore, the computed results may be inaccurate. * * @author Alp Torac Genc */ @@ -36,7 +35,10 @@ public class RepoTestSimilarityValueEstimator { * @param df The {@link DiffFormatter} that created diffEntries * @param diffEntries A list of {@link DiffEntry} instances from diffing 2 * commits C1 and C2 - * @return Whether model resources parsed from C1 and C2 are similar + * @return Whether model resources parsed from C1 and C2 are similar according + * to this instance + * + * TODO Fix the regex used in the "code" local variable */ public boolean getExpectedSimilarityValueFor(OutputStream os, DiffFormatter df, List diffEntries) { try (var outputStream = os; var diffFormatter = df) { @@ -59,7 +61,8 @@ public boolean getExpectedSimilarityValueFor(OutputStream os, DiffFormatter df, /** * @param diffEntries A list of {@link DiffEntry} instances from diffing 2 * commits C1 and C2 - * @return Whether model resources parsed from C1 and C2 are similar + * @return Whether model resources parsed from C1 and C2 are similar according + * to this instance */ public boolean getExpectedSimilarityValueFor(List diffEntries) { try (var os = new ByteArrayOutputStream()) { @@ -101,7 +104,8 @@ public boolean getExpectedSimilarityValueFor(Git git, AbstractTreeIterator oldTr * given commits * @param commitID1 A commit from git * @param commitID2 Another commit from git - * @return Whether model resources parsed from the given commits are similar. + * @return Whether model resources parsed from the given commits are similar + * according to this instance */ public boolean getExpectedSimilarityValueFor(Git git, String commitID1, String commitID2) { try (var reader = git.getRepository().newObjectReader()) { @@ -140,8 +144,13 @@ public List getEffectiveLines(String text) { /** * Computes whether applying the changes in the given diff DOES NOT introduce - * any changes to the effective code. Assuming the given diff is computed by - * comparing the commits oldCommit and newCommit: + * any changes to the effective code, i.e. code without commentary and without + * whitespaces. This is the case, if all inserting lines combined and all + * removing lines combined are textually equal, such that applying the diff + * patch results in the same effective code.
      + *
      + * Assuming the given diff is computed by comparing the commits oldCommit and + * newCommit: *
        *
      • true: oldCommit is still similar to newCommit, without applying the diff * patch script on oldCommit @@ -149,7 +158,8 @@ public List getEffectiveLines(String text) { * that oldCommit and newCommit are not similar *
      * - * @param lines The lines from a given diff patch script, without any metadata + * @param lines The effective code lines from a given diff patch script, without + * any metadata */ public boolean computeExpectedSimilarityValue(List lines) { var added = new ArrayList(); @@ -179,10 +189,7 @@ public int getContextLineCount() { } /** - * Sets the number of context lines that will be considered while diffing, if no - * {@link DiffFormatter} is explicitly provided. Defaults to - * {@value #defaultContextLineCount}, unless re-set via - * {@link #setContextLineCount(int)}. + * {@link #getContextLineCount()} */ public void setContextLineCount(int contextLineCount) { this.contextLineCount = contextLineCount; diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/AbstractSimilarityTest.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/AbstractSimilarityTest.java index a2d31a2d46..781ce6ff97 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/AbstractSimilarityTest.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/AbstractSimilarityTest.java @@ -6,10 +6,7 @@ import org.junit.jupiter.api.BeforeEach; /** - * An abstract class for similarity checking tests to extend.
      - *
      - * Contains methods that provide information on the next test method to be run - * and various delegation methods that spare call chains. + * An abstract class for similarity checking tests to extend. * * @author Alp Torac Genc */ @@ -27,8 +24,8 @@ public abstract class AbstractSimilarityTest { * errors caused by the order of set up operations.
      *
      * {@link AbstractSimilarityTest}: Sets up the underlying - * {@link ISimilarityCheckerContainer}, which will be used for - * {@link #isSimilar(Object, Object)} and + * {@link ISimilarityCheckerContainer}, which will be used for similarity + * checking through {@link #isSimilar(Object, Object)} and * {@link #areSimilar(Collection, Collection)}. */ @BeforeEach @@ -113,6 +110,9 @@ public Boolean areSimilar(Collection elements1, Collection elements2) { } /** + * Use this method to retrieve the currently running test class' name for + * consistency. + * * @return The name of the currently running test class. */ public String getCurrentTestClassName() { diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/eobject/AbstractEObjectSimilarityTest.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/eobject/AbstractEObjectSimilarityTest.java index 273f6f2c31..7ee7436b81 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/eobject/AbstractEObjectSimilarityTest.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/eobject/AbstractEObjectSimilarityTest.java @@ -40,7 +40,7 @@ public void setUp() { /** * {@inheritDoc}
      *
      - * {@link AbstractEObjectSimilarityTest}: Sets {@link #getResourceHelper()}, + * {@link AbstractEObjectSimilarityTest}: Sets * {@link #getResourceParsingStrategy()} and {@link #getResourceTestOptions()} * to null, in order to ensure that each test has freshly created instances. */ @@ -53,31 +53,59 @@ public void tearDown() { super.tearDown(); } + /** + * @return An object that has the means to parse {@link ResourceSet} instances + * from model source files + */ protected AbstractResourceParsingStrategy getResourceParsingStrategy() { return this.parsingStrat; } + /** + * @param parsingStrat {@link #getResourceParsingStrategy()} + */ protected void setResourceParsingStrategy(AbstractResourceParsingStrategy parsingStrat) { this.parsingStrat = parsingStrat; } + /** + * @return An object that contains various test configurations, especially those + * concerning {@link Resource} instances + */ protected ResourceTestOptions getResourceTestOptions() { return this.resourceTestOptions; } + /** + * @param resourceTestOptions {@link #getResourceTestOptions()} + */ protected void setResourceTestOptions(ResourceTestOptions resourceTestOptions) { this.resourceTestOptions = resourceTestOptions; } + /** + * Cleans all status information regarding how {@link Resource} instances are + * parsed from model source files + */ protected void cleanUpResourceParsingStrategy() { this.parsingStrat = null; } + /** + * Cleans all test configurations, especially those concerning {@link Resource} + * instances + */ protected void cleanUpResourceTestOptions() { this.resourceTestOptions = null; } + /** + * @return {@link #getResourceTestOptions()} + */ protected abstract ResourceTestOptions initResourceTestOptions(); + /** + * @return {@link #getResourceParsingStrategy()} + */ protected abstract AbstractResourceParsingStrategy initResourceParsingStrategy(); } diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/eobject/AbstractResourceParsingStrategy.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/eobject/AbstractResourceParsingStrategy.java index 0457d10ae7..48827d8d44 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/eobject/AbstractResourceParsingStrategy.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/eobject/AbstractResourceParsingStrategy.java @@ -10,7 +10,7 @@ /** * An abstract class meant to be extended by classes that envelop the means to - * parse Resource instances from (original) model files.
      + * parse Resource instances from model source files.
      *
      * Implementors are expected to: *
        @@ -132,11 +132,13 @@ protected void preConstructionSetup() { /** * Parses a ResourceSet for the model at given path. * - * @param modelDir The path to a given model. Refer to the concrete - * implementation for more information on where this path is - * supposed to point at. + * TODO Rename parameter + * + * @param modelDir The path to a given model source file directory. Refer to the + * concrete implementation for more information on where this + * path is supposed to point at. * @return A ResourceSet that contains all parsed Resource instances for the - * given model path. + * given model source file directory path. */ public abstract ResourceSet parseModelResource(Path modelDir); diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/eobject/ResourceHelper.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/eobject/ResourceHelper.java index c6f5a3cb6a..417f905eab 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/eobject/ResourceHelper.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/eobject/ResourceHelper.java @@ -72,7 +72,7 @@ public static Resource createResource(Collection eos, Resourc * Adds the extension to factory mapping into * {@link Resource.Factory.Registry}.
        *
        - * Said entry denotes that resources with the given extension are saved using + * Said entry denotes that resources with the given extension are created using * the given factory. * * @see {@link #setDefaultResourceRegistry()} @@ -84,6 +84,8 @@ public static void setResourceRegistry(String extension, Object factory) { /** * Attempts to save the given resource instance. Instead of throwing exceptions, * returns true/false to indicate success/failure. + * + * TODO Log the error message */ public static boolean saveResource(Resource res) { var uri = res.getURI(); @@ -113,6 +115,8 @@ public static boolean saveResourceIfNotSaved(Resource res) { /** * Loads the given resource + * + * TODO Log error message */ public static void loadResource(Resource res) { try { @@ -150,7 +154,7 @@ public static Resource loadResource(Path resourcePath) { } /** - * @param resSet The resource ste, which will contain the created resource + * @param resSet The resource set, which will contain the created resource * @param resourceURI The URI, where the resource points at * @return An empty resource inside the given resource set, with the given URI */ @@ -160,7 +164,7 @@ public static Resource createResource(ResourceSet resSet, URI resourceURI) { /** * @param resourceURI The URI, where the resource points at - * @return An empty resource, inside a freshly created resource set, with the + * @return An empty resource inside a freshly created resource set, with the * given URI */ public static Resource createResource(URI resourceURI) { @@ -187,6 +191,8 @@ public static boolean resourceFileExists(URI resURI) { /** * Deletes the given resource * + * TODO Log error message + * * @return Whether the file of the given resource is deleted. */ public static boolean deleteResource(Resource res) { diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/eobject/package-info.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/eobject/package-info.java index 422e0aa10f..009815e743 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/eobject/package-info.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/eobject/package-info.java @@ -1,5 +1,6 @@ /** * Contains {@link EObject} and {@link Resource} extensions for - * {@link cipm.consistency.fitests.similarity}. + * {@link cipm.consistency.fitests.similarity}, as well as a utility class for + * Resource related operations {@link ResourceHelper}. */ package cipm.consistency.fitests.similarity.eobject; \ No newline at end of file diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/AbstractJaMoPPSimilarityTest.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/AbstractJaMoPPSimilarityTest.java index 913185e881..074499828e 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/AbstractJaMoPPSimilarityTest.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/AbstractJaMoPPSimilarityTest.java @@ -5,9 +5,7 @@ /** * An abstract test class that extends {@link AbstractEObjectSimilarityTest} - * with concrete method implementations for JaMoPP context, as well as static - * methods that can be used in parameterised tests to generate initialiser - * instances. + * with concrete method implementations for JaMoPP context. * * @author Alp Torac Genc */ diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/JaMoPPResourceParsingStrategy.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/JaMoPPResourceParsingStrategy.java index 9349f7539a..f1b1e239a3 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/JaMoPPResourceParsingStrategy.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/JaMoPPResourceParsingStrategy.java @@ -14,11 +14,10 @@ /** * A class that uses {@link JaMoPPJDTSingleFileParser} to parse Java model * Resources. Provides methods for performing {@link TrivialRecovery} in cases, - * where bindings are used.
        - *
        + * where bindings are used. *
          - *
        • Given model paths should point at the top-most directory of the Java - * project + *
        • Given model source file directory paths should point at the top-most + * directory of the Java project *
        • Supports Regex expressions for model paths as exclusion patterns *
        * diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/package-info.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/package-info.java index 99370c6111..ec662a4a67 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/package-info.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/package-info.java @@ -1,9 +1,6 @@ /** * Contains test classes that can be used to test the similarity checking of - * Java-model elements, which are stored and represented by {@link EObject} - * implementors present in JaMoPP.
        - *
        - * Also contains some general tests, which do not target specific - * {@link EObject} types. + * Java model elements, which are represented by {@link EObject} implementors + * present in JaMoPP. */ package cipm.consistency.fitests.similarity.jamopp; \ No newline at end of file diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/AbstractJaMoPPParserSimilarityTest.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/AbstractJaMoPPParserSimilarityTest.java index 2fd174488f..1cbbff022d 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/AbstractJaMoPPParserSimilarityTest.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/AbstractJaMoPPParserSimilarityTest.java @@ -31,13 +31,23 @@ /** * An abstract test class, which can be used for implementing tests that involve - * parsing models from Java-related files and checking their similarity.
        + * parsing models from Java model source files and checking their similarity. + *
        *
        * It does not include any hard-coded model source file directory to allow - * models at different locations to be usable in tests. If there is a group of - * model source file directories, it is recommended to make an abstract test - * class for them, in order to store details about the common sub-path of those - * models and details on what directories contain model source files. + * models at different locations to be parsed and used in tests. If certain + * groups of model source file directories are to be used in tests, it is + * recommended to make an abstract test class for them for storing their common + * details.
        + *
        + * Note: Since dynamic tests are used here, the + * {@link org.junit.jupiter.api.BeforeEach} and + * {@link org.junit.jupiter.api.AfterEach} methods will be triggered only + * once at the start / end of each test method annotated with + * {@link org.junit.jupiter.api.TestFactory} , as opposed to before / + * after each dynamic test. In that sense, they are similar to their static + * versions {@link org.junit.jupiter.api.BeforeAll} and + * {@link org.junit.jupiter.api.AfterAll} method. * * @author Alp Torac Genc * @@ -45,42 +55,43 @@ */ public abstract class AbstractJaMoPPParserSimilarityTest extends AbstractJaMoPPSimilarityTest { /** - * An object that caches and grants access to the parsed models, which were - * cached after being parsed.
        + * An object that caches and grants access to parsed models, which were cached + * after being parsed.
        *
        - * Make sure that it persists throughout tests, which are supposed to make use - * of it. + * Make sure that the {@link CacheUtil} instance persists throughout tests, + * which are supposed to make use of it. * * @see {@link #parseModelsDirWithoutCaching(Path)} * @see {@link #parseModelsDirWithCaching(Path)} */ private static final CacheUtil resourceCache = new CacheUtil(); + /** + * @see {@link #getTestFileLayout()} + */ private ParserTestFileLayout layout; /** - * The relative path to the directory, where parsed model resource files are to - * be saved (if desired). + * @see {@link ParserTestFileLayout#setTestModelResourceFilesSaveDirPath(Path)} */ private static final Path testModelResourceFilesSaveDirPath = Path.of("target", "testResources"); /** - * The relative path to the directory, where the contents of - * {@link #resourceCache} are to be saved (if desired). + * @see {@link ParserTestFileLayout#setTestModelResourceFilesSaveDirPath(Path)} */ private static final Path cacheSaveDirPath = testModelResourceFilesSaveDirPath.resolve("testmodel-cache"); /** - * The relative path to the directory, where time measurements are to be saved - * (if desired). + * @see {@link ParserTestFileLayout#setTimeMeasurementsFileSavePath(Path)} */ private static final Path timeMeasurementsFileSavePath = Path.of("target", "timeMeasurements"); /** * {@inheritDoc}
        *
        - * {@link AbstractJaMoPPParserSimilarityTest}: Sets up the file layout - * {@link ParserTestFileLayout} + * {@link AbstractJaMoPPParserSimilarityTest}: Sets up the file layout for the + * test {@link ParserTestFileLayout}. See + * {@link AbstractJaMoPPParserSimilarityTest} for more information. */ @BeforeEach @Override @@ -99,14 +110,11 @@ public void setUp() { * {@inheritDoc}
        *
        * {@link AbstractJaMoPPParserSimilarityTest}: Performs various operations on - * the model resource files that were parsed in the dynamic tests, according to - * the preferences that are encoded in the methods of this test, such as + * model resources that were parsed in the dynamic tests, according to the + * preferences that are encoded in the methods of this test, such as * {@link AbstractJaMoPPParserSimilarityTest#shouldSaveCachedResources()}. It - * then saves the time measurements taken during the tests. Note: Since - * dynamic tests are used here, this method will be triggered only once at the - * end of each test method annotated with - * {@link org.junit.jupiter.api.TestFactory}, as opposed to after each dynamic - * test. + * then saves the time measurements taken during the tests. See + * {@link AbstractJaMoPPParserSimilarityTest} for more information. */ @AfterEach @Override @@ -171,10 +179,20 @@ public void tearDown() { SimilarityTestLogger.logDebugMsg("Tore down after parser test", this.getClass()); } + /** + * Returns a builder for {@link ParserTestTimeMeasurementKey} instances, which + * should be included to time measurements to describe what they are taken from. + * + * @return An object that can be used to construct + * {@link ParserTestTimeMeasurementKey} instances + */ protected ParserTestTimeMeasurementKeyBuilder getTimeMeasurementKeyBuilder() { return new ParserTestTimeMeasurementKeyBuilder(); } + /** + * @return Creates the value of {@link #getTestFileLayout()} + */ protected ParserTestFileLayout initParserTestFileLayout() { var layout = new ParserTestFileLayout(); layout.setModelSourceFileRootDirPath(new File("").getAbsoluteFile().toPath()); @@ -185,6 +203,9 @@ protected ParserTestFileLayout initParserTestFileLayout() { return layout; } + /** + * @return An object encapsulating the file layout for the test + */ protected ParserTestFileLayout getTestFileLayout() { return this.layout; } @@ -205,6 +226,10 @@ protected Path getTimeMeasurementSavePathForCurrentTestClass() { return this.getTestFileLayout().getTimeMeasurementsFileSavePath().resolve(fileName); } + /** + * Sets up {@link ParserTestTimeMeasurer} for taking time measurements. Should + * be called prior to taking time measurements. + */ protected void setupForTimeMeasurements() { ParserTestTimeMeasurer.getInstance().setDataStructure(new DefaultTimeMeasurementDataStructure()); ParserTestTimeMeasurer.getInstance().setMeasuringStrat(new StopwatchStrategy()); @@ -213,8 +238,7 @@ protected void setupForTimeMeasurements() { } /** - * Saves the time measurements taken during tests via - * {@code startTimeMeasurement} and {@code stopTimeMeasurement} calls. + * Saves the time measurements taken during tests. */ protected void saveTimeMeasurements() { SimilarityTestLogger.logDebugMsg("Saving time measurements", this.getClass()); @@ -224,16 +248,11 @@ protected void saveTimeMeasurements() { } /** - * Delegates to the time measuring mechanism and signals that a time measurement - * with the given parameters should be started.
        + * Delegates to {@link ParserTestTimeMeasurer}. Refer to the documentation of + * {@link ParserTestTimeMeasurer} for more information.
        *
        - * Refer to the documentation of {@link ParserTestTimeMeasurer} for more - * information. - * - * @param key The key of the taken time measurement, which describes what the - * time measurement is taken from - * @param tag The tag of the time measurement, which is used to group time - * measurements + * Complements the (so far) built {@link ParserTestTimeMeasurementKey} instance + * with information about this test, finishes building it and delegates it. */ protected void startTimeMeasurement(ParserTestTimeMeasurementKeyBuilder keyBuilder, ITimeMeasurementTag tag) { ParserTestTimeMeasurer.getInstance() @@ -250,25 +269,16 @@ protected void startTimeMeasurement(ITimeMeasurementTag tag) { } /** - * Delegates to the time measuring mechanism and signals that the most recently - * started time measurement (via - * {@link #startTimeMeasurement(String, ITimeMeasurementTag)}) should be - * stopped.
        - *
        - * This method is to be seen as the closing bracket for the opening bracket - * {@link #startTimeMeasurement(String, ITimeMeasurementTag)}, such that the - * time elapsed while executing the lines between that method call and this - * method call is the time measurement. Not using them similar to brackets will - * result in inaccurate measurements.
        - *
        - * Refer to the documentation of {@link ParserTestTimeMeasurer} for more - * information. + * Delegates to {@link ParserTestTimeMeasurer}. Refer to the documentation of + * {@link ParserTestTimeMeasurer} for more information. */ protected void stopTimeMeasurement() { ParserTestTimeMeasurer.getInstance().stopTimeMeasurement(); } /** + * TODO Remove once FileUtil is a singleton + * * @return A utility object that can be used to perform file operations. */ protected FileUtil getFileUtil() { @@ -284,13 +294,18 @@ protected CacheUtil getCacheUtil() { } /** - * Parses all Java-Model files under the given directory into a {@link Resource} - * instance. Uses no means of caching.
        + * Parses all model source files under the given model source file directory + * into a {@link Resource} instance. Uses no means of caching.
        *
        - * Note: This method will parse ALL such files. Therefore, the given model - * directory should only contain one Java-Model. + * Note: This method will only parse one model from all model source files. + * Therefore, the given model source file directory should only belong to one + * model. + * + * TODO Rename parameter and parameters of all variants TODO Rename method and + * all variants of it (?) * - * @param modelDir A directory that contains all files of a model + * @param modelDir A model source file directory that contains all model source + * files of a (and only one) model * * @see {@link #isResourceRelevant()} * @see {@link #prepareArtificialResource(Resource, URI)} @@ -395,6 +410,8 @@ protected IModelResourceWrapper parseModelsDirWithCaching(Path modelDir, URI cac } /** + * TODO Rename parameter + * * @param modelDir A directory that directly contains the Java-model files * @return The test display name for the given modelPath */ @@ -411,10 +428,10 @@ protected String getDisplayNameForModelDir(Path modelPath) { * Defaults to using {@link #isModelSourceFileDirectoryName(String)} on the file * name. Check the concrete implementation for more details. * - * @param f The file object representing the directory + * @param f The file object representing the model source file directory * - * @return Whether a given directory contains any Java elements, from which a - * Java model can be parsed. + * @return Whether a given (possible) model source file directory contains any + * Java elements, from which a Java model can be parsed. */ protected boolean isModelSourceFileDirectory(File f) { return this.isModelSourceFileDirectoryName(f.getName()); @@ -440,7 +457,7 @@ public Collection createTests(Resource[] resArr) { /** * Parses model resources (with caching) for each given path. * - * @param pathArr An array of paths to model directories + * @param pathArr An array of paths to model source file directories * @return Dynamic test instances for the models under the given paths * @see {@link #createTests()} */ @@ -455,7 +472,7 @@ public Collection createTests(Path[] pathArr) { } /** - * @param pathArr An array of paths to model directories + * @param pathArr An array of paths to model source file directories * @param resArr An array of parsed model resources * @return Dynamic test instances for the given model resources * @see {@link #createTests()} @@ -486,9 +503,10 @@ public Collection createTests(Path[] pathArr, Resource[] resArr) { } /** - * Generates dynamic tests for each model directories based on the registered - * {@link AbstractJaMoPPParserSimilarityTestFactory} instances. Implemented here - * in efforts to have a unified template for dynamic test generation.
        + * Generates dynamic tests for each model source file directories based on the + * registered {@link AbstractJaMoPPParserSimilarityTestFactory} instances. + * Implemented here in efforts to have a unified template for dynamic test + * generation.
        *
        * Can be overridden in implementors; in order to add preparatory actions, * clean up actions or to change the default test generation. DUE TO HOW @@ -499,8 +517,8 @@ public Collection createTests(Path[] pathArr, Resource[] resArr) { * {@link TestFactory}, which will run the tests generated here. * * @see {@link #discoverModelSourceFileDirsAt(Path)} and - * {@link #discoverModelSourceParentDirsAt(Path)} for locating model - * directories + * {@link #discoverModelSourceParentDirsAt(Path)} for locating model source + * file directories * @see {@link TestFactory} for what tests are to be generated */ @TestFactory @@ -542,14 +560,14 @@ public Collection createTests() { * concrete implementors. * * @return Factories of tests that should be generated for each relevant model - * directories. + * source file directories. */ protected abstract Collection getTestFactories(); /** * @param rootPath The top-most directory, whose contents should be scanned for - * model directories - * @return A collection of model directory paths under rootPath + * model source file directories + * @return A collection of model source file directory paths under rootPath */ protected Collection discoverModelSourceFileDirsAt(Path rootPath) { var discoveryStrat = new ModelDirDiscoveryStrategy((f) -> this.isModelSourceFileDirectory(f)); @@ -563,8 +581,8 @@ protected Collection discoverModelSourceFileDirsAt(Path rootPath) { /** * @param rootPath The top-most directory, whose contents should be scanned for - * directories containing model directories. - * @return A collection of paths of directories containing model directory under + * directories containing model source parent directories. + * @return A collection of paths of model source parent directories under * rootPath */ protected Collection discoverModelSourceParentDirsAt(Path rootPath) { @@ -580,8 +598,7 @@ protected Collection discoverModelSourceParentDirsAt(Path rootPath) { /** * Check the concrete implementation for more details. * - * @param dirName The name of the directory, which potentially contains files of - * a model + * @param dirName The name of the potential model source file directory * * @return Whether a given directory contains any Java elements, from which a * Java model can be parsed. diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/CacheUtil.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/CacheUtil.java index ed3836daec..7bef7d32ba 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/CacheUtil.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/CacheUtil.java @@ -8,12 +8,10 @@ import org.eclipse.emf.ecore.resource.Resource; /** - * A utility object, which encapsulates caching logic (for parsed models) and - * can be used to hasten tests.
        + * Encapsulates caching logic for model resources and can be used to hasten + * tests.
        *
        - * Only used to contain {@link Resource} instances with String keys. Does not - * process the given resources in any other way, such as unloading or removing - * them. + * Only used to contain {@link Resource} instances with String keys. * * @author Alp Torac Genc */ @@ -27,7 +25,7 @@ public CacheUtil() { /** * This is used from within the constructor. * - * @return The underlying map, which will be used to store the parsed models. + * @return The underlying map, which will be used to store model resources. */ protected Map initResourceCache() { return new HashMap<>(); @@ -43,34 +41,35 @@ protected Map getResourceCache() { } /** - * Adds the given resource wrapper with the given key to the cache. Replaces the - * resource, if the key is already in the cache. + * Adds the given model resource wrapper with the given key to the cache. + * Replaces the resource, if the key is already in the cache. * * @param key The key associated with the given resource wrapper - * @param res A given resource + * @param res A given model resource wrapper */ public void addToCache(String key, IModelResourceWrapper res) { this.getResourceCache().put(key, res); } /** - * @return Gets the wrapper of the resource associated with the given key from - * the cache. Null, if there is no such key in the cache. + * @return Gets the model resource wrapper of the resource associated with the + * given key from the cache. Null, if there is no such key in the cache. */ public IModelResourceWrapper getFromCache(String key) { return this.getResourceCache().get(key); } /** - * @return Wrappers of all cached resources, without their corresponding keys + * @return Wrappers of all cached model resources, without their corresponding + * keys */ public Collection getCachedResources() { return new ArrayList(this.getResourceCache().values()); } /** - * @return All contents of the underlying cache (i.e. cached resources and their - * corresponding keys) + * @return All contents of the underlying cache (i.e. cached model resources and + * their corresponding keys) */ public Map getAllCacheContent() { return new HashMap(this.getResourceCache()); @@ -84,14 +83,14 @@ public boolean isInCache(String key) { } /** - * Removes the cached resource associated with the given key. + * Removes the cached model resource associated with the given key. */ public void removeFromCache(String key) { this.getResourceCache().remove(key); } /** - * Removes all entries from the cache. + * Removes all model resources and their key from the cache. */ public void cleanCache() { this.getResourceCache().clear(); diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/FileUtil.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/FileUtil.java index f52ab299cd..2ad1b3170e 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/FileUtil.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/FileUtil.java @@ -11,6 +11,8 @@ /** * A utility class that contains file-related operations. * + * TODO Turn into a singleton + * * @author Alp Torac Genc */ public class FileUtil { @@ -64,6 +66,8 @@ public boolean filesEqual(File f1, File f2) { } /** + * TODO Use Files.walk instead, if possible + * * Recursively checks the equality of the given directories, based on their * effective content (i.e. the files/sub-directories they contain and the * contents of those files without whitespaces). diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/IModelDirDiscoveryStrategy.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/IModelDirDiscoveryStrategy.java index fcbe38f918..425f698b25 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/IModelDirDiscoveryStrategy.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/IModelDirDiscoveryStrategy.java @@ -5,26 +5,25 @@ import java.util.Collection; /** - * An interface for classes meant to find model directories. How models' source - * files' directories are discovered and filtered depends on the concrete - * implementor.
        - *
        - * Implemented minimally, as discovering model directories may span across - * multiple "root" directories, and may have to be adapted heavily for concrete - * scenarios. + * An interface for classes meant to find model source parent directories and + * model source file directories. The method of discovery depends on the + * concrete implementor. + * + * TODO Rename interface TODO Rename parameters * * @author Alp Torac Genc */ public interface IModelDirDiscoveryStrategy { /** - * Finds and returns paths to all parent directories, which have nested model - * source file directories. Use {@link #discoverModelSourceDirs(File)} on the - * directories found here to get the actual model source file directories. + * Finds and returns paths to all model source parent directories. Use + * {@link #discoverModelSourceDirs(File)} on the directories found here to get + * the model source file directories. * * @param dirToDiscover The top-most directory, whose contents will be scanned + * for model source parent directories * - * @return All parent directories containing model source file directories that - * are found according to the concrete implementor. + * @return All model source parent directories containing model source file + * directories that are found according to the concrete implementor. */ public Collection discoverModelSourceParentDirs(File dirToDiscover); @@ -32,6 +31,7 @@ public interface IModelDirDiscoveryStrategy { * Finds and returns paths to all model source file directories. * * @param dirToDiscover The top-most directory, whose contents will be scanned + * for model source file directories * * @return All model source file directories that are found according to the * concrete implementor @@ -39,10 +39,9 @@ public interface IModelDirDiscoveryStrategy { public Collection discoverModelSourceDirs(File dirToDiscover); /** - * @param dir A directory that potentially contains source files of one (and - * only one) model - * @return Whether the given directory is contains source files of one (and only - * one) model + * @param dir A potential model source file directory that contains model source + * files of one (and only one) model + * @return Whether the given directory is a model source file directory */ public boolean isModelSourceDirectory(File dir); } diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/IModelResourceWrapper.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/IModelResourceWrapper.java index efec033b6e..0e77712daf 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/IModelResourceWrapper.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/IModelResourceWrapper.java @@ -12,25 +12,25 @@ *
        * Concrete implementors should consider only one primary model resource * (referred as model resource in methods), which contains all direct contents - * of all model files, and grant access to it via {@link #getModelResource()}. - * They may, however, choose to split contents that are required by the model - * resource into separate Resources. Such Resources should also be parsed within - * {@link #parseModelResource(Path, URI)}. They are then loaded automatically on - * demand by the internals of EMF-Framework. Therefore, - * {@link #loadModelResource(URI)} should only load the model resource. + * of all model source files, and grant access to it via + * {@link #getModelResource()}. They may, however, choose to split contents that + * are required by the model resource into separate Resources. Such Resources + * should also be parsed within {@link #parseModelResource(Path, URI)}. They are + * then loaded automatically on demand by the internals of EMF-Framework. + * Therefore, {@link #loadModelResource(URI)} should only load the model + * resource. * * @author Alp Torac Genc */ public interface IModelResourceWrapper { /** - * Parses all Java-Model files under the given directory. The parsed model - * resource can be accessed via {@link #getModelResource()}. + * Parses all Java-Model source files under the given model source file + * directory. The parsed model resource can be accessed via + * {@link #getModelResource()}. * - * @param modelDir A directory that contains all files of a model + * @param modelDir A model source file directory * @param modelResourceURI The URI that the parsed model resource will reside * at, once saved - * @param parser The parser that will be used to parse the model - * resource and all other necessary resources */ public void parseModelResource(Path modelDir, URI modelResourceURI); @@ -88,7 +88,7 @@ public interface IModelResourceWrapper { /** * Sets the URIs of all parsed resources with respect to the given URI, which * will be assigned to the parsed model resource that contains all direct - * contents of the model files. + * contents of the model source files. * * @param newParsedModelResourceURI The new URI of the parsed model resource * ({@link #getModelResource()} in this case) @@ -96,8 +96,8 @@ public interface IModelResourceWrapper { public void setModelResourcesURI(URI newParsedModelResourceURI); /** - * @return The model resource, which contains all contents of all (directly) - * parsed model files + * @return The model resource, which contains all direct contents of all parsed + * model source files */ public Resource getModelResource(); diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/JaMoPPModelResourceWrapper.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/JaMoPPModelResourceWrapper.java index c51e5bd2dc..7bf2173ff2 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/JaMoPPModelResourceWrapper.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/JaMoPPModelResourceWrapper.java @@ -21,12 +21,16 @@ *
      • Merged model resource: Contains all direct contents of the model files * (i.e. the Java code directly present in model files) *
      • Artificial resource: Contains all contents that are required by the - * merged model resource, but are not directly present in model files, such as - * contents of native Java libraries and synthetic elements. + * merged model resource, but are not directly present in model source files, + * such as contents of native Java libraries and synthetic elements. Whether + * Artificial resource is split from merged resource is controlled with + * {@link #setSplitArtificialResource(boolean)}. *
      * The main purpose of this class is to make operations on parsed model * resources, and other resources parsed in the process, tidier. * + * TODO Add override tags, remove redundant commentary + * * @author Alp Torac Genc */ public class JaMoPPModelResourceWrapper implements IModelResourceWrapper { @@ -56,7 +60,7 @@ public class JaMoPPModelResourceWrapper implements IModelResourceWrapper { private Resource mergedModelResource; /** * The artificial resource, which contains all contents required by the merged - * model resource that were not directly present in the model files + * model resource that were not directly present in the model source files */ private Resource artificialResource; @@ -113,7 +117,7 @@ protected URI getArtificialResourceURI(URI correspondingResourceURI) { *
      * If {@link #isSplitArtificialResource()}, moves all non-direct model resources * (i.e. model resources that are not a part of directModelResources), into the - * created ArtificialResource. This way, direct model elements inside + * created ArtificialResource. This way, direct model resource contents inside * directModelResources can be compared more efficiently, since the non-direct * model resources will likely be excluded from the comparison. * @@ -122,10 +126,10 @@ protected URI getArtificialResourceURI(URI correspondingResourceURI) { * created for this ResourceSet, within this * ResourceSet. * @param directModelResources A list of model resources, which were directly - * parsed from the contents of the model source - * files. This list should not include any - * dependency, which is not a direct part of the - * model (such as Java native libraries). + * parsed from model source files. This list should + * not include any dependency, which is not a + * direct part of the model (such as Java native + * libraries). * @param artificialResourceURI The URI, which the created ArtificialResource * will have. ArtificialResource will be saved at * that URI, if desired. @@ -192,14 +196,16 @@ protected Resource prepareArtificialResource(ResourceSet modelResourceSet, List< } /** - * Parses all Java-Model files under the given directory into a {@link Resource} - * instance (merged model resource). Uses no means of caching. The parsed merged - * model resource can be accessed via {@link #getModelResource()}.
      + * Parses all Java-Model source files under the given model source file + * directory into a {@link Resource} instance (merged model resource). Uses no + * means of caching. The parsed merged model resource can be accessed via + * {@link #getModelResource()}.
      *
      * Note: This method will parse ALL such files. Therefore, the given model - * directory should only contain one Java-Model. + * source file directory should only contain one Java-Model.
      * - * @param modelDir A directory that contains all files of a model + * @param modelDir A model source file directory that contains all files + * of a model * @param modelResourceURI The URI that the parsed model resource will reside * at, once saved */ @@ -383,7 +389,7 @@ public boolean loadParsedResources() { /** * Sets the URIs of all parsed resources with respect to the given URI, which * will be assigned to the parsed model resource that contains all direct - * contents of the model files. + * contents of the model source files. * * @param newParsedModelResourceURI The new URI of the parsed model resource * ({@link #getModelResource()} in this case) @@ -399,7 +405,7 @@ public void setModelResourcesURI(URI newParsedModelResourceURI) { /** * @return The merged model resource, which contains all contents of all - * (directly) parsed model files + * (directly) parsed model source files */ public Resource getModelResource() { return mergedModelResource; diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ModelDirDiscoveryStrategy.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ModelDirDiscoveryStrategy.java index 8a56793cee..1b0bb201c4 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ModelDirDiscoveryStrategy.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ModelDirDiscoveryStrategy.java @@ -7,10 +7,12 @@ import java.util.function.Predicate; /** - * A model directory discovery strategy, which considers one top-most directory - * and discovers its contents for model directories, similar to depth first - * search but with a single start point. Uses a given filter to determine - * whether a given directory encompasses one (and only one) model. + * A concrete implementation that considers one top-most directory and discovers + * its contents, similar to depth first search but with a single start point. + * Uses a given filter to determine whether a given directory is a model source + * file directory and encompasses one (and only one) model. + * + * TODO Rename methods and parameters * * @author Alp Torac Genc */ @@ -20,17 +22,19 @@ public class ModelDirDiscoveryStrategy implements IModelDirDiscoveryStrategy { /** * Constructs an instance. * - * @param modelDirFilter A filter for determining whether a given directory - * encompasses one (and only one) model + * @param modelDirFilter A filter for determining whether a given directory is a + * model source file directory and encompasses one (and + * only one) model */ public ModelDirDiscoveryStrategy(Predicate modelDirFilter) { this.modelDirFilter = modelDirFilter; } /** - * @param modelParentDirPath A parent directory, which potentially contains - * model source file directories - * @return All model source file directories under the given path + * @param modelParentDirPath A model source parent directory, which potentially + * contains model source file directories + * @return All model source file directories under the given path to model + * source parent directory * * @see {@link #isModelSourceDirectory(File)} */ @@ -63,8 +67,9 @@ public boolean isModelSourceDirectory(File dir) { } /** - * Recursively searches for directories containing Java-Model files, starting - * from the given directory, and returns a list of all such directories. + * Recursively searches for model source file directories containing Java-Model + * files, starting from the given directory, and returns a list of all model + * source file directories. */ protected Collection discoverModels(File dirToDiscover) { var foundModelDirs = new ArrayList(); @@ -73,12 +78,11 @@ protected Collection discoverModels(File dirToDiscover) { } /** - * Recursively searches for directories that contain model source files. All - * directories containing models (determined via - * {@link #isModelSourceDirectory(File)}) will be added to foundModelDirs, if - * not already there. + * Recursively searches for model source files directories. All directories + * containing models (determined via {@link #isModelSourceDirectory(File)}) will + * be added to foundModelDirs, if not already there. * - * @param dirToDiscover The directory, where the recursive search will begin + * @param dirToDiscover The directory, where the recursive search shall begin * @param foundModelDirs A collection of model source file directories */ protected void discoverModels(File dirToDiscover, Collection foundModelDirs) { @@ -99,7 +103,7 @@ protected void discoverModels(File dirToDiscover, Collection foundModelDir /** * @implSpec Check {@link #isModelSourceDirectory(File)} for more details on how - * model directories are filtered. + * model source file directories are filtered. */ @Override public Collection discoverModelSourceDirs(File dirToDiscover) { @@ -108,7 +112,7 @@ public Collection discoverModelSourceDirs(File dirToDiscover) { /** * @implSpec Check {@link #isModelSourceDirectory(File)} for more details on how - * model directories are filtered. + * model source file directories are filtered. */ @Override public Collection discoverModelSourceParentDirs(File dirToDiscover) { diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ParserTestFileLayout.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ParserTestFileLayout.java index 4d0dac8dd0..9b6c3dddc0 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ParserTestFileLayout.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ParserTestFileLayout.java @@ -8,6 +8,8 @@ /** * Contains layout-related information for the corresponding parser test. * + * TODO Rename parameters and methods + * * @author Alp Torac Genc */ public class ParserTestFileLayout { @@ -50,15 +52,14 @@ public ParserTestFileLayout(ParserTestFileLayout layout) { } /** - * Sets the path to the root folder of the model source file directories, under - * which all models' source file directories reside + * {@link #getModelSourceFileRootDirPath(Path)} */ public void setModelSourceFileRootDirPath(Path modelSourceFileRootDirPath) { this.modelSourceFileRootDirPath = modelSourceFileRootDirPath; } /** - * Sets the file extension of the Resource files (if desired to be saved) + * {@link #getModelResourceFileExtension()} */ public void setModelResourceFileExtension(String modelResourceFileExtension) { this.modelResourceFileExtension = modelResourceFileExtension; @@ -72,7 +73,9 @@ public String getModelResourceFileExtension() { } /** - * Sets the absolute path, at which taken time measurements are to be saved. + * Sets the relative path to the directory, where time measurements are to be + * saved (if desired). {@link #getTimeMeasurementsFileSavePath()} will return + * the derived absolute path. */ public void setTimeMeasurementsFileSavePath(Path timeMeasurementsFileSavePath) { this.timeMeasurementsFileSavePath = timeMeasurementsFileSavePath; @@ -89,8 +92,8 @@ public void setCacheSaveDirPath(Path cacheSaveDirPath) { } /** - * Sets up the relative path to the {@link #getAbsoluteCurrentDirectory()} - * directory, where parsed model resource files are to be saved (if desired). + * Sets up the relative path to the directory, where parsed model resource files + * are to be saved (if desired). */ public void setTestModelResourceFilesSaveDirPath(Path testModelResourceFilesSaveDirPath) { this.testModelResourceFilesSaveDirPath = testModelResourceFilesSaveDirPath; @@ -154,15 +157,15 @@ public URI getModelResourceURI(Path modelDir) { /** * Defaults to {@link #getAbsoluteCurrentDirectory()}. * - * @return Path to the root folder of the model source file directories, under - * which all models' source file directories reside + * @return Path to the top-most model source parent directory, under which all + * models' source file directories reside */ public Path getModelSourceFileRootDirPath() { return this.modelSourceFileRootDirPath; } /** - * @return The root directory, under which generated test resources will be + * @return The root directory, under which generated model resources will be * saved. */ public Path getModelResourceSaveRootDirectory() { @@ -170,8 +173,8 @@ public Path getModelResourceSaveRootDirectory() { } /** - * @return The relative path between the current directory and the root - * directory ({@link #getModelSourceFileRootDirPath()}). + * @return The relative path between the current directory and + * ({@link #getModelSourceFileRootDirPath()}). * @see {@link #getModelSourceFileRootDirPath()} */ public Path getRelativeModelSourceFileRootDirPath() { @@ -179,12 +182,10 @@ public Path getRelativeModelSourceFileRootDirPath() { } /** - * @param modelParentDirPath The parent directory for a group of models, which - * contains other directories that contain model - * files. + * @param modelParentDirPath A model source parent directory path * @return The relative path between ({@link #getModelSourceFileRootDirPath()}) - * and the given path. If both paths are the same, returns the file name - * (without extension) in the parameter. + * and the given model source parent path. If both paths are the same, + * returns the file name (without extension) in the parameter. */ public Path getRelativeModelSourceParentDirPath(Path modelParentDirPath) { var rootPath = this.getModelSourceFileRootDirPath(); diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ParserTestOptions.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ParserTestOptions.java index 1128bd8067..9594d2d90f 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ParserTestOptions.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ParserTestOptions.java @@ -6,12 +6,14 @@ * A class that contains various options for test classes that parse * {@link Resource} instances and cache them: *
        - *
      • shouldSaveCachedResources: Whether the cached resources should be saved - * after tests - *
      • shouldRemoveResourcesFromCache: Whether cached resources should be + *
      • shouldSaveCachedResources: Whether the cached model resources should be + * saved after tests + *
      • shouldRemoveResourcesFromCache: Whether cached model resources should be * removed after each test deleted after tests *
      * + * TODO Rename methods + * * @see {@link ResourceTestOptions} for other options * @author Alp Torac Genc */ diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/package-info.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/package-info.java index 993acb1350..a23b160f9e 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/package-info.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/package-info.java @@ -1,5 +1,16 @@ /** - * Contains tests that involve small-scale Java projects, Java-elements and/or - * fragments thereof in form of concrete files. + * Contains the means to parse Java models in form of {@link Resource} and + * {@link ResourceSet} instances, along with an abstract test class + * {@link AbstractJaMoPPParserSimilarityTest} that integrates them.
      + *
      + * {@link cipm.consistency.fitests.similarity.jamopp.parser.timemeasurement} + * includes the means to measure time in tests.
      + *
      + * {@link cipm.consistency.fitests.similarity.jamopp.parser.testfactory} + * encapsulates dynamic test creation and order.
      + *
      + * {@link cipm.consistency.fitests.similarity.jamopp.parser.resultprovider} + * contains expected similarity result providers, which provide expected results + * to dynamic tests, depending on their implementation. */ package cipm.consistency.fitests.similarity.jamopp.parser; \ No newline at end of file diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/resultprovider/FileContentSimilarityResultProvider.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/resultprovider/FileContentSimilarityResultProvider.java index 9d752f5bc5..855a6d75d2 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/resultprovider/FileContentSimilarityResultProvider.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/resultprovider/FileContentSimilarityResultProvider.java @@ -7,8 +7,10 @@ import cipm.consistency.fitests.similarity.jamopp.parser.FileUtil; /** - * Provides expected similarity results for model resources by comparing the - * file contents under their paths. + * Provides expected similarity results for model resources by comparing their + * respective model source files' (or model source file directories') content. + * + * TODO Remove fileUtil once it is a singleton * * @author Alp Torac Genc */ @@ -17,9 +19,11 @@ public class FileContentSimilarityResultProvider implements IExpectedSimilarityR /** * @implSpec Determines the expected similarity result purely based on the given - * paths. Compares the contents of files under both given paths - * pairwise. If all files are present on both sides, and have the same - * content (up to whitespaces). + * model source file (or model source file directory) paths. Compares + * the contents of model source files under both given paths pairwise. + * If all files are present on both sides, and have the same content + * (up to whitespaces), the given resources are expected to be + * similar. */ @Override public boolean getExpectedSimilarityResultFor(Resource lhsRes, Path lhsResPath, Resource rhsRes, Path rhsResPath) { diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/resultprovider/IExpectedSimilarityResultProvider.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/resultprovider/IExpectedSimilarityResultProvider.java index 7aa185d8c6..a27c18ffdb 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/resultprovider/IExpectedSimilarityResultProvider.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/resultprovider/IExpectedSimilarityResultProvider.java @@ -14,22 +14,25 @@ * expected similarity results of others. How the expected similarity results * are derived and provided depends on the concrete implementor. * + * TODO Rename parameters + * * @author Alp Torac Genc */ public interface IExpectedSimilarityResultProvider { /** - * Model resources and their paths should be provided via separate parameters, - * as the original files that were parsed into model resources may reside under + * Model resources and the respective paths should be provided via separate + * parameters, as the original files that were parsed into model resources (i.e. + * model source files / model source file directories) may reside under * different paths, which cannot be determined from the model resource alone. * * @param lhsRes Left-hand side resource * @param lhsResPath The path that the resource lhsRes was originally parsed - * from, i.e. the path to the files that were parsed into - * lhsRes. + * from, i.e. the path to the model source file / model source + * file directory. * @param rhsRes Right-hand side resource * @param rhsResPath The path that the resource rhsRes was originally parsed - * from, i.e. the path to the files that were parsed into - * rhsRes. + * from, i.e. the path to the model source file / model source + * file directory. * @return The expected result of similarity checking the given resources, * according to the concrete implementor. */ diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/resultprovider/ResourceContentSimilarityResultProvider.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/resultprovider/ResourceContentSimilarityResultProvider.java index 1133bd5700..02f338560f 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/resultprovider/ResourceContentSimilarityResultProvider.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/resultprovider/ResourceContentSimilarityResultProvider.java @@ -20,8 +20,7 @@ public class ResourceContentSimilarityResultProvider implements IExpectedSimilarityResultProvider { private ISimilarityCheckerContainer scc; /** - * Whether the order of the contents of the model resources should be accounted - * for + * @see {@link #ResourceContentSimilarityResultProvider(ISimilarityCheckerContainer, boolean)} */ private boolean contentOrderMatters; @@ -38,8 +37,7 @@ public ResourceContentSimilarityResultProvider(ISimilarityCheckerContainer scc, /** * Checks if both sides' contents ({@code res.getAllContents()}) are similar, if - * their order does not matter. Makes sure that the result is the same as - * {@code allContentSimilar(rhs, lhs)}. + * their order does not matter. * * @return Whether all contents of lhs and rhs are similar, i.e. if all contents * of lhs have a corresponding similar content on rhs. @@ -55,8 +53,7 @@ private boolean contentwiseSimilar(Resource lhs, Resource rhs) { /** * Checks if both sides' contents ({@code obj.eAllContents()}) are similar, if - * their order does not matter. Makes sure that the result is the same as - * {@code allContentSimilar(rhs, lhs)}. + * their order does not matter. * * @return Whether all contents of lhs and rhs are similar, i.e. if all contents * of lhs have a corresponding similar content on rhs. @@ -109,6 +106,10 @@ private boolean contentwiseSimilar(Collection lhs, Collection * {@link ISimilarityCheckerContainer} and content order (if desired * in * {@link #ResourceContentSimilarityResultProvider(ISimilarityCheckerContainer, boolean)}). + * If both paths are equal, the resources are expected to be similar. + * If the paths are different, TODO Fix this method by adding + * FileContentSimilarityResultProvider to !this.contentOrderSimilar + * case */ @Override public boolean getExpectedSimilarityResultFor(Resource lhsRes, Path lhsResPath, Resource rhsRes, Path rhsResPath) { diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/resultprovider/ResourceReferenceEqualitySimilarityResultProvider.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/resultprovider/ResourceReferenceEqualitySimilarityResultProvider.java index f9612a5c72..9b49a5d84c 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/resultprovider/ResourceReferenceEqualitySimilarityResultProvider.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/resultprovider/ResourceReferenceEqualitySimilarityResultProvider.java @@ -13,7 +13,7 @@ public class ResourceReferenceEqualitySimilarityResultProvider implements IExpectedSimilarityResultProvider { /** * @implSpec Determines expected similarity results based on the reference - * equality of model resources. + * equality of model resources, i.e. {@code lhsRes == rhsRes} */ @Override public boolean getExpectedSimilarityResultFor(Resource lhsRes, Path lhsResPath, Resource rhsRes, Path rhsResPath) { diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/resultprovider/package-info.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/resultprovider/package-info.java index 6310f36518..e3278d71c7 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/resultprovider/package-info.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/resultprovider/package-info.java @@ -1 +1,6 @@ +/** + * Contains the means to supply dynamic tests with expected results. + * + * @see {@link IExpectedSimilarityResultProvider} for more information + */ package cipm.consistency.fitests.similarity.jamopp.parser.resultprovider; \ No newline at end of file diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/testfactory/AbstractJaMoPPParserSimilarityTestFactory.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/testfactory/AbstractJaMoPPParserSimilarityTestFactory.java index 375ae9e583..b84095e963 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/testfactory/AbstractJaMoPPParserSimilarityTestFactory.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/testfactory/AbstractJaMoPPParserSimilarityTestFactory.java @@ -15,6 +15,8 @@ * An abstract class meant to be implemented by classes that encapsulate logic * about dynamic test generation. * + * TODO Rename parameters + * * @author Alp Torac Genc */ public abstract class AbstractJaMoPPParserSimilarityTestFactory { @@ -57,7 +59,7 @@ public IExpectedSimilarityResultProvider getExpectedSimilarityResultProvider() { } /** - * Changes how this instance provides expected similarity values to the dynamic + * Changes how this instance provides expected similarity results to the dynamic * tests it generates.
      *
      * If the given provider is null, sets the current provider to @@ -75,8 +77,8 @@ public void setExpectedSimilarityResultProvider(IExpectedSimilarityResultProvide * Defaults to the name of the concrete implementing type. Can be overridden in * concrete implementors for a more accurate description. * - * @return A description for this test generation strategy, which may be added - * to test descriptions. + * @return A description for this test generation factory, which may be added to + * test descriptions. */ public String getTestDescription() { return this.getClass().getSimpleName(); @@ -137,7 +139,9 @@ protected ParserTestTimeMeasurementKeyBuilder getTimeMeasurementKeyBuilderFor(Re /** * The provided model resources are not assumed to have a certain order here, * because the concrete implementor could change what resources are checked for - * similarity in which order. + * similarity in which order. Refer to the concrete implementations of + * {@link #getExpectedSimilarityResultProvider()} and + * {@link #getDefaultExpectedSimilarityResultProvider()} for more information. * * @return Dynamic tests generated based on the concrete implementor. */ diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/testfactory/EAllContentSimilarityTestFactory.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/testfactory/EAllContentSimilarityTestFactory.java index 4980a38f8e..d6e928ba97 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/testfactory/EAllContentSimilarityTestFactory.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/testfactory/EAllContentSimilarityTestFactory.java @@ -54,11 +54,6 @@ protected void testSimilarityOfAllContents(Resource res1, Resource res2, Boolean ParserTestTimeMeasurer.getInstance().stopTimeMeasurement(); } - /** - * Ensures that all contents of the parsed models are only then similar - * (accounting for their order too), if the content of their source files are - * equal (in terms of code, not whitespace nor comments etc.). - */ @Override public DynamicNode createTestsFor(Resource res1, Path path1, Resource res2, Path path2) { return DynamicTest.dynamicTest(String.format("%s vs %s", path1.getFileName(), path2.getFileName()), () -> { diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/testfactory/IJaMoPPParserTestGenerationStrategy.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/testfactory/IJaMoPPParserTestGenerationStrategy.java index d9f75061dd..98593c72a9 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/testfactory/IJaMoPPParserTestGenerationStrategy.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/testfactory/IJaMoPPParserTestGenerationStrategy.java @@ -4,7 +4,7 @@ /** * An interface meant for classes that encapsulate the logic on how to iterate - * through the given Resource array, while generating dynamic tests.
      + * through the given model Resource array, while generating dynamic tests.
      *
      * Does not directly generate dynamic tests, because the order of elements may * matter for other concerns as well. Therefore, implementors of this interface @@ -22,8 +22,8 @@ public interface IJaMoPPParserTestGenerationStrategy { * elements in resArr and pathArr, which are to be used in the current dynamic * test. In other words, the current dynamic test will use the * {@code idxs[0]}-th elements for the left hand side (lhs) and - * {@code idxs[1]}-th elements for the right hand side in the current dynamic - * test. + * {@code idxs[1]}-th elements for the right hand side (rhs) in the current + * dynamic test. * * @param testResourceCount The amount of test resources that are present. Used * to mark when the returned iterator finishes, diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/testfactory/ModelComparisonTestFactory.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/testfactory/ModelComparisonTestFactory.java index 981a2b11ce..b8605ae395 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/testfactory/ModelComparisonTestFactory.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/testfactory/ModelComparisonTestFactory.java @@ -90,10 +90,6 @@ protected void testSimilarityWithModelComparison(Resource res1, Resource res2, B ParserTestTimeMeasurer.getInstance().stopTimeMeasurement(); } - /** - * Checks if parsed {@link Resource} instances are detected as similar. Checks - * the similarity of res1 with res2. - */ @Override public DynamicNode createTestsFor(Resource res1, Path path1, Resource res2, Path path2) { return DynamicTest.dynamicTest(String.format("%s vs %s", path1.getFileName(), path2.getFileName()), () -> { diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/testfactory/ReflexiveSymmetricIterationTestGenerationStrategy.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/testfactory/ReflexiveSymmetricIterationTestGenerationStrategy.java index 5a8d045394..26ad8e3a3f 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/testfactory/ReflexiveSymmetricIterationTestGenerationStrategy.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/testfactory/ReflexiveSymmetricIterationTestGenerationStrategy.java @@ -5,7 +5,10 @@ /** * An implementation of {@link IJaMoPPParserTestGenerationStrategy} that * provides an iterator, which denotes a linear and symmetric index sequence for - * test resources. + * test resources.
      + *
      + * + * @see {@link #getTestResourceIterator(int)} for more information. * * @author Alp Torac Genc */ @@ -14,16 +17,27 @@ public class ReflexiveSymmetricIterationTestGenerationStrategy implements IJaMoP /** * @implSpec Returns an iterator that helps generate dynamic tests by using test - * resources in an iterative, reflexive, symmetric way. If - * {@code testResourceCount = 3}, then the order denoted by the - * returned iterator will be as follows, where {@code (i, j)} stands - * for the indices of test resources that will be used in the current - * test:
      - *
      + * resources in an iterative, reflexive, symmetric way. The order + * denoted by the returned iterator will be as follows, where + * {@code (i, j)} stands for the indices of test resources that will + * be used in the current test: + *
        + *
      1. Start with {@code currentIdx = 0}: In-place (currentIdx, + * currentIdx) + *
      2. while {@code currentIdx < testResourceCount} : + *
          + *
        1. Forward (currentIdx, currentIdx + 1) + *
        2. Reverse (currentIdx + 1, currentIdx) + *
        3. In-place (currentIdx + 1, currentIdx + 1) + *
        4. {@code currentIdx++} + *
        + *
      + * Example with {@code testResourceCount = 3}: * {@code (0,0); (0,1); (1,0); (1,1); (1,2); (2,1); (2,2)} * @implNote Assuming both arrays' length is {@code N}, then the returned - * iterator iterates {@code 3*N} times. As such, a maximum of - * {@code 3*N} dynamic tests can be generated. + * iterator iterates {@code 1 + 3*(N - 1)} times. As such, a maximum + * of {@code 1 + 3*(N - 1)} dynamic tests can be generated. In the + * example, {@code N = 3} and hence 7 dynamic tests are to be created. */ @Override public Iterator getTestResourceIterator(int testResourceCount) { diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/testfactory/package-info.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/testfactory/package-info.java index 5187110705..7fb147728f 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/testfactory/package-info.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/testfactory/package-info.java @@ -1 +1,11 @@ +/** + * Contains the means to generate dynamic tests that are created through the + * constructs within {@link cipm.consistency.fitests.similarity.jamopp.parser} + * or sub-types thereof.
      + *
      + * Test factories extending {@link AbstractJaMoPPParserSimilarityTestFactory} + * define what is tested in the dynamic tests. Test generation strategies + * implementing {@link IJaMoPPParserTestGenerationStrategy} encapsulate the + * order of dynamic tests. + */ package cipm.consistency.fitests.similarity.jamopp.parser.testfactory; \ No newline at end of file diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/GeneralTimeMeasurementTag.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/GeneralTimeMeasurementTag.java index 4853baaeab..fadd7593e9 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/GeneralTimeMeasurementTag.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/GeneralTimeMeasurementTag.java @@ -8,12 +8,12 @@ */ public enum GeneralTimeMeasurementTag implements ITimeMeasurementTag { /** - * A tag meant for time measurements from discovering model source files + * A tag meant for time measurements from discovering model source files, model + * source file directories, model source parent directories. */ DISCOVER_MODEL_RESOURCES, /** - * A tag meant for time measurements from parsing model resources from model - * source files + * A tag meant for time measurements from parsing model resources */ PARSE_MODEL_RESOURCE, /** @@ -45,12 +45,14 @@ public enum GeneralTimeMeasurementTag implements ITimeMeasurementTag { /** * A tag meant for time measurements from the test methods annotated with - * {@link org.junit.jupiter.api.BeforeEach} + * {@link org.junit.jupiter.api.BeforeEach} and + * {@link org.junit.jupiter.api.BeforeAll}. */ TEST_BEFOREEACH, /** * A tag meant for time measurements from the test methods annotated with - * {@link org.junit.jupiter.api.AfterEach} + * {@link org.junit.jupiter.api.AfterEach} and + * {@link {@link org.junit.jupiter.api.AfterAll}}. */ TEST_AFTEREACH, /** @@ -60,8 +62,8 @@ public enum GeneralTimeMeasurementTag implements ITimeMeasurementTag { DYNAMIC_TEST_CREATION, /** * A tag meant for time measurements from miscellaneous preparation operations - * (except those from {@link #TEST_BEFOREEACH} and {@link #TEST_AFTEREACH} ) in - * tests that cannot be reasonably assigned to a more accurate tag + * (except those from {@link #TEST_BEFOREEACH} and {@link #TEST_AFTEREACH}) in + * tests that cannot be reasonably assigned to a more accurate tag. */ TEST_OVERHEAD, diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/ParserTestTimeMeasurementKey.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/ParserTestTimeMeasurementKey.java index d6a5f90bd1..703bd94f24 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/ParserTestTimeMeasurementKey.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/ParserTestTimeMeasurementKey.java @@ -4,8 +4,8 @@ import java.util.Map; /** - * A class that contains information about time measurements. There is no - * mandatory information that should be given to this class.
      + * A class that contains information about time measurements in a map instance. + * There is no mandatory information that should be given to this class.
      *
      * For convenience and clarity, instances should be constructed via builder * classes such as {@link ParserTestTimeMeasurementKeyBuilder}. Its constructor diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/package-info.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/package-info.java index 340fa6b9f0..959462ca10 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/package-info.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/package-info.java @@ -1 +1,34 @@ +/** + * Contains the means to measure, persist and load previous time measurements + * from tests.
      + *
      + * {@link ParserTestTimeMeasurer} is the singleton that serves as a facade to + * time measurement operations and aggregates the time measuring components: + *
        + *
      • {@link ITimeMeasuringStrategy} encapsulates the means to measure time + *
      • {@link ITimeMeasurementDataStructure} stores taken time measurements and + * aggregates in form of {@link TimeMeasurementEntry} instances + *
      • {@link ITimeMeasurementPersistingStrategy} defines how + * {@link ITimeMeasurementDataStructure} instances can be saved into files or + * persisted + *
      • {@link ITimeMeasurementLoadingStrategy} provides the means to load + * previously taken time measurements + *
      + * Time measurements are stored in form of {@link TimeMeasurementEntry} + * instances, which consist of 2 high-level parts: + *
        + *
      • {@link ParserTestTimeMeasurementKey} houses all information regarding a + * time measurement, such as the amount of time elapsed and what the time + * measurement is taken from. For each piece of information supported by + * ParserTestTimeMeasurementKey, there is a corresponding + * {@link ParserTestTimeMeasurerKeyType} constant. ParserTestTimeMeasurementKey + * instances should be constructed via their builders, such as + * {@link ParserTestTimeMeasurementKeyBuilder}. + *
      • {@link ITimeMeasurementTag} that indicates the over-arching purpose of + * the time measurement, which allows time measurements to be grouped up easier. + * It is the unifying interface of tag enums (such as + * {@link GeneralTimeMeasurementTag}), which enables implementing further tags + * without having to modify existing tag enums. + *
      + */ package cipm.consistency.fitests.similarity.jamopp.parser.timemeasurement; \ No newline at end of file From c688bc1579b0b32100962a14e7e27004ce701518 Mon Sep 17 00:00:00 2001 From: AlpTorac Date: Sat, 30 Aug 2025 18:12:50 +0200 Subject: [PATCH 54/72] Log error messages --- .../fitests/similarity/eobject/ResourceHelper.java | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/eobject/ResourceHelper.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/eobject/ResourceHelper.java index 417f905eab..7b0c1190dd 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/eobject/ResourceHelper.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/eobject/ResourceHelper.java @@ -84,8 +84,6 @@ public static void setResourceRegistry(String extension, Object factory) { /** * Attempts to save the given resource instance. Instead of throwing exceptions, * returns true/false to indicate success/failure. - * - * TODO Log the error message */ public static boolean saveResource(Resource res) { var uri = res.getURI(); @@ -95,6 +93,7 @@ public static boolean saveResource(Resource res) { return resourceFileExists(uri); } catch (IOException excep) { excep.printStackTrace(); + SimilarityTestLogger.logErrorMsg(excep.getMessage(), ResourceHelper.class); return resourceFileExists(uri); } } @@ -115,8 +114,6 @@ public static boolean saveResourceIfNotSaved(Resource res) { /** * Loads the given resource - * - * TODO Log error message */ public static void loadResource(Resource res) { try { @@ -128,6 +125,7 @@ public static void loadResource(Resource res) { e.printStackTrace(); SimilarityTestLogger.logInfoMsg(String.format("Could not load resource at: %s", res.getURI()), ResourceHelper.class); + SimilarityTestLogger.logErrorMsg(e.getMessage(), ResourceHelper.class); } } @@ -191,8 +189,6 @@ public static boolean resourceFileExists(URI resURI) { /** * Deletes the given resource * - * TODO Log error message - * * @return Whether the file of the given resource is deleted. */ public static boolean deleteResource(Resource res) { @@ -207,6 +203,7 @@ public static boolean deleteResource(Resource res) { String.format("Could not delete resource as expected: %s (is deleted: %s) %s %s", res.getURI().toString(), isResourceDeleted, System.lineSeparator(), e.getMessage()), ResourceHelper.class); + SimilarityTestLogger.logErrorMsg(e.getMessage(), ResourceHelper.class); return isResourceDeleted; } } From 9bc3b90a3f43d4bd95acd2e91aa64d550839e669 Mon Sep 17 00:00:00 2001 From: AlpTorac Date: Sat, 30 Aug 2025 18:22:08 +0200 Subject: [PATCH 55/72] Make FileUtil a utility class --- .../AbstractJaMoPPParserRepoTest.java | 7 +++-- .../AbstractJaMoPPParserSimilarityTest.java | 9 ------ .../similarity/jamopp/parser/FileUtil.java | 29 +++++++++---------- .../FileContentSimilarityResultProvider.java | 6 +--- 4 files changed, 18 insertions(+), 33 deletions(-) diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/AbstractJaMoPPParserRepoTest.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/AbstractJaMoPPParserRepoTest.java index f32e8f578f..52e384fa75 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/AbstractJaMoPPParserRepoTest.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/AbstractJaMoPPParserRepoTest.java @@ -7,6 +7,7 @@ import cipm.consistency.fitests.similarity.eobject.ResourceHelper; import cipm.consistency.fitests.similarity.jamopp.JaMoPPResourceParsingStrategy; import cipm.consistency.fitests.similarity.jamopp.parser.AbstractJaMoPPParserSimilarityTest; +import cipm.consistency.fitests.similarity.jamopp.parser.FileUtil; import cipm.consistency.fitests.similarity.jamopp.parser.IModelResourceWrapper; import cipm.consistency.fitests.similarity.jamopp.parser.resultprovider.IExpectedSimilarityResultProvider; import cipm.consistency.fitests.similarity.jamopp.parser.testfactory.IJaMoPPParserTestGenerationStrategy; @@ -177,7 +178,7 @@ public void tearDown() { var localRepoPath = this.getTestFileLayout().getModelSourceFileRootDirPath(); if (this.getResourceTestOptions().shouldDeleteRepositoryClones() && localRepoPath.toFile().exists()) { this.startTimeMeasurement(RepoTimeMeasurementTag.DELETE_LOCAL_REPO_CLONE); - this.getFileUtil().deleteAll(localRepoPath); + FileUtil.deleteAll(localRepoPath); this.stopTimeMeasurement(); } @@ -313,7 +314,7 @@ protected Collection cacheCommitResources() { this.getClass()); this.startTimeMeasurement(RepoTimeMeasurementTag.DELETE_LOCAL_REPO_CLONE); - this.getFileUtil().deleteAll(mainLocalClonePath); + FileUtil.deleteAll(mainLocalClonePath); this.stopTimeMeasurement(); SimilarityTestLogger.logDebugMsg("Cleaned main local repository clone", this.getClass()); @@ -399,7 +400,7 @@ protected Git cloneRepo(String repoToCloneURI, Path clonePath) { // Faulty repository clone, delete and re-try SimilarityTestLogger.logDebugMsg("Could not open existing repository, deleting it and re-cloning", this.getClass()); - this.getFileUtil().deleteAll(clonePath); + FileUtil.deleteAll(clonePath); if (clonePath.toFile().exists() && clonePath.toFile().list().length != 0) { throw new IllegalStateException("Could not delete faulty repository clone"); } diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/AbstractJaMoPPParserSimilarityTest.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/AbstractJaMoPPParserSimilarityTest.java index 1cbbff022d..f301ba3bcc 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/AbstractJaMoPPParserSimilarityTest.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/AbstractJaMoPPParserSimilarityTest.java @@ -276,15 +276,6 @@ protected void stopTimeMeasurement() { ParserTestTimeMeasurer.getInstance().stopTimeMeasurement(); } - /** - * TODO Remove once FileUtil is a singleton - * - * @return A utility object that can be used to perform file operations. - */ - protected FileUtil getFileUtil() { - return new FileUtil(); - } - /** * @return A utility object, which encapsulates caching logic (for parsed * models) and can be used to hasten tests. diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/FileUtil.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/FileUtil.java index 2ad1b3170e..7ff9811fe6 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/FileUtil.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/FileUtil.java @@ -11,8 +11,6 @@ /** * A utility class that contains file-related operations. * - * TODO Turn into a singleton - * * @author Alp Torac Genc */ public class FileUtil { @@ -22,7 +20,7 @@ public class FileUtil { * @see {@link #filesEqual(File, File)} * @see {@link #dirsEqual(File, File)} */ - public boolean areContentsEqual(Path path1, Path path2) { + public static boolean areContentsEqual(Path path1, Path path2) { return dirsEqual(path1.toFile(), path2.toFile()); } @@ -32,15 +30,14 @@ public boolean areContentsEqual(Path path1, Path path2) { * If the given file cannot be read (due to IOException), returns an empty * string. */ - public String readEffectiveText(File f) { + public static String readEffectiveText(File f) { var content = ""; try { content = Files.readString(f.toPath()); } catch (IOException e) { SimilarityTestLogger.logDebugMsg( - String.format("Could not read: %s, returning empty string", f.toPath().toString()), - this.getClass()); + String.format("Could not read: %s, returning empty string", f.toPath().toString()), FileUtil.class); } return content.replaceAll("\\n", "").replaceAll("\\r", "").replaceAll("\\s", ""); @@ -54,7 +51,7 @@ public String readEffectiveText(File f) { * * @see {@link #readEffectiveText(File)} */ - public boolean filesEqual(File f1, File f2) { + public static boolean filesEqual(File f1, File f2) { var f1Content = readEffectiveText(f1); var f2Content = readEffectiveText(f2); @@ -74,8 +71,8 @@ public boolean filesEqual(File f1, File f2) { * * @see {@link #filesEqual(File, File)}, {@link #readEffectiveText(File)} */ - public boolean dirsEqual(File dir1, File dir2) { - SimilarityTestLogger.logDebugMsg("Comparing: " + dir1.getName() + " and " + dir2.getName(), this.getClass()); + public static boolean dirsEqual(File dir1, File dir2) { + SimilarityTestLogger.logDebugMsg("Comparing: " + dir1.getName() + " and " + dir2.getName(), FileUtil.class); // There cannot be 2 files with the same path, name and extension // so using TreeSet, which sorts the files spares doing so here @@ -110,17 +107,17 @@ public boolean dirsEqual(File dir1, File dir2) { if (f1.isDirectory() && f2.isDirectory()) { if (!dirsEqual(f1, f2)) { SimilarityTestLogger.logDebugMsg( - "Directories " + f1.getName() + " and " + f2.getName() + " are not equal", this.getClass()); + "Directories " + f1.getName() + " and " + f2.getName() + " are not equal", FileUtil.class); return false; } } else if (f1.isFile() && f2.isFile()) { if (!filesEqual(f1, f2)) { SimilarityTestLogger.logDebugMsg( - "Files " + f1.getName() + " and " + f2.getName() + " are not equal", this.getClass()); + "Files " + f1.getName() + " and " + f2.getName() + " are not equal", FileUtil.class); return false; } } else { - SimilarityTestLogger.logErrorMsg("Unexpected case there is a file and a directory", this.getClass()); + SimilarityTestLogger.logErrorMsg("Unexpected case there is a file and a directory", FileUtil.class); return false; } } @@ -135,14 +132,14 @@ public boolean dirsEqual(File dir1, File dir2) { * @param file The file or directory to delete * @see {@link File#deleteOnExit()} */ - public void deleteAll(File file) { + public static void deleteAll(File file) { if (file.exists()) { if (file.isDirectory()) { var children = file.listFiles(); if (children != null) { for (var cf : children) { - this.deleteAll(cf); + deleteAll(cf); } } } @@ -156,7 +153,7 @@ public void deleteAll(File file) { /** * A variant of {@link #deleteAll(File)} that converts the given path to a file. */ - public void deleteAll(Path path) { - this.deleteAll(path.toFile()); + public static void deleteAll(Path path) { + deleteAll(path.toFile()); } } diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/resultprovider/FileContentSimilarityResultProvider.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/resultprovider/FileContentSimilarityResultProvider.java index 855a6d75d2..240a6e2bd2 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/resultprovider/FileContentSimilarityResultProvider.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/resultprovider/FileContentSimilarityResultProvider.java @@ -10,13 +10,9 @@ * Provides expected similarity results for model resources by comparing their * respective model source files' (or model source file directories') content. * - * TODO Remove fileUtil once it is a singleton - * * @author Alp Torac Genc */ public class FileContentSimilarityResultProvider implements IExpectedSimilarityResultProvider { - private FileUtil fileUtil = new FileUtil(); - /** * @implSpec Determines the expected similarity result purely based on the given * model source file (or model source file directory) paths. Compares @@ -27,6 +23,6 @@ public class FileContentSimilarityResultProvider implements IExpectedSimilarityR */ @Override public boolean getExpectedSimilarityResultFor(Resource lhsRes, Path lhsResPath, Resource rhsRes, Path rhsResPath) { - return fileUtil.areContentsEqual(lhsResPath, rhsResPath); + return FileUtil.areContentsEqual(lhsResPath, rhsResPath); } } From fc3896e297133aa4f4eabdc6210615cef0c83439 Mon Sep 17 00:00:00 2001 From: AlpTorac Date: Sun, 14 Sep 2025 14:02:08 +0200 Subject: [PATCH 56/72] Fix JaMoPPModelResourceWrapper Edit its commentary --- .../parser/JaMoPPModelResourceWrapper.java | 105 +++++++++--------- 1 file changed, 55 insertions(+), 50 deletions(-) diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/JaMoPPModelResourceWrapper.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/JaMoPPModelResourceWrapper.java index 7bf2173ff2..fdc41df99b 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/JaMoPPModelResourceWrapper.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/JaMoPPModelResourceWrapper.java @@ -14,9 +14,9 @@ import cipm.consistency.fitests.similarity.jamopp.JaMoPPResourceParsingStrategy; /** - * A class that wraps a model resource, which is either already parsed or is to - * be parsed. It encapsulates the desired model resource, as well as all other - * resources it requires: + * A class that wraps a (merged) Java model resource, which is either already + * parsed or is to be parsed. It encapsulates the desired model resource, as + * well as all other resources it requires: *
        *
      • Merged model resource: Contains all direct contents of the model files * (i.e. the Java code directly present in model files) @@ -29,8 +29,6 @@ * The main purpose of this class is to make operations on parsed model * resources, and other resources parsed in the process, tidier. * - * TODO Add override tags, remove redundant commentary - * * @author Alp Torac Genc */ public class JaMoPPModelResourceWrapper implements IModelResourceWrapper { @@ -52,26 +50,26 @@ public class JaMoPPModelResourceWrapper implements IModelResourceWrapper { /** * @see {@link #JaMoPPModelResourceWrapper(AbstractResourceHelper, JaMoPPResourceParsingStrategy)} */ - private JaMoPPResourceParsingStrategy parsingStrat; + private JaMoPPResourceParsingStrategy modelResourceParsingStrat; /** * @see {@link #getModelResource()} */ private Resource mergedModelResource; /** - * The artificial resource, which contains all contents required by the merged - * model resource that were not directly present in the model source files + * @see {@link #prepareArtificialResource(ResourceSet, List, URI)} */ private Resource artificialResource; /** * Constructs an instance. * - * @param parsingStrat The parser that will be used to parse the model resource - * and all other necessary resources + * @param modelResourceParsingStrat The parser that will be used to parse the + * model resource and all other necessary + * resources */ - public JaMoPPModelResourceWrapper(JaMoPPResourceParsingStrategy parsingStrat) { - this.parsingStrat = parsingStrat; + public JaMoPPModelResourceWrapper(JaMoPPResourceParsingStrategy modelResourceParsingStrat) { + this.modelResourceParsingStrat = modelResourceParsingStrat; } /** @@ -82,29 +80,31 @@ public JaMoPPModelResourceWrapper() { } /** - * @param correspondingResourceFileNameWithoutExt The name of the model - * resource, whose corresponding - * ArtificialResource's name - * (without file extension) is to - * be computed + * @param correspondingModelResourceFileNameWithoutExt The name of the model + * resource, whose + * corresponding + * ArtificialResource's name + * (without file extension) + * is to be computed * @return The name of the ArtificialResource corresponding to the model * resource with the given name. */ - protected String getArtificialResourceFileName(String correspondingResourceFileNameWithoutExt) { - return correspondingResourceFileNameWithoutExt + artificialResourceName + "." - + this.parsingStrat.getResourceFileExtension(); + protected String getArtificialResourceFileName(String correspondingModelResourceFileNameWithoutExt) { + return correspondingModelResourceFileNameWithoutExt + artificialResourceName + "." + + this.modelResourceParsingStrat.getResourceFileExtension(); } /** - * @param correspondingResourceURI The URI of the model resource, whose - * ArtificialResource's URI is to be computed + * @param correspondingModelResourceURI The URI of the model resource, whose + * ArtificialResource's URI is to be + * computed * @return The URI of the ArtificialResource of the model resource with the * given URI */ - protected URI getArtificialResourceURI(URI correspondingResourceURI) { - var fileNameWithoutExt = correspondingResourceURI.trimFileExtension().lastSegment(); + protected URI getArtificialResourceURI(URI correspondingModelResourceURI) { + var fileNameWithoutExt = correspondingModelResourceURI.trimFileExtension().lastSegment(); var arName = this.getArtificialResourceFileName(fileNameWithoutExt); - var arURI = correspondingResourceURI.trimSegments(1); + var arURI = correspondingModelResourceURI.trimSegments(1); return arURI.appendSegment(arName); } @@ -138,7 +138,7 @@ protected URI getArtificialResourceURI(URI correspondingResourceURI) { protected Resource prepareArtificialResource(ResourceSet modelResourceSet, List directModelResources, URI artificialResourceURI) { // Create the ArtificialResource - parsingStrat.performTrivialRecovery(modelResourceSet); + modelResourceParsingStrat.performTrivialRecovery(modelResourceSet); Resource artificialResourceForModelResSet = null; @@ -215,7 +215,7 @@ public void parseModelResource(Path modelDir, URI modelResourceURI) { // Parser returns the same ResourceSet it was previously given // via setResourceSet(...) - modelResourceSet = parsingStrat.parseModelResource(modelDir); + modelResourceSet = modelResourceParsingStrat.parseModelResource(modelDir); var resCount = modelResourceSet.getResources().size(); SimilarityTestLogger.logDebugMsg(String.format("%d resources have been parsed under %s", resCount, modelDir), @@ -280,19 +280,19 @@ public void parseModelResource(Path modelDir, URI modelResourceURI) { } /** - * Loads the merged model resource that was previously parsed. - * - * @param modelResourceURI The URI, at which a previously parsed merged model - * resource resides + * @implSpec Loads the resource with the given URI as + * {@link #getModelResource()} */ + @Override public void loadModelResource(URI modelResourceURI) { this.mergedModelResource = ResourceHelper.loadResource(modelResourceURI); } /** - * @return Whether all parsed resources have been saved. If no resources have - * been parsed, no resources will be saved. + * @implSpec Saves both {@link #getModelResource()} and the ArtificialResource + * (if existent, see {@link JaMoPPModelResourceWrapper}) */ + @Override public boolean saveResources() { var result = true; if (mergedModelResource != null) { @@ -311,9 +311,10 @@ public boolean saveResources() { } /** - * @return Whether all parsed resources have been deleted. If no resources have - * been parsed, no resource will be deleted. + * @implSpec Deletes both {@link #getModelResource()} and the ArtificialResource + * (if existent, see {@link JaMoPPModelResourceWrapper}) */ + @Override public boolean deleteResources() { var result = false; if (mergedModelResource != null) { @@ -333,9 +334,10 @@ public boolean deleteResources() { } /** - * @return Whether all parsed resources have been unloaded. If no resources have - * been parsed, no resource will be unloaded. + * @implSpec Unloads both {@link #getModelResource()} and the ArtificialResource + * (if existent, see {@link JaMoPPModelResourceWrapper}) */ + @Override public boolean unloadResources() { var result = false; if (mergedModelResource != null) { @@ -355,31 +357,35 @@ public boolean unloadResources() { } /** - * Only checks whether the merged model resource is loaded, because other - * resources will be automatically loaded on demand. + * @implSpec Only checks whether the merged model resource is loaded, because + * other resources will be automatically loaded on demand. * * @return Whether the merged model resource is loaded */ + @Override public boolean isModelResourceLoaded() { return this.mergedModelResource != null && this.mergedModelResource.isLoaded(); } /** - * @return Whether all parsed model resources have been loaded. If no resources - * have been parsed, no resource will be loaded. + * @implSpec Loads both {@link #getModelResource()} and the ArtificialResource + * (if existent, see {@link JaMoPPModelResourceWrapper}) */ + @Override public boolean loadParsedResources() { var result = true; if (mergedModelResource != null && !this.mergedModelResource.isLoaded()) { SimilarityTestLogger.logDebugMsg("Merged model resource exists, loading it now", this.getClass()); - result = ResourceHelper.unloadResource(mergedModelResource); + ResourceHelper.loadResource(mergedModelResource); + result = mergedModelResource.isLoaded(); SimilarityTestLogger.logDebugMsg(String.format("%s merged model resource at %s", result ? "Loaded" : "Could not load", mergedModelResource.getURI()), this.getClass()); } if (artificialResource != null && !this.artificialResource.isLoaded()) { - SimilarityTestLogger.logDebugMsg("Artificial resource exists, unloading it now", this.getClass()); - result = result && ResourceHelper.unloadResource(artificialResource); + SimilarityTestLogger.logDebugMsg("Artificial resource exists, loading it now", this.getClass()); + ResourceHelper.loadResource(artificialResource); + result = artificialResource.isLoaded(); SimilarityTestLogger.logDebugMsg(String.format("%s artificial resource at %s", result ? "Loaded" : "Could not load", artificialResource.getURI()), this.getClass()); } @@ -387,13 +393,10 @@ public boolean loadParsedResources() { } /** - * Sets the URIs of all parsed resources with respect to the given URI, which - * will be assigned to the parsed model resource that contains all direct - * contents of the model source files. - * - * @param newParsedModelResourceURI The new URI of the parsed model resource - * ({@link #getModelResource()} in this case) + * @implSpec Sets the URI of {@link #getModelResource()} to the given URI, then + * sets URI of ArtificialResource accordingly (if existent). */ + @Override public void setModelResourcesURI(URI newParsedModelResourceURI) { if (mergedModelResource != null) { mergedModelResource.setURI(newParsedModelResourceURI); @@ -407,6 +410,7 @@ public void setModelResourcesURI(URI newParsedModelResourceURI) { * @return The merged model resource, which contains all contents of all * (directly) parsed model source files */ + @Override public Resource getModelResource() { return mergedModelResource; } @@ -415,6 +419,7 @@ public Resource getModelResource() { * @return Whether there is a parsed model resource * ({@link #getModelResource()}) saved in this instance. */ + @Override public boolean modelResourceExists() { return this.getModelResource() != null; } From 9e8db4868b4126dc5f49f76e9827646cfd27d0fe Mon Sep 17 00:00:00 2001 From: AlpTorac Date: Sun, 14 Sep 2025 14:03:05 +0200 Subject: [PATCH 57/72] Rename classes, methods, variables To match the terminology in README.md --- .../AbstractJaMoPPParserRepoTest.java | 79 +++--- .../RepoParserTestFileLayout.java | 27 +- .../RepoCacheSimilarityResultProvider.java | 4 +- .../util/RepoTestResultCacheTest.java | 18 +- ...ava => RepoTestSimilarityResultCache.java} | 12 +- .../AbstractResourceParsingStrategy.java | 11 +- .../eobject/ResourceTestOptions.java | 38 +-- .../AbstractJaMoPPParserSimilarityTest.java | 255 ++++++++++-------- ...tegy.java => IModelDiscoveryStrategy.java} | 28 +- .../parser/ModelDirDiscoveryStrategy.java | 121 --------- .../jamopp/parser/ModelDiscoveryStrategy.java | 126 +++++++++ .../jamopp/parser/ParserTestFileLayout.java | 34 +-- .../jamopp/parser/ParserTestOptions.java | 34 ++- .../FileContentSimilarityResultProvider.java | 5 +- .../IExpectedSimilarityResultProvider.java | 23 +- ...sourceContentSimilarityResultProvider.java | 7 +- ...renceEqualitySimilarityResultProvider.java | 8 +- ...ractJaMoPPParserSimilarityTestFactory.java | 35 +-- .../EAllContentSimilarityTestFactory.java | 25 +- .../ModelComparisonTestFactory.java | 48 ++-- 20 files changed, 491 insertions(+), 447 deletions(-) rename commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/{RepoTestResultCache.java => RepoTestSimilarityResultCache.java} (97%) rename commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/{IModelDirDiscoveryStrategy.java => IModelDiscoveryStrategy.java} (53%) delete mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ModelDirDiscoveryStrategy.java create mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ModelDiscoveryStrategy.java diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/AbstractJaMoPPParserRepoTest.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/AbstractJaMoPPParserRepoTest.java index 52e384fa75..d0124ca7c0 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/AbstractJaMoPPParserRepoTest.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/AbstractJaMoPPParserRepoTest.java @@ -1,7 +1,7 @@ package cipm.consistency.fitests.repositorytests; import cipm.consistency.fitests.repositorytests.util.RepoCacheSimilarityResultProvider; -import cipm.consistency.fitests.repositorytests.util.RepoTestResultCache; +import cipm.consistency.fitests.repositorytests.util.RepoTestSimilarityResultCache; import cipm.consistency.fitests.repositorytests.util.RepoTestSimilarityValueEstimator; import cipm.consistency.fitests.similarity.SimilarityTestLogger; import cipm.consistency.fitests.similarity.eobject.ResourceHelper; @@ -43,6 +43,10 @@ * An abstract test class, which can be used for implementing tests that involve * parsing models from GIT repositories and checking their similarity.
        *
        + * Here, model source file directories and model source parent directories are + * both equal to the local repository clone directory. This means, all Java + * models are assumed to be stored in their respective repository clones.
        + *
        * Note: Since dynamic tests are used here, the * {@link org.junit.jupiter.api.BeforeEach} and * {@link org.junit.jupiter.api.AfterEach} methods will be triggered only @@ -60,7 +64,7 @@ public abstract class AbstractJaMoPPParserRepoTest extends AbstractJaMoPPParserS /** * Contains expected similarity results needed by tests */ - private static RepoTestResultCache resultCache = new RepoTestResultCache(); + private static RepoTestSimilarityResultCache similarityResultCache = new RepoTestSimilarityResultCache(); /** * The pattern of "gradle-wrapper.jar" file path, which should be excluded when @@ -69,9 +73,9 @@ public abstract class AbstractJaMoPPParserRepoTest extends AbstractJaMoPPParserS private static final String gradleWrapperJarPathPattern = ".*?/gradle-wrapper\\.jar"; /** - * @see {@link RepoParserTestFileLayout#setRepoModelImplDirName(String)} + * @see {@link RepoParserTestFileLayout#setRepoCloneRootDirName(String)} */ - private static final String repoModelImplDirName = "repo-clones"; + private static final String repoCloneRootDirName = "repo-clones"; /** * The segment in remote GIT repository URLs, which are followed by the commit @@ -113,7 +117,8 @@ public void setUp() { try (BufferedReader reader = Files.newBufferedReader(resultCachePath)) { SimilarityTestLogger.logDebugMsg(String.format("Reading cached expected similarity results"), this.getClass()); - resultCache = new RepoTestResultCache(new Gson().fromJson(reader, resultCache.getClass())); + similarityResultCache = new RepoTestSimilarityResultCache( + new Gson().fromJson(reader, similarityResultCache.getClass())); SimilarityTestLogger.logDebugMsg(String.format("Read cached expected similarity results"), this.getClass()); } catch (IOException e) { @@ -164,7 +169,7 @@ public void tearDown() { try (BufferedWriter writer = Files.newBufferedWriter(resultCachePath); var gsonWriter = gson.newJsonWriter(writer)) { - gson.toJson(resultCache, resultCache.getClass(), gsonWriter); + gson.toJson(similarityResultCache, similarityResultCache.getClass(), gsonWriter); } catch (IOException e) { Assertions.fail(String.format("Could not save the expected similarity results at %s", resultCachePath), e); @@ -175,7 +180,7 @@ public void tearDown() { this.stopTimeMeasurement(); } - var localRepoPath = this.getTestFileLayout().getModelSourceFileRootDirPath(); + var localRepoPath = this.getTestFileLayout().getModelSourceParentRootDirPath(); if (this.getResourceTestOptions().shouldDeleteRepositoryClones() && localRepoPath.toFile().exists()) { this.startTimeMeasurement(RepoTimeMeasurementTag.DELETE_LOCAL_REPO_CLONE); FileUtil.deleteAll(localRepoPath); @@ -199,7 +204,7 @@ protected RepoParserTestFileLayout initParserTestFileLayout() { layout.setRepoName(this.getRepoName()); layout.setExpectedSimilarityResultCacheDirName(expectedSimilarityResultCacheDirName); layout.setExpectedSimilarityResultCacheFileName(expectedSimilarityResultCacheFileName); - layout.setRepoModelImplDirName(repoModelImplDirName); + layout.setRepoCloneRootDirName(repoCloneRootDirName); return layout; } @@ -209,21 +214,20 @@ protected RepoParserTestFileLayout getTestFileLayout() { } /** - * Refer to {@link RepoTestResultCache} for more information on expected - * similarity results. + * Refer to {@link RepoTestSimilarityResultCache} for more information on + * expected similarity results. * * @return The expected similarity checking result for the given commits. */ protected Boolean getExpectedResult(String lhsCommit, String rhsCommit) { - return resultCache.getResult(lhsCommit, rhsCommit); + return similarityResultCache.getResult(lhsCommit, rhsCommit); } /** - * TODO Rename to prepareTestResources or something similar - * * Prepares model resources and expected similarity results needed by tests and * caches them. Must be executed before all tests. * + * @return The cached model resources parsed from {@link #getCommitIDs()} * @see {@link #getCommitIDs()} */ protected Collection cacheCommitResources() { @@ -241,7 +245,7 @@ protected Collection cacheCommitResources() { testStrats.forEach((ts) -> ts.getTestResourceIterator(commitIDList.size()).forEachRemaining((idxs) -> { var commitID1 = commitIDList.get(idxs[0]); var commitID2 = commitIDList.get(idxs[1]); - if (resultCache.getResult(commitID1, commitID2) == null) { + if (similarityResultCache.getResult(commitID1, commitID2) == null) { SimilarityTestLogger.logDebugMsg( String.format("Expected similarity result missing for: %s vs %s", commitID1, commitID2), this.getClass()); @@ -307,7 +311,7 @@ protected Collection cacheCommitResources() { SimilarityTestLogger.logDebugMsg(String.format("Closed repository wrapper"), this.getClass()); } - var mainLocalClonePath = this.getTestFileLayout().getModelSourceFileRootDirPath(); + var mainLocalClonePath = this.getTestFileLayout().getModelSourceParentRootDirPath(); SimilarityTestLogger.logDebugMsg( String.format("Cleaning main local repository clone under: %s", mainLocalClonePath.toString()), @@ -343,7 +347,7 @@ protected void computeExpectedSimilarityResults(Git git, List commitIDLi testStrats.forEach((ts) -> ts.getTestResourceIterator(commitIDList.size()).forEachRemaining((idxs) -> { var commitID1 = commitIDList.get(idxs[0]); var commitID2 = commitIDList.get(idxs[1]); - if (resultCache.getResult(commitID1, commitID2) == null) { + if (similarityResultCache.getResult(commitID1, commitID2) == null) { SimilarityTestLogger.logDebugMsg( String.format("Computing expected similarity result for: %s vs %s", commitID1, commitID2), this.getClass()); @@ -352,7 +356,7 @@ protected void computeExpectedSimilarityResults(Git git, List commitIDLi GeneralTimeMeasurementTag.EXPECTED_SIMILARITY_RESULT_COMPUTATION); var result = expectedValueEstimator.getExpectedSimilarityValueFor(git, commitID1, commitID2); - resultCache.addResult(commitID1, commitID2, result); + similarityResultCache.addResult(commitID1, commitID2, result); this.stopTimeMeasurement(); SimilarityTestLogger.logDebugMsg(String.format("Computed expected similarity result (%s) for: %s vs %s", @@ -364,26 +368,25 @@ protected void computeExpectedSimilarityResults(Git git, List commitIDLi /** * Clones the repository desired by this test. * - * @param repoToCloneURI URI to the repository, which should be cloned (local or - * remote) - * @param clonePath The path to the folder, where the repository under - * repoToCloneURI will be cloned + * @param repoToCloneURI URI to the (remote) repository, which should be locally + * cloned + * @param repoClonePath The path to the folder, where the repository clone will + * reside * * @return An object that can be used to perform GIT operations on the * repository clone. */ - protected Git cloneRepo(String repoToCloneURI, Path clonePath) { + protected Git cloneRepo(String repoToCloneURI, Path repoClonePath) { this.startTimeMeasurement(RepoTimeMeasurementTag.CLONE_REPOSITORY); Git git = null; // Repository clone does not exist, clone it - if (!clonePath.toFile().exists() || clonePath.toFile().list() == null - || clonePath.toFile().list().length == 0) { + if (!repoClonePath.toFile().exists() || repoClonePath.toFile().list() == null + || repoClonePath.toFile().list().length == 0) { try { - SimilarityTestLogger.logDebugMsg( - String.format("Cloning remote repository (%s) to: %s", repoToCloneURI, clonePath.toString()), - this.getClass()); - git = Git.cloneRepository().setURI(repoToCloneURI).setDirectory(clonePath.toFile()) + SimilarityTestLogger.logDebugMsg(String.format("Cloning remote repository (%s) to: %s", repoToCloneURI, + repoClonePath.toString()), this.getClass()); + git = Git.cloneRepository().setURI(repoToCloneURI).setDirectory(repoClonePath.toFile()) .setCloneAllBranches(true).call(); SimilarityTestLogger.logDebugMsg(String.format("Cloning successful"), this.getClass()); } catch (GitAPIException e) { @@ -395,16 +398,16 @@ protected Git cloneRepo(String repoToCloneURI, Path clonePath) { // If it does not open, delete it and re-try else { try { - git = Git.open(clonePath.toFile()); + git = Git.open(repoClonePath.toFile()); } catch (IOException e) { // Faulty repository clone, delete and re-try SimilarityTestLogger.logDebugMsg("Could not open existing repository, deleting it and re-cloning", this.getClass()); - FileUtil.deleteAll(clonePath); - if (clonePath.toFile().exists() && clonePath.toFile().list().length != 0) { + FileUtil.deleteAll(repoClonePath); + if (repoClonePath.toFile().exists() && repoClonePath.toFile().list().length != 0) { throw new IllegalStateException("Could not delete faulty repository clone"); } - git = this.cloneRepo(repoToCloneURI, clonePath); + git = this.cloneRepo(repoToCloneURI, repoClonePath); } } @@ -420,13 +423,13 @@ protected Git cloneRepo(String repoToCloneURI, Path clonePath) { protected Git cloneRepo() { // Do not explicitly add a folder for this repository, since GIT will do that // implicitly - return this.cloneRepo(this.getRepoURI().toString(), this.getTestFileLayout().getModelSourceFileRootDirPath()); + return this.cloneRepo(this.getRepoURI().toString(), this.getTestFileLayout().getModelSourceParentRootDirPath()); } /** * @return The cache key for the model resource parsed from the given commit * hash of the repository, when its model resource is inserted into the - * cache via {@link #parseModelsDirWithCaching(Path, URI, String)}. + * cache via {@link #parseModelWithCaching(Path, URI, String)}. */ protected String getCacheKeyForCommit(URI repoURI, String commitID) { return repoURI.appendSegment(repoURICommitSegment).appendSegment(commitID).toString(); @@ -440,7 +443,7 @@ protected String getCacheKeyForCommit(URI repoURI, String commitID) { * * @param commits Commits for which a model resource will be parsed * @param gitWrapper The object that can be used to perform GIT operations on - * the "main" repository clone, which should be created with + * the local repository clone, which should be created with * {@link #cloneRepo()}. */ protected Collection prepareReposForCommits(List commits, Git git) { @@ -481,10 +484,10 @@ protected Collection prepareReposForCommits(List commits, Git * it. */ if (targetPath.toFile().exists()) { - commitRes = this.parseModelsDirWithCaching(targetPath, commitResURI, + commitRes = this.parseModelWithCaching(targetPath, commitResURI, getCacheKeyForCommit(this.getRepoURI(), commitID)); } else { - commitRes = this.parseModelsDirWithCaching(git.getRepository().getDirectory().getParentFile().toPath(), + commitRes = this.parseModelWithCaching(git.getRepository().getDirectory().getParentFile().toPath(), commitResURI, getCacheKeyForCommit(this.getRepoURI(), commitID)); commitRes.setModelResourcesURI(commitResURI); } @@ -543,7 +546,7 @@ protected String getRepoName() { * resources parsed from commits in tests. */ protected IExpectedSimilarityResultProvider getExpectedSimilarityResultProviderForCommits() { - return new RepoCacheSimilarityResultProvider(resultCache); + return new RepoCacheSimilarityResultProvider(similarityResultCache); } @Override diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/RepoParserTestFileLayout.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/RepoParserTestFileLayout.java index 7b25749611..271afb5edc 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/RepoParserTestFileLayout.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/RepoParserTestFileLayout.java @@ -14,9 +14,9 @@ */ public class RepoParserTestFileLayout extends ParserTestFileLayout { /** - * @see {@link #setRepoModelImplDirName(String)} + * @see {@link #setRepoCloneRootDirName(String)} */ - private String repoModelImplDirName; + private String repoCloneRootDirName; /** * @see {@link #setExpectedSimilarityResultCacheDirName(String)} @@ -52,8 +52,8 @@ public void setRepoName(String repoName) { * Sets the name of the root directory of local repository clones that will be * used in tests */ - public void setRepoModelImplDirName(String repoModelImplDirName) { - this.repoModelImplDirName = repoModelImplDirName; + public void setRepoCloneRootDirName(String repoCloneRootDirName) { + this.repoCloneRootDirName = repoCloneRootDirName; } /** @@ -92,7 +92,7 @@ public URI getModelResourceSaveURIForCommit(String commitID) { * @return The path, where the given commit should be cloned */ public Path getRepoClonePathForCommit(String commitID) { - return this.getModelSourceFileRootDirPath().resolve(commitID); + return this.getModelSourceParentRootDirPath().resolve(commitID); } /** @@ -108,18 +108,19 @@ public URI getRepoCloneURIForCommit(String commitID) { * * @return The top-most directory, where the repositories will be cloned to */ - public Path getRepoClonesDirPath() { - return this.getTestFilesSavePath().resolve(repoModelImplDirName); + public Path getRepoCloneRootDirPath() { + return this.getTestFilesSavePath().resolve(repoCloneRootDirName); } /** - * @implSpec Returns The path, at which the local repository clone resides. - * Meant to be used for accessing the local repository clone. Use - * {@link #getRepoClonesDirPath()} while cloning instead, so that the - * top-most folder of the repository is not duplicated. + * @implSpec Returns The path, at which the local repository clone of + * {@link #setRepoName(String)} resides. Meant to be used for + * accessing the local repository clone. Use + * {@link #getRepoCloneRootDirPath()} while cloning instead, so that + * the top-most folder of the repository is not duplicated. */ @Override - public Path getModelSourceFileRootDirPath() { - return this.getRepoClonesDirPath().resolve(this.repoName); + public Path getModelSourceParentRootDirPath() { + return this.getRepoCloneRootDirPath().resolve(this.repoName); } } diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/RepoCacheSimilarityResultProvider.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/RepoCacheSimilarityResultProvider.java index 800ad1d93a..617eddc936 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/RepoCacheSimilarityResultProvider.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/RepoCacheSimilarityResultProvider.java @@ -12,9 +12,9 @@ * @author Alp Torac Genc */ public class RepoCacheSimilarityResultProvider implements IExpectedSimilarityResultProvider { - private final RepoTestResultCache cache; + private final RepoTestSimilarityResultCache cache; - public RepoCacheSimilarityResultProvider(RepoTestResultCache cache) { + public RepoCacheSimilarityResultProvider(RepoTestSimilarityResultCache cache) { this.cache = cache; } diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/RepoTestResultCacheTest.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/RepoTestResultCacheTest.java index a2c19e5e7f..c6441e4ae4 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/RepoTestResultCacheTest.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/RepoTestResultCacheTest.java @@ -5,7 +5,7 @@ import org.junit.jupiter.api.Test; /** - * A test class for {@link RepoTestResultCache}, which ensures that it works as + * A test class for {@link RepoTestSimilarityResultCache}, which ensures that it works as * expected and that its properties hold. * * @author Alp Torac Genc @@ -18,16 +18,16 @@ public class RepoTestResultCacheTest { private static final String cID5 = "cID5"; private static final String cID6 = "cID6"; - private RepoTestResultCache cache; + private RepoTestSimilarityResultCache cache; @BeforeEach public void setUp() { - cache = new RepoTestResultCache(); + cache = new RepoTestSimilarityResultCache(); } /** * Makes the necessary assertions for - * {@link RepoTestResultCache#getDirectResult(String, String)}. + * {@link RepoTestSimilarityResultCache#getDirectResult(String, String)}. */ private void testDirectCacheResult(String commitID1, String commitID2, Boolean expectedSimilarityResult) { Assertions.assertEquals(Boolean.TRUE, cache.getDirectResult(commitID1, commitID1)); @@ -39,7 +39,7 @@ private void testDirectCacheResult(String commitID1, String commitID2, Boolean e /** * Makes the necessary assertions for - * {@link RepoTestResultCache#isInCache(String, String)}. + * {@link RepoTestSimilarityResultCache#isInCache(String, String)}. */ private void testIsInCache(String commitID1, String commitID2, boolean shouldBeInCache) { Assertions.assertEquals(false, cache.isInCache(commitID1, commitID1)); @@ -51,7 +51,7 @@ private void testIsInCache(String commitID1, String commitID2, boolean shouldBeI /** * Makes the necessary assertions for - * {@link RepoTestResultCache#getTransitiveResult(String, String)}. + * {@link RepoTestSimilarityResultCache#getTransitiveResult(String, String)}. */ private void testTransitiveCacheResult(String commitID1, String commitID2, Boolean expectedTransitiveResult) { Assertions.assertEquals(expectedTransitiveResult, cache.getTransitiveResult(commitID1, commitID2)); @@ -60,9 +60,9 @@ private void testTransitiveCacheResult(String commitID1, String commitID2, Boole /** * Makes the necessary assertions for - * {@link RepoTestResultCache#getDirectResult(String, String)}, - * {@link RepoTestResultCache#getTransitiveResult(String, String)} and - * {@link RepoTestResultCache#getResult(String, String)}. + * {@link RepoTestSimilarityResultCache#getDirectResult(String, String)}, + * {@link RepoTestSimilarityResultCache#getTransitiveResult(String, String)} and + * {@link RepoTestSimilarityResultCache#getResult(String, String)}. */ private void testCacheResult(String commitID1, String commitID2, Boolean expectedDirectSimilarityResult, Boolean expectedTransitiveResult) { diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/RepoTestResultCache.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/RepoTestSimilarityResultCache.java similarity index 97% rename from commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/RepoTestResultCache.java rename to commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/RepoTestSimilarityResultCache.java index 32c3818c79..23c96c8ca2 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/RepoTestResultCache.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/RepoTestSimilarityResultCache.java @@ -48,20 +48,20 @@ * * @author Alp Torac Genc */ -public class RepoTestResultCache { +public class RepoTestSimilarityResultCache { private final Collection similarityResults = new ArrayList(); /** * Constructs an instance with no similarity results. */ - public RepoTestResultCache() { + public RepoTestSimilarityResultCache() { } /** * Constructs an instance and copies the contents of the given cache into this * cache. */ - public RepoTestResultCache(RepoTestResultCache cache) { + public RepoTestSimilarityResultCache(RepoTestSimilarityResultCache cache) { this.copyResultsOf(cache, true); } @@ -71,7 +71,7 @@ public RepoTestResultCache(RepoTestResultCache cache) { * @param overrideResultIfPresent Whether the copied expected similarity results * should override any potentially existing ones */ - public void copyResultsOf(RepoTestResultCache cache, boolean overrideResultIfPresent) { + public void copyResultsOf(RepoTestSimilarityResultCache cache, boolean overrideResultIfPresent) { this.similarityResults.addAll(cache.similarityResults); } @@ -115,7 +115,7 @@ public void addResult(String commitID1, String commitID2, boolean expectedResult /** * Uses the reflexivity, symmetry and transitivity assumptions in - * {@link RepoTestResultCache}. Transitivity property will be utilised last, + * {@link RepoTestSimilarityResultCache}. Transitivity property will be utilised last, * i.e. entry chains will only be considered, if there are no direct entries in * this instance or the given commit IDs are equal.
        *
        @@ -309,7 +309,7 @@ public void replaceResult(String commitID1, String commitID2, boolean expectedRe } /** - * See {@link RepoTestResultCache} for assumptions on expected similarity + * See {@link RepoTestSimilarityResultCache} for assumptions on expected similarity * results. * * @return Whether the expected similarity result for the given commits can be diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/eobject/AbstractResourceParsingStrategy.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/eobject/AbstractResourceParsingStrategy.java index 48827d8d44..643d60e8d4 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/eobject/AbstractResourceParsingStrategy.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/eobject/AbstractResourceParsingStrategy.java @@ -132,15 +132,14 @@ protected void preConstructionSetup() { /** * Parses a ResourceSet for the model at given path. * - * TODO Rename parameter - * - * @param modelDir The path to a given model source file directory. Refer to the - * concrete implementation for more information on where this - * path is supposed to point at. + * @param modelSourceFileDirPath The path to a given model source file + * directory. Refer to the concrete implementation + * for more information on where this path is + * supposed to point at. * @return A ResourceSet that contains all parsed Resource instances for the * given model source file directory path. */ - public abstract ResourceSet parseModelResource(Path modelDir); + public abstract ResourceSet parseModelResource(Path modelSourceFileDirPath); /** * @return The extension of the {@link Resource} files, if they are saved. diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/eobject/ResourceTestOptions.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/eobject/ResourceTestOptions.java index 23be8b5a82..5219208c4c 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/eobject/ResourceTestOptions.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/eobject/ResourceTestOptions.java @@ -4,47 +4,47 @@ * A class that contains various options for test classes that use * {@link Resource} instances: *
          - *
        • shouldUnloadAllResources: Whether all created resource instances should - * be unloaded after each test - *
        • shouldDeleteAllResources: Whether all created resource files should be - * deleted after each test + *
        • shouldUnloadAllModelResources: Whether all created model resource + * instances should be unloaded after each test + *
        • shouldDeleteAllModelResources: Whether all created model resource files + * should be deleted after each test *
        - * Note: This class is only responsible for containing Resource-related - * options. Giving these options meanings and applying them is not the concern - * of this class. + * Note: This class is only responsible for containing (model) + * Resource-related options. Giving these options meanings and applying them is + * not the concern of this class. * * @author Alp Torac Genc */ public class ResourceTestOptions { - private boolean shouldUnloadAllResources; - private boolean shouldDeleteAllResources; + private boolean shouldUnloadAllModelResources; + private boolean shouldDeleteAllModelResources; /** * @see {@link ResourceTestOptions} */ - public void setShouldUnloadAllResources(boolean shouldUnloadAllResources) { - this.shouldUnloadAllResources = shouldUnloadAllResources; + public void setShouldUnloadAllModelResources(boolean shouldUnloadAllModelResources) { + this.shouldUnloadAllModelResources = shouldUnloadAllModelResources; } /** * @see {@link ResourceTestOptions} */ - public void setShouldDeleteAllResources(boolean shouldDeleteAllResources) { - this.shouldDeleteAllResources = shouldDeleteAllResources; + public void setShouldDeleteAllModelResources(boolean shouldDeleteAllModelResources) { + this.shouldDeleteAllModelResources = shouldDeleteAllModelResources; } /** * @see {@link ResourceTestOptions} */ - public boolean shouldUnloadAllResources() { - return shouldUnloadAllResources; + public boolean shouldUnloadAllModelResources() { + return shouldUnloadAllModelResources; } /** * @see {@link ResourceTestOptions} */ - public boolean shouldDeleteAllResources() { - return shouldDeleteAllResources; + public boolean shouldDeleteAllModelResources() { + return shouldDeleteAllModelResources; } /** @@ -53,7 +53,7 @@ public boolean shouldDeleteAllResources() { * in this. */ public void copyOptionsFrom(ResourceTestOptions opts) { - this.shouldUnloadAllResources = opts.shouldUnloadAllResources; - this.shouldDeleteAllResources = opts.shouldDeleteAllResources; + this.shouldUnloadAllModelResources = opts.shouldUnloadAllModelResources; + this.shouldDeleteAllModelResources = opts.shouldDeleteAllModelResources; } } diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/AbstractJaMoPPParserSimilarityTest.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/AbstractJaMoPPParserSimilarityTest.java index f301ba3bcc..3aca7bd712 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/AbstractJaMoPPParserSimilarityTest.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/AbstractJaMoPPParserSimilarityTest.java @@ -61,8 +61,8 @@ public abstract class AbstractJaMoPPParserSimilarityTest extends AbstractJaMoPPS * Make sure that the {@link CacheUtil} instance persists throughout tests, * which are supposed to make use of it. * - * @see {@link #parseModelsDirWithoutCaching(Path)} - * @see {@link #parseModelsDirWithCaching(Path)} + * @see {@link #parseModelWithoutCaching(Path)} + * @see {@link #parseModelWithCaching(Path)} */ private static final CacheUtil resourceCache = new CacheUtil(); @@ -112,7 +112,7 @@ public void setUp() { * {@link AbstractJaMoPPParserSimilarityTest}: Performs various operations on * model resources that were parsed in the dynamic tests, according to the * preferences that are encoded in the methods of this test, such as - * {@link AbstractJaMoPPParserSimilarityTest#shouldSaveCachedResources()}. It + * {@link AbstractJaMoPPParserSimilarityTest#shouldSaveCachedModelResources()}. It * then saves the time measurements taken during the tests. See * {@link AbstractJaMoPPParserSimilarityTest} for more information. */ @@ -124,7 +124,7 @@ public void tearDown() { this.startTimeMeasurement(GeneralTimeMeasurementTag.TEST_AFTEREACH); var cachedResources = resourceCache.getCachedResources(); - if (this.getResourceTestOptions().shouldSaveCachedResources()) { + if (this.getResourceTestOptions().shouldSaveCachedModelResources()) { SimilarityTestLogger.logDebugMsg("Saving all cached resources after parser test", this.getClass()); cachedResources.forEach((res) -> { this.startTimeMeasurement( @@ -137,7 +137,7 @@ public void tearDown() { SimilarityTestLogger.logDebugMsg("Saved all cached resources after parser test", this.getClass()); } - if (this.getResourceTestOptions().shouldDeleteAllResources()) { + if (this.getResourceTestOptions().shouldDeleteAllModelResources()) { SimilarityTestLogger.logDebugMsg("Deleting all cached resources after parser test", this.getClass()); cachedResources.forEach((res) -> { this.startTimeMeasurement( @@ -148,7 +148,7 @@ public void tearDown() { this.stopTimeMeasurement(); }); SimilarityTestLogger.logDebugMsg("Deleted all cached resources after parser test", this.getClass()); - } else if (this.getResourceTestOptions().shouldUnloadAllResources()) { + } else if (this.getResourceTestOptions().shouldUnloadAllModelResources()) { SimilarityTestLogger.logDebugMsg("Unloading all cached resources after parser test", this.getClass()); cachedResources.forEach((res) -> { this.startTimeMeasurement( @@ -161,7 +161,7 @@ public void tearDown() { SimilarityTestLogger.logDebugMsg("Unloaded all cached resources after parser test", this.getClass()); } - if (this.getResourceTestOptions().shouldRemoveResourcesFromCache()) { + if (this.getResourceTestOptions().shouldRemoveModelResourcesFromCache()) { SimilarityTestLogger.logDebugMsg("Removing all cached resources from cache after parser test", this.getClass()); this.startTimeMeasurement(GeneralTimeMeasurementTag.MODEL_RESOURCE_CACHE_ACCESS); @@ -195,7 +195,7 @@ protected ParserTestTimeMeasurementKeyBuilder getTimeMeasurementKeyBuilder() { */ protected ParserTestFileLayout initParserTestFileLayout() { var layout = new ParserTestFileLayout(); - layout.setModelSourceFileRootDirPath(new File("").getAbsoluteFile().toPath()); + layout.setModelSourceParentRootDirPath(new File("").getAbsoluteFile().toPath()); layout.setTestModelResourceFilesSaveDirPath(testModelResourceFilesSaveDirPath); layout.setCacheSaveDirPath(cacheSaveDirPath); layout.setTimeMeasurementsFileSavePath(timeMeasurementsFileSavePath); @@ -292,59 +292,65 @@ protected CacheUtil getCacheUtil() { * Therefore, the given model source file directory should only belong to one * model.
        * - * TODO Rename parameter and parameters of all variants TODO Rename method and - * all variants of it (?) - * - * @param modelDir A model source file directory that contains all model source - * files of a (and only one) model + * @param modelSourceFileDirPath Path to a model source file directory that + * contains all model source files of a (and only + * one) model * * @see {@link #isResourceRelevant()} * @see {@link #prepareArtificialResource(Resource, URI)} */ - protected IModelResourceWrapper parseModelsDirWithoutCaching(Path modelDir) { - this.startTimeMeasurement(getTimeMeasurementKeyBuilder().withOriginalModelLocation(modelDir.toString()) - .withResourceParsingStrategyClassName(this.getResourceParsingStrategy().getClass().getSimpleName()), + protected IModelResourceWrapper parseModelWithoutCaching(Path modelSourceFileDirPath) { + this.startTimeMeasurement( + getTimeMeasurementKeyBuilder().withOriginalModelLocation(modelSourceFileDirPath.toString()) + .withResourceParsingStrategyClassName( + this.getResourceParsingStrategy().getClass().getSimpleName()), GeneralTimeMeasurementTag.PARSE_MODEL_RESOURCE); var wrapper = new JaMoPPModelResourceWrapper(this.getResourceParsingStrategy()); - wrapper.parseModelResource(modelDir, this.getTestFileLayout().getModelResourceURI(modelDir)); + wrapper.parseModelResource(modelSourceFileDirPath, + this.getTestFileLayout().getModelResourceURI(modelSourceFileDirPath)); this.stopTimeMeasurement(); return wrapper; } /** - * A variant of {@link #parseModelsDirWithCaching(Path, URI, String)} that uses - * the given path as cache key (converts it to string via - * {@code path.toString()}) + * A variant of {@link #parseModelWithCaching(Path, URI, String)} that uses the + * given path model source file directory as cache key (converts it to string + * via {@code path.toString()}) */ - protected IModelResourceWrapper parseModelsDirWithCaching(Path modelDir) { - return this.parseModelsDirWithCaching(modelDir, modelDir.toString()); + protected IModelResourceWrapper parseModelWithCaching(Path modelSourceFileDirPath) { + return this.parseModelWithCaching(modelSourceFileDirPath, modelSourceFileDirPath.toString()); } /** - * A variant of {@link #parseModelsDirWithCaching(Path, URI, String)} that uses - * {@code this.getModelResourceURI(modelDir)} as cached model URI. + * A variant of {@link #parseModelWithCaching(Path, URI, String)} that uses + * {@link ParserTestFileLayout#getModelResourceURI(Path)} as cached model + * resource URI. */ - protected IModelResourceWrapper parseModelsDirWithCaching(Path modelDir, String cacheKey) { - return this.parseModelsDirWithCaching(modelDir, this.getTestFileLayout().getModelResourceURI(modelDir), - cacheKey); + protected IModelResourceWrapper parseModelWithCaching(Path modelSourceFileDirPath, String modelResourceCacheKey) { + return this.parseModelWithCaching(modelSourceFileDirPath, + this.getTestFileLayout().getModelResourceURI(modelSourceFileDirPath), modelResourceCacheKey); } /** - * Works similar to {@link #parseModelsDirWithCaching(Path)}, except for the - * caching part:
        + * Works similar to {@link #parseModelWithCaching(Path)}, except for the caching + * part:
        *
        - * Checks the cache first for previously parsed model resources, if cacheKey is - * not null. If a model resource from the given path was previously parsed and - * cached under cacheKey, returns the cached model resource (at cachedModelURI) - * instead. If there were no cached model resources for the given path, adds the - * parsed model resource to the cache under cacheKey. - */ - protected IModelResourceWrapper parseModelsDirWithCaching(Path modelDir, URI cachedModelURI, String cacheKey) { - this.startTimeMeasurement(getTimeMeasurementKeyBuilder().withOriginalModelLocation(modelDir.toString()) - .withParsedModelLocation(cachedModelURI.toString()), + * Checks the cache first for previously parsed model resources, if + * modelResourceCacheKey is not null. If a model resource from the given path + * model source file directory was previously parsed and cached under + * modelResourceCacheKey, returns the cached model resource (at + * modelResourceCachedURI) instead. If there were no cached model resources for + * the given path, adds the parsed model resource to the cache under + * modelResourceCacheKey. + */ + protected IModelResourceWrapper parseModelWithCaching(Path modelSourceFileDirPath, URI modelResourceCachedURI, + String modelResourceCacheKey) { + this.startTimeMeasurement( + getTimeMeasurementKeyBuilder().withOriginalModelLocation(modelSourceFileDirPath.toString()) + .withParsedModelLocation(modelResourceCachedURI.toString()), GeneralTimeMeasurementTag.MODEL_RESOURCE_CACHE_ACCESS); var cache = this.getCacheUtil(); - var modelName = this.getDisplayNameForModelDir(modelDir); + var modelName = this.getDisplayNameForModelSourceFileDir(modelSourceFileDirPath); IModelResourceWrapper resWrapper = null; @@ -354,16 +360,16 @@ protected IModelResourceWrapper parseModelsDirWithCaching(Path modelDir, URI cac * automatically loaded in the background when needed. */ - if (cacheKey != null) { + if (modelResourceCacheKey != null) { // Search for the resource in the cache - if (cache.isInCache(cacheKey)) { + if (cache.isInCache(modelResourceCacheKey)) { SimilarityTestLogger.logDebugMsg(String.format("%s is in cache, using cached version", modelName), this.getClass()); - resWrapper = cache.getFromCache(cacheKey); + resWrapper = cache.getFromCache(modelResourceCacheKey); if (!resWrapper.isModelResourceLoaded()) { this.startTimeMeasurement( - getTimeMeasurementKeyBuilder().withOriginalModelLocation(modelDir.toString()) - .withParsedModelLocation(cachedModelURI.toString()), + getTimeMeasurementKeyBuilder().withOriginalModelLocation(modelSourceFileDirPath.toString()) + .withParsedModelLocation(modelResourceCachedURI.toString()), GeneralTimeMeasurementTag.LOAD_MODEL_RESOURCE); resWrapper.loadParsedResources(); this.stopTimeMeasurement(); @@ -374,10 +380,10 @@ protected IModelResourceWrapper parseModelsDirWithCaching(Path modelDir, URI cac if (resWrapper == null) { resWrapper = new JaMoPPModelResourceWrapper(); this.startTimeMeasurement( - getTimeMeasurementKeyBuilder().withOriginalModelLocation(modelDir.toString()) - .withParsedModelLocation(cachedModelURI.toString()), + getTimeMeasurementKeyBuilder().withOriginalModelLocation(modelSourceFileDirPath.toString()) + .withParsedModelLocation(modelResourceCachedURI.toString()), GeneralTimeMeasurementTag.LOAD_MODEL_RESOURCE); - resWrapper.loadModelResource(cachedModelURI); + resWrapper.loadModelResource(modelResourceCachedURI); this.stopTimeMeasurement(); if (resWrapper.isModelResourceLoaded()) { SimilarityTestLogger.logDebugMsg(String.format("Loaded %s from its resource file", modelName), @@ -388,31 +394,29 @@ protected IModelResourceWrapper parseModelsDirWithCaching(Path modelDir, URI cac // Resource is completely new, parse it from scratch if (resWrapper == null || !resWrapper.isModelResourceLoaded()) { - resWrapper = this.parseModelsDirWithoutCaching(modelDir); + resWrapper = this.parseModelWithoutCaching(modelSourceFileDirPath); } - var key = cacheKey != null ? cacheKey : modelDir.toString(); + var key = modelResourceCacheKey != null ? modelResourceCacheKey : modelSourceFileDirPath.toString(); cache.addToCache(key, resWrapper); this.stopTimeMeasurement(); - SimilarityTestLogger.logDebugMsg( - String.format("%s parsed (with caching)", this.getDisplayNameForModelDir(modelDir)), this.getClass()); + SimilarityTestLogger.logDebugMsg(String.format("%s parsed (with caching)", + this.getDisplayNameForModelSourceFileDir(modelSourceFileDirPath)), this.getClass()); return resWrapper; } /** - * TODO Rename parameter - * - * @param modelDir A directory that directly contains the Java-model files - * @return The test display name for the given modelPath + * @param modelSourceFileDirPath Path to the model source file directory + * @return The test display name for the given path */ - protected String getDisplayNameForModelDir(Path modelPath) { - var nameCount = modelPath.getNameCount(); + protected String getDisplayNameForModelSourceFileDir(Path modelSourceFileDirPath) { + var nameCount = modelSourceFileDirPath.getNameCount(); var startIndex = nameCount > 2 ? nameCount - 2 : nameCount - 1; var endIndex = nameCount; - return modelPath.subpath(startIndex, endIndex).toString(); + return modelSourceFileDirPath.subpath(startIndex, endIndex).toString(); } /** @@ -429,64 +433,72 @@ protected boolean isModelSourceFileDirectory(File f) { } /** - * Derives the path to the model resources from their URI. + * Derives the path to the model resources from their URI. Assumes that the URI + * of the provided resources point at the model source file directory. * - * @param resArr An array of parsed model resources + * @param modelResources An array of parsed model resources * @return Dynamic test instances for the given model resources * @see {@link #createTests()} */ - public Collection createTests(Resource[] resArr) { - var pathArr = new Path[resArr.length]; + public Collection createTests(Resource[] modelResources) { + var pathArr = new Path[modelResources.length]; for (int i = 0; i < pathArr.length; i++) { - pathArr[i] = Path.of(resArr[i].getURI().path()); + pathArr[i] = Path.of(modelResources[i].getURI().path()); } - return this.createTests(pathArr, resArr); + return this.createTests(pathArr, modelResources); } /** - * Parses model resources (with caching) for each given path. + * Parses model resources (with caching) for each given model source file + * directory path. * - * @param pathArr An array of paths to model source file directories + * @param modelSourceFileDirPaths An array of paths to model source file + * directories * @return Dynamic test instances for the models under the given paths * @see {@link #createTests()} */ - public Collection createTests(Path[] pathArr) { - var resArr = new Resource[pathArr.length]; + public Collection createTests(Path[] modelSourceFileDirPaths) { + var resArr = new Resource[modelSourceFileDirPaths.length]; for (int i = 0; i < resArr.length; i++) { - resArr[i] = this.parseModelsDirWithCaching(pathArr[i]).getModelResource(); + resArr[i] = this.parseModelWithCaching(modelSourceFileDirPaths[i]).getModelResource(); } - return this.createTests(pathArr, resArr); + return this.createTests(modelSourceFileDirPaths, resArr); } /** - * @param pathArr An array of paths to model source file directories - * @param resArr An array of parsed model resources + * Paths to model source file directories and corresponding parsed model + * resources should be provided in the same order. + * + * @param modelSourceFileDirPaths An array of paths to model source file + * directories + * @param modelResources An array of parsed model resources * @return Dynamic test instances for the given model resources * @see {@link #createTests()} */ - public Collection createTests(Path[] pathArr, Resource[] resArr) { - if (pathArr.length != resArr.length) { + public Collection createTests(Path[] modelSourceFileDirPaths, Resource[] modelResources) { + if (modelSourceFileDirPaths.length != modelResources.length) { Assertions.fail("Lengths of path and resource arrays do not match"); } var tests = new ArrayList(); - this.getTestGenerationStrategies().forEach((testStrat) -> { + this.getTestGenerationStrategies().forEach((testGenStrat) -> { this.getTestFactories().forEach((tf) -> { - var testsForModelDirs = new ArrayList(); - testStrat.getTestResourceIterator(resArr.length).forEachRemaining((idxs) -> { - var path1 = pathArr[idxs[0]]; - var res1 = resArr[idxs[0]]; - var path2 = pathArr[idxs[1]]; - var res2 = resArr[idxs[1]]; - testsForModelDirs.add(tf.createTestsFor(res1, path1, res2, path2)); + var testsForModelSourceFileDirs = new ArrayList(); + testGenStrat.getTestResourceIterator(modelResources.length).forEachRemaining((idxs) -> { + var modelSourceFileDirPath1 = modelSourceFileDirPaths[idxs[0]]; + var modelResource1 = modelResources[idxs[0]]; + var modelSourceFileDirPath2 = modelSourceFileDirPaths[idxs[1]]; + var modelResource2 = modelResources[idxs[1]]; + testsForModelSourceFileDirs.add(tf.createTestsFor(modelResource1, modelSourceFileDirPath1, + modelResource2, modelSourceFileDirPath2)); }); tests.add(DynamicContainer.dynamicContainer(String.format("%s (with %s)", tf.getTestDescription(), - testStrat.getTestGenerationStrategyDescription()), testsForModelDirs)); + testGenStrat.getTestGenerationStrategyDescription()), testsForModelSourceFileDirs)); }); }); @@ -494,7 +506,7 @@ public Collection createTests(Path[] pathArr, Resource[] resArr) { } /** - * Generates dynamic tests for each model source file directories based on the + * Generates dynamic tests for each model source file directory based on the * registered {@link AbstractJaMoPPParserSimilarityTestFactory} instances. * Implemented here in efforts to have a unified template for dynamic test * generation.
        @@ -508,39 +520,39 @@ public Collection createTests(Path[] pathArr, Resource[] resArr) { * {@link TestFactory}, which will run the tests generated here. * * @see {@link #discoverModelSourceFileDirsAt(Path)} and - * {@link #discoverModelSourceParentDirsAt(Path)} for locating model source - * file directories + * {@link #discoverModelSourceParentDirsAt(Path)} for finding models to + * parse * @see {@link TestFactory} for what tests are to be generated */ @TestFactory public Collection createTests() { this.startTimeMeasurement(GeneralTimeMeasurementTag.DYNAMIC_TEST_CREATION); - var modelSourceFileRootDirPath = this.getTestFileLayout().getModelSourceFileRootDirPath(); + var modelSourceParentRootDirPath = this.getTestFileLayout().getModelSourceParentRootDirPath(); var tests = new ArrayList(); - var modelParentDirs = this.discoverModelSourceParentDirsAt(modelSourceFileRootDirPath); - var modelDirMap = new HashMap>(); + var modelSourceParentDirs = this.discoverModelSourceParentDirsAt(modelSourceParentRootDirPath); + var modelSourceFileDirMap = new HashMap>(); - for (var parentDir : modelParentDirs) { - modelDirMap.put(parentDir, this.discoverModelSourceFileDirsAt(parentDir)); + for (var modelSourceParentDir : modelSourceParentDirs) { + modelSourceFileDirMap.put(modelSourceParentDir, this.discoverModelSourceFileDirsAt(modelSourceParentDir)); } - var testsForModelParentDirs = new ArrayList(); - modelParentDirs.forEach((md) -> { - final var modelDirs = modelDirMap.get(md); + var testsForModelSourceParentDirs = new ArrayList(); + modelSourceParentDirs.forEach((md) -> { + final var modelSourceFileDirs = modelSourceFileDirMap.get(md); - var testsForModelDirs = this.createTests(modelDirs.toArray(Path[]::new)); + var testsForModelSourceFileDirs = this.createTests(modelSourceFileDirs.toArray(Path[]::new)); - testsForModelParentDirs.add(DynamicContainer.dynamicContainer( + testsForModelSourceParentDirs.add(DynamicContainer.dynamicContainer( String.format("model = %s", this.getTestFileLayout().getRelativeModelSourceParentDirPath(md)), - testsForModelDirs)); + testsForModelSourceFileDirs)); }); tests.add(DynamicContainer.dynamicContainer( - String.format("root = %s", this.getTestFileLayout().getRelativeModelSourceFileRootDirPath()), - testsForModelParentDirs)); + String.format("root = %s", this.getTestFileLayout().getRelativeModelSourceParentRootDirPath()), + testsForModelSourceParentDirs)); this.stopTimeMeasurement(); return tests; @@ -556,32 +568,37 @@ public Collection createTests() { protected abstract Collection getTestFactories(); /** - * @param rootPath The top-most directory, whose contents should be scanned for - * model source file directories - * @return A collection of model source file directory paths under rootPath + * @param modelSourceParentDirPath A potential model source parent directory + * path, whose contents should be scanned for + * model source file directories + * @return A collection of model source file directory paths under + * modelSourceParentDirPath */ - protected Collection discoverModelSourceFileDirsAt(Path rootPath) { - var discoveryStrat = new ModelDirDiscoveryStrategy((f) -> this.isModelSourceFileDirectory(f)); - this.startTimeMeasurement(getTimeMeasurementKeyBuilder().withModelDiscoveryPath(rootPath.toString()) - .withModelDiscoveryClassName(discoveryStrat.getClass().getSimpleName()), + protected Collection discoverModelSourceFileDirsAt(Path modelSourceParentDirPath) { + var modelDiscoveryStrat = new ModelDiscoveryStrategy((f) -> this.isModelSourceFileDirectory(f)); + this.startTimeMeasurement( + getTimeMeasurementKeyBuilder().withModelDiscoveryPath(modelSourceParentDirPath.toString()) + .withModelDiscoveryClassName(modelDiscoveryStrat.getClass().getSimpleName()), GeneralTimeMeasurementTag.DISCOVER_MODEL_RESOURCES); - var result = discoveryStrat.discoverModelSourceDirs(rootPath.toFile()); + var result = modelDiscoveryStrat.discoverModelSourceFileDirs(modelSourceParentDirPath.toFile()); this.stopTimeMeasurement(); return result; } /** - * @param rootPath The top-most directory, whose contents should be scanned for - * directories containing model source parent directories. + * @param modelSourceParentRootPath The top-most directory, whose contents + * should be scanned for directories containing + * model source parent directories. * @return A collection of paths of model source parent directories under - * rootPath + * modelSourceParentRootPath */ - protected Collection discoverModelSourceParentDirsAt(Path rootPath) { - var discoveryStrat = new ModelDirDiscoveryStrategy((f) -> this.isModelSourceFileDirectory(f)); - this.startTimeMeasurement(getTimeMeasurementKeyBuilder().withModelDiscoveryPath(rootPath.toString()) - .withModelDiscoveryClassName(discoveryStrat.getClass().getSimpleName()), + protected Collection discoverModelSourceParentDirsAt(Path modelSourceParentRootPath) { + var modelDiscoveryStrat = new ModelDiscoveryStrategy((f) -> this.isModelSourceFileDirectory(f)); + this.startTimeMeasurement( + getTimeMeasurementKeyBuilder().withModelDiscoveryPath(modelSourceParentRootPath.toString()) + .withModelDiscoveryClassName(modelDiscoveryStrat.getClass().getSimpleName()), GeneralTimeMeasurementTag.DISCOVER_MODEL_RESOURCES); - var result = discoveryStrat.discoverModelSourceParentDirs(rootPath.toFile()); + var result = modelDiscoveryStrat.discoverModelSourceParentDirs(modelSourceParentRootPath.toFile()); this.stopTimeMeasurement(); return result; } @@ -631,11 +648,11 @@ protected ParserTestOptions initResourceTestOptions() { * Parser tests require the created resource files to persist across tests, as * they are cached. */ - opts.setShouldDeleteAllResources(false); - opts.setShouldUnloadAllResources(false); + opts.setShouldDeleteAllModelResources(false); + opts.setShouldUnloadAllModelResources(false); - opts.setShouldSaveCachedResources(true); - opts.setShouldRemoveResourcesFromCache(false); + opts.setShouldSaveCachedModelResources(true); + opts.setShouldRemoveModelResourcesFromCache(false); return opts; } diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/IModelDirDiscoveryStrategy.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/IModelDiscoveryStrategy.java similarity index 53% rename from commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/IModelDirDiscoveryStrategy.java rename to commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/IModelDiscoveryStrategy.java index 425f698b25..490e28322c 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/IModelDirDiscoveryStrategy.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/IModelDiscoveryStrategy.java @@ -9,39 +9,43 @@ * model source file directories. The method of discovery depends on the * concrete implementor. * - * TODO Rename interface TODO Rename parameters - * * @author Alp Torac Genc */ -public interface IModelDirDiscoveryStrategy { +public interface IModelDiscoveryStrategy { /** * Finds and returns paths to all model source parent directories. Use - * {@link #discoverModelSourceDirs(File)} on the directories found here to get - * the model source file directories. + * {@link #discoverModelSourceFileDirs(File)} on the directories found here to + * get the model source file directories. * * @param dirToDiscover The top-most directory, whose contents will be scanned * for model source parent directories * - * @return All model source parent directories containing model source file + * @return All model source parent directory paths containing model source file * directories that are found according to the concrete implementor. + * Returned paths are the longest common model source file directory + * paths. */ public Collection discoverModelSourceParentDirs(File dirToDiscover); /** - * Finds and returns paths to all model source file directories. + * Finds and returns paths to all model source file directories. Should be used + * in conjunction with {@link #discoverModelSourceParentDirs(File)}, unless + * model source parent directories are already known. * - * @param dirToDiscover The top-most directory, whose contents will be scanned - * for model source file directories + * @param modelSourceParentDirToExplore The top-most directory, whose contents + * will be scanned for model source file + * directories. Should be a model source + * parent directory. * * @return All model source file directories that are found according to the - * concrete implementor + * concrete implementor. */ - public Collection discoverModelSourceDirs(File dirToDiscover); + public Collection discoverModelSourceFileDirs(File modelSourceParentDirToExplore); /** * @param dir A potential model source file directory that contains model source * files of one (and only one) model * @return Whether the given directory is a model source file directory */ - public boolean isModelSourceDirectory(File dir); + public boolean isModelSourceFileDirectory(File dir); } diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ModelDirDiscoveryStrategy.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ModelDirDiscoveryStrategy.java deleted file mode 100644 index 1b0bb201c4..0000000000 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ModelDirDiscoveryStrategy.java +++ /dev/null @@ -1,121 +0,0 @@ -package cipm.consistency.fitests.similarity.jamopp.parser; - -import java.io.File; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.Collection; -import java.util.function.Predicate; - -/** - * A concrete implementation that considers one top-most directory and discovers - * its contents, similar to depth first search but with a single start point. - * Uses a given filter to determine whether a given directory is a model source - * file directory and encompasses one (and only one) model. - * - * TODO Rename methods and parameters - * - * @author Alp Torac Genc - */ -public class ModelDirDiscoveryStrategy implements IModelDirDiscoveryStrategy { - private Predicate modelDirFilter; - - /** - * Constructs an instance. - * - * @param modelDirFilter A filter for determining whether a given directory is a - * model source file directory and encompasses one (and - * only one) model - */ - public ModelDirDiscoveryStrategy(Predicate modelDirFilter) { - this.modelDirFilter = modelDirFilter; - } - - /** - * @param modelParentDirPath A model source parent directory, which potentially - * contains model source file directories - * @return All model source file directories under the given path to model - * source parent directory - * - * @see {@link #isModelSourceDirectory(File)} - */ - protected Collection getAllModelDirsUnder(Path modelParentDirPath) { - var result = new ArrayList(); - var dirs = modelParentDirPath.toFile().listFiles(); - for (var dir : dirs) { - if (this.isModelSourceDirectory(dir)) { - result.add(dir.toPath()); - } - } - return result; - } - - /** - * @implSpec Determines whether a discovered directory is a model source file - * directory using the filter from the constructor - * ({@link #ModelDirDiscoveryStrategy(Path, Predicate)}). Any - * directory that is considered a model source file directory is - * assumed to encapsulate one (and only one) model, even if it - * contains multiple models in reality. - */ - @Override - public boolean isModelSourceDirectory(File dir) { - if (this.modelDirFilter == null) { - return true; - } else { - return this.modelDirFilter.test(dir); - } - } - - /** - * Recursively searches for model source file directories containing Java-Model - * files, starting from the given directory, and returns a list of all model - * source file directories. - */ - protected Collection discoverModels(File dirToDiscover) { - var foundModelDirs = new ArrayList(); - discoverModels(dirToDiscover, foundModelDirs); - return foundModelDirs; - } - - /** - * Recursively searches for model source files directories. All directories - * containing models (determined via {@link #isModelSourceDirectory(File)}) will - * be added to foundModelDirs, if not already there. - * - * @param dirToDiscover The directory, where the recursive search shall begin - * @param foundModelDirs A collection of model source file directories - */ - protected void discoverModels(File dirToDiscover, Collection foundModelDirs) { - if (dirToDiscover != null && dirToDiscover.isDirectory()) { - var discovered = new ArrayList(); - - for (var f : dirToDiscover.listFiles()) { - if (!this.isModelSourceDirectory(f)) { - discovered.add(f); - } else if (!foundModelDirs.contains(dirToDiscover.toPath())) { - foundModelDirs.add(dirToDiscover.toPath()); - } - } - - discovered.forEach((d) -> discoverModels(d, foundModelDirs)); - } - } - - /** - * @implSpec Check {@link #isModelSourceDirectory(File)} for more details on how - * model source file directories are filtered. - */ - @Override - public Collection discoverModelSourceDirs(File dirToDiscover) { - return this.getAllModelDirsUnder(dirToDiscover.toPath()); - } - - /** - * @implSpec Check {@link #isModelSourceDirectory(File)} for more details on how - * model source file directories are filtered. - */ - @Override - public Collection discoverModelSourceParentDirs(File dirToDiscover) { - return this.discoverModels(dirToDiscover); - } -} diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ModelDiscoveryStrategy.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ModelDiscoveryStrategy.java new file mode 100644 index 0000000000..667389f303 --- /dev/null +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ModelDiscoveryStrategy.java @@ -0,0 +1,126 @@ +package cipm.consistency.fitests.similarity.jamopp.parser; + +import java.io.File; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collection; +import java.util.function.Predicate; + +/** + * A concrete implementation that considers one top-most directory and discovers + * its contents for models, similar to depth first search but with a single + * start point. Uses a given filter to determine whether a given directory is a + * model source file directory and encompasses one (and only one) model. + * + * @author Alp Torac Genc + */ +public class ModelDiscoveryStrategy implements IModelDiscoveryStrategy { + private Predicate modelSourceFileDirFilter; + + /** + * Constructs an instance. + * + * @param modelSourceFileDirFilter A filter for determining whether a given + * directory is a model source file directory + * and encompasses one (and only one) model + */ + public ModelDiscoveryStrategy(Predicate modelSourceFileDirFilter) { + this.modelSourceFileDirFilter = modelSourceFileDirFilter; + } + + /** + * @param modelSourceParentDirPath A potential model source parent directory, + * which potentially contains model source file + * directories + * @return All model source file directories under the given path to potential + * model source parent directory + * + * @see {@link #isModelSourceFileDirectory(File)} + */ + protected Collection getAllModelSourceFileDirsUnder(Path modelSourceParentDirPath) { + var modelSourceFileDirPaths = new ArrayList(); + var dirs = modelSourceParentDirPath.toFile().listFiles(); + for (var dir : dirs) { + if (this.isModelSourceFileDirectory(dir)) { + modelSourceFileDirPaths.add(dir.toPath()); + } + } + return modelSourceFileDirPaths; + } + + /** + * @implSpec Determines whether a discovered directory is a model source file + * directory using the filter from the constructor + * ({@link #ModelDirDiscoveryStrategy(Path, Predicate)}). Any + * directory that is considered a model source file directory is + * assumed to encapsulate one (and only one) model, even if it + * contains multiple models in reality. + */ + @Override + public boolean isModelSourceFileDirectory(File dir) { + if (this.modelSourceFileDirFilter == null) { + return true; + } else { + return this.modelSourceFileDirFilter.test(dir); + } + } + + /** + * Recursively searches for model source parent directories, starting from the + * given directory, and returns a list of all model source parent directories. + * + * @see {@link #findModelSourceParentDirs(File, Collection)} for more + * information. + */ + protected Collection findModelSourceParentDirs(File dirToDiscover) { + var foundModelDirs = new ArrayList(); + findModelSourceParentDirs(dirToDiscover, foundModelDirs); + return foundModelDirs; + } + + /** + * Recursively searches for model source parent directories. All directories + * containing models (determined via {@link #isModelSourceFileDirectory(File)}) + * will be added to foundModelSourceParentDirs, if not already there. + * + * @param dirToDiscover The directory, whose contents will be + * explored + * @param foundModelSourceParentDirs A collection of model source parent + * directories. The found model source parent + * directories' path is the parent directory + * of nested model source file directories + */ + protected void findModelSourceParentDirs(File dirToDiscover, Collection foundModelSourceParentDirs) { + if (dirToDiscover != null && dirToDiscover.isDirectory()) { + var discovered = new ArrayList(); + + for (var f : dirToDiscover.listFiles()) { + if (!this.isModelSourceFileDirectory(f)) { + discovered.add(f); + } else if (!foundModelSourceParentDirs.contains(dirToDiscover.toPath())) { + foundModelSourceParentDirs.add(dirToDiscover.toPath()); + } + } + + discovered.forEach((d) -> findModelSourceParentDirs(d, foundModelSourceParentDirs)); + } + } + + /** + * @implSpec Check {@link #isModelSourceFileDirectory(File)} for more details on + * how model source file directories are filtered. + */ + @Override + public Collection discoverModelSourceFileDirs(File modelSourceParentDirToExplore) { + return this.getAllModelSourceFileDirsUnder(modelSourceParentDirToExplore.toPath()); + } + + /** + * @implSpec Check {@link #isModelSourceFileDirectory(File)} for more details on + * how model source file directories are filtered. + */ + @Override + public Collection discoverModelSourceParentDirs(File dirToDiscover) { + return this.findModelSourceParentDirs(dirToDiscover); + } +} diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ParserTestFileLayout.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ParserTestFileLayout.java index 9b6c3dddc0..c5305940d3 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ParserTestFileLayout.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ParserTestFileLayout.java @@ -8,15 +8,13 @@ /** * Contains layout-related information for the corresponding parser test. * - * TODO Rename parameters and methods - * * @author Alp Torac Genc */ public class ParserTestFileLayout { /** - * @see {@link #getModelSourceFileRootDirPath()} + * @see {@link #getModelSourceParentRootDirPath()} */ - private Path modelSourceFileRootDirPath; + private Path modelSourceParentRootDirPath; /** * @see {@link #setTestModelResourceFilesSaveDirPath(Path)} */ @@ -54,8 +52,8 @@ public ParserTestFileLayout(ParserTestFileLayout layout) { /** * {@link #getModelSourceFileRootDirPath(Path)} */ - public void setModelSourceFileRootDirPath(Path modelSourceFileRootDirPath) { - this.modelSourceFileRootDirPath = modelSourceFileRootDirPath; + public void setModelSourceParentRootDirPath(Path modelSourceParentRootDirPath) { + this.modelSourceParentRootDirPath = modelSourceParentRootDirPath; } /** @@ -158,10 +156,11 @@ public URI getModelResourceURI(Path modelDir) { * Defaults to {@link #getAbsoluteCurrentDirectory()}. * * @return Path to the top-most model source parent directory, under which all - * models' source file directories reside + * models' source parent directories (and thus model source file + * directories too) reside */ - public Path getModelSourceFileRootDirPath() { - return this.modelSourceFileRootDirPath; + public Path getModelSourceParentRootDirPath() { + return this.modelSourceParentRootDirPath; } /** @@ -174,21 +173,22 @@ public Path getModelResourceSaveRootDirectory() { /** * @return The relative path between the current directory and - * ({@link #getModelSourceFileRootDirPath()}). - * @see {@link #getModelSourceFileRootDirPath()} + * ({@link #getModelSourceParentRootDirPath()}). + * @see {@link #getModelSourceParentRootDirPath()} */ - public Path getRelativeModelSourceFileRootDirPath() { - return this.getAbsoluteCurrentDirectory().relativize(this.getModelSourceFileRootDirPath()); + public Path getRelativeModelSourceParentRootDirPath() { + return this.getAbsoluteCurrentDirectory().relativize(this.getModelSourceParentRootDirPath()); } /** * @param modelParentDirPath A model source parent directory path - * @return The relative path between ({@link #getModelSourceFileRootDirPath()}) - * and the given model source parent path. If both paths are the same, - * returns the file name (without extension) in the parameter. + * @return The relative path between + * ({@link #getModelSourceParentRootDirPath()}) and the given model + * source parent path. If both paths are the same, returns the file name + * (without extension) in the parameter. */ public Path getRelativeModelSourceParentDirPath(Path modelParentDirPath) { - var rootPath = this.getModelSourceFileRootDirPath(); + var rootPath = this.getModelSourceParentRootDirPath(); var relPath = rootPath.relativize(modelParentDirPath); if (relPath.getParent() == null) { return modelParentDirPath.getFileName(); diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ParserTestOptions.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ParserTestOptions.java index 9594d2d90f..9194a75606 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ParserTestOptions.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ParserTestOptions.java @@ -6,47 +6,45 @@ * A class that contains various options for test classes that parse * {@link Resource} instances and cache them: *
          - *
        • shouldSaveCachedResources: Whether the cached model resources should be - * saved after tests - *
        • shouldRemoveResourcesFromCache: Whether cached model resources should be - * removed after each test deleted after tests + *
        • shouldSaveCachedModelResources: Whether the cached model resources should + * be saved after tests + *
        • shouldRemoveModelResourcesFromCache: Whether cached model resources + * should be removed after each test deleted after tests *
        * - * TODO Rename methods - * * @see {@link ResourceTestOptions} for other options * @author Alp Torac Genc */ public class ParserTestOptions extends ResourceTestOptions { - private boolean shouldSaveCachedResources; - private boolean shouldRemoveResourcesFromCache; + private boolean shouldSaveCachedModelResources; + private boolean shouldRemoveModelResourcesFromCache; /** * @see {@link ParserTestOptions} */ - public void setShouldSaveCachedResources(boolean shouldSaveCachedResources) { - this.shouldSaveCachedResources = shouldSaveCachedResources; + public void setShouldSaveCachedModelResources(boolean shouldSaveCachedModelResources) { + this.shouldSaveCachedModelResources = shouldSaveCachedModelResources; } /** * @see {@link ParserTestOptions} */ - public void setShouldRemoveResourcesFromCache(boolean shouldRemoveResourcesFromCache) { - this.shouldRemoveResourcesFromCache = shouldRemoveResourcesFromCache; + public void setShouldRemoveModelResourcesFromCache(boolean shouldRemoveModelResourcesFromCache) { + this.shouldRemoveModelResourcesFromCache = shouldRemoveModelResourcesFromCache; } /** * @see {@link ParserTestOptions} */ - public boolean shouldSaveCachedResources() { - return shouldSaveCachedResources; + public boolean shouldSaveCachedModelResources() { + return shouldSaveCachedModelResources; } /** * @see {@link ParserTestOptions} */ - public boolean shouldRemoveResourcesFromCache() { - return shouldRemoveResourcesFromCache; + public boolean shouldRemoveModelResourcesFromCache() { + return shouldRemoveModelResourcesFromCache; } /** @@ -56,7 +54,7 @@ public boolean shouldRemoveResourcesFromCache() { */ public void copyOptionsFrom(ParserTestOptions opts) { super.copyOptionsFrom(opts); - this.shouldSaveCachedResources = opts.shouldSaveCachedResources; - this.shouldRemoveResourcesFromCache = opts.shouldRemoveResourcesFromCache; + this.shouldSaveCachedModelResources = opts.shouldSaveCachedModelResources; + this.shouldRemoveModelResourcesFromCache = opts.shouldRemoveModelResourcesFromCache; } } diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/resultprovider/FileContentSimilarityResultProvider.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/resultprovider/FileContentSimilarityResultProvider.java index 240a6e2bd2..c4fb4134d5 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/resultprovider/FileContentSimilarityResultProvider.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/resultprovider/FileContentSimilarityResultProvider.java @@ -22,7 +22,8 @@ public class FileContentSimilarityResultProvider implements IExpectedSimilarityR * similar. */ @Override - public boolean getExpectedSimilarityResultFor(Resource lhsRes, Path lhsResPath, Resource rhsRes, Path rhsResPath) { - return FileUtil.areContentsEqual(lhsResPath, rhsResPath); + public boolean getExpectedSimilarityResultFor(Resource lhsModelResource, Path lhsModelSourceFileDirPath, + Resource rhsModelResource, Path rhsModelSourceFileDirPath) { + return FileUtil.areContentsEqual(lhsModelSourceFileDirPath, rhsModelSourceFileDirPath); } } diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/resultprovider/IExpectedSimilarityResultProvider.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/resultprovider/IExpectedSimilarityResultProvider.java index a27c18ffdb..07909b3b36 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/resultprovider/IExpectedSimilarityResultProvider.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/resultprovider/IExpectedSimilarityResultProvider.java @@ -14,8 +14,6 @@ * expected similarity results of others. How the expected similarity results * are derived and provided depends on the concrete implementor. * - * TODO Rename parameters - * * @author Alp Torac Genc */ public interface IExpectedSimilarityResultProvider { @@ -25,16 +23,19 @@ public interface IExpectedSimilarityResultProvider { * model source files / model source file directories) may reside under * different paths, which cannot be determined from the model resource alone. * - * @param lhsRes Left-hand side resource - * @param lhsResPath The path that the resource lhsRes was originally parsed - * from, i.e. the path to the model source file / model source - * file directory. - * @param rhsRes Right-hand side resource - * @param rhsResPath The path that the resource rhsRes was originally parsed - * from, i.e. the path to the model source file / model source - * file directory. + * @param lhsModelResource Left-hand side model resource + * @param lhsModelSourceFileDirPath The path that the resource lhsRes was + * originally parsed from, i.e. the path to the + * model source file / model source file + * directory. + * @param rhsModelResource Right-hand side model resource + * @param rhsModelSourceFileDirPath The path that the resource rhsRes was + * originally parsed from, i.e. the path to the + * model source file / model source file + * directory. * @return The expected result of similarity checking the given resources, * according to the concrete implementor. */ - public boolean getExpectedSimilarityResultFor(Resource lhsRes, Path lhsResPath, Resource rhsRes, Path rhsResPath); + public boolean getExpectedSimilarityResultFor(Resource lhsModelResource, Path lhsModelSourceFileDirPath, + Resource rhsModelResource, Path rhsModelSourceFileDirPath); } diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/resultprovider/ResourceContentSimilarityResultProvider.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/resultprovider/ResourceContentSimilarityResultProvider.java index 02f338560f..2e2f75b56f 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/resultprovider/ResourceContentSimilarityResultProvider.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/resultprovider/ResourceContentSimilarityResultProvider.java @@ -112,8 +112,9 @@ private boolean contentwiseSimilar(Collection lhs, Collection * case */ @Override - public boolean getExpectedSimilarityResultFor(Resource lhsRes, Path lhsResPath, Resource rhsRes, Path rhsResPath) { - var pathsEqual = lhsResPath.toString().equals(rhsResPath.toString()); - return pathsEqual || (!this.contentOrderMatters && this.contentwiseSimilar(lhsRes, rhsRes)); + public boolean getExpectedSimilarityResultFor(Resource lhsModelResource, Path lhsModelSourceFileDirPath, + Resource rhsModelResource, Path rhsModelSourceFileDirPath) { + var pathsEqual = lhsModelSourceFileDirPath.toString().equals(rhsModelSourceFileDirPath.toString()); + return pathsEqual || (!this.contentOrderMatters && this.contentwiseSimilar(lhsModelResource, rhsModelResource)); } } diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/resultprovider/ResourceReferenceEqualitySimilarityResultProvider.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/resultprovider/ResourceReferenceEqualitySimilarityResultProvider.java index 9b49a5d84c..6423908887 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/resultprovider/ResourceReferenceEqualitySimilarityResultProvider.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/resultprovider/ResourceReferenceEqualitySimilarityResultProvider.java @@ -13,10 +13,12 @@ public class ResourceReferenceEqualitySimilarityResultProvider implements IExpectedSimilarityResultProvider { /** * @implSpec Determines expected similarity results based on the reference - * equality of model resources, i.e. {@code lhsRes == rhsRes} + * equality of model resources, i.e. + * {@code lhsModelResource == rhsModelResource} */ @Override - public boolean getExpectedSimilarityResultFor(Resource lhsRes, Path lhsResPath, Resource rhsRes, Path rhsResPath) { - return lhsRes == rhsRes; + public boolean getExpectedSimilarityResultFor(Resource lhsModelResource, Path lhsModelSourceFileDirPath, + Resource rhsModelResource, Path rhsModelSourceFileDirPath) { + return lhsModelResource == rhsModelResource; } } diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/testfactory/AbstractJaMoPPParserSimilarityTestFactory.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/testfactory/AbstractJaMoPPParserSimilarityTestFactory.java index b84095e963..e4f578c545 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/testfactory/AbstractJaMoPPParserSimilarityTestFactory.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/testfactory/AbstractJaMoPPParserSimilarityTestFactory.java @@ -15,8 +15,6 @@ * An abstract class meant to be implemented by classes that encapsulate logic * about dynamic test generation. * - * TODO Rename parameters - * * @author Alp Torac Genc */ public abstract class AbstractJaMoPPParserSimilarityTestFactory { @@ -90,12 +88,14 @@ public String getTestDescription() { * * @see {@link #getExpectedSimilarityResultProvider()} */ - public boolean getExpectedSimilarityResultFor(Resource lhsRes, Path lhsResPath, Resource rhsRes, Path rhsResPath) { + public boolean getExpectedSimilarityResultFor(Resource lhsModelResource, Path lhsModelSourceFileDirPath, + Resource rhsModelResource, Path rhsModelSourceFileDirPath) { ParserTestTimeMeasurer.getInstance().startTimeMeasurement( - this.getTimeMeasurementKeyBuilderFor(lhsRes, lhsResPath, rhsRes, rhsResPath).createKey(), + this.getTimeMeasurementKeyBuilderFor(lhsModelResource, lhsModelSourceFileDirPath, rhsModelResource, + rhsModelSourceFileDirPath).createKey(), GeneralTimeMeasurementTag.EXPECTED_SIMILARITY_RESULT_COMPUTATION); - var result = this.getExpectedSimilarityResultProvider().getExpectedSimilarityResultFor(lhsRes, lhsResPath, - rhsRes, rhsResPath); + var result = this.getExpectedSimilarityResultProvider().getExpectedSimilarityResultFor(lhsModelResource, + lhsModelSourceFileDirPath, rhsModelResource, rhsModelSourceFileDirPath); ParserTestTimeMeasurer.getInstance().stopTimeMeasurement(); return result; } @@ -109,28 +109,28 @@ public boolean getExpectedSimilarityResultFor(Resource lhsRes, Path lhsResPath, * information regarding the time measurement, which is derivable from * the given parameters. */ - protected ParserTestTimeMeasurementKeyBuilder getTimeMeasurementKeyBuilderFor(Resource lhsRes, Path lhsResPath, - Resource rhsRes, Path rhsResPath) { + protected ParserTestTimeMeasurementKeyBuilder getTimeMeasurementKeyBuilderFor(Resource lhsModelResource, + Path lhsModelSourceFileDirPath, Resource rhsModelResource, Path rhsModelSourceFileDirPath) { var keyBuilder = new ParserTestTimeMeasurementKeyBuilder(); keyBuilder.withTestFactoryClassName(this.getClass().getSimpleName()); keyBuilder.withExpectedSimilarityResultProviderClassName( this.getExpectedSimilarityResultProvider().getClass().getSimpleName()); - if (lhsRes != null) { - keyBuilder.withParsedLeftModelLocation(lhsRes.getURI().toString()); + if (lhsModelResource != null) { + keyBuilder.withParsedLeftModelLocation(lhsModelResource.getURI().toString()); } - if (lhsResPath != null) { - keyBuilder.withOriginalLeftModelLocation(lhsResPath.toString()); + if (lhsModelSourceFileDirPath != null) { + keyBuilder.withOriginalLeftModelLocation(lhsModelSourceFileDirPath.toString()); } - if (rhsRes != null) { - keyBuilder.withParsedRightModelLocation(rhsRes.getURI().toString()); + if (rhsModelResource != null) { + keyBuilder.withParsedRightModelLocation(rhsModelResource.getURI().toString()); } - if (rhsResPath != null) { - keyBuilder.withOriginalRightModelLocation(rhsResPath.toString()); + if (rhsModelSourceFileDirPath != null) { + keyBuilder.withOriginalRightModelLocation(rhsModelSourceFileDirPath.toString()); } return keyBuilder; @@ -145,5 +145,6 @@ protected ParserTestTimeMeasurementKeyBuilder getTimeMeasurementKeyBuilderFor(Re * * @return Dynamic tests generated based on the concrete implementor. */ - public abstract DynamicNode createTestsFor(Resource res1, Path path1, Resource res2, Path path2); + public abstract DynamicNode createTestsFor(Resource lhsModelResource, Path lhsModelSourceFileDirPath, + Resource rhsModelResource, Path rhsModelSourceFileDirPath); } diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/testfactory/EAllContentSimilarityTestFactory.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/testfactory/EAllContentSimilarityTestFactory.java index d6e928ba97..0847474fe9 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/testfactory/EAllContentSimilarityTestFactory.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/testfactory/EAllContentSimilarityTestFactory.java @@ -18,7 +18,7 @@ /** * A test class factory, which generates dynamic tests that check the similarity * of all contents ({@code res.getAllContents()}) of the given Resources - * {@code res1, res2} pairwise. + * {@code lhsModelResource, rhsModelResource} pairwise. * * @author Alp Torac Genc */ @@ -36,18 +36,19 @@ public EAllContentSimilarityTestFactory(ISimilarityCheckerContainer scc) { * {@code res_i.getAllContents()}. The order of the direct contents is also * considered and will impact the result. */ - protected void testSimilarityOfAllContents(Resource res1, Resource res2, Boolean expectedResult) { + protected void testSimilarityOfAllContents(Resource lhsModelResource, Resource rhsModelResource, + Boolean expectedResult) { ParserTestTimeMeasurer.getInstance().startTimeMeasurement( - this.getTimeMeasurementKeyBuilderFor(res1, null, res2, null).createKey(), + this.getTimeMeasurementKeyBuilderFor(lhsModelResource, null, rhsModelResource, null).createKey(), GeneralTimeMeasurementTag.TEST_OVERHEAD); var list1 = new ArrayList(); var list2 = new ArrayList(); - res1.getAllContents().forEachRemaining((o) -> list1.add(o)); - res2.getAllContents().forEachRemaining((o) -> list2.add(o)); + lhsModelResource.getAllContents().forEachRemaining((o) -> list1.add(o)); + rhsModelResource.getAllContents().forEachRemaining((o) -> list2.add(o)); ParserTestTimeMeasurer.getInstance().startTimeMeasurement( - this.getTimeMeasurementKeyBuilderFor(res1, null, res2, null).createKey(), + this.getTimeMeasurementKeyBuilderFor(lhsModelResource, null, rhsModelResource, null).createKey(), GeneralTimeMeasurementTag.SIMILARITY_CHECKING); Assertions.assertEquals(expectedResult, this.scc.areSimilar(list1, list2)); ParserTestTimeMeasurer.getInstance().stopTimeMeasurement(); @@ -55,10 +56,14 @@ protected void testSimilarityOfAllContents(Resource res1, Resource res2, Boolean } @Override - public DynamicNode createTestsFor(Resource res1, Path path1, Resource res2, Path path2) { - return DynamicTest.dynamicTest(String.format("%s vs %s", path1.getFileName(), path2.getFileName()), () -> { - this.testSimilarityOfAllContents(res1, res2, this.getExpectedSimilarityResultFor(res1, path1, res2, path2)); - }); + public DynamicNode createTestsFor(Resource lhsModelResource, Path lhsModelSourceFileDirPath, + Resource rhsModelResource, Path rhsModelSourceFileDirPath) { + return DynamicTest.dynamicTest(String.format("%s vs %s", lhsModelSourceFileDirPath.getFileName(), + rhsModelSourceFileDirPath.getFileName()), () -> { + this.testSimilarityOfAllContents(lhsModelResource, rhsModelResource, + this.getExpectedSimilarityResultFor(lhsModelResource, lhsModelSourceFileDirPath, + rhsModelResource, rhsModelSourceFileDirPath)); + }); } @Override diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/testfactory/ModelComparisonTestFactory.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/testfactory/ModelComparisonTestFactory.java index b8605ae395..272f4c4055 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/testfactory/ModelComparisonTestFactory.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/testfactory/ModelComparisonTestFactory.java @@ -17,8 +17,9 @@ /** * A test class factory, which generates dynamic tests that performs - * hierarchical similarity checking on the given Resources {@code res1, res2} - * and returns the result in form of {@link Comparison} objects.
        + * hierarchical similarity checking on the given Resources + * {@code lhsModelResource, rhsModelResource} and returns the result in form of + * {@link Comparison} objects.
        *
        * The difference between this and {@link EAllContentSimilarityTestFactory} is * that the comparison here is much more detailed. @@ -45,20 +46,21 @@ public ModelComparisonTestFactory(boolean contentOrderMatters) { * result, since reaching from one side to the other will require "opposite" * operations. * - * @param res1 The new state - * @param res2 The old state - * @return Result of comparing {@code res2} to {@code res1}, i.e. what needs to - * be done to {@code res2} to get to {@code res1}. + * @param lhsModelResource The new state + * @param rhsModelResource The old state + * @return Result of comparing {@code rhsModelResource} to + * {@code lhsModelResource}, i.e. what needs to be done to + * {@code rhsModelResource} to get to {@code lhsModelResource}. * * @see {@link #getSCC()} */ - protected Comparison compareModels(Resource res1, Resource res2) { + protected Comparison compareModels(Resource lhsModelResource, Resource rhsModelResource) { ParserTestTimeMeasurer.getInstance().startTimeMeasurement( - this.getTimeMeasurementKeyBuilderFor(res1, null, res2, null) + this.getTimeMeasurementKeyBuilderFor(lhsModelResource, null, rhsModelResource, null) .withModelComparisonClassName(JavaModelComparator.class.getSimpleName()).createKey(), GeneralTimeMeasurementTag.MODEL_RESOURCE_COMPARISON); // TODO Integrate "this.scc" into the model comparator - var result = JavaModelComparator.compareJavaModels(res1, res2, null, null, null); + var result = JavaModelComparator.compareJavaModels(lhsModelResource, rhsModelResource, null, null, null); ParserTestTimeMeasurer.getInstance().stopTimeMeasurement(); return result; } @@ -67,35 +69,39 @@ protected Comparison compareModels(Resource res1, Resource res2) { * Asserts that the result of similarity checking via model comparison results * in differences or not (denoted by expectedResult).
        *
        - * Compares res1 and res2, as well as res2 and res1; in order to ensure that the - * comparison is symmetric. + * Compares lhsModelResource and rhsModelResource, as well as rhsModelResource + * and lhsModelResource; in order to ensure that the comparison is symmetric. */ - protected void testSimilarityWithModelComparison(Resource res1, Resource res2, Boolean expectedResult) { + protected void testSimilarityWithModelComparison(Resource lhsModelResource, Resource rhsModelResource, + Boolean expectedResult) { ParserTestTimeMeasurer.getInstance().startTimeMeasurement( - this.getTimeMeasurementKeyBuilderFor(res1, null, res2, null).createKey(), + this.getTimeMeasurementKeyBuilderFor(lhsModelResource, null, rhsModelResource, null).createKey(), GeneralTimeMeasurementTag.TEST_OVERHEAD); - var cmp1To2 = this.compareModels(res1, res2); + var cmp1To2 = this.compareModels(lhsModelResource, rhsModelResource); Assertions.assertEquals(expectedResult, cmp1To2.getDifferences().size() == 0); ParserTestTimeMeasurer.getInstance().stopTimeMeasurement(); ParserTestTimeMeasurer.getInstance().startTimeMeasurement( - this.getTimeMeasurementKeyBuilderFor(res2, null, res1, null).createKey(), + this.getTimeMeasurementKeyBuilderFor(rhsModelResource, null, lhsModelResource, null).createKey(), GeneralTimeMeasurementTag.TEST_OVERHEAD); - var cmp2To1 = this.compareModels(res2, res1); + var cmp2To1 = this.compareModels(rhsModelResource, lhsModelResource); Assertions.assertEquals(expectedResult, cmp2To1.getDifferences().size() == 0); ParserTestTimeMeasurer.getInstance().stopTimeMeasurement(); } @Override - public DynamicNode createTestsFor(Resource res1, Path path1, Resource res2, Path path2) { - return DynamicTest.dynamicTest(String.format("%s vs %s", path1.getFileName(), path2.getFileName()), () -> { - this.testSimilarityWithModelComparison(res1, res2, - this.getExpectedSimilarityResultFor(res1, path1, res2, path2)); - }); + public DynamicNode createTestsFor(Resource lhsModelResource, Path lhsModelSourceFileDirPath, + Resource rhsModelResource, Path rhsModelSourceFileDirPath) { + return DynamicTest.dynamicTest(String.format("%s vs %s", lhsModelSourceFileDirPath.getFileName(), + rhsModelSourceFileDirPath.getFileName()), () -> { + this.testSimilarityWithModelComparison(lhsModelResource, rhsModelResource, + this.getExpectedSimilarityResultFor(lhsModelResource, lhsModelSourceFileDirPath, + rhsModelResource, rhsModelSourceFileDirPath)); + }); } @Override From 72dc291eced6d1f423a0d4a4cb588c470e6945a7 Mon Sep 17 00:00:00 2001 From: AlpTorac Date: Mon, 1 Sep 2025 11:51:35 +0200 Subject: [PATCH 58/72] Fix new line regex --- .../util/RepoTestSimilarityValueEstimator.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/RepoTestSimilarityValueEstimator.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/RepoTestSimilarityValueEstimator.java index 2a2dd73cda..c0cf33a4c1 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/RepoTestSimilarityValueEstimator.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/RepoTestSimilarityValueEstimator.java @@ -37,15 +37,14 @@ public class RepoTestSimilarityValueEstimator { * commits C1 and C2 * @return Whether model resources parsed from C1 and C2 are similar according * to this instance - * - * TODO Fix the regex used in the "code" local variable */ public boolean getExpectedSimilarityValueFor(OutputStream os, DiffFormatter df, List diffEntries) { try (var outputStream = os; var diffFormatter = df) { for (var e : diffEntries) { diffFormatter.format(e); - // Adapt all UNIX new lines to the current system - var code = this.getEffectiveLines(outputStream.toString().replaceAll("\\n", System.lineSeparator())); + // Adapt all new lines to the current system + var code = this + .getEffectiveLines(outputStream.toString().replaceAll("\\r?\\n", System.lineSeparator())); var expectedSimVal = this.computeExpectedSimilarityValue(code); if (!expectedSimVal) return false; From b4c39e6759244cac37a456fa70645d692db69dbe Mon Sep 17 00:00:00 2001 From: AlpTorac Date: Sat, 6 Sep 2025 20:53:04 +0200 Subject: [PATCH 59/72] Refactor time measurements Relativize paths and URIs to hide sensitive data in paths Gather all time measurement files generated from a test run within a folder, so that it is possible to tell what time measurements are taken from which test runs --- .../AbstractJaMoPPParserRepoTest.java | 12 +- .../AbstractJaMoPPParserSimilarityTest.java | 127 ++++++++++++------ .../similarity/jamopp/parser/FileUtil.java | 2 - .../jamopp/parser/ParserTestFileLayout.java | 19 +++ ...ractJaMoPPParserSimilarityTestFactory.java | 13 +- .../ParserTestTimeMeasurementKeyUtil.java | 35 +++++ 6 files changed, 159 insertions(+), 49 deletions(-) create mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/ParserTestTimeMeasurementKeyUtil.java diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/AbstractJaMoPPParserRepoTest.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/AbstractJaMoPPParserRepoTest.java index d0124ca7c0..9eb1eaa21d 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/AbstractJaMoPPParserRepoTest.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/AbstractJaMoPPParserRepoTest.java @@ -15,6 +15,7 @@ import cipm.consistency.fitests.similarity.jamopp.parser.timemeasurement.GeneralTimeMeasurementTag; import cipm.consistency.fitests.similarity.jamopp.parser.timemeasurement.ITimeMeasurementTag; import cipm.consistency.fitests.similarity.jamopp.parser.timemeasurement.ParserTestTimeMeasurementKeyBuilder; +import cipm.consistency.fitests.similarity.jamopp.parser.timemeasurement.ParserTestTimeMeasurementKeyUtil; import cipm.consistency.fitests.similarity.jamopp.parser.JaMoPPModelResourceWrapper; import java.io.BufferedReader; @@ -68,7 +69,7 @@ public abstract class AbstractJaMoPPParserRepoTest extends AbstractJaMoPPParserS /** * The pattern of "gradle-wrapper.jar" file path, which should be excluded when - * parsing model resources to avoid IOExceptions. + * parsing Java model resources to avoid IOExceptions. */ private static final String gradleWrapperJarPathPattern = ".*?/gradle-wrapper\\.jar"; @@ -225,7 +226,7 @@ protected Boolean getExpectedResult(String lhsCommit, String rhsCommit) { /** * Prepares model resources and expected similarity results needed by tests and - * caches them. Must be executed before all tests. + * caches them. Must be executed before dynamic tests. * * @return The cached model resources parsed from {@link #getCommitIDs()} * @see {@link #getCommitIDs()} @@ -291,7 +292,8 @@ protected Collection cacheCommitResources() { var cachedCommitURI = this.getTestFileLayout().getModelResourceSaveURIForCommit(cID); var res = new JaMoPPModelResourceWrapper(); this.startTimeMeasurement( - getTimeMeasurementKeyBuilder().withParsedModelLocation(cachedCommitURI.toString()), + getTimeMeasurementKeyBuilder().withParsedModelLocation( + ParserTestTimeMeasurementKeyUtil.getAdaptedURIString(cachedCommitURI)), GeneralTimeMeasurementTag.LOAD_MODEL_RESOURCE); res.loadModelResource(cachedCommitURI); this.stopTimeMeasurement(); @@ -557,8 +559,8 @@ protected Collection getTestGenerationStrat } /** - * Extends the super method by preparing repository clones before generating - * dynamic tests.
        + * Extends the super method by parsing and caching model resources from the + * local repository clone before generating dynamic tests.
        *
        * {@inheritDoc} */ diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/AbstractJaMoPPParserSimilarityTest.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/AbstractJaMoPPParserSimilarityTest.java index 3aca7bd712..2a8993b872 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/AbstractJaMoPPParserSimilarityTest.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/AbstractJaMoPPParserSimilarityTest.java @@ -26,6 +26,7 @@ import cipm.consistency.fitests.similarity.jamopp.parser.timemeasurement.ITimeMeasurementTag; import cipm.consistency.fitests.similarity.jamopp.parser.timemeasurement.ParserTestTimeMeasurementKey; import cipm.consistency.fitests.similarity.jamopp.parser.timemeasurement.ParserTestTimeMeasurementKeyBuilder; +import cipm.consistency.fitests.similarity.jamopp.parser.timemeasurement.ParserTestTimeMeasurementKeyUtil; import cipm.consistency.fitests.similarity.jamopp.parser.timemeasurement.ParserTestTimeMeasurer; import cipm.consistency.fitests.similarity.jamopp.parser.timemeasurement.StopwatchStrategy; @@ -55,14 +56,7 @@ */ public abstract class AbstractJaMoPPParserSimilarityTest extends AbstractJaMoPPSimilarityTest { /** - * An object that caches and grants access to parsed models, which were cached - * after being parsed.
        - *
        - * Make sure that the {@link CacheUtil} instance persists throughout tests, - * which are supposed to make use of it. - * - * @see {@link #parseModelWithoutCaching(Path)} - * @see {@link #parseModelWithCaching(Path)} + * @see {@link #getCacheUtil()} */ private static final CacheUtil resourceCache = new CacheUtil(); @@ -72,38 +66,63 @@ public abstract class AbstractJaMoPPParserSimilarityTest extends AbstractJaMoPPS private ParserTestFileLayout layout; /** - * @see {@link ParserTestFileLayout#setTestModelResourceFilesSaveDirPath(Path)} + * The parent path of all time measurement files. Used to compute + * {@link ParserTestFileLayout#setTimeMeasurementsFileSavePath(Path)} */ - private static final Path testModelResourceFilesSaveDirPath = Path.of("target", "testResources"); + private static final Path timeMeasurementsSaveRootPath = Path.of("target", "timeMeasurements"); + /** + * The prefix of the directory name, under which all time measurement files from + * the entirety of this test run are to be saved. + * {@link #previousTimeMeasurementCount} is appended to the end of this to get + * the full directory name. + */ + private static final String timeMeasurementSaveFolderPrefix = "Test run - "; + /** + * The amount of saved time measurement folders under + * {@link #timeMeasurementsSaveRootPath} from previous test runs. Used to + * compute {@link ParserTestFileLayout#setTimeMeasurementsFileSavePath(Path)} + *

        + * Computed here as a static final variable, so that the current test run uses + * the same folder across all concrete test classes + */ + private static final int previousTimeMeasurementCount = timeMeasurementsSaveRootPath.toFile().list().length + 1; + /** + * @see {@link ParserTestFileLayout#getTimeMeasurementFileExtension()} + */ + private static final String timeMeasurementFileExtension = "json"; /** * @see {@link ParserTestFileLayout#setTestModelResourceFilesSaveDirPath(Path)} */ - private static final Path cacheSaveDirPath = testModelResourceFilesSaveDirPath.resolve("testmodel-cache"); + private static final Path testModelResourceFilesSaveDirPath = Path.of("target", "testResources"); /** - * @see {@link ParserTestFileLayout#setTimeMeasurementsFileSavePath(Path)} + * @see {@link ParserTestFileLayout#setTestModelResourceFilesSaveDirPath(Path)} */ - private static final Path timeMeasurementsFileSavePath = Path.of("target", "timeMeasurements"); + private static final Path cacheSaveDirPath = testModelResourceFilesSaveDirPath.resolve("testmodel-cache"); /** * {@inheritDoc}
        *
        * {@link AbstractJaMoPPParserSimilarityTest}: Sets up the file layout for the - * test {@link ParserTestFileLayout}. See + * test {@link #getTestFileLayout()} and the time measuring mechanism + * {@link #setupForTimeMeasurements()}. See * {@link AbstractJaMoPPParserSimilarityTest} for more information. */ @BeforeEach @Override public void setUp() { + SimilarityTestLogger.logDebugMsg("Setting up before parser test", this.getClass()); this.setupForTimeMeasurements(); ParserTestTimeMeasurer.getInstance().startTimeMeasuring(); this.startTimeMeasurement(GeneralTimeMeasurementTag.TEST_BEFOREEACH); super.setUp(); this.layout = this.initParserTestFileLayout(); + ParserTestTimeMeasurementKeyUtil.setRelativizationPath(this.getTestFileLayout().getTestFilesSavePath()); this.stopTimeMeasurement(); + SimilarityTestLogger.logDebugMsg("Set up before parser test", this.getClass()); } /** @@ -111,10 +130,10 @@ public void setUp() { *
        * {@link AbstractJaMoPPParserSimilarityTest}: Performs various operations on * model resources that were parsed in the dynamic tests, according to the - * preferences that are encoded in the methods of this test, such as - * {@link AbstractJaMoPPParserSimilarityTest#shouldSaveCachedModelResources()}. It - * then saves the time measurements taken during the tests. See - * {@link AbstractJaMoPPParserSimilarityTest} for more information. + * preferences that are encoded in {@link #getResourceTestOptions()}, such as + * {@link ParserTestOptions#shouldSaveCachedModelResources()}. It then finishes + * time measurement taking and saves the time measurements from the current test + * class. See {@link AbstractJaMoPPParserSimilarityTest} for more information. */ @AfterEach @Override @@ -128,8 +147,8 @@ public void tearDown() { SimilarityTestLogger.logDebugMsg("Saving all cached resources after parser test", this.getClass()); cachedResources.forEach((res) -> { this.startTimeMeasurement( - getTimeMeasurementKeyBuilder() - .withParsedModelLocation(res.getModelResource().getURI().toString()), + getTimeMeasurementKeyBuilder().withParsedModelLocation( + ParserTestTimeMeasurementKeyUtil.getAdaptedURIString(res.getModelResource().getURI())), GeneralTimeMeasurementTag.SAVE_MODEL_RESOURCE); res.saveResources(); this.stopTimeMeasurement(); @@ -141,8 +160,8 @@ public void tearDown() { SimilarityTestLogger.logDebugMsg("Deleting all cached resources after parser test", this.getClass()); cachedResources.forEach((res) -> { this.startTimeMeasurement( - getTimeMeasurementKeyBuilder() - .withParsedModelLocation(res.getModelResource().getURI().toString()), + getTimeMeasurementKeyBuilder().withParsedModelLocation( + ParserTestTimeMeasurementKeyUtil.getAdaptedURIString(res.getModelResource().getURI())), GeneralTimeMeasurementTag.DELETE_MODEL_RESOURCE); res.deleteResources(); this.stopTimeMeasurement(); @@ -152,8 +171,8 @@ public void tearDown() { SimilarityTestLogger.logDebugMsg("Unloading all cached resources after parser test", this.getClass()); cachedResources.forEach((res) -> { this.startTimeMeasurement( - getTimeMeasurementKeyBuilder() - .withParsedModelLocation(res.getModelResource().getURI().toString()), + getTimeMeasurementKeyBuilder().withParsedModelLocation( + ParserTestTimeMeasurementKeyUtil.getAdaptedURIString(res.getModelResource().getURI())), GeneralTimeMeasurementTag.UNLOAD_MODEL_RESOURCE); res.unloadResources(); this.stopTimeMeasurement(); @@ -198,8 +217,13 @@ protected ParserTestFileLayout initParserTestFileLayout() { layout.setModelSourceParentRootDirPath(new File("").getAbsoluteFile().toPath()); layout.setTestModelResourceFilesSaveDirPath(testModelResourceFilesSaveDirPath); layout.setCacheSaveDirPath(cacheSaveDirPath); - layout.setTimeMeasurementsFileSavePath(timeMeasurementsFileSavePath); + + layout.setTimeMeasurementsFileSavePath( + timeMeasurementsSaveRootPath.resolve(timeMeasurementSaveFolderPrefix + previousTimeMeasurementCount)); + layout.setTimeMeasurementFileExtension(timeMeasurementFileExtension); + layout.setModelResourceFileExtension(this.getResourceParsingStrategy().getResourceFileExtension()); + return layout; } @@ -207,7 +231,7 @@ protected ParserTestFileLayout initParserTestFileLayout() { * @return An object encapsulating the file layout for the test */ protected ParserTestFileLayout getTestFileLayout() { - return this.layout; + return layout; } /** @@ -216,13 +240,15 @@ protected ParserTestFileLayout getTestFileLayout() { * @return The path, at which time measurements of the currently running test * class will be saved. */ - protected Path getTimeMeasurementSavePathForCurrentTestClass() { + protected Path getTimeMeasurementFileSavePathForCurrentTestClass() { var dateFormatInFileName = DateTimeFormatter.ofPattern("dd-MM-yyyy_HH-mm-ss"); var startTime = ParserTestTimeMeasurer.getInstance().getDataStructure().getStartTime(); var endTime = ParserTestTimeMeasurer.getInstance().getDataStructure().getEndTime(); var fileName = String.format("%s___%s-%s.%s", dateFormatInFileName.format(startTime), - dateFormatInFileName.format(endTime), this.getCurrentTestClassName(), "json"); + dateFormatInFileName.format(endTime), this.getCurrentTestClassName(), + this.getTestFileLayout().getTimeMeasurementFileExtension()); + return this.getTestFileLayout().getTimeMeasurementsFileSavePath().resolve(fileName); } @@ -242,7 +268,7 @@ protected void setupForTimeMeasurements() { */ protected void saveTimeMeasurements() { SimilarityTestLogger.logDebugMsg("Saving time measurements", this.getClass()); - ParserTestTimeMeasurer.getInstance().save(this.getTimeMeasurementSavePathForCurrentTestClass()); + ParserTestTimeMeasurer.getInstance().save(this.getTimeMeasurementFileSavePathForCurrentTestClass()); ParserTestTimeMeasurer.getInstance().reset(); SimilarityTestLogger.logDebugMsg("Saved time measurements", this.getClass()); } @@ -277,8 +303,18 @@ protected void stopTimeMeasurement() { } /** + * An object that caches and grants access to parsed models, which were cached + * after being parsed.
        + *
        + * Make sure that the {@link CacheUtil} instance persists and the same instance + * is used across all concrete test classes. That way, previously parsed model + * resource instances can be re-used. + * * @return A utility object, which encapsulates caching logic (for parsed * models) and can be used to hasten tests. + * + * @see {@link #parseModelWithoutCaching(Path)} + * @see {@link #parseModelWithCaching(Path)} */ protected CacheUtil getCacheUtil() { return resourceCache; @@ -301,7 +337,9 @@ protected CacheUtil getCacheUtil() { */ protected IModelResourceWrapper parseModelWithoutCaching(Path modelSourceFileDirPath) { this.startTimeMeasurement( - getTimeMeasurementKeyBuilder().withOriginalModelLocation(modelSourceFileDirPath.toString()) + getTimeMeasurementKeyBuilder() + .withOriginalModelLocation( + ParserTestTimeMeasurementKeyUtil.getAdaptedPathString(modelSourceFileDirPath)) .withResourceParsingStrategyClassName( this.getResourceParsingStrategy().getClass().getSimpleName()), GeneralTimeMeasurementTag.PARSE_MODEL_RESOURCE); @@ -346,8 +384,11 @@ protected IModelResourceWrapper parseModelWithCaching(Path modelSourceFileDirPat protected IModelResourceWrapper parseModelWithCaching(Path modelSourceFileDirPath, URI modelResourceCachedURI, String modelResourceCacheKey) { this.startTimeMeasurement( - getTimeMeasurementKeyBuilder().withOriginalModelLocation(modelSourceFileDirPath.toString()) - .withParsedModelLocation(modelResourceCachedURI.toString()), + getTimeMeasurementKeyBuilder() + .withOriginalModelLocation( + ParserTestTimeMeasurementKeyUtil.getAdaptedPathString(modelSourceFileDirPath)) + .withParsedModelLocation( + ParserTestTimeMeasurementKeyUtil.getAdaptedURIString(modelResourceCachedURI)), GeneralTimeMeasurementTag.MODEL_RESOURCE_CACHE_ACCESS); var cache = this.getCacheUtil(); var modelName = this.getDisplayNameForModelSourceFileDir(modelSourceFileDirPath); @@ -368,8 +409,11 @@ protected IModelResourceWrapper parseModelWithCaching(Path modelSourceFileDirPat resWrapper = cache.getFromCache(modelResourceCacheKey); if (!resWrapper.isModelResourceLoaded()) { this.startTimeMeasurement( - getTimeMeasurementKeyBuilder().withOriginalModelLocation(modelSourceFileDirPath.toString()) - .withParsedModelLocation(modelResourceCachedURI.toString()), + getTimeMeasurementKeyBuilder() + .withOriginalModelLocation(ParserTestTimeMeasurementKeyUtil + .getAdaptedPathString(modelSourceFileDirPath)) + .withParsedModelLocation(ParserTestTimeMeasurementKeyUtil + .getAdaptedURIString(modelResourceCachedURI)), GeneralTimeMeasurementTag.LOAD_MODEL_RESOURCE); resWrapper.loadParsedResources(); this.stopTimeMeasurement(); @@ -380,8 +424,11 @@ protected IModelResourceWrapper parseModelWithCaching(Path modelSourceFileDirPat if (resWrapper == null) { resWrapper = new JaMoPPModelResourceWrapper(); this.startTimeMeasurement( - getTimeMeasurementKeyBuilder().withOriginalModelLocation(modelSourceFileDirPath.toString()) - .withParsedModelLocation(modelResourceCachedURI.toString()), + getTimeMeasurementKeyBuilder() + .withOriginalModelLocation( + ParserTestTimeMeasurementKeyUtil.getAdaptedPathString(modelSourceFileDirPath)) + .withParsedModelLocation( + ParserTestTimeMeasurementKeyUtil.getAdaptedURIString(modelResourceCachedURI)), GeneralTimeMeasurementTag.LOAD_MODEL_RESOURCE); resWrapper.loadModelResource(modelResourceCachedURI); this.stopTimeMeasurement(); @@ -577,7 +624,9 @@ public Collection createTests() { protected Collection discoverModelSourceFileDirsAt(Path modelSourceParentDirPath) { var modelDiscoveryStrat = new ModelDiscoveryStrategy((f) -> this.isModelSourceFileDirectory(f)); this.startTimeMeasurement( - getTimeMeasurementKeyBuilder().withModelDiscoveryPath(modelSourceParentDirPath.toString()) + getTimeMeasurementKeyBuilder() + .withModelDiscoveryPath( + ParserTestTimeMeasurementKeyUtil.getAdaptedPathString(modelSourceParentDirPath)) .withModelDiscoveryClassName(modelDiscoveryStrat.getClass().getSimpleName()), GeneralTimeMeasurementTag.DISCOVER_MODEL_RESOURCES); var result = modelDiscoveryStrat.discoverModelSourceFileDirs(modelSourceParentDirPath.toFile()); @@ -595,7 +644,9 @@ protected Collection discoverModelSourceFileDirsAt(Path modelSourceParentD protected Collection discoverModelSourceParentDirsAt(Path modelSourceParentRootPath) { var modelDiscoveryStrat = new ModelDiscoveryStrategy((f) -> this.isModelSourceFileDirectory(f)); this.startTimeMeasurement( - getTimeMeasurementKeyBuilder().withModelDiscoveryPath(modelSourceParentRootPath.toString()) + getTimeMeasurementKeyBuilder() + .withModelDiscoveryPath( + ParserTestTimeMeasurementKeyUtil.getAdaptedPathString(modelSourceParentRootPath)) .withModelDiscoveryClassName(modelDiscoveryStrat.getClass().getSimpleName()), GeneralTimeMeasurementTag.DISCOVER_MODEL_RESOURCES); var result = modelDiscoveryStrat.discoverModelSourceParentDirs(modelSourceParentRootPath.toFile()); diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/FileUtil.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/FileUtil.java index 7ff9811fe6..64d78dd299 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/FileUtil.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/FileUtil.java @@ -63,8 +63,6 @@ public static boolean filesEqual(File f1, File f2) { } /** - * TODO Use Files.walk instead, if possible - * * Recursively checks the equality of the given directories, based on their * effective content (i.e. the files/sub-directories they contain and the * contents of those files without whitespaces). diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ParserTestFileLayout.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ParserTestFileLayout.java index c5305940d3..11e19eabdc 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ParserTestFileLayout.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ParserTestFileLayout.java @@ -29,6 +29,10 @@ public class ParserTestFileLayout { * @see {@link #getTimeMeasurementsFileSavePath()} */ private Path timeMeasurementsFileSavePath; + /** + * @see {@link #getTimeMeasurementFileExtension()} + */ + private String timeMeasurementFileExtension; /** * @see {@link #getModelResourceFileExtension()} @@ -46,6 +50,7 @@ public ParserTestFileLayout(ParserTestFileLayout layout) { this.testModelResourceFilesSaveDirPath = layout.testModelResourceFilesSaveDirPath; this.cacheSaveDirPath = layout.cacheSaveDirPath; this.timeMeasurementsFileSavePath = layout.timeMeasurementsFileSavePath; + this.timeMeasurementFileExtension = layout.timeMeasurementFileExtension; this.modelResourceFileExtension = layout.modelResourceFileExtension; } @@ -121,6 +126,20 @@ public Path getTestFilesSavePath() { return this.getAbsoluteCurrentDirectory().resolve(testModelResourceFilesSaveDirPath); } + /** + * @return The extension of the time measurement files + */ + public String getTimeMeasurementFileExtension() { + return timeMeasurementFileExtension; + } + + /** + * @param timeMeasurementFileExtension {@link #getTimeMeasurementFileExtension()} + */ + public void setTimeMeasurementFileExtension(String timeMeasurementFileExtension) { + this.timeMeasurementFileExtension = timeMeasurementFileExtension; + } + /** * @param modelDir The path to a directory, which has files for one (and only * one) model diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/testfactory/AbstractJaMoPPParserSimilarityTestFactory.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/testfactory/AbstractJaMoPPParserSimilarityTestFactory.java index e4f578c545..4f395f38a8 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/testfactory/AbstractJaMoPPParserSimilarityTestFactory.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/testfactory/AbstractJaMoPPParserSimilarityTestFactory.java @@ -9,6 +9,7 @@ import cipm.consistency.fitests.similarity.jamopp.parser.resultprovider.ResourceReferenceEqualitySimilarityResultProvider; import cipm.consistency.fitests.similarity.jamopp.parser.timemeasurement.GeneralTimeMeasurementTag; import cipm.consistency.fitests.similarity.jamopp.parser.timemeasurement.ParserTestTimeMeasurementKeyBuilder; +import cipm.consistency.fitests.similarity.jamopp.parser.timemeasurement.ParserTestTimeMeasurementKeyUtil; import cipm.consistency.fitests.similarity.jamopp.parser.timemeasurement.ParserTestTimeMeasurer; /** @@ -118,19 +119,23 @@ protected ParserTestTimeMeasurementKeyBuilder getTimeMeasurementKeyBuilderFor(Re this.getExpectedSimilarityResultProvider().getClass().getSimpleName()); if (lhsModelResource != null) { - keyBuilder.withParsedLeftModelLocation(lhsModelResource.getURI().toString()); + keyBuilder.withParsedLeftModelLocation( + ParserTestTimeMeasurementKeyUtil.getAdaptedURIString(lhsModelResource.getURI())); } if (lhsModelSourceFileDirPath != null) { - keyBuilder.withOriginalLeftModelLocation(lhsModelSourceFileDirPath.toString()); + keyBuilder.withOriginalLeftModelLocation( + ParserTestTimeMeasurementKeyUtil.getAdaptedPathString(lhsModelSourceFileDirPath)); } if (rhsModelResource != null) { - keyBuilder.withParsedRightModelLocation(rhsModelResource.getURI().toString()); + keyBuilder.withParsedRightModelLocation( + ParserTestTimeMeasurementKeyUtil.getAdaptedURIString(rhsModelResource.getURI())); } if (rhsModelSourceFileDirPath != null) { - keyBuilder.withOriginalRightModelLocation(rhsModelSourceFileDirPath.toString()); + keyBuilder.withOriginalRightModelLocation( + ParserTestTimeMeasurementKeyUtil.getAdaptedPathString(rhsModelSourceFileDirPath)); } return keyBuilder; diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/ParserTestTimeMeasurementKeyUtil.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/ParserTestTimeMeasurementKeyUtil.java new file mode 100644 index 0000000000..399f657ee3 --- /dev/null +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/ParserTestTimeMeasurementKeyUtil.java @@ -0,0 +1,35 @@ +package cipm.consistency.fitests.similarity.jamopp.parser.timemeasurement; + +import java.io.File; +import java.nio.file.Path; + +import org.eclipse.emf.common.util.URI; + +/** + * TODO Commentary + */ +public final class ParserTestTimeMeasurementKeyUtil { + private static final File currentPathFile = new File("").getAbsoluteFile(); + private static final Path currentPath = currentPathFile.toPath().toAbsolutePath(); + private static final URI currentURI = URI.createFileURI(currentPath.toString()); + + private static final String absolutePathSeparatorRegex = "\\\\"; + private static final String portablePathSeparator = "/"; + + private static URI baseURI = currentURI; + private static Path relativizationPath = currentPath; + + public static String getAdaptedURIString(URI uri) { + return uri.deresolve(baseURI).toString(); + } + + public static String getAdaptedPathString(Path path) { + return relativizationPath.relativize(path.toAbsolutePath()).toString().replaceAll(absolutePathSeparatorRegex, + portablePathSeparator); + } + + public static void setRelativizationPath(Path pathOfReference) { + relativizationPath = pathOfReference.toAbsolutePath(); + baseURI = URI.createFileURI(relativizationPath.toAbsolutePath().toString()); + } +} From 4340795b5c55f846746f15b0f4b0320ab4521ab6 Mon Sep 17 00:00:00 2001 From: AlpTorac Date: Mon, 8 Sep 2025 11:52:31 +0200 Subject: [PATCH 60/72] Fix ResourceContentSimilarityResultProvider, irrelevant for current state ResourceContentSimilarityResultProvider is currently only used by ModelComparisonTestFactory as default provider. It is however currently changed in all concrete tests, so that this fix makes no difference --- ...sourceContentSimilarityResultProvider.java | 31 ++++++++++++++----- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/resultprovider/ResourceContentSimilarityResultProvider.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/resultprovider/ResourceContentSimilarityResultProvider.java index 2e2f75b56f..5232ca99ce 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/resultprovider/ResourceContentSimilarityResultProvider.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/resultprovider/ResourceContentSimilarityResultProvider.java @@ -39,8 +39,8 @@ public ResourceContentSimilarityResultProvider(ISimilarityCheckerContainer scc, * Checks if both sides' contents ({@code res.getAllContents()}) are similar, if * their order does not matter. * - * @return Whether all contents of lhs and rhs are similar, i.e. if all contents - * of lhs have a corresponding similar content on rhs. + * @return Whether all contents of lhs and rhs are similar (up to order), i.e. + * if all contents of lhs have a corresponding similar content on rhs. */ private boolean contentwiseSimilar(Resource lhs, Resource rhs) { var lhsContent = new ArrayList(); @@ -55,8 +55,8 @@ private boolean contentwiseSimilar(Resource lhs, Resource rhs) { * Checks if both sides' contents ({@code obj.eAllContents()}) are similar, if * their order does not matter. * - * @return Whether all contents of lhs and rhs are similar, i.e. if all contents - * of lhs have a corresponding similar content on rhs. + * @return Whether all contents of lhs and rhs are similar (up to order), i.e. + * if all contents of lhs have a corresponding similar content on rhs. */ private boolean contentwiseSimilar(EObject lhs, EObject rhs) { if (!this.scc.isSimilar(lhs, rhs) || !this.scc.isSimilar(rhs, lhs)) { @@ -101,20 +101,35 @@ private boolean contentwiseSimilar(Collection lhs, Collection return lhsContent.isEmpty() && rhsContent.isEmpty(); } + /** + * Checks if both sides' contents ({@code res.getAllContents()}) are pairwise + * similar. Accounts for the order of contents too. + * + * @return Whether all contents of lhs and rhs are similar + */ + private boolean contentPairwiseSimilar(Resource lhs, Resource rhs) { + var lhsContent = new ArrayList(); + lhs.getAllContents().forEachRemaining((e) -> lhsContent.add(e)); + var rhsContent = new ArrayList(); + rhs.getAllContents().forEachRemaining((e) -> rhsContent.add(e)); + + return this.scc.areSimilar(lhsContent, rhsContent); + } + /** * @implSpec Determines expected similarity results based on the given * {@link ISimilarityCheckerContainer} and content order (if desired * in * {@link #ResourceContentSimilarityResultProvider(ISimilarityCheckerContainer, boolean)}). * If both paths are equal, the resources are expected to be similar. - * If the paths are different, TODO Fix this method by adding - * FileContentSimilarityResultProvider to !this.contentOrderSimilar - * case + * Otherwise, all contents of the given Resources will be compared + * while also accounting / not accounting for content order. */ @Override public boolean getExpectedSimilarityResultFor(Resource lhsModelResource, Path lhsModelSourceFileDirPath, Resource rhsModelResource, Path rhsModelSourceFileDirPath) { var pathsEqual = lhsModelSourceFileDirPath.toString().equals(rhsModelSourceFileDirPath.toString()); - return pathsEqual || (!this.contentOrderMatters && this.contentwiseSimilar(lhsModelResource, rhsModelResource)); + return pathsEqual || (!this.contentOrderMatters && this.contentwiseSimilar(lhsModelResource, rhsModelResource)) + || (this.contentOrderMatters && this.contentPairwiseSimilar(lhsModelResource, rhsModelResource)); } } From 1beb675cb66216ff9635fb01914f52e20ba7ae85 Mon Sep 17 00:00:00 2001 From: AlpTorac Date: Mon, 8 Sep 2025 11:59:13 +0200 Subject: [PATCH 61/72] Rename time measurement key types and corresponding builder method names --- .../AbstractJaMoPPParserRepoTest.java | 2 +- .../util/commentremoval/package-info.java | 7 + .../util/difffilter/package-info.java | 5 + .../repositorytests/util/package-info.java | 15 +++ .../AbstractJaMoPPParserSimilarityTest.java | 20 +-- ...ractJaMoPPParserSimilarityTestFactory.java | 8 +- .../ParserTestTimeMeasurementKeyBuilder.java | 108 ++++++--------- .../ParserTestTimeMeasurementKeyUtil.java | 21 ++- .../ParserTestTimeMeasurerKeyType.java | 127 ++++++++++++++++-- 9 files changed, 219 insertions(+), 94 deletions(-) create mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/commentremoval/package-info.java create mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/difffilter/package-info.java create mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/package-info.java diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/AbstractJaMoPPParserRepoTest.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/AbstractJaMoPPParserRepoTest.java index 9eb1eaa21d..3e5e2516ee 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/AbstractJaMoPPParserRepoTest.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/AbstractJaMoPPParserRepoTest.java @@ -292,7 +292,7 @@ protected Collection cacheCommitResources() { var cachedCommitURI = this.getTestFileLayout().getModelResourceSaveURIForCommit(cID); var res = new JaMoPPModelResourceWrapper(); this.startTimeMeasurement( - getTimeMeasurementKeyBuilder().withParsedModelLocation( + getTimeMeasurementKeyBuilder().withModelResourceLocation( ParserTestTimeMeasurementKeyUtil.getAdaptedURIString(cachedCommitURI)), GeneralTimeMeasurementTag.LOAD_MODEL_RESOURCE); res.loadModelResource(cachedCommitURI); diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/commentremoval/package-info.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/commentremoval/package-info.java new file mode 100644 index 0000000000..f1087ec4a5 --- /dev/null +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/commentremoval/package-info.java @@ -0,0 +1,7 @@ +/** + * Contains constructs that can be used to remove code commentary (according to + * Java Language Specification) from text. Currently consists of the interface + * {@link ICommentRemover} for encapsulating commentary removal logic, its + * concrete implementation {@link QuickCommentRemover} and its unit tests. + */ +package cipm.consistency.fitests.repositorytests.util.commentremoval; \ No newline at end of file diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/difffilter/package-info.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/difffilter/package-info.java new file mode 100644 index 0000000000..217c5f07b2 --- /dev/null +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/difffilter/package-info.java @@ -0,0 +1,5 @@ +/** + * Contains the means to filter GIT diff patches to get the actual changes from + * them. Currently only consists of {@link DiffFilter} and its unit test. + */ +package cipm.consistency.fitests.repositorytests.util.difffilter; \ No newline at end of file diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/package-info.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/package-info.java new file mode 100644 index 0000000000..e221b8d5c1 --- /dev/null +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/package-info.java @@ -0,0 +1,15 @@ +/** + * Contains constructs that encapsulate various aspects of repository parser + * tests: + *

        + * {@link RepoTestSimilarityResultCache} stores expected similarity results + * required by repository parser tests. + * {@link RepoCacheSimilarityResultProvider} serves as a bridge between + * repository parser tests and RepoTestSimilarityResultCache by providing access + * to the expected similarity results stored therein. + *

        + * {@link RepoTestSimilarityValueEstimator} integrates the contents of this + * package's sub-packages and computes approximative expected similarity results + * for repository parser tests. + */ +package cipm.consistency.fitests.repositorytests.util; \ No newline at end of file diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/AbstractJaMoPPParserSimilarityTest.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/AbstractJaMoPPParserSimilarityTest.java index 2a8993b872..214f759640 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/AbstractJaMoPPParserSimilarityTest.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/AbstractJaMoPPParserSimilarityTest.java @@ -147,7 +147,7 @@ public void tearDown() { SimilarityTestLogger.logDebugMsg("Saving all cached resources after parser test", this.getClass()); cachedResources.forEach((res) -> { this.startTimeMeasurement( - getTimeMeasurementKeyBuilder().withParsedModelLocation( + getTimeMeasurementKeyBuilder().withModelResourceLocation( ParserTestTimeMeasurementKeyUtil.getAdaptedURIString(res.getModelResource().getURI())), GeneralTimeMeasurementTag.SAVE_MODEL_RESOURCE); res.saveResources(); @@ -160,7 +160,7 @@ public void tearDown() { SimilarityTestLogger.logDebugMsg("Deleting all cached resources after parser test", this.getClass()); cachedResources.forEach((res) -> { this.startTimeMeasurement( - getTimeMeasurementKeyBuilder().withParsedModelLocation( + getTimeMeasurementKeyBuilder().withModelResourceLocation( ParserTestTimeMeasurementKeyUtil.getAdaptedURIString(res.getModelResource().getURI())), GeneralTimeMeasurementTag.DELETE_MODEL_RESOURCE); res.deleteResources(); @@ -171,7 +171,7 @@ public void tearDown() { SimilarityTestLogger.logDebugMsg("Unloading all cached resources after parser test", this.getClass()); cachedResources.forEach((res) -> { this.startTimeMeasurement( - getTimeMeasurementKeyBuilder().withParsedModelLocation( + getTimeMeasurementKeyBuilder().withModelResourceLocation( ParserTestTimeMeasurementKeyUtil.getAdaptedURIString(res.getModelResource().getURI())), GeneralTimeMeasurementTag.UNLOAD_MODEL_RESOURCE); res.unloadResources(); @@ -338,7 +338,7 @@ protected CacheUtil getCacheUtil() { protected IModelResourceWrapper parseModelWithoutCaching(Path modelSourceFileDirPath) { this.startTimeMeasurement( getTimeMeasurementKeyBuilder() - .withOriginalModelLocation( + .withModelSourceFileDirLocation( ParserTestTimeMeasurementKeyUtil.getAdaptedPathString(modelSourceFileDirPath)) .withResourceParsingStrategyClassName( this.getResourceParsingStrategy().getClass().getSimpleName()), @@ -385,9 +385,9 @@ protected IModelResourceWrapper parseModelWithCaching(Path modelSourceFileDirPat String modelResourceCacheKey) { this.startTimeMeasurement( getTimeMeasurementKeyBuilder() - .withOriginalModelLocation( + .withModelSourceFileDirLocation( ParserTestTimeMeasurementKeyUtil.getAdaptedPathString(modelSourceFileDirPath)) - .withParsedModelLocation( + .withModelResourceLocation( ParserTestTimeMeasurementKeyUtil.getAdaptedURIString(modelResourceCachedURI)), GeneralTimeMeasurementTag.MODEL_RESOURCE_CACHE_ACCESS); var cache = this.getCacheUtil(); @@ -410,9 +410,9 @@ protected IModelResourceWrapper parseModelWithCaching(Path modelSourceFileDirPat if (!resWrapper.isModelResourceLoaded()) { this.startTimeMeasurement( getTimeMeasurementKeyBuilder() - .withOriginalModelLocation(ParserTestTimeMeasurementKeyUtil + .withModelSourceFileDirLocation(ParserTestTimeMeasurementKeyUtil .getAdaptedPathString(modelSourceFileDirPath)) - .withParsedModelLocation(ParserTestTimeMeasurementKeyUtil + .withModelResourceLocation(ParserTestTimeMeasurementKeyUtil .getAdaptedURIString(modelResourceCachedURI)), GeneralTimeMeasurementTag.LOAD_MODEL_RESOURCE); resWrapper.loadParsedResources(); @@ -425,9 +425,9 @@ protected IModelResourceWrapper parseModelWithCaching(Path modelSourceFileDirPat resWrapper = new JaMoPPModelResourceWrapper(); this.startTimeMeasurement( getTimeMeasurementKeyBuilder() - .withOriginalModelLocation( + .withModelSourceFileDirLocation( ParserTestTimeMeasurementKeyUtil.getAdaptedPathString(modelSourceFileDirPath)) - .withParsedModelLocation( + .withModelResourceLocation( ParserTestTimeMeasurementKeyUtil.getAdaptedURIString(modelResourceCachedURI)), GeneralTimeMeasurementTag.LOAD_MODEL_RESOURCE); resWrapper.loadModelResource(modelResourceCachedURI); diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/testfactory/AbstractJaMoPPParserSimilarityTestFactory.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/testfactory/AbstractJaMoPPParserSimilarityTestFactory.java index 4f395f38a8..5b031d8724 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/testfactory/AbstractJaMoPPParserSimilarityTestFactory.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/testfactory/AbstractJaMoPPParserSimilarityTestFactory.java @@ -119,22 +119,22 @@ protected ParserTestTimeMeasurementKeyBuilder getTimeMeasurementKeyBuilderFor(Re this.getExpectedSimilarityResultProvider().getClass().getSimpleName()); if (lhsModelResource != null) { - keyBuilder.withParsedLeftModelLocation( + keyBuilder.withLeftModelResourceLocation( ParserTestTimeMeasurementKeyUtil.getAdaptedURIString(lhsModelResource.getURI())); } if (lhsModelSourceFileDirPath != null) { - keyBuilder.withOriginalLeftModelLocation( + keyBuilder.withLeftModelSourceFileDirLocation( ParserTestTimeMeasurementKeyUtil.getAdaptedPathString(lhsModelSourceFileDirPath)); } if (rhsModelResource != null) { - keyBuilder.withParsedRightModelLocation( + keyBuilder.withRightModelResourceLocation( ParserTestTimeMeasurementKeyUtil.getAdaptedURIString(rhsModelResource.getURI())); } if (rhsModelSourceFileDirPath != null) { - keyBuilder.withOriginalRightModelLocation( + keyBuilder.withRightModelSourceFileDirLocation( ParserTestTimeMeasurementKeyUtil.getAdaptedPathString(rhsModelSourceFileDirPath)); } diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/ParserTestTimeMeasurementKeyBuilder.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/ParserTestTimeMeasurementKeyBuilder.java index 3cbeddeaa8..0baadf009e 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/ParserTestTimeMeasurementKeyBuilder.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/ParserTestTimeMeasurementKeyBuilder.java @@ -80,78 +80,61 @@ public ParserTestTimeMeasurementKeyBuilder withResourceParsingStrategyClassName( } /** - * The location, under which all original model files can be found. These files - * were parsed to create the corresponding model resource. The location can be - * any form of String that can be used to navigate (ex: Path.toString() or - * URI.toString()).
        + * The location of the model source file directory, under which all model source + * files can be found. The location can be any form of String that can be used + * to navigate (ex: Path.toString() or URI.toString()).
        *
        * Use this, if only one model is considered. */ - public ParserTestTimeMeasurementKeyBuilder withOriginalModelLocation(String originalModelLocation) { - this.keyMap.put(ParserTestTimeMeasurerKeyType.ORIGINAL_MODEL_LOCATION, originalModelLocation); + public ParserTestTimeMeasurementKeyBuilder withModelSourceFileDirLocation(String modelSourceFileDirLocation) { + this.keyMap.put(ParserTestTimeMeasurerKeyType.MODEL_SOURCE_FILE_DIR_LOCATION, modelSourceFileDirLocation); return this; } /** - * The location, under which the parsed model resource can be found. The - * location can be any form of String that can be used to navigate (ex: - * Path.toString() or URI.toString()).
        + * The location of the model resource. The location can be any form of String + * that can be used to navigate (ex: Path.toString() or URI.toString()).
        *
        * Use this, if only one model is considered. */ - public ParserTestTimeMeasurementKeyBuilder withParsedModelLocation(String parsedModelLocation) { - this.keyMap.put(ParserTestTimeMeasurerKeyType.PARSED_MODEL_LOCATION, parsedModelLocation); + public ParserTestTimeMeasurementKeyBuilder withModelResourceLocation(String modelResourceLocation) { + this.keyMap.put(ParserTestTimeMeasurerKeyType.MODEL_RESOURCE_LOCATION, modelResourceLocation); return this; } /** - * The path, under which all (left hand side) original model files can be found. - * These files were parsed to create the corresponding model resource. The - * location can be any form of String that can be used to navigate (ex: - * Path.toString() or URI.toString()).
        - *
        - * Use this, if two models are considered. + * {@link #withModelSourceFileDirLocation(String)} for the left hand side model + * for cases, where two models are considered. */ - public ParserTestTimeMeasurementKeyBuilder withOriginalLeftModelLocation(String originalModelLocation) { - this.keyMap.put(ParserTestTimeMeasurerKeyType.ORIGINAL_LEFT_MODEL_LOCATION, originalModelLocation); + public ParserTestTimeMeasurementKeyBuilder withLeftModelSourceFileDirLocation(String modelSourceFileDirLocation) { + this.keyMap.put(ParserTestTimeMeasurerKeyType.LEFT_MODEL_SOURCE_FILE_DIR_LOCATION, modelSourceFileDirLocation); return this; } /** - * The location, under which the (left hand side) parsed model resource can be - * found. The location can be any form of String that can be used to navigate - * (ex: Path.toString() or URI.toString()).
        - *
        - * Use this, if two models are considered. + * {@link #withModelSourceFileDirLocation(String)} for the right hand side model + * for cases, where two models are considered. */ - public ParserTestTimeMeasurementKeyBuilder withParsedLeftModelLocation(String parsedModelLocation) { - this.keyMap.put(ParserTestTimeMeasurerKeyType.PARSED_LEFT_MODEL_LOCATION, parsedModelLocation); + public ParserTestTimeMeasurementKeyBuilder withRightModelSourceFileDirLocation(String modelSourceFileDirLocation) { + this.keyMap.put(ParserTestTimeMeasurerKeyType.RIGHT_MODEL_SOURCE_FILE_DIR_LOCATION, modelSourceFileDirLocation); return this; } /** - * The path, under which all (right hand side) original model files can be - * found. These files were parsed to create the corresponding model resource.The - * location can be any form of String that can be used to navigate (ex: - * Path.toString() or URI.toString()).
        - *
        - *
        - * Use this, if two models are considered. + * {@link #withModelResourceLocation(String)} for the left hand side model for + * cases, where two models are considered. */ - public ParserTestTimeMeasurementKeyBuilder withOriginalRightModelLocation(String originalModelLocation) { - this.keyMap.put(ParserTestTimeMeasurerKeyType.ORIGINAL_RIGHT_MODEL_LOCATION, originalModelLocation); + public ParserTestTimeMeasurementKeyBuilder withLeftModelResourceLocation(String modelResourceLocation) { + this.keyMap.put(ParserTestTimeMeasurerKeyType.LEFT_MODEL_RESOURCE_LOCATION, modelResourceLocation); return this; } /** - * The location, under which the (right hand side) parsed model resource can be - * found. The location can be any form of String that can be used to navigate - * (ex: Path.toString() or URI.toString()).
        - *
        - * Use this, if two models are considered. + * {@link #withModelResourceLocation(String)} for the right hand side model for + * cases, where two models are considered. */ - public ParserTestTimeMeasurementKeyBuilder withParsedRightModelLocation(String parsedModelLocation) { - this.keyMap.put(ParserTestTimeMeasurerKeyType.PARSED_RIGHT_MODEL_LOCATION, parsedModelLocation); + public ParserTestTimeMeasurementKeyBuilder withRightModelResourceLocation(String modelResourceLocation) { + this.keyMap.put(ParserTestTimeMeasurerKeyType.RIGHT_MODEL_RESOURCE_LOCATION, modelResourceLocation); return this; } @@ -184,7 +167,8 @@ public ParserTestTimeMeasurementKeyBuilder withExpectedSimilarityResultProviderC } /** - * The name of the repository that is considered in the test class.
        + * The name of the repository that is considered in the test class, from which + * model resource was parsed.
        *
        * Use this, if only one repository/commit is considered. */ @@ -214,9 +198,8 @@ public ParserTestTimeMeasurementKeyBuilder withCommitID(String commitID) { } /** - * The name of the (left-hand-side) repository.
        - *
        - * Use this, if two repositories/commits are considered. + * {@link #withRepositoryName(String)} for the repository of the left hand side + * model for cases, where two repositories/commits are considered. */ public ParserTestTimeMeasurementKeyBuilder withLeftRepositoryName(String leftRepositoryName) { this.keyMap.put(ParserTestTimeMeasurerKeyType.LEFT_REPOSITORY_NAME, leftRepositoryName); @@ -224,29 +207,26 @@ public ParserTestTimeMeasurementKeyBuilder withLeftRepositoryName(String leftRep } /** - * The URI to the (left-hand-side) repository.
        - *
        - * Use this, if two repositories/commits are considered. + * {@link #withRepositoryName(String)} for the repository of the right hand side + * model for cases, where two repositories/commits are considered. */ - public ParserTestTimeMeasurementKeyBuilder withLeftRepositoryURI(String leftRepositoryURI) { - this.keyMap.put(ParserTestTimeMeasurerKeyType.LEFT_REPOSITORY_URI, leftRepositoryURI); + public ParserTestTimeMeasurementKeyBuilder withRightRepositoryName(String rightRepositoryName) { + this.keyMap.put(ParserTestTimeMeasurerKeyType.RIGHT_REPOSITORY_NAME, rightRepositoryName); return this; } /** - * The name of the (right-hand-side) repository.
        - *
        - * Use this, if two repositories/commits are considered. + * {@link #withRepositoryURI(String)} for the repository URI of the left hand + * side model for cases, where two repositories/commits are considered. */ - public ParserTestTimeMeasurementKeyBuilder withRightRepositoryName(String rightRepositoryName) { - this.keyMap.put(ParserTestTimeMeasurerKeyType.RIGHT_REPOSITORY_NAME, rightRepositoryName); + public ParserTestTimeMeasurementKeyBuilder withLeftRepositoryURI(String leftRepositoryURI) { + this.keyMap.put(ParserTestTimeMeasurerKeyType.LEFT_REPOSITORY_URI, leftRepositoryURI); return this; } /** - * The URI to the (right-hand-side) repository.
        - *
        - * Use this, if two repositories/commits are considered. + * {@link #withRepositoryURI(String)} for the repository URI of the right hand + * side model for cases, where two repositories/commits are considered. */ public ParserTestTimeMeasurementKeyBuilder withRightRepositoryURI(String rightRepositoryURI) { this.keyMap.put(ParserTestTimeMeasurerKeyType.RIGHT_REPOSITORY_URI, rightRepositoryURI); @@ -254,9 +234,8 @@ public ParserTestTimeMeasurementKeyBuilder withRightRepositoryURI(String rightRe } /** - * The hash of the (left-hand-side) commit that is currently considered.
        - *
        - * Use this, if two commits are considered. + * {@link #withCommitID(String)} for the commit ID of the left hand side model + * for cases, where two repositories/commits are considered. */ public ParserTestTimeMeasurementKeyBuilder withLeftCommitID(String leftCommitID) { this.keyMap.put(ParserTestTimeMeasurerKeyType.LEFT_COMMIT_ID, leftCommitID); @@ -264,9 +243,8 @@ public ParserTestTimeMeasurementKeyBuilder withLeftCommitID(String leftCommitID) } /** - * The hash of the (right-hand-side) commit that is currently considered.
        - *
        - * Use this, if two commits are considered. + * {@link #withCommitID(String)} for the commit ID of the right hand side model + * for cases, where two repositories/commits are considered. */ public ParserTestTimeMeasurementKeyBuilder withRightCommitID(String rightCommitID) { this.keyMap.put(ParserTestTimeMeasurerKeyType.RIGHT_COMMIT_ID, rightCommitID); diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/ParserTestTimeMeasurementKeyUtil.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/ParserTestTimeMeasurementKeyUtil.java index 399f657ee3..90bfa9c8d7 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/ParserTestTimeMeasurementKeyUtil.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/ParserTestTimeMeasurementKeyUtil.java @@ -6,7 +6,11 @@ import org.eclipse.emf.common.util.URI; /** - * TODO Commentary + * A utility class for {@link ParserTestTimeMeasurementKey} building process. + * Contains helper methods to adapt various parameters, especially to relativize + * paths and URIs. + * + * @author Alp Torac Genc */ public final class ParserTestTimeMeasurementKeyUtil { private static final File currentPathFile = new File("").getAbsoluteFile(); @@ -19,15 +23,30 @@ public final class ParserTestTimeMeasurementKeyUtil { private static URI baseURI = currentURI; private static Path relativizationPath = currentPath; + /** + * @return Relative URI (in String form), which results in the given uri upon + * being appended to {@link #setRelativizationPath(Path)}. + */ public static String getAdaptedURIString(URI uri) { return uri.deresolve(baseURI).toString(); } + /** + * Converts the given path to an absolute path and uses + * {@value #portablePathSeparator} as path separator for better portability. + * + * @return Relative path (in String form), which results in the given path upon + * being appended to {@link #setRelativizationPath(Path)}. + */ public static String getAdaptedPathString(Path path) { return relativizationPath.relativize(path.toAbsolutePath()).toString().replaceAll(absolutePathSeparatorRegex, portablePathSeparator); } + /** + * Sets the location, which will be used for relativization operations (on both + * paths and URIs) within this class. + */ public static void setRelativizationPath(Path pathOfReference) { relativizationPath = pathOfReference.toAbsolutePath(); baseURI = URI.createFileURI(relativizationPath.toAbsolutePath().toString()); diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/ParserTestTimeMeasurerKeyType.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/ParserTestTimeMeasurerKeyType.java index 2036946640..0e7cce2bf3 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/ParserTestTimeMeasurerKeyType.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/ParserTestTimeMeasurerKeyType.java @@ -4,33 +4,134 @@ * An enum that can be used to associate time measurement related information * with descriptions, in form of enum constants. * - * TODO Decide whether all enum constants require commentary - * * @author Alp Torac Genc */ public enum ParserTestTimeMeasurerKeyType { + /** + * A key type meant for paths, where discovery of model source file directories + * and model source parent directories start. + */ MODEL_DISCOVERY_PATH, - + /** + * A key type meant for the name of the class encapsulating how model source + * file directories and model source parent directories are to be discovered. + */ MODEL_DISCOVERY_CLASS_NAME, - ORIGINAL_MODEL_LOCATION, PARSED_MODEL_LOCATION, + /** + * A key type meant for model source file directory locations. Use this, if time + * measurement is from an operation involving one model resource. + */ + MODEL_SOURCE_FILE_DIR_LOCATION, + /** + * A key type meant for model resource locations. Use this, if time measurement + * is from an operation involving one model resource. + */ + MODEL_RESOURCE_LOCATION, - ORIGINAL_LEFT_MODEL_LOCATION, PARSED_LEFT_MODEL_LOCATION, ORIGINAL_RIGHT_MODEL_LOCATION, - PARSED_RIGHT_MODEL_LOCATION, + /** + * A key type meant for model source file directory locations for the left hand + * side model resource. Use this, if time measurement is from an operation + * involving two model resources. + */ + LEFT_MODEL_SOURCE_FILE_DIR_LOCATION, + /** + * A key type meant for model resource locations for the left hand side model + * resource. Use this, if time measurement is from an operation involving two + * model resources. + */ + LEFT_MODEL_RESOURCE_LOCATION, + /** + * A key type meant for model source file directory locations for the right hand + * side model resource. Use this, if time measurement is from an operation + * involving two model resources. + */ + RIGHT_MODEL_SOURCE_FILE_DIR_LOCATION, + /** + * A key type meant for model resource locations for the right hand side model + * resource. Use this, if time measurement is from an operation involving two + * model resources. + */ + RIGHT_MODEL_RESOURCE_LOCATION, + /** + * A key type meant for the name of the concrete resource parsing strategy + * class, which was used to parse a model resource. + */ RESOURCE_PARSING_STRATEGY_CLASS_NAME, + /** + * A key type meant for the name of the concrete model comparison class, which + * was used to perform model comparison on model resources. + */ MODEL_COMPARISON_CLASS_NAME, - TEST_CLASS_NAME, TEST_FACTORY_CLASS_NAME, + /** + * A key type meant for the name of the currently running test class. + */ + TEST_CLASS_NAME, + /** + * A key type meant for the name of the test factory class, which created the + * currently running dynamic test. + */ + TEST_FACTORY_CLASS_NAME, + /** + * A key type meant for the name of the concrete expected similarity result + * provider class. + */ EXPECTED_SIMILARITY_RESULT_PROVIDER_CLASS_NAME, - REPOSITORY_NAME, REPOSITORY_URI, COMMIT_ID, - - LEFT_REPOSITORY_NAME, LEFT_REPOSITORY_URI, - - RIGHT_REPOSITORY_NAME, RIGHT_REPOSITORY_URI, + /** + * A key type meant for the name of the repository. Use this, if time + * measurement is from an operation involving one model resource. + */ + REPOSITORY_NAME, + /** + * A key type meant for the URI of the repository. Use this, if time measurement + * is from an operation involving one model resource. + */ + REPOSITORY_URI, + /** + * A key type meant for commit IDs from the repository. Use this, if time + * measurement is from an operation involving one model resource. + */ + COMMIT_ID, - LEFT_COMMIT_ID, RIGHT_COMMIT_ID; + /** + * A key type meant for the name of the repository for the left hand side model + * resource. Use this, if time measurement is from an operation involving two + * model resources. + */ + LEFT_REPOSITORY_NAME, + /** + * A key type meant for the URI of the repository for the left hand side model + * resource. Use this, if time measurement is from an operation involving two + * model resources. + */ + LEFT_REPOSITORY_URI, + /** + * A key type meant for the name of the repository for the right hand side model + * resource. Use this, if time measurement is from an operation involving two + * model resources. + */ + RIGHT_REPOSITORY_NAME, + /** + * A key type meant for the URI of the repository for the right hand side model + * resource. Use this, if time measurement is from an operation involving two + * model resources. + */ + RIGHT_REPOSITORY_URI, + /** + * A key type meant for commit IDs of the repository for the left hand side + * model resource. Use this, if time measurement is from an operation involving + * two model resources. + */ + LEFT_COMMIT_ID, + /** + * A key type meant for commit IDs of the repository for the right hand side + * model resource. Use this, if time measurement is from an operation involving + * two model resources. + */ + RIGHT_COMMIT_ID; } \ No newline at end of file From ef5fdd17b244bdec6e031fb0b979a43ed2864701 Mon Sep 17 00:00:00 2001 From: AlpTorac Date: Sun, 14 Sep 2025 14:45:11 +0200 Subject: [PATCH 62/72] Fix layout objects now subtypes can copy attributes from supertypes --- .../AbstractJaMoPPParserRepoTest.java | 11 ++++++-- .../RepoParserTestFileLayout.java | 21 ++++++++------ .../jamopp/parser/ParserTestFileLayout.java | 28 +++++++++---------- 3 files changed, 34 insertions(+), 26 deletions(-) diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/AbstractJaMoPPParserRepoTest.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/AbstractJaMoPPParserRepoTest.java index 3e5e2516ee..7e8d0795cf 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/AbstractJaMoPPParserRepoTest.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/AbstractJaMoPPParserRepoTest.java @@ -99,7 +99,8 @@ public abstract class AbstractJaMoPPParserRepoTest extends AbstractJaMoPPParserS *
        * {@link AbstractJaMoPPParserRepoTest}: Loads expected similarity results * needed by tests, if their file exists. See - * {@link AbstractJaMoPPParserRepoTest} for more information. + * {@link AbstractJaMoPPParserRepoTest} for more information on the interactions + * between this method and the dynamic tests. */ @BeforeEach @Override @@ -140,7 +141,8 @@ public void setUp() { *
        * {@link AbstractJaMoPPParserRepoTest}: Saves the computed expected similarity * results needed by tests and deletes the local repository clone, if desired. - * See {@link AbstractJaMoPPParserRepoTest} for more information. + * See {@link AbstractJaMoPPParserRepoTest} for more information on the + * interactions between this method and the dynamic tests. */ @AfterEach @Override @@ -201,7 +203,10 @@ protected void startTimeMeasurement(ParserTestTimeMeasurementKeyBuilder keyBuild @Override protected RepoParserTestFileLayout initParserTestFileLayout() { var parserTestLayout = super.initParserTestFileLayout(); - var layout = new RepoParserTestFileLayout(parserTestLayout); + var layout = new RepoParserTestFileLayout(); + + layout.copyLayoutFrom(parserTestLayout); + layout.setRepoName(this.getRepoName()); layout.setExpectedSimilarityResultCacheDirName(expectedSimilarityResultCacheDirName); layout.setExpectedSimilarityResultCacheFileName(expectedSimilarityResultCacheFileName); diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/RepoParserTestFileLayout.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/RepoParserTestFileLayout.java index 271afb5edc..02c3d61ab0 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/RepoParserTestFileLayout.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/RepoParserTestFileLayout.java @@ -33,14 +33,6 @@ public class RepoParserTestFileLayout extends ParserTestFileLayout { */ private String repoName; - public RepoParserTestFileLayout() { - super(); - } - - public RepoParserTestFileLayout(ParserTestFileLayout layout) { - super(layout); - } - /** * Sets the name of the repository that will be locally cloned and used in tests */ @@ -123,4 +115,17 @@ public Path getRepoCloneRootDirPath() { public Path getModelSourceParentRootDirPath() { return this.getRepoCloneRootDirPath().resolve(this.repoName); } + + /** + * Copies the attributes of the given layout instance. All sub-types should + * implement a version of this method for their own type, in order to enable + * partially copying attributes from super-types. + */ + public void copyLayoutFrom(RepoParserTestFileLayout layout) { + super.copyLayoutFrom(layout); + this.expectedSimilarityResultCacheDirName = layout.expectedSimilarityResultCacheDirName; + this.expectedSimilarityResultCacheFileName = layout.expectedSimilarityResultCacheFileName; + this.repoCloneRootDirName = layout.repoCloneRootDirName; + this.repoName = layout.repoName; + } } diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ParserTestFileLayout.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ParserTestFileLayout.java index 11e19eabdc..b4ff551c1c 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ParserTestFileLayout.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ParserTestFileLayout.java @@ -39,21 +39,6 @@ public class ParserTestFileLayout { */ private String modelResourceFileExtension; - public ParserTestFileLayout() { - } - - /** - * Constructs a new instance and copies the attributes of the given layout - * instance. - */ - public ParserTestFileLayout(ParserTestFileLayout layout) { - this.testModelResourceFilesSaveDirPath = layout.testModelResourceFilesSaveDirPath; - this.cacheSaveDirPath = layout.cacheSaveDirPath; - this.timeMeasurementsFileSavePath = layout.timeMeasurementsFileSavePath; - this.timeMeasurementFileExtension = layout.timeMeasurementFileExtension; - this.modelResourceFileExtension = layout.modelResourceFileExtension; - } - /** * {@link #getModelSourceFileRootDirPath(Path)} */ @@ -221,4 +206,17 @@ public Path getRelativeModelSourceParentDirPath(Path modelParentDirPath) { private Path getAbsoluteCurrentDirectory() { return new File("").getAbsoluteFile().toPath(); } + + /** + * Copies the attributes of the given layout instance. All sub-types should + * implement a version of this method for their own type, in order to enable + * partially copying attributes from super-types. + */ + public void copyLayoutFrom(ParserTestFileLayout layout) { + this.testModelResourceFilesSaveDirPath = layout.testModelResourceFilesSaveDirPath; + this.cacheSaveDirPath = layout.cacheSaveDirPath; + this.timeMeasurementsFileSavePath = layout.timeMeasurementsFileSavePath; + this.timeMeasurementFileExtension = layout.timeMeasurementFileExtension; + this.modelResourceFileExtension = layout.modelResourceFileExtension; + } } From 0e392e0e72c1fcbe70156a2a84d34b21536de94c Mon Sep 17 00:00:00 2001 From: AlpTorac Date: Sun, 14 Sep 2025 14:46:02 +0200 Subject: [PATCH 63/72] Add missing Override annotations --- .../util/commentremoval/QuickCommentRemover.java | 3 +++ .../jamopp/parser/timemeasurement/GSONPersistingStrategy.java | 1 + .../jamopp/parser/timemeasurement/StopwatchStrategy.java | 2 ++ 3 files changed, 6 insertions(+) diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/commentremoval/QuickCommentRemover.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/commentremoval/QuickCommentRemover.java index d5bcf06485..1f85a3e33c 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/commentremoval/QuickCommentRemover.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/commentremoval/QuickCommentRemover.java @@ -192,6 +192,7 @@ private int parseBlockComment(int slashStarIdx, String text) { * * @see {@link QuickCommentRemover} for more information. */ + @Override public String removeComments(String text) { var result = ""; @@ -247,6 +248,7 @@ public String removeComments(String text) { *
        * Does not account for the broken comments to be a part of a multi-line string. */ + @Override public boolean hasLeadingBrokenComment(String text) { var blockCommentStartIdx = text.indexOf(blockCommentStart); var blockCommentEndIdx = text.indexOf(blockCommentEnd); @@ -260,6 +262,7 @@ public boolean hasLeadingBrokenComment(String text) { *
        * Does not account for the broken comments to be a part of a multi-line string. */ + @Override public boolean hasTrailingBrokenComment(String text) { var blockCommentStartIdx = text.lastIndexOf(blockCommentStart); var blockCommentEndIdx = text.lastIndexOf(blockCommentEnd); diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/GSONPersistingStrategy.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/GSONPersistingStrategy.java index a86900a93e..7fa2b2a127 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/GSONPersistingStrategy.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/GSONPersistingStrategy.java @@ -42,6 +42,7 @@ public GSONPersistingStrategy(DateTimeFormatter fileContentTimePattern) { this.fileContentTimePattern = fileContentTimePattern; } + @Override public void save(ITimeMeasurementDataStructure dataStructure, Path measurementsSavePath) { // Ensure that all necessary parent directories exist prior to saving var measurementsFile = measurementsSavePath.toFile(); diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/StopwatchStrategy.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/StopwatchStrategy.java index 8ca18edc05..1303bdece9 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/StopwatchStrategy.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/timemeasurement/StopwatchStrategy.java @@ -57,6 +57,7 @@ public class StopwatchStrategy implements ITimeMeasuringStrategy { * call is the time measurement. Not using them similar to brackets * will result in problems. */ + @Override public void startTimeMeasurement(ParserTestTimeMeasurementKey key, ITimeMeasurementTag tag) { /* * Suspends the potential outer method's Stopwatch, so that time measurements do @@ -85,6 +86,7 @@ public void startTimeMeasurement(ParserTestTimeMeasurementKey key, ITimeMeasurem * method call and this method call is the time measurement. Not using * them similar to brackets will result in inaccurate measurements. */ + @Override public TimeMeasurementEntry stopTimeMeasurement() { var currentMethodPair = watchEntryPairs.pop(); var watch = currentMethodPair.getWatch(); From f5af9a0e847e7faf6b2fc7cf61e02d1e99def55c Mon Sep 17 00:00:00 2001 From: AlpTorac Date: Sun, 14 Sep 2025 14:46:40 +0200 Subject: [PATCH 64/72] Extract regex as final variable --- .../util/difffilter/DiffFilter.java | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/difffilter/DiffFilter.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/difffilter/DiffFilter.java index 3bc9c70de8..57680df342 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/difffilter/DiffFilter.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/difffilter/DiffFilter.java @@ -77,6 +77,11 @@ public class DiffFilter { * The line separator used by the current OS. */ private static final String lineSeparator = System.lineSeparator(); + /** + * A regex (as string) for finding line separators in a less system dependent + * way. + */ + private static final String lineSeparatorRegex = "\\r?\\n"; /** * @return Splits the given (multi-line) text into its lines, where lines are @@ -87,7 +92,7 @@ public List splitLines(String text) { // Do not use System.lineSeparator since GIT uses UNIX terminal // UNIX terminal uses "\n" for new line - var diffLines = text.split("\\r?\\n"); + var diffLines = text.split(lineSeparatorRegex); for (var l : diffLines) { lines.add(l); @@ -97,8 +102,8 @@ public List splitLines(String text) { } /** - * Concatenates the given lines into a single String by gluing them with the - * line separator used by the system. + * Concatenates the given lines into a single String by concatenating them with + * the line separator used by the system. * * @return All lines as one String. Returns empty String if lines is null. */ @@ -117,8 +122,8 @@ public String concatLines(String... lines) { } /** - * Concatenates the given lines into a single String by gluing them with the - * line separator used by the system. + * Concatenates the given lines into a single String by concatenating them with + * the line separator used by the system. * * @return All lines as one String. Returns empty String if lines is null. */ From 9e7b48f41bc660d521c6a28385f5d08de4e52b1b Mon Sep 17 00:00:00 2001 From: AlpTorac Date: Sun, 14 Sep 2025 14:47:27 +0200 Subject: [PATCH 65/72] Track being set up in logging class Edit commentary --- .../similarity/SimilarityTestLogger.java | 78 +++++++++++++------ 1 file changed, 56 insertions(+), 22 deletions(-) diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/SimilarityTestLogger.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/SimilarityTestLogger.java index adeaa3ee1b..4064878827 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/SimilarityTestLogger.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/SimilarityTestLogger.java @@ -14,9 +14,20 @@ * @author Alp Torac Genc */ public class SimilarityTestLogger { + /** + * The prefix of each CIPM-related logger without the separating dot (".") + */ private final static String cipmRootLoggerName = "cipm"; + /** + * The prefix of each CIPM-related logger with the separating dot (".") + */ private final static String cipmLoggerNamePrefix = cipmRootLoggerName + "."; + /** + * Whether loggers have been set up + */ + private static boolean areLoggersSetUp = false; + /** * @return The Logger with the given name */ @@ -24,52 +35,75 @@ private static Logger getLoggerFor(String loggerName) { return Logger.getLogger(loggerName); } + /** + * @return The Logger for the given class + */ private static Logger getLoggerFor(Class cls) { return getLoggerFor(cipmLoggerNamePrefix + cls.getSimpleName()); } /** - * Sets up all loggers that have the {@code "cipm"} prefix in their name. + * Sets up all loggers that have the {@value #cipmLoggerNamePrefix} prefix in + * their name. Calling this method multiple times will have no effect on + * loggers, unless {@code forceSetUp == true}. + * + * @param forceSetUp Whether logger should be set anew after already being set + * previously */ - public static void setUpLogger() { - /* - * Order of precedence in logging levels: - * - * OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL - */ + public static void setUpLogger(boolean forceSetUp) { + if (forceSetUp || !areLoggersSetUp) { + /* + * Order of precedence in logging levels: + * + * OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL + */ - Logger logger = getLoggerFor(cipmRootLoggerName); - logger.setLevel(Level.DEBUG); + Logger logger = getLoggerFor(cipmRootLoggerName); + logger.setLevel(Level.DEBUG); - // logger = Logger.getLogger("jamopp"); - // logger.setLevel(Level.ALL); + // logger = Logger.getLogger("jamopp"); + // logger.setLevel(Level.ALL); - // TODO Re-think how logging should work + // TODO Re-think how logging should work + + logger = Logger.getRootLogger(); + logger.setLevel(Level.OFF); + logger.removeAllAppenders(); + ConsoleAppender ap = new ConsoleAppender(new PatternLayout("[%d{DATE}] %-5p: %c - %m%n"), + ConsoleAppender.SYSTEM_OUT); + logger.addAppender(ap); + areLoggersSetUp = true; + } + } - logger = Logger.getRootLogger(); - logger.setLevel(Level.OFF); - logger.removeAllAppenders(); - ConsoleAppender ap = new ConsoleAppender(new PatternLayout("[%d{DATE}] %-5p: %c - %m%n"), - ConsoleAppender.SYSTEM_OUT); - logger.addAppender(ap); + /** + * Sets up all loggers, if not already done. + * + * @see {@link #setUpLogger(boolean)} + */ + public static void setUpLogger() { + setUpLogger(false); } /** - * Logs the given message at {@link Level#DEBUG} level. + * Logs the given message at {@link Level#DEBUG} level, using the logger for the + * given class. */ public static void logDebugMsg(String msg, Class cls) { getLoggerFor(cls).debug(msg); } /** - * Logs the given message at {@link Level#INFO} level. + * Logs the given message at {@link Level#INFO} level, using the logger for the + * given class. */ public static void logInfoMsg(String msg, Class cls) { getLoggerFor(cls).info(msg); } /** - * Logs the given message at {@link Level#ERROR} level. + * Logs the given message at {@link Level#ERROR} level, using the logger for the + * given class. */ public static void logErrorMsg(String msg, Class cls) { getLoggerFor(cls).error(msg); @@ -77,7 +111,7 @@ public static void logErrorMsg(String msg, Class cls) { /** * Logs the given message at the {@link Level} that corresponds to the given - * priority. + * priority, using the logger for the given class. */ public static void logMsg(String msg, int priority, Class cls) { getLoggerFor(cls).log(Level.toLevel(priority), msg); From 778312d18960d827689927bf525524bfe8affca5 Mon Sep 17 00:00:00 2001 From: AlpTorac Date: Sun, 14 Sep 2025 14:48:06 +0200 Subject: [PATCH 66/72] Rename parameters Edit commentary --- .../similarity/jamopp/parser/FileUtil.java | 40 +++++++++++-------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/FileUtil.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/FileUtil.java index 64d78dd299..96d80ad6bf 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/FileUtil.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/FileUtil.java @@ -15,7 +15,7 @@ */ public class FileUtil { /** - * @return Whether the content of both dirs are similar. + * @return Whether the content of both paths are similar. * * @see {@link #filesEqual(File, File)} * @see {@link #dirsEqual(File, File)} @@ -49,6 +49,9 @@ public static String readEffectiveText(File f) { *
        * If both files cannot be read, they are ignored and this method returns true. * + * @param f1 A file object. Must be a file, directories are not allowed + * @param f2 Another file object. Must be a file, directories are not allowed + * * @see {@link #readEffectiveText(File)} */ public static boolean filesEqual(File f1, File f2) { @@ -63,28 +66,32 @@ public static boolean filesEqual(File f1, File f2) { } /** - * Recursively checks the equality of the given directories, based on their + * Recursively checks the equality of the given file objects, based on their * effective content (i.e. the files/sub-directories they contain and the - * contents of those files without whitespaces). + * contents of those files without whitespaces). If the given file objects + * represent files, delegates to {@link #filesEqual(File, File)} instead. + * + * @param f1 A file object representing either a file or a directory + * @param f2 Another file object representing either a file or a directory * - * @see {@link #filesEqual(File, File)}, {@link #readEffectiveText(File)} + * @see {@link #filesEqual(File, File)} */ - public static boolean dirsEqual(File dir1, File dir2) { - SimilarityTestLogger.logDebugMsg("Comparing: " + dir1.getName() + " and " + dir2.getName(), FileUtil.class); + public static boolean dirsEqual(File f1, File f2) { + SimilarityTestLogger.logDebugMsg("Comparing: " + f1.getName() + " and " + f2.getName(), FileUtil.class); // There cannot be 2 files with the same path, name and extension // so using TreeSet, which sorts the files spares doing so here var files1 = new TreeSet(); var files2 = new TreeSet(); - var dir1Files = dir1.listFiles(); + var dir1Files = f1.listFiles(); if (dir1Files != null) { for (var f : dir1Files) { files1.add(f); } } - var dir2Files = dir2.listFiles(); + var dir2Files = f2.listFiles(); if (dir2Files != null) { for (var f : dir2Files) { files2.add(f); @@ -99,19 +106,20 @@ public static boolean dirsEqual(File dir1, File dir2) { var fileIter2 = files2.iterator(); for (int i = 0; i < files1.size(); i++) { - var f1 = fileIter1.next(); - var f2 = fileIter2.next(); + var file1 = fileIter1.next(); + var file2 = fileIter2.next(); - if (f1.isDirectory() && f2.isDirectory()) { - if (!dirsEqual(f1, f2)) { + if (file1.isDirectory() && file2.isDirectory()) { + if (!dirsEqual(file1, file2)) { SimilarityTestLogger.logDebugMsg( - "Directories " + f1.getName() + " and " + f2.getName() + " are not equal", FileUtil.class); + "Directories " + file1.getName() + " and " + file2.getName() + " are not equal", + FileUtil.class); return false; } - } else if (f1.isFile() && f2.isFile()) { - if (!filesEqual(f1, f2)) { + } else if (file1.isFile() && file2.isFile()) { + if (!filesEqual(file1, file2)) { SimilarityTestLogger.logDebugMsg( - "Files " + f1.getName() + " and " + f2.getName() + " are not equal", FileUtil.class); + "Files " + file1.getName() + " and " + file2.getName() + " are not equal", FileUtil.class); return false; } } else { From 80ce2fd958bd7d3f12d9cf9de9074118b7629229 Mon Sep 17 00:00:00 2001 From: AlpTorac Date: Sun, 14 Sep 2025 14:48:56 +0200 Subject: [PATCH 67/72] Edit commentary --- .../RepoParserTestOptions.java | 5 ++++- .../RepoTestSimilarityValueEstimator.java | 3 ++- .../similarity/AbstractSimilarityTest.java | 11 +++++++--- .../AbstractResourceParsingStrategy.java | 2 +- .../similarity/eobject/ResourceHelper.java | 5 +++-- .../eobject/ResourceTestOptions.java | 3 ++- .../AbstractJaMoPPParserSimilarityTest.java | 20 +++++++++++-------- .../jamopp/parser/IModelResourceWrapper.java | 14 ++++++------- .../parser/JaMoPPModelResourceWrapper.java | 16 ++++++++------- .../jamopp/parser/ParserTestOptions.java | 3 ++- .../IExpectedSimilarityResultProvider.java | 3 ++- ...renceEqualitySimilarityResultProvider.java | 2 +- ...ractJaMoPPParserSimilarityTestFactory.java | 6 +++++- .../IJaMoPPParserTestGenerationStrategy.java | 10 +++++----- .../ModelComparisonTestFactory.java | 19 +++++++++++++++--- 15 files changed, 79 insertions(+), 43 deletions(-) diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/RepoParserTestOptions.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/RepoParserTestOptions.java index 6b60d5aa95..9ba41b4bb4 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/RepoParserTestOptions.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/RepoParserTestOptions.java @@ -15,6 +15,8 @@ * similarity results should actually be used in tests *

      * + * @see {@link ParserTestOptions} for other options. + * * @author Alp Torac Genc */ public class RepoParserTestOptions extends ParserTestOptions { @@ -67,7 +69,8 @@ public boolean shouldUseCachedExpectedSimilarityResults() { /** * Copies all options from the given instance; i.e. after calling this method, * all options inside the given instance will override the corresponding options - * in this. + * in this. All sub-types should implement a version of this method for their + * own type, in order to enable partially copying options from super-types. */ public void copyOptionsFrom(RepoParserTestOptions opts) { super.copyOptionsFrom(opts); diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/RepoTestSimilarityValueEstimator.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/RepoTestSimilarityValueEstimator.java index c0cf33a4c1..e7fd85b086 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/RepoTestSimilarityValueEstimator.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/util/RepoTestSimilarityValueEstimator.java @@ -22,7 +22,8 @@ * re-using various GIT elements.
      *
      * Uses {@link QuickCommentRemover}, which removes commentaries in an - * approximative fashion. Therefore, the computed results may be inaccurate. + * approximative fashion. Therefore, the computed results may not always be + * fully accurate. * * @author Alp Torac Genc */ diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/AbstractSimilarityTest.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/AbstractSimilarityTest.java index 781ce6ff97..2806e258db 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/AbstractSimilarityTest.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/AbstractSimilarityTest.java @@ -21,12 +21,15 @@ public abstract class AbstractSimilarityTest { *
      * It is suggested to have a call to {@code super.setUp()} as the FIRST * statement in overriding implementations. Doing so circumvents potential - * errors caused by the order of set up operations.
      + * errors caused by the order of set up operations, such as logging not working + * as expected. Sub-types are still allowed to perform other preparatory + * steps prior to {@code super.setUp()}, however.
      *
      * {@link AbstractSimilarityTest}: Sets up the underlying * {@link ISimilarityCheckerContainer}, which will be used for similarity * checking through {@link #isSimilar(Object, Object)} and - * {@link #areSimilar(Collection, Collection)}. + * {@link #areSimilar(Collection, Collection)}. Also sets up logging via + * {@link SimilarityTestLogger#setUpLogger()}. */ @BeforeEach public void setUp() { @@ -41,7 +44,9 @@ public void setUp() { *
      * It is suggested to have a call to {@code super.tearDown()} as the LAST * statement in overriding implementations. Doing so circumvents potential - * errors caused by the order of clean up operations.
      + * errors caused by the order of clean up operations. Sub-types are still + * allowed to perform other finalisation steps after {@code super.tearDown()}, + * however .
      *
      * {@link AbstractSimilarityTest}: Cleans up the underlying * {@link ISimilarityCheckerContainer} diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/eobject/AbstractResourceParsingStrategy.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/eobject/AbstractResourceParsingStrategy.java index 643d60e8d4..72e25d5d8a 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/eobject/AbstractResourceParsingStrategy.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/eobject/AbstractResourceParsingStrategy.java @@ -10,7 +10,7 @@ /** * An abstract class meant to be extended by classes that envelop the means to - * parse Resource instances from model source files.
      + * parse model Resource instances from model source files.
      *
      * Implementors are expected to: *
        diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/eobject/ResourceHelper.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/eobject/ResourceHelper.java index 7b0c1190dd..e75e9c8bd6 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/eobject/ResourceHelper.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/eobject/ResourceHelper.java @@ -20,14 +20,15 @@ */ public class ResourceHelper { /** - * @return The resource registry, which will be modified by this instance. + * @return The (singleton) resource registry, which will be modified by this + * instance. */ private static Resource.Factory.Registry getResourceRegistry() { return Resource.Factory.Registry.INSTANCE; } /** - * @return An empty {@link ResourceSetImpl} + * @return An empty {@link ResourceSetImpl} instance */ public static ResourceSet createResourceSet() { return new ResourceSetImpl(); diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/eobject/ResourceTestOptions.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/eobject/ResourceTestOptions.java index 5219208c4c..341f9d2611 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/eobject/ResourceTestOptions.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/eobject/ResourceTestOptions.java @@ -50,7 +50,8 @@ public boolean shouldDeleteAllModelResources() { /** * Copies all options from the given instance; i.e. after calling this method, * all options inside the given instance will override the corresponding options - * in this. + * in this. All sub-types should implement a version of this method for their + * own type, in order to enable partially copying options from super-types. */ public void copyOptionsFrom(ResourceTestOptions opts) { this.shouldUnloadAllModelResources = opts.shouldUnloadAllModelResources; diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/AbstractJaMoPPParserSimilarityTest.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/AbstractJaMoPPParserSimilarityTest.java index 214f759640..25f8718992 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/AbstractJaMoPPParserSimilarityTest.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/AbstractJaMoPPParserSimilarityTest.java @@ -79,8 +79,9 @@ public abstract class AbstractJaMoPPParserSimilarityTest extends AbstractJaMoPPS private static final String timeMeasurementSaveFolderPrefix = "Test run - "; /** * The amount of saved time measurement folders under - * {@link #timeMeasurementsSaveRootPath} from previous test runs. Used to - * compute {@link ParserTestFileLayout#setTimeMeasurementsFileSavePath(Path)} + * {@link #timeMeasurementsSaveRootPath} from previous test runs (starts with 1, + * not 0, hence the "+1" in its declaration). Used to compute + * {@link ParserTestFileLayout#setTimeMeasurementsFileSavePath(Path)} *

        * Computed here as a static final variable, so that the current test run uses * the same folder across all concrete test classes @@ -106,8 +107,10 @@ public abstract class AbstractJaMoPPParserSimilarityTest extends AbstractJaMoPPS *
        * {@link AbstractJaMoPPParserSimilarityTest}: Sets up the file layout for the * test {@link #getTestFileLayout()} and the time measuring mechanism - * {@link #setupForTimeMeasurements()}. See - * {@link AbstractJaMoPPParserSimilarityTest} for more information. + * {@link #setupForTimeMeasurements()}. Set up logging before + * {@code super.setUp()} and takes a time measurement for this method. + * See {@link AbstractJaMoPPParserSimilarityTest} for more information on the + * interactions between this method and the dynamic tests. */ @BeforeEach @Override @@ -131,9 +134,11 @@ public void setUp() { * {@link AbstractJaMoPPParserSimilarityTest}: Performs various operations on * model resources that were parsed in the dynamic tests, according to the * preferences that are encoded in {@link #getResourceTestOptions()}, such as - * {@link ParserTestOptions#shouldSaveCachedModelResources()}. It then finishes + * {@link ParserTestOptions#shouldSaveCachedModelResources()}. Takes a time + * measurement for this method. After {@code super.tearDown()}, finishes * time measurement taking and saves the time measurements from the current test - * class. See {@link AbstractJaMoPPParserSimilarityTest} for more information. + * class. See {@link AbstractJaMoPPParserSimilarityTest} for more + * information on the interactions between this method and the dynamic tests. */ @AfterEach @Override @@ -569,7 +574,6 @@ public Collection createTests(Path[] modelSourceFileDirPaths, Resou * @see {@link #discoverModelSourceFileDirsAt(Path)} and * {@link #discoverModelSourceParentDirsAt(Path)} for finding models to * parse - * @see {@link TestFactory} for what tests are to be generated */ @TestFactory public Collection createTests() { @@ -670,7 +674,7 @@ protected Collection discoverModelSourceParentDirsAt(Path modelSourceParen * Dynamic tests will be generated for each strategy in the returned collection, * regardless of what dynamic tests where generated previously.
        *
        - * This method allows splitting dynamic test generation; with respect to what + * This method allows splitting dynamic test generation, with respect to what * model resources will be compared to which ones, and in what order. * * @return A collection of test generation strategies, which encapsulate how diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/IModelResourceWrapper.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/IModelResourceWrapper.java index 0e77712daf..77f81a4832 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/IModelResourceWrapper.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/IModelResourceWrapper.java @@ -24,9 +24,8 @@ */ public interface IModelResourceWrapper { /** - * Parses all Java-Model source files under the given model source file - * directory. The parsed model resource can be accessed via - * {@link #getModelResource()}. + * Parses all model source files under the given model source file directory. + * The parsed model resource can be accessed via {@link #getModelResource()}. * * @param modelDir A model source file directory * @param modelResourceURI The URI that the parsed model resource will reside @@ -81,14 +80,15 @@ public interface IModelResourceWrapper { * Loads all parsed model resources. * * @return Whether all parsed model resources have been loaded. If no resources - * have been parsed, no resource will be loaded. + * have been parsed, no resource will be loaded and this method will + * return true. */ public boolean loadParsedResources(); /** - * Sets the URIs of all parsed resources with respect to the given URI, which - * will be assigned to the parsed model resource that contains all direct - * contents of the model source files. + * Sets the URIs of all parsed resources according to the given URI, which will + * be assigned to the parsed model resource that contains all direct contents of + * the model source files. * * @param newParsedModelResourceURI The new URI of the parsed model resource * ({@link #getModelResource()} in this case) diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/JaMoPPModelResourceWrapper.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/JaMoPPModelResourceWrapper.java index fdc41df99b..7c5a129b31 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/JaMoPPModelResourceWrapper.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/JaMoPPModelResourceWrapper.java @@ -115,11 +115,13 @@ protected URI getArtificialResourceURI(URI correspondingModelResourceURI) { * proxy objects within directModelResources, as well as the native Java library * resources that are needed by modelResourceSet.
        *
        - * If {@link #isSplitArtificialResource()}, moves all non-direct model resources - * (i.e. model resources that are not a part of directModelResources), into the - * created ArtificialResource. This way, direct model resource contents inside - * directModelResources can be compared more efficiently, since the non-direct - * model resources will likely be excluded from the comparison. + * If {@link #isSplitArtificialResource()} == true, moves all non-direct model + * resources (i.e. model resources that are not a part of directModelResources), + * into the created ArtificialResource. This way, direct model resource contents + * inside directModelResources can be compared more efficiently, since the + * non-direct model resources will likely be excluded from the comparison. If + * {@link #isSplitArtificialResource()} == false, only performs TrivialRecovery + * on modelResourceSet. * * @param modelResourceSet The model resource set that was the result of * parsing a model. An ArtificialResource will be @@ -407,8 +409,8 @@ public void setModelResourcesURI(URI newParsedModelResourceURI) { } /** - * @return The merged model resource, which contains all contents of all - * (directly) parsed model source files + * @return The merged model resource, which contains all (parsed) contents of + * all (directly) model source files */ @Override public Resource getModelResource() { diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ParserTestOptions.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ParserTestOptions.java index 9194a75606..746cc761e4 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ParserTestOptions.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/ParserTestOptions.java @@ -50,7 +50,8 @@ public boolean shouldRemoveModelResourcesFromCache() { /** * Copies all options from the given instance; i.e. after calling this method, * all options inside the given instance will override the corresponding options - * in this. + * in this. All sub-types should implement a version of this method for their + * own type, in order to enable partially copying options from super-types. */ public void copyOptionsFrom(ParserTestOptions opts) { super.copyOptionsFrom(opts); diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/resultprovider/IExpectedSimilarityResultProvider.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/resultprovider/IExpectedSimilarityResultProvider.java index 07909b3b36..199bf841cf 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/resultprovider/IExpectedSimilarityResultProvider.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/resultprovider/IExpectedSimilarityResultProvider.java @@ -21,7 +21,8 @@ public interface IExpectedSimilarityResultProvider { * Model resources and the respective paths should be provided via separate * parameters, as the original files that were parsed into model resources (i.e. * model source files / model source file directories) may reside under - * different paths, which cannot be determined from the model resource alone. + * different paths, which cannot always be determined from the model resource + * alone. * * @param lhsModelResource Left-hand side model resource * @param lhsModelSourceFileDirPath The path that the resource lhsRes was diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/resultprovider/ResourceReferenceEqualitySimilarityResultProvider.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/resultprovider/ResourceReferenceEqualitySimilarityResultProvider.java index 6423908887..f7a1d64b9e 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/resultprovider/ResourceReferenceEqualitySimilarityResultProvider.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/resultprovider/ResourceReferenceEqualitySimilarityResultProvider.java @@ -6,7 +6,7 @@ /** * Provides expected similarity results based on the reference equality of model - * resources. + * resources (i.e. {@code modelResource1 == modelResource2}). * * @author Alp Torac Genc */ diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/testfactory/AbstractJaMoPPParserSimilarityTestFactory.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/testfactory/AbstractJaMoPPParserSimilarityTestFactory.java index 5b031d8724..6b26884dea 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/testfactory/AbstractJaMoPPParserSimilarityTestFactory.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/testfactory/AbstractJaMoPPParserSimilarityTestFactory.java @@ -30,7 +30,11 @@ public abstract class AbstractJaMoPPParserSimilarityTestFactory { /** * Since there should always be a way to determine the expected similarity - * results, this method is implemented to provide a default way to do so.
        + * results, this method is implemented to provide a default way to do so. The + * default value (return value) of this method will be used, unless another + * IExpectedSimilarityResultProvider is set via + * {@link #setExpectedSimilarityResultProvider(IExpectedSimilarityResultProvider)}. + *
        *
        * Defaults to {@link ResourceReferenceEqualitySimilarityResultProvider}.
        *
        diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/testfactory/IJaMoPPParserTestGenerationStrategy.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/testfactory/IJaMoPPParserTestGenerationStrategy.java index 98593c72a9..d105a49fb6 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/testfactory/IJaMoPPParserTestGenerationStrategy.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/testfactory/IJaMoPPParserTestGenerationStrategy.java @@ -19,11 +19,11 @@ public interface IJaMoPPParserTestGenerationStrategy { * concrete implementor uses. The returned iterator {@code it} will return an * int array of size 2 upon {@code idxs = it.next()}, until all intended dynamic * tests are generated. Ints stored in {@code idxs} stand for the indices of - * elements in resArr and pathArr, which are to be used in the current dynamic - * test. In other words, the current dynamic test will use the - * {@code idxs[0]}-th elements for the left hand side (lhs) and - * {@code idxs[1]}-th elements for the right hand side (rhs) in the current - * dynamic test. + * elements in the model resource and model source file directory path arrays, + * which are to be used in the current dynamic test. More precisely, the current + * dynamic test will use the {@code idxs[0]}-th elements for the left hand side + * (lhs) and {@code idxs[1]}-th elements for the right hand side (rhs) in the + * current dynamic test. * * @param testResourceCount The amount of test resources that are present. Used * to mark when the returned iterator finishes, diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/testfactory/ModelComparisonTestFactory.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/testfactory/ModelComparisonTestFactory.java index 272f4c4055..d7b2ea7b7e 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/testfactory/ModelComparisonTestFactory.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/testfactory/ModelComparisonTestFactory.java @@ -22,18 +22,31 @@ * {@link Comparison} objects.
        *
        * The difference between this and {@link EAllContentSimilarityTestFactory} is - * that the comparison here is much more detailed. + * that the comparison here is much more detailed.
        + *
        + * Currently, {@link JavaModelComparator} is used for model comparison. * * @author Alp Torac Genc */ public class ModelComparisonTestFactory extends AbstractJaMoPPParserSimilarityTestFactory { private static final String description = "Java model comparison on both sides"; + /** + * Whether the order of model resource contents should matter in model + * comparison + */ private boolean contentOrderMatters; + /** + * Constructs an instance, for which {@code contentOrderMatters == true} + */ public ModelComparisonTestFactory() { this(true); } + /** + * @param contentOrderMatters Whether the order of model resource contents + * should matter in model comparison + */ public ModelComparisonTestFactory(boolean contentOrderMatters) { this.contentOrderMatters = contentOrderMatters; } @@ -69,8 +82,8 @@ protected Comparison compareModels(Resource lhsModelResource, Resource rhsModelR * Asserts that the result of similarity checking via model comparison results * in differences or not (denoted by expectedResult).
        *
        - * Compares lhsModelResource and rhsModelResource, as well as rhsModelResource - * and lhsModelResource; in order to ensure that the comparison is symmetric. + * Compares lhsModelResource to rhsModelResource, as well as rhsModelResource to + * lhsModelResource; in order to ensure that the comparison is symmetric. */ protected void testSimilarityWithModelComparison(Resource lhsModelResource, Resource rhsModelResource, Boolean expectedResult) { From 3f92ec3a02ffc47cf954ae58bcf39616f83baa69 Mon Sep 17 00:00:00 2001 From: AlpTorac Date: Sun, 14 Sep 2025 13:40:34 +0200 Subject: [PATCH 68/72] Add GSONTest to ensure saved time measurements are parseable via GSON --- .../timeMeasurementSample.json | 1062 +++++++++++++++++ .../fitests/repositorytests/GSONTest.java | 178 +++ 2 files changed, 1240 insertions(+) create mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/gsonTestResource/timeMeasurementSample.json create mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/GSONTest.java diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/gsonTestResource/timeMeasurementSample.json b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/gsonTestResource/timeMeasurementSample.json new file mode 100644 index 0000000000..4d4704e71a --- /dev/null +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/gsonTestResource/timeMeasurementSample.json @@ -0,0 +1,1062 @@ +{ + "startTime": "2025-09-08T14:52:53.972324", + "endTime": "2025-09-08T14:57:35.3576288", + "timeMeasurerDescription": "org.apache.commons.lang.time.StopWatch", + "timeUnit": "MILLISECONDS", + "overallRunTime": 281319, + "measurementTagSummary": { + "TEST_AFTEREACH": 4, + "TEST_BEFOREEACH": 15, + "DELETE_LOCAL_REPO_CLONE": 2, + "MODEL_RESOURCE_COMPARISON": 266233, + "TEST_OVERHEAD": 879, + "SAVE_EXPECTED_SIMILARITY_RESULTS": 7, + "LOAD_EXPECTED_SIMILARITY_RESULTS": 77, + "LOAD_MODEL_RESOURCE": 14094, + "SAVE_MODEL_RESOURCE": 4, + "EXPECTED_SIMILARITY_RESULT_COMPUTATION": 4 + }, + "measurementTagPercentageSummary": { + "TEST_AFTEREACH": "0.00", + "TEST_BEFOREEACH": "0.01", + "DELETE_LOCAL_REPO_CLONE": "0.00", + "MODEL_RESOURCE_COMPARISON": "94.64", + "TEST_OVERHEAD": "0.31", + "SAVE_EXPECTED_SIMILARITY_RESULTS": "0.00", + "LOAD_EXPECTED_SIMILARITY_RESULTS": "0.03", + "LOAD_MODEL_RESOURCE": "5.01", + "SAVE_MODEL_RESOURCE": "0.00", + "EXPECTED_SIMILARITY_RESULT_COMPUTATION": "0.00" + }, + "measurements": [ + { + "timeElapsed": 15, + "key": { + "keyMap": { + "REPOSITORY_URI": "https://github.com/TEAMMATES/teammates", + "TEST_CLASS_NAME": "TeammatesRepoTest", + "REPOSITORY_NAME": "teammates" + } + }, + "tag": "TEST_BEFOREEACH" + }, + { + "timeElapsed": 77, + "key": { + "keyMap": { + "REPOSITORY_URI": "https://github.com/TEAMMATES/teammates", + "TEST_CLASS_NAME": "TeammatesRepoTest", + "REPOSITORY_NAME": "teammates" + } + }, + "tag": "LOAD_EXPECTED_SIMILARITY_RESULTS" + }, + { + "timeElapsed": 4433, + "key": { + "keyMap": { + "REPOSITORY_URI": "https://github.com/TEAMMATES/teammates", + "TEST_CLASS_NAME": "TeammatesRepoTest", + "MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/648425746bb9434051647c8266dfab50a8f2d6a3.javaxmi", + "REPOSITORY_NAME": "teammates" + } + }, + "tag": "LOAD_MODEL_RESOURCE" + }, + { + "timeElapsed": 2287, + "key": { + "keyMap": { + "REPOSITORY_URI": "https://github.com/TEAMMATES/teammates", + "TEST_CLASS_NAME": "TeammatesRepoTest", + "MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/48b67bae03babf5a5e578aefce47f0285e8de8b4.javaxmi", + "REPOSITORY_NAME": "teammates" + } + }, + "tag": "LOAD_MODEL_RESOURCE" + }, + { + "timeElapsed": 2292, + "key": { + "keyMap": { + "REPOSITORY_URI": "https://github.com/TEAMMATES/teammates", + "TEST_CLASS_NAME": "TeammatesRepoTest", + "MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/83f518e279807dc7eb7023d008a4d1ab290fefee.javaxmi", + "REPOSITORY_NAME": "teammates" + } + }, + "tag": "LOAD_MODEL_RESOURCE" + }, + { + "timeElapsed": 2247, + "key": { + "keyMap": { + "REPOSITORY_URI": "https://github.com/TEAMMATES/teammates", + "TEST_CLASS_NAME": "TeammatesRepoTest", + "MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/f33d0bcd5843678b832efd8ee2963e72a95ecfc9.javaxmi", + "REPOSITORY_NAME": "teammates" + } + }, + "tag": "LOAD_MODEL_RESOURCE" + }, + { + "timeElapsed": 2835, + "key": { + "keyMap": { + "REPOSITORY_URI": "https://github.com/TEAMMATES/teammates", + "TEST_CLASS_NAME": "TeammatesRepoTest", + "MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/ce4463a8741840fd25a41b14801eab9193c7ed18.javaxmi", + "REPOSITORY_NAME": "teammates" + } + }, + "tag": "LOAD_MODEL_RESOURCE" + }, + { + "timeElapsed": 2, + "key": { + "keyMap": { + "REPOSITORY_URI": "https://github.com/TEAMMATES/teammates", + "TEST_CLASS_NAME": "TeammatesRepoTest", + "REPOSITORY_NAME": "teammates" + } + }, + "tag": "DELETE_LOCAL_REPO_CLONE" + }, + { + "timeElapsed": 20, + "key": { + "keyMap": { + "REPOSITORY_URI": "https://github.com/TEAMMATES/teammates", + "TEST_CLASS_NAME": "TeammatesRepoTest", + "REPOSITORY_NAME": "teammates" + } + }, + "tag": "TEST_OVERHEAD" + }, + { + "timeElapsed": 3, + "key": { + "keyMap": { + "RIGHT_MODEL_SOURCE_FILE_DIR_LOCATION": "testmodel-cache/teammates/648425746bb9434051647c8266dfab50a8f2d6a3.javaxmi", + "LEFT_MODEL_SOURCE_FILE_DIR_LOCATION": "testmodel-cache/teammates/648425746bb9434051647c8266dfab50a8f2d6a3.javaxmi", + "RIGHT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/648425746bb9434051647c8266dfab50a8f2d6a3.javaxmi", + "TEST_FACTORY_CLASS_NAME": "ModelComparisonTestFactory", + "EXPECTED_SIMILARITY_RESULT_PROVIDER_CLASS_NAME": "RepoCacheSimilarityResultProvider", + "LEFT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/648425746bb9434051647c8266dfab50a8f2d6a3.javaxmi" + } + }, + "tag": "EXPECTED_SIMILARITY_RESULT_COMPUTATION" + }, + { + "timeElapsed": 7693, + "key": { + "keyMap": { + "RIGHT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/648425746bb9434051647c8266dfab50a8f2d6a3.javaxmi", + "TEST_FACTORY_CLASS_NAME": "ModelComparisonTestFactory", + "EXPECTED_SIMILARITY_RESULT_PROVIDER_CLASS_NAME": "RepoCacheSimilarityResultProvider", + "LEFT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/648425746bb9434051647c8266dfab50a8f2d6a3.javaxmi", + "MODEL_COMPARISON_CLASS_NAME": "JavaModelComparator" + } + }, + "tag": "MODEL_RESOURCE_COMPARISON" + }, + { + "timeElapsed": 133, + "key": { + "keyMap": { + "RIGHT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/648425746bb9434051647c8266dfab50a8f2d6a3.javaxmi", + "TEST_FACTORY_CLASS_NAME": "ModelComparisonTestFactory", + "EXPECTED_SIMILARITY_RESULT_PROVIDER_CLASS_NAME": "RepoCacheSimilarityResultProvider", + "LEFT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/648425746bb9434051647c8266dfab50a8f2d6a3.javaxmi" + } + }, + "tag": "TEST_OVERHEAD" + }, + { + "timeElapsed": 5381, + "key": { + "keyMap": { + "RIGHT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/648425746bb9434051647c8266dfab50a8f2d6a3.javaxmi", + "TEST_FACTORY_CLASS_NAME": "ModelComparisonTestFactory", + "EXPECTED_SIMILARITY_RESULT_PROVIDER_CLASS_NAME": "RepoCacheSimilarityResultProvider", + "LEFT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/648425746bb9434051647c8266dfab50a8f2d6a3.javaxmi", + "MODEL_COMPARISON_CLASS_NAME": "JavaModelComparator" + } + }, + "tag": "MODEL_RESOURCE_COMPARISON" + }, + { + "timeElapsed": 84, + "key": { + "keyMap": { + "RIGHT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/648425746bb9434051647c8266dfab50a8f2d6a3.javaxmi", + "TEST_FACTORY_CLASS_NAME": "ModelComparisonTestFactory", + "EXPECTED_SIMILARITY_RESULT_PROVIDER_CLASS_NAME": "RepoCacheSimilarityResultProvider", + "LEFT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/648425746bb9434051647c8266dfab50a8f2d6a3.javaxmi" + } + }, + "tag": "TEST_OVERHEAD" + }, + { + "timeElapsed": 0, + "key": { + "keyMap": { + "RIGHT_MODEL_SOURCE_FILE_DIR_LOCATION": "testmodel-cache/teammates/48b67bae03babf5a5e578aefce47f0285e8de8b4.javaxmi", + "LEFT_MODEL_SOURCE_FILE_DIR_LOCATION": "testmodel-cache/teammates/648425746bb9434051647c8266dfab50a8f2d6a3.javaxmi", + "RIGHT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/48b67bae03babf5a5e578aefce47f0285e8de8b4.javaxmi", + "TEST_FACTORY_CLASS_NAME": "ModelComparisonTestFactory", + "EXPECTED_SIMILARITY_RESULT_PROVIDER_CLASS_NAME": "RepoCacheSimilarityResultProvider", + "LEFT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/648425746bb9434051647c8266dfab50a8f2d6a3.javaxmi" + } + }, + "tag": "EXPECTED_SIMILARITY_RESULT_COMPUTATION" + }, + { + "timeElapsed": 18792, + "key": { + "keyMap": { + "RIGHT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/48b67bae03babf5a5e578aefce47f0285e8de8b4.javaxmi", + "TEST_FACTORY_CLASS_NAME": "ModelComparisonTestFactory", + "EXPECTED_SIMILARITY_RESULT_PROVIDER_CLASS_NAME": "RepoCacheSimilarityResultProvider", + "LEFT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/648425746bb9434051647c8266dfab50a8f2d6a3.javaxmi", + "MODEL_COMPARISON_CLASS_NAME": "JavaModelComparator" + } + }, + "tag": "MODEL_RESOURCE_COMPARISON" + }, + { + "timeElapsed": 0, + "key": { + "keyMap": { + "RIGHT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/48b67bae03babf5a5e578aefce47f0285e8de8b4.javaxmi", + "TEST_FACTORY_CLASS_NAME": "ModelComparisonTestFactory", + "EXPECTED_SIMILARITY_RESULT_PROVIDER_CLASS_NAME": "RepoCacheSimilarityResultProvider", + "LEFT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/648425746bb9434051647c8266dfab50a8f2d6a3.javaxmi" + } + }, + "tag": "TEST_OVERHEAD" + }, + { + "timeElapsed": 15107, + "key": { + "keyMap": { + "RIGHT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/648425746bb9434051647c8266dfab50a8f2d6a3.javaxmi", + "TEST_FACTORY_CLASS_NAME": "ModelComparisonTestFactory", + "EXPECTED_SIMILARITY_RESULT_PROVIDER_CLASS_NAME": "RepoCacheSimilarityResultProvider", + "LEFT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/48b67bae03babf5a5e578aefce47f0285e8de8b4.javaxmi", + "MODEL_COMPARISON_CLASS_NAME": "JavaModelComparator" + } + }, + "tag": "MODEL_RESOURCE_COMPARISON" + }, + { + "timeElapsed": 0, + "key": { + "keyMap": { + "RIGHT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/648425746bb9434051647c8266dfab50a8f2d6a3.javaxmi", + "TEST_FACTORY_CLASS_NAME": "ModelComparisonTestFactory", + "EXPECTED_SIMILARITY_RESULT_PROVIDER_CLASS_NAME": "RepoCacheSimilarityResultProvider", + "LEFT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/48b67bae03babf5a5e578aefce47f0285e8de8b4.javaxmi" + } + }, + "tag": "TEST_OVERHEAD" + }, + { + "timeElapsed": 0, + "key": { + "keyMap": { + "RIGHT_MODEL_SOURCE_FILE_DIR_LOCATION": "testmodel-cache/teammates/648425746bb9434051647c8266dfab50a8f2d6a3.javaxmi", + "LEFT_MODEL_SOURCE_FILE_DIR_LOCATION": "testmodel-cache/teammates/48b67bae03babf5a5e578aefce47f0285e8de8b4.javaxmi", + "RIGHT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/648425746bb9434051647c8266dfab50a8f2d6a3.javaxmi", + "TEST_FACTORY_CLASS_NAME": "ModelComparisonTestFactory", + "EXPECTED_SIMILARITY_RESULT_PROVIDER_CLASS_NAME": "RepoCacheSimilarityResultProvider", + "LEFT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/48b67bae03babf5a5e578aefce47f0285e8de8b4.javaxmi" + } + }, + "tag": "EXPECTED_SIMILARITY_RESULT_COMPUTATION" + }, + { + "timeElapsed": 12863, + "key": { + "keyMap": { + "RIGHT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/648425746bb9434051647c8266dfab50a8f2d6a3.javaxmi", + "TEST_FACTORY_CLASS_NAME": "ModelComparisonTestFactory", + "EXPECTED_SIMILARITY_RESULT_PROVIDER_CLASS_NAME": "RepoCacheSimilarityResultProvider", + "LEFT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/48b67bae03babf5a5e578aefce47f0285e8de8b4.javaxmi", + "MODEL_COMPARISON_CLASS_NAME": "JavaModelComparator" + } + }, + "tag": "MODEL_RESOURCE_COMPARISON" + }, + { + "timeElapsed": 0, + "key": { + "keyMap": { + "RIGHT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/648425746bb9434051647c8266dfab50a8f2d6a3.javaxmi", + "TEST_FACTORY_CLASS_NAME": "ModelComparisonTestFactory", + "EXPECTED_SIMILARITY_RESULT_PROVIDER_CLASS_NAME": "RepoCacheSimilarityResultProvider", + "LEFT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/48b67bae03babf5a5e578aefce47f0285e8de8b4.javaxmi" + } + }, + "tag": "TEST_OVERHEAD" + }, + { + "timeElapsed": 13244, + "key": { + "keyMap": { + "RIGHT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/48b67bae03babf5a5e578aefce47f0285e8de8b4.javaxmi", + "TEST_FACTORY_CLASS_NAME": "ModelComparisonTestFactory", + "EXPECTED_SIMILARITY_RESULT_PROVIDER_CLASS_NAME": "RepoCacheSimilarityResultProvider", + "LEFT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/648425746bb9434051647c8266dfab50a8f2d6a3.javaxmi", + "MODEL_COMPARISON_CLASS_NAME": "JavaModelComparator" + } + }, + "tag": "MODEL_RESOURCE_COMPARISON" + }, + { + "timeElapsed": 0, + "key": { + "keyMap": { + "RIGHT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/48b67bae03babf5a5e578aefce47f0285e8de8b4.javaxmi", + "TEST_FACTORY_CLASS_NAME": "ModelComparisonTestFactory", + "EXPECTED_SIMILARITY_RESULT_PROVIDER_CLASS_NAME": "RepoCacheSimilarityResultProvider", + "LEFT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/648425746bb9434051647c8266dfab50a8f2d6a3.javaxmi" + } + }, + "tag": "TEST_OVERHEAD" + }, + { + "timeElapsed": 0, + "key": { + "keyMap": { + "RIGHT_MODEL_SOURCE_FILE_DIR_LOCATION": "testmodel-cache/teammates/48b67bae03babf5a5e578aefce47f0285e8de8b4.javaxmi", + "LEFT_MODEL_SOURCE_FILE_DIR_LOCATION": "testmodel-cache/teammates/48b67bae03babf5a5e578aefce47f0285e8de8b4.javaxmi", + "RIGHT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/48b67bae03babf5a5e578aefce47f0285e8de8b4.javaxmi", + "TEST_FACTORY_CLASS_NAME": "ModelComparisonTestFactory", + "EXPECTED_SIMILARITY_RESULT_PROVIDER_CLASS_NAME": "RepoCacheSimilarityResultProvider", + "LEFT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/48b67bae03babf5a5e578aefce47f0285e8de8b4.javaxmi" + } + }, + "tag": "EXPECTED_SIMILARITY_RESULT_COMPUTATION" + }, + { + "timeElapsed": 4806, + "key": { + "keyMap": { + "RIGHT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/48b67bae03babf5a5e578aefce47f0285e8de8b4.javaxmi", + "TEST_FACTORY_CLASS_NAME": "ModelComparisonTestFactory", + "EXPECTED_SIMILARITY_RESULT_PROVIDER_CLASS_NAME": "RepoCacheSimilarityResultProvider", + "LEFT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/48b67bae03babf5a5e578aefce47f0285e8de8b4.javaxmi", + "MODEL_COMPARISON_CLASS_NAME": "JavaModelComparator" + } + }, + "tag": "MODEL_RESOURCE_COMPARISON" + }, + { + "timeElapsed": 76, + "key": { + "keyMap": { + "RIGHT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/48b67bae03babf5a5e578aefce47f0285e8de8b4.javaxmi", + "TEST_FACTORY_CLASS_NAME": "ModelComparisonTestFactory", + "EXPECTED_SIMILARITY_RESULT_PROVIDER_CLASS_NAME": "RepoCacheSimilarityResultProvider", + "LEFT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/48b67bae03babf5a5e578aefce47f0285e8de8b4.javaxmi" + } + }, + "tag": "TEST_OVERHEAD" + }, + { + "timeElapsed": 4779, + "key": { + "keyMap": { + "RIGHT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/48b67bae03babf5a5e578aefce47f0285e8de8b4.javaxmi", + "TEST_FACTORY_CLASS_NAME": "ModelComparisonTestFactory", + "EXPECTED_SIMILARITY_RESULT_PROVIDER_CLASS_NAME": "RepoCacheSimilarityResultProvider", + "LEFT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/48b67bae03babf5a5e578aefce47f0285e8de8b4.javaxmi", + "MODEL_COMPARISON_CLASS_NAME": "JavaModelComparator" + } + }, + "tag": "MODEL_RESOURCE_COMPARISON" + }, + { + "timeElapsed": 77, + "key": { + "keyMap": { + "RIGHT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/48b67bae03babf5a5e578aefce47f0285e8de8b4.javaxmi", + "TEST_FACTORY_CLASS_NAME": "ModelComparisonTestFactory", + "EXPECTED_SIMILARITY_RESULT_PROVIDER_CLASS_NAME": "RepoCacheSimilarityResultProvider", + "LEFT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/48b67bae03babf5a5e578aefce47f0285e8de8b4.javaxmi" + } + }, + "tag": "TEST_OVERHEAD" + }, + { + "timeElapsed": 0, + "key": { + "keyMap": { + "RIGHT_MODEL_SOURCE_FILE_DIR_LOCATION": "testmodel-cache/teammates/83f518e279807dc7eb7023d008a4d1ab290fefee.javaxmi", + "LEFT_MODEL_SOURCE_FILE_DIR_LOCATION": "testmodel-cache/teammates/48b67bae03babf5a5e578aefce47f0285e8de8b4.javaxmi", + "RIGHT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/83f518e279807dc7eb7023d008a4d1ab290fefee.javaxmi", + "TEST_FACTORY_CLASS_NAME": "ModelComparisonTestFactory", + "EXPECTED_SIMILARITY_RESULT_PROVIDER_CLASS_NAME": "RepoCacheSimilarityResultProvider", + "LEFT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/48b67bae03babf5a5e578aefce47f0285e8de8b4.javaxmi" + } + }, + "tag": "EXPECTED_SIMILARITY_RESULT_COMPUTATION" + }, + { + "timeElapsed": 13388, + "key": { + "keyMap": { + "RIGHT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/83f518e279807dc7eb7023d008a4d1ab290fefee.javaxmi", + "TEST_FACTORY_CLASS_NAME": "ModelComparisonTestFactory", + "EXPECTED_SIMILARITY_RESULT_PROVIDER_CLASS_NAME": "RepoCacheSimilarityResultProvider", + "LEFT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/48b67bae03babf5a5e578aefce47f0285e8de8b4.javaxmi", + "MODEL_COMPARISON_CLASS_NAME": "JavaModelComparator" + } + }, + "tag": "MODEL_RESOURCE_COMPARISON" + }, + { + "timeElapsed": 0, + "key": { + "keyMap": { + "RIGHT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/83f518e279807dc7eb7023d008a4d1ab290fefee.javaxmi", + "TEST_FACTORY_CLASS_NAME": "ModelComparisonTestFactory", + "EXPECTED_SIMILARITY_RESULT_PROVIDER_CLASS_NAME": "RepoCacheSimilarityResultProvider", + "LEFT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/48b67bae03babf5a5e578aefce47f0285e8de8b4.javaxmi" + } + }, + "tag": "TEST_OVERHEAD" + }, + { + "timeElapsed": 13419, + "key": { + "keyMap": { + "RIGHT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/48b67bae03babf5a5e578aefce47f0285e8de8b4.javaxmi", + "TEST_FACTORY_CLASS_NAME": "ModelComparisonTestFactory", + "EXPECTED_SIMILARITY_RESULT_PROVIDER_CLASS_NAME": "RepoCacheSimilarityResultProvider", + "LEFT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/83f518e279807dc7eb7023d008a4d1ab290fefee.javaxmi", + "MODEL_COMPARISON_CLASS_NAME": "JavaModelComparator" + } + }, + "tag": "MODEL_RESOURCE_COMPARISON" + }, + { + "timeElapsed": 0, + "key": { + "keyMap": { + "RIGHT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/48b67bae03babf5a5e578aefce47f0285e8de8b4.javaxmi", + "TEST_FACTORY_CLASS_NAME": "ModelComparisonTestFactory", + "EXPECTED_SIMILARITY_RESULT_PROVIDER_CLASS_NAME": "RepoCacheSimilarityResultProvider", + "LEFT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/83f518e279807dc7eb7023d008a4d1ab290fefee.javaxmi" + } + }, + "tag": "TEST_OVERHEAD" + }, + { + "timeElapsed": 0, + "key": { + "keyMap": { + "RIGHT_MODEL_SOURCE_FILE_DIR_LOCATION": "testmodel-cache/teammates/48b67bae03babf5a5e578aefce47f0285e8de8b4.javaxmi", + "LEFT_MODEL_SOURCE_FILE_DIR_LOCATION": "testmodel-cache/teammates/83f518e279807dc7eb7023d008a4d1ab290fefee.javaxmi", + "RIGHT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/48b67bae03babf5a5e578aefce47f0285e8de8b4.javaxmi", + "TEST_FACTORY_CLASS_NAME": "ModelComparisonTestFactory", + "EXPECTED_SIMILARITY_RESULT_PROVIDER_CLASS_NAME": "RepoCacheSimilarityResultProvider", + "LEFT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/83f518e279807dc7eb7023d008a4d1ab290fefee.javaxmi" + } + }, + "tag": "EXPECTED_SIMILARITY_RESULT_COMPUTATION" + }, + { + "timeElapsed": 13256, + "key": { + "keyMap": { + "RIGHT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/48b67bae03babf5a5e578aefce47f0285e8de8b4.javaxmi", + "TEST_FACTORY_CLASS_NAME": "ModelComparisonTestFactory", + "EXPECTED_SIMILARITY_RESULT_PROVIDER_CLASS_NAME": "RepoCacheSimilarityResultProvider", + "LEFT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/83f518e279807dc7eb7023d008a4d1ab290fefee.javaxmi", + "MODEL_COMPARISON_CLASS_NAME": "JavaModelComparator" + } + }, + "tag": "MODEL_RESOURCE_COMPARISON" + }, + { + "timeElapsed": 0, + "key": { + "keyMap": { + "RIGHT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/48b67bae03babf5a5e578aefce47f0285e8de8b4.javaxmi", + "TEST_FACTORY_CLASS_NAME": "ModelComparisonTestFactory", + "EXPECTED_SIMILARITY_RESULT_PROVIDER_CLASS_NAME": "RepoCacheSimilarityResultProvider", + "LEFT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/83f518e279807dc7eb7023d008a4d1ab290fefee.javaxmi" + } + }, + "tag": "TEST_OVERHEAD" + }, + { + "timeElapsed": 12802, + "key": { + "keyMap": { + "RIGHT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/83f518e279807dc7eb7023d008a4d1ab290fefee.javaxmi", + "TEST_FACTORY_CLASS_NAME": "ModelComparisonTestFactory", + "EXPECTED_SIMILARITY_RESULT_PROVIDER_CLASS_NAME": "RepoCacheSimilarityResultProvider", + "LEFT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/48b67bae03babf5a5e578aefce47f0285e8de8b4.javaxmi", + "MODEL_COMPARISON_CLASS_NAME": "JavaModelComparator" + } + }, + "tag": "MODEL_RESOURCE_COMPARISON" + }, + { + "timeElapsed": 0, + "key": { + "keyMap": { + "RIGHT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/83f518e279807dc7eb7023d008a4d1ab290fefee.javaxmi", + "TEST_FACTORY_CLASS_NAME": "ModelComparisonTestFactory", + "EXPECTED_SIMILARITY_RESULT_PROVIDER_CLASS_NAME": "RepoCacheSimilarityResultProvider", + "LEFT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/48b67bae03babf5a5e578aefce47f0285e8de8b4.javaxmi" + } + }, + "tag": "TEST_OVERHEAD" + }, + { + "timeElapsed": 0, + "key": { + "keyMap": { + "RIGHT_MODEL_SOURCE_FILE_DIR_LOCATION": "testmodel-cache/teammates/83f518e279807dc7eb7023d008a4d1ab290fefee.javaxmi", + "LEFT_MODEL_SOURCE_FILE_DIR_LOCATION": "testmodel-cache/teammates/83f518e279807dc7eb7023d008a4d1ab290fefee.javaxmi", + "RIGHT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/83f518e279807dc7eb7023d008a4d1ab290fefee.javaxmi", + "TEST_FACTORY_CLASS_NAME": "ModelComparisonTestFactory", + "EXPECTED_SIMILARITY_RESULT_PROVIDER_CLASS_NAME": "RepoCacheSimilarityResultProvider", + "LEFT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/83f518e279807dc7eb7023d008a4d1ab290fefee.javaxmi" + } + }, + "tag": "EXPECTED_SIMILARITY_RESULT_COMPUTATION" + }, + { + "timeElapsed": 5301, + "key": { + "keyMap": { + "RIGHT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/83f518e279807dc7eb7023d008a4d1ab290fefee.javaxmi", + "TEST_FACTORY_CLASS_NAME": "ModelComparisonTestFactory", + "EXPECTED_SIMILARITY_RESULT_PROVIDER_CLASS_NAME": "RepoCacheSimilarityResultProvider", + "LEFT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/83f518e279807dc7eb7023d008a4d1ab290fefee.javaxmi", + "MODEL_COMPARISON_CLASS_NAME": "JavaModelComparator" + } + }, + "tag": "MODEL_RESOURCE_COMPARISON" + }, + { + "timeElapsed": 75, + "key": { + "keyMap": { + "RIGHT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/83f518e279807dc7eb7023d008a4d1ab290fefee.javaxmi", + "TEST_FACTORY_CLASS_NAME": "ModelComparisonTestFactory", + "EXPECTED_SIMILARITY_RESULT_PROVIDER_CLASS_NAME": "RepoCacheSimilarityResultProvider", + "LEFT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/83f518e279807dc7eb7023d008a4d1ab290fefee.javaxmi" + } + }, + "tag": "TEST_OVERHEAD" + }, + { + "timeElapsed": 4282, + "key": { + "keyMap": { + "RIGHT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/83f518e279807dc7eb7023d008a4d1ab290fefee.javaxmi", + "TEST_FACTORY_CLASS_NAME": "ModelComparisonTestFactory", + "EXPECTED_SIMILARITY_RESULT_PROVIDER_CLASS_NAME": "RepoCacheSimilarityResultProvider", + "LEFT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/83f518e279807dc7eb7023d008a4d1ab290fefee.javaxmi", + "MODEL_COMPARISON_CLASS_NAME": "JavaModelComparator" + } + }, + "tag": "MODEL_RESOURCE_COMPARISON" + }, + { + "timeElapsed": 77, + "key": { + "keyMap": { + "RIGHT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/83f518e279807dc7eb7023d008a4d1ab290fefee.javaxmi", + "TEST_FACTORY_CLASS_NAME": "ModelComparisonTestFactory", + "EXPECTED_SIMILARITY_RESULT_PROVIDER_CLASS_NAME": "RepoCacheSimilarityResultProvider", + "LEFT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/83f518e279807dc7eb7023d008a4d1ab290fefee.javaxmi" + } + }, + "tag": "TEST_OVERHEAD" + }, + { + "timeElapsed": 0, + "key": { + "keyMap": { + "RIGHT_MODEL_SOURCE_FILE_DIR_LOCATION": "testmodel-cache/teammates/f33d0bcd5843678b832efd8ee2963e72a95ecfc9.javaxmi", + "LEFT_MODEL_SOURCE_FILE_DIR_LOCATION": "testmodel-cache/teammates/83f518e279807dc7eb7023d008a4d1ab290fefee.javaxmi", + "RIGHT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/f33d0bcd5843678b832efd8ee2963e72a95ecfc9.javaxmi", + "TEST_FACTORY_CLASS_NAME": "ModelComparisonTestFactory", + "EXPECTED_SIMILARITY_RESULT_PROVIDER_CLASS_NAME": "RepoCacheSimilarityResultProvider", + "LEFT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/83f518e279807dc7eb7023d008a4d1ab290fefee.javaxmi" + } + }, + "tag": "EXPECTED_SIMILARITY_RESULT_COMPUTATION" + }, + { + "timeElapsed": 12529, + "key": { + "keyMap": { + "RIGHT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/f33d0bcd5843678b832efd8ee2963e72a95ecfc9.javaxmi", + "TEST_FACTORY_CLASS_NAME": "ModelComparisonTestFactory", + "EXPECTED_SIMILARITY_RESULT_PROVIDER_CLASS_NAME": "RepoCacheSimilarityResultProvider", + "LEFT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/83f518e279807dc7eb7023d008a4d1ab290fefee.javaxmi", + "MODEL_COMPARISON_CLASS_NAME": "JavaModelComparator" + } + }, + "tag": "MODEL_RESOURCE_COMPARISON" + }, + { + "timeElapsed": 0, + "key": { + "keyMap": { + "RIGHT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/f33d0bcd5843678b832efd8ee2963e72a95ecfc9.javaxmi", + "TEST_FACTORY_CLASS_NAME": "ModelComparisonTestFactory", + "EXPECTED_SIMILARITY_RESULT_PROVIDER_CLASS_NAME": "RepoCacheSimilarityResultProvider", + "LEFT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/83f518e279807dc7eb7023d008a4d1ab290fefee.javaxmi" + } + }, + "tag": "TEST_OVERHEAD" + }, + { + "timeElapsed": 12677, + "key": { + "keyMap": { + "RIGHT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/83f518e279807dc7eb7023d008a4d1ab290fefee.javaxmi", + "TEST_FACTORY_CLASS_NAME": "ModelComparisonTestFactory", + "EXPECTED_SIMILARITY_RESULT_PROVIDER_CLASS_NAME": "RepoCacheSimilarityResultProvider", + "LEFT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/f33d0bcd5843678b832efd8ee2963e72a95ecfc9.javaxmi", + "MODEL_COMPARISON_CLASS_NAME": "JavaModelComparator" + } + }, + "tag": "MODEL_RESOURCE_COMPARISON" + }, + { + "timeElapsed": 0, + "key": { + "keyMap": { + "RIGHT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/83f518e279807dc7eb7023d008a4d1ab290fefee.javaxmi", + "TEST_FACTORY_CLASS_NAME": "ModelComparisonTestFactory", + "EXPECTED_SIMILARITY_RESULT_PROVIDER_CLASS_NAME": "RepoCacheSimilarityResultProvider", + "LEFT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/f33d0bcd5843678b832efd8ee2963e72a95ecfc9.javaxmi" + } + }, + "tag": "TEST_OVERHEAD" + }, + { + "timeElapsed": 0, + "key": { + "keyMap": { + "RIGHT_MODEL_SOURCE_FILE_DIR_LOCATION": "testmodel-cache/teammates/83f518e279807dc7eb7023d008a4d1ab290fefee.javaxmi", + "LEFT_MODEL_SOURCE_FILE_DIR_LOCATION": "testmodel-cache/teammates/f33d0bcd5843678b832efd8ee2963e72a95ecfc9.javaxmi", + "RIGHT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/83f518e279807dc7eb7023d008a4d1ab290fefee.javaxmi", + "TEST_FACTORY_CLASS_NAME": "ModelComparisonTestFactory", + "EXPECTED_SIMILARITY_RESULT_PROVIDER_CLASS_NAME": "RepoCacheSimilarityResultProvider", + "LEFT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/f33d0bcd5843678b832efd8ee2963e72a95ecfc9.javaxmi" + } + }, + "tag": "EXPECTED_SIMILARITY_RESULT_COMPUTATION" + }, + { + "timeElapsed": 12667, + "key": { + "keyMap": { + "RIGHT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/83f518e279807dc7eb7023d008a4d1ab290fefee.javaxmi", + "TEST_FACTORY_CLASS_NAME": "ModelComparisonTestFactory", + "EXPECTED_SIMILARITY_RESULT_PROVIDER_CLASS_NAME": "RepoCacheSimilarityResultProvider", + "LEFT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/f33d0bcd5843678b832efd8ee2963e72a95ecfc9.javaxmi", + "MODEL_COMPARISON_CLASS_NAME": "JavaModelComparator" + } + }, + "tag": "MODEL_RESOURCE_COMPARISON" + }, + { + "timeElapsed": 0, + "key": { + "keyMap": { + "RIGHT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/83f518e279807dc7eb7023d008a4d1ab290fefee.javaxmi", + "TEST_FACTORY_CLASS_NAME": "ModelComparisonTestFactory", + "EXPECTED_SIMILARITY_RESULT_PROVIDER_CLASS_NAME": "RepoCacheSimilarityResultProvider", + "LEFT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/f33d0bcd5843678b832efd8ee2963e72a95ecfc9.javaxmi" + } + }, + "tag": "TEST_OVERHEAD" + }, + { + "timeElapsed": 12812, + "key": { + "keyMap": { + "RIGHT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/f33d0bcd5843678b832efd8ee2963e72a95ecfc9.javaxmi", + "TEST_FACTORY_CLASS_NAME": "ModelComparisonTestFactory", + "EXPECTED_SIMILARITY_RESULT_PROVIDER_CLASS_NAME": "RepoCacheSimilarityResultProvider", + "LEFT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/83f518e279807dc7eb7023d008a4d1ab290fefee.javaxmi", + "MODEL_COMPARISON_CLASS_NAME": "JavaModelComparator" + } + }, + "tag": "MODEL_RESOURCE_COMPARISON" + }, + { + "timeElapsed": 0, + "key": { + "keyMap": { + "RIGHT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/f33d0bcd5843678b832efd8ee2963e72a95ecfc9.javaxmi", + "TEST_FACTORY_CLASS_NAME": "ModelComparisonTestFactory", + "EXPECTED_SIMILARITY_RESULT_PROVIDER_CLASS_NAME": "RepoCacheSimilarityResultProvider", + "LEFT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/83f518e279807dc7eb7023d008a4d1ab290fefee.javaxmi" + } + }, + "tag": "TEST_OVERHEAD" + }, + { + "timeElapsed": 0, + "key": { + "keyMap": { + "RIGHT_MODEL_SOURCE_FILE_DIR_LOCATION": "testmodel-cache/teammates/f33d0bcd5843678b832efd8ee2963e72a95ecfc9.javaxmi", + "LEFT_MODEL_SOURCE_FILE_DIR_LOCATION": "testmodel-cache/teammates/f33d0bcd5843678b832efd8ee2963e72a95ecfc9.javaxmi", + "RIGHT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/f33d0bcd5843678b832efd8ee2963e72a95ecfc9.javaxmi", + "TEST_FACTORY_CLASS_NAME": "ModelComparisonTestFactory", + "EXPECTED_SIMILARITY_RESULT_PROVIDER_CLASS_NAME": "RepoCacheSimilarityResultProvider", + "LEFT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/f33d0bcd5843678b832efd8ee2963e72a95ecfc9.javaxmi" + } + }, + "tag": "EXPECTED_SIMILARITY_RESULT_COMPUTATION" + }, + { + "timeElapsed": 4452, + "key": { + "keyMap": { + "RIGHT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/f33d0bcd5843678b832efd8ee2963e72a95ecfc9.javaxmi", + "TEST_FACTORY_CLASS_NAME": "ModelComparisonTestFactory", + "EXPECTED_SIMILARITY_RESULT_PROVIDER_CLASS_NAME": "RepoCacheSimilarityResultProvider", + "LEFT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/f33d0bcd5843678b832efd8ee2963e72a95ecfc9.javaxmi", + "MODEL_COMPARISON_CLASS_NAME": "JavaModelComparator" + } + }, + "tag": "MODEL_RESOURCE_COMPARISON" + }, + { + "timeElapsed": 105, + "key": { + "keyMap": { + "RIGHT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/f33d0bcd5843678b832efd8ee2963e72a95ecfc9.javaxmi", + "TEST_FACTORY_CLASS_NAME": "ModelComparisonTestFactory", + "EXPECTED_SIMILARITY_RESULT_PROVIDER_CLASS_NAME": "RepoCacheSimilarityResultProvider", + "LEFT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/f33d0bcd5843678b832efd8ee2963e72a95ecfc9.javaxmi" + } + }, + "tag": "TEST_OVERHEAD" + }, + { + "timeElapsed": 4853, + "key": { + "keyMap": { + "RIGHT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/f33d0bcd5843678b832efd8ee2963e72a95ecfc9.javaxmi", + "TEST_FACTORY_CLASS_NAME": "ModelComparisonTestFactory", + "EXPECTED_SIMILARITY_RESULT_PROVIDER_CLASS_NAME": "RepoCacheSimilarityResultProvider", + "LEFT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/f33d0bcd5843678b832efd8ee2963e72a95ecfc9.javaxmi", + "MODEL_COMPARISON_CLASS_NAME": "JavaModelComparator" + } + }, + "tag": "MODEL_RESOURCE_COMPARISON" + }, + { + "timeElapsed": 77, + "key": { + "keyMap": { + "RIGHT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/f33d0bcd5843678b832efd8ee2963e72a95ecfc9.javaxmi", + "TEST_FACTORY_CLASS_NAME": "ModelComparisonTestFactory", + "EXPECTED_SIMILARITY_RESULT_PROVIDER_CLASS_NAME": "RepoCacheSimilarityResultProvider", + "LEFT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/f33d0bcd5843678b832efd8ee2963e72a95ecfc9.javaxmi" + } + }, + "tag": "TEST_OVERHEAD" + }, + { + "timeElapsed": 0, + "key": { + "keyMap": { + "RIGHT_MODEL_SOURCE_FILE_DIR_LOCATION": "testmodel-cache/teammates/ce4463a8741840fd25a41b14801eab9193c7ed18.javaxmi", + "LEFT_MODEL_SOURCE_FILE_DIR_LOCATION": "testmodel-cache/teammates/f33d0bcd5843678b832efd8ee2963e72a95ecfc9.javaxmi", + "RIGHT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/ce4463a8741840fd25a41b14801eab9193c7ed18.javaxmi", + "TEST_FACTORY_CLASS_NAME": "ModelComparisonTestFactory", + "EXPECTED_SIMILARITY_RESULT_PROVIDER_CLASS_NAME": "RepoCacheSimilarityResultProvider", + "LEFT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/f33d0bcd5843678b832efd8ee2963e72a95ecfc9.javaxmi" + } + }, + "tag": "EXPECTED_SIMILARITY_RESULT_COMPUTATION" + }, + { + "timeElapsed": 12428, + "key": { + "keyMap": { + "RIGHT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/ce4463a8741840fd25a41b14801eab9193c7ed18.javaxmi", + "TEST_FACTORY_CLASS_NAME": "ModelComparisonTestFactory", + "EXPECTED_SIMILARITY_RESULT_PROVIDER_CLASS_NAME": "RepoCacheSimilarityResultProvider", + "LEFT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/f33d0bcd5843678b832efd8ee2963e72a95ecfc9.javaxmi", + "MODEL_COMPARISON_CLASS_NAME": "JavaModelComparator" + } + }, + "tag": "MODEL_RESOURCE_COMPARISON" + }, + { + "timeElapsed": 0, + "key": { + "keyMap": { + "RIGHT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/ce4463a8741840fd25a41b14801eab9193c7ed18.javaxmi", + "TEST_FACTORY_CLASS_NAME": "ModelComparisonTestFactory", + "EXPECTED_SIMILARITY_RESULT_PROVIDER_CLASS_NAME": "RepoCacheSimilarityResultProvider", + "LEFT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/f33d0bcd5843678b832efd8ee2963e72a95ecfc9.javaxmi" + } + }, + "tag": "TEST_OVERHEAD" + }, + { + "timeElapsed": 13154, + "key": { + "keyMap": { + "RIGHT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/f33d0bcd5843678b832efd8ee2963e72a95ecfc9.javaxmi", + "TEST_FACTORY_CLASS_NAME": "ModelComparisonTestFactory", + "EXPECTED_SIMILARITY_RESULT_PROVIDER_CLASS_NAME": "RepoCacheSimilarityResultProvider", + "LEFT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/ce4463a8741840fd25a41b14801eab9193c7ed18.javaxmi", + "MODEL_COMPARISON_CLASS_NAME": "JavaModelComparator" + } + }, + "tag": "MODEL_RESOURCE_COMPARISON" + }, + { + "timeElapsed": 0, + "key": { + "keyMap": { + "RIGHT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/f33d0bcd5843678b832efd8ee2963e72a95ecfc9.javaxmi", + "TEST_FACTORY_CLASS_NAME": "ModelComparisonTestFactory", + "EXPECTED_SIMILARITY_RESULT_PROVIDER_CLASS_NAME": "RepoCacheSimilarityResultProvider", + "LEFT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/ce4463a8741840fd25a41b14801eab9193c7ed18.javaxmi" + } + }, + "tag": "TEST_OVERHEAD" + }, + { + "timeElapsed": 1, + "key": { + "keyMap": { + "RIGHT_MODEL_SOURCE_FILE_DIR_LOCATION": "testmodel-cache/teammates/f33d0bcd5843678b832efd8ee2963e72a95ecfc9.javaxmi", + "LEFT_MODEL_SOURCE_FILE_DIR_LOCATION": "testmodel-cache/teammates/ce4463a8741840fd25a41b14801eab9193c7ed18.javaxmi", + "RIGHT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/f33d0bcd5843678b832efd8ee2963e72a95ecfc9.javaxmi", + "TEST_FACTORY_CLASS_NAME": "ModelComparisonTestFactory", + "EXPECTED_SIMILARITY_RESULT_PROVIDER_CLASS_NAME": "RepoCacheSimilarityResultProvider", + "LEFT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/ce4463a8741840fd25a41b14801eab9193c7ed18.javaxmi" + } + }, + "tag": "EXPECTED_SIMILARITY_RESULT_COMPUTATION" + }, + { + "timeElapsed": 12968, + "key": { + "keyMap": { + "RIGHT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/f33d0bcd5843678b832efd8ee2963e72a95ecfc9.javaxmi", + "TEST_FACTORY_CLASS_NAME": "ModelComparisonTestFactory", + "EXPECTED_SIMILARITY_RESULT_PROVIDER_CLASS_NAME": "RepoCacheSimilarityResultProvider", + "LEFT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/ce4463a8741840fd25a41b14801eab9193c7ed18.javaxmi", + "MODEL_COMPARISON_CLASS_NAME": "JavaModelComparator" + } + }, + "tag": "MODEL_RESOURCE_COMPARISON" + }, + { + "timeElapsed": 0, + "key": { + "keyMap": { + "RIGHT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/f33d0bcd5843678b832efd8ee2963e72a95ecfc9.javaxmi", + "TEST_FACTORY_CLASS_NAME": "ModelComparisonTestFactory", + "EXPECTED_SIMILARITY_RESULT_PROVIDER_CLASS_NAME": "RepoCacheSimilarityResultProvider", + "LEFT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/ce4463a8741840fd25a41b14801eab9193c7ed18.javaxmi" + } + }, + "tag": "TEST_OVERHEAD" + }, + { + "timeElapsed": 13186, + "key": { + "keyMap": { + "RIGHT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/ce4463a8741840fd25a41b14801eab9193c7ed18.javaxmi", + "TEST_FACTORY_CLASS_NAME": "ModelComparisonTestFactory", + "EXPECTED_SIMILARITY_RESULT_PROVIDER_CLASS_NAME": "RepoCacheSimilarityResultProvider", + "LEFT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/f33d0bcd5843678b832efd8ee2963e72a95ecfc9.javaxmi", + "MODEL_COMPARISON_CLASS_NAME": "JavaModelComparator" + } + }, + "tag": "MODEL_RESOURCE_COMPARISON" + }, + { + "timeElapsed": 0, + "key": { + "keyMap": { + "RIGHT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/ce4463a8741840fd25a41b14801eab9193c7ed18.javaxmi", + "TEST_FACTORY_CLASS_NAME": "ModelComparisonTestFactory", + "EXPECTED_SIMILARITY_RESULT_PROVIDER_CLASS_NAME": "RepoCacheSimilarityResultProvider", + "LEFT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/f33d0bcd5843678b832efd8ee2963e72a95ecfc9.javaxmi" + } + }, + "tag": "TEST_OVERHEAD" + }, + { + "timeElapsed": 0, + "key": { + "keyMap": { + "RIGHT_MODEL_SOURCE_FILE_DIR_LOCATION": "testmodel-cache/teammates/ce4463a8741840fd25a41b14801eab9193c7ed18.javaxmi", + "LEFT_MODEL_SOURCE_FILE_DIR_LOCATION": "testmodel-cache/teammates/ce4463a8741840fd25a41b14801eab9193c7ed18.javaxmi", + "RIGHT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/ce4463a8741840fd25a41b14801eab9193c7ed18.javaxmi", + "TEST_FACTORY_CLASS_NAME": "ModelComparisonTestFactory", + "EXPECTED_SIMILARITY_RESULT_PROVIDER_CLASS_NAME": "RepoCacheSimilarityResultProvider", + "LEFT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/ce4463a8741840fd25a41b14801eab9193c7ed18.javaxmi" + } + }, + "tag": "EXPECTED_SIMILARITY_RESULT_COMPUTATION" + }, + { + "timeElapsed": 4802, + "key": { + "keyMap": { + "RIGHT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/ce4463a8741840fd25a41b14801eab9193c7ed18.javaxmi", + "TEST_FACTORY_CLASS_NAME": "ModelComparisonTestFactory", + "EXPECTED_SIMILARITY_RESULT_PROVIDER_CLASS_NAME": "RepoCacheSimilarityResultProvider", + "LEFT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/ce4463a8741840fd25a41b14801eab9193c7ed18.javaxmi", + "MODEL_COMPARISON_CLASS_NAME": "JavaModelComparator" + } + }, + "tag": "MODEL_RESOURCE_COMPARISON" + }, + { + "timeElapsed": 77, + "key": { + "keyMap": { + "RIGHT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/ce4463a8741840fd25a41b14801eab9193c7ed18.javaxmi", + "TEST_FACTORY_CLASS_NAME": "ModelComparisonTestFactory", + "EXPECTED_SIMILARITY_RESULT_PROVIDER_CLASS_NAME": "RepoCacheSimilarityResultProvider", + "LEFT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/ce4463a8741840fd25a41b14801eab9193c7ed18.javaxmi" + } + }, + "tag": "TEST_OVERHEAD" + }, + { + "timeElapsed": 4592, + "key": { + "keyMap": { + "RIGHT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/ce4463a8741840fd25a41b14801eab9193c7ed18.javaxmi", + "TEST_FACTORY_CLASS_NAME": "ModelComparisonTestFactory", + "EXPECTED_SIMILARITY_RESULT_PROVIDER_CLASS_NAME": "RepoCacheSimilarityResultProvider", + "LEFT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/ce4463a8741840fd25a41b14801eab9193c7ed18.javaxmi", + "MODEL_COMPARISON_CLASS_NAME": "JavaModelComparator" + } + }, + "tag": "MODEL_RESOURCE_COMPARISON" + }, + { + "timeElapsed": 78, + "key": { + "keyMap": { + "RIGHT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/ce4463a8741840fd25a41b14801eab9193c7ed18.javaxmi", + "TEST_FACTORY_CLASS_NAME": "ModelComparisonTestFactory", + "EXPECTED_SIMILARITY_RESULT_PROVIDER_CLASS_NAME": "RepoCacheSimilarityResultProvider", + "LEFT_MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/ce4463a8741840fd25a41b14801eab9193c7ed18.javaxmi" + } + }, + "tag": "TEST_OVERHEAD" + }, + { + "timeElapsed": 7, + "key": { + "keyMap": { + "REPOSITORY_URI": "https://github.com/TEAMMATES/teammates", + "TEST_CLASS_NAME": "TeammatesRepoTest", + "REPOSITORY_NAME": "teammates" + } + }, + "tag": "SAVE_EXPECTED_SIMILARITY_RESULTS" + }, + { + "timeElapsed": 0, + "key": { + "keyMap": { + "REPOSITORY_URI": "https://github.com/TEAMMATES/teammates", + "TEST_CLASS_NAME": "TeammatesRepoTest", + "REPOSITORY_NAME": "teammates" + } + }, + "tag": "TEST_AFTEREACH" + }, + { + "timeElapsed": 1, + "key": { + "keyMap": { + "REPOSITORY_URI": "https://github.com/TEAMMATES/teammates", + "TEST_CLASS_NAME": "TeammatesRepoTest", + "MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/83f518e279807dc7eb7023d008a4d1ab290fefee.javaxmi", + "REPOSITORY_NAME": "teammates" + } + }, + "tag": "SAVE_MODEL_RESOURCE" + }, + { + "timeElapsed": 0, + "key": { + "keyMap": { + "REPOSITORY_URI": "https://github.com/TEAMMATES/teammates", + "TEST_CLASS_NAME": "TeammatesRepoTest", + "MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/f33d0bcd5843678b832efd8ee2963e72a95ecfc9.javaxmi", + "REPOSITORY_NAME": "teammates" + } + }, + "tag": "SAVE_MODEL_RESOURCE" + }, + { + "timeElapsed": 1, + "key": { + "keyMap": { + "REPOSITORY_URI": "https://github.com/TEAMMATES/teammates", + "TEST_CLASS_NAME": "TeammatesRepoTest", + "MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/ce4463a8741840fd25a41b14801eab9193c7ed18.javaxmi", + "REPOSITORY_NAME": "teammates" + } + }, + "tag": "SAVE_MODEL_RESOURCE" + }, + { + "timeElapsed": 1, + "key": { + "keyMap": { + "REPOSITORY_URI": "https://github.com/TEAMMATES/teammates", + "TEST_CLASS_NAME": "TeammatesRepoTest", + "MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/648425746bb9434051647c8266dfab50a8f2d6a3.javaxmi", + "REPOSITORY_NAME": "teammates" + } + }, + "tag": "SAVE_MODEL_RESOURCE" + }, + { + "timeElapsed": 1, + "key": { + "keyMap": { + "REPOSITORY_URI": "https://github.com/TEAMMATES/teammates", + "TEST_CLASS_NAME": "TeammatesRepoTest", + "MODEL_RESOURCE_LOCATION": "testResources/testmodel-cache/teammates/48b67bae03babf5a5e578aefce47f0285e8de8b4.javaxmi", + "REPOSITORY_NAME": "teammates" + } + }, + "tag": "SAVE_MODEL_RESOURCE" + }, + { + "timeElapsed": 4, + "key": { + "keyMap": { + "REPOSITORY_URI": "https://github.com/TEAMMATES/teammates", + "TEST_CLASS_NAME": "TeammatesRepoTest", + "REPOSITORY_NAME": "teammates" + } + }, + "tag": "TEST_AFTEREACH" + } + ] +} \ No newline at end of file diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/GSONTest.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/GSONTest.java new file mode 100644 index 0000000000..5dcb57bf8a --- /dev/null +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/GSONTest.java @@ -0,0 +1,178 @@ +package cipm.consistency.fitests.repositorytests; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.time.format.DateTimeFormatter; +import java.util.concurrent.TimeUnit; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import cipm.consistency.fitests.similarity.jamopp.parser.timemeasurement.DefaultTimeMeasurementDataStructure; +import cipm.consistency.fitests.similarity.jamopp.parser.timemeasurement.GSONLoadingStrategy; +import cipm.consistency.fitests.similarity.jamopp.parser.timemeasurement.GSONPersistingStrategy; +import cipm.consistency.fitests.similarity.jamopp.parser.timemeasurement.GeneralTimeMeasurementTag; +import cipm.consistency.fitests.similarity.jamopp.parser.timemeasurement.ITimeMeasurementDataStructure; +import cipm.consistency.fitests.similarity.jamopp.parser.timemeasurement.ITimeMeasurementLoadingStrategy; +import cipm.consistency.fitests.similarity.jamopp.parser.timemeasurement.ITimeMeasurementPersistingStrategy; +import cipm.consistency.fitests.similarity.jamopp.parser.timemeasurement.ITimeMeasurementTag; +import cipm.consistency.fitests.similarity.jamopp.parser.timemeasurement.ParserTestTimeMeasurerKeyType; + +/** + * Contains tests for GSON-based, time measurement related classes that ensure + * they work as intended. + *

        + * Note: Make sure to keep the time measurement file at + * {@link #gsonTestResourceRootPath} up to date, if there are format changes, as + * this test otherwise does not account for new format changes within time + * sample files. + * + * @author Alp Torac Genc + */ +public class GSONTest { + private static final DateTimeFormatter fileContentTimePattern = DateTimeFormatter.ISO_DATE_TIME; + + @SuppressWarnings("unchecked") + private static final ITimeMeasurementLoadingStrategy loadingStrat = new GSONLoadingStrategy(fileContentTimePattern, + DefaultTimeMeasurementDataStructure.class, + new Class[] { GeneralTimeMeasurementTag.class, RepoTimeMeasurementTag.class }); + private static final ITimeMeasurementPersistingStrategy persistingStrat = new GSONPersistingStrategy( + fileContentTimePattern); + + private static final Path gsonTestResourceRootPath = Path.of("gsonTestResource").toAbsolutePath(); + private static final Path formerTimeMeasurementPath = gsonTestResourceRootPath + .resolve("timeMeasurementSample.json"); + private static final Path newTimeMeasurementPath = gsonTestResourceRootPath + .resolve("gsonTestNewTimeMeasurement.json"); + + @BeforeEach + public void setUp() { + var timeMeasurementsRootDir = gsonTestResourceRootPath.toFile(); + if (!timeMeasurementsRootDir.exists() || timeMeasurementsRootDir.listFiles().length == 0) { + Assertions.fail("Test file missing at " + formerTimeMeasurementPath.toString()); + } + } + + @AfterEach + public void tearDown() { + if (newTimeMeasurementPath != null && newTimeMeasurementPath.toFile().exists()) { + try { + Files.delete(newTimeMeasurementPath); + } catch (IOException e) { + e.printStackTrace(); + Assertions.fail(e); + } + } + } + + /** + * Asserts that the content of the file under the given path is not blank + * + * @return Contents of the given path as a string instance + */ + private String readTimeMeasurement(Path pathToTimeMeasurementToRead) { + String content = null; + try { + content = Files.readString(pathToTimeMeasurementToRead); + Assertions.assertFalse(content.isBlank()); + } catch (IOException e) { + e.printStackTrace(); + Assertions.fail(e); + } + + return content; + } + + /** + * @return The data structure parsed from the file at the given path + */ + private ITimeMeasurementDataStructure loadTimeMeasurement(Path pathToTimeMeasurementToLoad) { + return loadingStrat.load(pathToTimeMeasurementToLoad); + } + + /** + * Persists the given data structure under the given path + */ + private void persistTimeMeasurement(ITimeMeasurementDataStructure dataStructure, Path savePath) { + persistingStrat.save(dataStructure, savePath); + } + + /** + * Asserts that the given data structure is parsed correctly and does not have + * any unexpected empty fields. + */ + private void assertDataStructureIntact(ITimeMeasurementDataStructure timeMeasurements) { + Assertions.assertNotNull(timeMeasurements.getTimeMeasurerDescription()); + + Assertions.assertNotNull(timeMeasurements.getEndTime()); + + Assertions.assertNotNull(timeMeasurements.getStartTime()); + + var entries = timeMeasurements.getTimeMeasurementEntries(); + Assertions.assertNotNull(entries); + Assertions.assertFalse(entries.isEmpty()); + + timeMeasurements.getTimeMeasurementEntries().forEach((e) -> { + var key = e.getKey(); + Assertions.assertNotNull(key); + key.getKeys().entrySet().forEach((ke) -> { + Assertions.assertNotNull(ke.getKey()); + Assertions.assertTrue(ParserTestTimeMeasurerKeyType.class.isAssignableFrom(ke.getKey().getClass())); + Assertions.assertNotNull(ke.getValue()); + }); + Assertions.assertNotNull(e.getTag()); + Assertions.assertTrue(ITimeMeasurementTag.class.isAssignableFrom(e.getTag().getClass())); + }); + + var tu = timeMeasurements.getTimeUnit(); + Assertions.assertNotNull(tu); + Assertions.assertTrue(TimeUnit.class.isAssignableFrom(tu.getClass())); + } + + /** + * Ensures that loading previously saved time measurements works as intended + */ + @Test + public void testDataStructureLoading() { + var timeMeasurements = this.loadTimeMeasurement(formerTimeMeasurementPath); + this.assertDataStructureIntact(timeMeasurements); + } + + /** + * Ensures that loaded and re-saved time measurements can be parsed as intended + */ + @Test + public void testSavedDataStructureLoading() { + var timeMeasurements = this.loadTimeMeasurement(formerTimeMeasurementPath); + this.persistTimeMeasurement(timeMeasurements, newTimeMeasurementPath); + var persistedTimeMeasurements = this.loadTimeMeasurement(newTimeMeasurementPath); + this.assertDataStructureIntact(persistedTimeMeasurements); + } + + /** + * Ensures that loaded and re-saved time measurements can be parsed as intended + * and the content of their files are equal + */ + @Test + public void testSavedDataStructureLoading_ContentEquality() { + var formerFileContent = this.readTimeMeasurement(formerTimeMeasurementPath); + var formerTimeMeasurements = this.loadTimeMeasurement(formerTimeMeasurementPath); + this.persistTimeMeasurement(formerTimeMeasurements, newTimeMeasurementPath); + + var newFileContent = this.readTimeMeasurement(newTimeMeasurementPath); + // Enable if GSON serialises Long instances with trailing zeroes (".0") + // newFileContent = newFileContent.replaceAll("\\.0,", ","); + + // Ensure that serialising produces the same file + Assertions.assertEquals(formerFileContent, newFileContent); + + var newTimeMeasurements = this.loadTimeMeasurement(newTimeMeasurementPath); + + // Ensure that deserialising freshly serialised instance produces an equal + // instance + Assertions.assertTrue(formerTimeMeasurements.equals(newTimeMeasurements)); + } +} From 51f8de09040ef6387b40340096a015639d41fd0b Mon Sep 17 00:00:00 2001 From: AlpTorac Date: Sun, 14 Sep 2025 13:47:49 +0200 Subject: [PATCH 69/72] Add README for fitests plug-in to provide an introduction and terminology --- .../cipm.consistency.fitests/README.md | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests/README.md diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/README.md b/commit-based-cipm/fi-tests/cipm.consistency.fitests/README.md new file mode 100644 index 0000000000..1954a00cc7 --- /dev/null +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/README.md @@ -0,0 +1,41 @@ +# Introduction + +cipm.consistency.fitests ("fitests" for short) plug-in contains tests for various aspects of similarity checking and model comparison. fitests is structured in a way that minimises dependencies to outside plug-ins. To this end, there are several abstract test classes that extend one another. This way, many different parts of fitests can be re-used in the future to implement further tests for EMF-based models. The "package-info.java" files under packages of fitests contain more information on their respective packages. + +# Contained Tests + +## Unittests + +TODO Write once the corresponding pull request is adapted + +## Parser Tests + +Tests under cipm.consistency.fitests.similarity.jamopp.parser package and its sub-packages are referred to as parser tests. They consider Java models and perform similarity checking and model comparison on them, according to concrete test classes. Throughout those tests, Java models in form of Java source files are parsed with JaMoPP, resulting in EMF-based Java model Resource instances. These Resource instances are then used in dynamic tests created by parser tests, in order to test various aspects of CIPM. + +The main difference between parser tests and the tests in the cipm.consistency.vsum.test package is, the latter runs commits from repositories through the entire CIPM pipeline, whereas the former only perform similarity checking and model comparison. Since CIPM pipeline additionally considers change propagation, code instrumentation and performance parameter calibration; parser tests are more lightweight in comparison. Therefore, parser tests are better suited to cover isolated cases in model comparison. + +### Repository Parser Tests + +Refer to the README of [cipm.consistency.fitests.repositorytests](../cipm.consistency.fitests.repositorytests/README.md) and the "package-info.java" files of packages under cipm.consistency.fitests.repositorytests plug-in for more information. + +# Terminology + +There are numerous terms that are commonly used across fitests, which are defined below: + +- Similarity checking + - Similarity result / Similarity checking result: (usually) a Boolean that indicates whether 2 or more objects are similar: Similar if the result is true, not similar if the result is false, undecidable if the result is null. Under normal circumstances, the result should not be null. + - Similarity Checking: Computation of the similarity of objects, especially in-memory models. The result of this operation is the similarity result. + - Similarity Checker: Mechanisms that perform similarity checking + - Similarity Checker Container (SCC): A provider of similarity checkers that contains similarity checker(s) + +- Models + - Model source file: A file containing parts of or information about a model. These are the original files of a model provided as input to parsing methods, which parse an in-memory version of the model. These files typically only contain direct contents of the model, i.e. the contents of the actual model that are declared directly in the model. If the model has any outside dependencies, typically only references to those dependencies are stored. + - Model source file directory: A directory that contains all model source files belonging to a (and only one) model. Passing a model source directory to a model parsing method will result in an in-memory model, which consists of the parsed contents of model source files. Model source files therein may or may not be nested in further directories. + - Model source parent directory: A directory that contains model source file directories of one or more models. Each nested model source file directory should be passed to model parsing methods separately, if in-memory models to be parsed should be separate. + - Model resource content: An in-memory representation of a model element, which is a part of a model. + - Model resource: An in-memory representation of a model (usually in form of a Resource instance). If multiple model resources are involved, their in-memory representation may be an object that aggregates individual model resources (such as a ResourceSet instance). Model resources consist of model resource contents and may include other metadata. + - Parsed model file / model resource file: A file containing parts of or information about a parsed model. These files persist the parsed in-memory models, allowing them to be loaded for speeding up tests. If all necessary parsed model files for a model are present, parsing the model from scratch is not necessary, as the resulting parsed model should have the same content as parsed model files. Keep in mind that the order of contents may differ, if model parsing methods are not fully deterministic. + +- Model comparison + - Model comparison: Thorough comparison of 2 or more model resources based on their contents. The result of this operation is a model comparison result. + - Model comparison result: (typically) an object, which yields all details about the comparison process, such as the concrete differences (if any) and which model resource contents were matched. It is more elaborate compared to a similarity checking result, as it provides more than whether multiple objects are similar, such as the means to locate the detected difference. \ No newline at end of file From 4af0553ffe5d1297718f5035336bb610ea842a13 Mon Sep 17 00:00:00 2001 From: AlpTorac Date: Mon, 8 Sep 2025 15:48:43 +0200 Subject: [PATCH 70/72] Add README for repositorytests to provide an introduction and link to the README of fitests plug-in --- .../cipm.consistency.fitests.repositorytests/README.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/README.md diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/README.md b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/README.md new file mode 100644 index 0000000000..9f56e56105 --- /dev/null +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/README.md @@ -0,0 +1,3 @@ +Tests under cipm.consistency.fitests.repositorytests package and its sub-packages are referred to as repository parser tests. They are a variant of parser tests, which consider Java code repositories (only GIT repositories at the time of writing this file) and parse EMF-based Java model Resources from them using JaMoPP. To this end, certain commits are checked out and then Java model Resources are parsed for each considered commit. To estimate expected similarity results in tests during run time, GIT diff patches between commits are analyzed for code changes. + +Refer to the README of [cipm.consistency.fitests](../cipm.consistency.fitests/README.md) for related tests and terminology. \ No newline at end of file From 87a37fac19a9de5bf92770a6aa33b728d511286b Mon Sep 17 00:00:00 2001 From: AlpTorac Date: Sun, 14 Sep 2025 15:34:23 +0200 Subject: [PATCH 71/72] Refactor FileUtil --- .../similarity/jamopp/parser/FileUtil.java | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/FileUtil.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/FileUtil.java index 96d80ad6bf..98afc9cd54 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/FileUtil.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests/src/cipm/consistency/fitests/similarity/jamopp/parser/FileUtil.java @@ -25,10 +25,12 @@ public static boolean areContentsEqual(Path path1, Path path2) { } /** - * Reads the given file and removes line breaks and whitespaces.
        + * Reads the effective text in the given file.
        *
        * If the given file cannot be read (due to IOException), returns an empty * string. + * + * @see {@link #getEffectiveText(String)} */ public static String readEffectiveText(File f) { var content = ""; @@ -40,7 +42,17 @@ public static String readEffectiveText(File f) { String.format("Could not read: %s, returning empty string", f.toPath().toString()), FileUtil.class); } - return content.replaceAll("\\n", "").replaceAll("\\r", "").replaceAll("\\s", ""); + return getEffectiveText(content); + } + + /** + * @return The given text without line breaks and whitespaces. Returns empty + * string ("") if the given text is null. + */ + public static String getEffectiveText(String text) { + if (text == null) + return ""; + return text.replaceAll("\\n", "").replaceAll("\\r", "").replaceAll("\\s", ""); } /** From 19401386b0941145f8e442405864e72cc93c73bd Mon Sep 17 00:00:00 2001 From: AlpTorac Date: Sun, 14 Sep 2025 15:35:25 +0200 Subject: [PATCH 72/72] Fix GSONTest The time measurement sample file touched by GIT had its line separator(s) replaced with the one for UNIX systems. This led to the parsed and re-serialised file in the tests to have slightly different contents (line separators). Solved by using FileUtil to get their effective content. --- .../fitests/repositorytests/GSONTest.java | 28 ++++++++++++++++--- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/GSONTest.java b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/GSONTest.java index 5dcb57bf8a..396c36889d 100644 --- a/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/GSONTest.java +++ b/commit-based-cipm/fi-tests/cipm.consistency.fitests.repositorytests/src/cipm/consistency/fitests/repositorytests/GSONTest.java @@ -11,6 +11,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import cipm.consistency.fitests.similarity.jamopp.parser.FileUtil; import cipm.consistency.fitests.similarity.jamopp.parser.timemeasurement.DefaultTimeMeasurementDataStructure; import cipm.consistency.fitests.similarity.jamopp.parser.timemeasurement.GSONLoadingStrategy; import cipm.consistency.fitests.similarity.jamopp.parser.timemeasurement.GSONPersistingStrategy; @@ -163,11 +164,30 @@ public void testSavedDataStructureLoading_ContentEquality() { this.persistTimeMeasurement(formerTimeMeasurements, newTimeMeasurementPath); var newFileContent = this.readTimeMeasurement(newTimeMeasurementPath); - // Enable if GSON serialises Long instances with trailing zeroes (".0") - // newFileContent = newFileContent.replaceAll("\\.0,", ","); - // Ensure that serialising produces the same file - Assertions.assertEquals(formerFileContent, newFileContent); + /* + * Remove redundant training zeroes comparing to address cases, where GSON + * serialises Long instances as Double instances, i.e. with trailing zeroes + * (".0"). + * + * Make sure to match the comma after the trailing zero too, so that start and + * end times are not affected, as their formatting may include decimal numbers. + */ + newFileContent = newFileContent.replaceAll("\\.0,", ","); + + /* + * Ensure that serialising produces the same file + * + * Remove all white-spaces from the read file content to avoid cross-platform + * issues, especially due to the differing line separators. + * + * This is particularly important, if the time measurement sample file at + * gsonTestResourceRootPath is included into the GIT repository, as GIT may + * replace existing line separators with the one for UNIX systems or add a line + * break to the end of the file. + */ + Assertions.assertEquals(FileUtil.getEffectiveText(formerFileContent), + FileUtil.getEffectiveText(newFileContent)); var newTimeMeasurements = this.loadTimeMeasurement(newTimeMeasurementPath);