         ///
         /// If the range ends before the actual end of the string,
         /// an ellipsis is added at the end.
-        func windowSubstring(_ s: NSString, _ range: NSRange, isPrefix: Bool = false, isSuffix: Bool = false) -> String {
-            let validRange = NSMakeRange(range.location, min(range.length, s.length - range.location))
-            let substring = s.substring(with: validRange)
+        func windowSubstring(
+          _ s: String,
+          _ range: (location: Int, length: Int),
+          isPrefix: Bool = false,
+          isSuffix: Bool = false
+        ) -> String {
+            let minLen = min(range.length, s.count - range.location)
+            let startIndex = s.index(s.startIndex, offsetBy: range.location)
+            let endIndex = s.index(startIndex, offsetBy: minLen)
+            let substring = String(s[startIndex..<endIndex])
 
             let prefix = isPrefix && range.location > 0 ? ellipsis : ""
-            let suffix = isSuffix && (s.length - range.location > range.length) ? ellipsis : ""
+            let suffix = isSuffix && (s.count - range.location > range.length) ? ellipsis : ""
 
             return "\(prefix)\(substring)\(suffix)"
         }

        let windowPrefixLength = min(120, index)
        let windowSuffixLength = 120

        let prefix1 = windowSubstring(s1, NSMakeRange(index - windowPrefixLength, windowPrefixLength), isPrefix: true)
        let suffix1 = windowSubstring(s1, NSMakeRange(index, windowSuffixLength), isSuffix: true)

        let prefix2 = windowSubstring(s2, NSMakeRange(index - windowPrefixLength, windowPrefixLength), isPrefix: true)
        let suffix2 = windowSubstring(s2, NSMakeRange(index, windowSuffixLength), isSuffix: true)

        return "Difference at index \(index):\n------ Result: \n\(prefix1)\(markerArrow)\(suffix1)\n------ Expected:\n\(prefix2)\(markerArrow)\(suffix2)\n------\n"
    }

    switch firstDifferenceResult {
    case .NoDifference:                 return "No difference"
    case .DifferenceAtIndex(let index): return diffString(index, s1, s2)
    }
}


/// Result type for firstDifferenceBetweenStrings()
public enum FirstDifferenceResult {
    /// Strings are identical
    case noDifference

    /// Strings differ at the specified index.
    ///
    /// This could mean that characters at the specified index are different,
    /// or that one string is longer than the other
    case differenceAtIndex(Int)
}
