Rework LanguageAnnotationValues and add test

This commit is contained in:
Peter Dell
2023-02-13 00:22:46 +01:00
parent e2989f03c1
commit c013951d56
7 changed files with 174 additions and 75 deletions

View File

@@ -20,11 +20,27 @@
package com.wudsn.ide.base.common; package com.wudsn.ide.base.common;
public class Assertions { public class Assertions {
public static void assertFalse(boolean actual) { public static void assertFalse(boolean actual) {
throw new RuntimeException("Actual values is not false"); throw new RuntimeException("Actual values is not false");
} }
public static void assertEquals(Object actual, Object expected) {
if (actual == expected) {
return;
}
if (actual == null && expected != null) {
fail("Actual value is null");
}
if (actual != null && expected == null) {
fail("Actual value " + actual + " is not null");
}
if (!actual.equals(expected)) {
fail("Actual value " + actual + " is not equal to expected value " + expected + "");
}
}
public static void fail(String message) { public static void fail(String message) {
throw new RuntimeException(message); throw new RuntimeException(message);
} }

View File

@@ -25,6 +25,8 @@ import java.util.TreeMap;
import java.util.TreeSet; import java.util.TreeSet;
import org.eclipse.core.resources.IMarker; import org.eclipse.core.resources.IMarker;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import com.wudsn.ide.base.common.StringUtility; import com.wudsn.ide.base.common.StringUtility;
@@ -46,6 +48,23 @@ public final class LanguageAnnotationValues {
this.lineNumber = lineNumber; this.lineNumber = lineNumber;
} }
public boolean equals(Object other) {
if (other instanceof LanguageAnnotationValue) {
LanguageAnnotationValue otherObject = (LanguageAnnotationValue) other;
if (!this.key.equals(otherObject.key)) {
return false;
}
if (!this.value.equals(otherObject.value)) {
return false;
}
if (this.lineNumber != (otherObject.lineNumber)) {
return false;
}
return true;
}
return false;
}
@Override @Override
public String toString() { public String toString() {
return key + "=" + value + " in line " + lineNumber; return key + "=" + value + " in line " + lineNumber;
@@ -132,4 +151,58 @@ public final class LanguageAnnotationValues {
return properties.toString(); return properties.toString();
} }
public static LanguageAnnotationValues parseDocument(IDocument document) {
if (document == null) {
throw new IllegalArgumentException("Parameter 'document' must not be null.");
}
String content = document.get();
LanguageAnnotationValues result = new LanguageAnnotationValues();
int index = getMinIndex(content.indexOf(LanguageAnnotation.PREFIX),
content.indexOf(LanguageAnnotation.OLD_PREFIX));
while (index >= 0) {
int indexEqualSign = content.indexOf('=', index);
int indexNewLine = content.indexOf('\n', index);
if (indexNewLine < 0) {
indexNewLine = content.indexOf('\r', index);
}
if (indexNewLine < 0) {
indexNewLine = content.length();
}
if (indexEqualSign >= 0 && indexEqualSign < indexNewLine) {
String key = content.substring(index, indexEqualSign).trim();
String value = content.substring(indexEqualSign + 1, indexNewLine).trim();
int lineNumber;
try {
lineNumber = document.getLineOfOffset(index) + 1;
} catch (BadLocationException ex) {
lineNumber = 0;
}
result.put(key, value, lineNumber);
}
index = getMinIndex(content.indexOf(LanguageAnnotation.PREFIX, indexNewLine),
content.indexOf(LanguageAnnotation.OLD_PREFIX, indexNewLine));
}
return result;
}
/**
* Gets the smaller of two string indexes. Values less than 0 indicate "not
* found" and are ignored.
*
* @param index1 The first index
* @param index2 The second index
* @return The smaller index or a value less than 0 if no index is valid.
*/
private static int getMinIndex(int index1, int index2) {
if (index1 < 0) {
return index2;
}
if (index2 < 0) {
return index1;
}
return Math.min(index1, index2);
}
} }

View File

