diff --git a/modules/main/src/main/java/com/annimon/ownlang/modules/ounit/ounit.java b/modules/main/src/main/java/com/annimon/ownlang/modules/ounit/ounit.java index c087230..3908872 100644 --- a/modules/main/src/main/java/com/annimon/ownlang/modules/ounit/ounit.java +++ b/modules/main/src/main/java/com/annimon/ownlang/modules/ounit/ounit.java @@ -5,7 +5,6 @@ import com.annimon.ownlang.lib.*; import com.annimon.ownlang.modules.Module; import java.text.DecimalFormat; import java.util.Collections; -import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -22,110 +21,91 @@ public final class ounit implements Module { @Override public Map functions() { - final var result = new LinkedHashMap(16); - result.put("assertEquals", new assertEquals()); - result.put("assertNotEquals", new assertNotEquals()); - result.put("assertSameType", new assertSameType()); - result.put("assertTrue", new assertTrue()); - result.put("assertFalse", new assertFalse()); - result.put("runTests", new runTests()); - return result; + return Map.of( + "assertEquals", this::assertEquals, + "assertNotEquals", this::assertNotEquals, + "assertSameType", this::assertSameType, + "assertTrue", this::assertTrue, + "assertFalse", this::assertFalse, + "runTests", this::runTests + ); } private static String microsToSeconds(long micros) { return new DecimalFormat("#0.0000").format(micros / 1000d / 1000d) + " sec"; } - - private static class assertEquals implements Function { - @Override - public Value execute(Value[] args) { - Arguments.check(2, args.length); - if (args[0].equals(args[1])) return NumberValue.ONE; - throw new OUnitAssertionException("Values are not equal: " - + "1: " + args[0] + ", 2: " + args[1]); - } - } - - private static class assertNotEquals implements Function { - @Override - public Value execute(Value[] args) { - Arguments.check(2, args.length); - if (!args[0].equals(args[1])) return NumberValue.ONE; - throw new OUnitAssertionException("Values are equal: " + args[0]); - } - } - - private static class assertSameType implements Function { - @Override - public Value execute(Value[] args) { - Arguments.check(2, args.length); - if (args[0].type() == args[1].type()) return NumberValue.ONE; - throw new OUnitAssertionException("Types mismatch. " - + "1: " + Types.typeToString(args[0].type()) - + ", 2: " + Types.typeToString(args[1].type())); - } - } - - private static class assertTrue implements Function { - @Override - public Value execute(Value[] args) { - Arguments.check(1, args.length); - if (args[0].asInt() != 0) return NumberValue.ONE; - throw new OUnitAssertionException("Expected true, but found false."); - } - } - - private static class assertFalse implements Function { - @Override - public Value execute(Value[] args) { - Arguments.check(1, args.length); - if (args[0].asInt() == 0) return NumberValue.ONE; - throw new OUnitAssertionException("Expected false, but found true."); - } - } - - private static class runTests implements Function { - - @Override - public Value execute(Value[] args) { - final var testFunctions = ScopeHandler.functions().entrySet().stream() - .filter(e -> e.getKey().toLowerCase().startsWith("test")) - .toList(); - List tests = testFunctions.stream() - .map(e -> runTest(e.getKey(), e.getValue())) - .toList(); - int failures = 0; - long summaryTime = 0; - final StringBuilder result = new StringBuilder(); - for (TestInfo test : tests) { - if (!test.isPassed) failures++; - summaryTime += test.elapsedTimeInMicros; - result.append(Console.newline()); - result.append(test.info()); - } + private Value assertEquals(Value[] args) { + Arguments.check(2, args.length); + if (args[0].equals(args[1])) return NumberValue.ONE; + throw new OUnitAssertionException("Values are not equal: " + + "1: " + args[0] + ", 2: " + args[1]); + } + + private Value assertNotEquals(Value[] args) { + Arguments.check(2, args.length); + if (!args[0].equals(args[1])) return NumberValue.ONE; + throw new OUnitAssertionException("Values are equal: " + args[0]); + } + + private Value assertSameType(Value[] args) { + Arguments.check(2, args.length); + if (args[0].type() == args[1].type()) return NumberValue.ONE; + throw new OUnitAssertionException("Types mismatch. " + + "1: " + Types.typeToString(args[0].type()) + + ", 2: " + Types.typeToString(args[1].type())); + } + + private Value assertTrue(Value[] args) { + Arguments.check(1, args.length); + if (args[0].asInt() != 0) return NumberValue.ONE; + throw new OUnitAssertionException("Expected true, but found false."); + } + + private Value assertFalse(Value[] args) { + Arguments.check(1, args.length); + if (args[0].asInt() == 0) return NumberValue.ONE; + throw new OUnitAssertionException("Expected false, but found true."); + } + + private Value runTests(Value[] args) { + final var testFunctions = ScopeHandler.functions().entrySet().stream() + .filter(e -> e.getKey().toLowerCase().startsWith("test")) + .toList(); + List tests = testFunctions.stream() + .map(e -> runTest(e.getKey(), e.getValue())) + .toList(); + + int failures = 0; + long summaryTime = 0; + final StringBuilder result = new StringBuilder(); + for (TestInfo test : tests) { + if (!test.isPassed) failures++; + summaryTime += test.elapsedTimeInMicros; result.append(Console.newline()); - result.append(String.format("Tests run: %d, Failures: %d, Time elapsed: %s", - tests.size(), failures, - microsToSeconds(summaryTime))); - return new StringValue(result.toString()); + result.append(test.info()); } + result.append(Console.newline()); + result.append(String.format("Tests run: %d, Failures: %d, Time elapsed: %s", + tests.size(), failures, + microsToSeconds(summaryTime))); + return new StringValue(result.toString()); + } - private TestInfo runTest(String name, Function f) { - final long startTime = System.nanoTime(); - boolean isSuccessfull; - String failureDescription; - try { - f.execute(); - isSuccessfull = true; - failureDescription = ""; - } catch (OUnitAssertionException oae) { - isSuccessfull = false; - failureDescription = oae.getMessage(); - } - final long elapsedTime = System.nanoTime() - startTime; - return new TestInfo(name, isSuccessfull, failureDescription, elapsedTime / 1000); + private TestInfo runTest(String name, Function f) { + final long startTime = System.nanoTime(); + boolean isSuccessfull; + String failureDescription; + try { + f.execute(); + isSuccessfull = true; + failureDescription = ""; + } catch (OUnitAssertionException oae) { + isSuccessfull = false; + failureDescription = oae.getMessage(); } + final long elapsedTime = System.nanoTime() - startTime; + return new TestInfo(name, isSuccessfull, failureDescription, elapsedTime / 1000); } private static class OUnitAssertionException extends RuntimeException { @@ -142,7 +122,7 @@ public final class ounit implements Module { long elapsedTimeInMicros ) { public String info() { - return String.format("%s [%s]\n%sElapsed: %s\n", + return "%s [%s]\n%sElapsed: %s\n".formatted( name, isPassed ? "passed" : "FAILED", isPassed ? "" : (failureDescription + "\n"), diff --git a/ownlang-parser/src/test/java/com/annimon/ownlang/parser/MockOUnitStage.java b/ownlang-parser/src/test/java/com/annimon/ownlang/parser/MockOUnitStage.java new file mode 100644 index 0000000..3ac9db4 --- /dev/null +++ b/ownlang-parser/src/test/java/com/annimon/ownlang/parser/MockOUnitStage.java @@ -0,0 +1,52 @@ +package com.annimon.ownlang.parser; + +import com.annimon.ownlang.lib.FunctionValue; +import com.annimon.ownlang.lib.NumberValue; +import com.annimon.ownlang.lib.ScopeHandler; +import com.annimon.ownlang.parser.ast.Node; +import com.annimon.ownlang.stages.Stage; +import com.annimon.ownlang.stages.StagesData; +import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.fail; + +public class MockOUnitStage implements Stage { + + @Override + public Node perform(StagesData stagesData, Node input) { + ScopeHandler.resetScope(); + ScopeHandler.setFunction("assertEquals", (args) -> { + assertEquals(args[0], args[1]); + return NumberValue.ONE; + }); + ScopeHandler.setFunction("assertNotEquals", (args) -> { + assertNotEquals(args[0], args[1]); + return NumberValue.ONE; + }); + ScopeHandler.setFunction("assertSameType", (args) -> { + assertEquals(args[0].type(), args[1].type()); + return NumberValue.ONE; + }); + ScopeHandler.setFunction("assertTrue", (args) -> { + assertTrue(args[0].asInt() != 0); + return NumberValue.ONE; + }); + ScopeHandler.setFunction("assertFalse", (args) -> { + assertFalse(args[0].asInt() != 0); + return NumberValue.ONE; + }); + ScopeHandler.setFunction("assertFail", (args) -> { + assertThrows(Throwable.class, + () -> ((FunctionValue) args[0]).getValue().execute()); + return NumberValue.ONE; + }); + ScopeHandler.setFunction("fail", (args) -> { + if (args.length > 0) { + fail(args[0].asString()); + } else { + fail(); + } + return NumberValue.ONE; + }); + return input; + } +} diff --git a/ownlang-parser/src/test/java/com/annimon/ownlang/parser/ProgramsTest.java b/ownlang-parser/src/test/java/com/annimon/ownlang/parser/ProgramsTest.java index d08787d..2de0039 100644 --- a/ownlang-parser/src/test/java/com/annimon/ownlang/parser/ProgramsTest.java +++ b/ownlang-parser/src/test/java/com/annimon/ownlang/parser/ProgramsTest.java @@ -2,8 +2,6 @@ package com.annimon.ownlang.parser; import com.annimon.ownlang.Console; import com.annimon.ownlang.exceptions.OwnLangParserException; -import com.annimon.ownlang.lib.FunctionValue; -import com.annimon.ownlang.lib.NumberValue; import com.annimon.ownlang.lib.ScopeHandler; import com.annimon.ownlang.parser.ast.ClassDeclarationStatement; import com.annimon.ownlang.parser.ast.FunctionDefineStatement; @@ -42,7 +40,7 @@ public class ProgramsTest { .then(new ParserStage()) .then(new LinterStage(LinterStage.Mode.SEMANTIC)) .thenConditional(true, new OptimizationStage(9)) - .then(ProgramsTest::mockOUnit) + .then(new MockOUnitStage()) .then(new ExecutionStage()) .then((stagesData, input) -> { input.accept(testFunctionsExecutor); @@ -50,45 +48,6 @@ public class ProgramsTest { }); } - private static Node mockOUnit(StagesData stagesData, Node input) { - ScopeHandler.resetScope(); - // Let's mock junit methods as ounit functions - ScopeHandler.setFunction("assertEquals", (args) -> { - assertEquals(args[0], args[1]); - return NumberValue.ONE; - }); - ScopeHandler.setFunction("assertNotEquals", (args) -> { - assertNotEquals(args[0], args[1]); - return NumberValue.ONE; - }); - ScopeHandler.setFunction("assertSameType", (args) -> { - assertEquals(args[0].type(), args[1].type()); - return NumberValue.ONE; - }); - ScopeHandler.setFunction("assertTrue", (args) -> { - assertTrue(args[0].asInt() != 0); - return NumberValue.ONE; - }); - ScopeHandler.setFunction("assertFalse", (args) -> { - assertFalse(args[0].asInt() != 0); - return NumberValue.ONE; - }); - ScopeHandler.setFunction("assertFail", (args) -> { - assertThrows(Throwable.class, - () -> ((FunctionValue) args[0]).getValue().execute()); - return NumberValue.ONE; - }); - ScopeHandler.setFunction("fail", (args) -> { - if (args.length > 0) { - fail(args[0].asString()); - } else { - fail(); - } - return NumberValue.ONE; - }); - return input; - } - @ParameterizedTest @MethodSource("data") public void testProgram(InputSource inputSource) { @@ -119,7 +78,7 @@ public class ProgramsTest { @Override public void visit(ClassDeclarationStatement s) { - + // skip for tests } }; }