diff --git a/backend.native/tests/external/stdlib/text/RegexTest/harmony/MatchResultTest.kt b/backend.native/tests/external/stdlib/text/RegexTest/harmony/MatchResultTest.kt new file mode 100644 index 00000000000..ef335128f27 --- /dev/null +++ b/backend.native/tests/external/stdlib/text/RegexTest/harmony/MatchResultTest.kt @@ -0,0 +1,508 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import kotlin.text.* +import kotlin.test.* + +internal var testPatterns = arrayOf("(a|b)*abb", "(1*2*3*4*)*567", "(a|b|c|d)*aab", "(1|2|3|4|5|6|7|8|9|0)(1|2|3|4|5|6|7|8|9|0)*", "(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ)*", "(a|b)*(a|b)*A(a|b)*lice.*", "(a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z)(a|b|c|d|e|f|g|h|" + "i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z)*(1|2|3|4|5|6|7|8|9|0)*|while|for|struct|if|do") + +internal var groupPatterns = arrayOf("(a|b)*aabb", "((a)|b)*aabb", "((a|b)*)a(abb)", "(((a)|(b))*)aabb", "(((a)|(b))*)aa(b)b", "(((a)|(b))*)a(a(b)b)") + +fun testReplaceAll() { + val input = "aabfooaabfooabfoob" + val pattern = "a*b" + val regex = Regex(pattern) + + assertEquals("-foo-foo-foo-", regex.replace(input, "-")) +} + +fun testReplaceFirst() { + val input = "zzzdogzzzdogzzz" + val pattern = "dog" + val regex = Regex(pattern) + + assertEquals("zzzcatzzzdogzzz", regex.replaceFirst(input, "cat")) +} + +/* + * Class under test for String group(int) + */ +fun testGroupint() { + val positiveTestString = "ababababbaaabb" + + // test IndexOutOfBoundsException + // // + for (i in groupPatterns.indices) { + val regex = Regex(groupPatterns[i]) + val result = regex.matchEntire(positiveTestString)!! + try { + // groupPattern equals to number of groups + // of the specified pattern + // // + result.groups[i + 2] + fail("IndexOutBoundsException expected") + result.groups[i + 100] + fail("IndexOutBoundsException expected") + result.groups[-1] + fail("IndexOutBoundsException expected") + result.groups[-100] + fail("IndexOutBoundsException expected") + } catch (e: IndexOutOfBoundsException) { + } + } + + val groupResults = arrayOf( + arrayOf("a"), + arrayOf("a", "a"), + arrayOf("ababababba", "a", "abb"), + arrayOf("ababababba", "a", "a", "b"), + arrayOf("ababababba", "a", "a", "b", "b"), + arrayOf("ababababba", "a", "a", "b", "abb", "b") + ) + + for (i in groupPatterns.indices) { + val regex = Regex(groupPatterns[i]) + val result = regex.matchEntire(positiveTestString)!! + for (j in 0..groupResults[i].size - 1) { + assertEquals("i: $i j: $j", groupResults[i][j], result.groupValues[j + 1]) + } + } + +} + +fun testGroup() { + val positiveTestString = "ababababbaaabb" + val negativeTestString = "gjhfgdsjfhgcbv" + for (element in groupPatterns) { + val regex = Regex(element) + val result = regex.matchEntire(positiveTestString)!! + assertEquals(positiveTestString, result.groupValues[0]) + assertEquals(positiveTestString, result.groups[0]!!.value) + assertEquals(0 until positiveTestString.length, result.groups[0]!!.range) + } + + for (element in groupPatterns) { + val regex = Regex(element) + val result = regex.matchEntire(negativeTestString) + assertEquals(result, null) + } +} + +fun testGroupPossessive() { + val regex = Regex("((a)|(b))++c") + assertEquals("a", regex.matchEntire("aac")!!.groupValues[1]) +} + +fun testMatchesMisc() { + val posSeq = arrayOf( + arrayOf("abb", "ababb", "abababbababb", "abababbababbabababbbbbabb"), + arrayOf("213567", "12324567", "1234567", "213213567", "21312312312567", "444444567"), + arrayOf("abcdaab", "aab", "abaab", "cdaab", "acbdadcbaab"), + arrayOf("213234567", "3458", "0987654", "7689546432", "0398576", "98432", "5"), + arrayOf("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"), + arrayOf("ababbaAabababblice", "ababbaAliceababab", "ababbAabliceaaa", "abbbAbbbliceaaa", "Alice"), + arrayOf("a123", "bnxnvgds156", "for", "while", "if", "struct")) + + for (i in testPatterns.indices) { + val regex = Regex(testPatterns[i]) + for (j in 0..posSeq[i].size - 1) { + assertTrue("Incorrect match: " + testPatterns[i] + " vs " + posSeq[i][j], regex.matches(posSeq[i][j])) + } + } +} + +fun testMatchesQuantifiers() { + val testPatternsSingles = arrayOf("a{5}", "a{2,4}", "a{3,}") + val testPatternsMultiple = arrayOf("((a)|(b)){1,2}abb", "((a)|(b)){2,4}", "((a)|(b)){3,}") + + val stringSingles = arrayOf( + arrayOf("aaaaa", "aaa"), + arrayOf("aa", "a", "aaa", "aaaaaa", "aaaa", "aaaaa"), + arrayOf("aaa", "a", "aaaa", "aa") + ) + + val stringMultiples = arrayOf( + arrayOf("ababb", "aba"), + arrayOf("ab", "b", "bab", "ababa", "abba", "abababbb"), + arrayOf("aba", "b", "abaa", "ba") + ) + + for (i in testPatternsSingles.indices) { + val regex = Regex(testPatternsSingles[i]) + for (j in 0..stringSingles.size / 2 - 1) { + assertTrue("Match expected, but failed: " + regex.pattern + " : " + stringSingles[i][j], + regex.matches(stringSingles[i][j * 2]) + ) + assertFalse("Match failure expected, but match succeed: " + regex.pattern + " : " + stringSingles[i][j * 2 + 1], + regex.matches(stringSingles[i][j * 2 + 1]) + ) + } + } + + for (i in testPatternsMultiple.indices) { + val regex = Regex(testPatternsMultiple[i]) + for (j in 0..stringMultiples.size / 2 - 1) { + assertTrue("Match expected, but failed: " + regex.pattern + " : " + stringMultiples[i][j], + regex.matches(stringMultiples[i][j * 2]) + ) + assertFalse("Match failure expected, but match succeed: " + regex.pattern + " : " + stringMultiples[i][j * 2 + 1], + regex.matches(stringMultiples[i][j * 2 + 1]) + ) + } + } + + // Test for the optimized '.+' quantifier node. + assertFalse(Regex(".+abc").matches("abc")) + assertFalse(Regex(".+\nabc", RegexOption.DOT_MATCHES_ALL).matches("\nabc")) + assertFalse(Regex(".+").matches("")) + assertFalse(Regex(".+\n", RegexOption.DOT_MATCHES_ALL).matches("\n")) + assertFalse(Regex(".+abc").containsMatchIn("abc")) + assertFalse(Regex(".+\nabc", RegexOption.DOT_MATCHES_ALL).containsMatchIn("\nabc")) + assertFalse(Regex(".+").containsMatchIn("")) + assertFalse(Regex(".+\n", RegexOption.DOT_MATCHES_ALL).containsMatchIn("\n")) + + assertTrue(Regex(".+abc").matches("aabc")) + assertTrue(Regex(".+\nabc", RegexOption.DOT_MATCHES_ALL).matches("a\nabc")) + assertTrue(Regex(".+").matches("a")) + assertTrue(Regex(".+\n", RegexOption.DOT_MATCHES_ALL).matches("a\n")) + assertTrue(Regex(".+abc").containsMatchIn("aabc")) + assertTrue(Regex(".+\nabc", RegexOption.DOT_MATCHES_ALL).containsMatchIn("a\nabc")) + assertTrue(Regex(".+").containsMatchIn("a")) + assertTrue(Regex(".+\n", RegexOption.DOT_MATCHES_ALL).containsMatchIn("a\n")) +} + +fun testQuantVsGroup() { + val patternString = "(d{1,3})((a|c)*)(d{1,3})((a|c)*)(d{1,3})" + val testString = "dacaacaacaaddaaacaacaaddd" + + val regex = Regex(patternString) + + val result = regex.matchEntire(testString)!! + assertEquals("dacaacaacaaddaaacaacaaddd", result.groupValues[0]) + assertEquals("d", result.groupValues[1]) + assertEquals("acaacaacaa", result.groupValues[2]) + assertEquals("dd", result.groupValues[4]) + assertEquals("aaacaacaa", result.groupValues[5]) + assertEquals("ddd", result.groupValues[7]) +} + +/* + * Class under test for boolean find() + */ +fun testFind() { + var testPattern = "(abb)" + var testString = "cccabbabbabbabbabb" + val regex = Regex(testPattern) + var result = regex.find(testString) + var start = 3 + var end = 6 + while (result != null) { + assertEquals(start, result.groups[1]!!.range.start) + assertEquals(end, result.groups[1]!!.range.endInclusive + 1) + + start = end + end += 3 + result = result.next() + } + + testPattern = "(\\d{1,3})" + testString = "aaaa123456789045" + + val regex2 = Regex(testPattern) + var result2 = regex2.find(testString) + start = 4 + val length = 3 + while (result2 != null) { + assertEquals(testString.substring(start, start + length), result2.groupValues[1]) + start += length + result2 = result2.next() + } +} + +fun testSEOLsymbols() { + val regex = Regex("^a\\(bb\\[$") + assertTrue(regex.matches("a(bb[")) +} + +fun testGroupCount() { + for (i in groupPatterns.indices) { + val regex = Regex(groupPatterns[i]) + val result = regex.matchEntire("ababababbaaabb")!! + assertEquals(i + 1, result.groups.size - 1) + } +} + +fun testReluctantQuantifiers() { + val regex = Regex("(ab*)*b") + val result = regex.matchEntire("abbbb") + if (result != null) { + assertEquals("abbb", result.groupValues[1]) + } else { + fail("Match expected: (ab*)*b vs abbbb") + } +} + +fun testEnhancedFind() { + val input = "foob" + val pattern = "a*b" + val regex = Regex(pattern) + val result = regex.find(input)!! + assertEquals("b", result.groupValues[0]) +} + +fun testPosCompositeGroup() { + val posExamples = arrayOf("aabbcc", "aacc", "bbaabbcc") + val negExamples = arrayOf("aabb", "bb", "bbaabb") + val posPat = Regex("(aa|bb){1,3}+cc") + val negPat = Regex("(aa|bb){1,3}+bb") + + for (element in posExamples) { + assertTrue(posPat.matches(element)) + } + + for (element in negExamples) { + assertFalse(negPat.matches(element)) + } + + assertTrue(Regex("(aa|bb){1,3}+bb").matches("aabbaabb")) +} + +fun testPosAltGroup() { + val posExamples = arrayOf("aacc", "bbcc", "cc") + val negExamples = arrayOf("bb", "aa") + val posPat = Regex("(aa|bb)?+cc") + val negPat = Regex("(aa|bb)?+bb") + + for (element in posExamples) { + assertTrue(posPat.toString() + " vs: " + element, posPat.matches(element)) + } + + for (element in negExamples) { + assertFalse(negPat.matches(element)) + } + + assertTrue(Regex("(aa|bb)?+bb").matches("aabb")) +} + +fun testRelCompGroup() { + var res = "" + for (i in 0..3) { + val regex = Regex("((aa|bb){$i,3}?).*cc") + val result = regex.matchEntire("aaaaaacc") + assertTrue(regex.toString() + " vs: " + "aaaaaacc", result != null) + assertEquals(res, result!!.groupValues[1]) + res += "aa" + } +} + +fun testRelAltGroup() { + var regex = Regex("((aa|bb)??).*cc") + var result = regex.matchEntire("aacc") + assertTrue(regex.toString() + " vs: " + "aacc", result != null) + assertEquals("", result!!.groupValues[1]) + + regex = Regex("((aa|bb)??)cc") + result = regex.matchEntire("aacc") + assertTrue(regex.toString() + " vs: " + "aacc", result != null) + assertEquals("aa", result!!.groupValues[1]) +} + +fun testIgnoreCase() { + var regex = Regex("(aa|bb)*", RegexOption.IGNORE_CASE) + assertTrue(regex.matches("aAbb")) + + regex = Regex("(a|b|c|d|e)*", RegexOption.IGNORE_CASE) + assertTrue(regex.matches("aAebbAEaEdebbedEccEdebbedEaedaebEbdCCdbBDcdcdADa")) + + regex = Regex("[a-e]*", RegexOption.IGNORE_CASE) + assertTrue(regex.matches("aAebbAEaEdebbedEccEdebbedEaedaebEbdCCdbBDcdcdADa")) +} + +fun testQuoteReplacement() { + assertEquals("\\\\aaCC\\$1", Regex.escapeReplacement("\\aaCC$1")) +} + +fun testOverFlow() { + var regex = Regex("(a*)*") + var result = regex.matchEntire("aaa") + assertTrue(result != null) + assertEquals("", result!!.groupValues[1]) + + assertTrue(Regex("(1+)\\1+").matches("11")) + assertTrue(Regex("(1+)(2*)\\2+").matches("11")) + + regex = Regex("(1+)\\1*") + result = regex.matchEntire("11") + + assertTrue(result != null) + assertEquals("11", result!!.groupValues[1]) + + regex = Regex("((1+)|(2+))(\\2+)") + result = regex.matchEntire("11") + + assertTrue(result != null) + assertEquals("1", result!!.groupValues[2]) + assertEquals("1", result.groupValues[1]) + assertEquals("1", result.groupValues[4]) + assertEquals("", result.groupValues[3]) +} + +fun testUnicode() { + assertTrue(Regex("\\x61a").matches("aa")) + assertTrue(Regex("\\u0061a").matches("aa")) + assertTrue(Regex("\\0141a").matches("aa")) + assertTrue(Regex("\\0777").matches("?7")) +} + +fun testUnicodeCategory() { + assertTrue(Regex("\\p{Ll}").matches("k")) // Unicode lower case + assertTrue(Regex("\\P{Ll}").matches("K")) // Unicode non-lower + // case + assertTrue(Regex("\\p{Lu}").matches("K")) // Unicode upper case + assertTrue(Regex("\\P{Lu}").matches("k")) // Unicode non-upper + // case combinations + assertTrue(Regex("[\\p{L}&&[^\\p{Lu}]]").matches("k")) + assertTrue(Regex("[\\p{L}&&[^\\p{Ll}]]").matches("K")) + assertFalse(Regex("[\\p{L}&&[^\\p{Lu}]]").matches("K")) + assertFalse(Regex("[\\p{L}&&[^\\p{Ll}]]").matches("k")) + + // category/character combinations + assertFalse(Regex("[\\p{L}&&[^a-z]]").matches("k")) + assertTrue(Regex("[\\p{L}&&[^a-z]]").matches("K")) + + assertTrue(Regex("[\\p{Lu}a-z]").matches("k")) + assertTrue(Regex("[a-z\\p{Lu}]").matches("k")) + + assertFalse(Regex("[\\p{Lu}a-d]").matches("k")) + assertTrue(Regex("[a-d\\p{Lu}]").matches("K")) + + assertFalse(Regex("[\\p{L}&&[^\\p{Lu}&&[^G]]]").matches("K")) + +} + +fun testSplitEmpty() { + + val regex = Regex("") + val s = regex.split("", 0) + + assertEquals(1, s.size) + assertEquals("", s[0]) +} + +fun testFindDollar() { + val regex = Regex("a$") + val result = regex.find("a\n") + assertTrue(result != null) + assertEquals("a", result!!.groupValues[0]) +} + + +fun testAllCodePoints() { + // Regression for HARMONY-3145 + val codePoint = IntArray(1) + var p = Regex("(\\p{all})+") + var res = true + var cnt = 0 + var s: String + for (i in 0..1114111) { + codePoint[0] = i + s = String(codePoint, 0, 1) + if (!s.matches(p.toString().toRegex())) { + cnt++ + res = false + } + } + assertTrue(res) + assertEquals(0, cnt) + + p = Regex("(\\P{all})+") + res = true + cnt = 0 + + for (i in 0..1114111) { + codePoint[0] = i + s = String(codePoint, 0, 1) + if (!s.matches(p.toString().toRegex())) { + cnt++ + res = false + } + } + + assertFalse(res) + assertEquals(0x110000, cnt) +} + +/* + * Regression test for HARMONY-674 + */ +fun testPatternMatcher() { + assertTrue(Regex("(?:\\d+)(?:pt)").matches("14pt")) +} + +/** + * Inspired by HARMONY-3360 + */ +fun test3360() { + val str = "!\"#%&'(),-./" + val regex = Regex("\\s") + assertFalse(regex.containsMatchIn(str)) +} + +/** + * Regression test for HARMONY-3360 + */ +fun testGeneralPunctuationCategory() { + val s = arrayOf(",", "!", "\"", "#", "%", "&", "'", "(", ")", "-", ".", "/") + val regexp = "\\p{P}" + + for (i in s.indices) { + val regex = Regex(regexp) + assertTrue(regex.containsMatchIn(s[i])) + } +} + +fun box() { + testReplaceAll() + testReplaceFirst() + testGroupint() + testGroup() + testGroupPossessive() + testMatchesMisc() + testMatchesQuantifiers() + testQuantVsGroup() + testFind() + testSEOLsymbols() + testGroupCount() + testReluctantQuantifiers() + testEnhancedFind() + testPosCompositeGroup() + testPosAltGroup() + testRelCompGroup() + testRelAltGroup() + testIgnoreCase() + testQuoteReplacement() + testOverFlow() + testUnicode() + testUnicodeCategory() + testSplitEmpty() + testFindDollar() + testAllCodePoints() + testPatternMatcher() + test3360() + testGeneralPunctuationCategory() +} \ No newline at end of file diff --git a/backend.native/tests/external/stdlib/text/RegexTest/harmony/MatchResultTest2.kt b/backend.native/tests/external/stdlib/text/RegexTest/harmony/MatchResultTest2.kt new file mode 100644 index 00000000000..0c53b19436b --- /dev/null +++ b/backend.native/tests/external/stdlib/text/RegexTest/harmony/MatchResultTest2.kt @@ -0,0 +1,116 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import kotlin.text.* +import kotlin.test.* + +fun testErrorConditions2() { + // Test match cursors in absence of a match + val regex = Regex("(foo[0-9])(bar[a-z])") + var result = regex.find("foo1barzfoo2baryfoozbar5") + + Assert.assertTrue(result != null) + Assert.assertEquals(0, result!!.range.start) + Assert.assertEquals(7, result.range.endInclusive) + Assert.assertEquals(0, result.groups[0]!!.range.start) + Assert.assertEquals(7, result.groups[0]!!.range.endInclusive) + Assert.assertEquals(0, result.groups[1]!!.range.start) + Assert.assertEquals(3, result.groups[1]!!.range.endInclusive) + Assert.assertEquals(4, result.groups[2]!!.range.start) + Assert.assertEquals(7, result.groups[2]!!.range.endInclusive) + + try { + result.groups[3] + Assert.fail("IndexOutOfBoundsException expected") + } catch (e: IndexOutOfBoundsException) { + } + + try { + result.groupValues[3] + Assert.fail("IndexOutOfBoundsException expected") + } catch (e: IndexOutOfBoundsException) { + } + + try { + result.groups[-1] + Assert.fail("IndexOutOfBoundsException expected") + } catch (e: IndexOutOfBoundsException) { + } + + try { + result.groupValues[-1] + Assert.fail("IndexOutOfBoundsException expected") + } catch (e: IndexOutOfBoundsException) { + } + + result = result.next() + Assert.assertTrue(result != null) + Assert.assertEquals(8, result!!.range.start) + Assert.assertEquals(15, result.range.endInclusive) + Assert.assertEquals(8, result.groups[0]!!.range.start) + Assert.assertEquals(15, result.groups[0]!!.range.endInclusive) + Assert.assertEquals(8, result.groups[1]!!.range.start) + Assert.assertEquals(11, result.groups[1]!!.range.endInclusive) + Assert.assertEquals(12, result.groups[2]!!.range.start) + Assert.assertEquals(15, result.groups[2]!!.range.endInclusive) + + try { + result.groups[3] + Assert.fail("IndexOutOfBoundsException expected") + } catch (e: IndexOutOfBoundsException) { + } + + try { + result.groupValues[3] + Assert.fail("IndexOutOfBoundsException expected") + } catch (e: IndexOutOfBoundsException) { + } + + try { + result.groups[-1] + Assert.fail("IndexOutOfBoundsException expected") + } catch (e: IndexOutOfBoundsException) { + } + + try { + result.groupValues[-1] + Assert.fail("IndexOutOfBoundsException expected") + } catch (e: IndexOutOfBoundsException) { + } + + result = result.next() + Assert.assertFalse(result != null) +} + +/* + * Regression test for HARMONY-997 + */ +fun testReplacementBackSlash() { + val str = "replace me" + val replacedString = "me" + val substitutionString = "\\" + val regex = Regex(replacedString) + try { + regex.replace(str, substitutionString) + Assert.fail("IllegalArgumentException should be thrown") + } catch (e: IllegalArgumentException) { + } +} + +fun box() { + testErrorConditions2() + testReplacementBackSlash() +} diff --git a/backend.native/tests/external/stdlib/text/RegexTest/harmony/ModeTest.kt b/backend.native/tests/external/stdlib/text/RegexTest/harmony/ModeTest.kt new file mode 100644 index 00000000000..e36b1c6528f --- /dev/null +++ b/backend.native/tests/external/stdlib/text/RegexTest/harmony/ModeTest.kt @@ -0,0 +1,116 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import kotlin.text.* +import kotlin.test.* + +/** + * Tests Pattern compilation modes and modes triggered in pattern strings + */ +fun testCase() { + var regex: Regex + var result: MatchResult? + + regex = Regex("([a-z]+)[0-9]+") + result = regex.find("cAT123#dog345") + Assert.assertNotNull(result) + Assert.assertEquals("dog", result!!.groupValues[1]) + Assert.assertNull(result.next()) + + regex = Regex("([a-z]+)[0-9]+", RegexOption.IGNORE_CASE) + result = regex.find("cAt123#doG345") + Assert.assertNotNull(result) + Assert.assertEquals("cAt", result!!.groupValues[1]) + result = result.next() + Assert.assertNotNull(result) + Assert.assertEquals("doG", result!!.groupValues[1]) + Assert.assertNull(result.next()) + + regex = Regex("(?i)([a-z]+)[0-9]+") + result = regex.find("cAt123#doG345") + Assert.assertNotNull(result) + Assert.assertEquals("cAt", result!!.groupValues[1]) + result = result.next() + Assert.assertNotNull(result) + Assert.assertEquals("doG", result!!.groupValues[1]) + Assert.assertNull(result.next()) +} + +fun testMultiline() { + var regex: Regex + var result: MatchResult? + + regex = Regex("^foo") + result = regex.find("foobar") + Assert.assertNotNull(result) + Assert.assertTrue(result!!.range.start == 0 && result.range.endInclusive == 2) + Assert.assertTrue(result.groups[0]!!.range.start == 0 && result.groups[0]!!.range.endInclusive == 2) + Assert.assertNull(result.next()) + + result = regex.find("barfoo") + Assert.assertNull(result) + + regex = Regex("foo$") + result = regex.find("foobar") + Assert.assertNull(result) + + result = regex.find("barfoo") + Assert.assertNotNull(result) + Assert.assertTrue(result!!.range.start == 3 && result.range.endInclusive == 5) + Assert.assertTrue(result.groups[0]!!.range.start == 3 && result.groups[0]!!.range.endInclusive == 5) + Assert.assertNull(result.next()) + + regex = Regex("^foo([0-9]*)", RegexOption.MULTILINE) + result = regex.find("foo1bar\nfoo2foo3\nbarfoo4") + Assert.assertNotNull(result) + Assert.assertEquals("1", result!!.groupValues[1]) + result = result.next() + Assert.assertNotNull(result) + Assert.assertEquals("2", result!!.groupValues[1]) + Assert.assertNull(result.next()) + + regex = Regex("foo([0-9]*)$", RegexOption.MULTILINE) + result = regex.find("foo1bar\nfoo2foo3\nbarfoo4") + Assert.assertNotNull(result) + Assert.assertEquals("3", result!!.groupValues[1]) + result = result.next() + Assert.assertNotNull(result) + Assert.assertEquals("4", result!!.groupValues[1]) + Assert.assertNull(result.next()) + + regex = Regex("(?m)^foo([0-9]*)") + result = regex.find("foo1bar\nfoo2foo3\nbarfoo4") + Assert.assertNotNull(result) + Assert.assertEquals("1", result!!.groupValues[1]) + result = result.next() + Assert.assertNotNull(result) + Assert.assertEquals("2", result!!.groupValues[1]) + Assert.assertNull(result.next()) + + regex = Regex("(?m)foo([0-9]*)$") + result = regex.find("foo1bar\nfoo2foo3\nbarfoo4") + Assert.assertNotNull(result) + Assert.assertEquals("3", result!!.groupValues[1]) + result = result.next() + Assert.assertNotNull(result) + Assert.assertEquals("4", result!!.groupValues[1]) + Assert.assertNull(result.next()) +} + +fun box() { + testCase() + testMultiline() +} diff --git a/backend.native/tests/external/stdlib/text/RegexTest/harmony/PatternErrorTest.kt b/backend.native/tests/external/stdlib/text/RegexTest/harmony/PatternErrorTest.kt new file mode 100644 index 00000000000..7daea215ac7 --- /dev/null +++ b/backend.native/tests/external/stdlib/text/RegexTest/harmony/PatternErrorTest.kt @@ -0,0 +1,43 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import kotlin.text.* +import kotlin.test.* + +fun testCompileErrors() { + // empty regex string - no exception should be thrown + Regex("") + + // note: invalid regex syntax checked in PatternSyntaxExceptionTest + + // flags = 0 should raise no exception + Regex("foo", emptySet()) + + // check that all valid flags accepted without exception + val options = setOf( + RegexOption.UNIX_LINES, + RegexOption.IGNORE_CASE, + RegexOption.MULTILINE, + RegexOption.CANON_EQ, + RegexOption.COMMENTS, + RegexOption.DOT_MATCHES_ALL) + Regex("foo", options) +} + +fun box() { + testCompileErrors() +} + diff --git a/backend.native/tests/external/stdlib/text/RegexTest/harmony/PatternSyntaxExceptionTest.kt b/backend.native/tests/external/stdlib/text/RegexTest/harmony/PatternSyntaxExceptionTest.kt new file mode 100644 index 00000000000..3ac44315eb5 --- /dev/null +++ b/backend.native/tests/external/stdlib/text/RegexTest/harmony/PatternSyntaxExceptionTest.kt @@ -0,0 +1,45 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import kotlin.text.* +import kotlin.test.* + +fun testCase() { + val regex = "(" + try { + Regex(regex) + Assert.fail("PatternSyntaxException expected") + } catch (e: PatternSyntaxException) { + // TODO: Check the exception's properties. + } + +} + +fun testCase2() { + val regex = "[4-" + try { + Regex(regex) + Assert.fail("PatternSyntaxException expected") + } catch (e: PatternSyntaxException) { + } + +} + + +fun box() { + testCase() + testCase2() +} \ No newline at end of file diff --git a/backend.native/tests/external/stdlib/text/RegexTest/harmony/PatternTest.kt b/backend.native/tests/external/stdlib/text/RegexTest/harmony/PatternTest.kt new file mode 100644 index 00000000000..920bcdbd7b8 --- /dev/null +++ b/backend.native/tests/external/stdlib/text/RegexTest/harmony/PatternTest.kt @@ -0,0 +1,1303 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import kotlin.text.* +import kotlin.test.* + +internal var testPatterns = arrayOf("(a|b)*abb", "(1*2*3*4*)*567", "(a|b|c|d)*aab", "(1|2|3|4|5|6|7|8|9|0)(1|2|3|4|5|6|7|8|9|0)*", "(abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ)*", "(a|b)*(a|b)*A(a|b)*lice.*", "(a|b|c|d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z)(a|b|c|d|e|f|g|h|" + "i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z)*(1|2|3|4|5|6|7|8|9|0)*|while|for|struct|if|do", "x(?c)y", "x(?cc)y", "x(?:c)y") + +fun testCommentsInPattern() { + val p = Regex("ab# this is a comment\ncd", RegexOption.COMMENTS) + Assert.assertTrue(p.matches("abcd")) +} + +fun testSplitCharSequenceint() { + // Splitting CharSequence which ends with pattern. + // Harmony regress tests. + Assert.assertEquals(",,".split(",".toRegex(), 3).toTypedArray().size, 3) + Assert.assertEquals(",,".split(",".toRegex(), 4).toTypedArray().size, 3) + Assert.assertEquals(Regex("o").split("boo:and:foo", 5).size, 5) + Assert.assertEquals(Regex("b").split("ab", 0).size, 2) + var s: List + var regex = Regex("x") + s = regex.split("zxx:zzz:zxx", 10) + Assert.assertEquals(s.size, 5) + s = regex.split("zxx:zzz:zxx", 3) + Assert.assertEquals(s.size, 3) + s = regex.split("zxx:zzz:zxx", 0) + Assert.assertEquals(s.size, 5) + + // Other splitting. + // Negative limit + regex = Regex("b") + s = regex.split("abccbadfebb", 0) + Assert.assertEquals(s.size, 5) + s = regex.split("", 0) + Assert.assertEquals(s.size, 1) + regex = Regex("") + s = regex.split("", 0) + Assert.assertEquals(s.size, 1) + s = regex.split("abccbadfe", 0) + Assert.assertEquals(s.size, 11) + + // positive limit + regex = Regex("b") + s = regex.split("abccbadfebb", 12) + Assert.assertEquals(s.size, 5) + s = regex.split("", 6) + Assert.assertEquals(s.size, 1) + regex = Regex("") + s = regex.split("", 11) + Assert.assertEquals(s.size, 1) + s = regex.split("abccbadfe", 15) + Assert.assertEquals(s.size, 11) + + regex = Regex("b") + s = regex.split("abccbadfebb", 5) + Assert.assertEquals(s.size, 5) + s = regex.split("", 1) + Assert.assertEquals(s.size, 1) + regex = Regex("") + s = regex.split("", 1) + Assert.assertEquals(s.size, 1) + s = regex.split("abccbadfe", 11) + Assert.assertEquals(s.size, 11) + + regex = Regex("b") + s = regex.split("abccbadfebb", 3) + Assert.assertEquals(s.size, 3) + regex = Regex("") + s = regex.split("abccbadfe", 5) + Assert.assertEquals(s.size, 5) +} + +fun testFlags() { + var baseString: String + var testString: String + var regex: Regex + + baseString = "((?i)|b)a" + testString = "A" + regex = Regex(baseString) + Assert.assertFalse(regex.matches(testString)) + + baseString = "(?i)a|b" + testString = "A" + regex = Regex(baseString) + Assert.assertTrue(regex.matches(testString)) + + baseString = "(?i)a|b" + testString = "B" + regex = Regex(baseString) + Assert.assertTrue(regex.matches(testString)) + + baseString = "c|(?i)a|b" + testString = "B" + regex = Regex(baseString) + Assert.assertTrue(regex.matches(testString)) + + baseString = "(?i)a|(?s)b" + testString = "B" + regex = Regex(baseString) + Assert.assertTrue(regex.matches(testString)) + + baseString = "(?i)a|(?-i)b" + testString = "B" + regex = Regex(baseString) + Assert.assertFalse(regex.matches(testString)) + + baseString = "(?i)a|(?-i)c|b" + testString = "B" + regex = Regex(baseString) + Assert.assertFalse(regex.matches(testString)) + + baseString = "(?i)a|(?-i)c|(?i)b" + testString = "B" + regex = Regex(baseString) + Assert.assertTrue(regex.matches(testString)) + + baseString = "(?i)a|(?-i)b" + testString = "A" + regex = Regex(baseString) + Assert.assertTrue(regex.matches(testString)) + + baseString = "((?i))a" + testString = "A" + regex = Regex(baseString) + Assert.assertFalse(regex.matches(testString)) + + baseString = "|(?i)|a" + testString = "A" + regex = Regex(baseString) + Assert.assertTrue(regex.matches(testString)) + + baseString = "(?i)((?s)a.)" + testString = "A\n" + regex = Regex(baseString) + Assert.assertTrue(regex.matches(testString)) + + baseString = "(?i)((?-i)a)" + testString = "A" + regex = Regex(baseString) + Assert.assertFalse(regex.matches(testString)) + + baseString = "(?i)(?s:a.)" + testString = "A\n" + regex = Regex(baseString) + Assert.assertTrue(regex.matches(testString)) + + baseString = "(?i)fgh(?s:aa)" + testString = "fghAA" + regex = Regex(baseString) + Assert.assertTrue(regex.matches(testString)) + + baseString = "(?i)((?-i))a" + testString = "A" + regex = Regex(baseString) + Assert.assertTrue(regex.matches(testString)) + + baseString = "abc(?i)d" + testString = "ABCD" + regex = Regex(baseString) + Assert.assertFalse(regex.matches(testString)) + + testString = "abcD" + Assert.assertTrue(regex.matches(testString)) + + baseString = "a(?i)a(?-i)a(?i)a(?-i)a" + testString = "aAaAa" + regex = Regex(baseString) + Assert.assertTrue(regex.matches(testString)) + + testString = "aAAAa" + Assert.assertFalse(regex.matches(testString)) +} + +fun Set.containsOnly(vararg options: RegexOption): Boolean { + val toCheck = options.toSet() + return size == toCheck.size && containsAll(toCheck) +} + +fun testFlagsMethod() { + val a = kotlin.text.Regex("sdf") + var baseString: String + var regex: Regex + + baseString = "(?-i)" + regex = Regex(baseString) + + baseString = "(?idmsux)abc(?-i)vg(?-dmu)" + regex = Regex(baseString) + Assert.assertTrue(regex.options.containsOnly(RegexOption.DOT_MATCHES_ALL, RegexOption.COMMENTS)) + + baseString = "(?idmsux)abc|(?-i)vg|(?-dmu)" + regex = Regex(baseString) + Assert.assertTrue(regex.options.containsOnly(RegexOption.DOT_MATCHES_ALL, RegexOption.COMMENTS)) + + baseString = "(?is)a((?x)b.)" + regex = Regex(baseString) + Assert.assertTrue(regex.options.containsOnly(RegexOption.DOT_MATCHES_ALL, RegexOption.IGNORE_CASE)) + + baseString = "(?i)a((?-i))" + regex = Regex(baseString) + Assert.assertTrue(regex.options.containsOnly(RegexOption.IGNORE_CASE)) + + baseString = "((?i)a)" + regex = Regex(baseString) + Assert.assertTrue(regex.options.isEmpty()) + + regex = Regex("(?is)abc") + Assert.assertTrue(regex.options.containsOnly(RegexOption.IGNORE_CASE, RegexOption.DOT_MATCHES_ALL)) +} + +fun testCompileStringint() { + /* + * this tests are needed to verify that appropriate exceptions are hrown + */ + var pattern = "b)a" + try { + Regex(pattern) + Assert.fail("Expected a PatternSyntaxException when compiling pattern: " + pattern) + } catch (e: PatternSyntaxException) { + // pass + } + + pattern = "bcde)a" + try { + Regex(pattern) + Assert.fail("Expected a PatternSyntaxException when compiling pattern: " + pattern) + } catch (e: PatternSyntaxException) { + // pass + } + + pattern = "bbg())a" + try { + Regex(pattern) + Assert.fail("Expected a PatternSyntaxException when compiling pattern: " + pattern) + } catch (e: PatternSyntaxException) { + // pass + } + + pattern = "cdb(?i))a" + try { + Regex(pattern) + Assert.fail("Expected a PatternSyntaxException when compiling pattern: " + pattern) + } catch (e: PatternSyntaxException) { + // pass + } + + /* + * This pattern should compile (Originally it is a regression test for HARMONY-2127) + */ + pattern = "x(?c)y" + Regex(pattern) + + /* + * This pattern doesn't match any string, but should be compiled anyway + */ + pattern = "(b\\u0001)a" + Regex(pattern) +} + + +fun testQuantCompileNeg() { + val patterns = arrayOf("5{,2}", "{5asd", "{hgdhg", "{5,hjkh", "{,5hdsh", "{5,3shdfkjh}") + for (element in patterns) { + try { + Regex(element) + Assert.fail("PatternSyntaxException was expected, but compilation succeeds") + } catch (pse: PatternSyntaxException) { + continue + } + + } +} + +fun testQuantCompilePos() { + val patterns = arrayOf("abc{2,}", "abc{5}") + for (element in patterns) { + Regex(element) + } +} + +fun testQuantComposition() { + val pattern = "(a{1,3})aab" + val regex = Regex(pattern) + val result = regex.matchEntire("aaab") + Assert.assertNotNull(result) + Assert.assertEquals(result!!.groups[1]!!.range.start, 0) + Assert.assertEquals(result.groupValues[1], "a") +} + +fun testTimeZoneIssue() { + val regex = Regex("GMT(\\+|\\-)(\\d+)(:(\\d+))?") + val result = regex.matchEntire("GMT-9:45") + Assert.assertNotNull(result) + Assert.assertEquals("-", result!!.groupValues[1]) + Assert.assertEquals("9", result.groupValues[2]) + Assert.assertEquals(":45", result.groupValues[3]) + Assert.assertEquals("45", result.groupValues[4]) +} + +fun testCompileRanges() { + val correctTestPatterns = arrayOf("[^]*abb]*", "[^a-d[^m-p]]*abb", "[a-d\\d]*abb", "[abc]*abb", + "[a-e&&[de]]*abb", "[^abc]*abb", "[a-e&&[^de]]*abb", "[a-z&&[^m-p]]*abb", "[a-d[m-p]]*abb", + "[a-zA-Z]*abb", "[+*?]*abb", "[^+*?]*abb") + + val inputSecuence = arrayOf("kkkk", "admpabb", "abcabcd124654abb", "abcabccbacababb", + "dededededededeedabb", "gfdhfghgdfghabb", "accabacbcbaabb", "acbvfgtyabb", "adbcacdbmopabcoabb", + "jhfkjhaSDFGHJkdfhHNJMjkhfabb", "+*??+*abb", "sdfghjkabb") + + for (i in correctTestPatterns.indices) { + Assert.assertTrue("pattern: " + correctTestPatterns[i] + " input: " + inputSecuence[i], + Regex(correctTestPatterns[i]).matches(inputSecuence[i])) + } + + val wrongInputSecuence = arrayOf("]", "admpkk", "abcabcd124k654abb", "abwcabccbacababb", + "abababdeababdeabb", "abcabcacbacbabb", "acdcbecbaabb", "acbotyabb", "adbcaecdbmopabcoabb", + "jhfkjhaSDFGHJk;dfhHNJMjkhfabb", "+*?a?+*abb", "sdf+ghjkabb") + + for (i in correctTestPatterns.indices) { + Assert.assertFalse("pattern: " + correctTestPatterns[i] + " input: " + wrongInputSecuence[i], + Regex(correctTestPatterns[i]).matches(wrongInputSecuence[i])) + } +} + +fun testRangesSpecialCases() { + val neg_patterns = arrayOf("[a-&&[b-c]]", "[a-\\w]", "[b-a]", "[]") + + for (element in neg_patterns) { + try { + Regex(element) + Assert.fail("PatternSyntaxException was expected: " + element) + } catch (pse: PatternSyntaxException) { + } + + } + + val pos_patterns = arrayOf("[-]+", "----", "[a-]+", "a-a-a-a-aa--", "[\\w-a]+", "123-2312--aaa-213", "[a-]]+", "-]]]]]]]]]]]]]]]") + + var i = 0 + while (i < pos_patterns.size) { + val pat = pos_patterns[i++] + val inp = pos_patterns[i] + Assert.assertTrue("pattern: $pat input: $inp", Regex(pat).matches(inp)) + i++ + } +} + +fun testZeroSymbols() { + Assert.assertTrue(Regex("[\u0000]*abb").matches("\u0000\u0000\u0000\u0000\u0000\u0000abb")) +} + +fun testEscapes() { + val regex = Regex("\\Q{]()*?") + Assert.assertTrue(regex.matches("{]()*?")) +} + +fun testRegressions() { + // Bug 181 + Regex("[\\t-\\r]") + + // HARMONY-4472 + Regex("a*.+") + + // Bug187 + Regex("|(?idmsux-idmsux)|(?idmsux-idmsux)|[^|\\[-\\0274|\\,-\\\\[^|W\\}\\nq\\x65\\002\\xFE\\05\\06\\00\\x66\\x47i\\,\\xF2\\=\\06\\u0EA4\\x9B\\x3C\\f\\|\\{\\xE5\\05\\r\\u944A\\xCA\\e|\\x19\\04\\x07\\04\\u607B\\023\\0073\\x91Tr\\0150\\x83]]?(?idmsux-idmsux:\\p{Alpha}{7}?)||(?<=[^\\uEC47\\01\\02\\u3421\\a\\f\\a\\013q\\035w\\e])(?<=\\p{Punct}{0,}?)(?=^\\p{Lower})(?!\\b{8,14})(?[\\x3E-\\]])|(?idmsux-idmsux:\\p{Punct})|(?[|\\n\\042\\uB09F\\06\\u0F2B\\uC96D\\x89\\uC166\\xAA|\\04-\\][^|\\a\\|\\rx\\04\\uA770\\n\\02\\t\\052\\056\\0274\\|\\=\\07\\e|\\00-\\x1D&&[^\\005\\uB15B\\uCDAC\\n\\x74\\0103\\0147\\uD91B\\n\\062G\\u9B4B\\077\\}\\0324&&[^\\0302\\,\\0221\\04\\u6D16\\04xy\\uD193\\[\\061\\06\\045\\x0F|\\e\\xBB\\f\\u1B52\\023\\u3AD2\\033\\007\\022\\}\\x66\\uA63FJ-\\0304]]]]{0,0})||(?^+)|(?![^|\\|\\nJ\\t\\<\\04E\\\\\\t\\01\\\\\\02\\|\\=\\}\\xF3\\uBEC2\\032K\\014\\uCC5F\\072q\\|\\0153\\xD9\\0322\\uC6C8[^\\t\\0342\\x34\\x91\\06\\{\\xF1\\a\\u1710\\?\\xE7\\uC106\\02pF\\<&&[^|\\]\\064\\u381D\\u50CF\\eO&&[^|\\06\\x2F\\04\\045\\032\\u8536W\\0377\\0017|\\x06\\uE5FA\\05\\xD4\\020\\04c\\xFC\\02H\\x0A\\r]]]]+?)(?idmsux-idmsux)|(?[\\{-\\0207|\\06-\\0276\\p{XDigit}])(?idmsux-idmsux:[^|\\x52\\0012\\]u\\xAD\\0051f\\0142\\\\l\\|\\050\\05\\f\\t\\u7B91\\r\\u7763\\{|h\\0104\\a\\f\\0234\\u2D4F&&^\\P{InGreek}]))") + + // HARMONY-5858 + Regex("\\u6211", RegexOption.LITERAL) +} + +fun testOrphanQuantifiers() { + try { + Regex("+++++") + Assert.fail("PatternSyntaxException expected") + } catch (pse: PatternSyntaxException) { + } + +} + +fun testOrphanQuantifiers2() { + try { + Regex("\\d+*") + Assert.fail("PatternSyntaxException expected") + } catch (pse: PatternSyntaxException) { + } + +} + +fun testBug197() { + val vals = arrayOf(":", 2, arrayOf("boo", "and:foo"), + ":", 5, arrayOf("boo", "and", "foo"), + ":", 0, arrayOf("boo", "and", "foo"), + ":", 3, arrayOf("boo", "and", "foo"), + ":", 1, arrayOf("boo:and:foo"), + "o", 5, arrayOf("b", "", ":and:f", "", ""), + "o", 4, arrayOf("b", "", ":and:f", "o"), + "o", 0, arrayOf("b", "", ":and:f", "", "") + ) + + var i = 0 + while (i < vals.size / 3) { + val res = Regex(vals[i++].toString()).split("boo:and:foo", (vals[i++] as Int)) + val expectedRes = vals[i++] as Array + + Assert.assertEquals(expectedRes.size, res.size) + + for (j in expectedRes.indices) { + Assert.assertEquals(expectedRes[j], res[j]) + } + } +} + +fun testURIPatterns() { + val URI_REGEXP_STR = "^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?"; + val SCHEME_REGEXP_STR = "^[a-zA-Z]{1}[\\w+-.]+$"; + val REL_URI_REGEXP_STR = "^(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?"; + val IPV6_REGEXP_STR = "^[0-9a-fA-F\\:\\.]+(\\%\\w+)?$"; + val IPV6_REGEXP_STR2 = "^\\[[0-9a-fA-F\\:\\.]+(\\%\\w+)?\\]$"; + val IPV4_REGEXP_STR = "^[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}$"; + val HOSTNAME_REGEXP_STR = "\\w+[\\w\\-\\.]*"; + + Regex(URI_REGEXP_STR) + Regex(REL_URI_REGEXP_STR) + Regex(SCHEME_REGEXP_STR) + Regex(IPV4_REGEXP_STR) + Regex(IPV6_REGEXP_STR) + Regex(IPV6_REGEXP_STR2) + Regex(HOSTNAME_REGEXP_STR) +} + +fun testFindBoundaryCases1() { + val regex = Regex(".*\n") + val result = regex.find("a\n") + + Assert.assertNotNull(result) + Assert.assertEquals("a\n", result!!.value) +} + +fun testFindBoundaryCases2() { + val regex = Regex(".*A") + val result = regex.find("aAa") + + Assert.assertNotNull(result) + Assert.assertEquals("aA", result!!.value) + +} + +fun testFindBoundaryCases3() { + val regex = Regex(".*A") + val result = regex.find("a\naA\n") + + Assert.assertNotNull(result) + Assert.assertEquals("aA", result!!.value) + +} + +fun testFindBoundaryCases4() { + val regex = Regex("A.*") + val result = regex.find("A\n") + + Assert.assertNotNull(result) + Assert.assertEquals("A", result!!.value) + +} + +fun testFindBoundaryCases5() { + val regex = Regex(".*A.*") + var result = regex.find("\nA\naaa\nA\naaAaa\naaaA\n") + val expected = arrayOf("A", "A", "aaAaa", "aaaA") + + var k = 0 + while (result != null) { + Assert.assertEquals(expected[k], result.value) + result = result.next() + k++ + } +} + +fun testFindBoundaryCases6() { + val regex = Regex(".*") + var result = regex.find("\na\n") + val expected = arrayOf("", "a", "", "") + + var k = 0 + while (result != null) { + Assert.assertEquals(expected[k], result.value) + k++ + result = result.next() + } +} + +fun testBackReferences() { + var regex = Regex("(\\((\\w*):(.*):(\\2)\\))") + var result = regex.find("(start1: word :start1)(start2: word :start2)") + + var k = 1 + while (result != null) { + Assert.assertEquals("start" + k, result.groupValues[2]) + Assert.assertEquals(" word ", result.groupValues[3]) + Assert.assertEquals("start" + k, result.groupValues[4]) + k++ + result = result.next() + } + + Assert.assertEquals(3, k) + regex = Regex(".*(.)\\1") + Assert.assertTrue(regex.matches("saa")) +} + +fun testNewLine() { + val regex = Regex("(^$)*\n", RegexOption.MULTILINE) + var result = regex.find("\r\n\n") + var counter = 0 + while (result != null) { + counter++ + result = result.next() + } + Assert.assertEquals(2, counter) +} + +fun testFindGreedy() { + val regex = Regex(".*aaa", RegexOption.DOT_MATCHES_ALL) + val result = regex.matchEntire("aaaa\naaa\naaaaaa") + Assert.assertNotNull(result) + Assert.assertEquals(14, result!!.range.endInclusive) +} + +fun testSOLQuant() { + val regex = Regex("$*", RegexOption.MULTILINE) + var result = regex.find("\n\n") + var counter = 0 + while (result != null) { + counter++ + result = result.next() + } + Assert.assertEquals(3, counter) +} + +fun testIllegalEscape() { + try { + Regex("\\y") + Assert.fail("PatternSyntaxException expected") + } catch (pse: PatternSyntaxException) { + } +} + +fun testEmptyFamily() { + Regex("\\p{Lower}") +} + +fun testNonCaptConstr() { + // Flags + var regex = Regex("(?i)b*(?-i)a*") + Assert.assertTrue(regex.matches("bBbBaaaa")) + Assert.assertFalse(regex.matches("bBbBAaAa")) + + // Non-capturing groups + regex = Regex("(?i:b*)a*") + Assert.assertTrue(regex.matches("bBbBaaaa")) + Assert.assertFalse(regex.matches("bBbBAaAa")) + + // 1 2 3 4 5 6 7 8 9 10 11 + regex = Regex("(?:-|(-?\\d+\\d\\d\\d))?(?:-|-(\\d\\d))?(?:-|-(\\d\\d))?(T)?(?:(\\d\\d):(\\d\\d):(\\d\\d)(\\.\\d+)?)?(?:(?:((?:\\+|\\-)\\d\\d):(\\d\\d))|(Z))?") + val result = regex.matchEntire("-1234-21-31T41:51:61.789+71:81") + Assert.assertNotNull(result) + Assert.assertEquals("-1234", result!!.groupValues[1]) + Assert.assertEquals("21", result.groupValues[2]) + Assert.assertEquals("31", result.groupValues[3]) + Assert.assertEquals("T", result.groupValues[4]) + Assert.assertEquals("41", result.groupValues[5]) + Assert.assertEquals("51", result.groupValues[6]) + Assert.assertEquals("61", result.groupValues[7]) + Assert.assertEquals(".789", result.groupValues[8]) + Assert.assertEquals("+71", result.groupValues[9]) + Assert.assertEquals("81", result.groupValues[10]) + + // positive lookahead + regex = Regex(".*\\.(?=log$).*$") + Assert.assertTrue(regex.matches("a.b.c.log")) + Assert.assertFalse(regex.matches("a.b.c.log.")) + + // negative lookahead + regex = Regex(".*\\.(?!log$).*$") + Assert.assertFalse(regex.matches("abc.log")) + Assert.assertTrue(regex.matches("abc.logg")) + + // positive lookbehind + regex = Regex(".*(?<=abc)\\.log$") + Assert.assertFalse(regex.matches("cde.log")) + Assert.assertTrue(regex.matches("abc.log")) + + // negative lookbehind + regex = Regex(".*(?a*)abb") + Assert.assertFalse(regex.matches("aaabb")) + regex = Regex("(?>a*)bb") + Assert.assertTrue(regex.matches("aaabb")) + + regex = Regex("(?>a|aa)aabb") + Assert.assertTrue(regex.matches("aaabb")) + regex = Regex("(?>aa|a)aabb") + Assert.assertFalse(regex.matches("aaabb")) + + // quantifiers over look ahead + regex = Regex(".*(?<=abc)*\\.log$") + Assert.assertTrue(regex.matches("cde.log")) + regex = Regex(".*(?<=abc)+\\.log$") + Assert.assertFalse(regex.matches("cde.log")) +} + +fun testCompilePatternWithTerminatorMark() { + val regex = Regex("a\u0000\u0000cd") + Assert.assertTrue(regex.matches("a\u0000\u0000cd")) +} + +fun testAlternations() { + var baseString = "|a|bc" + var regex = Regex(baseString) + Assert.assertTrue(regex.matches("")) + + baseString = "a||bc" + regex = Regex(baseString) + Assert.assertTrue(regex.matches("")) + + baseString = "a|bc|" + regex = Regex(baseString) + Assert.assertTrue(regex.matches("")) + + baseString = "a|b|" + regex = Regex(baseString) + Assert.assertTrue(regex.matches("")) + + baseString = "a(|b|cd)e" + regex = Regex(baseString) + Assert.assertTrue(regex.matches("ae")) + + baseString = "a(b||cd)e" + regex = Regex(baseString) + Assert.assertTrue(regex.matches("ae")) + + baseString = "a(b|cd|)e" + regex = Regex(baseString) + Assert.assertTrue(regex.matches("ae")) + + baseString = "a(b|c|)e" + regex = Regex(baseString) + Assert.assertTrue(regex.matches("ae")) + + baseString = "a(|)e" + regex = Regex(baseString) + Assert.assertTrue(regex.matches("ae")) + + baseString = "|" + regex = Regex(baseString) + Assert.assertTrue(regex.matches("")) + + baseString = "a(?:|)e" + regex = Regex(baseString) + Assert.assertTrue(regex.matches("ae")) + + baseString = "a||||bc" + regex = Regex(baseString) + Assert.assertTrue(regex.matches("")) + + baseString = "(?i-is)|a" + regex = Regex(baseString) + Assert.assertTrue(regex.matches("a")) +} + +fun testMatchWithGroups() { + var baseString = "jwkerhjwehrkwjehrkwjhrwkjehrjwkehrjkwhrkwehrkwhrkwrhwkhrwkjehr" + var pattern = ".*(..).*\\1.*" + Assert.assertTrue(Regex(pattern).matches(baseString)) + + baseString = "saa" + pattern = ".*(.)\\1" + Assert.assertTrue(Regex(pattern).matches(baseString)) + Assert.assertTrue(Regex(pattern).containsMatchIn(baseString)) +} + +fun testSplitEmptyCharSequence() { + val s1 = "" + val arr = s1.split(":".toRegex()) + Assert.assertEquals(arr.size, 1) +} + +fun testSplitEndsWithPattern() { + Assert.assertEquals(",,".split(",".toRegex(), 3).toTypedArray().size, 3) + Assert.assertEquals(",,".split(",".toRegex(), 4).toTypedArray().size, 3) + + Assert.assertEquals(Regex("o").split("boo:and:foo", 5).size, 5) + Assert.assertEquals(Regex("b").split("ab", 0).size, 2) +} + +fun testCaseInsensitiveFlag() { + Assert.assertTrue(Regex("(?i-:AbC)").matches("ABC")) +} + +fun testEmptyGroups() { + var regex = Regex("ab(?>)cda") + Assert.assertTrue(regex.matches("abcda")) + + regex = Regex("ab()") + Assert.assertTrue(regex.matches("ab")) + + regex = Regex("abc(?:)(..)") + Assert.assertTrue(regex.matches("abcgf")) +} + +fun testCompileNonCaptGroup() { + var isCompiled = false + + try { + Regex("(?:)", RegexOption.CANON_EQ) + Regex("(?:)", setOf(RegexOption.CANON_EQ, RegexOption.DOT_MATCHES_ALL)) + Regex("(?:)", setOf(RegexOption.CANON_EQ, RegexOption.IGNORE_CASE)) + Regex("(?:)", setOf(RegexOption.CANON_EQ, RegexOption.COMMENTS, RegexOption.UNIX_LINES)) + isCompiled = true + } catch (e: PatternSyntaxException) { + println(e) + } + Assert.assertTrue(isCompiled) +} + +fun testEmbeddedFlags() { + var baseString = "(?i)((?s)a)" + var testString = "A" + var regex = Regex(baseString) + Assert.assertTrue(regex.matches(testString)) + + baseString = "(?x)(?i)(?s)(?d)a" + testString = "A" + regex = Regex(baseString) + Assert.assertTrue(regex.matches(testString)) + + baseString = "(?x)(?i)(?s)(?d)a." + testString = "a\n" + regex = Regex(baseString) + Assert.assertTrue(regex.matches(testString)) + + baseString = "abc(?x:(?i)(?s)(?d)a.)" + testString = "abcA\n" + regex = Regex(baseString) + Assert.assertTrue(regex.matches(testString)) + + baseString = "abc((?x)d)(?i)(?s)a" + testString = "abcdA" + regex = Regex(baseString) + Assert.assertTrue(regex.matches(testString)) +} + +fun testAltWithFlags() { + Regex("|(?i-xi)|()") +} + +fun testRestoreFlagsAfterGroup() { + val baseString = "abc((?x)d) a" + val testString = "abcd a" + val regex = Regex(baseString) + Assert.assertTrue(regex.matches(testString)) +} + +fun testCanonEqFlag() { + + /* + * for decompositions see + * http://www.unicode.org/Public/4.0-Update/UnicodeData-4.0.0.txt + * http://www.unicode.org/reports/tr15/#Decomposition + */ + var baseString: String + var testString: String + var regex: Regex + + baseString = "ab(a*)\\u0001" + regex = Regex(baseString, RegexOption.CANON_EQ) + + baseString = "a(abcdf)d" + regex = Regex(baseString, RegexOption.CANON_EQ) + + baseString = "aabcdfd" + regex = Regex(baseString, RegexOption.CANON_EQ) + + // \u01E0 -> \u0226\u0304 ->\u0041\u0307\u0304 + // \u00CC -> \u0049\u0300 + + baseString = "\u01E0\u00CCcdb(ac)" + testString = "\u0226\u0304\u0049\u0300cdbac" + regex = Regex(baseString, RegexOption.CANON_EQ) + Assert.assertTrue(regex.matches(testString)) + + baseString = "\u01E0cdb(a\u00CCc)" + testString = "\u0041\u0307\u0304cdba\u0049\u0300c" + regex = Regex(baseString, RegexOption.CANON_EQ) + Assert.assertTrue(regex.matches(testString)) + + baseString = "a\u00CC" + testString = "a\u0049\u0300" + regex = Regex(baseString, RegexOption.CANON_EQ) + Assert.assertTrue(regex.matches(testString)) + + baseString = "\u0226\u0304cdb(ac\u0049\u0300)" + testString = "\u01E0cdbac\u00CC" + regex = Regex(baseString, RegexOption.CANON_EQ) + Assert.assertTrue(regex.matches(testString)) + + baseString = "cdb(?:\u0041\u0307\u0304\u00CC)" + testString = "cdb\u0226\u0304\u0049\u0300" + regex = Regex(baseString, RegexOption.CANON_EQ) + Assert.assertTrue(regex.matches(testString)) + + baseString = "\u01E0[a-c]\u0049\u0300cdb(ac)" + testString = "\u01E0b\u00CCcdbac" + regex = Regex(baseString, RegexOption.CANON_EQ) + Assert.assertTrue(regex.matches(testString)) + + baseString = "\u01E0|\u00CCcdb(ac)" + testString = "\u0041\u0307\u0304" + regex = Regex(baseString, RegexOption.CANON_EQ) + Assert.assertTrue(regex.matches(testString)) + + baseString = "\u00CC?cdb(ac)*(\u01E0)*[a-c]" + testString = "cdb\u0041\u0307\u0304b" + regex = Regex(baseString, RegexOption.CANON_EQ) + Assert.assertTrue(regex.matches(testString)) + + baseString = "a\u0300" + regex = Regex(baseString, RegexOption.CANON_EQ) + Assert.assertTrue(regex.containsMatchIn("a\u00E0a")) + + baseString = "\u7B20\uF9F8abc" + regex = Regex(baseString, RegexOption.CANON_EQ) + Assert.assertTrue(regex.matches("\uF9F8\uF9F8abc")) + + // \u01F9 -> \u006E\u0300 + // \u00C3 -> \u0041\u0303 + + baseString = "cdb(?:\u00C3\u006E\u0300)" + testString = "cdb\u0041\u0303\u01F9" + regex = Regex(baseString, RegexOption.CANON_EQ) + Assert.assertTrue(regex.matches(testString)) + + // \u014C -> \u004F\u0304 + // \u0163 -> \u0074\u0327 + + baseString = "cdb(?:\u0163\u004F\u0304)" + testString = "cdb\u0074\u0327\u014C" + regex = Regex(baseString, RegexOption.CANON_EQ) + Assert.assertTrue(regex.matches(testString)) + + // \u00E1->a\u0301 + // canonical ordering takes place \u0301\u0327 -> \u0327\u0301 + + baseString = "c\u0327\u0301" + testString = "c\u0301\u0327" + regex = Regex(baseString, RegexOption.CANON_EQ) + Assert.assertTrue(regex.matches(testString)) + + /* + * Hangul decompositions + */ + // \uD4DB->\u1111\u1171\u11B6 + // \uD21E->\u1110\u116D\u11B5 + // \uD264->\u1110\u1170 + // not Hangul:\u0453->\u0433\u0301 + baseString = "a\uD4DB\u1111\u1171\u11B6\uD264" + regex = Regex(baseString, RegexOption.CANON_EQ) + + baseString = "\u0453c\uD4DB" + regex = Regex(baseString, RegexOption.CANON_EQ) + + baseString = "a\u1110\u116D\u11B5b\uD21Ebc" + regex = Regex(baseString, RegexOption.CANON_EQ) + + baseString = "\uD4DB\uD21E\u1110\u1170cdb(ac)" + testString = "\u1111\u1171\u11B6\u1110\u116D\u11B5\uD264cdbac" + regex = Regex(baseString, RegexOption.CANON_EQ) + Assert.assertTrue(regex.matches(testString)) + + baseString = "\uD4DB\uD264cdb(a\uD21Ec)" + testString = "\u1111\u1171\u11B6\u1110\u1170cdba\u1110\u116D\u11B5c" + regex = Regex(baseString, RegexOption.CANON_EQ) + Assert.assertTrue(regex.matches(testString)) + + baseString = "a\uD4DB" + testString = "a\u1111\u1171\u11B6" + regex = Regex(baseString, RegexOption.CANON_EQ) + Assert.assertTrue(regex.matches(testString)) + + baseString = "a\uD21E" + testString = "a\u1110\u116D\u11B5" + regex = Regex(baseString, RegexOption.CANON_EQ) + Assert.assertTrue(regex.matches(testString)) + + baseString = "\u1111\u1171\u11B6cdb(ac\u1110\u116D\u11B5)" + testString = "\uD4DBcdbac\uD21E" + regex = Regex(baseString, RegexOption.CANON_EQ) + Assert.assertTrue(regex.matches(testString)) + + baseString = "cdb(?:\u1111\u1171\u11B6\uD21E)" + testString = "cdb\uD4DB\u1110\u116D\u11B5" + regex = Regex(baseString, RegexOption.CANON_EQ) + Assert.assertTrue(regex.matches(testString)) + + baseString = "\uD4DB[a-c]\u1110\u116D\u11B5cdb(ac)" + testString = "\uD4DBb\uD21Ecdbac" + regex = Regex(baseString, RegexOption.CANON_EQ) + Assert.assertTrue(regex.matches(testString)) + + baseString = "\uD4DB|\u00CCcdb(ac)" + testString = "\u1111\u1171\u11B6" + regex = Regex(baseString, RegexOption.CANON_EQ) + Assert.assertTrue(regex.matches(testString)) + + baseString = "\uD4DB|\u00CCcdb(ac)" + testString = "\u1111\u1171" + regex = Regex(baseString, RegexOption.CANON_EQ) + Assert.assertFalse(regex.matches(testString)) + + baseString = "\u00CC?cdb(ac)*(\uD4DB)*[a-c]" + testString = "cdb\u1111\u1171\u11B6b" + regex = Regex(baseString, RegexOption.CANON_EQ) + Assert.assertTrue(regex.matches(testString)) + + baseString = "\uD4DB" + regex = Regex(baseString, RegexOption.CANON_EQ) + Assert.assertTrue(regex.containsMatchIn("a\u1111\u1171\u11B6a")) + + baseString = "\u1111" + regex = Regex(baseString, RegexOption.CANON_EQ) + Assert.assertFalse(regex.containsMatchIn("bcda\uD4DBr")) +} + +fun testIndexesCanonicalEq() { + var baseString: String + var testString: String + var regex: Regex + var result: MatchResult? + + baseString = "\uD4DB" + testString = "bcda\u1111\u1171\u11B6awr" + regex = Regex(baseString, RegexOption.CANON_EQ) + result = regex.find(testString) + Assert.assertNotNull(result) + Assert.assertEquals(result!!.range.start, 4) + Assert.assertEquals(result.range.endInclusive, 6) + + baseString = "\uD4DB\u1111\u1171\u11B6" + testString = "bcda\u1111\u1171\u11B6\uD4DBawr" + regex = Regex(baseString, RegexOption.CANON_EQ) + result = regex.find(testString) // Use the same testString + Assert.assertNotNull(result) + Assert.assertEquals(result!!.range.start, 4) + Assert.assertEquals(result.range.endInclusive, 7) + + baseString = "\uD4DB\uD21E\u1110\u1170" + testString = "abcabc\u1111\u1171\u11B6\u1110\u116D\u11B5\uD264cdbac" + regex = Regex(baseString, RegexOption.CANON_EQ) + result = regex.find(testString) + Assert.assertNotNull(result) + Assert.assertEquals(result!!.range.start, 6) + Assert.assertEquals(result.range.endInclusive, 12) +} + +fun testCanonEqFlagWithSupplementaryCharacters() { + + /* + * \u1D1BF->\u1D1BB\u1D16F->\u1D1B9\u1D165\u1D16F in UTF32 + * \uD834\uDDBF->\uD834\uDDBB\uD834\uDD6F + * ->\uD834\uDDB9\uD834\uDD65\uD834\uDD6F in UTF16 + */ + var patString = "abc\uD834\uDDBFef" + var testString = "abc\uD834\uDDB9\uD834\uDD65\uD834\uDD6Fef" + var regex = Regex(patString, RegexOption.CANON_EQ) + Assert.assertTrue(regex.matches(testString)) + + testString = "abc\uD834\uDDBB\uD834\uDD6Fef" + Assert.assertTrue(regex.matches(testString)) + + patString = "abc\uD834\uDDBB\uD834\uDD6Fef" + testString = "abc\uD834\uDDBFef" + regex = Regex(patString, RegexOption.CANON_EQ) + Assert.assertTrue(regex.matches(testString)) + + testString = "abc\uD834\uDDB9\uD834\uDD65\uD834\uDD6Fef" + Assert.assertTrue(regex.matches(testString)) + + patString = "abc\uD834\uDDB9\uD834\uDD65\uD834\uDD6Fef" + testString = "abc\uD834\uDDBFef" + regex = Regex(patString, RegexOption.CANON_EQ) + Assert.assertTrue(regex.matches(testString)) + + testString = "abc\uD834\uDDBB\uD834\uDD6Fef" + Assert.assertTrue(regex.matches(testString)) + + /* + * testSupplementary characters with no decomposition + */ + patString = "a\uD9A0\uDE8Ebc\uD834\uDDBB\uD834\uDD6Fe\uDE8Ef" + testString = "a\uD9A0\uDE8Ebc\uD834\uDDBFe\uDE8Ef" + regex = Regex(patString, RegexOption.CANON_EQ) + Assert.assertTrue(regex.matches(testString)) +} + +fun testRangesWithSurrogatesSupplementary() { + var patString = "[abc\uD8D2]" + var testString = "\uD8D2" + var regex = Regex(patString) + Assert.assertTrue(regex.matches(testString)) + + testString = "a" + Assert.assertTrue(regex.matches(testString)) + + testString = "ef\uD8D2\uDD71gh" + Assert.assertFalse(regex.containsMatchIn(testString)) + + testString = "ef\uD8D2gh" + Assert.assertTrue(regex.containsMatchIn(testString)) + + patString = "[abc\uD8D3&&[c\uD8D3]]" + testString = "c" + regex = Regex(patString) + Assert.assertTrue(regex.matches(testString)) + + testString = "a" + Assert.assertFalse(regex.matches(testString)) + + testString = "ef\uD8D3\uDD71gh" + Assert.assertFalse(regex.containsMatchIn(testString)) + + testString = "ef\uD8D3gh" + Assert.assertTrue(regex.containsMatchIn(testString)) + + patString = "[abc\uD8D3\uDBEE\uDF0C&&[c\uD8D3\uDBEE\uDF0C]]" + testString = "c" + regex = Regex(patString) + Assert.assertTrue(regex.matches(testString)) + + testString = "\uDBEE\uDF0C" + Assert.assertTrue(regex.matches(testString)) + + testString = "ef\uD8D3\uDD71gh" + Assert.assertFalse(regex.containsMatchIn(testString)) + + testString = "ef\uD8D3gh" + Assert.assertTrue(regex.containsMatchIn(testString)) + + patString = "[abc\uDBFC]\uDDC2cd" + testString = "\uDBFC\uDDC2cd" + regex = Regex(patString) + Assert.assertFalse(regex.matches(testString)) + + testString = "a\uDDC2cd" + Assert.assertTrue(regex.matches(testString)) +} + +fun testSequencesWithSurrogatesSupplementary() { + var patString = "abcd\uD8D3" + var testString = "abcd\uD8D3\uDFFC" + var regex = Regex(patString) + Assert.assertFalse(regex.containsMatchIn(testString)) + + testString = "abcd\uD8D3abc" + Assert.assertTrue(regex.containsMatchIn(testString)) + + patString = "ab\uDBEFcd" + testString = "ab\uDBEFcd" + regex = Regex(patString) + Assert.assertTrue(regex.matches(testString)) + + patString = "\uDFFCabcd" + testString = "\uD8D3\uDFFCabcd" + regex = Regex(patString) + Assert.assertFalse(regex.containsMatchIn(testString)) + + testString = "abc\uDFFCabcdecd" + Assert.assertTrue(regex.containsMatchIn(testString)) + + patString = "\uD8D3\uDFFCabcd" + testString = "abc\uD8D3\uD8D3\uDFFCabcd" + regex = Regex(patString) + Assert.assertTrue(regex.containsMatchIn(testString)) +} + +fun testPredefinedClassesWithSurrogatesSupplementary() { + var patString = "[123\\D]" + var testString = "a" + var regex = Regex(patString) + Assert.assertTrue(regex.containsMatchIn(testString)) + + testString = "5" + Assert.assertFalse(regex.containsMatchIn(testString)) + + testString = "3" + Assert.assertTrue(regex.containsMatchIn(testString)) + + // low surrogate + testString = "\uDFC4" + Assert.assertTrue(regex.containsMatchIn(testString)) + + // high surrogate + testString = "\uDADA" + Assert.assertTrue(regex.containsMatchIn(testString)) + + testString = "\uDADA\uDFC4" + Assert.assertTrue(regex.containsMatchIn(testString)) + + testString = "5" + Assert.assertFalse(regex.containsMatchIn(testString)) + + testString = "3" + Assert.assertTrue(regex.containsMatchIn(testString)) + + // low surrogate + testString = "\uDFC4" + Assert.assertTrue(regex.containsMatchIn(testString)) + + // high surrogate + testString = "\uDADA" + Assert.assertTrue(regex.containsMatchIn(testString)) + + testString = "\uDADA\uDFC4" + Assert.assertTrue(regex.containsMatchIn(testString)) + + // surrogate characters + patString = "\\p{Cs}" + testString = "\uD916\uDE27" + regex = Regex(patString) + /* + * see http://www.unicode.org/reports/tr18/#Supplementary_Characters we + * have to treat text as code points not code units. \\p{Cs} matches any + * surrogate character but here testString is a one code point + * consisting of two code units (two surrogate characters) so we find + * nothing + */ + Assert.assertFalse(regex.containsMatchIn(testString)) + + // swap low and high surrogates + testString = "\uDE27\uD916" + Assert.assertTrue(regex.containsMatchIn(testString)) + + patString = "[\uD916\uDE271\uD91623&&[^\\p{Cs}]]" + testString = "1" + regex = Regex(patString) + Assert.assertTrue(regex.containsMatchIn(testString)) + + testString = "\uD916" + regex = Regex(patString) + Assert.assertFalse(regex.containsMatchIn(testString)) + + testString = "\uD916\uDE27" + regex = Regex(patString) + Assert.assertTrue(regex.containsMatchIn(testString)) + + // \uD9A0\uDE8E=\u7828E + // \u78281=\uD9A0\uDE81 + patString = "[a-\uD9A0\uDE8E]" + testString = "\uD9A0\uDE81" + regex = Regex(patString) + Assert.assertTrue(regex.matches(testString)) +} + +fun testDotConstructionWithSurrogatesSupplementary() { + var patString = "." + var testString = "\uD9A0\uDE81" + var regex = Regex(patString) + Assert.assertTrue(regex.matches(testString)) + + testString = "\uDE81" + Assert.assertTrue(regex.matches(testString)) + + testString = "\uD9A0" + Assert.assertTrue(regex.matches(testString)) + + testString = "\n" + Assert.assertFalse(regex.matches(testString)) + + patString = ".*\uDE81" + testString = "\uD9A0\uDE81\uD9A0\uDE81\uD9A0\uDE81" + regex = Regex(patString) + Assert.assertFalse(regex.matches(testString)) + + testString = "\uD9A0\uDE81\uD9A0\uDE81\uDE81" + Assert.assertTrue(regex.matches(testString)) + + patString = ".*" + testString = "\uD9A0\uDE81\n\uD9A0\uDE81\uD9A0\n\uDE81" + regex = Regex(patString, RegexOption.DOT_MATCHES_ALL) + Assert.assertTrue(regex.matches(testString)) +} + +fun testQuantifiersWithSurrogatesSupplementary() { + val patString = "\uD9A0\uDE81*abc" + var testString = "\uD9A0\uDE81\uD9A0\uDE81abc" + val regex = Regex(patString) + Assert.assertTrue(regex.matches(testString)) + + testString = "abc" + Assert.assertTrue(regex.matches(testString)) +} + +fun testAlternationsWithSurrogatesSupplementary() { + val patString = "\uDE81|\uD9A0\uDE81|\uD9A0" + var testString = "\uD9A0" + val regex = Regex(patString) + Assert.assertTrue(regex.matches(testString)) + + testString = "\uDE81" + Assert.assertTrue(regex.matches(testString)) + + testString = "\uD9A0\uDE81" + Assert.assertTrue(regex.matches(testString)) + + testString = "\uDE81\uD9A0" + Assert.assertFalse(regex.matches(testString)) +} + +fun testGroupsWithSurrogatesSupplementary() { + + // this pattern matches nothing + var patString = "(\uD9A0)\uDE81" + var testString = "\uD9A0\uDE81" + var regex = Regex(patString) + Assert.assertFalse(regex.matches(testString)) + + patString = "(\uD9A0)" + testString = "\uD9A0\uDE81" + regex = Regex(patString, RegexOption.DOT_MATCHES_ALL) + Assert.assertFalse(regex.containsMatchIn(testString)) +} + +fun box() { + testCommentsInPattern() + testSplitCharSequenceint() + testFlags() + testFlagsMethod() + testCompileStringint() + testQuantCompileNeg() + testQuantCompilePos() + testQuantComposition() + testTimeZoneIssue() + testCompileRanges() + testRangesSpecialCases() + testZeroSymbols() + testEscapes() + testRegressions() + testOrphanQuantifiers() + testOrphanQuantifiers2() + testBug197() + testURIPatterns() + testFindBoundaryCases1() + testFindBoundaryCases2() + testFindBoundaryCases3() + testFindBoundaryCases4() + testFindBoundaryCases5() + testFindBoundaryCases6() + testBackReferences() + testNewLine() + testFindGreedy() + testSOLQuant() + testIllegalEscape() + testEmptyFamily() + testNonCaptConstr() + testCompilePatternWithTerminatorMark() + testAlternations() + testMatchWithGroups() + testSplitEmptyCharSequence() + testSplitEndsWithPattern() + testCaseInsensitiveFlag() + testEmptyGroups() + testCompileNonCaptGroup() + testEmbeddedFlags() + testAltWithFlags() + testRestoreFlagsAfterGroup() + testCanonEqFlag() + testIndexesCanonicalEq() + testCanonEqFlagWithSupplementaryCharacters() + testRangesWithSurrogatesSupplementary() + testSequencesWithSurrogatesSupplementary() + testPredefinedClassesWithSurrogatesSupplementary() + testDotConstructionWithSurrogatesSupplementary() + testQuantifiersWithSurrogatesSupplementary() + testAlternationsWithSurrogatesSupplementary() + testGroupsWithSurrogatesSupplementary() +} \ No newline at end of file diff --git a/backend.native/tests/external/stdlib/text/RegexTest/harmony/PatternTest2.kt b/backend.native/tests/external/stdlib/text/RegexTest/harmony/PatternTest2.kt new file mode 100644 index 00000000000..35e54b09cee --- /dev/null +++ b/backend.native/tests/external/stdlib/text/RegexTest/harmony/PatternTest2.kt @@ -0,0 +1,1212 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import kotlin.text.* +import kotlin.test.* + +/** + * Tests simple pattern compilation and matching methods + */ +fun testSimpleMatch() { + val regex = Regex("foo.*") + + var testString = "foo123" + Assert.assertTrue(regex.matches(testString)) + Assert.assertTrue(regex.containsMatchIn(testString, 0)) + Assert.assertTrue(regex.lookingAt(testString)) + + testString = "fox" + Assert.assertFalse(regex.matches(testString)) + Assert.assertFalse(regex.containsMatchIn(testString, 0)) + Assert.assertFalse(regex.lookingAt(testString)) + + Assert.assertTrue(Regex("foo.*").matches("foo123")) + Assert.assertFalse(Regex("foo.*").matches("fox")) + Assert.assertFalse(Regex("bar").matches("foobar")) + Assert.assertTrue(Regex("").matches("")) +} + +fun testCursors() { + val regex: Regex + var result: MatchResult? + + try { + regex = Regex("foo") + + result = regex.find("foobar") + Assert.assertNotNull(result) + Assert.assertEquals(0, result!!.range.start) + Assert.assertEquals(3, result.range.endInclusive + 1) + Assert.assertNull(result.next()) + + + result = regex.find("barfoobar") + Assert.assertNotNull(result) + Assert.assertEquals(3, result!!.range.start) + Assert.assertEquals(6, result.range.endInclusive + 1) + Assert.assertNull(result.next()) + + result = regex.find("barfoo") + Assert.assertNotNull(result) + Assert.assertEquals(3, result!!.range.start) + Assert.assertEquals(6, result.range.endInclusive + 1) + Assert.assertNull(result.next()) + + result = regex.find("foobarfoobarfoo") + Assert.assertNotNull(result) + Assert.assertEquals(0, result!!.range.start) + Assert.assertEquals(3, result.range.endInclusive + 1) + result = result.next() + Assert.assertNotNull(result) + Assert.assertEquals(6, result!!.range.start) + Assert.assertEquals(9, result.range.endInclusive + 1) + result = result.next() + Assert.assertNotNull(result) + Assert.assertEquals(12, result!!.range.start) + Assert.assertEquals(15, result.range.endInclusive + 1) + Assert.assertNull(result.next()) + + result = regex.find("foobarfoobarfoo", 0) + Assert.assertNotNull(result) + Assert.assertEquals(0, result!!.range.start) + Assert.assertEquals(3, result.range.endInclusive + 1) + + result = regex.find("foobarfoobarfoo", 4) + Assert.assertNotNull(result) + Assert.assertEquals(6, result!!.range.start) + Assert.assertEquals(9, result.range.endInclusive + 1) + } catch (e: PatternSyntaxException) { + println(e.message) + Assert.fail() + } + +} + +fun testGroups() { + val regex: Regex + var result: MatchResult? + + regex = Regex("(p[0-9]*)#?(q[0-9]*)") + + result = regex.find("p1#q3p2q42p5p71p63#q888") + Assert.assertNotNull(result) + Assert.assertEquals(0, result!!.range.start) + Assert.assertEquals(5, result.range.endInclusive + 1) + Assert.assertEquals(3, result.groups.size) + Assert.assertEquals(0, result.groups[0]!!.range.start) + Assert.assertEquals(5, result.groups[0]!!.range.endInclusive + 1) + Assert.assertEquals(0, result.groups[1]!!.range.start) + Assert.assertEquals(2, result.groups[1]!!.range.endInclusive + 1) + Assert.assertEquals(3, result.groups[2]!!.range.start) + Assert.assertEquals(5, result.groups[2]!!.range.endInclusive + 1) + Assert.assertEquals("p1#q3", result.value) + Assert.assertEquals("p1#q3", result.groupValues[0]) + Assert.assertEquals("p1", result.groupValues[1]) + Assert.assertEquals("q3", result.groupValues[2]) + + result = result.next() + Assert.assertNotNull(result) + Assert.assertEquals(5, result!!.range.start) + Assert.assertEquals(10, result.range.endInclusive + 1) + Assert.assertEquals(3, result.groups.size) + Assert.assertEquals(10, result.groups[0]!!.range.endInclusive + 1) + Assert.assertEquals(5, result.groups[1]!!.range.start) + Assert.assertEquals(7, result.groups[1]!!.range.endInclusive + 1) + Assert.assertEquals(7, result.groups[2]!!.range.start) + Assert.assertEquals(10, result.groups[2]!!.range.endInclusive + 1) + Assert.assertEquals("p2q42", result.value) + Assert.assertEquals("p2q42", result.groupValues[0]) + Assert.assertEquals("p2", result.groupValues[1]) + Assert.assertEquals("q42", result.groupValues[2]) + + result = result.next() + Assert.assertNotNull(result) + Assert.assertEquals(15, result!!.range.start) + Assert.assertEquals(23, result.range.endInclusive + 1) + Assert.assertEquals(3, result.groups.size) + Assert.assertEquals(15, result.groups[0]!!.range.start) + Assert.assertEquals(23, result.groups[0]!!.range.endInclusive + 1) + Assert.assertEquals(15, result.groups[1]!!.range.start) + Assert.assertEquals(18, result.groups[1]!!.range.endInclusive + 1) + Assert.assertEquals(19, result.groups[2]!!.range.start) + Assert.assertEquals(23, result.groups[2]!!.range.endInclusive + 1) + Assert.assertEquals("p63#q888", result.value) + Assert.assertEquals("p63#q888", result.groupValues[0]) + Assert.assertEquals("p63", result.groupValues[1]) + Assert.assertEquals("q888", result.groupValues[2]) + Assert.assertNull(result.next()) +} + +fun testReplace() { + var regex: Regex + + // Note: examples from book, + // Hitchens, Ron, 2002, "Java NIO", O'Reilly, page 171 + regex = Regex("a*b") + + var testString = "aabfooaabfooabfoob" + Assert.assertTrue(regex.replace(testString, "-") == "-foo-foo-foo-") + Assert.assertTrue(regex.replaceFirst(testString, "-") == "-fooaabfooabfoob") + + regex = Regex("([bB])yte") + + testString = "Byte for byte" + Assert.assertTrue(regex.replaceFirst(testString, "$1ite") == "Bite for byte") + Assert.assertTrue(regex.replace(testString, "$1ite") == "Bite for bite") + + regex = Regex("\\d\\d\\d\\d([- ])") + + testString = "card #1234-5678-1234" + Assert.assertTrue(regex.replaceFirst(testString, "xxxx$1") == "card #xxxx-5678-1234") + Assert.assertTrue(regex.replace(testString, "xxxx$1") == "card #xxxx-xxxx-1234") + + regex = Regex("(up|left)( *)(right|down)") + + testString = "left right, up down" + Assert.assertTrue(regex.replaceFirst(testString, "$3$2$1") == "right left, up down") + Assert.assertTrue(regex.replace(testString, "$3$2$1") == "right left, down up") + + regex = Regex("([CcPp][hl]e[ea]se)") + + testString = "I want cheese. Please." + Assert.assertTrue(regex.replaceFirst(testString, " $1 ") == "I want cheese . Please.") + Assert.assertTrue(regex.replace(testString, " $1 ") == "I want cheese . Please .") +} + +fun testEscapes() { + var regex: Regex + var result: MatchResult? + + // Test \\ sequence + regex = Regex("([a-z]+)\\\\([a-z]+);") + result = regex.find("fred\\ginger;abbott\\costello;jekell\\hyde;") + Assert.assertNotNull(result) + Assert.assertEquals("fred", result!!.groupValues[1]) + Assert.assertEquals("ginger", result.groupValues[2]) + result = result.next() + Assert.assertNotNull(result) + Assert.assertEquals("abbott", result!!.groupValues[1]) + Assert.assertEquals("costello", result.groupValues[2]) + result = result.next() + Assert.assertNotNull(result) + Assert.assertEquals("jekell", result!!.groupValues[1]) + Assert.assertEquals("hyde", result.groupValues[2]) + Assert.assertNull(result.next()) + + // Test \n, \t, \r, \f, \e, \a sequences + regex = Regex("([a-z]+)[\\n\\t\\r\\f\\e\\a]+([a-z]+)") + result = regex.find("aa\nbb;cc\u0009\rdd;ee\u000C\u001Bff;gg\n\u0007hh") + Assert.assertNotNull(result) + Assert.assertEquals("aa", result!!.groupValues[1]) + Assert.assertEquals("bb", result.groupValues[2]) + result = result.next() + Assert.assertNotNull(result) + Assert.assertEquals("cc", result!!.groupValues[1]) + Assert.assertEquals("dd", result.groupValues[2]) + result = result.next() + Assert.assertNotNull(result) + Assert.assertEquals("ee", result!!.groupValues[1]) + Assert.assertEquals("ff", result.groupValues[2]) + result = result.next() + Assert.assertNotNull(result) + Assert.assertEquals("gg", result!!.groupValues[1]) + Assert.assertEquals("hh", result.groupValues[2]) + Assert.assertNull(result.next()) + + // Test \\u and \\x sequences + regex = Regex("([0-9]+)[\\u0020:\\x21];") + result = regex.find("11:;22 ;33-;44!;") + Assert.assertNotNull(result) + Assert.assertEquals("11", result!!.groupValues[1]) + result = result.next() + Assert.assertNotNull(result) + Assert.assertEquals("22", result!!.groupValues[1]) + result = result.next() + Assert.assertNotNull(result) + Assert.assertEquals("44", result!!.groupValues[1]) + Assert.assertNull(result.next()) + + // Test invalid unicode sequences // TODO: Double check it. + try { + regex = Regex("\\u") + Assert.fail("PatternSyntaxException expected") + } catch (e: PatternSyntaxException) { + } + + try { + regex = Regex("\\u;") + Assert.fail("PatternSyntaxException expected") + } catch (e: PatternSyntaxException) { + } + + try { + regex = Regex("\\u002") + Assert.fail("PatternSyntaxException expected") + } catch (e: PatternSyntaxException) { + } + + try { + regex = Regex("\\u002;") + Assert.fail("PatternSyntaxException expected") + } catch (e: PatternSyntaxException) { + } + + // Test invalid hex sequences + try { + regex = Regex("\\x") + Assert.fail("PatternSyntaxException expected") + } catch (e: PatternSyntaxException) { + } + + try { + regex = Regex("\\x;") + Assert.fail("PatternSyntaxException expected") + } catch (e: PatternSyntaxException) { + } + + try { + regex = Regex("\\xa") + Assert.fail("PatternSyntaxException expected") + } catch (e: PatternSyntaxException) { + } + + try { + regex = Regex("\\xa;") + Assert.fail("PatternSyntaxException expected") + } catch (e: PatternSyntaxException) { + } + + // Test \0 (octal) sequences (1, 2 and 3 digit) + regex = Regex("([0-9]+)[\\07\\040\\0160];") + result = regex.find("11\u0007;22:;33 ;44p;") + Assert.assertNotNull(result) + Assert.assertEquals("11", result!!.groupValues[1]) + result = result.next() + Assert.assertNotNull(result) + Assert.assertEquals("33", result!!.groupValues[1]) + result = result.next() + Assert.assertNotNull(result) + Assert.assertEquals("44", result!!.groupValues[1]) + Assert.assertNull(result.next()) + + // Test invalid octal sequences + try { + regex = Regex("\\08") + Assert.fail("PatternSyntaxException expected") + } catch (e: PatternSyntaxException) { + } + + try { + regex = Regex("\\0") + Assert.fail("PatternSyntaxException expected") + } catch (e: PatternSyntaxException) { + } + + try { + regex = Regex("\\0;") + Assert.fail("PatternSyntaxException expected") + } catch (e: PatternSyntaxException) { + } + + // Test \c (control character) sequence + regex = Regex("([0-9]+)[\\cA\\cB\\cC\\cD];") + result = regex.find("11\u0001;22:;33\u0002;44p;55\u0003;66\u0004;") + Assert.assertNotNull(result) + Assert.assertEquals("11", result!!.groupValues[1]) + result = result.next() + Assert.assertNotNull(result) + Assert.assertEquals("33", result!!.groupValues[1]) + result = result.next() + Assert.assertNotNull(result) + Assert.assertEquals("55", result!!.groupValues[1]) + result = result.next() + Assert.assertNotNull(result) + Assert.assertEquals("66", result!!.groupValues[1]) + Assert.assertNull(result.next()) + + // More thorough control escape test + // Ensure that each escape matches exactly the corresponding + // character + // code and no others (well, from 0-255 at least) + for (i in 0..25) { + regex = Regex("\\c${'A' + i}") + var match_char = -1 + for (j in 0..255) { + if (regex.matches("${j.toChar()}")) { + Assert.assertEquals(-1, match_char) + match_char = j + } + } + Assert.assertTrue(match_char == i + 1) + } + + + // Test invalid control escapes + try { + regex = Regex("\\c") + Assert.fail("PatternSyntaxException expected") + } catch (e: PatternSyntaxException) { + } +} + +fun testCharacterClasses() { + var regex: Regex + + // Test one character range + regex = Regex("[p].*[l]") + Assert.assertTrue(regex.matches("paul")) + Assert.assertTrue(regex.matches("pool")) + Assert.assertFalse(regex.matches("pong")) + Assert.assertTrue(regex.matches("pl")) + + // Test two character range + regex = Regex("[pm].*[lp]") + Assert.assertTrue(regex.matches("prop")) + Assert.assertTrue(regex.matches("mall")) + Assert.assertFalse(regex.matches("pong")) + Assert.assertTrue(regex.matches("pill")) + + // Test range including [ and ] + regex = Regex("[<\\[].*[\\]>]") + Assert.assertTrue(regex.matches("")) + Assert.assertTrue(regex.matches("[bar]")) + Assert.assertFalse(regex.matches("{foobar]")) + Assert.assertTrue(regex.matches("") + Assert.assertTrue(regex.matches("")) + Assert.assertFalse(regex.matches("")) + val result = regex.find("xyz zzz") + Assert.assertNotNull(result) + Assert.assertNotNull(result!!.next()) + Assert.assertNull(result.next()!!.next()) + + // Test \S (not whitespace) // TODO: We've removed \f from string since kotlin doesn't recognize this escape in a string. + regex = Regex("<[a-z] \\S[0-9][\\S\n]+[^\\S]221>") + Assert.assertTrue(regex.matches("")) + Assert.assertTrue(regex.matches("")) + Assert.assertFalse(regex.matches("")) + Assert.assertTrue(regex.matches("")) + regex = Regex("<[a-z] \\S[0-9][\\S\n]+[^\\S]221[\\S&&[^abc]]>") + Assert.assertTrue(regex.matches("")) + Assert.assertTrue(regex.matches("")) + Assert.assertFalse(regex.matches("")) + Assert.assertFalse(regex.matches("")) + Assert.assertFalse(regex.matches("")) + Assert.assertTrue(regex.matches("")) + + // Test \w (ascii word) + regex = Regex("<\\w+\\s[0-9]+;[^\\w]\\w+/[\\w$]+;") + Assert.assertTrue(regex.matches(""); + * m = p.matcher(""); assertTrue(m.matches()); m = p.matcher(""); + * assertTrue(m.matches()); m = p.matcher(""); + * assertFalse(m.matches()); + */ + regex = Regex("\\p{Lower}+") + Assert.assertTrue(regex.matches("abcdefghijklmnopqrstuvwxyz")) + + // Invalid uses of \p{Lower} + try { + regex = Regex("\\p") + Assert.fail("PatternSyntaxException expected") + } catch (e: PatternSyntaxException) { + } + + try { + regex = Regex("\\p;") + Assert.fail("PatternSyntaxException expected") + } catch (e: PatternSyntaxException) { + } + + try { + regex = Regex("\\p{") + Assert.fail("PatternSyntaxException expected") + } catch (e: PatternSyntaxException) { + } + + try { + regex = Regex("\\p{;") + Assert.fail("PatternSyntaxException expected") + } catch (e: PatternSyntaxException) { + } + + try { + regex = Regex("\\p{Lower") + Assert.fail("PatternSyntaxException expected") + } catch (e: PatternSyntaxException) { + } + + try { + regex = Regex("\\p{Lower;") + Assert.fail("PatternSyntaxException expected") + } catch (e: PatternSyntaxException) { + } + + // Test \p{Upper} + /* + * FIXME: Requires complex range processing p = Regex("<\\p{Upper}\\d\\P{Upper}:[\\p{Upper}z]\\s[^\\P{Upper}]>"); + * m = p.matcher(""); assertTrue(m.matches()); m = p.matcher(""); + * assertTrue(m.matches()); m = p.matcher(""); + * assertFalse(m.matches()); + */ + regex = Regex("\\p{Upper}+") + Assert.assertTrue(regex.matches("ABCDEFGHIJKLMNOPQRSTUVWXYZ")) + + // Invalid uses of \p{Upper} + try { + regex = Regex("\\p{Upper") + Assert.fail("PatternSyntaxException expected") + } catch (e: PatternSyntaxException) { + } + + try { + regex = Regex("\\p{Upper;") + Assert.fail("PatternSyntaxException expected") + } catch (e: PatternSyntaxException) { + } + + // Test \p{ASCII} + /* + * FIXME: Requires complex range processing p = Regex("<\\p{ASCII}\\d\\P{ASCII}:[\\p{ASCII}\u1234]\\s[^\\P{ASCII}]>"); + * m = p.matcher(""); assertTrue(m.matches()); m = + * p.matcher(""); assertTrue(m.matches()); m = + * p.matcher("<\u00846#:E E>"); assertFalse(m.matches()) + */ + regex = Regex("\\p{ASCII}") + for (i in 0 until 0x80) { + Assert.assertTrue(regex.matches("${i.toChar()}")) + } + for (i in 0x80..0xff) { + Assert.assertFalse(regex.matches("${i.toChar()}")) + } + + // Invalid uses of \p{ASCII} + try { + regex = Regex("\\p{ASCII") + Assert.fail("PatternSyntaxException expected") + } catch (e: PatternSyntaxException) { + } + + try { + regex = Regex("\\p{ASCII;") + Assert.fail("PatternSyntaxException expected") + } catch (e: PatternSyntaxException) { + } + + // Test \p{Alpha} + // TODO + + // Test \p{Digit} + // TODO + + // Test \p{XDigit} + // TODO + + // Test \p{Alnum} + // TODO + + // Test \p{Punct} + // TODO + + // Test \p{Graph} + // TODO + + // Test \p{Print} + // TODO + + // Test \p{Blank} + // TODO + + // Test \p{Space} + // TODO + + // Test \p{Cntrl} + // TODO +} + +fun testUnicodeCategories() { + // Test Unicode categories using \p and \P + // One letter codes: L, M, N, P, S, Z, C + // Two letter codes: Lu, Nd, Sc, Sm, ... + // See java.lang.Character and Unicode standard for complete list + // TODO + // Test \p{L} + // TODO + + // Test \p{N} + // TODO + + // ... etc + + // Test two letter codes: + // From unicode.org: + // Lu + // Ll + // Lt + // Lm + // Lo + // Mn + // Mc + // Me + // Nd + // Nl + // No + // Pc + // Pd + // Ps + // Pe + // Pi + // Pf + // Po + // Sm + // Sc + // Sk + // So + // Zs + // Zl + // Zp + // Cc + // Cf + // Cs + // Co + // Cn +} + +fun testUnicodeBlocks() { + var regex: Regex + + // Test Unicode blocks using \p and \P + for (block in UBlocks) { + regex = Regex("\\p{In" + block.name + "}") + if (block.low > 0) { + Assert.assertFalse(regex.matches((block.low - 1).toChar().toString())) + } + for (i in block.low..block.high) { + Assert.assertTrue(regex.matches(i.toChar().toString())) + } + if (block.high < 0xFFFF) { + Assert.assertFalse(regex.matches((block.high + 1).toChar().toString())) + } + + regex = Regex("\\P{In" + block.name + "}") + if (block.low > 0) { + Assert.assertTrue(regex.matches((block.low - 1).toChar().toString())) + } + for (i in block.low..block.high) { + Assert.assertFalse("assert: Regex: $regex, match to: ${i.toChar()} ($i)", regex.matches(i.toChar().toString())) + } + if (block.high < 0xFFFF) { + Assert.assertTrue(regex.matches((block.high + 1).toChar().toString())) + } + + } +} + +fun testCapturingGroups() { + // Test simple capturing groups + // TODO + + // Test grouping without capture (?:...) + // TODO + + // Test combination of grouping and capture + // TODO + + // Test \ sequence with capturing and non-capturing groups + // TODO + + // Test \ with out of range + // TODO +} + +fun testRepeats() { + // Test ? + // TODO + + // Test * + // TODO + + // Test + + // TODO + + // Test {}, including 0, 1 and more + // TODO + + // Test {,}, including 0, 1 and more + // TODO + + // Test {,}, with n1 < n2, n1 = n2 and n1 > n2 (illegal?) + // TODO +} + +fun testAnchors() { + // Test ^, default and MULTILINE + // TODO + + // Test $, default and MULTILINE + // TODO + + // Test \b (word boundary) + // TODO + + // Test \B (not a word boundary) + // TODO + + // Test \A (beginning of string) + // TODO + + // Test \Z (end of string) + // TODO + + // Test \z (end of string) + // TODO + + // Test \G + // TODO + + // Test positive lookahead using (?=...) + // TODO + + // Test negative lookahead using (?!...) + // TODO + + // Test positive lookbehind using (?<=...) + // TODO + + // Test negative lookbehind using (?...) + // TODO + + // Test (?onflags-offflags) + // Valid flags are i,m,d,s,u,x + // TODO + + // Test (?onflags-offflags:...) + // TODO + + // Test \Q, \E + regex = Regex("[a-z]+;\\Q[a-z]+;\\Q(foo.*);\\E[0-9]+") + Assert.assertTrue(regex.matches("abc;[a-z]+;\\Q(foo.*);411")) + Assert.assertFalse(regex.matches("abc;def;foo42;555")) + Assert.assertFalse(regex.matches("abc;\\Qdef;\\Qfoo99;\\E123")) + + regex = Regex("[a-z]+;(foo[0-9]-\\Q(...)\\E);[0-9]+") + val result = regex.matchEntire("abc;foo5-(...);123") + Assert.assertNotNull(result) + Assert.assertEquals("foo5-(...)", result!!.groupValues[1]) + Assert.assertFalse(regex.matches("abc;foo9-(xxx);789")) + + regex = Regex("[a-z]+;(bar[0-9]-[a-z\\Q$-\\E]+);[0-9]+") + Assert.assertTrue(regex.matches("abc;bar0-def$-;123")) + + regex = Regex("[a-z]+;(bar[0-9]-[a-z\\Q-$\\E]+);[0-9]+") + Assert.assertTrue(regex.matches("abc;bar0-def$-;123")) + + regex = Regex("[a-z]+;(bar[0-9]-[a-z\\Q[0-9]\\E]+);[0-9]+") + Assert.assertTrue(regex.matches("abc;bar0-def[99]-]0x[;123")); + + regex = Regex("[a-z]+;(bar[0-9]-[a-z\\[0\\-9\\]]+);[0-9]+") + Assert.assertTrue(regex.matches("abc;bar0-def[99]-]0x[;123")) + + // Test # + // TODO +} + +fun testCompile1() { + val regex = Regex("[0-9A-Za-z][0-9A-Za-z\\x2e\\x3a\\x2d\\x5f]*") + val name = "iso-8859-1" + Assert.assertTrue(regex.matches(name)) +} + +fun testCompile2() { + val findString = "\\Qimport\\E" + val regex = Regex(findString) + regex.containsMatchIn("import a.A;\n\n import b.B;\nclass C {}", 0) +} + +fun testCompile3() { + var regex: Regex + var result: MatchResult? + + regex = Regex("a$") + result = regex.find("a\n") + Assert.assertNotNull(result) + Assert.assertEquals("a", result!!.value) + Assert.assertNull(result.next()) + + regex = Regex("(a$)") + result = regex.find("a\n") + Assert.assertNotNull(result) + Assert.assertEquals("a", result!!.value) + Assert.assertEquals("a", result.groupValues[1]) + Assert.assertNull(result.next()) + + regex = Regex("^.*$", RegexOption.MULTILINE) + + result = regex.find("a\n") + Assert.assertNotNull(result) + Assert.assertEquals("a", result!!.value) + Assert.assertNull(result.next()) + + result = regex.find("a\nb\n") + Assert.assertNotNull(result) + Assert.assertEquals("a", result!!.value) + result = result.next() + Assert.assertNotNull(result) + Assert.assertEquals("b", result!!.value) + Assert.assertNull(result.next()) + + result = regex.find("a\nb") + Assert.assertNotNull(result) + Assert.assertEquals("a", result!!.value) + result = result.next() + Assert.assertNotNull(result) + Assert.assertEquals("b", result!!.value) + Assert.assertNull(result.next()) + + result = regex.find("\naa\r\nbb\rcc\n\n") + Assert.assertNotNull(result) + Assert.assertTrue(result!!.value == "") + result = result.next() + Assert.assertNotNull(result) + Assert.assertEquals("aa", result!!.value) + result = result.next() + Assert.assertNotNull(result) + Assert.assertEquals("bb", result!!.value) + result = result.next() + Assert.assertNotNull(result) + Assert.assertEquals("cc", result!!.value) + result = result.next() + Assert.assertNotNull(result) + Assert.assertTrue(result!!.value == "") + Assert.assertNull(result.next()) + + result = regex.find("a") + Assert.assertNotNull(result) + Assert.assertEquals("a", result!!.value) + Assert.assertNull(result.next()) + + result = regex.find("") + Assert.assertNull(result) + + regex = Regex("^.*$") + result = regex.find("") + Assert.assertNotNull(result) + Assert.assertTrue(result!!.value == "") + Assert.assertNull(result.next()) +} + +fun testCompile4() { + val findString = "\\Qpublic\\E" + val text = StringBuffer(" public class Class {\n" + " public class Class {") + val regex = Regex(findString) + + val result = regex.find(text) + Assert.assertNotNull(result) + Assert.assertEquals(4, result!!.range.start) + + // modify text + text.delete(0, text.length) + text.append("Text have been changed.") + // TODO: Check the existing result. + + Assert.assertNull(regex.find(text)) +} + +fun testCompile5() { + val p = Regex("^[0-9]") + val s = p.split("12", 0) + Assert.assertEquals("", s[0]) + Assert.assertEquals("2", s[1]) + Assert.assertEquals(2, s.size) +} + +private class UBInfo(var low: Int, var high: Int, var name: String) + +companion object { + + // A table representing the unicode categories + // private static UBInfo[] UCategories = { + // Lu + // Ll + // Lt + // Lm + // Lo + // Mn + // Mc + // Me + // Nd + // Nl + // No + // Pc + // Pd + // Ps + // Pe + // Pi + // Pf + // Po + // Sm + // Sc + // Sk + // So + // Zs + // Zl + // Zp + // Cc + // Cf + // Cs + // Co + // Cn + // }; + + // A table representing the unicode character blocks + private val UBlocks = arrayOf( + /* 0000; 007F; Basic Latin */ + UBInfo(0x0000, 0x007F, "BasicLatin"), // Character.UnicodeBlock.BASIC_LATIN + /* 0080; 00FF; Latin-1 Supplement */ + UBInfo(0x0080, 0x00FF, "Latin-1Supplement"), // Character.UnicodeBlock.LATIN_1_SUPPLEMENT + /* 0100; 017F; Latin Extended-A */ + UBInfo(0x0100, 0x017F, "LatinExtended-A"), // Character.UnicodeBlock.LATIN_EXTENDED_A + /* 0180; 024F; Latin Extended-B */ + // new UBInfo (0x0180,0x024F,"InLatinExtended-B"), // + // Character.UnicodeBlock.LATIN_EXTENDED_B + /* 0250; 02AF; IPA Extensions */ + UBInfo(0x0250, 0x02AF, "IPAExtensions"), // Character.UnicodeBlock.IPA_EXTENSIONS + /* 02B0; 02FF; Spacing Modifier Letters */ + UBInfo(0x02B0, 0x02FF, "SpacingModifierLetters"), // Character.UnicodeBlock.SPACING_MODIFIER_LETTERS + /* 0300; 036F; Combining Diacritical Marks */ + UBInfo(0x0300, 0x036F, "CombiningDiacriticalMarks"), // Character.UnicodeBlock.COMBINING_DIACRITICAL_MARKS + /* 0370; 03FF; Greek */ + UBInfo(0x0370, 0x03FF, "Greek"), // Character.UnicodeBlock.GREEK + /* 0400; 04FF; Cyrillic */ + UBInfo(0x0400, 0x04FF, "Cyrillic"), // Character.UnicodeBlock.CYRILLIC + /* 0530; 058F; Armenian */ + UBInfo(0x0530, 0x058F, "Armenian"), // Character.UnicodeBlock.ARMENIAN + /* 0590; 05FF; Hebrew */ + UBInfo(0x0590, 0x05FF, "Hebrew"), // Character.UnicodeBlock.HEBREW + /* 0600; 06FF; Arabic */ + UBInfo(0x0600, 0x06FF, "Arabic"), // Character.UnicodeBlock.ARABIC + /* 0700; 074F; Syriac */ + UBInfo(0x0700, 0x074F, "Syriac"), // Character.UnicodeBlock.SYRIAC + /* 0780; 07BF; Thaana */ + UBInfo(0x0780, 0x07BF, "Thaana"), // Character.UnicodeBlock.THAANA + /* 0900; 097F; Devanagari */ + UBInfo(0x0900, 0x097F, "Devanagari"), // Character.UnicodeBlock.DEVANAGARI + /* 0980; 09FF; Bengali */ + UBInfo(0x0980, 0x09FF, "Bengali"), // Character.UnicodeBlock.BENGALI + /* 0A00; 0A7F; Gurmukhi */ + UBInfo(0x0A00, 0x0A7F, "Gurmukhi"), // Character.UnicodeBlock.GURMUKHI + /* 0A80; 0AFF; Gujarati */ + UBInfo(0x0A80, 0x0AFF, "Gujarati"), // Character.UnicodeBlock.GUJARATI + /* 0B00; 0B7F; Oriya */ + UBInfo(0x0B00, 0x0B7F, "Oriya"), // Character.UnicodeBlock.ORIYA + /* 0B80; 0BFF; Tamil */ + UBInfo(0x0B80, 0x0BFF, "Tamil"), // Character.UnicodeBlock.TAMIL + /* 0C00; 0C7F; Telugu */ + UBInfo(0x0C00, 0x0C7F, "Telugu"), // Character.UnicodeBlock.TELUGU + /* 0C80; 0CFF; Kannada */ + UBInfo(0x0C80, 0x0CFF, "Kannada"), // Character.UnicodeBlock.KANNADA + /* 0D00; 0D7F; Malayalam */ + UBInfo(0x0D00, 0x0D7F, "Malayalam"), // Character.UnicodeBlock.MALAYALAM + /* 0D80; 0DFF; Sinhala */ + UBInfo(0x0D80, 0x0DFF, "Sinhala"), // Character.UnicodeBlock.SINHALA + /* 0E00; 0E7F; Thai */ + UBInfo(0x0E00, 0x0E7F, "Thai"), // Character.UnicodeBlock.THAI + /* 0E80; 0EFF; Lao */ + UBInfo(0x0E80, 0x0EFF, "Lao"), // Character.UnicodeBlock.LAO + /* 0F00; 0FFF; Tibetan */ + UBInfo(0x0F00, 0x0FFF, "Tibetan"), // Character.UnicodeBlock.TIBETAN + /* 1000; 109F; Myanmar */ + UBInfo(0x1000, 0x109F, "Myanmar"), // Character.UnicodeBlock.MYANMAR + /* 10A0; 10FF; Georgian */ + UBInfo(0x10A0, 0x10FF, "Georgian"), // Character.UnicodeBlock.GEORGIAN + /* 1100; 11FF; Hangul Jamo */ + UBInfo(0x1100, 0x11FF, "HangulJamo"), // Character.UnicodeBlock.HANGUL_JAMO + /* 1200; 137F; Ethiopic */ + UBInfo(0x1200, 0x137F, "Ethiopic"), // Character.UnicodeBlock.ETHIOPIC + /* 13A0; 13FF; Cherokee */ + UBInfo(0x13A0, 0x13FF, "Cherokee"), // Character.UnicodeBlock.CHEROKEE + /* 1400; 167F; Unified Canadian Aboriginal Syllabics */ + UBInfo(0x1400, 0x167F, "UnifiedCanadianAboriginalSyllabics"), // Character.UnicodeBlock.UNIFIED_CANADIAN_ABORIGINAL_SYLLABICS + /* 1680; 169F; Ogham */ + UBInfo(0x1680, 0x169F, "Ogham"), // Character.UnicodeBlock.OGHAM + /* 16A0; 16FF; Runic */ + UBInfo(0x16A0, 0x16FF, "Runic"), // Character.UnicodeBlock.RUNIC + /* 1780; 17FF; Khmer */ + UBInfo(0x1780, 0x17FF, "Khmer"), // Character.UnicodeBlock.KHMER + /* 1800; 18AF; Mongolian */ + UBInfo(0x1800, 0x18AF, "Mongolian"), // Character.UnicodeBlock.MONGOLIAN + /* 1E00; 1EFF; Latin Extended Additional */ + UBInfo(0x1E00, 0x1EFF, "LatinExtendedAdditional"), // Character.UnicodeBlock.LATIN_EXTENDED_ADDITIONAL + /* 1F00; 1FFF; Greek Extended */ + UBInfo(0x1F00, 0x1FFF, "GreekExtended"), // Character.UnicodeBlock.GREEK_EXTENDED + /* 2000; 206F; General Punctuation */ + UBInfo(0x2000, 0x206F, "GeneralPunctuation"), // Character.UnicodeBlock.GENERAL_PUNCTUATION + /* 2070; 209F; Superscripts and Subscripts */ + UBInfo(0x2070, 0x209F, "SuperscriptsandSubscripts"), // Character.UnicodeBlock.SUPERSCRIPTS_AND_SUBSCRIPTS + /* 20A0; 20CF; Currency Symbols */ + UBInfo(0x20A0, 0x20CF, "CurrencySymbols"), // Character.UnicodeBlock.CURRENCY_SYMBOLS + /* 20D0; 20FF; Combining Marks for Symbols */ + UBInfo(0x20D0, 0x20FF, "CombiningMarksforSymbols"), // Character.UnicodeBlock.COMBINING_MARKS_FOR_SYMBOLS + /* 2100; 214F; Letterlike Symbols */ + UBInfo(0x2100, 0x214F, "LetterlikeSymbols"), // Character.UnicodeBlock.LETTERLIKE_SYMBOLS + /* 2150; 218F; Number Forms */ + UBInfo(0x2150, 0x218F, "NumberForms"), // Character.UnicodeBlock.NUMBER_FORMS + /* 2190; 21FF; Arrows */ + UBInfo(0x2190, 0x21FF, "Arrows"), // Character.UnicodeBlock.ARROWS + /* 2200; 22FF; Mathematical Operators */ + UBInfo(0x2200, 0x22FF, "MathematicalOperators"), // Character.UnicodeBlock.MATHEMATICAL_OPERATORS + /* 2300; 23FF; Miscellaneous Technical */ + UBInfo(0x2300, 0x23FF, "MiscellaneousTechnical"), // Character.UnicodeBlock.MISCELLANEOUS_TECHNICAL + /* 2400; 243F; Control Pictures */ + UBInfo(0x2400, 0x243F, "ControlPictures"), // Character.UnicodeBlock.CONTROL_PICTURES + /* 2440; 245F; Optical Character Recognition */ + UBInfo(0x2440, 0x245F, "OpticalCharacterRecognition"), // Character.UnicodeBlock.OPTICAL_CHARACTER_RECOGNITION + /* 2460; 24FF; Enclosed Alphanumerics */ + UBInfo(0x2460, 0x24FF, "EnclosedAlphanumerics"), // Character.UnicodeBlock.ENCLOSED_ALPHANUMERICS + /* 2500; 257F; Box Drawing */ + UBInfo(0x2500, 0x257F, "BoxDrawing"), // Character.UnicodeBlock.BOX_DRAWING + /* 2580; 259F; Block Elements */ + UBInfo(0x2580, 0x259F, "BlockElements"), // Character.UnicodeBlock.BLOCK_ELEMENTS + /* 25A0; 25FF; Geometric Shapes */ + UBInfo(0x25A0, 0x25FF, "GeometricShapes"), // Character.UnicodeBlock.GEOMETRIC_SHAPES + /* 2600; 26FF; Miscellaneous Symbols */ + UBInfo(0x2600, 0x26FF, "MiscellaneousSymbols"), // Character.UnicodeBlock.MISCELLANEOUS_SYMBOLS + /* 2700; 27BF; Dingbats */ + UBInfo(0x2700, 0x27BF, "Dingbats"), // Character.UnicodeBlock.DINGBATS + /* 2800; 28FF; Braille Patterns */ + UBInfo(0x2800, 0x28FF, "BraillePatterns"), // Character.UnicodeBlock.BRAILLE_PATTERNS + /* 2E80; 2EFF; CJK Radicals Supplement */ + UBInfo(0x2E80, 0x2EFF, "CJKRadicalsSupplement"), // Character.UnicodeBlock.CJK_RADICALS_SUPPLEMENT + /* 2F00; 2FDF; Kangxi Radicals */ + UBInfo(0x2F00, 0x2FDF, "KangxiRadicals"), // Character.UnicodeBlock.KANGXI_RADICALS + /* 2FF0; 2FFF; Ideographic Description Characters */ + UBInfo(0x2FF0, 0x2FFF, "IdeographicDescriptionCharacters"), // Character.UnicodeBlock.IDEOGRAPHIC_DESCRIPTION_CHARACTERS + /* 3000; 303F; CJK Symbols and Punctuation */ + UBInfo(0x3000, 0x303F, "CJKSymbolsandPunctuation"), // Character.UnicodeBlock.CJK_SYMBOLS_AND_PUNCTUATION + /* 3040; 309F; Hiragana */ + UBInfo(0x3040, 0x309F, "Hiragana"), // Character.UnicodeBlock.HIRAGANA + /* 30A0; 30FF; Katakana */ + UBInfo(0x30A0, 0x30FF, "Katakana"), // Character.UnicodeBlock.KATAKANA + /* 3100; 312F; Bopomofo */ + UBInfo(0x3100, 0x312F, "Bopomofo"), // Character.UnicodeBlock.BOPOMOFO + /* 3130; 318F; Hangul Compatibility Jamo */ + UBInfo(0x3130, 0x318F, "HangulCompatibilityJamo"), // Character.UnicodeBlock.HANGUL_COMPATIBILITY_JAMO + /* 3190; 319F; Kanbun */ + UBInfo(0x3190, 0x319F, "Kanbun"), // Character.UnicodeBlock.KANBUN + /* 31A0; 31BF; Bopomofo Extended */ + UBInfo(0x31A0, 0x31BF, "BopomofoExtended"), // Character.UnicodeBlock.BOPOMOFO_EXTENDED + /* 3200; 32FF; Enclosed CJK Letters and Months */ + UBInfo(0x3200, 0x32FF, "EnclosedCJKLettersandMonths"), // Character.UnicodeBlock.ENCLOSED_CJK_LETTERS_AND_MONTHS + /* 3300; 33FF; CJK Compatibility */ + UBInfo(0x3300, 0x33FF, "CJKCompatibility"), // Character.UnicodeBlock.CJK_COMPATIBILITY + /* 3400; 4DB5; CJK Unified Ideographs Extension A */ + UBInfo(0x3400, 0x4DB5, "CJKUnifiedIdeographsExtensionA"), // Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A + /* 4E00; 9FFF; CJK Unified Ideographs */ + UBInfo(0x4E00, 0x9FFF, "CJKUnifiedIdeographs"), // Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS + /* A000; A48F; Yi Syllables */ + UBInfo(0xA000, 0xA48F, "YiSyllables"), // Character.UnicodeBlock.YI_SYLLABLES + /* A490; A4CF; Yi Radicals */ + UBInfo(0xA490, 0xA4CF, "YiRadicals"), // Character.UnicodeBlock.YI_RADICALS + /* AC00; D7A3; Hangul Syllables */ + UBInfo(0xAC00, 0xD7A3, "HangulSyllables"), // Character.UnicodeBlock.HANGUL_SYLLABLES + /* D800; DB7F; High Surrogates */ + /* DB80; DBFF; High Private Use Surrogates */ + /* DC00; DFFF; Low Surrogates */ + /* E000; F8FF; Private Use */ + /* F900; FAFF; CJK Compatibility Ideographs */ + UBInfo(0xF900, 0xFAFF, "CJKCompatibilityIdeographs"), // Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS + /* FB00; FB4F; Alphabetic Presentation Forms */ + UBInfo(0xFB00, 0xFB4F, "AlphabeticPresentationForms"), // Character.UnicodeBlock.ALPHABETIC_PRESENTATION_FORMS + /* FB50; FDFF; Arabic Presentation Forms-A */ + UBInfo(0xFB50, 0xFDFF, "ArabicPresentationForms-A"), // Character.UnicodeBlock.ARABIC_PRESENTATION_FORMS_A + /* FE20; FE2F; Combining Half Marks */ + UBInfo(0xFE20, 0xFE2F, "CombiningHalfMarks"), // Character.UnicodeBlock.COMBINING_HALF_MARKS + /* FE30; FE4F; CJK Compatibility Forms */ + UBInfo(0xFE30, 0xFE4F, "CJKCompatibilityForms"), // Character.UnicodeBlock.CJK_COMPATIBILITY_FORMS + /* FE50; FE6F; Small Form Variants */ + UBInfo(0xFE50, 0xFE6F, "SmallFormVariants"), // Character.UnicodeBlock.SMALL_FORM_VARIANTS + /* FE70; FEFE; Arabic Presentation Forms-B */ + // new UBInfo (0xFE70,0xFEFE,"InArabicPresentationForms-B"), // + // Character.UnicodeBlock.ARABIC_PRESENTATION_FORMS_B + /* FEFF; FEFF; Specials */ + UBInfo(0xFEFF, 0xFEFF, "Specials"), // Character.UnicodeBlock.SPECIALS + /* FF00; FFEF; Halfwidth and Fullwidth Forms */ + UBInfo(0xFF00, 0xFFEF, "HalfwidthandFullwidthForms"), // Character.UnicodeBlock.HALFWIDTH_AND_FULLWIDTH_FORMS + /* FFF0; FFFD; Specials */ + UBInfo(0xFFF0, 0xFFFD, "Specials") // Character.UnicodeBlock.SPECIALS + ) +} + +fun box() { + testSimpleMatch() + testCursors() + testGroups() + testReplace() + testEscapes() + testCharacterClasses() + testPOSIXGroups() + testUnicodeCategories() + testUnicodeBlocks() + testCapturingGroups() + testRepeats() + testAnchors() + testMisc() + testCompile1() + testCompile2() + testCompile3() + testCompile4() + testCompile5() +} \ No newline at end of file diff --git a/backend.native/tests/external/stdlib/text/RegexTest/harmony/ReplaceTest.kt b/backend.native/tests/external/stdlib/text/RegexTest/harmony/ReplaceTest.kt new file mode 100644 index 00000000000..0de953a396b --- /dev/null +++ b/backend.native/tests/external/stdlib/text/RegexTest/harmony/ReplaceTest.kt @@ -0,0 +1,85 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import kotlin.text.* +import kotlin.test.* + +fun testSimpleReplace() { + val target: String + val pattern: String + val repl: String + + target = "foobarfobarfoofo1" + pattern = "fo[^o]" + repl = "xxx" + + val regex = Regex(pattern) + + Assert.assertEquals("foobarxxxarfoofo1", regex.replaceFirst(target, repl)) + Assert.assertEquals("foobarxxxarfooxxx", regex.replace(target, repl)) +} + +fun testCaptureReplace() { + var target: String + var pattern: String + var repl: String + var s: String + var regex: Regex + + target = "[31]foo;bar[42];[99]xyz" + pattern = "\\[([0-9]+)\\]([a-z]+)" + repl = "$2[$1]" + + regex = Regex(pattern) + s = regex.replaceFirst(target, repl) + Assert.assertEquals("foo[31];bar[42];[99]xyz", s) + s = regex.replace(target, repl) + Assert.assertEquals("foo[31];bar[42];xyz[99]", s) + + target = "[31]foo(42)bar{63}zoo;[12]abc(34)def{56}ghi;{99}xyz[88]xyz(77)xyz;" + pattern = "\\[([0-9]+)\\]([a-z]+)\\(([0-9]+)\\)([a-z]+)\\{([0-9]+)\\}([a-z]+)" + repl = "[$5]$6($3)$4{$1}$2" + regex = Regex(pattern) + s = regex.replaceFirst(target, repl) + Assert.assertEquals("[63]zoo(42)bar{31}foo;[12]abc(34)def{56}ghi;{99}xyz[88]xyz(77)xyz;", s) + s = regex.replace(target, repl) + Assert.assertEquals("[63]zoo(42)bar{31}foo;[56]ghi(34)def{12}abc;{99}xyz[88]xyz(77)xyz;", s) +} + +fun testEscapeReplace() { + val target: String + val pattern: String + var repl: String + var s: String + + target = "foo'bar''foo" + pattern = "'" + repl = "\\'" + s = target.replace(pattern.toRegex(), repl) + Assert.assertEquals("foo'bar''foo", s) + repl = "\\\\'" + s = target.replace(pattern.toRegex(), repl) + Assert.assertEquals("foo\\'bar\\'\\'foo", s) + repl = "\\$3" + s = target.replace(pattern.toRegex(), repl) + Assert.assertEquals("foo$3bar$3$3foo", s) +} + +fun box() { + testSimpleReplace() + testCaptureReplace() + testEscapeReplace() +} diff --git a/backend.native/tests/external/stdlib/text/RegexTest/harmony/SplitTest.kt b/backend.native/tests/external/stdlib/text/RegexTest/harmony/SplitTest.kt new file mode 100644 index 00000000000..8b7573d7e1e --- /dev/null +++ b/backend.native/tests/external/stdlib/text/RegexTest/harmony/SplitTest.kt @@ -0,0 +1,157 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import kotlin.text.* +import kotlin.test.* + +fun testSimple() { + val p = Regex("/") + val results = p.split("have/you/done/it/right") + val expected = arrayOf("have", "you", "done", "it", "right") + Assert.assertEquals(expected.size, results.size) + for (i in expected.indices) { + Assert.assertEquals(results[i], expected[i]) + } +} + +@Throws(PatternSyntaxException::class) +fun testSplit1() { + var p = Regex(" ") + + val input = "poodle zoo" + var tokens: List + + tokens = p.split(input, 1) + Assert.assertEquals(1, tokens.size) + Assert.assertTrue(tokens[0] == input) + tokens = p.split(input, 2) + Assert.assertEquals(2, tokens.size) + Assert.assertEquals("poodle", tokens[0]) + Assert.assertEquals("zoo", tokens[1]) + tokens = p.split(input, 5) + Assert.assertEquals(2, tokens.size) + Assert.assertEquals("poodle", tokens[0]) + Assert.assertEquals("zoo", tokens[1]) + tokens = p.split(input, 0) + Assert.assertEquals(2, tokens.size) + Assert.assertEquals("poodle", tokens[0]) + Assert.assertEquals("zoo", tokens[1]) + tokens = p.split(input) + Assert.assertEquals(2, tokens.size) + Assert.assertEquals("poodle", tokens[0]) + Assert.assertEquals("zoo", tokens[1]) + + p = Regex("d") + + tokens = p.split(input, 1) + Assert.assertEquals(1, tokens.size) + Assert.assertTrue(tokens[0] == input) + tokens = p.split(input, 2) + Assert.assertEquals(2, tokens.size) + Assert.assertEquals("poo", tokens[0]) + Assert.assertEquals("le zoo", tokens[1]) + tokens = p.split(input, 5) + Assert.assertEquals(2, tokens.size) + Assert.assertEquals("poo", tokens[0]) + Assert.assertEquals("le zoo", tokens[1]) + tokens = p.split(input, 0) + Assert.assertEquals(2, tokens.size) + Assert.assertEquals("poo", tokens[0]) + Assert.assertEquals("le zoo", tokens[1]) + tokens = p.split(input) + Assert.assertEquals(2, tokens.size) + Assert.assertEquals("poo", tokens[0]) + Assert.assertEquals("le zoo", tokens[1]) + + p = Regex("o") + + tokens = p.split(input, 1) + Assert.assertEquals(1, tokens.size) + Assert.assertTrue(tokens[0] == input) + tokens = p.split(input, 2) + Assert.assertEquals(2, tokens.size) + Assert.assertEquals("p", tokens[0]) + Assert.assertEquals("odle zoo", tokens[1]) + tokens = p.split(input, 5) + Assert.assertEquals(5, tokens.size) + Assert.assertEquals("p", tokens[0]) + Assert.assertTrue(tokens[1] == "") + Assert.assertEquals("dle z", tokens[2]) + Assert.assertTrue(tokens[3] == "") + Assert.assertTrue(tokens[4] == "") + tokens = p.split(input, 0) + Assert.assertEquals(5, tokens.size) + Assert.assertEquals("p", tokens[0]) + Assert.assertTrue(tokens[1] == "") + Assert.assertEquals("dle z", tokens[2]) + Assert.assertTrue(tokens[3] == "") + Assert.assertTrue(tokens[4] == "") + tokens = p.split(input) + Assert.assertEquals(5, tokens.size) + Assert.assertEquals("p", tokens[0]) + Assert.assertTrue(tokens[1] == "") + Assert.assertEquals("dle z", tokens[2]) + Assert.assertTrue(tokens[3] == "") + Assert.assertTrue(tokens[4] == "") +} + +fun testSplit2() { + val p = Regex("") + var s: List + s = p.split("a", 0) + Assert.assertEquals(3, s.size) + Assert.assertEquals("", s[0]) + Assert.assertEquals("a", s[1]) + Assert.assertEquals("", s[2]) + + s = p.split("", 0) + Assert.assertEquals(1, s.size) + Assert.assertEquals("", s[0]) + + s = p.split("abcd", 0) + Assert.assertEquals(6, s.size) + Assert.assertEquals("", s[0]) + Assert.assertEquals("a", s[1]) + Assert.assertEquals("b", s[2]) + Assert.assertEquals("c", s[3]) + Assert.assertEquals("d", s[4]) + Assert.assertEquals("", s[5]) +} + +fun testSplitSupplementaryWithEmptyString() { + + /* + * See http://www.unicode.org/reports/tr18/#Supplementary_Characters We + * have to treat text as code points not code units. + */ + val p = Regex("") + val s: List + s = p.split("a\ud869\uded6b", 0) + Assert.assertEquals(5, s.size) + Assert.assertEquals("", s[0]) + Assert.assertEquals("a", s[1]) + Assert.assertEquals("\ud869\uded6", s[2]) + Assert.assertEquals("b", s[3]) + Assert.assertEquals("", s[4]) +} + +fun box() { + testSimple() + testSplit1() + testSplit2() + testSplitSupplementaryWithEmptyString() +}