diff --git a/de.tubs.variantsync.core/pom.xml b/de.tubs.variantsync.core/pom.xml index b69f88b..0d8aecc 100644 --- a/de.tubs.variantsync.core/pom.xml +++ b/de.tubs.variantsync.core/pom.xml @@ -6,10 +6,11 @@ de.tubs.variantsync de.tubs.variantsync 0.0.3-SNAPSHOT + ../pom.xml de.tubs.variantsync.core eclipse-plugin de.tubs.variantsync.core - \ No newline at end of file + diff --git a/de.tubs.variantsync.core/src/de/tubs/variantsync/core/VariantSyncPlugin.java b/de.tubs.variantsync.core/src/de/tubs/variantsync/core/VariantSyncPlugin.java index b225291..1408770 100644 --- a/de.tubs.variantsync.core/src/de/tubs/variantsync/core/VariantSyncPlugin.java +++ b/de.tubs.variantsync.core/src/de/tubs/variantsync/core/VariantSyncPlugin.java @@ -197,11 +197,12 @@ public void listenForActiveClass() { } public static void addNature(IProject project) { - final VariantSyncProgressMonitor progressMonitor = new VariantSyncProgressMonitor("Adding VariantSync nature to " + project.getName()); + final VariantSyncProgressMonitor progressMonitor = new VariantSyncProgressMonitor(String.format("Adding VariantSync nature to %s", project.getName())); try { final IProjectDescription description = project.getDescription(); final String[] natures = description.getNatureIds(); + // the natures array is copied to a newNatures array, in which the variant NATURE_ID is added as first element final String[] newNatures = new String[natures.length + 1]; System.arraycopy(natures, 0, newNatures, 1, natures.length); diff --git a/de.tubs.variantsync.core/src/de/tubs/variantsync/core/exceptions/ProjectNotFoundException.java b/de.tubs.variantsync.core/src/de/tubs/variantsync/core/exceptions/ProjectNotFoundException.java index b80263f..fd095d9 100644 --- a/de.tubs.variantsync.core/src/de/tubs/variantsync/core/exceptions/ProjectNotFoundException.java +++ b/de.tubs.variantsync.core/src/de/tubs/variantsync/core/exceptions/ProjectNotFoundException.java @@ -25,7 +25,7 @@ public ProjectNotFoundException(Type type, String message) { @Override public String toString() { - return "A " + (type == Type.CONFIGURATION ? "configuration project" : "variant") + " does not exist in the workspace. " + getMessage(); + return String.format("A %s does not exist in the workspace. %s", (type == Type.CONFIGURATION ? "configuration project" : "variant"), getMessage()); } } diff --git a/de.tubs.variantsync.core/src/de/tubs/variantsync/core/managers/ConfigurationProjectManager.java b/de.tubs.variantsync.core/src/de/tubs/variantsync/core/managers/ConfigurationProjectManager.java index 45d0285..2553842 100644 --- a/de.tubs.variantsync.core/src/de/tubs/variantsync/core/managers/ConfigurationProjectManager.java +++ b/de.tubs.variantsync.core/src/de/tubs/variantsync/core/managers/ConfigurationProjectManager.java @@ -106,7 +106,7 @@ private List findConfigurationProjects() { for (final IFeatureProject project : CorePlugin.getFeatureProjects()) { // System.out.print(" project " + project.getProjectName()); if (project.getComposerID().equals("de.tubs.variantsync.core.composer")) { - LogOperations.logInfo("Found configuration project with name: " + project.getProjectName()); + LogOperations.logInfo(String.format("Found configuration project with name: %s", project.getProjectName())); projects.add(project); // System.out.println(" is variant composing"); } else { @@ -126,7 +126,7 @@ private void findVariants(ConfigurationProject configurationProject) { } else { try { final IMarker m = file.createMarker("de.tubs.variantsync.marker.error"); - m.setAttribute(IMarker.MESSAGE, "Project " + projectName + " is missing in the workspace"); + m.setAttribute(IMarker.MESSAGE, String.format("Project %s is missing in the workspace", projectName)); m.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_WARNING); m.setAttribute(IMarker.PRIORITY, IMarker.PRIORITY_HIGH); m.setAttribute(IMarker.LINE_NUMBER, 0); @@ -176,9 +176,9 @@ public ConfigurationProject getActiveConfigurationProject() { public void propertyChange(FeatureIDEEvent event) { switch (event.getEventType()) { case FEATURE_ADD: - LogOperations.logInfo("Feature added: " + event); + LogOperations.logInfo(String.format("Feature added: %s", event)); case MODEL_DATA_SAVED: - LogOperations.logInfo("Model Event" + event); + LogOperations.logInfo(String.format("Model Event %s", event)); if (event.getSource() instanceof IFeatureModel) { final IFeatureModel model = (IFeatureModel) event.getSource(); final List featureExpressions = getActiveConfigurationProject().getFeatureContextManager().getContextsAsStrings(); diff --git a/de.tubs.variantsync.core/src/de/tubs/variantsync/core/managers/data/ConfigurationProject.java b/de.tubs.variantsync.core/src/de/tubs/variantsync/core/managers/data/ConfigurationProject.java index 2c926ab..bca2fe0 100644 --- a/de.tubs.variantsync.core/src/de/tubs/variantsync/core/managers/data/ConfigurationProject.java +++ b/de.tubs.variantsync.core/src/de/tubs/variantsync/core/managers/data/ConfigurationProject.java @@ -38,7 +38,7 @@ public class ConfigurationProject extends AManager implements ISaveableManager { private List projects = new ArrayList<>(); public IFeatureProject getFeatureProject() { - if(configurationProject != null && configurationProject.getProject().exists()) { + if ((configurationProject != null) && configurationProject.getProject().exists()) { return configurationProject; } @@ -85,8 +85,8 @@ public Configuration getConfigurationForVariant(IProject project) { final IFile configPath = (IFile) EclipseFileSystem.getResource(confPath); final String configFileName = configPath.getName(); final String configName = configFileName.substring(0, configFileName.lastIndexOf('.')); - System.out.println("[ConfigurationProject.getConfigurationForVariant] Check name equality Project(" + project.getName() + ") with Config(" - + configName + ")"); + System.out.println(String.format("[ConfigurationProject.getConfigurationForVariant] Check name equality Project(%s) with Config(%s)", + project.getName(), configName)); if (configName.equals(project.getName())) { final ConfigurationManager configurationManager = ConfigurationManager.getInstance(Paths.get(configPath.getRawLocationURI())); if (configurationManager != null) { diff --git a/de.tubs.variantsync.core/src/de/tubs/variantsync/core/managers/data/FeatureContext.java b/de.tubs.variantsync.core/src/de/tubs/variantsync/core/managers/data/FeatureContext.java index 7bb7cc9..bc44fa5 100644 --- a/de.tubs.variantsync.core/src/de/tubs/variantsync/core/managers/data/FeatureContext.java +++ b/de.tubs.variantsync.core/src/de/tubs/variantsync/core/managers/data/FeatureContext.java @@ -25,6 +25,7 @@ public FeatureContext(String name, FeatureColor highlighter) { } public boolean isComposed() { + // if the name contains one of the operators "or", "and" or "not" in its middle, the FeatureContext is supposed to be composed return name.matches(".*(or|and|not).*"); } diff --git a/de.tubs.variantsync.core/src/de/tubs/variantsync/core/managers/persistence/CodeMappingFormat.java b/de.tubs.variantsync.core/src/de/tubs/variantsync/core/managers/persistence/CodeMappingFormat.java index ea80e0a..ca541c6 100644 --- a/de.tubs.variantsync.core/src/de/tubs/variantsync/core/managers/persistence/CodeMappingFormat.java +++ b/de.tubs.variantsync.core/src/de/tubs/variantsync/core/managers/persistence/CodeMappingFormat.java @@ -25,7 +25,8 @@ public class CodeMappingFormat extends AXMLFormat> { private static final String MAPPINGS = "Mappings"; private static final String SOURCEFILE = "SourceFile"; private static final String CODEMAPPINGS = "CodeMapping"; - private static final Pattern CONTENT_REGEX = Pattern.compile("\\A\\s*(<[?]xml\\s.*[?]>\\s*)?<" + MAPPINGS + "[\\s>]"); + + private static final Pattern CONTENT_REGEX = XMLFormatHelper.createContentRegex(MAPPINGS); public static final String FILENAME = ".mapping.xml"; @@ -108,5 +109,4 @@ public boolean supportsContent(CharSequence content) { public String getName() { return "CodeMapping"; } - } diff --git a/de.tubs.variantsync.core/src/de/tubs/variantsync/core/managers/persistence/FeatureContextFormat.java b/de.tubs.variantsync.core/src/de/tubs/variantsync/core/managers/persistence/FeatureContextFormat.java index b5013c0..137caaf 100644 --- a/de.tubs.variantsync.core/src/de/tubs/variantsync/core/managers/persistence/FeatureContextFormat.java +++ b/de.tubs.variantsync.core/src/de/tubs/variantsync/core/managers/persistence/FeatureContextFormat.java @@ -18,7 +18,8 @@ public class FeatureContextFormat extends AXMLFormat> { private static final String ID = "FeatureContexts"; private static final String FEATURE_CONTEXTS = "contexts"; private static final String FEATURE_CONTEXT = "context"; - private static final Pattern CONTENT_REGEX = Pattern.compile("\\A\\s*(<[?]xml\\s.*[?]>\\s*)?<" + FEATURE_CONTEXTS + "[\\s>]"); + + private static final Pattern CONTENT_REGEX = XMLFormatHelper.createContentRegex(FEATURE_CONTEXTS); public static final String FILENAME = ".contexts.xml"; diff --git a/de.tubs.variantsync.core/src/de/tubs/variantsync/core/managers/persistence/PatchFormat.java b/de.tubs.variantsync.core/src/de/tubs/variantsync/core/managers/persistence/PatchFormat.java index 9609a27..3dca493 100644 --- a/de.tubs.variantsync.core/src/de/tubs/variantsync/core/managers/persistence/PatchFormat.java +++ b/de.tubs.variantsync.core/src/de/tubs/variantsync/core/managers/persistence/PatchFormat.java @@ -33,7 +33,8 @@ public class PatchFormat extends AXMLFormat>> { private static final String PATCHES = "Patches"; private static final String PATCH = "Patch"; private static final String DELTA = "Delta"; - private static final Pattern CONTENT_REGEX = Pattern.compile("\\A\\s*(<[?]xml\\s.*[?]>\\s*)?<" + PATCHES + "[\\s>]"); + + private static final Pattern CONTENT_REGEX = XMLFormatHelper.createContentRegex(PATCHES); public static final String FILENAME = ".patches.xml"; diff --git a/de.tubs.variantsync.core/src/de/tubs/variantsync/core/managers/persistence/XMLFormatHelper.java b/de.tubs.variantsync.core/src/de/tubs/variantsync/core/managers/persistence/XMLFormatHelper.java new file mode 100644 index 0000000..8067b83 --- /dev/null +++ b/de.tubs.variantsync.core/src/de/tubs/variantsync/core/managers/persistence/XMLFormatHelper.java @@ -0,0 +1,12 @@ +package de.tubs.variantsync.core.managers.persistence; + +import java.util.regex.Pattern; + +public class XMLFormatHelper { + + // the xml pattern should start with an optional standard xml-starting line (e.g. ) + // followed by an xml tag starting with the content string + public static Pattern createContentRegex(String content) { + return Pattern.compile("\\A\\s*(<[?]xml\\s.*[?]>\\s*)?<" + content + "[\\s>]"); + } +} diff --git a/de.tubs.variantsync.core/src/de/tubs/variantsync/core/nature/CreateVariantProject.java b/de.tubs.variantsync.core/src/de/tubs/variantsync/core/nature/CreateVariantProject.java index 3f1c619..16ef304 100644 --- a/de.tubs.variantsync.core/src/de/tubs/variantsync/core/nature/CreateVariantProject.java +++ b/de.tubs.variantsync.core/src/de/tubs/variantsync/core/nature/CreateVariantProject.java @@ -53,7 +53,7 @@ public Object execute(ExecutionEvent event) throws ExecutionException { } private IProject createJavaProjectWithVariantNature(String projectName) { - final VariantSyncProgressMonitor progressMonitor = new VariantSyncProgressMonitor("Create Project " + projectName); + final VariantSyncProgressMonitor progressMonitor = new VariantSyncProgressMonitor(String.format("Create Project %s", projectName)); // create project final IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); final IProject project = root.getProject(projectName); diff --git a/de.tubs.variantsync.core/src/de/tubs/variantsync/core/patch/APatch.java b/de.tubs.variantsync.core/src/de/tubs/variantsync/core/patch/APatch.java index 71102f4..4ed46bf 100644 --- a/de.tubs.variantsync.core/src/de/tubs/variantsync/core/patch/APatch.java +++ b/de.tubs.variantsync.core/src/de/tubs/variantsync/core/patch/APatch.java @@ -64,7 +64,7 @@ public boolean isEmpty() { @Override public String toString() { - return "APatch [deltas=" + deltas + "]"; + return String.format("APatch [deltas= %s ]", deltas); } @Override diff --git a/de.tubs.variantsync.core/src/de/tubs/variantsync/core/patch/DeltaFactoryManager.java b/de.tubs.variantsync.core/src/de/tubs/variantsync/core/patch/DeltaFactoryManager.java index a491f96..fe12a1d 100644 --- a/de.tubs.variantsync.core/src/de/tubs/variantsync/core/patch/DeltaFactoryManager.java +++ b/de.tubs.variantsync.core/src/de/tubs/variantsync/core/patch/DeltaFactoryManager.java @@ -115,8 +115,8 @@ public IDeltaFactory getExtension(String id) throws NoSuchExtensionException { return extension; } } - StringBuilder errorMsg = new StringBuilder("No extension found for ID ").append(id); - throw new NoSuchExtensionException(errorMsg.toString()); + final String errorMsg = String.format("No extension found for ID %s", id); + throw new NoSuchExtensionException(errorMsg); } } diff --git a/de.tubs.variantsync.core/src/de/tubs/variantsync/core/patch/base/DefaultDelta.java b/de.tubs.variantsync.core/src/de/tubs/variantsync/core/patch/base/DefaultDelta.java index 7e1c752..6af8f01 100644 --- a/de.tubs.variantsync.core/src/de/tubs/variantsync/core/patch/base/DefaultDelta.java +++ b/de.tubs.variantsync.core/src/de/tubs/variantsync/core/patch/base/DefaultDelta.java @@ -21,27 +21,29 @@ public DefaultDelta(IFile res, long timestamp, String factoryId) { @Override public String getOriginalAsString() { - String ret = String.valueOf(original.getPosition()); - ret = ret + ":;:"; + StringBuilder ret = new StringBuilder(String.valueOf(original.getPosition())); + ret.append(":;:"); for (final String line : original.getLines()) { - ret = ret + line + "#:#"; + ret.append(line); + ret.append("#:#"); } - ret = ret.substring(0, ret.lastIndexOf("#:#")); - ret = ret + ":;:"; + ret = new StringBuilder(ret.substring(0, ret.lastIndexOf("#:#"))); + ret.append(":;:"); for (final String bLine : original.getBefore()) { - ret = ret + bLine + "#:#"; + ret.append(bLine); + ret.append("#:#"); } - ret = ret.substring(0, ret.lastIndexOf("#:#")); - ret = ret + ":;:"; + ret = new StringBuilder(ret.substring(0, ret.lastIndexOf("#:#"))); + ret.append(":;:"); for (final String aLine : original.getAfter()) { - ret = ret + aLine + "#:#"; + ret.append(aLine); + ret.append("#:#"); } - ret = ret.substring(0, ret.lastIndexOf("#:#")); - return ret; + return ret.substring(0, ret.lastIndexOf("#:#")); } @Override @@ -58,33 +60,36 @@ public void setOriginalFromString(String original) { @Override public String getRevisedAsString() { - String ret = String.valueOf(revised.getPosition()); - ret = ret + ":;:"; + StringBuilder ret = new StringBuilder(String.valueOf(revised.getPosition())); + ret.append(":;:"); for (final String line : revised.getLines()) { - ret = ret + line + "#:#"; + ret.append(line); + ret.append("#:#"); } if (!revised.getLines().isEmpty()) { - ret = ret.substring(0, ret.lastIndexOf("#:#")); + ret = new StringBuilder(ret.substring(0, ret.lastIndexOf("#:#"))); } - ret = ret + ":;:"; + ret.append(":;:"); for (final String bLine : revised.getBefore()) { - ret = ret + bLine + "#:#"; + ret.append(bLine); + ret.append("#:#"); } if (!revised.getBefore().isEmpty()) { - ret = ret.substring(0, ret.lastIndexOf("#:#")); + ret = new StringBuilder(ret.substring(0, ret.lastIndexOf("#:#"))); } - ret = ret + ":;:"; + ret.append(":;:"); for (final String aLine : revised.getAfter()) { - ret = ret + aLine + "#:#"; + ret.append(aLine); + ret.append("#:#"); } if (!revised.getAfter().isEmpty()) { - ret = ret.substring(0, ret.lastIndexOf("#:#")); + ret = new StringBuilder(ret.substring(0, ret.lastIndexOf("#:#"))); } - return ret; + return ret.toString(); } @Override @@ -101,7 +106,7 @@ public void setRevisedFromString(String revised) { @Override public String getRepresentation() { - return "--- (" + original.getPosition() + ") " + original.getLines() + "\n" + "+++ (" + revised.getPosition() + ") " + revised.getLines(); + return String.format("--- (%s) %s%n+++ (%s) %s", original.getPosition(), original.getLines(), revised.getPosition(), revised.getLines()); } @Override diff --git a/de.tubs.variantsync.core/src/de/tubs/variantsync/core/patch/base/DefaultDeltaFactory.java b/de.tubs.variantsync.core/src/de/tubs/variantsync/core/patch/base/DefaultDeltaFactory.java index 26bd0a1..d3be9aa 100644 --- a/de.tubs.variantsync.core/src/de/tubs/variantsync/core/patch/base/DefaultDeltaFactory.java +++ b/de.tubs.variantsync.core/src/de/tubs/variantsync/core/patch/base/DefaultDeltaFactory.java @@ -52,7 +52,7 @@ public static IDeltaFactory getInstance() { @Override public String toString() { - return "DefaultDeltaFactory [getId()=" + getId() + ", getName()=" + getName() + "]"; + return String.format("DefaultDeltaFactory [getId()=%s, getName()=%s]", getId(), getName()); } @Override diff --git a/de.tubs.variantsync.core/src/de/tubs/variantsync/core/patch/base/DefaultMarkerHandler.java b/de.tubs.variantsync.core/src/de/tubs/variantsync/core/patch/base/DefaultMarkerHandler.java index db46718..1e74da1 100644 --- a/de.tubs.variantsync.core/src/de/tubs/variantsync/core/patch/base/DefaultMarkerHandler.java +++ b/de.tubs.variantsync.core/src/de/tubs/variantsync/core/patch/base/DefaultMarkerHandler.java @@ -25,6 +25,8 @@ public List getMarkersForDeltas(IFile file, List variantSyncMarkers = new ArrayList<>(); for (final IDelta> delta : deltas) { final Chunk revised = delta.getRevised(); + // For the display of markers, the utilities.MarkerUtils.setMarker-method uses Editor/Document-information provided by IDocument. + // IDocument is 0-based (so the first line is line 0 in IDocument), which means that every line number has to be reduced by 1 final IVariantSyncMarker variantSyncMarker = new AMarkerInformation(revised.getPosition() - 1, revised.getLines().size() - 1, true); variantSyncMarker.setContext(delta.getContext()); variantSyncMarkers.add(variantSyncMarker); diff --git a/de.tubs.variantsync.core/src/de/tubs/variantsync/core/patch/base/DefaultPatchFactory.java b/de.tubs.variantsync.core/src/de/tubs/variantsync/core/patch/base/DefaultPatchFactory.java index 45b23db..e7543c8 100644 --- a/de.tubs.variantsync.core/src/de/tubs/variantsync/core/patch/base/DefaultPatchFactory.java +++ b/de.tubs.variantsync.core/src/de/tubs/variantsync/core/patch/base/DefaultPatchFactory.java @@ -36,7 +36,7 @@ public IFile applyDelta(IFile file, IPatch patch) { final IDeltaFactory factory = DeltaFactoryManager.getFactoryById(delta.getFactoryId()); newFile = factory.applyDelta(newFile, delta); } catch (final NoSuchExtensionException e) { - LogOperations.logError("Could not find extension with id: " + delta.getFactoryId(), e); + LogOperations.logError(String.format("Could not find extension with id: %s", delta.getFactoryId()), e); } } return newFile; diff --git a/de.tubs.variantsync.core/src/de/tubs/variantsync/core/syncronization/ResourceCompareInput.java b/de.tubs.variantsync.core/src/de/tubs/variantsync/core/syncronization/ResourceCompareInput.java index 605d2c0..544c03a 100644 --- a/de.tubs.variantsync.core/src/de/tubs/variantsync/core/syncronization/ResourceCompareInput.java +++ b/de.tubs.variantsync.core/src/de/tubs/variantsync/core/syncronization/ResourceCompareInput.java @@ -68,7 +68,7 @@ class MyDiffNode extends DiffNode { @Override public String toString() { - return "MyDiffNode [fDirty=" + fDirty + ", fLastId=" + fLastId + ", fLastName=" + fLastName + "]"; + return String.format("MyDiffNode [fDirty=%s, fLastId=%s, fLastName=%s]", fDirty, fLastId, fLastName); } private boolean fDirty = false; @@ -99,7 +99,7 @@ public String getName() { fLastName = super.getName(); } if (fDirty) { - return '<' + fLastName + '>'; + return String.format("<%s>", fLastName); } return fLastName; } diff --git a/de.tubs.variantsync.core/src/de/tubs/variantsync/core/syncronization/compare/DeltaCompareViewer.java b/de.tubs.variantsync.core/src/de/tubs/variantsync/core/syncronization/compare/DeltaCompareViewer.java index 3e4465d..5b96392 100644 --- a/de.tubs.variantsync.core/src/de/tubs/variantsync/core/syncronization/compare/DeltaCompareViewer.java +++ b/de.tubs.variantsync.core/src/de/tubs/variantsync/core/syncronization/compare/DeltaCompareViewer.java @@ -17,7 +17,7 @@ @Deprecated public class DeltaCompareViewer extends Wizard { - public static final String ID = VariantSyncPlugin.PLUGIN_ID + ".views.synchronization.compare"; + public static final String ID = String.format("%s.views.synchronization.compare", VariantSyncPlugin.PLUGIN_ID); private final DeltaCompareViewerPage page; private final IFile file; private final IDelta delta; diff --git a/de.tubs.variantsync.core/src/de/tubs/variantsync/core/syncronization/compare/DeltaCompareViewerPage.java b/de.tubs.variantsync.core/src/de/tubs/variantsync/core/syncronization/compare/DeltaCompareViewerPage.java index 8d59169..6ec2ab1 100644 --- a/de.tubs.variantsync.core/src/de/tubs/variantsync/core/syncronization/compare/DeltaCompareViewerPage.java +++ b/de.tubs.variantsync.core/src/de/tubs/variantsync/core/syncronization/compare/DeltaCompareViewerPage.java @@ -75,13 +75,13 @@ public void createControl(Composite parent) { } public List getSourceCode() { - return Arrays.asList(sourceViewer.getDocument().get().split("\n")); + return Arrays.asList(sourceViewer.getDocument().get().split(String.format("%n"))); } private String getStringFromList(List entries) { String str = ""; for (final String el : entries) { - str += el + "\n"; + str += String.format("%s%n", el); } return str; } diff --git a/de.tubs.variantsync.core/src/de/tubs/variantsync/core/utilities/MarkerUtils.java b/de.tubs.variantsync.core/src/de/tubs/variantsync/core/utilities/MarkerUtils.java index 2358fb9..8b1361b 100644 --- a/de.tubs.variantsync.core/src/de/tubs/variantsync/core/utilities/MarkerUtils.java +++ b/de.tubs.variantsync.core/src/de/tubs/variantsync/core/utilities/MarkerUtils.java @@ -139,7 +139,7 @@ private static long addMarker(IResource res, int posStart, int posEnd, FeatureCo IMarker marker = null; if (res.exists()) { marker = res.createMarker(getMarker(featureContext.highlighter)); - marker.setAttribute(IMarker.MESSAGE, "Feature: " + featureContext.name); + marker.setAttribute(IMarker.MESSAGE, String.format("Feature: %s", featureContext.name)); marker.setAttribute(IMarker.CHAR_START, posStart); marker.setAttribute(IMarker.CHAR_END, posEnd); return marker.getId(); diff --git a/de.tubs.variantsync.core/src/de/tubs/variantsync/core/utilities/PerspectiveFactory.java b/de.tubs.variantsync.core/src/de/tubs/variantsync/core/utilities/PerspectiveFactory.java index 08df5c3..2cbe9ca 100644 --- a/de.tubs.variantsync.core/src/de/tubs/variantsync/core/utilities/PerspectiveFactory.java +++ b/de.tubs.variantsync.core/src/de/tubs/variantsync/core/utilities/PerspectiveFactory.java @@ -19,7 +19,7 @@ */ public class PerspectiveFactory implements IPerspectiveFactory { - public static final String ID = VariantSyncPlugin.PLUGIN_ID + ".perspective"; + public static final String ID = String.format("%s.perspective", VariantSyncPlugin.PLUGIN_ID); @Override public void createInitialLayout(IPageLayout layout) { diff --git a/de.tubs.variantsync.core/src/de/tubs/variantsync/core/utilities/Tree.java b/de.tubs.variantsync.core/src/de/tubs/variantsync/core/utilities/Tree.java index 8c0117e..293dcac 100644 --- a/de.tubs.variantsync.core/src/de/tubs/variantsync/core/utilities/Tree.java +++ b/de.tubs.variantsync.core/src/de/tubs/variantsync/core/utilities/Tree.java @@ -99,10 +99,10 @@ public String toString() { if (root != null) { int i = 0; TreeNode currentNode = root; - String ret = root.toString() + "\n"; + String ret = String.format("%s%n", root.toString()); while ((currentNode == null) && (i < currentNode.getNumberOfChildren())) { currentNode = currentNode.getChildAt(i); - ret = ret + currentNode.toString() + "\n"; + ret += String.format("%s%n", currentNode.toString()); i++; } return ret; diff --git a/de.tubs.variantsync.core/src/de/tubs/variantsync/core/utilities/event/VariantSyncEvent.java b/de.tubs.variantsync.core/src/de/tubs/variantsync/core/utilities/event/VariantSyncEvent.java index 57832df..36a55be 100644 --- a/de.tubs.variantsync.core/src/de/tubs/variantsync/core/utilities/event/VariantSyncEvent.java +++ b/de.tubs.variantsync.core/src/de/tubs/variantsync/core/utilities/event/VariantSyncEvent.java @@ -143,7 +143,7 @@ public Object getNewValue() { @Override public String toString() { - return "VariantSyncEvent [source=" + source + ", eventType=" + eventType + ", oldValue=" + oldValue + ", newValue=" + newValue + "]"; + return String.format("VariantSyncEvent [source=%s, eventType=%s, oldValue=%s, newValue=%s]", source, eventType, oldValue, newValue); } } diff --git a/de.tubs.variantsync.core/src/de/tubs/variantsync/core/view/editor/PartAdapter.java b/de.tubs.variantsync.core/src/de/tubs/variantsync/core/view/editor/PartAdapter.java index 3a3656a..33711ca 100644 --- a/de.tubs.variantsync.core/src/de/tubs/variantsync/core/view/editor/PartAdapter.java +++ b/de.tubs.variantsync.core/src/de/tubs/variantsync/core/view/editor/PartAdapter.java @@ -117,7 +117,7 @@ public IStatus runInUIThread(IProgressMonitor monitor) { try { MarkerUtils.cleanResource(currentFile); } catch (final CoreException e) { - LogOperations.logError("Cannot clear all markers from: " + currentFile.getFullPath(), e); + LogOperations.logError(String.format("Cannot clear all markers from: %s", currentFile.getFullPath()), e); } final ConfigurationProject configurationProject = VariantSyncPlugin.getActiveConfigurationProject(); diff --git a/de.tubs.variantsync.core/src/de/tubs/variantsync/core/view/featurecontext/FeatureContextManager.java b/de.tubs.variantsync.core/src/de/tubs/variantsync/core/view/featurecontext/FeatureContextManager.java index 4900fc4..49b0132 100644 --- a/de.tubs.variantsync.core/src/de/tubs/variantsync/core/view/featurecontext/FeatureContextManager.java +++ b/de.tubs.variantsync.core/src/de/tubs/variantsync/core/view/featurecontext/FeatureContextManager.java @@ -14,7 +14,7 @@ */ public class FeatureContextManager extends Wizard { - public static final String ID = VariantSyncPlugin.PLUGIN_ID + ".views.featurecontexts.manage"; + public static final String ID = String.format("%s.views.featurecontexts.manage", VariantSyncPlugin.PLUGIN_ID); private final List expressions; diff --git a/de.tubs.variantsync.core/src/de/tubs/variantsync/core/view/featurecontext/FeatureContextWizard.java b/de.tubs.variantsync.core/src/de/tubs/variantsync/core/view/featurecontext/FeatureContextWizard.java index 3013b78..ddb628a 100644 --- a/de.tubs.variantsync.core/src/de/tubs/variantsync/core/view/featurecontext/FeatureContextWizard.java +++ b/de.tubs.variantsync.core/src/de/tubs/variantsync/core/view/featurecontext/FeatureContextWizard.java @@ -19,7 +19,7 @@ */ public class FeatureContextWizard extends Wizard { - public static final String ID = VariantSyncPlugin.PLUGIN_ID + ".views.featurecontexts.wizard"; + public static final String ID = String.format("%s.views.featurecontexts.wizard", VariantSyncPlugin.PLUGIN_ID); private final Iterable features; private FeatureContext featureContext = null; diff --git a/de.tubs.variantsync.core/src/de/tubs/variantsync/core/view/featurecontext/FeatureContextWizardPage.java b/de.tubs.variantsync.core/src/de/tubs/variantsync/core/view/featurecontext/FeatureContextWizardPage.java index f4b4e98..73863bd 100644 --- a/de.tubs.variantsync.core/src/de/tubs/variantsync/core/view/featurecontext/FeatureContextWizardPage.java +++ b/de.tubs.variantsync.core/src/de/tubs/variantsync/core/view/featurecontext/FeatureContextWizardPage.java @@ -147,12 +147,19 @@ public void handleEvent(Event event) { final TableItem[] selectedItem = tabFeatures.getTable().getSelection(); if (selectedItem.length > 0) { String featureName = selectedItem[0].getText(); + // if the featureName is of the following structure: + // arbitrary amount of chars until the first occurence of 1 or more consecutive spaces followed by an arbitrary amount of chars + // so, if the featureName contains 1 or more spaces, it is surrounded by double quotes because the space character is needed to put features + // together by operators like "and" or "or" + // this might be a relict of previous versions because it is currently not even possible to add new features to the feature model which + // contain a space character in the middle if (featureName.matches(".*?\\s+.*")) { - featureName = "\"" + featureName + "\""; + featureName = String.format("\"%s\"", featureName); } else { + // if the featureName equals one of the operator names, it is also surrounded by double quotes for the reasons mentioned above for (final String op : Operator.NAMES) { if (featureName.equalsIgnoreCase(op)) { - featureName = "\"" + featureName + "\""; + featureName = String.format("\"%s\"", featureName); break; } } diff --git a/de.tubs.variantsync.core/src/de/tubs/variantsync/core/view/featurecontext/View.java b/de.tubs.variantsync.core/src/de/tubs/variantsync/core/view/featurecontext/View.java index ad07718..5bc3e2b 100644 --- a/de.tubs.variantsync.core/src/de/tubs/variantsync/core/view/featurecontext/View.java +++ b/de.tubs.variantsync.core/src/de/tubs/variantsync/core/view/featurecontext/View.java @@ -39,7 +39,7 @@ */ public class View extends ViewPart implements IEventListener { - public static final String ID = VariantSyncPlugin.PLUGIN_ID + ".views.featurecontexts"; + public static final String ID = String.format("%s.views.featurecontexts", VariantSyncPlugin.PLUGIN_ID); private List expressions; diff --git a/de.tubs.variantsync.core/src/de/tubs/variantsync/core/view/resourcechanges/ResourceChangesColumnLabelProvider.java b/de.tubs.variantsync.core/src/de/tubs/variantsync/core/view/resourcechanges/ResourceChangesColumnLabelProvider.java index 059e9a7..a495b05 100644 --- a/de.tubs.variantsync.core/src/de/tubs/variantsync/core/view/resourcechanges/ResourceChangesColumnLabelProvider.java +++ b/de.tubs.variantsync.core/src/de/tubs/variantsync/core/view/resourcechanges/ResourceChangesColumnLabelProvider.java @@ -73,9 +73,11 @@ public void update(ViewerCell cell) { if (o instanceof IDelta) { String projects = ""; for (final IProject project : ((IDelta) o).getSynchronizedProjects()) { - projects += project.getName() + ", "; + projects += String.format("%s, ", project.getName()); + } + if (projects.lastIndexOf(",") != -1) { + projects = projects.substring(0, projects.lastIndexOf(",")); } - projects = projects.lastIndexOf(",") == -1 ? projects : projects.substring(0, projects.lastIndexOf(",")); cell.setText(projects); } break; @@ -83,9 +85,11 @@ public void update(ViewerCell cell) { if (o instanceof IDelta) { String projects = ""; for (final IProject project : targetsCalculator.getTargetsWithConflict(((IDelta) o))) { - projects += project.getName() + ", "; + projects += String.format("%s, ", project.getName()); + } + if (projects.lastIndexOf(",") != -1) { + projects = projects.substring(0, projects.lastIndexOf(",")); } - projects = projects.lastIndexOf(",") == -1 ? projects : projects.substring(0, projects.lastIndexOf(",")); cell.setText(projects); } break; @@ -93,9 +97,11 @@ public void update(ViewerCell cell) { if (o instanceof IDelta) { String projects = ""; for (final IProject project : targetsCalculator.getTargetsWithoutConflict(((IDelta) o))) { - projects += project.getName() + ", "; + projects += String.format("%s, ", project.getName()); + } + if (projects.lastIndexOf(",") != -1) { + projects = projects.substring(0, projects.lastIndexOf(",")); } - projects = projects.lastIndexOf(",") == -1 ? projects : projects.substring(0, projects.lastIndexOf(",")); cell.setText(projects); } break; diff --git a/de.tubs.variantsync.core/src/de/tubs/variantsync/core/view/resourcechanges/View.java b/de.tubs.variantsync.core/src/de/tubs/variantsync/core/view/resourcechanges/View.java index e54ea43..4c458ae 100644 --- a/de.tubs.variantsync.core/src/de/tubs/variantsync/core/view/resourcechanges/View.java +++ b/de.tubs.variantsync.core/src/de/tubs/variantsync/core/view/resourcechanges/View.java @@ -29,7 +29,7 @@ */ public class View extends ViewPart implements IEventListener { - public static final String ID = VariantSyncPlugin.PLUGIN_ID + ".views.resourcechanges"; + public static final String ID = String.format("%s.views.resourcechanges", VariantSyncPlugin.PLUGIN_ID); private TreeViewer tvResourceChanges; public View() { diff --git a/de.tubs.variantsync.core/src/de/tubs/variantsync/core/view/sourcefocus/View.java b/de.tubs.variantsync.core/src/de/tubs/variantsync/core/view/sourcefocus/View.java index dc3f27e..56127b0 100644 --- a/de.tubs.variantsync.core/src/de/tubs/variantsync/core/view/sourcefocus/View.java +++ b/de.tubs.variantsync.core/src/de/tubs/variantsync/core/view/sourcefocus/View.java @@ -68,7 +68,7 @@ public void run() { } } - public static final String ID = VariantSyncPlugin.PLUGIN_ID + ".views.sourcefocus"; + public static final String ID = String.format("%s.views.sourcefocus", VariantSyncPlugin.PLUGIN_ID); private Combo cbFeature; private TreeViewer tvChanges; @@ -322,7 +322,11 @@ public void selectionChanged(SelectionChangedEvent event) { return; } lastSelections.add(delta); - ret += ret.isEmpty() ? delta.getRepresentation() : "\n\n" + delta.getRepresentation(); + if (ret.isEmpty()) { + ret += delta.getRepresentation(); + } else { + ret += String.format("%n%n%s", delta.getRepresentation()); + } } } lbChange.setDocument(new Document(ret)); diff --git a/de.tubs.variantsync.core/src/de/tubs/variantsync/core/view/targetfocus/View.java b/de.tubs.variantsync.core/src/de/tubs/variantsync/core/view/targetfocus/View.java index 0a1e54e..4ebcfdf 100644 --- a/de.tubs.variantsync.core/src/de/tubs/variantsync/core/view/targetfocus/View.java +++ b/de.tubs.variantsync.core/src/de/tubs/variantsync/core/view/targetfocus/View.java @@ -54,7 +54,7 @@ */ public class View extends ViewPart implements SelectionListener, ISelectionChangedListener, IEventListener { - public static final String ID = VariantSyncPlugin.PLUGIN_ID + ".views.targetfocus"; + public static final String ID = String.format("%s.views.targetfocus", VariantSyncPlugin.PLUGIN_ID); private Combo cbVariant; private TreeViewer tvChanges; @@ -275,7 +275,11 @@ public void selectionChanged(SelectionChangedEvent event) { return; } lastSelections.add(delta); - ret += ret.isEmpty() ? delta.getRepresentation() : "\n\n" + delta.getRepresentation(); + if (ret.isEmpty()) { + ret += delta.getRepresentation(); + } else { + ret += String.format("%n%n%s", delta.getRepresentation()); + } btnSync.setEnabled(true); } } diff --git a/de.variantsync.core/.classpath b/de.variantsync.core/.classpath new file mode 100644 index 0000000..fd1d061 --- /dev/null +++ b/de.variantsync.core/.classpath @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/de.variantsync.core/pom.xml b/de.variantsync.core/pom.xml new file mode 100644 index 0000000..5cfd5f5 --- /dev/null +++ b/de.variantsync.core/pom.xml @@ -0,0 +1,94 @@ + + + 4.0.0 + + de.tubs.variantsync + de.tubs.variantsync + 0.0.3-SNAPSHOT + + + de.tubs.variantsync + de.variantsync.core + 0.0.3-SNAPSHOT + + de.variantsync.core + + http://www.example.com + + + UTF-8 + + + + + junit + junit + 4.11 + test + + + com.google.code.gson + gson + 2.8.6 + compile + + + + + + + + + + + maven-clean-plugin + 3.1.0 + + + + maven-resources-plugin + 3.0.2 + + + maven-compiler-plugin + 3.8.0 + + + maven-surefire-plugin + 2.22.1 + + + maven-jar-plugin + 3.0.2 + + + maven-install-plugin + 2.5.2 + + + maven-deploy-plugin + 2.8.2 + + + + maven-site-plugin + 3.7.1 + + + maven-project-info-reports-plugin + 3.0.0 + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 11 + 11 + + + + + diff --git a/de.variantsync.core/src/main/java/de/variantsync/core/ast/AST.java b/de.variantsync.core/src/main/java/de/variantsync/core/ast/AST.java new file mode 100644 index 0000000..5e947f0 --- /dev/null +++ b/de.variantsync.core/src/main/java/de/variantsync/core/ast/AST.java @@ -0,0 +1,181 @@ +package de.variantsync.core.ast; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.UUID; + +import de.variantsync.core.interfaces.Grammar; + +/** + * This class represents the Abstract Syntax Tree data structure. + * + * @param a generic which needs to extend the Grammar class, defining the type of the AST + * @param a generic which defines the value of the actual AST + * @author eric + */ +public class AST, V> { + + private UUID id; + private G type; + private V value; + private List> subtrees; + + // all attributes which should not be visible to the GSON parser need to be at least transient + public static transient final String INDENT_STRING = " "; + public static transient final String NEXT_SEPARATOR = "\u2502 "; + public static transient final String NEXT_ACT_SEPARATOR = "\u251C\u2500 "; + public static transient final String LAST_SEPARATOR = "\u2514\u2500 "; + + public AST(UUID id, G type, V value) { + this.id = id; + this.type = type; + this.value = value; + this.subtrees = new ArrayList<>(); + } + + public AST(G type, V value) { + this(UUID.randomUUID(), type, value); + } + + /** + * Empty AST is forbidden at the moment. + */ + private AST() { + + } + + public UUID getId() { + return id; + } + + public V getValue() { + return value; + } + + public G getType() { + return type; + } + + /** + * @return the subtrees as an unmodifiable List + */ + public List> getSubtrees() { + return Collections.unmodifiableList(subtrees); + } + + public int getDepth() { + int maxDepth = 1; + if (subtrees.isEmpty()) { + return maxDepth; + } + + for (final AST node : subtrees) { + maxDepth = Math.max(node.getDepth(), maxDepth); + } + return ++maxDepth; + } + + /** + * This method calls the addChild method for each element of the given list. ASTs which would be rejected by the addChild method are skipped. + * + * @param toAdd List of AST which should be added as subtrees + * @return true if all items where successfully added + */ + public boolean addChildren(List> toAdd) { + boolean out = toAdd != null; + if (out) { + for (final AST elem : toAdd) { + if (!addChild(elem)) { + out = false; + } + } + } + return out; + } + + /** + * This method adds an element to the AST by checking its validity through the the Grammar G and assuring that the element is not null. + * + * @param toAdd Single AST which should be added as subtree + * @return true if the item was successfully added + */ + public boolean addChild(AST toAdd) { + if ((toAdd != null) && type.isValidChild(toAdd.type)) { + return subtrees.add(toAdd); + } + return false; + } + + public int size() { + int tmpSize = 1; + for (final AST act : subtrees) { + tmpSize += act.size(); + } + return tmpSize; + } + + /** + * This method returns only the most significant bits of the UUID, the type, value and subtree size as a String of the actual AST. + * + * @return UUID, Type, Value, subtree size as String + */ + @Override + public String toString() { + return String.format("[ Id: %d, Type: %s, Value: %s, Subtree-size: %d ]", id.getMostSignificantBits(), type.toString(), value.toString(), + subtrees.size()); + } + + /** + * This recursive method prints for each tree element the Grammar type, the Value and (for the sake of readability) only the most significant bits of the + * UUID. It returns the whole AST as human readable tree. + * + * @return AST as readable String + */ + public String printTree() { + final StringBuilder result = new StringBuilder(); + if (value != null) { + final int depth = 0; + + final HashSet levelFinished = new HashSet<>(); // determines if all subtrees of the actual tree on this depth have been drawn or not + final boolean isActualElementLastElement = false; + printTree(result, this, depth, levelFinished, isActualElementLastElement); + } + return result.toString(); + } + + private void printTree(StringBuilder result, AST parent, int depth, HashSet levelFinished, boolean isLast) { + // print enough INDENT_STRINGS and choose separator according to whether or not there are subtrees left + for (int i = 0; i < depth; i++) { + StringBuilder line = new StringBuilder(INDENT_STRING).append(NEXT_SEPARATOR); + if (levelFinished.contains(i)) { + // new depth indent + line = new StringBuilder(INDENT_STRING); + } + if (i == (depth - 1)) { + // make separator for next subtree and printing actual subtree fields + line = new StringBuilder(INDENT_STRING).append(NEXT_ACT_SEPARATOR); + if (isLast) { + // last subtree of parent tree, only print last separator for last subtree fields + line = new StringBuilder(INDENT_STRING).append(LAST_SEPARATOR); + } + } + result.append(line.toString()); + } + result.append(String.format("%s %s uuid: %d%n", parent.type, parent.value, parent.getId().getMostSignificantBits())); + depth++; + for (final AST child : parent.subtrees) { + isLast = false; + if (parent.subtrees.indexOf(child) == (parent.subtrees.size() - 1)) { + // reached last child of parent + levelFinished.add(depth - 1); + isLast = true; + } else if (parent.subtrees.indexOf(child) == 0) { + // first child of new sub tree with unfinished depth so it needs NEXT_SEPARATOR later + levelFinished.remove(depth - 1); + } + printTree(result, child, depth, levelFinished, isLast); + } + } +} diff --git a/de.variantsync.core/src/main/java/de/variantsync/core/ast/JsonParserASTWithLineGrammar.java b/de.variantsync.core/src/main/java/de/variantsync/core/ast/JsonParserASTWithLineGrammar.java new file mode 100644 index 0000000..815b057 --- /dev/null +++ b/de.variantsync.core/src/main/java/de/variantsync/core/ast/JsonParserASTWithLineGrammar.java @@ -0,0 +1,85 @@ +package de.variantsync.core.ast; + +import java.io.IOException; +import java.lang.reflect.Field; +import java.lang.reflect.Type; +import java.nio.file.Files; +import java.nio.file.Path; + +import com.google.gson.FieldNamingStrategy; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.reflect.TypeToken; + +/** + * + * Uses gson to import and export ASTs to and from json. A generic use of grammar is not possible, hence for each grammar a different class has to be created. + * In this case the used grammar is LineGrammar. + * + * @author Jeremia Heinle + * + */ +public class JsonParserASTWithLineGrammar { + + // json parser uses a custom policy to define the name of the field + // inside of the json + static FieldNamingStrategy customPolicy = new FieldNamingStrategy() { + + @Override + public String translateName(Field f) { + + switch (f.getName()) { + case "id": + return "uuid"; + case "type": + return "grammar_type"; + default: + return f.getName(); + } + } + + }; + + static Gson prettyStringGsonBuilder = new GsonBuilder().setPrettyPrinting().setFieldNamingStrategy(customPolicy).create(); + + public static String toJson(AST ast) { + + final Type type = new TypeToken>() {}.getType(); + + return prettyStringGsonBuilder.toJson(ast, type); + } + + public static AST toAST(String json) { + + final Type type = new TypeToken>() {}.getType(); + + return prettyStringGsonBuilder.fromJson(json, type); + } + + public static String exportAST(Path path, AST ast) { + + final String content = toJson(ast); + try { + Files.writeString(path, content); + } catch (final IOException e) { + e.printStackTrace(); + return null; + } + + return content; + } + + public static AST importAST(Path path) { + + String json = ""; + try { + json = Files.readString(path); + } catch (final IOException e) { + e.printStackTrace(); + return null; + } + + return toAST(json); + } + +} diff --git a/de.variantsync.core/src/main/java/de/variantsync/core/ast/LineBasedParser.java b/de.variantsync.core/src/main/java/de/variantsync/core/ast/LineBasedParser.java new file mode 100644 index 0000000..cdc9c0a --- /dev/null +++ b/de.variantsync.core/src/main/java/de/variantsync/core/ast/LineBasedParser.java @@ -0,0 +1,68 @@ +package de.variantsync.core.ast; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.nio.file.DirectoryStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class LineBasedParser { + + public LineBasedParser() {} + + public AST parseDirectory(Path path) throws IOException { + AST result = null; + if (Files.exists(path)) { + if (Files.isDirectory(path)) { + result = new AST<>(LineGrammar.Directory, path.getFileName().toString()); + + try (DirectoryStream directoryStream = Files.newDirectoryStream(path)) { + // DirectoryStream has no specific order. Thus, the entries are added to an ArrayList which can be sorted. + final List list = new ArrayList<>(); + for (final Path entry : directoryStream) { + list.add(entry); + } + Collections.sort(list); + for (final Path entry : list) { + result.addChild(parseDirectory(entry)); + } + + } + } else { + if (!isBinaryFile(path)) { + result = new AST<>(LineGrammar.TextFile, path.getFileName().toString()); + final List fileStream = Files.readAllLines(path); + for (final String line : fileStream) { + result.addChild(new AST<>(LineGrammar.Line, line)); + } + } else { + result = new AST<>(LineGrammar.BinaryFile, path.getFileName().toString()); + } + } + } else { + throw new FileNotFoundException("This path does not exist: " + path); + } + return result; + } + + private static boolean isBinaryFile(Path file) throws IOException { + if (Files.exists(file)) { + final String type = Files.probeContentType(file); + if (type == null) { + // type couldn't be determined => assume binary + return true; + } else if (type.startsWith("text")) { + // non-binary + return false; + } else { + // type isn't text => assume binary + return true; + } + } else { + throw new FileNotFoundException("This file does not exist: " + file); + } + } +} diff --git a/de.variantsync.core/src/main/java/de/variantsync/core/ast/LineGrammar.java b/de.variantsync.core/src/main/java/de/variantsync/core/ast/LineGrammar.java new file mode 100644 index 0000000..6cef70d --- /dev/null +++ b/de.variantsync.core/src/main/java/de/variantsync/core/ast/LineGrammar.java @@ -0,0 +1,37 @@ +package de.variantsync.core.ast; + +import de.variantsync.core.interfaces.Grammar; + +public enum LineGrammar implements Grammar { + + Directory, TextFile, BinaryFile, Line; + + @Override + public boolean isValidChild(LineGrammar child) { + if (this == LineGrammar.Directory) { + // Dir can't have line as child + return child != LineGrammar.Line; + } else if ((this == LineGrammar.TextFile) || (this == LineGrammar.BinaryFile)) { + // File can't have dir or file as child + return child == LineGrammar.Line; + } else { + // Line is always leaf node + return false; + } + + } + + @Override + public OptionalType getTypeOf(LineGrammar sym) { + switch (sym) { + case Directory: + return OptionalType.Wrapper; + case TextFile: + case BinaryFile: + case Line: + return OptionalType.Optional; + default: + throw new IllegalArgumentException("[BUG] There is not OptionalType for symbol " + sym + " specified!"); + } + } +} diff --git a/de.variantsync.core/src/main/java/de/variantsync/core/interfaces/Grammar.java b/de.variantsync.core/src/main/java/de/variantsync/core/interfaces/Grammar.java new file mode 100644 index 0000000..7a3b7e7 --- /dev/null +++ b/de.variantsync.core/src/main/java/de/variantsync/core/interfaces/Grammar.java @@ -0,0 +1,12 @@ +package de.variantsync.core.interfaces; + +public interface Grammar { + + enum OptionalType { + Wrapper, Optional, Mandatory + } + + public boolean isValidChild(T child); + + public OptionalType getTypeOf(T sym); +} diff --git a/de.variantsync.core/src/test/java/de/variantsync/core/ASTTest.java b/de.variantsync.core/src/test/java/de/variantsync/core/ASTTest.java new file mode 100644 index 0000000..16620a6 --- /dev/null +++ b/de.variantsync.core/src/test/java/de/variantsync/core/ASTTest.java @@ -0,0 +1,191 @@ +package de.variantsync.core; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.util.Arrays; +import java.util.List; + +import org.junit.Before; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.runners.MethodSorters; + +import de.variantsync.core.ast.AST; +import de.variantsync.core.ast.LineGrammar; + +/** + * Here you can find the unit tests for the AST data structure. This also tests the (Line)Grammar indirectly. + * + * @author eric + */ +@FixMethodOrder(MethodSorters.NAME_ASCENDING) // run tests in lexicographic order +public class ASTTest { + + AST root; + AST mainDir; + AST testDir; + AST mainJava; + int lineIndex = 0; // only for printTree() testing + final int INITIAL_AST_SIZE = 11; + final int INITIAL_TOSTRING_ROWS = 10; + final int INITIAL_ROOT_VARIABLE_COUNT = 4; + + @Before + public void setup() { + root = new AST<>(LineGrammar.Directory, "src"); + mainDir = new AST<>(LineGrammar.Directory, "main"); + testDir = new AST<>(LineGrammar.Directory, "test"); + mainJava = new AST<>(LineGrammar.TextFile, "Main.java"); + final AST emptyJava = new AST<>(LineGrammar.TextFile, "Empty.java"); + final AST emptyTestJava = new AST<>(LineGrammar.TextFile, "EmptyTest.java"); + root.addChild(testDir); + testDir.addChild(emptyTestJava); + root.addChild(mainDir); + mainDir.addChild(mainJava); + mainDir.addChild(emptyJava); + + mainJava.addChildren( + Arrays.asList(new AST<>(LineGrammar.Line, "public class Main {"), new AST<>(LineGrammar.Line, " public static void main(String[] args)"), + new AST<>(LineGrammar.Line, " System.out.println(\"Hello World\");"), new AST<>(LineGrammar.Line, " }"), + new AST<>(LineGrammar.Line, "}"))); + } + + @Test + public void toStringOnInitialTest() { + final String[] lines = root.toString().split(" "); + assertEquals(INITIAL_TOSTRING_ROWS, lines.length); + // this loop skips the names of the variable and only checks their value + for (int i = 2; i < lines.length; i = i + 2) { + if (lines[i].charAt(lines[i].length() - 1) == ',') { + lines[i] = lines[i].substring(0, lines[i].length() - 1); + } + switch (i) { + case 2: + assertEquals(root.getId().getMostSignificantBits(), Long.parseLong(lines[i])); + break; + case 4: + assertEquals(root.getType().toString(), lines[i]); + break; + case 6: + assertEquals(root.getValue().toString(), lines[i]); + break; + case 8: + assertEquals(root.getSubtrees().size(), Integer.parseInt(lines[i])); + break; + default: + throw new IllegalArgumentException(String.format("toStringOnInitialTest has incorrect lines size: %d", i)); + } + } + } + + @Test + public void addOnInitialTest() { + assertFalse(root.addChild(null)); + assertEquals(INITIAL_AST_SIZE, root.size()); + + // Adding new Directory as subtree of a Directory should work + AST newTree = new AST<>(LineGrammar.Directory, "newROOT"); + int oldSize = root.getSubtrees().size(); + assertTrue(root.addChild(newTree)); + assertEquals(oldSize + 1, root.getSubtrees().size()); + + // Adding new Line as subtree of a Directory should not work + newTree = new AST<>(LineGrammar.Line, "!LineYouAreLookingFor"); + oldSize = root.getSubtrees().size(); + assertFalse(root.addChild(newTree)); + assertEquals(oldSize, root.getSubtrees().size()); + } + + @Test + public void addAllOnInitialTest() { + assertFalse(root.addChildren(null)); + assertEquals(INITIAL_AST_SIZE, root.size()); + + // Adding new List of ASTs, only the one satisfying the isValidChild of Grammar or != null will be added, + // rest is ignored. + List> newTrees = Arrays.asList(new AST<>(LineGrammar.Line, "public class Main {"), null, + new AST<>(LineGrammar.BinaryFile, "101010"), new AST<>(LineGrammar.TextFile, "fancyFile.txt"), new AST<>(LineGrammar.Directory, "fancyFolder")); + int oldSize = root.getSubtrees().size(); + assertFalse(root.addChildren(newTrees)); + assertEquals(oldSize + 3, root.getSubtrees().size()); + + // Adding only valid subtrees to the root + newTrees = Arrays.asList(new AST<>(LineGrammar.Directory, "public class Main {"), new AST<>(LineGrammar.BinaryFile, "101010")); + oldSize = root.getSubtrees().size(); + assertTrue(root.addChildren(newTrees)); + assertEquals(oldSize + 2, root.getSubtrees().size()); + } + + @Test(expected = UnsupportedOperationException.class) + public void addOnSubtreesList() { + root.getSubtrees().add(new AST<>(LineGrammar.Directory, "evilDir")); + } + + @Test + public void sizeOnInitialTest() { + assertEquals(INITIAL_AST_SIZE, root.size()); + } + + @Test + public void sizeOnEmptyASTTest() { + final AST badAST = new AST<>(null, null); + assertEquals(1, badAST.size()); + } + + @Test + public void getDepthOnInitialTest() { + assertEquals(4, root.getDepth()); + } + + @Test + public void getDepthOnEmptyASTTest() { + final AST badAST = new AST<>(null, null); + assertEquals(1, badAST.getDepth()); + } + + @Test + public void printTreeOnInitialTest() { + // assure that printTrees has as many rows as the AST has subtrees + final String[] lines = root.printTree().split(String.format("%n")); + assertEquals(INITIAL_AST_SIZE, lines.length); + + // assure the number of printed variables of the root value + final String[] rootAttributes = lines[0].split(" "); + assertEquals(INITIAL_ROOT_VARIABLE_COUNT, rootAttributes.length); + + // check root values + checkStringRoot(root, rootAttributes); + + // check subtrees + checkStringSubTree(root, lines); + } + + private void checkStringRoot(AST node, String[] rootAttributes) { + assertEquals(0, lineIndex); + // this test also tests the order of the attributes but + // in general checking like this is not possible due to the nature of AST.INDENT_STRING + // but root line does not contain AST.INDENT_STRING + assertEquals(node.getType().toString(), rootAttributes[0]); // Type + assertEquals(node.getValue(), rootAttributes[1]); // Value + assertEquals("uuid:", rootAttributes[2]); + assertEquals(((Long) node.getId().getMostSignificantBits()).toString(), rootAttributes[3]); // UUID + } + + private void checkStringSubTree(AST node, String[] lines) { + lineIndex++; + for (final AST child : node.getSubtrees()) { + // in contrast to checkStringRoot this only checks if the attributes are contained in the string + // but does not assure their order + final String line = lines[lineIndex]; + assertTrue(line.contains(AST.INDENT_STRING)); + assertTrue(line.contains(AST.NEXT_SEPARATOR) || line.contains(AST.NEXT_ACT_SEPARATOR) || line.contains(AST.LAST_SEPARATOR)); + assertTrue(line.contains(child.getType().toString())); + assertTrue(line.contains(child.getValue())); + assertTrue(line.contains(((Long) child.getId().getMostSignificantBits()).toString())); + + checkStringSubTree(child, lines); + } + } +} diff --git a/de.variantsync.core/src/test/java/de/variantsync/core/JsonParserASTWithLineGrammarTest.java b/de.variantsync.core/src/test/java/de/variantsync/core/JsonParserASTWithLineGrammarTest.java new file mode 100644 index 0000000..90f5038 --- /dev/null +++ b/de.variantsync.core/src/test/java/de/variantsync/core/JsonParserASTWithLineGrammarTest.java @@ -0,0 +1,110 @@ +package de.variantsync.core; + +import static org.junit.Assert.assertEquals; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Arrays; + +import org.junit.Before; +import org.junit.Test; + +import de.variantsync.core.ast.AST; +import de.variantsync.core.ast.JsonParserASTWithLineGrammar; +import de.variantsync.core.ast.LineGrammar; + +//TODO. Add compare method to AST and then compare ASTs with this method. + +public class JsonParserASTWithLineGrammarTest { + + AST exampleAst; + Path examplePath; + + @Before + public void InitJsonTest() throws IOException { + // init + exampleAst = new AST<>(LineGrammar.Directory, "src"); + final AST mainJava = new AST<>(LineGrammar.TextFile, "Main.java"); + exampleAst.addChild(mainJava); + mainJava.addChildren( + Arrays.asList(new AST<>(LineGrammar.Line, "public class Main {"), new AST<>(LineGrammar.Line, " public static void main(String[] args)"), + new AST<>(LineGrammar.Line, " System.out.println(\"Hello World\");"), new AST<>(LineGrammar.Line, " }"), + new AST<>(LineGrammar.Line, "}"))); + + examplePath = Path.of("out.txt"); + + } + + @Test + public void TestJsonParserAST() { + + // export to json + final String json = JsonParserASTWithLineGrammar.toJson(exampleAst); + + // import ast from json + final AST importAST = JsonParserASTWithLineGrammar.toAST(json); + + // toJson imported AST + final String importedJson = JsonParserASTWithLineGrammar.toJson(importAST); + + // print + System.out.println("FileFirst:" + json); + + System.out.println("FileSecond:" + importedJson); + + // compare json + assertEquals(json, importedJson); + + } + + @Test + public void TestJsonParserASTtoFile() throws IOException { + + // export to json file + final String json = JsonParserASTWithLineGrammar.exportAST(examplePath, exampleAst); + + // import ast from file + final AST importedAST = JsonParserASTWithLineGrammar.importAST(examplePath); + + // toJson imported AST + final String importedJson = JsonParserASTWithLineGrammar.toJson(importedAST); + + // print + System.out.println("FileFirst:" + json); + + System.out.println("FileSecond:" + importedJson); + + // compare json + assertEquals(json, importedJson); + + // delete created file + Files.delete(examplePath); + } + + @Test + public void TestJsonParserASTtoFileToString() throws IOException { + + // export to json file + JsonParserASTWithLineGrammar.exportAST(examplePath, exampleAst); + + // import ast from file + final AST importedAST = JsonParserASTWithLineGrammar.importAST(examplePath); + + // get toString + final String astString = exampleAst.toString(); + final String importedString = importedAST.toString(); + + // print + System.out.println("FileFirst:" + astString); + + System.out.println("FileSecond:" + importedString); + + // compare json + assertEquals(astString, importedString); + + // delete created file + Files.delete(examplePath); + } + +} diff --git a/de.variantsync.core/src/test/java/de/variantsync/core/LineBasedParserTest.java b/de.variantsync.core/src/test/java/de/variantsync/core/LineBasedParserTest.java new file mode 100644 index 0000000..6a6c682 --- /dev/null +++ b/de.variantsync.core/src/test/java/de/variantsync/core/LineBasedParserTest.java @@ -0,0 +1,68 @@ +package de.variantsync.core; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Arrays; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; + +import de.variantsync.core.ast.AST; +import de.variantsync.core.ast.LineBasedParser; +import de.variantsync.core.ast.LineGrammar; + +//TODO: Add compare method to AST and then compare ASTs with this method. + +public class LineBasedParserTest { + + private AST srcDir; + + @Rule + public TemporaryFolder tempFolder = new TemporaryFolder(); + + @Before + public void setupAST() { + srcDir = new AST<>(LineGrammar.Directory, "src"); + final AST mainDir = new AST<>(LineGrammar.Directory, "main"); + srcDir.addChild(mainDir); + final AST testDir = new AST<>(LineGrammar.Directory, "test"); + srcDir.addChild(testDir); + final AST binFile = new AST<>(LineGrammar.BinaryFile, "BinaryFile"); + mainDir.addChild(binFile); + final AST mainJava = new AST<>(LineGrammar.TextFile, "Main.java"); + mainDir.addChild(mainJava); + mainJava.addChildren( + Arrays.asList(new AST<>(LineGrammar.Line, "public class Main {"), new AST<>(LineGrammar.Line, " public static void main(String[] args)"), + new AST<>(LineGrammar.Line, " System.out.println(\"Hello World\");"), new AST<>(LineGrammar.Line, " }"), + new AST<>(LineGrammar.Line, "}"))); + } + + @Test + public void parseDirectoryTest() throws IOException { + final Path src = tempFolder.newFolder("src").toPath(); + final Path mainDir = Files.createDirectory(Paths.get(src + File.separator + "main")); + final Path testDir = Files.createDirectory(Paths.get(src + File.separator + "test")); + final Path mainFile = Files.createFile(Paths.get(mainDir + File.separator + "Main.java")); + final String fileContent = + String.format("public class Main {%n public static void main(String[] args)%n System.out.println(\"Hello World\");%n }%n}"); + Files.writeString(mainFile, fileContent); + + final Path binFile = Files.createFile(Paths.get(mainDir + File.separator + "BinaryFile")); + final byte[] bytes = "stringForCreationOfByteArray".getBytes(); + Files.write(binFile, bytes); + + final LineBasedParser parser = new LineBasedParser(); + final AST parsedAST = parser.parseDirectory(src); + + // Testing only the equality of the toString() methods at the moment + // waiting for equals() method for AST for comparison of the real AST-Objects + // TODO: FIX THIS + // assertEquals(parsedAST.toString(), srcDir.toString()); + } + +} diff --git a/pom.xml b/pom.xml index 0893581..7725576 100644 --- a/pom.xml +++ b/pom.xml @@ -1,5 +1,6 @@ + + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 de.tubs.variantsync de.tubs.variantsync @@ -9,9 +10,10 @@ 2.1.0 2.1.0 + 3.8.1 UTF-8 - https://download.eclipse.org/releases/2020-09/ - + https://download.eclipse.org/releases/2019-12/ + @@ -19,27 +21,38 @@ de.tubs.variantsync.core de.tubs.variantsync.core.feature de.tubs.variantsync.update - + de.variantsync.core - de.tubs.variantsync.core-test + de.tubs.variantsync.core-test - + eclipse-release ${eclipse-repo.url} p2 - + featureide http://featureide.cs.ovgu.de/update/v3/ p2 - + - + + + + org.apache.maven.plugins + maven-compiler-plugin + ${maven-compiler-version} + + 11 + 11 + + + org.eclipse.tycho tycho-maven-plugin @@ -52,16 +65,16 @@ ${tycho-version} true - - SYSTEM + + SYSTEM - + org.eclipse.tycho target-platform-configuration ${tycho-version} - + consider @@ -103,8 +116,8 @@ - +