[WASM] Regex std implementation

This commit is contained in:
Igor Yakovlev
2021-11-26 15:23:40 +01:00
committed by TeamCityServer
parent 4f9b54da26
commit d55e16a030
78 changed files with 3403 additions and 1286 deletions
@@ -0,0 +1,65 @@
/*
* 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.
*/
package test.text.harmony_regex
import kotlin.text.*
import kotlin.test.*
class AllCodePointsTest {
fun assertTrue(msg: String, value: Boolean) = assertTrue(value, msg)
fun assertFalse(msg: String, value: Boolean) = assertFalse(value, msg)
fun codePointToString(codePoint: Int): String {
val charArray = Char.toChars(codePoint)
return charArray.concatToString(0, charArray.size)
}
// TODO: Here is a performance problem: an execution of this test requires much more time than it in Kotlin/JVM.
@Test fun test() {
// Regression for HARMONY-3145
var p = Regex("(\\p{all})+")
var res = true
var cnt = 0
var s: String
for (i in 0..1114111) {
s = codePointToString(i)
if (!s.matches(p)) {
cnt++
res = false
}
}
assertTrue(res)
assertEquals(0, cnt)
p = Regex("(\\P{all})+")
res = true
cnt = 0
for (i in 0..1114111) {
s = codePointToString(i)
if (!s.matches(p)) {
cnt++
res = false
}
}
assertFalse(res)
assertEquals(0x110000, cnt)
}
}
@@ -0,0 +1,70 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
package test.text.harmony_regex
import kotlin.text.*
import kotlin.test.*
class FindAllTest {
internal fun Regex.allGroups(text: String) =
findAll(text).map {
it.groups.mapIndexed { index, it ->
"$index => ${it?.value}"
}.joinToString("; ")
}.toList()
/**
* Tests regular expressions with lookbehind asserts.
*/
@Test fun testLookBehind() {
var regex: Regex
var result: List<String>
regex = "(?<=^/nl(?:/nl)?/\\d{1,600}[\\d+]{0,600}/[\\d+]{0,600})(\\d+)".toRegex()
result = regex.allGroups("/nl/nl/1+2/3+4/")
assertEquals(2, result.count())
assertEquals("0 => 3; 1 => 3", result[0])
assertEquals("0 => 4; 1 => 4", result[1])
regex = "abe(?<=[ab][!be](.|\\b))(=|t)".toRegex()
result = regex.allGroups("abet abe=")
assertEquals(2, result.count())
assertEquals("0 => abet; 1 => e; 2 => t", result[0])
assertEquals("0 => abe=; 1 => ; 2 => =", result[1])
}
/**
* Tests regular expressions with lookahead asserts.
*/
@Test fun testLookAheadBehind() {
var regex: Regex
var result: List<String>
regex = "a(?=b?)(\\w|)c".toRegex()
result = regex.allGroups("abcfgac")
assertEquals(2, result.count())
assertEquals("0 => abc; 1 => b", result[0])
assertEquals("0 => ac; 1 => ", result[1])
regex = "[a!](?=d|&)\\b[&d]".toRegex()
result = regex.allGroups("ada& !d!&")
assertEquals(2, result.count())
assertEquals("0 => a&", result[0])
assertEquals("0 => !d", result[1])
regex = "(?=ab)(a|^)b".toRegex()
result = regex.allGroups("abcab")
assertEquals(2, result.count())
assertEquals("0 => ab; 1 => a", result[0])
assertEquals("0 => ab; 1 => a", result[1])
regex = "(?=[a-k][a-z])(?=[a-d][c-x])[d-y][x-z]".toRegex()
result = regex.allGroups("abdydx")
assertEquals(1, result.count())
assertEquals("0 => dx", result[0])
}
}
@@ -0,0 +1,479 @@
/*
* 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.
*/
package test.text.harmony_regex
import kotlin.text.*
import kotlin.test.*
class MatchResultTest {
fun assertTrue(msg: String, value: Boolean) = assertTrue(value, msg)
fun assertFalse(msg: String, value: Boolean) = assertFalse(value, msg)
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)")
@Test fun testReplaceAll() {
val input = "aabfooaabfooabfoob"
val pattern = "a*b"
val regex = Regex(pattern)
assertEquals("-foo-foo-foo-", regex.replace(input, "-"))
}
@Test 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)
*/
@Test fun testGroupint() {
val positiveTestString = "ababababbaaabb"
// test IndexOutOfBoundsException
// //
for (i in groupPatterns.indices) {
val regex = Regex(groupPatterns[i])
val result = regex.matchEntire(positiveTestString)!!
try {
// groupPattern <index + 1> 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(groupResults[i][j], result.groupValues[j + 1], "i: $i j: $j")
}
}
}
@Test 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)
}
}
@Test fun testGroupPossessive() {
val regex = Regex("((a)|(b))++c")
assertEquals("a", regex.matchEntire("aac")!!.groupValues[1])
}
@Test 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]))
}
}
}
@Test 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"))
}
@Test 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()
*/
@Test 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()
}
}
@Test fun testSEOLsymbols() {
val regex = Regex("^a\\(bb\\[$")
assertTrue(regex.matches("a(bb["))
}
@Test fun testGroupCount() {
for (i in groupPatterns.indices) {
val regex = Regex(groupPatterns[i])
val result = regex.matchEntire("ababababbaaabb")!!
assertEquals(i + 1, result.groups.size - 1)
}
}
@Test 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")
}
}
@Test fun testEnhancedFind() {
val input = "foob"
val pattern = "a*b"
val regex = Regex(pattern)
val result = regex.find(input)!!
assertEquals("b", result.groupValues[0])
}
@Test 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"))
}
@Test 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"))
}
@Test 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"
}
}
@Test 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])
}
@Test 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"))
}
@Test fun testQuoteReplacement() {
assertEquals("\\\\aaCC\\$1", Regex.escapeReplacement("\\aaCC$1"))
}
@Test 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])
}
@Test fun testUnicode() {
assertTrue(Regex("\\x61a").matches("aa"))
assertTrue(Regex("\\u0061a").matches("aa"))
assertTrue(Regex("\\0141a").matches("aa"))
assertTrue(Regex("\\0777").matches("?7"))
}
@Test 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"))
}
@Test fun testSplitEmpty() {
val regex = Regex("")
val s = regex.split("", 0)
assertEquals(2, s.size)
assertEquals("", s[0])
assertEquals("", s[1])
}
@Test fun testFindDollar() {
val regex = Regex("a$")
val result = regex.find("a\n")
assertTrue(result != null)
assertEquals("a", result!!.groupValues[0])
}
/*
* Regression test for HARMONY-674
*/
@Test fun testPatternMatcher() {
assertTrue(Regex("(?:\\d+)(?:pt)").matches("14pt"))
}
/**
* Inspired by HARMONY-3360
*/
@Test fun test3360() {
val str = "!\"#%&'(),-./"
val regex = Regex("\\s")
assertFalse(regex.containsMatchIn(str))
}
/**
* Regression test for HARMONY-3360
*/
@Test fun testGeneralPunctuationCategory() {
val s = arrayOf(",", "!", "\"", "#", "%", "&", "'", "(", ")", "-", ".", "/")
val regexp = "\\p{P}"
for (i in s.indices) {
val regex = Regex(regexp)
assertTrue(regex.containsMatchIn(s[i]))
}
}
/**
* Regression test for https://github.com/JetBrains/kotlin-native/issues/2297
*/
@Test fun test2297() {
assertTrue(Regex("^(:[0-5]?[0-9])+$").matches(":20:30"))
assertTrue(Regex("(.{1,}){2}").matches("aa"))
assertTrue(Regex("(.+b)+").matches("0b0b"))
assertTrue(Regex("(.+?b)+").matches("0b0b"))
assertTrue(Regex("(.?b)+").matches("0b0b"))
assertTrue(Regex("(.??b)+").matches("0b0b"))
assertTrue(Regex("(.*b)+").matches("0b0b"))
assertTrue(Regex("(.*?b)+").matches("0b0b"))
assertTrue(Regex("(.{1,2}b)+").matches("0b00b"))
assertTrue(Regex("(.{1,2}?b)+").matches("0b00b"))
assertTrue(Regex("([0]?[0]?)+").matches("0000"))
assertTrue(Regex("([0]?[0]?b)+").matches("00b00b"))
assertTrue(Regex("((b{2}){3})+").matches("bbbbbbbbbbbb"))
assertTrue(Regex("[^a]").matches("b"))
}
@Test fun kt28158() {
val comment = "😃😃😃😃😃😃"
val regex = Regex("(.{3,})\\1+", RegexOption.IGNORE_CASE)
assertTrue(comment.contains(regex))
}
}
@@ -0,0 +1,117 @@
/* 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.
*/
package test.text.harmony_regex
import kotlin.text.*
import kotlin.test.*
class MatchResultTest2 {
@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")
assertTrue(result != null)
assertEquals(0, result!!.range.start)
assertEquals(7, result.range.endInclusive)
assertEquals(0, result.groups[0]!!.range.start)
assertEquals(7, result.groups[0]!!.range.endInclusive)
assertEquals(0, result.groups[1]!!.range.start)
assertEquals(3, result.groups[1]!!.range.endInclusive)
assertEquals(4, result.groups[2]!!.range.start)
assertEquals(7, result.groups[2]!!.range.endInclusive)
try {
result.groups[3]
fail("IndexOutOfBoundsException expected")
} catch (e: IndexOutOfBoundsException) {
}
try {
result.groupValues[3]
fail("IndexOutOfBoundsException expected")
} catch (e: IndexOutOfBoundsException) {
}
try {
result.groups[-1]
fail("IndexOutOfBoundsException expected")
} catch (e: IndexOutOfBoundsException) {
}
try {
result.groupValues[-1]
fail("IndexOutOfBoundsException expected")
} catch (e: IndexOutOfBoundsException) {
}
result = result.next()
assertTrue(result != null)
assertEquals(8, result!!.range.start)
assertEquals(15, result.range.endInclusive)
assertEquals(8, result.groups[0]!!.range.start)
assertEquals(15, result.groups[0]!!.range.endInclusive)
assertEquals(8, result.groups[1]!!.range.start)
assertEquals(11, result.groups[1]!!.range.endInclusive)
assertEquals(12, result.groups[2]!!.range.start)
assertEquals(15, result.groups[2]!!.range.endInclusive)
try {
result.groups[3]
fail("IndexOutOfBoundsException expected")
} catch (e: IndexOutOfBoundsException) {
}
try {
result.groupValues[3]
fail("IndexOutOfBoundsException expected")
} catch (e: IndexOutOfBoundsException) {
}
try {
result.groups[-1]
fail("IndexOutOfBoundsException expected")
} catch (e: IndexOutOfBoundsException) {
}
try {
result.groupValues[-1]
fail("IndexOutOfBoundsException expected")
} catch (e: IndexOutOfBoundsException) {
}
result = result.next()
assertFalse(result != null)
}
/*
* Regression test for HARMONY-997
*/
@Test fun testReplacementBackSlash() {
val str = "replace me"
val replacedString = "me"
val substitutionString = "\\"
val regex = Regex(replacedString)
try {
regex.replace(str, substitutionString)
fail("IllegalArgumentException should be thrown")
} catch (e: IllegalArgumentException) {
}
}
}
@@ -0,0 +1,117 @@
/* 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.
*/
package test.text.harmony_regex
import kotlin.text.*
import kotlin.test.*
class ModeTest {
/**
* Tests Pattern compilation modes and modes triggered in pattern strings
*/
@Test fun testCase() {
var regex: Regex
var result: MatchResult?
regex = Regex("([a-z]+)[0-9]+")
result = regex.find("cAT123#dog345")
assertNotNull(result)
assertEquals("dog", result!!.groupValues[1])
assertNull(result.next())
regex = Regex("([a-z]+)[0-9]+", RegexOption.IGNORE_CASE)
result = regex.find("cAt123#doG345")
assertNotNull(result)
assertEquals("cAt", result!!.groupValues[1])
result = result.next()
assertNotNull(result)
assertEquals("doG", result!!.groupValues[1])
assertNull(result.next())
regex = Regex("(?i)([a-z]+)[0-9]+")
result = regex.find("cAt123#doG345")
assertNotNull(result)
assertEquals("cAt", result!!.groupValues[1])
result = result.next()
assertNotNull(result)
assertEquals("doG", result!!.groupValues[1])
assertNull(result.next())
}
@Test fun testMultiline() {
var regex: Regex
var result: MatchResult?
regex = Regex("^foo")
result = regex.find("foobar")
assertNotNull(result)
assertTrue(result!!.range.start == 0 && result.range.endInclusive == 2)
assertTrue(result.groups[0]!!.range.start == 0 && result.groups[0]!!.range.endInclusive == 2)
assertNull(result.next())
result = regex.find("barfoo")
assertNull(result)
regex = Regex("foo$")
result = regex.find("foobar")
assertNull(result)
result = regex.find("barfoo")
assertNotNull(result)
assertTrue(result!!.range.start == 3 && result.range.endInclusive == 5)
assertTrue(result.groups[0]!!.range.start == 3 && result.groups[0]!!.range.endInclusive == 5)
assertNull(result.next())
regex = Regex("^foo([0-9]*)", RegexOption.MULTILINE)
result = regex.find("foo1bar\nfoo2foo3\nbarfoo4")
assertNotNull(result)
assertEquals("1", result!!.groupValues[1])
result = result.next()
assertNotNull(result)
assertEquals("2", result!!.groupValues[1])
assertNull(result.next())
regex = Regex("foo([0-9]*)$", RegexOption.MULTILINE)
result = regex.find("foo1bar\nfoo2foo3\nbarfoo4")
assertNotNull(result)
assertEquals("3", result!!.groupValues[1])
result = result.next()
assertNotNull(result)
assertEquals("4", result!!.groupValues[1])
assertNull(result.next())
regex = Regex("(?m)^foo([0-9]*)")
result = regex.find("foo1bar\nfoo2foo3\nbarfoo4")
assertNotNull(result)
assertEquals("1", result!!.groupValues[1])
result = result.next()
assertNotNull(result)
assertEquals("2", result!!.groupValues[1])
assertNull(result.next())
regex = Regex("(?m)foo([0-9]*)$")
result = regex.find("foo1bar\nfoo2foo3\nbarfoo4")
assertNotNull(result)
assertEquals("3", result!!.groupValues[1])
result = result.next()
assertNotNull(result)
assertEquals("4", result!!.groupValues[1])
assertNull(result.next())
}
}
@@ -0,0 +1,44 @@
/* 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.
*/
package test.text.harmony_regex
import kotlin.text.*
import kotlin.test.*
class PatternErrorTest {
@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)
}
}
@@ -0,0 +1,44 @@
/* 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.
*/
package test.text.harmony_regex
import kotlin.text.*
import kotlin.test.*
class PatternSyntaxExceptionTest {
@Test fun testCase() {
val regex = "("
try {
Regex(regex)
fail("IllegalArgumentException expected")
} catch (e: IllegalArgumentException) {
// TODO: Check the exception's properties.
}
}
@Test fun testCase2() {
val regex = "[4-"
try {
Regex(regex)
fail("IllegalArgumentException expected")
} catch (e: IllegalArgumentException) {
}
}
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,84 @@
/* 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.
*/
package test.text.harmony_regex
import kotlin.text.*
import kotlin.test.*
class ReplaceTest {
@Test fun testSimpleReplace() {
val target: String
val pattern: String
val repl: String
target = "foobarfobarfoofo1"
pattern = "fo[^o]"
repl = "xxx"
val regex = Regex(pattern)
assertEquals("foobarxxxarfoofo1", regex.replaceFirst(target, repl))
assertEquals("foobarxxxarfooxxx", regex.replace(target, repl))
}
@Test 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)
assertEquals("foo[31];bar[42];[99]xyz", s)
s = regex.replace(target, repl)
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)
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)
assertEquals("[63]zoo(42)bar{31}foo;[56]ghi(34)def{12}abc;{99}xyz[88]xyz(77)xyz;", s)
}
@Test 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)
assertEquals("foo'bar''foo", s)
repl = "\\\\'"
s = target.replace(pattern.toRegex(), repl)
assertEquals("foo\\'bar\\'\\'foo", s)
repl = "\\$3"
s = target.replace(pattern.toRegex(), repl)
assertEquals("foo$3bar$3$3foo", s)
}
}
@@ -0,0 +1,156 @@
/*
* 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.
*/
package test.text.harmony_regex
import kotlin.text.*
import kotlin.test.*
class SplitTest {
@Test fun testSimple() {
val p = Regex("/")
val results = p.split("have/you/done/it/right")
val expected = arrayOf("have", "you", "done", "it", "right")
assertEquals(expected.size, results.size)
for (i in expected.indices) {
assertEquals(results[i], expected[i])
}
}
@Test fun testSplit1() {
var p = Regex(" ")
val input = "poodle zoo"
var tokens: List<String>
tokens = p.split(input, 1)
assertEquals(1, tokens.size)
assertTrue(tokens[0] == input)
tokens = p.split(input, 2)
assertEquals(2, tokens.size)
assertEquals("poodle", tokens[0])
assertEquals("zoo", tokens[1])
tokens = p.split(input, 5)
assertEquals(2, tokens.size)
assertEquals("poodle", tokens[0])
assertEquals("zoo", tokens[1])
tokens = p.split(input, 0)
assertEquals(2, tokens.size)
assertEquals("poodle", tokens[0])
assertEquals("zoo", tokens[1])
tokens = p.split(input)
assertEquals(2, tokens.size)
assertEquals("poodle", tokens[0])
assertEquals("zoo", tokens[1])
p = Regex("d")
tokens = p.split(input, 1)
assertEquals(1, tokens.size)
assertTrue(tokens[0] == input)
tokens = p.split(input, 2)
assertEquals(2, tokens.size)
assertEquals("poo", tokens[0])
assertEquals("le zoo", tokens[1])
tokens = p.split(input, 5)
assertEquals(2, tokens.size)
assertEquals("poo", tokens[0])
assertEquals("le zoo", tokens[1])
tokens = p.split(input, 0)
assertEquals(2, tokens.size)
assertEquals("poo", tokens[0])
assertEquals("le zoo", tokens[1])
tokens = p.split(input)
assertEquals(2, tokens.size)
assertEquals("poo", tokens[0])
assertEquals("le zoo", tokens[1])
p = Regex("o")
tokens = p.split(input, 1)
assertEquals(1, tokens.size)
assertTrue(tokens[0] == input)
tokens = p.split(input, 2)
assertEquals(2, tokens.size)
assertEquals("p", tokens[0])
assertEquals("odle zoo", tokens[1])
tokens = p.split(input, 5)
assertEquals(5, tokens.size)
assertEquals("p", tokens[0])
assertTrue(tokens[1] == "")
assertEquals("dle z", tokens[2])
assertTrue(tokens[3] == "")
assertTrue(tokens[4] == "")
tokens = p.split(input, 0)
assertEquals(5, tokens.size)
assertEquals("p", tokens[0])
assertTrue(tokens[1] == "")
assertEquals("dle z", tokens[2])
assertTrue(tokens[3] == "")
assertTrue(tokens[4] == "")
tokens = p.split(input)
assertEquals(5, tokens.size)
assertEquals("p", tokens[0])
assertTrue(tokens[1] == "")
assertEquals("dle z", tokens[2])
assertTrue(tokens[3] == "")
assertTrue(tokens[4] == "")
}
@Test fun testSplit2() {
val p = Regex("")
var s: List<String>
s = p.split("a", 0)
assertEquals(3, s.size)
assertEquals("", s[0])
assertEquals("a", s[1])
assertEquals("", s[2])
s = p.split("", 0)
assertEquals(2, s.size)
assertEquals("", s[0])
assertEquals("", s[1])
s = p.split("abcd", 0)
assertEquals(6, s.size)
assertEquals("", s[0])
assertEquals("a", s[1])
assertEquals("b", s[2])
assertEquals("c", s[3])
assertEquals("d", s[4])
assertEquals("", s[5])
}
@Test 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<String>
s = p.split("a\ud869\uded6b", 0)
assertEquals(5, s.size)
assertEquals("", s[0])
assertEquals("a", s[1])
assertEquals("\ud869\uded6", s[2])
assertEquals("b", s[3])
assertEquals("", s[4])
}
}