From 2e314f9ff02a29d3f525c4b825aaeeac1099ad22 Mon Sep 17 00:00:00 2001 From: Mike Cifelli Date: Sun, 28 Oct 2018 20:07:01 -0400 Subject: [PATCH] Convert definition tests to kotlin --- src/test/kotlin/function/builtin/LoadTest.kt | 4 +- .../builtin/special/DefineSpecialTest.java | 188 ----------------- .../builtin/special/DefineSpecialTest.kt | 197 +++++++++++++++++ .../builtin/special/DefmacroTest.java | 189 ----------------- .../function/builtin/special/DefmacroTest.kt | 198 ++++++++++++++++++ .../function/builtin/special/DefunTest.java | 187 ----------------- .../function/builtin/special/DefunTest.kt | 198 ++++++++++++++++++ 7 files changed, 595 insertions(+), 566 deletions(-) delete mode 100644 src/test/kotlin/function/builtin/special/DefineSpecialTest.java create mode 100644 src/test/kotlin/function/builtin/special/DefineSpecialTest.kt delete mode 100644 src/test/kotlin/function/builtin/special/DefmacroTest.java create mode 100644 src/test/kotlin/function/builtin/special/DefmacroTest.kt delete mode 100644 src/test/kotlin/function/builtin/special/DefunTest.java create mode 100644 src/test/kotlin/function/builtin/special/DefunTest.kt diff --git a/src/test/kotlin/function/builtin/LoadTest.kt b/src/test/kotlin/function/builtin/LoadTest.kt index 5fefc07..8090c92 100644 --- a/src/test/kotlin/function/builtin/LoadTest.kt +++ b/src/test/kotlin/function/builtin/LoadTest.kt @@ -46,8 +46,8 @@ class LoadTest : SymbolAndFunctionCleaner() { RuntimeEnvironment.errorOutput = PrintStream(errorOutputStream) RuntimeEnvironment.errorManager = ErrorManager() RuntimeEnvironment.path = "" - RuntimeEnvironment.warningOutputDecorator = { s -> s } - RuntimeEnvironment.errorOutputDecorator = { s -> s } + RuntimeEnvironment.warningOutputDecorator = { it } + RuntimeEnvironment.errorOutputDecorator = { it } } override fun additionalTearDown() { diff --git a/src/test/kotlin/function/builtin/special/DefineSpecialTest.java b/src/test/kotlin/function/builtin/special/DefineSpecialTest.java deleted file mode 100644 index 669567c..0000000 --- a/src/test/kotlin/function/builtin/special/DefineSpecialTest.java +++ /dev/null @@ -1,188 +0,0 @@ -package function.builtin.special; - -import environment.RuntimeEnvironment; -import error.ErrorManager; -import function.ArgumentValidator.BadArgumentTypeException; -import function.ArgumentValidator.DottedArgumentListException; -import function.ArgumentValidator.TooFewArgumentsException; -import function.ArgumentValidator.TooManyArgumentsException; -import function.UserDefinedFunction.IllegalKeywordRestPositionException; -import org.junit.Test; -import testutil.SymbolAndFunctionCleaner; - -import java.io.ByteArrayOutputStream; -import java.io.PrintStream; - -import static org.junit.Assert.assertTrue; -import static testutil.TestUtilities.assertSExpressionsMatch; -import static testutil.TestUtilities.evaluateString; -import static testutil.TestUtilities.parseString; - -public class DefineSpecialTest extends SymbolAndFunctionCleaner { - - private ByteArrayOutputStream outputStream; - private RuntimeEnvironment environment; - - public DefineSpecialTest() { - this.environment = RuntimeEnvironment.INSTANCE; - } - - private void assertSomethingPrinted() { - assertTrue(outputStream.toByteArray().length > 0); - } - - @Override - public void additionalSetUp() { - outputStream = new ByteArrayOutputStream(); - - environment.reset(); - environment.setOutput(new PrintStream(outputStream)); - environment.setErrorManager(new ErrorManager()); - environment.setWarningOutputDecorator(s -> s); - } - - @Override - public void additionalTearDown() { - environment.reset(); - } - - @Test - public void defineSpecial() { - String input = "(define-special f () t)"; - - assertSExpressionsMatch(parseString("f"), evaluateString(input)); - assertSExpressionsMatch(parseString("t"), evaluateString("(f)")); - } - - @Test - public void defineSpecialWithEmptyBody() { - String input = "(define-special f ())"; - - assertSExpressionsMatch(parseString("f"), evaluateString(input)); - assertSExpressionsMatch(parseString("()"), evaluateString("(f)")); - } - - @Test - public void defineSpecialDoesNotEvaluateArguments() { - evaluateString("(define-special f (x) (car x))"); - assertSExpressionsMatch(parseString("quote"), evaluateString("(f '(1 2 3))")); - } - - @Test - public void defineSpecialAdd() { - evaluateString("(define-special f (x) (+ (eval x) 23))"); - assertSExpressionsMatch(parseString("27"), evaluateString("(f (+ 2 2))")); - } - - @Test - public void defineSpecialSetVariable() { - evaluateString("(define-special f (x) (set x 23))"); - evaluateString("(f y)"); - assertSExpressionsMatch(parseString("23"), evaluateString("y")); - } - - @Test - public void defineSpecialVariableCapture() { - evaluateString("(setq x 0)"); - evaluateString("(define-special f (x) (set x 23))"); - evaluateString("(f x)"); - assertSExpressionsMatch(parseString("0"), evaluateString("x")); - } - - @Test - public void defineSpecialAvoidVariableCaptureConvention() { - evaluateString("(setq x 0)"); - evaluateString("(define-special f (-x-) (set -x- 23))"); - evaluateString("(f x)"); - assertSExpressionsMatch(parseString("23"), evaluateString("x")); - } - - @Test - public void redefineSpecial_DisplaysWarning() { - String input = "(define-special myFunction () nil)"; - evaluateString(input); - evaluateString(input); - - assertSomethingPrinted(); - } - - @Test - public void redefineSpecial_ActuallyRedefinesSpecialFunction() { - evaluateString("(define-special mySpecialFunction () nil)"); - evaluateString("(define-special mySpecialFunction () T)"); - - assertSomethingPrinted(); - assertSExpressionsMatch(parseString("t"), evaluateString("(mySpecialFunction)")); - } - - @Test(expected = DottedArgumentListException.class) - public void defineSpecialWithDottedLambdaList() { - evaluateString("(funcall 'define-special 'x (cons 'a 'b) ())"); - } - - @Test(expected = BadArgumentTypeException.class) - public void defineSpecialWithNonSymbolName() { - evaluateString("(define-special 1 () ())"); - } - - @Test(expected = BadArgumentTypeException.class) - public void defineSpecialWithBadLambdaList() { - evaluateString("(define-special x a ())"); - } - - @Test(expected = TooFewArgumentsException.class) - public void defineSpecialWithTooFewArguments() { - evaluateString("(define-special x)"); - } - - @Test(expected = TooFewArgumentsException.class) - public void defineSpecialAndCallWithTooFewArguments() { - evaluateString("(define-special x (a b))"); - evaluateString("(x a)"); - } - - @Test(expected = TooManyArgumentsException.class) - public void defineSpecialAndCallWithTooManyArguments() { - evaluateString("(define-special x (a b))"); - evaluateString("(x a b c)"); - } - - @Test - public void defineSpecialWithKeywordRestParameter() { - evaluateString("(define-special f (&rest x) (car x))"); - assertSExpressionsMatch(parseString("1"), evaluateString("(f 1 2 3 4 5)")); - } - - @Test - public void defineSpecialWithNormalAndKeywordRestParameter() { - evaluateString("(define-special f (a &rest b) (cons a b))"); - assertSExpressionsMatch(parseString("(1 2 3 4 5)"), evaluateString("(f 1 2 3 4 5)")); - } - - @Test(expected = IllegalKeywordRestPositionException.class) - public void defineSpecialWithParametersFollowingKeywordRest() { - evaluateString("(define-special f (a &rest b c) (cons a b))"); - evaluateString("(f 1 2 3)"); - } - - @Test - public void defineSpecialWithKeywordRest_CallWithNoArguments() { - evaluateString("(define-special f (&rest a) (car a))"); - assertSExpressionsMatch(parseString("nil"), evaluateString("(f)")); - } - - @Test(expected = TooFewArgumentsException.class) - public void defineSpecialWithNormalAndKeywordRest_CallWithNoArguments() { - evaluateString("(define-special f (a &rest b) a)"); - evaluateString("(f)"); - } - - @Test - public void resultOfSpecialFunctionIsNotEvaluated() { - evaluateString("(setq x 'grains)"); - evaluateString("(define-special f (x) x)"); - evaluateString("(f (setq x 'sprouts))"); - - assertSExpressionsMatch(parseString("grains"), evaluateString("x")); - } -} diff --git a/src/test/kotlin/function/builtin/special/DefineSpecialTest.kt b/src/test/kotlin/function/builtin/special/DefineSpecialTest.kt new file mode 100644 index 0000000..65a9575 --- /dev/null +++ b/src/test/kotlin/function/builtin/special/DefineSpecialTest.kt @@ -0,0 +1,197 @@ +package function.builtin.special + +import environment.RuntimeEnvironment +import error.ErrorManager +import function.ArgumentValidator.BadArgumentTypeException +import function.ArgumentValidator.DottedArgumentListException +import function.ArgumentValidator.TooFewArgumentsException +import function.ArgumentValidator.TooManyArgumentsException +import function.UserDefinedFunction.IllegalKeywordRestPositionException +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Assertions.assertThrows +import org.junit.jupiter.api.Test +import testutil.SymbolAndFunctionCleaner +import testutil.TestUtilities.assertSExpressionsMatch +import testutil.TestUtilities.evaluateString +import testutil.TestUtilities.parseString +import java.io.ByteArrayOutputStream +import java.io.PrintStream + +class DefineSpecialTest : SymbolAndFunctionCleaner() { + + private var outputStream = ByteArrayOutputStream() + + private fun assertSomethingPrinted() { + assertThat(outputStream.toByteArray()).isNotEmpty() + } + + override fun additionalSetUp() { + outputStream.reset() + RuntimeEnvironment.reset() + RuntimeEnvironment.output = PrintStream(outputStream) + RuntimeEnvironment.errorManager = ErrorManager() + RuntimeEnvironment.warningOutputDecorator = { it } + } + + override fun additionalTearDown() { + RuntimeEnvironment.reset() + } + + @Test + fun defineSpecial() { + val input = "(define-special f () t)" + + assertSExpressionsMatch(parseString("f"), evaluateString(input)) + assertSExpressionsMatch(parseString("t"), evaluateString("(f)")) + } + + @Test + fun defineSpecialWithEmptyBody() { + val input = "(define-special f ())" + + assertSExpressionsMatch(parseString("f"), evaluateString(input)) + assertSExpressionsMatch(parseString("()"), evaluateString("(f)")) + } + + @Test + fun defineSpecialDoesNotEvaluateArguments() { + evaluateString("(define-special f (x) (car x))") + assertSExpressionsMatch(parseString("quote"), evaluateString("(f '(1 2 3))")) + } + + @Test + fun defineSpecialAdd() { + evaluateString("(define-special f (x) (+ (eval x) 23))") + assertSExpressionsMatch(parseString("27"), evaluateString("(f (+ 2 2))")) + } + + @Test + fun defineSpecialSetVariable() { + evaluateString("(define-special f (x) (set x 23))") + evaluateString("(f y)") + assertSExpressionsMatch(parseString("23"), evaluateString("y")) + } + + @Test + fun defineSpecialVariableCapture() { + evaluateString("(setq x 0)") + evaluateString("(define-special f (x) (set x 23))") + evaluateString("(f x)") + assertSExpressionsMatch(parseString("0"), evaluateString("x")) + } + + @Test + fun defineSpecialAvoidVariableCaptureConvention() { + evaluateString("(setq x 0)") + evaluateString("(define-special f (-x-) (set -x- 23))") + evaluateString("(f x)") + assertSExpressionsMatch(parseString("23"), evaluateString("x")) + } + + @Test + fun redefineSpecial_DisplaysWarning() { + val input = "(define-special myFunction () nil)" + evaluateString(input) + evaluateString(input) + + assertSomethingPrinted() + } + + @Test + fun redefineSpecial_ActuallyRedefinesSpecialFunction() { + evaluateString("(define-special mySpecialFunction () nil)") + evaluateString("(define-special mySpecialFunction () T)") + + assertSomethingPrinted() + assertSExpressionsMatch(parseString("t"), evaluateString("(mySpecialFunction)")) + } + + @Test + fun defineSpecialWithDottedLambdaList() { + assertThrows(DottedArgumentListException::class.java) { + evaluateString("(funcall 'define-special 'x (cons 'a 'b) ())") + } + } + + @Test + fun defineSpecialWithNonSymbolName() { + assertThrows(BadArgumentTypeException::class.java) { + evaluateString("(define-special 1 () ())") + } + } + + @Test + fun defineSpecialWithBadLambdaList() { + assertThrows(BadArgumentTypeException::class.java) { + evaluateString("(define-special x a ())") + } + } + + @Test + fun defineSpecialWithTooFewArguments() { + assertThrows(TooFewArgumentsException::class.java) { + evaluateString("(define-special x)") + } + } + + @Test + fun defineSpecialAndCallWithTooFewArguments() { + evaluateString("(define-special x (a b))") + + assertThrows(TooFewArgumentsException::class.java) { + evaluateString("(x a)") + } + } + + @Test + fun defineSpecialAndCallWithTooManyArguments() { + evaluateString("(define-special x (a b))") + + assertThrows(TooManyArgumentsException::class.java) { + evaluateString("(x a b c)") + } + } + + @Test + fun defineSpecialWithKeywordRestParameter() { + evaluateString("(define-special f (&rest x) (car x))") + assertSExpressionsMatch(parseString("1"), evaluateString("(f 1 2 3 4 5)")) + } + + @Test + fun defineSpecialWithNormalAndKeywordRestParameter() { + evaluateString("(define-special f (a &rest b) (cons a b))") + assertSExpressionsMatch(parseString("(1 2 3 4 5)"), evaluateString("(f 1 2 3 4 5)")) + } + + @Test + fun defineSpecialWithParametersFollowingKeywordRest() { + assertThrows(IllegalKeywordRestPositionException::class.java) { + evaluateString("(define-special f (a &rest b c) (cons a b))") + } + } + + @Test + fun defineSpecialWithKeywordRest_CallWithNoArguments() { + evaluateString("(define-special f (&rest a) (car a))") + assertSExpressionsMatch(parseString("nil"), evaluateString("(f)")) + } + + @Test + fun defineSpecialWithNormalAndKeywordRest_CallWithNoArguments() { + evaluateString("(define-special f (a &rest b) a)") + + assertThrows(TooFewArgumentsException::class.java) { + evaluateString("(f)") + } + } + + @Test + fun resultOfSpecialFunctionIsNotEvaluated() { + evaluateString("(setq x 'grains)") + evaluateString("(define-special f (x) x)") + evaluateString("(f (setq x 'sprouts))") + + assertSExpressionsMatch(parseString("grains"), evaluateString("x")) + } +} diff --git a/src/test/kotlin/function/builtin/special/DefmacroTest.java b/src/test/kotlin/function/builtin/special/DefmacroTest.java deleted file mode 100644 index 495f994..0000000 --- a/src/test/kotlin/function/builtin/special/DefmacroTest.java +++ /dev/null @@ -1,189 +0,0 @@ -package function.builtin.special; - -import environment.RuntimeEnvironment; -import error.ErrorManager; -import function.ArgumentValidator.BadArgumentTypeException; -import function.ArgumentValidator.DottedArgumentListException; -import function.ArgumentValidator.TooFewArgumentsException; -import function.ArgumentValidator.TooManyArgumentsException; -import function.UserDefinedFunction.IllegalKeywordRestPositionException; -import org.junit.Test; -import testutil.SymbolAndFunctionCleaner; - -import java.io.ByteArrayOutputStream; -import java.io.PrintStream; - -import static org.junit.Assert.assertTrue; -import static testutil.TestUtilities.assertSExpressionsMatch; -import static testutil.TestUtilities.evaluateString; -import static testutil.TestUtilities.parseString; - -public class DefmacroTest extends SymbolAndFunctionCleaner { - - private ByteArrayOutputStream outputStream; - private RuntimeEnvironment environment; - - public DefmacroTest() { - this.environment = RuntimeEnvironment.INSTANCE; - } - - private void assertSomethingPrinted() { - assertTrue(outputStream.toByteArray().length > 0); - } - - @Override - public void additionalSetUp() { - outputStream = new ByteArrayOutputStream(); - - environment.reset(); - environment.setOutput(new PrintStream(outputStream)); - environment.setErrorManager(new ErrorManager()); - environment.setWarningOutputDecorator(s -> s); - } - - @Override - public void additionalTearDown() { - environment.reset(); - } - - @Test - public void defmacro() { - String input = "(defmacro m () t)"; - - assertSExpressionsMatch(parseString("m"), evaluateString(input)); - assertSExpressionsMatch(parseString("t"), evaluateString("(m)")); - } - - @Test - public void defmacroWithEmptyBody() { - String input = "(defmacro m ())"; - - assertSExpressionsMatch(parseString("m"), evaluateString(input)); - assertSExpressionsMatch(parseString("()"), evaluateString("(m)")); - } - - @Test - public void defmacroDoesNotEvaluateArguments() { - evaluateString("(setq x 'grains)"); - evaluateString("(defmacro m (x))"); - evaluateString("(m (setq x 'sprouts))"); - - assertSExpressionsMatch(parseString("grains"), evaluateString("x")); - } - - @Test - public void defmacroAdd() { - evaluateString("(defmacro m (x) (+ (eval x) 23))"); - assertSExpressionsMatch(parseString("27"), evaluateString("(m (+ 2 2))")); - } - - @Test - public void defmacroSetVariable() { - evaluateString("(defmacro m (x) (set x 23))"); - evaluateString("(m y)"); - assertSExpressionsMatch(parseString("23"), evaluateString("y")); - } - - @Test - public void defmacroVariableCapture() { - evaluateString("(setq x 0)"); - evaluateString("(defmacro m (x) (set x 23))"); - evaluateString("(m x)"); - assertSExpressionsMatch(parseString("0"), evaluateString("x")); - } - - @Test - public void redefineMacro_DisplaysWarning() { - String input = "(defmacro myMacro () nil)"; - evaluateString(input); - evaluateString(input); - - assertSomethingPrinted(); - } - - @Test - public void redefineMacro_ActuallyRedefinesSpecialFunction() { - evaluateString("(defmacro myMacro () nil)"); - evaluateString("(defmacro myMacro () T)"); - - assertSomethingPrinted(); - assertSExpressionsMatch(parseString("t"), evaluateString("(myMacro)")); - } - - @Test(expected = DottedArgumentListException.class) - public void defmacroWithDottedLambdaList() { - evaluateString("(funcall 'defmacro 'm (cons 'a 'b) ())"); - } - - @Test(expected = BadArgumentTypeException.class) - public void defmacroWithNonSymbolName() { - evaluateString("(defmacro 1 () ())"); - } - - @Test(expected = BadArgumentTypeException.class) - public void defmacroWithBadLambdaList() { - evaluateString("(defmacro m a ())"); - } - - @Test(expected = TooFewArgumentsException.class) - public void defmacroWithTooFewArguments() { - evaluateString("(defmacro m)"); - } - - @Test(expected = TooFewArgumentsException.class) - public void defmacroAndCallWithTooFewArguments() { - evaluateString("(defmacro m (a b))"); - evaluateString("(m a)"); - } - - @Test(expected = TooManyArgumentsException.class) - public void defmacroAndCallWithTooManyArguments() { - evaluateString("(defmacro m (a b))"); - evaluateString("(m a b c)"); - } - - @Test - public void defmacroWithKeywordRestParameter() { - evaluateString("(defmacro m (&rest x) (car x))"); - assertSExpressionsMatch(parseString("1"), evaluateString("(m 1 2 3 4 5)")); - } - - @Test - public void defmacroWithNormalAndKeywordRestParameter() { - evaluateString("(defmacro m (a &rest b) (list 'cons a (list 'quote b)))"); - assertSExpressionsMatch(parseString("(1 2 3 4 5)"), evaluateString("(m 1 2 3 4 5)")); - } - - @Test(expected = IllegalKeywordRestPositionException.class) - public void defmacroWithParametersFollowingKeywordRest() { - evaluateString("(defmacro m (a &rest b c) (cons a b))"); - evaluateString("(m 1 2 3)"); - } - - @Test - public void defmacroWithKeywordRest_CallWithNoArguments() { - evaluateString("(defmacro m (&rest a) (car a))"); - assertSExpressionsMatch(parseString("nil"), evaluateString("(m)")); - } - - @Test(expected = TooFewArgumentsException.class) - public void defmacroWithNormalAndKeywordRest_CallWithNoArguments() { - evaluateString("(defmacro m (a &rest b) a)"); - evaluateString("(m)"); - } - - @Test - public void macroIsEvaluatedAfterExpansion() { - evaluateString("(setq x 'grains)"); - evaluateString("(defmacro m (x) x)"); - evaluateString("(m (setq x 'sprouts))"); - - assertSExpressionsMatch(parseString("sprouts"), evaluateString("x")); - } - - @Test - public void macroIsEvaluatedCorrectly() { - evaluateString("(defmacro m (x) `'(+ 2 ,x))"); - assertSExpressionsMatch(parseString("(+ 2 25)"), evaluateString("(m 25)")); - } -} diff --git a/src/test/kotlin/function/builtin/special/DefmacroTest.kt b/src/test/kotlin/function/builtin/special/DefmacroTest.kt new file mode 100644 index 0000000..2c44fcb --- /dev/null +++ b/src/test/kotlin/function/builtin/special/DefmacroTest.kt @@ -0,0 +1,198 @@ +package function.builtin.special + +import environment.RuntimeEnvironment +import error.ErrorManager +import function.ArgumentValidator.BadArgumentTypeException +import function.ArgumentValidator.DottedArgumentListException +import function.ArgumentValidator.TooFewArgumentsException +import function.ArgumentValidator.TooManyArgumentsException +import function.UserDefinedFunction.IllegalKeywordRestPositionException +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Assertions.assertThrows +import org.junit.jupiter.api.Test +import testutil.SymbolAndFunctionCleaner +import testutil.TestUtilities.assertSExpressionsMatch +import testutil.TestUtilities.evaluateString +import testutil.TestUtilities.parseString +import java.io.ByteArrayOutputStream +import java.io.PrintStream + +class DefmacroTest : SymbolAndFunctionCleaner() { + + private var outputStream = ByteArrayOutputStream() + + private fun assertSomethingPrinted() { + assertThat(outputStream.toByteArray()).isNotEmpty() + } + + override fun additionalSetUp() { + outputStream.reset() + RuntimeEnvironment.reset() + RuntimeEnvironment.output = PrintStream(outputStream) + RuntimeEnvironment.errorManager = ErrorManager() + RuntimeEnvironment.warningOutputDecorator = { it } + } + + override fun additionalTearDown() { + RuntimeEnvironment.reset() + } + + @Test + fun defmacro() { + val input = "(defmacro m () t)" + + assertSExpressionsMatch(parseString("m"), evaluateString(input)) + assertSExpressionsMatch(parseString("t"), evaluateString("(m)")) + } + + @Test + fun defmacroWithEmptyBody() { + val input = "(defmacro m ())" + + assertSExpressionsMatch(parseString("m"), evaluateString(input)) + assertSExpressionsMatch(parseString("()"), evaluateString("(m)")) + } + + @Test + fun defmacroDoesNotEvaluateArguments() { + evaluateString("(setq x 'grains)") + evaluateString("(defmacro m (x))") + evaluateString("(m (setq x 'sprouts))") + + assertSExpressionsMatch(parseString("grains"), evaluateString("x")) + } + + @Test + fun defmacroAdd() { + evaluateString("(defmacro m (x) (+ (eval x) 23))") + assertSExpressionsMatch(parseString("27"), evaluateString("(m (+ 2 2))")) + } + + @Test + fun defmacroSetVariable() { + evaluateString("(defmacro m (x) (set x 23))") + evaluateString("(m y)") + assertSExpressionsMatch(parseString("23"), evaluateString("y")) + } + + @Test + fun defmacroVariableCapture() { + evaluateString("(setq x 0)") + evaluateString("(defmacro m (x) (set x 23))") + evaluateString("(m x)") + assertSExpressionsMatch(parseString("0"), evaluateString("x")) + } + + @Test + fun redefineMacro_DisplaysWarning() { + val input = "(defmacro myMacro () nil)" + evaluateString(input) + evaluateString(input) + + assertSomethingPrinted() + } + + @Test + fun redefineMacro_ActuallyRedefinesSpecialFunction() { + evaluateString("(defmacro myMacro () nil)") + evaluateString("(defmacro myMacro () T)") + + assertSomethingPrinted() + assertSExpressionsMatch(parseString("t"), evaluateString("(myMacro)")) + } + + @Test + fun defmacroWithDottedLambdaList() { + assertThrows(DottedArgumentListException::class.java) { + evaluateString("(funcall 'defmacro 'm (cons 'a 'b) ())") + } + } + + @Test + fun defmacroWithNonSymbolName() { + assertThrows(BadArgumentTypeException::class.java) { + evaluateString("(defmacro 1 () ())") + } + } + + @Test + fun defmacroWithBadLambdaList() { + assertThrows(BadArgumentTypeException::class.java) { + evaluateString("(defmacro m a ())") + } + } + + @Test + fun defmacroWithTooFewArguments() { + assertThrows(TooFewArgumentsException::class.java) { + evaluateString("(defmacro m)") + } + } + + @Test + fun defmacroAndCallWithTooFewArguments() { + evaluateString("(defmacro m (a b))") + + assertThrows(TooFewArgumentsException::class.java) { + evaluateString("(m a)") + } + } + + @Test + fun defmacroAndCallWithTooManyArguments() { + evaluateString("(defmacro m (a b))") + + assertThrows(TooManyArgumentsException::class.java) { + evaluateString("(m a b c)") + } + } + + @Test + fun defmacroWithKeywordRestParameter() { + evaluateString("(defmacro m (&rest x) (car x))") + assertSExpressionsMatch(parseString("1"), evaluateString("(m 1 2 3 4 5)")) + } + + @Test + fun defmacroWithNormalAndKeywordRestParameter() { + evaluateString("(defmacro m (a &rest b) (list 'cons a (list 'quote b)))") + assertSExpressionsMatch(parseString("(1 2 3 4 5)"), evaluateString("(m 1 2 3 4 5)")) + } + + @Test + fun defmacroWithParametersFollowingKeywordRest() { + assertThrows(IllegalKeywordRestPositionException::class.java) { + evaluateString("(defmacro m (a &rest b c) (cons a b))") + } + } + + @Test + fun defmacroWithKeywordRest_CallWithNoArguments() { + evaluateString("(defmacro m (&rest a) (car a))") + assertSExpressionsMatch(parseString("nil"), evaluateString("(m)")) + } + + @Test + fun defmacroWithNormalAndKeywordRest_CallWithNoArguments() { + evaluateString("(defmacro m (a &rest b) a)") + + assertThrows(TooFewArgumentsException::class.java) { + evaluateString("(m)") + } + } + + @Test + fun macroIsEvaluatedAfterExpansion() { + evaluateString("(setq x 'grains)") + evaluateString("(defmacro m (x) x)") + evaluateString("(m (setq x 'sprouts))") + + assertSExpressionsMatch(parseString("sprouts"), evaluateString("x")) + } + + @Test + fun macroIsEvaluatedCorrectly() { + evaluateString("(defmacro m (x) `'(+ 2 ,x))") + assertSExpressionsMatch(parseString("(+ 2 25)"), evaluateString("(m 25)")) + } +} diff --git a/src/test/kotlin/function/builtin/special/DefunTest.java b/src/test/kotlin/function/builtin/special/DefunTest.java deleted file mode 100644 index a75de22..0000000 --- a/src/test/kotlin/function/builtin/special/DefunTest.java +++ /dev/null @@ -1,187 +0,0 @@ -package function.builtin.special; - -import environment.RuntimeEnvironment; -import error.ErrorManager; -import function.ArgumentValidator.BadArgumentTypeException; -import function.ArgumentValidator.DottedArgumentListException; -import function.ArgumentValidator.TooFewArgumentsException; -import function.ArgumentValidator.TooManyArgumentsException; -import function.UserDefinedFunction.IllegalKeywordRestPositionException; -import org.junit.Test; -import testutil.SymbolAndFunctionCleaner; - -import java.io.ByteArrayOutputStream; -import java.io.PrintStream; - -import static org.junit.Assert.assertTrue; -import static testutil.TestUtilities.assertSExpressionsMatch; -import static testutil.TestUtilities.evaluateString; -import static testutil.TestUtilities.parseString; - -public class DefunTest extends SymbolAndFunctionCleaner { - - private ByteArrayOutputStream outputStream; - private RuntimeEnvironment environment; - - public DefunTest() { - this.environment = RuntimeEnvironment.INSTANCE; - } - - private void assertSomethingPrinted() { - assertTrue(outputStream.toByteArray().length > 0); - } - - @Override - public void additionalSetUp() { - outputStream = new ByteArrayOutputStream(); - - environment.reset(); - environment.setOutput(new PrintStream(outputStream)); - environment.setErrorManager(new ErrorManager()); - environment.setWarningOutputDecorator(s -> s); - } - - @Override - public void additionalTearDown() { - environment.reset(); - } - - @Test - public void defun() { - String input = "(defun f () t)"; - - assertSExpressionsMatch(parseString("f"), evaluateString(input)); - assertSExpressionsMatch(parseString("t"), evaluateString("(f)")); - } - - @Test - public void defunWithEmptyBody() { - String input = "(defun f ())"; - - assertSExpressionsMatch(parseString("f"), evaluateString(input)); - assertSExpressionsMatch(parseString("()"), evaluateString("(f)")); - } - - @Test - public void defunEvaluatesArguments() { - evaluateString("(defun f (x) (car x))"); - assertSExpressionsMatch(parseString("1"), evaluateString("(f '(1 2 3))")); - } - - @Test - public void defunRecursiveFunction() { - evaluateString("(defun fact (x) (if (< x 2) 1 (* x (fact (- x 1)))))"); - assertSExpressionsMatch(parseString("120"), evaluateString("(fact 5)")); - } - - @Test - public void defunTailRecursiveFunction() { - evaluateString("(defun fact-tail (x acc) (if (< x 2) acc (fact-tail (- x 1) (* x acc))))"); - assertSExpressionsMatch(parseString("120"), evaluateString("(fact-tail 5 1)")); - } - - @Test - public void defunSimpleClass() { - evaluateString("(defun counter-class () (let ((counter 0)) (lambda () (setq counter (+ 1 counter)))))"); - evaluateString("(setq my-counter (counter-class))"); - - assertSExpressionsMatch(parseString("1"), evaluateString("(funcall my-counter)")); - assertSExpressionsMatch(parseString("2"), evaluateString("(funcall my-counter)")); - assertSExpressionsMatch(parseString("3"), evaluateString("(funcall my-counter)")); - assertSExpressionsMatch(parseString("4"), evaluateString("(funcall my-counter)")); - } - - @Test - public void redefineFunction_DisplaysWarning() { - String input = "(defun myFunction () nil)"; - evaluateString(input); - evaluateString(input); - - assertSomethingPrinted(); - } - - @Test - public void redefineFunction_ActuallyRedefinesFunction() { - evaluateString("(defun myFunction () nil)"); - evaluateString("(defun myFunction () T)"); - - assertSomethingPrinted(); - assertSExpressionsMatch(parseString("t"), evaluateString("(myFunction)")); - } - - @Test(expected = DottedArgumentListException.class) - public void defunWithDottedLambdaList() { - evaluateString("(funcall 'defun 'f (cons 'a 'b) ())"); - } - - @Test(expected = BadArgumentTypeException.class) - public void defunWithNonSymbolName() { - evaluateString("(defun 1 () ())"); - } - - @Test(expected = BadArgumentTypeException.class) - public void defunWithBadLambdaList() { - evaluateString("(defun f a ())"); - } - - @Test(expected = BadArgumentTypeException.class) - public void defunWithNonSymbolInLambdaList() { - evaluateString("(defun f (1) ())"); - } - - @Test(expected = TooFewArgumentsException.class) - public void defunWithTooFewArguments() { - evaluateString("(defun f)"); - } - - @Test(expected = TooFewArgumentsException.class) - public void defunFunctionAndCallWithTooFewArguments() { - evaluateString("(defun f (a b))"); - evaluateString("(f 'a)"); - } - - @Test(expected = TooManyArgumentsException.class) - public void defunFunctionAndCallWithTooManyArguments() { - evaluateString("(defun f (a b))"); - evaluateString("(f 'a 'b 'c)"); - } - - @Test - public void defunWithKeywordRestParameter() { - evaluateString("(defun f (&rest x) (car x))"); - assertSExpressionsMatch(parseString("1"), evaluateString("(f 1 2 3 4 5)")); - } - - @Test - public void defunWithNormalAndKeywordRestParameter() { - evaluateString("(defun f (a &rest b) (cons a b))"); - assertSExpressionsMatch(parseString("(1 2 3 4 5)"), evaluateString("(f 1 2 3 4 5)")); - } - - @Test(expected = IllegalKeywordRestPositionException.class) - public void defunWithParametersFollowingKeywordRest() { - evaluateString("(defun f (a &rest b c) (cons a b))"); - evaluateString("(f 1 2 3)"); - } - - @Test - public void defunWithKeywordRest_CallWithNoArguments() { - evaluateString("(defun f (&rest a) (car a))"); - assertSExpressionsMatch(parseString("nil"), evaluateString("(f)")); - } - - @Test(expected = TooFewArgumentsException.class) - public void defunWithNormalAndKeywordRest_CallWithNoArguments() { - evaluateString("(defun f (a &rest b) a)"); - evaluateString("(f)"); - } - - @Test - public void resultOfFunctionIsNotEvaluated() { - evaluateString("(setq x 'grains)"); - evaluateString("(define-special f (x) 'x)"); - evaluateString("(f (setq x 'sprouts))"); - - assertSExpressionsMatch(parseString("grains"), evaluateString("x")); - } -} diff --git a/src/test/kotlin/function/builtin/special/DefunTest.kt b/src/test/kotlin/function/builtin/special/DefunTest.kt new file mode 100644 index 0000000..2acd4f8 --- /dev/null +++ b/src/test/kotlin/function/builtin/special/DefunTest.kt @@ -0,0 +1,198 @@ +package function.builtin.special + +import environment.RuntimeEnvironment +import error.ErrorManager +import function.ArgumentValidator.BadArgumentTypeException +import function.ArgumentValidator.DottedArgumentListException +import function.ArgumentValidator.TooFewArgumentsException +import function.ArgumentValidator.TooManyArgumentsException +import function.UserDefinedFunction.IllegalKeywordRestPositionException +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Assertions.assertThrows +import org.junit.jupiter.api.Test +import testutil.SymbolAndFunctionCleaner +import testutil.TestUtilities.assertSExpressionsMatch +import testutil.TestUtilities.evaluateString +import testutil.TestUtilities.parseString +import java.io.ByteArrayOutputStream +import java.io.PrintStream + +class DefunTest : SymbolAndFunctionCleaner() { + + private var outputStream = ByteArrayOutputStream() + + private fun assertSomethingPrinted() { + assertThat(outputStream.toByteArray()).isNotEmpty() + } + + override fun additionalSetUp() { + outputStream.reset() + RuntimeEnvironment.reset() + RuntimeEnvironment.output = PrintStream(outputStream) + RuntimeEnvironment.errorManager = ErrorManager() + RuntimeEnvironment.warningOutputDecorator = { it } + } + + override fun additionalTearDown() { + RuntimeEnvironment.reset() + } + + @Test + fun defun() { + val input = "(defun f () t)" + + assertSExpressionsMatch(parseString("f"), evaluateString(input)) + assertSExpressionsMatch(parseString("t"), evaluateString("(f)")) + } + + @Test + fun defunWithEmptyBody() { + val input = "(defun f ())" + + assertSExpressionsMatch(parseString("f"), evaluateString(input)) + assertSExpressionsMatch(parseString("()"), evaluateString("(f)")) + } + + @Test + fun defunEvaluatesArguments() { + evaluateString("(defun f (x) (car x))") + assertSExpressionsMatch(parseString("1"), evaluateString("(f '(1 2 3))")) + } + + @Test + fun defunRecursiveFunction() { + evaluateString("(defun fact (x) (if (< x 2) 1 (* x (fact (- x 1)))))") + assertSExpressionsMatch(parseString("120"), evaluateString("(fact 5)")) + } + + @Test + fun defunTailRecursiveFunction() { + evaluateString("(defun fact-tail (x acc) (if (< x 2) acc (fact-tail (- x 1) (* x acc))))") + assertSExpressionsMatch(parseString("120"), evaluateString("(fact-tail 5 1)")) + } + + @Test + fun defunSimpleClass() { + evaluateString("(defun counter-class () (let ((counter 0)) (lambda () (setq counter (+ 1 counter)))))") + evaluateString("(setq my-counter (counter-class))") + + assertSExpressionsMatch(parseString("1"), evaluateString("(funcall my-counter)")) + assertSExpressionsMatch(parseString("2"), evaluateString("(funcall my-counter)")) + assertSExpressionsMatch(parseString("3"), evaluateString("(funcall my-counter)")) + assertSExpressionsMatch(parseString("4"), evaluateString("(funcall my-counter)")) + } + + @Test + fun redefineFunction_DisplaysWarning() { + val input = "(defun myFunction () nil)" + evaluateString(input) + evaluateString(input) + + assertSomethingPrinted() + } + + @Test + fun redefineFunction_ActuallyRedefinesFunction() { + evaluateString("(defun myFunction () nil)") + evaluateString("(defun myFunction () T)") + + assertSomethingPrinted() + assertSExpressionsMatch(parseString("t"), evaluateString("(myFunction)")) + } + + @Test + fun defunWithDottedLambdaList() { + assertThrows(DottedArgumentListException::class.java) { + evaluateString("(funcall 'defun 'f (cons 'a 'b) ())") + } + } + + @Test + fun defunWithNonSymbolName() { + assertThrows(BadArgumentTypeException::class.java) { + evaluateString("(defun 1 () ())") + } + } + + @Test + fun defunWithBadLambdaList() { + assertThrows(BadArgumentTypeException::class.java) { + evaluateString("(defun f a ())") + } + } + + @Test + fun defunWithNonSymbolInLambdaList() { + assertThrows(BadArgumentTypeException::class.java) { + evaluateString("(defun f (1) ())") + } + } + + @Test + fun defunWithTooFewArguments() { + assertThrows(TooFewArgumentsException::class.java) { + evaluateString("(defun f)") + } + } + + @Test + fun defunFunctionAndCallWithTooFewArguments() { + evaluateString("(defun f (a b))") + + assertThrows(TooFewArgumentsException::class.java) { + evaluateString("(f 'a)") + } + } + + @Test + fun defunFunctionAndCallWithTooManyArguments() { + evaluateString("(defun f (a b))") + + assertThrows(TooManyArgumentsException::class.java) { + evaluateString("(f 'a 'b 'c)") + } + } + + @Test + fun defunWithKeywordRestParameter() { + evaluateString("(defun f (&rest x) (car x))") + assertSExpressionsMatch(parseString("1"), evaluateString("(f 1 2 3 4 5)")) + } + + @Test + fun defunWithNormalAndKeywordRestParameter() { + evaluateString("(defun f (a &rest b) (cons a b))") + assertSExpressionsMatch(parseString("(1 2 3 4 5)"), evaluateString("(f 1 2 3 4 5)")) + } + + @Test + fun defunWithParametersFollowingKeywordRest() { + assertThrows(IllegalKeywordRestPositionException::class.java) { + evaluateString("(defun f (a &rest b c) (cons a b))") + } + } + + @Test + fun defunWithKeywordRest_CallWithNoArguments() { + evaluateString("(defun f (&rest a) (car a))") + assertSExpressionsMatch(parseString("nil"), evaluateString("(f)")) + } + + @Test + fun defunWithNormalAndKeywordRest_CallWithNoArguments() { + evaluateString("(defun f (a &rest b) a)") + + assertThrows(TooFewArgumentsException::class.java) { + evaluateString("(f)") + } + } + + @Test + fun resultOfFunctionIsNotEvaluated() { + evaluateString("(setq x 'grains)") + evaluateString("(define-special f (x) 'x)") + evaluateString("(f (setq x 'sprouts))") + + assertSExpressionsMatch(parseString("grains"), evaluateString("x")) + } +}