diff --git a/common/src/main/java/me/topchetoeu/j2s/common/parsing/Location.java b/common/src/main/java/me/topchetoeu/j2s/common/parsing/Location.java index cc2eadd..28127d0 100644 --- a/common/src/main/java/me/topchetoeu/j2s/common/parsing/Location.java +++ b/common/src/main/java/me/topchetoeu/j2s/common/parsing/Location.java @@ -32,9 +32,9 @@ public abstract class Location implements Comparable { }; } public final Location nextLine() { - return changeLine(1); + return nextLine(1); } - public final Location changeLine(int offset) { + public final Location nextLine(int offset) { var self = this; return new Location() { @@ -60,7 +60,14 @@ public abstract class Location implements Comparable { } @Override public int compareTo(Location other) { - int a = filename().toString().compareTo(other.filename().toString()); + int a; + var filenameA = filename(); + var filenameB = other.filename(); + if (filenameB == null && filenameA == null) a = 0; + else if (filenameA == null) a = -1; + else if (filenameB == null) a = 1; + else a = filenameA.toString().compareTo(filenameB.toString()); + int b = Integer.compare(line(), other.line()); int c = Integer.compare(start(), other.start()); @@ -79,21 +86,27 @@ public abstract class Location implements Comparable { } public static Location of(String raw) { - var i0 = raw.lastIndexOf(':'); - if (i0 < 0) return Location.of(Filename.parse(raw), -1, -1); + var i1 = raw.lastIndexOf(':'); + if (i1 < 0) return Location.of(Filename.parse(raw), -1, -1); - var i1 = raw.lastIndexOf(':', i0); + var i0 = raw.substring(0, i1).lastIndexOf(':', i1); if (i0 < 0) { try { - return Location.of(Filename.parse(raw.substring(0, i0)), Integer.parseInt(raw.substring(i0 + 1)), -1); + return Location.of(null, Integer.parseInt(raw.substring(0, i1)) - 1, Integer.parseInt(raw.substring(i1 + 1)) - 1); } - catch (NumberFormatException e) { - return Location.of(Filename.parse(raw), -1, -1); + catch (NumberFormatException e) {} + + try { + return Location.of(Filename.parse(raw.substring(0, i1)), Integer.parseInt(raw.substring(i1 + 1)) - 1, -1); } + catch (NumberFormatException e) {} + + return Location.of(Filename.parse(raw), -1, -1); } int start, line; + try { start = Integer.parseInt(raw.substring(i1 + 1)); } @@ -105,9 +118,9 @@ public abstract class Location implements Comparable { line = Integer.parseInt(raw.substring(i0 + 1, i1)); } catch (NumberFormatException e) { - return Location.of(Filename.parse(raw.substring(i1 + 1)), start, -1); + return Location.of(Filename.parse(raw.substring(0, i1)), start - 1, -1); } - return Location.of(Filename.parse(raw.substring(0, i0)), start, line); + return Location.of(Filename.parse(raw.substring(0, i0)), line - 1, start - 1); } } diff --git a/common/src/test/java/me/topchetoeu/j2s/common/TestLocation.java b/common/src/test/java/me/topchetoeu/j2s/common/TestLocation.java new file mode 100644 index 0000000..af366ef --- /dev/null +++ b/common/src/test/java/me/topchetoeu/j2s/common/TestLocation.java @@ -0,0 +1,162 @@ +package me.topchetoeu.j2s.common; + +import org.junit.jupiter.api.Test; + +import me.topchetoeu.j2s.common.parsing.Filename; +import me.topchetoeu.j2s.common.parsing.Location; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class TestLocation { + @Test public void testShouldCreateLocation() { + var loc = Location.of(new Filename("file", "test.txt"), 10, 5); + assertEquals("test.txt", loc.filename().path); + assertEquals(10, loc.line()); + assertEquals(5, loc.start()); + } + + @Test public void testShouldGetNextLineLocation() { + var loc = Location.of("test.txt:10:5"); + var next = loc.nextLine(); + assertEquals(next.filename(), new Filename("file", "test.txt")); + assertEquals(next.line(), 10); + assertEquals(next.start(), 0); + assertEquals(loc.filename(), new Filename("file", "test.txt")); + assertEquals(loc.line(), 9); + assertEquals(loc.start(), 4); + } + @Test public void testShouldGetNextNthLineLocation() { + var loc = Location.of(new Filename("file", "test.txt"), 10, 5); + var next = loc.nextLine(5); + assertEquals(next.line(), 15); + assertEquals(next.start(), 0); + assertEquals(loc.line(), 10); + assertEquals(loc.start(), 5); + } + + @Test public void testShouldGetNextLocation() { + var loc = Location.of("test:10:5"); + var next = loc.add(10); + assertEquals(next.filename(), new Filename("file", "test")); + assertEquals(next.line(), 9); + assertEquals(next.start(), 14); + assertEquals(loc.filename(), new Filename("file", "test")); + assertEquals(loc.line(), 9); + assertEquals(loc.start(), 4); + } + + @Test public void testShouldParseLocation() { + var loc = Location.of("test.txt:10:5"); + assertEquals(loc.filename(), new Filename("file", "test.txt")); + assertEquals(loc.line(), 9); + assertEquals(loc.start(), 4); + } + @Test public void testShouldParseComplexFilenameLocation() { + var loc = Location.of("testificate://test.txt:10:5"); + assertEquals(loc.filename(), new Filename("testificate", "test.txt")); + assertEquals(loc.line(), 9); + assertEquals(loc.start(), 4); + } + @Test public void testShouldParseNoFilenameLocation() { + var loc = Location.of("10:5"); + assertEquals(loc.filename(), null); + assertEquals(loc.line(), 9); + assertEquals(loc.start(), 4); + } + @Test public void testShouldParseNoStartLocationA() { + var loc = Location.of("file://10:5"); + assertEquals(loc.filename(), new Filename("file", "10")); + assertEquals(loc.line(), 4); + assertEquals(loc.start(), -1); + } + @Test public void testShouldParseNoStartLocationB() { + var loc = Location.of("file:5"); + assertEquals(loc.filename(), new Filename("file", "file")); + assertEquals(loc.line(), 4); + assertEquals(loc.start(), -1); + } + @Test public void testShouldParseOnlyFilenameLocationA() { + var loc = Location.of("http://example.org/test.txt"); + assertEquals(loc.filename(), new Filename("http", "example.org/test.txt")); + assertEquals(loc.line(), -1); + assertEquals(loc.start(), -1); + } + @Test public void testShouldParseOnlyFilenameLocationB() { + var loc = Location.of("test.txt"); + assertEquals(loc.filename(), new Filename("file", "test.txt")); + assertEquals(loc.line(), -1); + assertEquals(loc.start(), -1); + } + @Test public void testShouldParseOnlyFilenameWithColonLocation() { + var loc = Location.of("my-file:bad-file"); + assertEquals(loc.filename(), new Filename("file", "my-file:bad-file")); + assertEquals(loc.line(), -1); + assertEquals(loc.start(), -1); + } + @Test public void testShouldParseOnlyFilenameWithTripleColonLocation() { + var loc = Location.of("a:my-file:bad-file"); + assertEquals(loc.filename(), new Filename("file", "a:my-file:bad-file")); + assertEquals(loc.line(), -1); + assertEquals(loc.start(), -1); + } + + @Test public void testCompareEqualLoc() { + var locA = Location.of("test:10:5"); + var locB = Location.of("test:10:5"); + + assertEquals(locA.compareTo(locB), 0); + assertEquals(locB.compareTo(locA), 0); + } + @Test public void testCompareNoFileLoc() { + var locA = Location.of("10:5"); + var locB = Location.of("11:5"); + + assertEquals(locA.compareTo(locB), -1); + assertEquals(locB.compareTo(locA), 1); + } + @Test public void testCompareOneNoFileLoc() { + var locA = Location.of("10:5"); + var locB = Location.of("test:10:5"); + + assertEquals(locA.compareTo(locB), -1); + assertEquals(locB.compareTo(locA), 1); + } + @Test public void testCompareDiffFileLoc() { + var locA = Location.of("a:10:5"); + var locB = Location.of("b:10:5"); + + assertEquals(locA.compareTo(locB), -1); + assertEquals(locB.compareTo(locA), 1); + } + @Test public void testCompareDiffLineLoc() { + var locA = Location.of("test:10:5"); + var locB = Location.of("test:11:5"); + + assertEquals(locA.compareTo(locB), -1); + assertEquals(locB.compareTo(locA), 1); + } + @Test public void testCompareDiffStartLoc() { + var locA = Location.of("test:10:5"); + var locB = Location.of("test:10:10"); + + assertEquals(locA.compareTo(locB), -1); + assertEquals(locB.compareTo(locA), 1); + } + + @Test public void testToStringAll() { + var locA = Location.of("test:10:5"); + assertEquals(locA.toString(), "file://test:10:5"); + } + @Test public void testToStringNoFilename() { + var locA = Location.of("10:5"); + assertEquals(locA.toString(), "10:5"); + } + @Test public void testToStringNoStart() { + var locA = Location.of("file:5"); + assertEquals(locA.toString(), "file://file:5"); + } + @Test public void testToStringNoLoc() { + var locA = Location.of("file"); + assertEquals(locA.toString(), "file://file"); + } +}