diff --git a/src/main/java/dan200/computercraft/core/apis/OSAPI.java b/src/main/java/dan200/computercraft/core/apis/OSAPI.java index 9b7b0c943..0ada26bb2 100644 --- a/src/main/java/dan200/computercraft/core/apis/OSAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/OSAPI.java @@ -494,7 +494,9 @@ public class OSAPI implements ILuaAPI DateTimeFormatterBuilder formatter = new DateTimeFormatterBuilder(); LuaDateTime.format( formatter, format ); - return formatter.toFormatter( Locale.ROOT ).format( date ); + // ROOT would be more sensible, but US appears more consistent with the default C locale + // on Linux. + return formatter.toFormatter( Locale.US ).format( date ); } } diff --git a/src/test/java/dan200/computercraft/core/ComputerTestDelegate.java b/src/test/java/dan200/computercraft/core/ComputerTestDelegate.java index 095ede05f..b9991d028 100644 --- a/src/test/java/dan200/computercraft/core/ComputerTestDelegate.java +++ b/src/test/java/dan200/computercraft/core/ComputerTestDelegate.java @@ -28,8 +28,10 @@ import org.opentest4j.AssertionFailedError; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.io.BufferedWriter; +import java.io.File; import java.io.IOException; import java.io.Writer; +import java.net.URI; import java.nio.channels.Channels; import java.nio.channels.WritableByteChannel; import java.nio.charset.StandardCharsets; @@ -43,8 +45,6 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Stream; -import static dan200.computercraft.api.lua.LuaValues.getType; - /** * Loads tests from {@code test-rom/spec} and executes them. *

@@ -195,36 +195,45 @@ public class ComputerTestDelegate private static class DynamicNodeBuilder { private final String name; + private final URI uri; private final Map children; private final Executable executor; - DynamicNodeBuilder( String name ) + DynamicNodeBuilder( String name, String path ) { this.name = name; + this.uri = getUri( path ); this.children = new HashMap<>(); this.executor = null; } - DynamicNodeBuilder( String name, Executable executor ) + DynamicNodeBuilder( String name, String path, Executable executor ) { this.name = name; + this.uri = getUri( path ); this.children = Collections.emptyMap(); this.executor = executor; } + private static URI getUri( String path ) + { + // Unfortunately ?line=xxx doesn't appear to work with IntelliJ, so don't worry about getting it working. + return path == null ? null : new File( "src/test/resources" + path.substring( 0, path.indexOf( ':' ) ) ).toURI(); + } + DynamicNodeBuilder get( String name ) { DynamicNodeBuilder child = children.get( name ); - if( child == null ) children.put( name, child = new DynamicNodeBuilder( name ) ); + if( child == null ) children.put( name, child = new DynamicNodeBuilder( name, null ) ); return child; } - void runs( String name, Executable executor ) + void runs( String name, String uri, Executable executor ) { if( this.executor != null ) throw new IllegalStateException( name + " is leaf node" ); if( children.containsKey( name ) ) throw new IllegalStateException( "Duplicate key for " + name ); - children.put( name, new DynamicNodeBuilder( name, executor ) ); + children.put( name, new DynamicNodeBuilder( name, uri, executor ) ); } boolean isActive() @@ -241,8 +250,8 @@ public class ComputerTestDelegate DynamicNode build() { return executor == null - ? DynamicContainer.dynamicContainer( name, buildChildren() ) - : DynamicTest.dynamicTest( name, executor ); + ? DynamicContainer.dynamicContainer( name, uri, buildChildren() ) + : DynamicTest.dynamicTest( name, uri, executor ); } Stream buildChildren() @@ -376,16 +385,17 @@ public class ComputerTestDelegate { // Submit several tests and signal for #get to run LOG.info( "Received tests from computer" ); - DynamicNodeBuilder root = new DynamicNodeBuilder( "" ); - for( Object key : tests.keySet() ) + DynamicNodeBuilder root = new DynamicNodeBuilder( "", null ); + for( Map.Entry entry : tests.entrySet() ) { - if( !(key instanceof String) ) throw new LuaException( "Non-key string " + getType( key ) ); + String name = (String) entry.getKey(); + Map details = (Map) entry.getValue(); + String def = (String) details.get( "definition" ); - String name = (String) key; String[] parts = name.split( "\0" ); DynamicNodeBuilder builder = root; for( int i = 0; i < parts.length - 1; i++ ) builder = builder.get( parts[i] ); - builder.runs( parts[parts.length - 1], () -> { + builder.runs( parts[parts.length - 1], def, () -> { // Run it lock.lockInterruptibly(); try diff --git a/src/test/resources/test-rom/mcfly.lua b/src/test/resources/test-rom/mcfly.lua index a5caec7a8..258a51236 100644 --- a/src/test/resources/test-rom/mcfly.lua +++ b/src/test/resources/test-rom/mcfly.lua @@ -424,6 +424,8 @@ local tests_locked = false local test_list = {} local test_map, test_count = {}, 0 +local function format_loc(info) return ("%s:%d"):format(info.short_src, info.currentline) end + --- Add a new test to our queue. -- -- @param test The descriptor of this test @@ -432,7 +434,7 @@ local function do_test(test) if not test.name then test.name = table.concat(test_stack, "\0", 1, test_stack.n) end test_count = test_count + 1 test_list[test_count] = test - test_map[test.name] = test_count + test_map[test.name] = { idx = test_count, definition = test.definition } end --- Get the "friendly" name of this test. @@ -456,7 +458,7 @@ local function describe(name, body) local ok, err = try(body) -- We count errors as a (failing) test. - if not ok then do_test { error = err } end + if not ok then do_test { error = err, definition = format_loc(debug.getinfo(2, "Sl")) } end test_stack.n = n - 1 end @@ -475,7 +477,7 @@ local function it(name, body) local n = test_stack.n + 1 test_stack[n], test_stack.n, tests_locked = name, n, true - do_test { action = body } + do_test { action = body, definition = format_loc(debug.getinfo(2, "Sl")) } -- Pop the test from the stack test_stack.n, tests_locked = n - 1, false @@ -488,12 +490,11 @@ local function pending(name) check('it', 1, 'string', name) if tests_locked then error("Cannot create test while running tests", 2) end - local _, loc = pcall(error, "", 3) - loc = loc:gsub(":%s*$", "") + local trace = format_loc(debug.getinfo(2, "Sl")) local n = test_stack.n + 1 test_stack[n], test_stack.n = name, n - do_test { pending = true, trace = loc } + do_test { pending = true, trace = trace, definition = trace } test_stack.n = n - 1 end @@ -667,7 +668,7 @@ if cct_test then while true do local _, name = os.pullEvent("cct_test_run") if not name then break end - do_run(test_list[test_map[name]]) + do_run(test_list[test_map[name].idx]) end else for _, test in pairs(test_list) do do_run(test) end