Skip to content

Commit

Permalink
Add code to make it easier to determine differences between actual an…
Browse files Browse the repository at this point in the history
…d expected test results
  • Loading branch information
kristopherjohnson committed Aug 24, 2014
1 parent f140e28 commit c1e8ecc
Show file tree
Hide file tree
Showing 4 changed files with 161 additions and 15 deletions.
4 changes: 4 additions & 0 deletions Markingbird.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
4EAF8DBF19A212F30020CA43 /* Markingbird.h in Headers */ = {isa = PBXBuildFile; fileRef = 4EAF8DBE19A212F30020CA43 /* Markingbird.h */; settings = {ATTRIBUTES = (Public, ); }; };
4EAF8DD319A213340020CA43 /* Markdown.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EAF8DD219A213340020CA43 /* Markdown.swift */; };
4EAF8DD519A213470020CA43 /* SimpleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EAF8DD419A213470020CA43 /* SimpleTests.swift */; };
4EC0AF3519A90DAC0068A458 /* differences.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EC0AF3419A90DAC0068A458 /* differences.swift */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
Expand All @@ -36,6 +37,7 @@
4EAF8DC719A212F30020CA43 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
4EAF8DD219A213340020CA43 /* Markdown.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Markdown.swift; sourceTree = "<group>"; };
4EAF8DD419A213470020CA43 /* SimpleTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SimpleTests.swift; sourceTree = "<group>"; };
4EC0AF3419A90DAC0068A458 /* differences.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = differences.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand Down Expand Up @@ -100,6 +102,7 @@
4EAF8DD419A213470020CA43 /* SimpleTests.swift */,
4EAF8DC619A212F30020CA43 /* Supporting Files */,
4E2A478C19A5EADD00B23DB6 /* testfiles */,
4EC0AF3419A90DAC0068A458 /* differences.swift */,
);
path = MarkingbirdTests;
sourceTree = "<group>";
Expand Down Expand Up @@ -230,6 +233,7 @@
files = (
4E2A478F19A5EB6F00B23DB6 /* MDTestTests.swift in Sources */,
4EAF8DD519A213470020CA43 /* SimpleTests.swift in Sources */,
4EC0AF3519A90DAC0068A458 /* differences.swift in Sources */,
4E3CBBA519A4A70400940D90 /* ConfigTest.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down
32 changes: 17 additions & 15 deletions Markingbird/Markdown.swift
Original file line number Diff line number Diff line change
Expand Up @@ -384,12 +384,13 @@ public struct Markdown {
var keepGoing = true // as long as replacements where made, keep going
while keepGoing && sanityCheck > 0 {
keepGoing = false
grafs[i] = Markdown._htmlBlockHash.replace(grafs[i]) { match in
if let value = self._htmlBlocks[match.value] {
let graf = grafs[i]
grafs[i] = Markdown._htmlBlockHash.replace(graf) { match in
if let replacementValue = self._htmlBlocks[match.value] {
keepGoing = true
return value
return replacementValue
}
return grafs[i]
return graf
}
sanityCheck--
}
Expand Down Expand Up @@ -1825,8 +1826,9 @@ private struct MarkdownRegex {
return
}
let match = MarkdownRegexMatch(textCheckingResult: result, string: s)
let range = result.range
let replacementText = evaluator(match)
let replacement = (result.range, replacementText)
let replacement = (range, replacementText)
replacements.append(replacement)
})

Expand Down Expand Up @@ -1928,24 +1930,24 @@ private struct MarkdownRegexMatch {
let textCheckingResult: NSTextCheckingResult
let string: NSString

private init(textCheckingResult: NSTextCheckingResult, string: NSString) {
init(textCheckingResult: NSTextCheckingResult, string: NSString) {
self.textCheckingResult = textCheckingResult
self.string = string
}

private var value: NSString {
var value: NSString {
return string.substringWithRange(textCheckingResult.range)
}

private var index: Int {
var index: Int {
return textCheckingResult.range.location
}

private var length: Int {
var length: Int {
return textCheckingResult.range.length
}

private func valueOfGroupAtIndex(idx: Int) -> NSString {
func valueOfGroupAtIndex(idx: Int) -> NSString {
if 0 <= idx && idx < textCheckingResult.numberOfRanges {
let groupRange = textCheckingResult.rangeAtIndex(idx)
if (groupRange.location == NSNotFound) {
Expand Down Expand Up @@ -1973,17 +1975,17 @@ private struct MarkdownRegexMatch {
/// - ExplicitCapture
private struct MarkdownRegexOptions {
/// Allow ^ and $ to match the start and end of lines.
private static let Multiline = NSRegularExpressionOptions.AnchorsMatchLines
static let Multiline = NSRegularExpressionOptions.AnchorsMatchLines

/// Ignore whitespace and #-prefixed comments in the pattern.
private static let IgnorePatternWhitespace = NSRegularExpressionOptions.AllowCommentsAndWhitespace
static let IgnorePatternWhitespace = NSRegularExpressionOptions.AllowCommentsAndWhitespace

/// Allow . to match any character, including line separators.
private static let Singleline = NSRegularExpressionOptions.DotMatchesLineSeparators
static let Singleline = NSRegularExpressionOptions.DotMatchesLineSeparators

/// Match letters in the pattern independent of case.
private static let IgnoreCase = NSRegularExpressionOptions.CaseInsensitive
static let IgnoreCase = NSRegularExpressionOptions.CaseInsensitive

/// Default options
private static let None = NSRegularExpressionOptions(0)
static let None = NSRegularExpressionOptions(0)
}
11 changes: 11 additions & 0 deletions MarkingbirdTests/MDTestTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,17 @@ class MDTestTests: XCTestCase {
/// and then compare the result with the corresponding .html file
func testTests() {
for test in getTests() {

// If there is a difference, print it in a more readable way than
// XCTest does
switch firstDifferenceBetweenStrings(test.actualResult, test.expectedResult) {
case .NoDifference:
break;
case .DifferenceAtIndex(let index):
let prettyDiff = prettyFirstDifferenceBetweenStrings(test.actualResult, test.expectedResult)
println("\n====\n\(test.actualName): \(prettyDiff)\n====\n")
}

XCTAssertEqual(test.actualResult, test.expectedResult,
"Mismatch between '\(test.actualName)' and the transformed '\(test.expectedName)'")
}
Expand Down
129 changes: 129 additions & 0 deletions MarkingbirdTests/differences.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
import Foundation


/// Find first differing character between two strings
///
/// :param: s1 First String
/// :param: s2 Second String
///
/// :returns: .DifferenceAtIndex(i) or .NoDifference
public func firstDifferenceBetweenStrings(s1: NSString, s2: NSString) -> FirstDifferenceResult {
let len1 = s1.length
let len2 = s2.length

let lenMin = min(len1, len2)

for i in 0..<lenMin {
if s1.characterAtIndex(i) != s2.characterAtIndex(i) {
return .DifferenceAtIndex(i)
}
}

if len1 < len2 {
return .DifferenceAtIndex(len1)
}

if len2 < len1 {
return .DifferenceAtIndex(len2)
}

return .NoDifference
}


/// Create a formatted String representation of difference between strings
///
/// :param: s1 First string
/// :param: s2 Second string
///
/// :returns: a string, possibly containing significant whitespace and newlines
public func prettyFirstDifferenceBetweenStrings(s1: NSString, s2: NSString) -> NSString {
let firstDifferenceResult = firstDifferenceBetweenStrings(s1, s2)
return prettyDescriptionOfFirstDifferenceResult(firstDifferenceResult, s1, s2)
}


/// Create a formatted String representation of a FirstDifferenceResult for two strings
///
/// :param: firstDifferenceResult FirstDifferenceResult
/// :param: s1 First string used in generation of firstDifferenceResult
/// :param: s2 Second string used in generation of firstDifferenceResult
///
/// :returns: a printable string, possibly containing significant whitespace and newlines
public func prettyDescriptionOfFirstDifferenceResult(firstDifferenceResult: FirstDifferenceResult, s1: NSString, s2: NSString) -> NSString {

func diffString(index: Int, s1: NSString, s2: NSString) -> NSString {
let markerArrow = "\u{2b06}" // "⬆"
let ellipsis = "\u{2026}" // "…"

/// Given a string and a range, return a string representing that substring.
///
/// If the range starts at a position other than 0, an ellipsis
/// will be included at the beginning.
///
/// If the range ends before the actual end of the string,
/// an ellipsis is added at the end.
func windowSubstring(s: NSString, range: NSRange) -> String {
let validRange = NSMakeRange(range.location, min(range.length, s.length - range.location))
let substring = s.substringWithRange(validRange)

let prefix = range.location > 0 ? ellipsis : ""
let suffix = (s.length - range.location > range.length) ? ellipsis : ""

return "\(prefix)\(substring)\(suffix)"
}

// Show this many characters before and after the first difference
let windowPrefixLength = 10
let windowSuffixLength = 10
let windowLength = windowPrefixLength + 1 + windowSuffixLength

let windowIndex = max(index - windowPrefixLength, 0)
let windowRange = NSMakeRange(windowIndex, windowLength)

let sub1 = windowSubstring(s1, windowRange)
let sub2 = windowSubstring(s2, windowRange)

let markerPosition = min(windowSuffixLength, index) + (windowIndex > 0 ? 1 : 0)

let markerPrefix = String(count: markerPosition, repeatedValue: " " as Character)
let markerLine = "\(markerPrefix)\(markerArrow)"

return "Difference at index \(index):\n\(sub1)\n\(sub2)\n\(markerLine)"
}

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)
}

extension FirstDifferenceResult: Printable, DebugPrintable {
/// Textual representation of a FirstDifferenceResult
public var description: String {
switch self {
case .NoDifference:
return "NoDifference"
case .DifferenceAtIndex(let index):
return "DifferenceAtIndex(\(index))"
}
}

/// Textual representation of a FirstDifferenceResult for debugging purposes
public var debugDescription: String {
return self.description
}
}

0 comments on commit c1e8ecc

Please sign in to comment.