Skip to content

Commit 5d99ba6

Browse files
authored
Add Unit Test case for _logChanges (#88)
* Update TestingHost xcodeproj * Fix Update throw issue * Fix Update.ensure implementation * Fix setPreferenceBridge * Update UIHostingView deinit * [Bugfix] Fix GraphHost property issue * Workaround Issue 87 * Add Unit Test case for _logChanges
1 parent a166851 commit 5d99ba6

File tree

24 files changed

+336
-122
lines changed

24 files changed

+336
-122
lines changed

.github/workflows/compatibility_tests.yml

+43-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ on:
88

99
jobs:
1010
compatibility_tests_macos:
11-
name: Execute compatibility tests
11+
name: Execute compatibility tests for macOS
1212
strategy:
1313
fail-fast: false
1414
matrix:
@@ -41,3 +41,45 @@ jobs:
4141
--build-path .build-compatibility-test-debug
4242
env:
4343
OPENSWIFTUI_COMPATIBILITY_TEST: 1
44+
compatibility_tests_ios:
45+
name: Execute compatibility tests for iOS
46+
strategy:
47+
fail-fast: false
48+
matrix:
49+
include:
50+
- os: macos-14
51+
xcode-version: "15.3" # Swift 5.10
52+
runs-on: ${{ matrix.os }}
53+
env:
54+
OPENSWIFTUI_WERROR: 1
55+
OPENSWIFTUI_SWIFT_TESTING: 1
56+
OPENGRAPH_ATTRIBUTEGRAPH: 1
57+
OPENSWIFTUI_SWIFT_LOG: 0
58+
steps:
59+
- uses: actions/checkout@v4
60+
- name: Setup Xcode
61+
uses: maxim-lobanov/setup-xcode@v1
62+
with:
63+
xcode-version: ${{ matrix.xcode-version }}
64+
- name: Swift version
65+
run: swift --version
66+
- name: Run compatibility tests on OpenSwiftUI + iOS
67+
run: |
68+
xcodebuild test \
69+
-scheme OpenSwiftUI \
70+
-configuration Debug \
71+
-destination "platform=iOS-Simulator" \
72+
-skipMacroValidation \
73+
-skipPackagePluginValidation
74+
env:
75+
OPENSWIFTUI_COMPATIBILITY_TEST: 0
76+
- name: Run compatibility tests on SwiftUI + iOS
77+
run: |
78+
xcodebuild test \
79+
-scheme OpenSwiftUI \
80+
-configuration Debug \
81+
-destination "platform=iOS-Simulator" \
82+
-skipMacroValidation \
83+
-skipPackagePluginValidation
84+
env:
85+
OPENSWIFTUI_COMPATIBILITY_TEST: 1

.github/workflows/wasm.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ on:
77
branches: [main]
88

99
jobs:
10-
wasmer_test:
10+
wasm_test:
1111
name: Execute tests on WASM
1212
strategy:
1313
fail-fast: false
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
PRODUCT_BUNDLE_IDENTIFIER=org.OpenSwiftUIProject.OpenSwiftUI.TestHost
1+
PRODUCT_BUNDLE_IDENTIFIER=org.OpenSwiftUIProject.OpenSwiftUI.TestingHost

README.md

+4-3
Original file line numberDiff line numberDiff line change
@@ -51,11 +51,12 @@ for various platforms:
5151

5252
| **Platform** | **CI Status** | **Support Status** | Build | Test | Deploy |
5353
|-|:-|-|-|-|-|
54-
| **macOS** | [![macOS](https://github.com/OpenSwiftUIProject/OpenSwiftUI/actions/workflows/macos.yml/badge.svg)](https://github.com/OpenSwiftUIProject/OpenSwiftUI/actions/workflows/macos.yml) [![Compatibility tests](https://github.com/OpenSwiftUIProject/OpenSwiftUI/actions/workflows/compatibility_tests.yml/badge.svg)](https://github.com/OpenSwiftUIProject/OpenSwiftUI/actions/workflows/compatibility_tests.yml) | ⭐️⭐️⭐️ *[^1] ||||
54+
| **SwiftUI Compatibility** | [![Compatibility tests](https://github.com/OpenSwiftUIProject/OpenSwiftUI/actions/workflows/compatibility_tests.yml/badge.svg)](https://github.com/OpenSwiftUIProject/OpenSwiftUI/actions/workflows/compatibility_tests.yml) | | | | |
55+
| **macOS** | [![macOS](https://github.com/OpenSwiftUIProject/OpenSwiftUI/actions/workflows/macos.yml/badge.svg)](https://github.com/OpenSwiftUIProject/OpenSwiftUI/actions/workflows/macos.yml) | ⭐️⭐️⭐️ *[^1] ||||
5556
| **iOS** | [![iOS](https://github.com/OpenSwiftUIProject/OpenSwiftUI/actions/workflows/ios.yml/badge.svg)](https://github.com/OpenSwiftUIProject/OpenSwiftUI/actions/workflows/ios.yml) | ⭐️⭐️⭐️⭐️ *[^2] ||||
5657
| **Ubuntu 22.04** | [![Ubuntu](https://github.com/OpenSwiftUIProject/OpenSwiftUI/actions/workflows/ubuntu.yml/badge.svg)](https://github.com/OpenSwiftUIProject/OpenSwiftUI/actions/workflows/ubuntu.yml) | ⭐️⭐️ *[^3] ||||
57-
| **Wasm** | [![Ubuntu](https://github.com/OpenSwiftUIProject/OpenSwiftUI/actions/workflows/ubuntu.yml/badge.svg)](https://github.com/OpenSwiftUIProject/OpenSwiftUI/actions/workflows/ubuntu.yml) | ⭐️ *[^4] ||||
58-
| **Windows** | | Not supported yet ||||
58+
| **Wasm** | [![Ubuntu](https://github.com/OpenSwiftUIProject/OpenSwiftUI/actions/workflows/wasm.yml/badge.svg)](https://github.com/OpenSwiftUIProject/OpenSwiftUI/actions/workflows/wasm.yml) | ⭐️ *[^4] ||||
59+
| **Windows** | None | Not supported yet ||||
5960

6061

6162
[^1]: AppKit and other UI framework backend is not intergrated yet.

Sources/OpenSwiftUI/Core/Graph/GraphHost.swift

+9-9
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,15 @@ private var blockedGraphHosts: [Unmanaged<GraphHost>] = []
1515
class GraphHost {
1616
// MARK: - Properties
1717

18-
private(set) var data: Data
19-
private(set) var isInstantiated = false
20-
/* private(set)*/ var hostPreferenceValues: OptionalAttribute<PreferenceList>
21-
private(set) var lastHostPreferencesSeed: VersionSeed = .invalid
22-
private var pendingTransactions: [AsyncTransaction] = []
23-
/*private(set)*/ var inTransaction = false
24-
/*private(set)*/ var continuations: [() -> Void] = []
25-
private(set) var mayDeferUpdate = true
26-
private(set) var removedState: RemovedState = []
18+
private(set) final var data: Data
19+
private(set) final var isInstantiated = false
20+
/* private(set)*/ final var hostPreferenceValues: OptionalAttribute<PreferenceList>
21+
private(set) final var lastHostPreferencesSeed: VersionSeed = .invalid
22+
private final var pendingTransactions: [AsyncTransaction] = []
23+
/*private(set)*/ final var inTransaction = false
24+
/*private(set)*/ final var continuations: [() -> Void] = []
25+
private(set) final var mayDeferUpdate = true
26+
private(set) final var removedState: RemovedState = []
2727

2828
// MARK: - static properties and methods
2929

Sources/OpenSwiftUI/Core/Update/Update.swift

+8-10
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,10 @@ import Foundation
1111

1212
extension MovableLock {
1313
@inline(__always)
14-
func withLock<R>(_ body: () -> R) -> R {
14+
func withLock<R>(_ body: () throws -> R) rethrows -> R {
1515
lock()
1616
defer { unlock() }
17-
return body()
17+
return try body()
1818
}
1919
}
2020

@@ -57,17 +57,15 @@ enum Update {
5757
end()
5858
}
5959

60-
static func ensure<Value>(_ body: () -> Value) throws -> Value {
61-
lock.withLock {
60+
static func ensure<Value>(_ body: () throws -> Value) rethrows -> Value {
61+
try lock.withLock {
6262
if depth == 0 {
6363
begin()
64+
defer { end() }
65+
return try body()
66+
} else {
67+
return try body()
6468
}
65-
defer {
66-
if depth == 0 {
67-
end()
68-
}
69-
}
70-
return body()
7169
}
7270
}
7371

Sources/OpenSwiftUI/Core/View/ViewGraph.swift

+23-6
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,7 @@ final class ViewGraph: GraphHost {
4949
private weak var _preferenceBridge: PreferenceBridge?
5050
var preferenceBridge: PreferenceBridge? {
5151
get { _preferenceBridge }
52-
// FIXME: TO BE CONFIRMED
53-
set { setPreferenceBridge(to: newValue, isInvalidating: newValue == nil) }
52+
set { setPreferenceBridge(to: newValue, isInvalidating: false) }
5453
}
5554
#if canImport(Darwin) // FIXME: See #39
5655
var bridgedPreferences: [(AnyPreferenceKey.Type, OGAttribute)] = []
@@ -88,6 +87,10 @@ final class ViewGraph: GraphHost {
8887
#endif
8988
}
9089

90+
deinit {
91+
removePreferenceOutlets(isInvalidating: true)
92+
}
93+
9194
@inline(__always)
9295
func updateOutputs(at time: Time) {
9396
beginNextUpdate(at: time)
@@ -168,10 +171,6 @@ final class ViewGraph: GraphHost {
168171
setPreferenceBridge(to: nil, isInvalidating: true)
169172
}
170173

171-
private func setPreferenceBridge(to bridge: PreferenceBridge?, isInvalidating: Bool) {
172-
// TODO
173-
}
174-
175174
private func makePreferenceOutlets(outputs: _ViewOutputs) {
176175
// TODO
177176
}
@@ -269,6 +268,24 @@ final class ViewGraph: GraphHost {
269268
}
270269
}
271270

271+
extension ViewGraph {
272+
fileprivate func setPreferenceBridge(to bridge: PreferenceBridge?, isInvalidating: Bool) {
273+
// TODO
274+
}
275+
}
276+
277+
extension PreferenceBridge {
278+
func invalidate() {
279+
requestedPreferences = PreferenceKeys()
280+
bridgedViewInputs = PropertyList()
281+
for child in children {
282+
let viewGraph = child.takeRetainedValue()
283+
viewGraph.setPreferenceBridge(to: nil, isInvalidating: true)
284+
child.release()
285+
}
286+
}
287+
}
288+
272289
extension ViewGraph {
273290
struct NextUpdate {
274291
var time: Time

Sources/OpenSwiftUI/Core/View/ViewRendererHost.swift

+5
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,11 @@ extension ViewRendererHost {
9696
// TODO:
9797
}
9898
}
99+
100+
func invalidate() {
101+
viewGraph.delegate = nil
102+
// TODO: Signpost.viewHost
103+
}
99104
}
100105

101106
struct ViewRendererHostProperties: OptionSet {

Sources/OpenSwiftUI/Data/Preference/PreferenceBridge.swift

+1-11
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ internal import OpenGraphShims
1010

1111
final class PreferenceBridge {
1212
unowned let viewGraph: ViewGraph
13-
private var children: [Unmanaged<ViewGraph>] = []
13+
private(set) var children: [Unmanaged<ViewGraph>] = []
1414
var requestedPreferences = PreferenceKeys()
1515
var bridgedViewInputs = PropertyList()
1616
@WeakAttribute var hostPreferenceKeys: PreferenceKeys?
@@ -141,16 +141,6 @@ final class PreferenceBridge {
141141
}
142142
}
143143

144-
func invalidate() {
145-
requestedPreferences = PreferenceKeys()
146-
bridgedViewInputs = PropertyList()
147-
for child in children {
148-
let viewGraph = child.takeRetainedValue()
149-
viewGraph.preferenceBridge = nil
150-
child.release()
151-
}
152-
}
153-
154144
func wrapInputs(_ inputs: inout _ViewInputs) {
155145
inputs.withMutableCustomInputs { $0 = bridgedViewInputs }
156146
inputs.preferences.merge(requestedPreferences)

Sources/OpenSwiftUI/Integration/UIKit/UIHostingView.swift

+24-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import UIKit
1111

1212
@available(macOS, unavailable)
1313
@available(watchOS, unavailable)
14-
@MainActor(unsafe)
1514
open class _UIHostingView<Content>: UIView where Content: View {
1615
private var _rootView: Content
1716
var viewGraph: ViewGraph
@@ -44,6 +43,18 @@ open class _UIHostingView<Content>: UIView where Content: View {
4443
fatalError("init(coder:) has not been implemented")
4544
}
4645

46+
deinit {
47+
updateRemovedState()
48+
NotificationCenter.default.removeObserver(self)
49+
clearDeisplayLink()
50+
clearUpdateTimer()
51+
invalidate()
52+
Update.ensure {
53+
viewGraph.preferenceBridge = nil
54+
viewGraph.invalidate()
55+
}
56+
}
57+
4758
func setRootView(_ view: Content, transaction: Transaction) {
4859
_rootView = view
4960
let mutation = CustomGraphMutation { [weak self] in
@@ -131,6 +142,14 @@ open class _UIHostingView<Content>: UIView where Content: View {
131142
lastRenderTime = timestamp
132143
return interval.seconds
133144
}
145+
146+
// TODO
147+
func clearDeisplayLink() {
148+
}
149+
150+
// TODO
151+
func clearUpdateTimer() {
152+
}
134153
}
135154

136155
extension _UIHostingView: ViewRendererHost {
@@ -168,6 +187,10 @@ extension _UIHostingView: ViewRendererHost {
168187
func preferencesDidChange() {
169188
// TODO
170189
}
190+
191+
func updateRemovedState() {
192+
// TODO
193+
}
171194
}
172195

173196
extension UITraitCollection {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
//
2+
// AnyViewTests.swift
3+
// OpenSwiftUIUITests
4+
5+
import XCTest
6+
7+
#if OPENSWIFTUI
8+
import OpenSwiftUI
9+
#else
10+
import SwiftUI
11+
#endif
12+
13+
#if os(iOS)
14+
import UIKit
15+
16+
#if !OPENSWIFTUI
17+
@available(iOS 15, *)
18+
#endif
19+
final class AnyViewTests: XCTestCase {
20+
}
21+
#endif

0 commit comments

Comments
 (0)