Skip to content

Commit

Permalink
Use Custom Dump (#736)
Browse files Browse the repository at this point in the history
* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* fix

* wip

* wip

* Model Tic-Tac-Toe board using proper type

* wip

* wip

* wip

* wip

Co-authored-by: Brandon Williams <[email protected]>
  • Loading branch information
stephencelis and mbrandonw authored Aug 23, 2021
1 parent b73f74f commit 575d7c0
Show file tree
Hide file tree
Showing 19 changed files with 192 additions and 1,268 deletions.
1 change: 1 addition & 0 deletions Examples/CaseStudies/SwiftUICaseStudies/00-Core.swift
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,7 @@ let rootReducer = Reducer<RootState, RootAction, RootEnvironment>.combine(
environment: { .init(mainQueue: $0.mainQueue, webSocket: $0.webSocket) }
)
)
.debug()
.signpost()

private func liveFetchNumber() -> Effect<Int, Never> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,6 @@ let alertAndSheetReducer = Reducer<
return .none
}
}
.debug()

struct AlertAndSheetView: View {
let store: Store<AlertAndSheetState, AlertAndSheetAction>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,4 @@ public let appReducer = Reducer<AppState, AppAction, AppEnvironment>.combine(
}
}
)
.debug()
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ extension Three where Element == Three<Player?> {
)

public var isFilled: Bool {
self.allSatisfy { row in row.allSatisfy { $0 != nil } }
self.allSatisfy { $0.allSatisfy { $0 != nil } }
}

func hasWin(_ player: Player) -> Bool {
Expand Down
3 changes: 1 addition & 2 deletions Examples/Todos/Todos/Todos.swift
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,7 @@ let appReducer = Reducer<AppState, AppAction, AppEnvironment>.combine(
}
}
)

.debugActions(actionFormat: .labelsOnly)
.debug()

