<commit_before>import Foundation
import Quick
import Nimble
import RxSwift
import RxTest

/// `Foundation`

extension Optional {
    func asString() -> String {
        guard let s = self else { return "nil" }
        return String(describing: s)
    }
}

/// `RxSwift`

extension Event {
    var isError: Bool {
        switch self {
        case .error: return true
        default: return false
        }
    }
}

/// Nimble

extension PredicateResult {
    static var evaluationFailed: PredicateResult {
        return PredicateResult(status: .doesNotMatch,
                               message: .fail("failed to evaluate given expression"))
    }
    
    static func isEqual<T: Equatable>(actual: T?, expected: T?) -> PredicateResult {
        return PredicateResult(bool: actual == expected,
                               message: .expectedCustomValueTo("get <\(expected.asString())>", "<\(actual.asString())>"))
    }
}

public func match<T: Equatable>(_ expected: T) -> Predicate<T> {
    return Predicate { events in
        
        guard let source = try events.evaluate() else {
            return PredicateResult.evaluationFailed
        }
        guard source == expected else {
            return PredicateResult(status: .doesNotMatch, message: .expectedCustomValueTo("get <\(expected)> events", "<\(source)> events"))
        }
        
        
        return PredicateResult(bool: true, message: .fail("matched values and timeline as expected"))
    }
}

public func match<T>(_ expected: [Recorded<Event<T>>]) -> Predicate<[Recorded<Event<T>>]> where T: Equatable {
    return Predicate { events in
        
        guard let source = try events.evaluate() else {
            return PredicateResult.evaluationFailed
        }
        guard source.count == expected.count else {
            return PredicateResult(bool: false, message: .expectedCustomValueTo("get <\(expected.count)> events", "<\(source.count)> events"))
        }
        
        for (lhs, rhs) in zip(source, expected) {
            guard lhs.time == rhs.time,
                lhs.value == rhs.value else {
                    return PredicateResult(bool: rhs == lhs, message: .expectedCustomValueTo("match <\(rhs)>", "<\(lhs)>"))
            }
            continue
        }
        
        return PredicateResult(bool: true, message: .fail("match timeline"))
    }
}
<commit_msg>Specs-Cleanup: Added `public func match<T, E: Error>(with expectedErrors: [Recorded<Event<E>>]) -> Predicate<[Recorded<Event<T>>]>` for Error specific matching<commit_after>import Foundation
import Quick
import Nimble
import RxSwift
import RxTest

/// `Foundation`

extension Optional {
    func asString() -> String {
        guard let s = self else { return "nil" }
        return String(describing: s)
    }
}

/// `RxSwift`

extension Event {
    var isError: Bool {
        switch self {
        case .error: return true
        default: return false
        }
    }
}

/// Nimble

extension PredicateResult {
    static var evaluationFailed: PredicateResult {
        return PredicateResult(status: .doesNotMatch,
                               message: .fail("failed to evaluate given expression"))
    }
    
    static func isEqual<T: Equatable>(actual: T?, expected: T?) -> PredicateResult {
        return PredicateResult(bool: actual == expected,
                               message: .expectedCustomValueTo("get <\(expected.asString())>", "<\(actual.asString())>"))
    }
}

public func match<T: Equatable>(_ expected: T) -> Predicate<T> {
    return Predicate { events in
        
        guard let source = try events.evaluate() else {
            return PredicateResult.evaluationFailed
        }
        guard source == expected else {
            return PredicateResult(status: .doesNotMatch, message: .expectedCustomValueTo("get <\(expected)> events", "<\(source)> events"))
        }
        
        
        return PredicateResult(bool: true, message: .fail("matched values and timeline as expected"))
    }
}

public func match<T>(_ expected: [Recorded<Event<T>>]) -> Predicate<[Recorded<Event<T>>]> where T: Equatable {
    return Predicate { events in
        
        guard let source = try events.evaluate() else {
            return PredicateResult.evaluationFailed
        }
        guard source.count == expected.count else {
            return PredicateResult(bool: false, message: .expectedCustomValueTo("get <\(expected.count)> events", "<\(source.count)> events"))
        }
        
        for (lhs, rhs) in zip(source, expected) {
            guard lhs.time == rhs.time,
                lhs.value == rhs.value else {
                    return PredicateResult(bool: rhs == lhs, message: .expectedCustomValueTo("match <\(rhs)>", "<\(lhs)>"))
            }
            continue
        }
        
        return PredicateResult(bool: true, message: .fail("match timeline"))
    }
}

public func match<T, E: Error>(with expectedErrors: [Recorded<Event<E>>]) -> Predicate<[Recorded<Event<T>>]> where E: Equatable {
    return Predicate { events in
        guard let source = try events.evaluate() else {
            return PredicateResult.evaluationFailed
        }
        let errorEvents = source.filter { $0.value.isError }
        for (lhs, rhs) in zip(errorEvents, expectedErrors) {
            guard lhs.time == rhs.time,
                lhs.value.error.asString() == rhs.value.error.asString() else {
                return PredicateResult(bool: false, message: .fail("did not error"))
            }
            continue
        }
        
        return PredicateResult(bool: true, message: .fail("matched values and timeline as expected"))
    }
}

{'fraction_non_alphanumeric': 0.11932921447484554, 'fraction_numerical': 0.000176522506619594, 'mean_word_length': 2.2999417588817703, 'pattern_counts': {'":': 0, '<': 49, '<?xml version=': 0, '>': 59, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1854533', 'n_tokens_mistral': 1562, 'n_tokens_neox': 1518, 'n_words': 422}