Files
Ruslan Alikhamov cec7895f0a Adjusted file structure to accommodate two generated files (#1299)
* Adjusted file structure to accommodate two generated files

* Adjusted scripting

* Removed Description, Diffable, Equality for now

* Removed Stencil import

* Updated templates

* Updated scripting

* Updated generated coding

* Disable build deletion (temp)

* Updated template

* Updated generated code

* updated generated code

* Updated generated code

* Adjusted scripting

* Updated scripting

* Updated generated code

* Reverted template deletion

* Removed Stencil imports

* Updated generated code

* trigger CI

* Removed description, diffable and equality stencil templates

* Reverted temporary changes

* Commented failing tests

* Skipping JSExport for description & hash

* Updated generated code

* Enabled failing tests

* Adding stencil templates back to test tests

* Reset generated file for linux for test

* Reverted Extensions for testing

* Reverted ParserResultsComposed

* Attempt to fix unit tests

* Attempt to resolve unit test

* Reverted TypeName asSource

* Reverted TypeName revertion

* Reverted revert of ParserResultComposed

* Reverted revert of Extensions

* Reverted revert of Linux.content.generated

* Reverted attempts to fix unit tests

* Fix for the failing codegen tests

* Added clarifying comment

* Removed description, diffable and equality stencil templates

* Updated generated code

* Tinkering with optimization level for speed boost

* Excluded stencil templates for codegen

* Fixed wrong compiler flag

* Removed speed optimization to a separate PR

* Reverted test code
2024-03-13 00:01:29 +04:00

230 lines
7.3 KiB
Swift

//
// Diffable.swift
// Sourcery
//
// Created by Krzysztof Zabłocki on 22/12/2016.
// Copyright © 2016 Pixle. All rights reserved.
//
import Foundation
public protocol Diffable {
/// Returns `DiffableResult` for the given objects.
///
/// - Parameter object: Object to diff against.
/// - Returns: Diffable results.
func diffAgainst(_ object: Any?) -> DiffableResult
}
/// :nodoc:
extension NSRange: Diffable {
/// :nodoc:
public static func == (lhs: NSRange, rhs: NSRange) -> Bool {
return NSEqualRanges(lhs, rhs)
}
public func diffAgainst(_ object: Any?) -> DiffableResult {
let results = DiffableResult()
guard let rhs = object as? NSRange else {
results.append("Incorrect type <expected: FileParserResult, received: \(type(of: object))>")
return results
}
results.append(contentsOf: DiffableResult(identifier: "location").trackDifference(actual: self.location, expected: rhs.location))
results.append(contentsOf: DiffableResult(identifier: "length").trackDifference(actual: self.length, expected: rhs.length))
return results
}
}
#if canImport(ObjectiveC)
@objcMembers
#endif
public class DiffableResult: NSObject, AutoEquatable {
// sourcery: skipEquality
private var results: [String]
internal var identifier: String?
init(results: [String] = [], identifier: String? = nil) {
self.results = results
self.identifier = identifier
}
func append(_ element: String) {
results.append(element)
}
func append(contentsOf contents: DiffableResult) {
if !contents.isEmpty {
results.append(contents.description)
}
}
var isEmpty: Bool { return results.isEmpty }
/// :nodoc:
// sourcery: skipJSExport
public override var hash: Int {
var hasher = Hasher()
hasher.combine(self.identifier)
return hasher.finalize()
}
/// :nodoc:
public override func isEqual(_ object: Any?) -> Bool {
guard let rhs = object as? DiffableResult else { return false }
if self.identifier != rhs.identifier { return false }
return true
}
public override var description: String {
guard !results.isEmpty else { return "" }
var description = "\(identifier.flatMap { "\($0) " } ?? "")"
description.append(results.joined(separator: "\n"))
return description
}
}
public extension DiffableResult {
#if swift(>=4.1)
#else
/// :nodoc:
@discardableResult func trackDifference<T: Equatable>(actual: T, expected: T) -> DiffableResult {
if actual != expected {
let result = DiffableResult(results: ["<expected: \(expected), received: \(actual)>"])
append(contentsOf: result)
}
return self
}
#endif
/// :nodoc:
@discardableResult func trackDifference<T: Equatable>(actual: T?, expected: T?) -> DiffableResult {
if actual != expected {
let expected = expected.map({ "\($0)" }) ?? "nil"
let actual = actual.map({ "\($0)" }) ?? "nil"
let result = DiffableResult(results: ["<expected: \(expected), received: \(actual)>"])
append(contentsOf: result)
}
return self
}
/// :nodoc:
@discardableResult func trackDifference<T: Equatable>(actual: T, expected: T) -> DiffableResult where T: Diffable {
let diffResult = actual.diffAgainst(expected)
append(contentsOf: diffResult)
return self
}
/// :nodoc:
@discardableResult func trackDifference<T: Equatable>(actual: [T], expected: [T]) -> DiffableResult where T: Diffable {
let diffResult = DiffableResult()
defer { append(contentsOf: diffResult) }
guard actual.count == expected.count else {
diffResult.append("Different count, expected: \(expected.count), received: \(actual.count)")
return self
}
for (idx, item) in actual.enumerated() {
let diff = DiffableResult()
diff.trackDifference(actual: item, expected: expected[idx])
if !diff.isEmpty {
let string = "idx \(idx): \(diff)"
diffResult.append(string)
}
}
return self
}
/// :nodoc:
@discardableResult func trackDifference<T: Equatable>(actual: [T], expected: [T]) -> DiffableResult {
let diffResult = DiffableResult()
defer { append(contentsOf: diffResult) }
guard actual.count == expected.count else {
diffResult.append("Different count, expected: \(expected.count), received: \(actual.count)")
return self
}
for (idx, item) in actual.enumerated() where item != expected[idx] {
let string = "idx \(idx): <expected: \(expected), received: \(actual)>"
diffResult.append(string)
}
return self
}
/// :nodoc:
@discardableResult func trackDifference<K, T: Equatable>(actual: [K: T], expected: [K: T]) -> DiffableResult where T: Diffable {
let diffResult = DiffableResult()
defer { append(contentsOf: diffResult) }
guard actual.count == expected.count else {
append("Different count, expected: \(expected.count), received: \(actual.count)")
if expected.count > actual.count {
let missingKeys = Array(expected.keys.filter {
actual[$0] == nil
}.map {
String(describing: $0)
})
diffResult.append("Missing keys: \(missingKeys.joined(separator: ", "))")
}
return self
}
for (key, actualElement) in actual {
guard let expectedElement = expected[key] else {
diffResult.append("Missing key \"\(key)\"")
continue
}
let diff = DiffableResult()
diff.trackDifference(actual: actualElement, expected: expectedElement)
if !diff.isEmpty {
let string = "key \"\(key)\": \(diff)"
diffResult.append(string)
}
}
return self
}
// MARK: - NSObject diffing
/// :nodoc:
@discardableResult func trackDifference<K, T: NSObjectProtocol>(actual: [K: T], expected: [K: T]) -> DiffableResult {
let diffResult = DiffableResult()
defer { append(contentsOf: diffResult) }
guard actual.count == expected.count else {
append("Different count, expected: \(expected.count), received: \(actual.count)")
if expected.count > actual.count {
let missingKeys = Array(expected.keys.filter {
actual[$0] == nil
}.map {
String(describing: $0)
})
diffResult.append("Missing keys: \(missingKeys.joined(separator: ", "))")
}
return self
}
for (key, actualElement) in actual {
guard let expectedElement = expected[key] else {
diffResult.append("Missing key \"\(key)\"")
continue
}
if !actualElement.isEqual(expectedElement) {
diffResult.append("key \"\(key)\": <expected: \(expected), received: \(actual)>")
}
}
return self
}
}