struct AppView: View {
let store: Store<AppState, AppAction>
Expand Down
4 changes: 3 additions & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,17 @@ let package = Package(
.package(name: "Benchmark", url: "https://github.com/google/swift-benchmark", from: "0.1.0"),
.package(url: "https://github.com/pointfreeco/combine-schedulers", from: "0.5.0"),
.package(url: "https://github.com/pointfreeco/swift-case-paths", from: "0.4.0"),
.package(url: "https://github.com/pointfreeco/swift-custom-dump", from: "0.1.0"),
.package(url: "https://github.com/pointfreeco/swift-identified-collections", from: "0.1.0"),
.package(url: "https://github.com/pointfreeco/xctest-dynamic-overlay", from: "0.1.0"),
.package(url: "https://github.com/pointfreeco/xctest-dynamic-overlay", from: "0.2.0"),
],
targets: [
.target(
name: "ComposableArchitecture",
dependencies: [
.product(name: "CasePaths", package: "swift-case-paths"),
.product(name: "CombineSchedulers", package: "combine-schedulers"),
.product(name: "CustomDump", package: "swift-custom-dump"),
.product(name: "IdentifiedCollections", package: "swift-identified-collections"),
.product(name: "XCTestDynamicOverlay", package: "xctest-dynamic-overlay"),
]
Expand Down
12 changes: 7 additions & 5 deletions Sources/ComposableArchitecture/Debugging/ReducerDebugging.swift
Original file line number Diff line number Diff line change
Expand Up @@ -115,14 +115,16 @@ extension Reducer {
return .merge(
.fireAndForget {
debugEnvironment.queue.async {
let actionOutput =
actionFormat == .prettyPrint
? debugOutput(localAction).indent(by: 2)
: debugCaseOutput(localAction).indent(by: 2)
var actionOutput = ""
if actionFormat == .prettyPrint {
customDump(localAction, to: &actionOutput, indent: 2)
} else {
actionOutput.write(debugCaseOutput(localAction).indent(by: 2))
}
let stateOutput =
LocalState.self == Void.self
? ""
: debugDiff(previousState, nextState).map { "\($0)\n" } ?? " (No state changes)\n"
: diff(previousState, nextState).map { "\($0)\n" } ?? " (No state changes)\n"
debugEnvironment.printer(
"""
\(prefix.isEmpty ? "" : "\(prefix): ")received action:
Expand Down
194 changes: 1 addition & 193 deletions Sources/ComposableArchitecture/Internal/Debug.swift
Original file line number Diff line number Diff line change
@@ -1,201 +1,9 @@
import CustomDump
import Foundation

func debugOutput(_ value: Any, indent: Int = 0) -> String {
var visitedItems: Set<ObjectIdentifier> = []

func debugOutputHelp(_ value: Any, indent: Int = 0) -> String {
let mirror = Mirror(reflecting: value)
switch (value, mirror.displayStyle) {
case let (value as CustomDebugOutputConvertible, _):
return value.debugOutput.indent(by: indent)
case (_, .collection?):
return """
[
\(mirror.children.map { "\(debugOutput($0.value, indent: 2)),\n" }.joined())]
"""
.indent(by: indent)

case (_, .dictionary?):
let pairs = mirror.children.map { label, value -> String in
let pair = value as! (key: AnyHashable, value: Any)
return
"\("\(debugOutputHelp(pair.key.base)): \(debugOutputHelp(pair.value)),".indent(by: 2))\n"
}
return """
[
\(pairs.sorted().joined())]
"""
.indent(by: indent)

case (_, .set?):
return """
Set([
\(mirror.children.map { "\(debugOutputHelp($0.value, indent: 2)),\n" }.sorted().joined())])
"""
.indent(by: indent)

case (_, .optional?):
return mirror.children.isEmpty
? "nil".indent(by: indent)
: debugOutputHelp(mirror.children.first!.value, indent: indent)

case (_, .enum?) where !mirror.children.isEmpty:
let child = mirror.children.first!
let childMirror = Mirror(reflecting: child.value)
let elements =
childMirror.displayStyle != .tuple
? debugOutputHelp(child.value, indent: 2)
: childMirror.children.map { child -> String in
let label = child.label!
return "\(label.hasPrefix(".") ? "" : "\(label): ")\(debugOutputHelp(child.value))"
}
.joined(separator: ",\n")
.indent(by: 2)
return """
\(mirror.subjectType).\(child.label!)(
\(elements)
)
"""
.indent(by: indent)

case (_, .enum?):
return """
\(mirror.subjectType).\(value)
"""
.indent(by: indent)

case (_, .struct?) where !mirror.children.isEmpty:
let elements = mirror.children
.map { "\($0.label.map { "\($0): " } ?? "")\(debugOutputHelp($0.value))".indent(by: 2) }
.joined(separator: ",\n")
return """
\(mirror.subjectType)(
\(elements)
)
"""
.indent(by: indent)

case let (value as AnyObject, .class?)
where !mirror.children.isEmpty && !visitedItems.contains(ObjectIdentifier(value)):
visitedItems.insert(ObjectIdentifier(value))
let elements = mirror.children
.map { "\($0.label.map { "\($0): " } ?? "")\(debugOutputHelp($0.value))".indent(by: 2) }
.joined(separator: ",\n")
return """
\(mirror.subjectType)(
\(elements)
)
"""
.indent(by: indent)

case let (value as AnyObject, .class?)
where !mirror.children.isEmpty && visitedItems.contains(ObjectIdentifier(value)):
return "\(mirror.subjectType)(↩︎)"

case let (value as CustomStringConvertible, .class?):
return value.description
.replacingOccurrences(
of: #"^<([^:]+): 0x[^>]+>$"#, with: "$1()", options: .regularExpression
)
.indent(by: indent)

case let (value as CustomDebugStringConvertible, _):
return value.debugDescription
.replacingOccurrences(
of: #"^<([^:]+): 0x[^>]+>$"#, with: "$1()", options: .regularExpression
)
.indent(by: indent)

case let (value as CustomStringConvertible, _):
return value.description
.indent(by: indent)

case (_, .struct?), (_, .class?):
return "\(mirror.subjectType)()"
.indent(by: indent)

case (_, .tuple?) where mirror.children.isEmpty:
return "()"
.indent(by: indent)

case (_, .tuple?):
let elements = mirror.children.map { child -> String in
let label = child.label!
return "\(label.hasPrefix(".") ? "" : "\(label): ")\(debugOutputHelp(child.value))"
.indent(by: 2)
}
return """
(
\(elements.joined(separator: ",\n"))
)
"""
.indent(by: indent)

case (_, nil):
return "\(value)"
.indent(by: indent)

@unknown default:
return "\(value)"
.indent(by: indent)
}
}

return debugOutputHelp(value, indent: indent)
}

func debugDiff<T>(_ before: T, _ after: T, printer: (T) -> String = { debugOutput($0) }) -> String?
{
diff(printer(before), printer(after))
}

extension String {
func indent(by indent: Int) -> String {
let indentation = String(repeating: " ", count: indent)
return indentation + self.replacingOccurrences(of: "\n", with: "\n\(indentation)")
}
}

public protocol CustomDebugOutputConvertible {
var debugOutput: String { get }
}

extension Date: CustomDebugOutputConvertible {
public var debugOutput: String {
dateFormatter.string(from: self)
}
}

private let dateFormatter: ISO8601DateFormatter = {
let formatter = ISO8601DateFormatter()
formatter.timeZone = TimeZone(identifier: "UTC")!
return formatter
}()

extension URL: CustomDebugOutputConvertible {
public var debugOutput: String {
self.absoluteString
}
}

#if DEBUG
#if canImport(Speech)
import Speech
extension SFSpeechRecognizerAuthorizationStatus: CustomDebugOutputConvertible {
public var debugOutput: String {
switch self {
case .notDetermined:
return "notDetermined"
case .denied:
return "denied"
case .restricted:
return "restricted"
case .authorized:
return "authorized"
@unknown default:
return "unknown"
}
}
}
#endif
#endif
82 changes: 0 additions & 82 deletions Sources/ComposableArchitecture/Internal/Diff.swift

This file was deleted.

2 changes: 2 additions & 0 deletions Sources/ComposableArchitecture/Internal/Exports.swift
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
@_exported import CasePaths
@_exported import CombineSchedulers
@_exported import CustomDump
@_exported import IdentifiedCollections
@_exported import XCTestDynamicOverlay

This comment has been minimized.

Copy link
@lukeredpath

lukeredpath Aug 25, 2021

Contributor

It looks like this change has caused a regression: pointfreeco/swift-issue-reporting#12

Exporting this means you now get errors if you import TCA and XCTest in the same file, which is probably common in a lot of test files. I think if somebody wants to use XCTestDynamicOverlay they should have to import it explicitly.

Loading

0 comments on commit 575d7c0

Please sign in to comment.