From ce2a8f1cb7981cca6a21940ae6331d515daab228 Mon Sep 17 00:00:00 2001 From: Geoffrey Challen Date: Tue, 29 Jun 2021 13:12:10 -0500 Subject: [PATCH] Better test for receivers. --- src/main/kotlin/Annotations.kt | 17 +++++++++++++++-- src/main/kotlin/generators/Parameters.kt | 16 +++++++++++----- .../edu.illinois.cs.cs125.jenisol.core.version | 2 +- .../cs/cs125/jenisol/core/TestJavaExamples.kt | 6 ++++++ .../java/noreceiver/kotlinmap/Correct.java | 13 +++++++++++++ .../java/noreceiver/kotlinmap/Correct0.kt | 9 +++++++++ .../java/noreceiver/kotlinmap/Incorrect0.java | 9 +++++++++ .../java/noreceiver/kotlinprintmap/Correct.java | 11 +++++++++++ .../java/noreceiver/kotlinprintmap/Correct0.kt | 7 +++++++ .../noreceiver/kotlinprintmap/Incorrect0.java | 9 +++++++++ 10 files changed, 91 insertions(+), 8 deletions(-) create mode 100644 src/test/java/examples/java/noreceiver/kotlinmap/Correct.java create mode 100644 src/test/java/examples/java/noreceiver/kotlinmap/Correct0.kt create mode 100644 src/test/java/examples/java/noreceiver/kotlinmap/Incorrect0.java create mode 100644 src/test/java/examples/java/noreceiver/kotlinprintmap/Correct.java create mode 100644 src/test/java/examples/java/noreceiver/kotlinprintmap/Correct0.kt create mode 100644 src/test/java/examples/java/noreceiver/kotlinprintmap/Incorrect0.java diff --git a/src/main/kotlin/Annotations.kt b/src/main/kotlin/Annotations.kt index aa47aeb..af46143 100644 --- a/src/main/kotlin/Annotations.kt +++ b/src/main/kotlin/Annotations.kt @@ -86,7 +86,7 @@ fun Method.isRandomType() = isAnnotationPresent(RandomType::class.java) annotation class FixedParameters(val methodName: String = "") { companion object { val name: String = FixedParameters::class.java.simpleName - fun validate(field: Field): Array { + fun validate(field: Field, solution: Class<*>): Array { check(field.isPrivate()) { "@$name fields must be private" } check(field.isStatic()) { "@$name fields must be static" } check(field.genericType is ParameterizedType) { @@ -102,6 +102,12 @@ annotation class FixedParameters(val methodName: String = "") { itemType.actualTypeArguments } else { arrayOf(itemType) + }.also { types -> + check(solution !in types) { + """@$name parameter fields cannot container receiver types. + |Generate receivers by targeting the constructor or factory method with @$name""" + .trimMargin() + } } } } @@ -118,7 +124,7 @@ fun Field.fixedParametersMatchAll() = this.getAnnotation(FixedParameters::class. annotation class RandomParameters(val methodName: String = "") { companion object { val name: String = RandomParameters::class.java.simpleName - fun validate(method: Method): Array { + fun validate(method: Method, solution: Class<*>): Array { check(method.isPrivate()) { "@$name methods must be private" } val message = "@$name methods must either accept parameters (java.util.Random random) " + "or (int complexity, java.util.Random random)" @@ -139,6 +145,13 @@ annotation class RandomParameters(val methodName: String = "") { (method.genericReturnType as ParameterizedType).actualTypeArguments } else { arrayOf(method.genericReturnType) + }.also { types -> + check(solution !in types) { + """ + |@$name return values cannot container receiver types. + |Generate receivers by targeting the constructor or factory method with @$name""" + .trimMargin().trim() + } } } } diff --git a/src/main/kotlin/generators/Parameters.kt b/src/main/kotlin/generators/Parameters.kt index 950baeb..0cf811a 100644 --- a/src/main/kotlin/generators/Parameters.kt +++ b/src/main/kotlin/generators/Parameters.kt @@ -478,7 +478,7 @@ class MethodParametersGeneratorGenerator(val target: Executable, val solution: C fixedParameters = solution.declaredFields .filter { field -> field.isFixedParameters() } .filter { field -> - FixedParameters.validate(field).compareBoxed(parameterTypes) + FixedParameters.validate(field, solution).compareBoxed(parameterTypes) }.filter { field -> field.getRandomParametersMethodName().let { if (it.isNotBlank()) { @@ -504,9 +504,15 @@ class MethodParametersGeneratorGenerator(val target: Executable, val solution: C } catch (e: ClassCastException) { values.map { One(it) } } - actualValues.forEach { - val solutionParameters = it.deepCopy() - val submissionParameters = it.deepCopy() + actualValues.forEach { group -> + check(group.toList().none { it != null && it::class.java == solution }) { + """ + |@${FixedParameters.name} field should not contain receiver objects, since this will not work as you expect. + |Target the constructor with @${FixedParameters.name} if you need to create receivers.""" + .trimMargin().trim() + } + val solutionParameters = group.deepCopy() + val submissionParameters = group.deepCopy() check(solutionParameters !== submissionParameters) { "@${FixedParameters.name} field produces referentially equal copies" } @@ -518,7 +524,7 @@ class MethodParametersGeneratorGenerator(val target: Executable, val solution: C } randomParameters = solution.declaredMethods .filter { method -> method.isRandomParameters() } - .filter { method -> RandomParameters.validate(method).compareBoxed(parameterTypes) } + .filter { method -> RandomParameters.validate(method, solution).compareBoxed(parameterTypes) } .filter { method -> method.getRandomParametersMethodName().let { if (it.isNotBlank()) { diff --git a/src/main/resources/edu.illinois.cs.cs125.jenisol.core.version b/src/main/resources/edu.illinois.cs.cs125.jenisol.core.version index c001f19..b482b47 100644 --- a/src/main/resources/edu.illinois.cs.cs125.jenisol.core.version +++ b/src/main/resources/edu.illinois.cs.cs125.jenisol.core.version @@ -1 +1 @@ -version=2021.6.4 \ No newline at end of file +version=2021.6.5 \ No newline at end of file diff --git a/src/test/java/edu/illinois/cs/cs125/jenisol/core/TestJavaExamples.kt b/src/test/java/edu/illinois/cs/cs125/jenisol/core/TestJavaExamples.kt index c0a2018..5014063 100644 --- a/src/test/java/edu/illinois/cs/cs125/jenisol/core/TestJavaExamples.kt +++ b/src/test/java/edu/illinois/cs/cs125/jenisol/core/TestJavaExamples.kt @@ -289,6 +289,12 @@ class TestJavaExamples : StringSpec( examples.java.noreceiver.customtypewithembeddedgenerators.Correct::class.java.also { "${it.testName()}" { it.test() } } + examples.java.noreceiver.kotlinmap.Correct::class.java.also { + "${it.testName()}" { it.test() } + } + examples.java.noreceiver.kotlinprintmap.Correct::class.java.also { + "${it.testName()}" { it.test() } + } examples.java.receiver.timeouttest.Correct::class.java.also { "${it.testName()}" { val runnable = object : Runnable { diff --git a/src/test/java/examples/java/noreceiver/kotlinmap/Correct.java b/src/test/java/examples/java/noreceiver/kotlinmap/Correct.java new file mode 100644 index 0000000..7938d52 --- /dev/null +++ b/src/test/java/examples/java/noreceiver/kotlinmap/Correct.java @@ -0,0 +1,13 @@ +package examples.java.noreceiver.kotlinmap; + +import java.util.Map; + +public class Correct { + public static int sumValues(Map map) { + int sum = 0; + for (int value : map.values()) { + sum += value; + } + return sum; + } +} diff --git a/src/test/java/examples/java/noreceiver/kotlinmap/Correct0.kt b/src/test/java/examples/java/noreceiver/kotlinmap/Correct0.kt new file mode 100644 index 0000000..1f5dfe7 --- /dev/null +++ b/src/test/java/examples/java/noreceiver/kotlinmap/Correct0.kt @@ -0,0 +1,9 @@ +package examples.java.noreceiver.kotlinmap + +fun sumValues(map: Map): Int { + var sum = 0 + for (value in map.values) { + sum += value + } + return sum +} \ No newline at end of file diff --git a/src/test/java/examples/java/noreceiver/kotlinmap/Incorrect0.java b/src/test/java/examples/java/noreceiver/kotlinmap/Incorrect0.java new file mode 100644 index 0000000..1a72558 --- /dev/null +++ b/src/test/java/examples/java/noreceiver/kotlinmap/Incorrect0.java @@ -0,0 +1,9 @@ +package examples.java.noreceiver.kotlinmap; + +import java.util.Map; + +public class Incorrect0 { + public static int sumValues(Map map) { + return 0; + } +} diff --git a/src/test/java/examples/java/noreceiver/kotlinprintmap/Correct.java b/src/test/java/examples/java/noreceiver/kotlinprintmap/Correct.java new file mode 100644 index 0000000..96b8ab3 --- /dev/null +++ b/src/test/java/examples/java/noreceiver/kotlinprintmap/Correct.java @@ -0,0 +1,11 @@ +package examples.java.noreceiver.kotlinprintmap; + +import java.util.Map; + +public class Correct { + public static void printValues(Map map) { + for (int value : map.values()) { + System.out.println(value); + } + } +} diff --git a/src/test/java/examples/java/noreceiver/kotlinprintmap/Correct0.kt b/src/test/java/examples/java/noreceiver/kotlinprintmap/Correct0.kt new file mode 100644 index 0000000..5e8c8e3 --- /dev/null +++ b/src/test/java/examples/java/noreceiver/kotlinprintmap/Correct0.kt @@ -0,0 +1,7 @@ +package examples.java.noreceiver.kotlinprintmap + +fun printValues(map: Map) { + for (value in map.values) { + println(value) + } +} \ No newline at end of file diff --git a/src/test/java/examples/java/noreceiver/kotlinprintmap/Incorrect0.java b/src/test/java/examples/java/noreceiver/kotlinprintmap/Incorrect0.java new file mode 100644 index 0000000..39d8f29 --- /dev/null +++ b/src/test/java/examples/java/noreceiver/kotlinprintmap/Incorrect0.java @@ -0,0 +1,9 @@ +package examples.java.noreceiver.kotlinprintmap; + +import java.util.Map; + +public class Incorrect0 { + public static void printValues(Map map) { + return; + } +}