Skip to content

Commit

Permalink
239
Browse files Browse the repository at this point in the history
  • Loading branch information
stephencelis committed Jun 28, 2023
1 parent 4b55f51 commit 53b9397
Show file tree
Hide file tree
Showing 19 changed files with 1,299 additions and 0 deletions.
5 changes: 5 additions & 0 deletions 0239-reliably-testing-async-pt2/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
## [Point-Free](https://www.pointfree.co)

> #### This directory contains code from Point-Free Episode: [Reliable Async Tests: More Problems](https://www.pointfree.co/episodes/ep239-reliable-async-tests-more-problems)
>
> We explore a few more advanced scenarios when it comes to async code—including cancellation, async sequences, and clocks—and how difficult they are to test.

Large diffs are not rendered by default.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1500"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "CAC2DD7C2A30B827007675BD"
BuildableName = "ReliablyTestingAsync.app"
BlueprintName = "ReliablyTestingAsync"
ReferencedContainer = "container:ReliablyTestingAsync.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<TestPlans>
<TestPlanReference
reference = "container:ReliablyTestingAsyncTests/ReliablyTestingAsync.xctestplan"
default = "YES">
</TestPlanReference>
</TestPlans>
<Testables>
<TestableReference
skipped = "NO"
parallelizable = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "CAC2DD8C2A30B829007675BD"
BuildableName = "ReliablyTestingAsyncTests.xctest"
BlueprintName = "ReliablyTestingAsyncTests"
ReferencedContainer = "container:ReliablyTestingAsync.xcodeproj">
</BuildableReference>
</TestableReference>
<TestableReference
skipped = "NO"
parallelizable = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "CAC2DD962A30B829007675BD"
BuildableName = "ReliablyTestingAsyncUITests.xctest"
BlueprintName = "ReliablyTestingAsyncUITests"
ReferencedContainer = "container:ReliablyTestingAsync.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "CAC2DD7C2A30B827007675BD"
BuildableName = "ReliablyTestingAsync.app"
BlueprintName = "ReliablyTestingAsync"
ReferencedContainer = "container:ReliablyTestingAsync.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "CAC2DD7C2A30B827007675BD"
BuildableName = "ReliablyTestingAsync.app"
BlueprintName = "ReliablyTestingAsync"
ReferencedContainer = "container:ReliablyTestingAsync.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import SwiftUI

@main
struct ReliablyTestingAsyncApp: App {
var body: some Scene {
WindowGroup {
if NSClassFromString("XCTestCase") == nil {
ContentView(model: NumberFactModel())
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"colors" : [
{
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"images" : [
{
"idiom" : "universal",
"platform" : "ios",
"size" : "1024x1024"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import Darwin

typealias Original = @convention(thin) (UnownedJob) -> Void
typealias Hook = @convention(thin) (UnownedJob, Original) -> Void

var swift_task_enqueueGlobal_hook: Hook? {
get { _swift_task_enqueueGlobal_hook.pointee }
set { _swift_task_enqueueGlobal_hook.pointee = newValue }
}

private let _swift_task_enqueueGlobal_hook =
dlsym(dlopen(nil, RTLD_LAZY), "swift_task_enqueueGlobal_hook")
.assumingMemoryBound(to: Hook?.self)
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import Dependencies
import SwiftUI

struct NumberFactClient {
var fact: @Sendable (Int) async throws -> String
}

extension NumberFactClient: DependencyKey {
static let liveValue = Self { number in
try await Task.sleep(for: .seconds(1))
return try await String(
decoding: URLSession.shared.data(from: URL(string: "http://numbersapi.com/\(number)")!).0,
as: UTF8.self
)
}
}

extension DependencyValues {
var numberFact: NumberFactClient {
get { self[NumberFactClient.self] }
set { self[NumberFactClient.self] = newValue }
}
}

@MainActor
class NumberFactModel: ObservableObject {
@Dependency(\.numberFact) var numberFact

@Published var count = 0
@Published var fact: String?
@Published var factTask: Task<String, Error>?
var isLoading: Bool { self.factTask != nil }

func incrementButtonTapped() {
self.fact = nil
self.factTask?.cancel()
self.factTask = nil
self.count += 1
}
func decrementButtonTapped() {
self.fact = nil
self.factTask?.cancel()
self.factTask = nil
self.count -= 1
}
func getFactButtonTapped() async {
self.factTask?.cancel()

self.fact = nil
self.factTask = Task {
try await self.numberFact.fact(self.count)
}
defer { self.factTask = nil }
do {
self.fact = try await self.factTask?.value
} catch {
// TODO: handle error
}
}
func cancelButtonTapped() {
self.factTask?.cancel()
self.factTask = nil
}
func onTask() async {
for await _ in NotificationCenter.default.notifications(named: UIApplication.userDidTakeScreenshotNotification) {
self.count += 1
}
}
}

struct ContentView: View {
@ObservedObject var model: NumberFactModel

var body: some View {
Form {
Section {
HStack {
Button("-") { self.model.decrementButtonTapped() }
Text("\(self.model.count)")
Button("+") { self.model.incrementButtonTapped() }
}
}
.buttonStyle(.plain)

Section {
if self.model.isLoading {
HStack(spacing: 4) {
Button("Cancel") {
self.model.cancelButtonTapped()
}
Spacer()
ProgressView()
.id(UUID())
}
} else {
Button("Get fact") {
Task { await self.model.getFactButtonTapped() }
}
}
}

if let fact = self.model.fact {
Text(fact)
}
}
.task { await self.model.onTask() }
}
}

struct ContentPreviews: PreviewProvider {
static var previews: some View {
ContentView(model: NumberFactModel())
}
}
Loading

0 comments on commit 53b9397

Please sign in to comment.