Custom Dump

repository·main·Indexed 21 days ago

https://github.com/pointfreeco/swift-custom-dump

A collection of Swift tools for improved debugging, diffing, and testing of data structures. It provides `customDump` as a readable alternative to the standard `dump` function, a `diff` utility for textual comparison of values, and testing assertions like `expectNoDifference` and `expectDifference` for XCTest and Swift Testing. The library includes protocols such as `CustomDumpStringConvertible`, `CustomDumpReflectable`, and `CustomDumpRepresentable` to customize how types are represented in the output.

Tokens
2.5K
Snippets
13
Records
16
Agent score
75%

What's inside swift-custom-dump

  1. Customize output with CustomDumpStringConvertible

    main

    The library provides conformance for many Apple ecosystem types to CustomDumpStringConvertible to ensure they dump to readable strings instead of unhelpful Objective-C internal representations (e.g., __C.UNNotificationSetting).

    You can implement this protocol yourself to provide a custom string representation for your own types when using customDump.

  2. Diff two values using `diff`

    main

    The diff function allows you to textually compare two values by generating a color-coded diff (using + and - notation) based on their customDump output. It is optimized to minimize the diff size, showing only the parts of the structure that have changed, even in large collections.

    var other = user
    other.favoriteNumbers[1] = 91
    
    print(diff(user, other)!) // Returns an optional string
  3. Use `customDump` for readable data structure output

    main

    The customDump function provides a more refined and readable output of nested structures compared to Swift's standard dump. It optimizes for readability by:

    • Mimicking Swift struct syntax for structs.
    • Including indices for array elements (e.g., [0]: value).
    • Using a compact, ordered format for dictionaries.
    • Providing a simplified tree structure for enums and deeply nested types.
    import CustomDump
    
    struct User {
      var favoriteNumbers: [Int]
      var id: Int
      var name: String
    }
    
    let user = User(
      favoriteNumbers: [42, 1729],
      id: 2,
      name: "Blob"
    )
    
    customDump(user)
  4. Assert equality with visual diffs using `expectNoDifference`

    main

    In testing environments (XCTest or Swift Testing), expectNoDifference provides a superior alternative to XCTAssertEqual or #expect. When an assertion fails, instead of a hard-to-read equality message, it produces a formatted diff showing exactly which field or value changed.

    var other = user
    other.name += "!"
    
    // Instead of XCTAssertEqual(user, other)
    expectNoDifference(user, other)
  5. Diff two values with diff(_:_:format:)

    main

    The diff(_:_:format:) function allows you to perform a textual diff between two values. It produces a formatted string showing additions (+) and removals (-), similar to standard diff tools. It is optimized to minimize the diff size by omitting unchanged parts of large collections (using ... (n unchanged) notation).

    var other = user
    other.favoriteNumbers[1] = 91
    
    print(diff(user, other)!)
  6. Assert equality with expectNoDifference

    main

    When testing, XCTAssertEqual often produces hard-to-read failure messages for complex types. Use expectNoDifference(_:_:_:file:line:) to assert that two values are equal. If they are not, it provides a beautifully formatted diff in the test failure message, making it easy to see exactly which field changed.

    var other = user
    other.name += "!"
    
    expectNoDifference(user, other)
  7. Assert specific changes using `expectDifference`

    main

    The expectDifference function asserts that a specific operation causes a predictable set of changes to a value.

    Exhaustive Assertion: Pass an operation in a closure and describe all expected changes in a changes closure. The assertion fails if the changes are not exhaustive.

    Non-exhaustive Assertion: Omit the operation closure to simply assert that a value matches a specific state for certain fields, ignoring others.

    struct Counter {
      var count = 0
      var isOdd = false
      mutating func increment() {
        self.count += 1
        self.isOdd.toggle()
      }
    }
    
    var counter = Counter()
    
    // Exhaustive: checks that count and isOdd changed as specified
    expectDifference(counter) { 
      counter.increment() 
    } changes: {
      $0.count = 1
      $0.isOdd = true
    }
    
    // Non-exhaustive: only asserts that count is 1
    counter.increment()
    expectDifference(counter) { 
      $0.count = 1
    }
  8. Use expectDifference for asynchronous testing

    main

    The expectDifference function allows you to assert that an asynchronous operation results in a difference between the current state and a previous state (or between two states). This is useful for testing side effects or state changes that occur within an async context.

    // Example usage of the async version of expectDifference
    // Note: The exact signature depends on the operation provided
    await expectDifference(value, operation: { await performAsyncAction() })
  9. Use customDump for refined data dumping

    main

    The customDump(_:name:indent:maxDepth:) function provides a more readable and structured output than Swift's built-in dump. It optimizes for readability by:

    • Mimicking Swift struct syntax for structs.
    • Including indices for array elements (e.g., [0]: value).
    • Using a compact, ordered format for dictionaries.
    • Providing a simplified tree structure for enums and deeply nested types.
    import CustomDump
    
    struct User {
      var favoriteNumbers: [Int]
      var id: Int
      var name: String
    }
    
    let user = User(
      favoriteNumbers: [42, 1729],
      id: 2,
      name: "Blob"
    )
    
    customDump(user)