Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
stephencelis committed Jul 4, 2023
1 parent 53b9397 commit 7e00028
Show file tree
Hide file tree
Showing 36 changed files with 2,722 additions and 0 deletions.
5 changes: 5 additions & 0 deletions 0240-reliably-testing-async-pt3/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: 😳](https://www.pointfree.co/episodes/ep240-reliable-async-tests)
>
> We dive into Apple’s Async Algorithms package to explore some advanced usages of Swift’s concurrency runtime, including a particular tool we can leverage to bend the will of async code to our advantage in tests.

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 7e00028

Please sign in to comment.