diff --git a/kotlin-native/backend.native/tests/stdlib_external/utils.kt b/kotlin-native/backend.native/tests/stdlib_external/utils.kt index 08b03e7ee97..2e8ba0ab2c1 100644 --- a/kotlin-native/backend.native/tests/stdlib_external/utils.kt +++ b/kotlin-native/backend.native/tests/stdlib_external/utils.kt @@ -32,4 +32,14 @@ public actual val supportsSuppressedExceptions: Boolean get() = true public actual val supportsNamedCapturingGroup: Boolean get() = true -public actual val regexSplitUnicodeCodePointHandling: Boolean get() = true \ No newline at end of file +public actual val regexSplitUnicodeCodePointHandling: Boolean get() = true + +public actual object BackReferenceHandling { + actual val captureLargestValidIndex: Boolean get() = true + + actual val notYetDefinedGroup: HandlingOption = HandlingOption.THROW + actual val notYetDefinedNamedGroup: HandlingOption = HandlingOption.THROW + actual val enclosingGroup: HandlingOption = HandlingOption.MATCH_NOTHING + actual val nonExistentGroup: HandlingOption = HandlingOption.THROW + actual val nonExistentNamedGroup: HandlingOption = HandlingOption.THROW +} \ No newline at end of file diff --git a/libraries/stdlib/common/test/testUtils.kt b/libraries/stdlib/common/test/testUtils.kt index 22c30e289d7..a5e01f4422f 100644 --- a/libraries/stdlib/common/test/testUtils.kt +++ b/libraries/stdlib/common/test/testUtils.kt @@ -20,4 +20,18 @@ public expect val supportsSuppressedExceptions: Boolean public expect val supportsNamedCapturingGroup: Boolean -public expect val regexSplitUnicodeCodePointHandling: Boolean \ No newline at end of file +public expect val regexSplitUnicodeCodePointHandling: Boolean + +public enum class HandlingOption { + MATCH_NOTHING, THROW, IGNORE_BACK_REFERENCE_EXPRESSION +} + +public expect object BackReferenceHandling { + val captureLargestValidIndex: Boolean + + val notYetDefinedGroup: HandlingOption + val notYetDefinedNamedGroup: HandlingOption + val enclosingGroup: HandlingOption + val nonExistentGroup: HandlingOption + val nonExistentNamedGroup: HandlingOption +} \ No newline at end of file diff --git a/libraries/stdlib/js/test/core/testUtils.kt b/libraries/stdlib/js/test/core/testUtils.kt index 8266e371fb1..0cd6dcae8c5 100644 --- a/libraries/stdlib/js/test/core/testUtils.kt +++ b/libraries/stdlib/js/test/core/testUtils.kt @@ -29,4 +29,14 @@ actual val supportsSuppressedExceptions: Boolean get() = true public actual val supportsNamedCapturingGroup: Boolean get() = true -public actual val regexSplitUnicodeCodePointHandling: Boolean get() = true \ No newline at end of file +public actual val regexSplitUnicodeCodePointHandling: Boolean get() = true + +public actual object BackReferenceHandling { + actual val captureLargestValidIndex: Boolean get() = false + + actual val notYetDefinedGroup: HandlingOption = HandlingOption.IGNORE_BACK_REFERENCE_EXPRESSION + actual val notYetDefinedNamedGroup: HandlingOption = HandlingOption.IGNORE_BACK_REFERENCE_EXPRESSION + actual val enclosingGroup: HandlingOption = HandlingOption.IGNORE_BACK_REFERENCE_EXPRESSION + actual val nonExistentGroup: HandlingOption = HandlingOption.THROW + actual val nonExistentNamedGroup: HandlingOption = HandlingOption.THROW +} \ No newline at end of file diff --git a/libraries/stdlib/jvm/test/testUtilsJVM.kt b/libraries/stdlib/jvm/test/testUtilsJVM.kt index 5a9dbff4ce6..6823759b78e 100644 --- a/libraries/stdlib/jvm/test/testUtilsJVM.kt +++ b/libraries/stdlib/jvm/test/testUtilsJVM.kt @@ -43,4 +43,14 @@ public actual val supportsSuppressedExceptions: Boolean get() = !isJava6 public actual val supportsNamedCapturingGroup: Boolean get() = !isJava6 -public actual val regexSplitUnicodeCodePointHandling: Boolean get() = false \ No newline at end of file +public actual val regexSplitUnicodeCodePointHandling: Boolean get() = false + +public actual object BackReferenceHandling { + actual val captureLargestValidIndex: Boolean get() = true + + actual val notYetDefinedGroup: HandlingOption = HandlingOption.MATCH_NOTHING + actual val notYetDefinedNamedGroup: HandlingOption = HandlingOption.THROW + actual val enclosingGroup: HandlingOption = HandlingOption.MATCH_NOTHING + actual val nonExistentGroup: HandlingOption = HandlingOption.MATCH_NOTHING + actual val nonExistentNamedGroup: HandlingOption = HandlingOption.THROW +} \ No newline at end of file diff --git a/libraries/stdlib/test/text/RegexTest.kt b/libraries/stdlib/test/text/RegexTest.kt index 584487069a5..30015647d0c 100644 --- a/libraries/stdlib/test/text/RegexTest.kt +++ b/libraries/stdlib/test/text/RegexTest.kt @@ -9,6 +9,8 @@ package test.text import test.regexSplitUnicodeCodePointHandling import test.supportsNamedCapturingGroup +import test.BackReferenceHandling +import test.HandlingOption import kotlin.test.* class RegexTest { @@ -216,13 +218,16 @@ class RegexTest { } // capture the largest valid group index - "(\\w+), yes \\12".toRegex().let { regex -> - val match = regex.find("Do you copy? Sir, yes Sir2")!! - assertEquals("Sir, yes Sir2", match.value) - assertEquals("Sir", match.groups[1]?.value) + "(\\w+), yes \\12".let { pattern -> + if (BackReferenceHandling.captureLargestValidIndex) { + val match = pattern.toRegex().find("Do you copy? Sir, yes Sir2")!! + assertEquals("Sir, yes Sir2", match.value) + assertEquals("Sir", match.groups[1]?.value) + } else { + // JS throws SyntaxError + assertFails { pattern.toRegex() } + } } - // back reference to non-existent group - assertNull("a(a)\\21".toRegex().find("aaaa1")) // back reference to a group with large index "0(1(2(3(4(5(6(7(8(9(A(B(C))))))))\\11))))".toRegex().let { regex -> @@ -232,10 +237,9 @@ class RegexTest { assertEquals("456789ABCBC", match.groups[4]?.value) } - // back reference to an enclosing group - assertNull("a(a\\1)".toRegex().find("aaaa")) - // back reference to not yet available group - assertNull("a\\1(a)".toRegex().find("aaaa")) + testInvalidBackReference(BackReferenceHandling.nonExistentGroup, pattern = "a(a)\\2") + testInvalidBackReference(BackReferenceHandling.enclosingGroup, pattern = "a(a\\1)") + testInvalidBackReference(BackReferenceHandling.notYetDefinedGroup, pattern = "a\\1(a)") } @Test fun matchNamedGroupsWithBackReference() { @@ -249,38 +253,51 @@ class RegexTest { assertNull(regex.find("Do you copy? Sir, yes I do!")) } - // back reference to an enclosing group - assertNull("a(?a\\k)".toRegex().find("aaaa")) - // back reference to not yet available group - assertFailsWith { - "a\\k(?a)".toRegex() + testInvalidBackReference(BackReferenceHandling.nonExistentNamedGroup, pattern = "a(a)\\k") + testInvalidBackReference(BackReferenceHandling.enclosingGroup, pattern = "a(?a\\k)") + testInvalidBackReference(BackReferenceHandling.notYetDefinedNamedGroup, pattern = "a\\k(?a)") + } + + private fun testInvalidBackReference(option: HandlingOption, pattern: String, input: CharSequence = "aaaa", matchValue: String = "aa") { + when (option) { + HandlingOption.IGNORE_BACK_REFERENCE_EXPRESSION -> + assertEquals(matchValue, pattern.toRegex().find(input)?.value) + HandlingOption.THROW -> + // TODO: should fail with IllegalArgumentException, but JS fails with SyntaxError + assertFails { pattern.toRegex() } + HandlingOption.MATCH_NOTHING -> + assertNull(pattern.toRegex().find(input)) } } - @Test fun incompleteNamedGroupDeclaration() { + @Test fun invalidNamedGroupDeclaration() { if (!supportsNamedCapturingGroup) return - assertFailsWith { + // TODO: should fail with IllegalArgumentException, but JS fails with SyntaxError + + assertFails { "(?<".toRegex() } - assertFailsWith { + assertFails { "(?<)".toRegex() } - assertFailsWith { + assertFails { "(? { + assertFails { "(? { + assertFails { "(?".toRegex() } - assertFailsWith { + assertFails { "(?<>\\w+), yes \\k<>".toRegex() } } // TODO: Test comment mode enabled and group name is separated by space, (before, in the middle, after) + // TODO: Test comment mode enabled and back reference group index is separated by space, (before, in the middle, after) + // TODO: Test back reference with \0 @Test fun matchMultiline() { val regex = "^[a-z]*$".toRegex(setOf(RegexOption.IGNORE_CASE, RegexOption.MULTILINE)) diff --git a/libraries/stdlib/wasm/test/testUtils.kt b/libraries/stdlib/wasm/test/testUtils.kt index 522fd9c8f60..1b1ca543915 100644 --- a/libraries/stdlib/wasm/test/testUtils.kt +++ b/libraries/stdlib/wasm/test/testUtils.kt @@ -30,4 +30,14 @@ actual val supportsSuppressedExceptions: Boolean get() = true public actual val supportsNamedCapturingGroup: Boolean get() = true -public actual val regexSplitUnicodeCodePointHandling: Boolean get() = true \ No newline at end of file +public actual val regexSplitUnicodeCodePointHandling: Boolean get() = true + +public actual object BackReferenceHandling { + actual val captureLargestValidIndex: Boolean get() = true + + actual val notYetDefinedGroup: HandlingOption = HandlingOption.THROW + actual val notYetDefinedNamedGroup: HandlingOption = HandlingOption.THROW + actual val enclosingGroup: HandlingOption = HandlingOption.MATCH_NOTHING + actual val nonExistentGroup: HandlingOption = HandlingOption.THROW + actual val nonExistentNamedGroup: HandlingOption = HandlingOption.THROW +} \ No newline at end of file