Search code examples
androidregexkotlinjunitjvm

I got different result for same input on junit tests and on Android (ART) at runtime


I have a one static method which finds matching texts on target text, but it returns different results for same input, results in Junit tests and result in Android at runtime is different.

private const val REGEX = "GE[a-zA-Z0-9]{2}\\s?([a-zA-Z0-9]{2})([0-9]{2}\\s?)([0-9]{4}\\s?){3}([0-9]{2})\\s?"
private val PATTERN: Pattern = Pattern.compile(REGEX, Pattern.MULTILINE or Pattern.CASE_INSENSITIVE)

fun find(text: String): List<String> {
    val textFormatted = text.replace("\\s".toRegex(), "")
    val list = ArrayList<String>()
    val matcher = matcher(textFormatted)
    when {
        matcher.matches() -> {
            list.add(textFormatted)
        }
        matcher.find() -> {
            val partitions = findGroupMatches(matcher)
            list.addAll(partitions)
        }
    }
    return list
}

private fun findGroupMatches(matcher: Matcher): List<String> {
    val partitions = mutableListOf<String>()
    for (i in 0 until matcher.groupCount()) {
        val partition = matcher.group(i)
        if (partition != null && PATTERN.matcher(partition).matches()) {
            partitions.add(partition.replace("\\s".toRegex(), ""))
        }
    }
    return partitions
}

And the magic (imho) happens here

On JVM tests, it returns emptyList

@Test
fun `find with not valid text returns emptyList`(){
    val targets = PatternUtils.find("GE03TB 7433311450666666300008")
    assertTrue(targets.isEmpty()) // success
}

PatternUtils.find("GE03TB 7433311450666666300008") on Android inside `onCreate()` returns 1 size list("GE03TB743331145066666") //

Why it works like that? Is there any bug? or am I missing something?


Solution

  • Reason was that Pattern.java implementation by Oracle and by Google are different.

    In order to work similarly I had to create new Matcher instead of reusing it. (Matcher.java has some methods with side effect)

    fun find(text: String): List<String> {
        val textFormatted = text.replace("\\s".toRegex(), "")
        val list = ArrayList<String>()
        val matcher = createMatcher(textFormatted)
        when {
            createMatcher(textFormatted).matches() -> {
                list.add(textFormatted)
            }
            matcher.find() -> {
                val partitions = findGroupMatches(matcher)
                list.addAll(partitions)
            }
        }
        return list
    }