Coverage Summary for Class: EmailScanner (io.heapy.kotmark.autolink.internal)

Class Class, % Method, % Branch, % Line, % Instruction, %
EmailScanner 100% (1/1) 100% (6/6) 100% (40/40) 100% (34/34) 100% (175/175)


 // Port of autolink-java 0.12.0. Copyright (c) 2015 Robin Stocker. MIT; see UPSTREAM.md.
 package io.heapy.kotmark.autolink.internal
 
 import io.heapy.kotmark.autolink.LinkSpan
 import io.heapy.kotmark.autolink.LinkType
 
 internal class EmailScanner(private val domainMustHaveDot: Boolean) : Scanner {
     override fun scan(input: CharSequence, triggerIndex: Int, rewindIndex: Int): LinkSpan? {
         val first = findFirst(input, triggerIndex - 1, rewindIndex)
         if (first == -1) return null
         val last = findLast(input, triggerIndex + 1)
         return if (last == -1) null else LinkSpanImpl(LinkType.EMAIL, first, last + 1)
     }
 
     private fun findFirst(input: CharSequence, beginIndex: Int, rewindIndex: Int): Int {
         var first = -1
         var atomBoundary = true
         for (i in beginIndex downTo rewindIndex) {
             val c = input[i]
             when {
                 localAtomAllowed(c) -> { first = i; atomBoundary = false }
                 c == '.' -> { if (atomBoundary) break; atomBoundary = true }
                 else -> break
             }
         }
         return first
     }
 
     private fun findLast(input: CharSequence, beginIndex: Int): Int {
         var firstInSubDomain = true
         var canEndSubDomain = false
         var firstDot = -1
         var last = -1
         for (i in beginIndex..<input.length) {
             val c = input[i]
             if (firstInSubDomain) {
                 if (!subDomainAllowed(c)) break
                 last = i
                 firstInSubDomain = false
                 canEndSubDomain = true
             } else {
                 when {
                     c == '.' -> {
                         if (!canEndSubDomain) break
                         firstInSubDomain = true
                         if (firstDot == -1) firstDot = i
                     }
                     c == '-' -> canEndSubDomain = false
                     subDomainAllowed(c) -> { last = i; canEndSubDomain = true }
                     else -> break
                 }
             }
         }
         return if (domainMustHaveDot && (firstDot == -1 || firstDot > last)) -1 else last
     }
 
     private fun localAtomAllowed(c: Char): Boolean =
         subDomainAllowed(c) || c in "!#$%&'*+-/=?^_`{|}~"
 
     private fun subDomainAllowed(c: Char): Boolean = Scanners.isAlnum(c) || Scanners.isNonAscii(c)
 }