@@ -0,0 +1,56 @@
/**
* Copyright (C) 2009 - 2021 <a href="https://www.wudsn.com" target="_top">Peter Dell</a>
*
* This file is part of WUDSN IDE.
*
* WUDSN IDE is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* WUDSN IDE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with WUDSN IDE. If not, see <http://www.gnu.org/licenses/>.
*/
package com.wudsn.ide.lng;
import java.util.Set;
import java.util.TreeSet;
import org.eclipse.jface.text.Document;
import com.wudsn.ide.base.common.Assertions;
import com.wudsn.ide.base.common.TestMethod;
import com.wudsn.ide.lng.LanguageAnnotationValues.LanguageAnnotationValue;
/**
* Utility class to test dynamic variables.
*
* @author Peter Dell
*/
public final class LanguageAnnotationValuesTest {
/**
* Creation is private.
*/
private LanguageAnnotationValuesTest() {
}
@TestMethod
public static void main(String[] args) {
var documment = new Document("; @com.wudsn.ide.asm.test=1");
var values = LanguageAnnotationValues.parseDocument(documment);
Set<String> expectedKeySet = new TreeSet<String>();
expectedKeySet.add("@com.wudsn.ide.asm.test");
values.keySet().equals(expectedKeySet);
Assertions.assertEquals(values.get("@com.wudsn.ide.asm.test"),
new LanguageAnnotationValue("@com.wudsn.ide.asm.test", "1", 1));
System.out.println(values);
}
}

View File

@@ -183,6 +183,7 @@ public final class LanguagePlugin extends AbstractIDEPlugin {
// TODO: Call unit tests // TODO: Call unit tests
CompilerPathsTest.main(new String[0]); CompilerPathsTest.main(new String[0]);
RunnerPathsTest.main(new String[0]); RunnerPathsTest.main(new String[0]);
LanguageAnnotationValuesTest.main(new String[0]);
} }

View File

@@ -87,59 +87,13 @@ public abstract class CompilerSourceParser {
* @param document The document, not <code>null</code>. * @param document The document, not <code>null</code>.
* @return The properties, may be empty, not <code>null</code>. * @return The properties, may be empty, not <code>null</code>.
*/ */
public static LanguageAnnotationValues getDocumentProperties(IDocument document) { public static LanguageAnnotationValues getAnnotationValues(IDocument document) {
if (document == null) { if (document == null) {
throw new IllegalArgumentException("Parameter 'document' must not be null."); throw new IllegalArgumentException("Parameter 'document' must not be null.");
} }
String content = document.get(); var result = LanguageAnnotationValues.parseDocument(document);
LanguageAnnotationValues properties = new LanguageAnnotationValues(); System.out.println("TEST:" + result);
return result;
int index = getMinIndex(content.indexOf(LanguageAnnotation.PREFIX),
content.indexOf(LanguageAnnotation.OLD_PREFIX));
while (index >= 0) {
int indexEqualSign = content.indexOf('=', index);
int indexNewLine = content.indexOf('\n', index);
if (indexNewLine < 0) {
indexNewLine = content.indexOf('\r', index);
}
if (indexNewLine < 0) {
indexNewLine = content.length();
}
if (indexEqualSign >= 0 && indexEqualSign < indexNewLine) {
String key = content.substring(index, indexEqualSign).trim();
String value = content.substring(indexEqualSign + 1, indexNewLine).trim();
int lineNumber;
try {
lineNumber = document.getLineOfOffset(index) + 1;
} catch (BadLocationException ex) {
lineNumber = 0;
}
properties.put(key, value, lineNumber);
}
index = getMinIndex(content.indexOf(LanguageAnnotation.PREFIX, indexNewLine),
content.indexOf(LanguageAnnotation.OLD_PREFIX, indexNewLine));
}
return properties;
}
/**
* Gets the smaller of two string indexes. Values less than 0 indicate "not
* found" and are ignored.
*
* @param index1 The first index
* @param index2 The second index
* @return The smaller index or a value less than 0 if no index is valid.
*/
private static int getMinIndex(int index1, int index2) {
if (index1 < 0) {
return index2;
}
if (index2 < 0) {
return index1;
}
return Math.min(index1, index2);
} }
/** /**

View File

@@ -244,12 +244,11 @@ public abstract class LanguageEditor extends TextEditor {
compiler.getDefinition().getSyntax()); compiler.getDefinition().getSyntax());
partitionScanner.createDocumentPartitioner(document); partitionScanner.createDocumentPartitioner(document);
LanguageAnnotationValues properties = CompilerSourceParser.getDocumentProperties(document); var iFile = getCurrentIFile();
IFile iFile = getCurrentIFile();
if (iFile != null) { if (iFile != null) {
try { try {
hardware = filesLogic.getHardware(iFile, properties); var annotationValues = CompilerSourceParser.getAnnotationValues(document);
hardware = filesLogic.getHardware(iFile, annotationValues);
} catch (InvalidLanguageAnnotationException ex) { } catch (InvalidLanguageAnnotationException ex) {
// Do not use MarkerUtility.gotoMarker to make sure this // Do not use MarkerUtility.gotoMarker to make sure this
// editor instance is used. // editor instance is used.

View File

@@ -88,19 +88,19 @@ public final class LanguageEditorFilesLogic {
if (sourceIFile != null) { if (sourceIFile != null) {
IDocument document = languageEditor.getDocumentProvider().getDocument(languageEditor.getEditorInput()); IDocument document = languageEditor.getDocumentProvider().getDocument(languageEditor.getEditorInput());
LanguageAnnotationValues sourceFileProperties = CompilerSourceParser.getDocumentProperties(document); LanguageAnnotationValues annotationValues = CompilerSourceParser.getAnnotationValues(document);
IFile mainSourceIFile; IFile mainSourceIFile;
LanguageAnnotationValues mainSourceFileProperties; LanguageAnnotationValues mainSourceFileProperties;
mainSourceIFile = sourceIFile; mainSourceIFile = sourceIFile;
mainSourceFileProperties = sourceFileProperties; mainSourceFileProperties = annotationValues;
LanguageAnnotationValue property = sourceFileProperties.get(LanguageAnnotation.MAIN_SOURCE_FILE); LanguageAnnotationValue annotationValue = annotationValues.get(LanguageAnnotation.MAIN_SOURCE_FILE);
if (property != null) { if (annotationValue != null) {
if (StringUtility.isSpecified(property.value)) { if (StringUtility.isSpecified(annotationValue.value)) {
IPath mainSourceFileIPath; IPath mainSourceFileIPath;
mainSourceFileIPath = sourceIFile.getFullPath().removeLastSegments(1).append(property.value); mainSourceFileIPath = sourceIFile.getFullPath().removeLastSegments(1).append(annotationValue.value);
mainSourceIFile = ResourcesPlugin.getWorkspace().getRoot().getFile(mainSourceFileIPath); mainSourceIFile = ResourcesPlugin.getWorkspace().getRoot().getFile(mainSourceFileIPath);
File mainSourceFile = new File(mainSourceIFile.getLocation().toOSString()); File mainSourceFile = new File(mainSourceIFile.getLocation().toOSString());
@@ -109,7 +109,7 @@ public final class LanguageEditorFilesLogic {
mainSource = FileUtility.readString(mainSourceFile, FileUtility.MAX_SIZE_UNLIMITED); mainSource = FileUtility.readString(mainSourceFile, FileUtility.MAX_SIZE_UNLIMITED);
document = new Document(mainSource); document = new Document(mainSource);
mainSourceFileProperties = CompilerSourceParser.getDocumentProperties(document); mainSourceFileProperties = CompilerSourceParser.getAnnotationValues(document);
} catch (CoreException ex) { } catch (CoreException ex) {
LanguagePlugin plugin = LanguagePlugin.getInstance(); LanguagePlugin plugin = LanguagePlugin.getInstance();
@@ -120,7 +120,7 @@ public final class LanguageEditorFilesLogic {
} }
} }
result = new CompilerFiles(mainSourceIFile, mainSourceFileProperties, sourceIFile, sourceFileProperties, result = new CompilerFiles(mainSourceIFile, mainSourceFileProperties, sourceIFile, annotationValues,
languageEditor.getLanguageHardwareCompilerPreferences()); languageEditor.getLanguageHardwareCompilerPreferences());
} else { } else {
result = null; result = null;
@@ -169,7 +169,7 @@ public final class LanguageEditorFilesLogic {
* *
* @param iFile The IFile to which error message will be associated, not * @param iFile The IFile to which error message will be associated, not
* <code>null</code>. * <code>null</code>.
* @param properties The language properties, not <code>null</code>. * @param annotationValues The annotation values, not <code>null</code>.
* *
* @return The hardware or <code>null</code> if is the not defined in the * @return The hardware or <code>null</code> if is the not defined in the
* properties. * properties.
@@ -179,13 +179,13 @@ public final class LanguageEditorFilesLogic {
* *
* @since 1.6.1 * @since 1.6.1
*/ */
Hardware getHardware(IFile iFile, LanguageAnnotationValues properties) throws InvalidLanguageAnnotationException { Hardware getHardware(IFile iFile, LanguageAnnotationValues annotationValues) throws InvalidLanguageAnnotationException {
if (iFile == null) { if (iFile == null) {
throw new IllegalArgumentException("Parameter 'iFile' must not be null."); throw new IllegalArgumentException("Parameter 'iFile' must not be null.");
} }
Hardware hardware = null; Hardware hardware = null;
LanguageAnnotationValue hardwareProperty = properties.get(LanguageAnnotation.HARDWARE); LanguageAnnotationValue hardwareAnnotationValue = annotationValues.get(LanguageAnnotation.HARDWARE);
if (hardwareProperty != null) { if (hardwareAnnotationValue != null) {
Map<String, Hardware> allowedValues = new TreeMap<String, Hardware>(); Map<String, Hardware> allowedValues = new TreeMap<String, Hardware>();
StringBuilder allowedValuesBuilder = new StringBuilder(); StringBuilder allowedValuesBuilder = new StringBuilder();
for (Hardware value : Hardware.values()) { for (Hardware value : Hardware.values()) {
@@ -199,8 +199,8 @@ public final class LanguageEditorFilesLogic {
} }
} }
String hardwarePropertyValue = hardwareProperty.value.toUpperCase(); String hardwareValue = hardwareAnnotationValue.value.toUpperCase();
if (StringUtility.isEmpty(hardwarePropertyValue)) { if (StringUtility.isEmpty(hardwareValue)) {
try { try {
iFile.deleteMarkers(IMarker.PROBLEM, true, IResource.DEPTH_ZERO); iFile.deleteMarkers(IMarker.PROBLEM, true, IResource.DEPTH_ZERO);
} catch (CoreException ex) { } catch (CoreException ex) {
@@ -208,11 +208,11 @@ public final class LanguageEditorFilesLogic {
} }
// ERROR: Hardware not specified. Specify one of the // ERROR: Hardware not specified. Specify one of the
// following valid values '{0}'. // following valid values '{0}'.
IMarker marker = MarkerUtility.createMarker(iFile, hardwareProperty.lineNumber, IMarker.SEVERITY_ERROR, IMarker marker = MarkerUtility.createMarker(iFile, hardwareAnnotationValue.lineNumber, IMarker.SEVERITY_ERROR,
Texts.MESSAGE_E128, new String[] { allowedValuesBuilder.toString() }); Texts.MESSAGE_E128, new String[] { allowedValuesBuilder.toString() });
throw new InvalidLanguageAnnotationException(hardwareProperty, marker); throw new InvalidLanguageAnnotationException(hardwareAnnotationValue, marker);
} }
hardware = allowedValues.get(hardwarePropertyValue); hardware = allowedValues.get(hardwareValue);
if (hardware == null) { if (hardware == null) {
try { try {
@@ -222,9 +222,9 @@ public final class LanguageEditorFilesLogic {
} }
// ERROR: Unknown hardware {0}. Specify one of the // ERROR: Unknown hardware {0}. Specify one of the
// following valid values '{1}'. // following valid values '{1}'.
IMarker marker = MarkerUtility.createMarker(iFile, hardwareProperty.lineNumber, IMarker.SEVERITY_ERROR, IMarker marker = MarkerUtility.createMarker(iFile, hardwareAnnotationValue.lineNumber, IMarker.SEVERITY_ERROR,
Texts.MESSAGE_E124, new String[] { hardwarePropertyValue, allowedValuesBuilder.toString() }); Texts.MESSAGE_E124, new String[] { hardwareValue, allowedValuesBuilder.toString() });
throw new InvalidLanguageAnnotationException(hardwareProperty, marker); throw new InvalidLanguageAnnotationException(hardwareAnnotationValue, marker);
} }
} }