From cc6e2c270d16924ceca7c9f874ee7ca6e06294c9 Mon Sep 17 00:00:00 2001 From: Patrick Date: Tue, 3 Aug 2021 13:24:16 +1000 Subject: [PATCH 01/99] Include ToolBarItem in readiness.md --- readiness.md | 1 + 1 file changed, 1 insertion(+) diff --git a/readiness.md b/readiness.md index af4cfc83..ce962264 100644 --- a/readiness.md +++ b/readiness.md @@ -93,6 +93,7 @@ Visit [this discussion](https://github.com/nalexn/ViewInspector/discussions/60) |:white_check_mark:| TextField | `label view`, `callOnEditingChanged()`, `callOnCommit()`, `input: String`, `setInput(_: String)` | |:white_check_mark:| Toggle | `label view`, `tap()`, `isOn: Bool` | |:white_check_mark:| ToggleStyleConfiguration.Label | | +|:technologist:| ToolbarItem | | |:white_check_mark:| TouchBar | `contained view`, `touchBarID: String` | |:white_check_mark:| TupleView | | |:white_check_mark:| VSplitView | `contained view` | From 9b72b0a6ae9bd65c2e86c8946f768a26d8859841 Mon Sep 17 00:00:00 2001 From: Alexey Naumov Date: Sat, 7 Aug 2021 21:51:00 +0300 Subject: [PATCH 02/99] Rework padding modifier inspection, better tests --- .../Modifiers/SizingModifiers.swift | 172 ++++++++++++------ .../ViewModifiers/ViewPaddingTests.swift | 53 +++++- 2 files changed, 159 insertions(+), 66 deletions(-) diff --git a/Sources/ViewInspector/Modifiers/SizingModifiers.swift b/Sources/ViewInspector/Modifiers/SizingModifiers.swift index 2206546a..3039d1cd 100644 --- a/Sources/ViewInspector/Modifiers/SizingModifiers.swift +++ b/Sources/ViewInspector/Modifiers/SizingModifiers.swift @@ -75,78 +75,60 @@ public extension InspectableView { @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) public extension InspectableView { - private struct PaddingAttributes { - let edgeInsets: EdgeInsets? - let edges: Edge.Set - } - func padding() throws -> EdgeInsets { - return try modifierAttribute( - modifierName: "_PaddingLayout", path: "modifier|insets", - type: EdgeInsets.self, call: "padding") - } - - func padding(_ edge: Edge.Set) throws -> CGFloat { - let attributes = try self.paddingAttributes() - for attribute in attributes { - if attribute.edges.contains(edge) { - if let value = edgeValue(attribute: attribute, edge: edge) { - return value - } - } + let attr = paddingAttributes() + guard attr.count > 0 else { + throw noPaddingModifierError() } - throw InspectionError.modifierNotFound( - parent: Inspector.typeName(value: self), modifier: "padding", index: 0) - } - - func hasPadding(_ edge: Edge.Set = .all) throws -> Bool { - let attributes = try self.paddingAttributes() - for attribute in attributes { - if attribute.edges.contains(edge) { - return true + do { + return .init(top: try attr.cumulativeValue(edge: .top) ?? 0, + leading: try attr.cumulativeValue(edge: .leading) ?? 0, + bottom: try attr.cumulativeValue(edge: .bottom) ?? 0, + trailing: try attr.cumulativeValue(edge: .trailing) ?? 0) + } catch let error { + if attr.allSatisfy({ $0.edges == .all }) { + throw InspectionError.notSupported( + "Please use `hasPadding(_:)` for inspecting padding without explicit value.") } + throw error } - return false } - private func edgeValue(attribute: PaddingAttributes, edge: Edge.Set) -> CGFloat? { - guard let edgeInsets = attribute.edgeInsets else { - return nil - } - var result = [CGFloat]() - if edge.contains(.top) { - result.append(edgeInsets.top) - } - if edge.contains(.bottom) { - result.append(edgeInsets.bottom) - } - if edge.contains(.trailing) { - result.append(edgeInsets.trailing) + func padding(_ edge: Edge.Set) throws -> CGFloat { + let attr = paddingAttributes() + let edges = edge.individualEdges + guard edges.count > 0 else { + throw InspectionError.notSupported("No edge is specified") } - if edge.contains(.leading) { - result.append(edgeInsets.leading) + let values = try edges.map { singleEdge -> CGFloat in + guard let value = try attr.cumulativeValue(edge: singleEdge.edgeSet) else { + throw noPaddingModifierError() + } + return value } - if hasSingleValue(result) { - return result[0] + guard values.areAllEqual() else { + throw InspectionError.notSupported( + """ + Insets for edges '\(edges)' have different values, \ + consider calling `padding` individually per edge. + """ + ) } - return nil + return values[0] } - private func hasSingleValue(_ array: [CGFloat]) -> Bool { - if array.count == 0 { - return false - } - return array.dropLast().allSatisfy { $0 == array.last } + func hasPadding(_ edge: Edge.Set = .all) -> Bool { + return paddingAttributes().contains(where: { $0.edges.contains(edge) }) } - private func paddingAttributes() throws -> [PaddingAttributes] { - - return try modifiersMatching({ $0.modifierType.contains("_PaddingLayout") }) + private func paddingAttributes() -> [Inspector.PaddingAttributes] { + return modifiersMatching({ $0.modifierType.contains("_PaddingLayout") }) .enumerated() - .map { index, modifier -> PaddingAttributes in - let edges = try modifierAttribute( + .compactMap { index, modifier -> Inspector.PaddingAttributes? in + guard let edges = try? modifierAttribute( modifierName: "_PaddingLayout", path: "modifier|edges", type: SwiftUI.Edge.Set.self, call: "padding", index: index) + else { return nil } let insets: EdgeInsets? do { insets = try modifierAttribute( @@ -158,4 +140,82 @@ public extension InspectableView { return .init(edgeInsets: insets, edges: edges) } } + + private func noPaddingModifierError() -> Error { + return InspectionError.modifierNotFound( + parent: Inspector.typeName(value: content.view), + modifier: "padding", index: 0) + } +} + +@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) +private extension Inspector { + struct PaddingAttributes { + let edgeInsets: EdgeInsets? + let edges: Edge.Set + } +} + +@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) +private extension Edge.Set { + var individualEdges: [Edge] { + return [Edge.top, .bottom, .leading, .trailing] + .filter { contains($0.edgeSet) } + } +} + +@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) +private extension Edge { + var edgeSet: Edge.Set { + switch self { + case .top: return .top + case .bottom: return .bottom + case .leading: return .leading + case .trailing: return .trailing + } + } +} + +@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) +private extension RandomAccessCollection where Element == Inspector.PaddingAttributes { + func cumulativeValue(edge: Edge.Set) throws -> CGFloat? { + let undefinedInsetError: (Edge) -> Error = { edge in + return InspectionError.notSupported( + """ + Undefined inset for '\(edge)' edge. Consider calling `hasPadding(_:)` \ + instead to assure a default padding is applied. + """) + } + let insets = try compactMap { attr -> CGFloat? in + if edge == .top, attr.edges.contains(.top) { + guard let insets = attr.edgeInsets + else { throw undefinedInsetError(.top) } + return insets.top + } + if edge == .bottom, attr.edges.contains(.bottom) { + guard let insets = attr.edgeInsets + else { throw undefinedInsetError(.bottom) } + return insets.bottom + } + if edge == .trailing, attr.edges.contains(.trailing) { + guard let insets = attr.edgeInsets + else { throw undefinedInsetError(.trailing) } + return insets.trailing + } + if edge == .leading, attr.edges.contains(.leading) { + guard let insets = attr.edgeInsets + else { throw undefinedInsetError(.leading) } + return insets.leading + } + return nil + } + return insets.count == 0 ? nil : insets.reduce(0, +) + } +} + +private extension RandomAccessCollection where Element: Equatable { + func areAllEqual() -> Bool { + guard let first = self.first else { return true } + return !contains(where: { $0 != first }) + } } diff --git a/Tests/ViewInspectorTests/ViewModifiers/ViewPaddingTests.swift b/Tests/ViewInspectorTests/ViewModifiers/ViewPaddingTests.swift index 41cf9239..08c077c9 100644 --- a/Tests/ViewInspectorTests/ViewModifiers/ViewPaddingTests.swift +++ b/Tests/ViewInspectorTests/ViewModifiers/ViewPaddingTests.swift @@ -32,9 +32,24 @@ final class ViewPaddingTests: XCTestCase { } func testPaddingEdgeSetInspection() throws { - let sut = try EmptyView().padding(.horizontal, 5).inspect().emptyView().padding() - // Looks like a bug in SwiftUI. All edges are set: - XCTAssertEqual(sut, EdgeInsets(top: 5, leading: 5, bottom: 5, trailing: 5)) + let sut = EmptyView().padding(.horizontal, 5) + XCTAssertEqual(try sut.inspect().emptyView().padding(), + EdgeInsets(top: 0, leading: 5, bottom: 0, trailing: 5)) + } + + func testDefaultPaddingValueError() throws { + let sut1 = EmptyView().padding() + let sut2 = EmptyView().padding([.leading]) + let sut3 = EmptyView().offset() + XCTAssertThrows(try sut1.inspect().emptyView().padding(), + "Please use `hasPadding(_:)` for inspecting padding without explicit value.") + XCTAssertThrows(try sut2.inspect().emptyView().padding(), + """ + Undefined inset for 'leading' edge. Consider calling `hasPadding(_:)` \ + instead to assure a default padding is applied. + """) + XCTAssertThrows(try sut3.inspect().emptyView().padding(), + "EmptyView does not have 'padding' modifier") } func testHasDefaultPadding() throws { @@ -54,7 +69,8 @@ final class ViewPaddingTests: XCTestCase { XCTAssertFalse(try sut.inspect().hasPadding([.trailing, .bottom])) XCTAssertFalse(try sut.inspect().hasPadding([.trailing, .top])) - XCTAssertFalse(try sut.inspect().hasPadding([.all])) + XCTAssertFalse(try sut.inspect().hasPadding(.all)) + XCTAssertTrue(try sut.inspect().hasPadding([])) } func testHasLeadingAndTrailingPadding() throws { @@ -89,17 +105,34 @@ final class ViewPaddingTests: XCTestCase { XCTAssertEqual(try sut.inspect().padding([.top]), 10) XCTAssertEqual(try sut.inspect().padding([.bottom]), 20) XCTAssertThrows(try sut.inspect().padding([.leading]), - "InspectableView does not have 'padding' modifier") + "Text does not have 'padding' modifier") XCTAssertThrows(try sut.inspect().padding([.trailing]), - "InspectableView does not have 'padding' modifier") + "Text does not have 'padding' modifier") + XCTAssertThrows(try sut.inspect().padding([.top, .bottom]), + """ + Insets for edges '[SwiftUI.Edge.top, SwiftUI.Edge.bottom]' have \ + different values, consider calling `padding` individually per edge. + """) + XCTAssertThrows(try sut.inspect().padding([]), "No edge is specified") } func testHasDifferentPaddingForEdges() throws { let sut = Text("Test").padding([.top, .bottom], 10).padding([.leading, .trailing], 20) - XCTAssertEqual(try sut.inspect().padding([.top]), 10) - XCTAssertEqual(try sut.inspect().padding([.bottom]), 10) - XCTAssertEqual(try sut.inspect().padding([.leading]), 20) - XCTAssertEqual(try sut.inspect().padding([.trailing]), 20) + XCTAssertEqual(try sut.inspect().padding(.top), 10) + XCTAssertEqual(try sut.inspect().padding(.bottom), 10) + XCTAssertEqual(try sut.inspect().padding(.leading), 20) + XCTAssertEqual(try sut.inspect().padding(.trailing), 20) + XCTAssertEqual(try sut.inspect().padding(), .init(top: 10, leading: 20, bottom: 10, trailing: 20)) + } + + func testCumulativePadding() throws { + let sut = Text("Test") + .padding([.top, .bottom], 10) + .padding([.top, .trailing], 20) + .padding(5) + + XCTAssertEqual(try sut.inspect().padding(.top), 35) + XCTAssertEqual(try sut.inspect().padding(), .init(top: 35, leading: 5, bottom: 15, trailing: 25)) } } From d58fff9ee856bd226247b5d0d8ad8a9b7edccc7e Mon Sep 17 00:00:00 2001 From: Alexey Naumov Date: Sat, 7 Aug 2021 22:04:48 +0300 Subject: [PATCH 03/99] Fix #126 - modifier not applied to a ConditionalView under ViewBuilder --- .../SwiftUI/ConditionalContent.swift | 2 +- .../SwiftUI/ConditionalContentTests.swift | 35 +++++++++++++++++-- 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/Sources/ViewInspector/SwiftUI/ConditionalContent.swift b/Sources/ViewInspector/SwiftUI/ConditionalContent.swift index 0c4dfbde..5f8b4f4a 100644 --- a/Sources/ViewInspector/SwiftUI/ConditionalContent.swift +++ b/Sources/ViewInspector/SwiftUI/ConditionalContent.swift @@ -12,7 +12,7 @@ extension ViewType.ConditionalContent: SingleViewContent { static func child(_ content: Content) throws -> Content { let storage = try Inspector.attribute(label: "storage", value: content.view) - let medium = content.medium.resettingViewModifiers() + let medium = content.medium if let trueContent = try? Inspector.attribute(label: "trueContent", value: storage) { return try Inspector.unwrap(view: trueContent, medium: medium) } diff --git a/Tests/ViewInspectorTests/SwiftUI/ConditionalContentTests.swift b/Tests/ViewInspectorTests/SwiftUI/ConditionalContentTests.swift index d5227121..eeaec139 100644 --- a/Tests/ViewInspectorTests/SwiftUI/ConditionalContentTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/ConditionalContentTests.swift @@ -15,9 +15,19 @@ final class ConditionalContentTests: XCTestCase { } func testResetsModifiers() throws { - let view = ConditionalView().padding() + let view = ConditionalView().padding().offset() let sut = try view.inspect().view(ConditionalView.self).group() - XCTAssertEqual(sut.content.medium.viewModifiers.count, 0) + XCTAssertEqual(sut.content.medium.viewModifiers.count, 1) + let text = try sut.text(0) + XCTAssertEqual(text.content.medium.viewModifiers.count, 0) + } + + func testRetainsModifiers() throws { + let sut = ConditionalViewWithModifier(value: true) + print(">> \(Inspector.print(sut) as AnyObject)") + let text = try sut.inspect().text() + XCTAssertEqual(try text.string(), "True") + XCTAssertEqual(try text.padding(), EdgeInsets(top: 8, leading: 8, bottom: 8, trailing: 8)) } } @@ -29,10 +39,29 @@ private struct ConditionalView: View, Inspectable { Group { if viewModel.flag { Text("Text") } else { Image("Image") } - } + }.padding(8) } class ViewModel: ObservableObject { @Published var flag: Bool = true } } + +@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) +private struct ConditionalViewWithModifier: View, Inspectable { + + let value: Bool + + var body: some View { + content + .padding(8) + } + + @ViewBuilder private var content: some View { + if value { + Text("True") + } else { + Text("False") + } + } +} From 52d2b659b84454361067ad3c43a3112dd7d1e6dd Mon Sep 17 00:00:00 2001 From: Alexey Naumov Date: Sun, 8 Aug 2021 13:53:20 +0300 Subject: [PATCH 04/99] Add one more test for padding inset --- .../ViewModifiers/ViewPaddingTests.swift | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Tests/ViewInspectorTests/ViewModifiers/ViewPaddingTests.swift b/Tests/ViewInspectorTests/ViewModifiers/ViewPaddingTests.swift index 08c077c9..14654fb5 100644 --- a/Tests/ViewInspectorTests/ViewModifiers/ViewPaddingTests.swift +++ b/Tests/ViewInspectorTests/ViewModifiers/ViewPaddingTests.swift @@ -135,4 +135,16 @@ final class ViewPaddingTests: XCTestCase { XCTAssertEqual(try sut.inspect().padding(.top), 35) XCTAssertEqual(try sut.inspect().padding(), .init(top: 35, leading: 5, bottom: 15, trailing: 25)) } + + func testCumulativeUndefinedPaddingError() throws { + let sut = Text("Test") + .padding(.trailing) + .padding(.trailing, 10) + XCTAssertThrows(try sut.inspect().padding(.trailing), + """ + Undefined inset for 'trailing' edge. Consider calling `hasPadding(_:)` \ + instead to assure a default padding is applied. + """) + XCTAssertTrue(try sut.inspect().hasPadding(.trailing)) + } } From 19b26b3128a602f86fa608dab6928904b6b9fa28 Mon Sep 17 00:00:00 2001 From: Alexey Naumov Date: Sun, 8 Aug 2021 14:43:26 +0300 Subject: [PATCH 05/99] Declare watchOS support --- README.md | 2 +- ViewInspector.xcodeproj/project.pbxproj | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index dce1d6f0..417930cf 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ -![Platform](https://img.shields.io/badge/platform-iOS%20%7C%20tvOS%20%7C%20macOS-lightgrey) [![Build Status](https://travis-ci.com/nalexn/ViewInspector.svg?branch=master)](https://travis-ci.com/nalexn/ViewInspector) [![codecov](https://codecov.io/gh/nalexn/ViewInspector/branch/master/graph/badge.svg)](https://codecov.io/gh/nalexn/ViewInspector) +![Platform](https://img.shields.io/badge/platform-iOS%20%7C%20macOS%20%7C%20tvOS%20%7C%20watchOS-lightgrey) [![Build Status](https://travis-ci.com/nalexn/ViewInspector.svg?branch=master)](https://travis-ci.com/nalexn/ViewInspector) [![codecov](https://codecov.io/gh/nalexn/ViewInspector/branch/master/graph/badge.svg)](https://codecov.io/gh/nalexn/ViewInspector) diff --git a/ViewInspector.xcodeproj/project.pbxproj b/ViewInspector.xcodeproj/project.pbxproj index 1b4f4658..5a5f4d8e 100644 --- a/ViewInspector.xcodeproj/project.pbxproj +++ b/ViewInspector.xcodeproj/project.pbxproj @@ -1283,11 +1283,13 @@ ONLY_ACTIVE_ARCH = YES; OTHER_SWIFT_FLAGS = "$(inherited) -DXcode"; PRODUCT_NAME = "$(TARGET_NAME)"; - SUPPORTED_PLATFORMS = "macosx iphoneos iphonesimulator appletvos appletvsimulator"; + SUPPORTED_PLATFORMS = "macosx iphoneos iphonesimulator appletvos appletvsimulator watchos watchsimulator"; SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) SWIFT_PACKAGE DEBUG"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + TARGETED_DEVICE_FAMILY = "1,2,3,4,6"; TVOS_DEPLOYMENT_TARGET = 13.0; USE_HEADERMAP = NO; + WATCHOS_DEPLOYMENT_TARGET = 6.0; }; name = Debug; }; @@ -1313,7 +1315,6 @@ SKIP_INSTALL = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited)"; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2,3"; TARGET_NAME = ViewInspector; }; name = Debug; @@ -1340,7 +1341,6 @@ SKIP_INSTALL = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited)"; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2,3"; TARGET_NAME = ViewInspector; }; name = Release; @@ -1389,11 +1389,13 @@ MACOSX_DEPLOYMENT_TARGET = 10.15; OTHER_SWIFT_FLAGS = "$(inherited) -DXcode"; PRODUCT_NAME = "$(TARGET_NAME)"; - SUPPORTED_PLATFORMS = "macosx iphoneos iphonesimulator appletvos appletvsimulator"; + SUPPORTED_PLATFORMS = "macosx iphoneos iphonesimulator appletvos appletvsimulator watchos watchsimulator"; SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) SWIFT_PACKAGE"; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + TARGETED_DEVICE_FAMILY = "1,2,3,4,6"; TVOS_DEPLOYMENT_TARGET = 13.0; USE_HEADERMAP = NO; + WATCHOS_DEPLOYMENT_TARGET = 6.0; }; name = Release; }; @@ -1446,7 +1448,6 @@ PRODUCT_BUNDLE_IDENTIFIER = ViewInspectorTests; SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited)"; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2,3"; TARGET_NAME = ViewInspectorTests; }; name = Debug; @@ -1470,7 +1471,6 @@ PRODUCT_BUNDLE_IDENTIFIER = ViewInspectorTests; SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited)"; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2,3"; TARGET_NAME = ViewInspectorTests; }; name = Release; From 98541b4e709036478320d53ce9a277353d979877 Mon Sep 17 00:00:00 2001 From: Alexey Naumov Date: Sun, 8 Aug 2021 15:45:05 +0300 Subject: [PATCH 06/99] Update availability for watchOS --- .../ViewInspector/Modifiers/TextInputModifiers.swift | 7 +++---- Sources/ViewInspector/SwiftUI/ColorPicker.swift | 4 ++-- Sources/ViewInspector/SwiftUI/Gesture.swift | 4 ++++ Sources/ViewInspector/SwiftUI/GroupBox.swift | 2 ++ Sources/ViewInspector/SwiftUI/Image.swift | 2 +- Sources/ViewInspector/SwiftUI/Label.swift | 4 ++-- Sources/ViewInspector/SwiftUI/LazyHGrid.swift | 6 +++--- Sources/ViewInspector/SwiftUI/LazyHStack.swift | 2 +- Sources/ViewInspector/SwiftUI/LazyVGrid.swift | 2 +- Sources/ViewInspector/SwiftUI/LazyVStack.swift | 2 +- Sources/ViewInspector/SwiftUI/Map.swift | 6 +++--- Sources/ViewInspector/SwiftUI/MapAnnotation.swift | 6 +++--- Sources/ViewInspector/SwiftUI/Menu.swift | 2 ++ Sources/ViewInspector/SwiftUI/OutlineGroup.swift | 1 + Sources/ViewInspector/SwiftUI/ProgressView.swift | 4 ++-- Sources/ViewInspector/SwiftUI/ScrollViewReader.swift | 4 ++-- .../ViewInspector/SwiftUI/StyleConfiguration.swift | 12 ++++++------ 17 files changed, 39 insertions(+), 31 deletions(-) diff --git a/Sources/ViewInspector/Modifiers/TextInputModifiers.swift b/Sources/ViewInspector/Modifiers/TextInputModifiers.swift index 2c4b6188..c20ce9d4 100644 --- a/Sources/ViewInspector/Modifiers/TextInputModifiers.swift +++ b/Sources/ViewInspector/Modifiers/TextInputModifiers.swift @@ -5,16 +5,14 @@ import SwiftUI @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) public extension InspectableView { - #if !os(macOS) + #if os(iOS) || os(tvOS) func textContentType() throws -> UITextContentType? { let reference = EmptyView().textContentType(.emailAddress) let keyPath = try Inspector.environmentKeyPath(Optional.self, reference) let value = try environment(keyPath, call: "textContentType") return value.flatMap { UITextContentType(rawValue: $0) } } - #endif - - #if os(iOS) || os(tvOS) + func keyboardType() throws -> UIKeyboardType { let reference = EmptyView().keyboardType(.default) let keyPath = try Inspector.environmentKeyPath(Int.self, reference) @@ -91,6 +89,7 @@ public extension InspectableView { return false } + @available(watchOS, unavailable) func disableAutocorrection() -> Bool { let reference = EmptyView().disableAutocorrection(false) if let keyPath = try? Inspector.environmentKeyPath(Optional.self, reference), diff --git a/Sources/ViewInspector/SwiftUI/ColorPicker.swift b/Sources/ViewInspector/SwiftUI/ColorPicker.swift index 36e78de9..2ae2f103 100644 --- a/Sources/ViewInspector/SwiftUI/ColorPicker.swift +++ b/Sources/ViewInspector/SwiftUI/ColorPicker.swift @@ -46,7 +46,7 @@ public extension InspectableView where View == ViewType.ColorPicker { .asInspectableView(ofType: ViewType.ClassifiedView.self) } - @available(tvOS 14.0, *) + @available(tvOS 14.0, watchOS 7.0, *) func select(color: Color) throws { try guardIsResponsive() #if os(macOS) @@ -101,7 +101,7 @@ public extension ViewType.ColorPicker { #endif } - @available(tvOS 14.0, *) + @available(tvOS 14.0, watchOS 7.0, *) init(color: Color) { #if os(macOS) self.init(color: NSColor(color)) diff --git a/Sources/ViewInspector/SwiftUI/Gesture.swift b/Sources/ViewInspector/SwiftUI/Gesture.swift index 6cc04a26..18c0f1c7 100644 --- a/Sources/ViewInspector/SwiftUI/Gesture.swift +++ b/Sources/ViewInspector/SwiftUI/Gesture.swift @@ -60,10 +60,12 @@ extension LongPressGesture: Inspectable {} @available(iOS 13.0, macOS 10.15, *) @available(tvOS, unavailable) +@available(watchOS, unavailable) extension MagnificationGesture: Inspectable {} @available(iOS 13.0, macOS 10.15, *) @available(tvOS, unavailable) +@available(watchOS, unavailable) extension RotationGesture: Inspectable {} @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) @@ -419,6 +421,7 @@ public extension LongPressGesture.Value { @available(iOS 13.0, macOS 10.15, *) @available(tvOS, unavailable) +@available(watchOS, unavailable) public extension MagnificationGesture.Value { private struct Allocator { @@ -435,6 +438,7 @@ public extension MagnificationGesture.Value { @available(iOS 13.0, macOS 10.15, *) @available(tvOS, unavailable) +@available(watchOS, unavailable) public extension RotationGesture.Value { private struct Allocator { diff --git a/Sources/ViewInspector/SwiftUI/GroupBox.swift b/Sources/ViewInspector/SwiftUI/GroupBox.swift index c92ce317..89f96dae 100644 --- a/Sources/ViewInspector/SwiftUI/GroupBox.swift +++ b/Sources/ViewInspector/SwiftUI/GroupBox.swift @@ -76,6 +76,7 @@ public extension InspectableView { @available(iOS 14.0, macOS 11.0, *) @available(tvOS, unavailable) +@available(watchOS, unavailable) public extension GroupBoxStyle { func inspect() throws -> InspectableView { let config = GroupBoxStyleConfiguration() @@ -88,6 +89,7 @@ public extension GroupBoxStyle { @available(iOS 14.0, macOS 11.0, *) @available(tvOS, unavailable) +@available(watchOS, unavailable) private extension GroupBoxStyleConfiguration { private struct Allocator { } init() { diff --git a/Sources/ViewInspector/SwiftUI/Image.swift b/Sources/ViewInspector/SwiftUI/Image.swift index 3eb425ca..17493d58 100644 --- a/Sources/ViewInspector/SwiftUI/Image.swift +++ b/Sources/ViewInspector/SwiftUI/Image.swift @@ -79,7 +79,7 @@ public extension SwiftUI.Image { .attribute(label: "name", value: rawImage(), type: String.self) } - #if os(iOS) || os(tvOS) + #if !os(macOS) func uiImage() throws -> UIImage { return try Inspector.cast(value: try rawImage(), type: UIImage.self) } diff --git a/Sources/ViewInspector/SwiftUI/Label.swift b/Sources/ViewInspector/SwiftUI/Label.swift index bd32b23f..2fc6fdb8 100644 --- a/Sources/ViewInspector/SwiftUI/Label.swift +++ b/Sources/ViewInspector/SwiftUI/Label.swift @@ -81,7 +81,7 @@ public extension InspectableView { // MARK: - LabelStyle inspection -@available(iOS 14.0, macOS 11.0, tvOS 14.0, *) +@available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *) public extension LabelStyle { func inspect() throws -> InspectableView { let config = LabelStyleConfiguration() @@ -92,7 +92,7 @@ public extension LabelStyle { // MARK: - Style Configuration initializer -@available(iOS 14.0, macOS 11.0, tvOS 14.0, *) +@available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *) private extension LabelStyleConfiguration { struct Allocator { } init() { diff --git a/Sources/ViewInspector/SwiftUI/LazyHGrid.swift b/Sources/ViewInspector/SwiftUI/LazyHGrid.swift index 8b835de8..3ac3c55c 100644 --- a/Sources/ViewInspector/SwiftUI/LazyHGrid.swift +++ b/Sources/ViewInspector/SwiftUI/LazyHGrid.swift @@ -41,7 +41,7 @@ extension ViewType.LazyHGrid: MultipleViewContent { // MARK: - Custom Attributes -@available(iOS 14.0, macOS 11.0, tvOS 14.0, *) +@available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *) public extension InspectableView where View == ViewType.LazyHGrid { func alignment() throws -> VerticalAlignment { @@ -69,7 +69,7 @@ public extension InspectableView where View == ViewType.LazyHGrid { } } -@available(iOS 14.0, macOS 11.0, tvOS 14.0, *) +@available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *) extension GridItem: Equatable { public static func == (lhs: GridItem, rhs: GridItem) -> Bool { return lhs.size == rhs.size @@ -78,7 +78,7 @@ extension GridItem: Equatable { } } -@available(iOS 14.0, macOS 11.0, tvOS 14.0, *) +@available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *) extension GridItem.Size: Equatable { public static func == (lhs: GridItem.Size, rhs: GridItem.Size) -> Bool { switch (lhs, rhs) { diff --git a/Sources/ViewInspector/SwiftUI/LazyHStack.swift b/Sources/ViewInspector/SwiftUI/LazyHStack.swift index 04231bc0..74b928d5 100644 --- a/Sources/ViewInspector/SwiftUI/LazyHStack.swift +++ b/Sources/ViewInspector/SwiftUI/LazyHStack.swift @@ -41,7 +41,7 @@ extension ViewType.LazyHStack: MultipleViewContent { // MARK: - Custom Attributes -@available(iOS 14.0, macOS 11.0, tvOS 14.0, *) +@available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *) public extension InspectableView where View == ViewType.LazyHStack { func alignment() throws -> VerticalAlignment { diff --git a/Sources/ViewInspector/SwiftUI/LazyVGrid.swift b/Sources/ViewInspector/SwiftUI/LazyVGrid.swift index 6a1adce5..6bfb895f 100644 --- a/Sources/ViewInspector/SwiftUI/LazyVGrid.swift +++ b/Sources/ViewInspector/SwiftUI/LazyVGrid.swift @@ -41,7 +41,7 @@ extension ViewType.LazyVGrid: MultipleViewContent { // MARK: - Custom Attributes -@available(iOS 14.0, macOS 11.0, tvOS 14.0, *) +@available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *) public extension InspectableView where View == ViewType.LazyVGrid { func alignment() throws -> HorizontalAlignment { diff --git a/Sources/ViewInspector/SwiftUI/LazyVStack.swift b/Sources/ViewInspector/SwiftUI/LazyVStack.swift index b619bd20..909fef0a 100644 --- a/Sources/ViewInspector/SwiftUI/LazyVStack.swift +++ b/Sources/ViewInspector/SwiftUI/LazyVStack.swift @@ -41,7 +41,7 @@ extension ViewType.LazyVStack: MultipleViewContent { // MARK: - Custom Attributes -@available(iOS 14.0, macOS 11.0, tvOS 14.0, *) +@available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *) public extension InspectableView where View == ViewType.LazyVStack { func alignment() throws -> HorizontalAlignment { diff --git a/Sources/ViewInspector/SwiftUI/Map.swift b/Sources/ViewInspector/SwiftUI/Map.swift index 0f19d2c4..74f62402 100644 --- a/Sources/ViewInspector/SwiftUI/Map.swift +++ b/Sources/ViewInspector/SwiftUI/Map.swift @@ -33,7 +33,7 @@ public extension InspectableView where View: MultipleViewContent { // MARK: - Custom Attributes -@available(iOS 14.0, tvOS 14.0, macOS 11.0, *) +@available(iOS 14.0, tvOS 14.0, macOS 11.0, watchOS 7.0, *) public extension InspectableView where View == ViewType.Map { func coordinateRegion() throws -> MKCoordinateRegion { @@ -92,7 +92,7 @@ public extension InspectableView where View == ViewType.Map { } } -@available(iOS 14.0, tvOS 14.0, macOS 11.0, *) +@available(iOS 14.0, tvOS 14.0, macOS 11.0, watchOS 7.0, *) private extension InspectableView where View == ViewType.Map { func coordinateRegionBinding() throws -> Binding { @@ -119,7 +119,7 @@ internal protocol IdentifiableItemsContainer { func contains(_ item: T) -> Bool } -@available(iOS 14.0, tvOS 14.0, macOS 11.0, *) +@available(iOS 14.0, tvOS 14.0, macOS 11.0, watchOS 7.0, *) extension _DefaultAnnotatedMapContent: IdentifiableItemsContainer { func contains(_ item: T) -> Bool { guard let item = item as? Items.Element, diff --git a/Sources/ViewInspector/SwiftUI/MapAnnotation.swift b/Sources/ViewInspector/SwiftUI/MapAnnotation.swift index 26ca181b..42de218a 100644 --- a/Sources/ViewInspector/SwiftUI/MapAnnotation.swift +++ b/Sources/ViewInspector/SwiftUI/MapAnnotation.swift @@ -41,7 +41,7 @@ public extension InspectableView where View == ViewType.MapAnnotation { // MARK: - SwiftUI MapAnnotation -@available(iOS 14.0, tvOS 14.0, macOS 11.0, *) +@available(iOS 14.0, tvOS 14.0, macOS 11.0, watchOS 7.0, *) public extension MapAnnotation { func coordinate() throws -> CLLocationCoordinate2D { @@ -63,7 +63,7 @@ public extension MapAnnotation { // MARK: - SwiftUI MapMarker -@available(iOS 14.0, tvOS 14.0, macOS 11.0, *) +@available(iOS 14.0, tvOS 14.0, macOS 11.0, watchOS 7.0, *) public extension MapMarker { func coordinate() throws -> CLLocationCoordinate2D { @@ -79,7 +79,7 @@ public extension MapMarker { // MARK: - SwiftUI MapPin -@available(iOS 14.0, tvOS 14.0, macOS 11.0, *) +@available(iOS 14.0, tvOS 14.0, macOS 11.0, watchOS 7.0, *) public extension MapPin { func coordinate() throws -> CLLocationCoordinate2D { diff --git a/Sources/ViewInspector/SwiftUI/Menu.swift b/Sources/ViewInspector/SwiftUI/Menu.swift index 55f53e43..c5c9a803 100644 --- a/Sources/ViewInspector/SwiftUI/Menu.swift +++ b/Sources/ViewInspector/SwiftUI/Menu.swift @@ -76,6 +76,7 @@ public extension InspectableView { @available(iOS 14.0, macOS 11.0, *) @available(tvOS, unavailable) +@available(watchOS, unavailable) public extension MenuStyle { func inspect() throws -> InspectableView { let config = MenuStyleConfiguration() @@ -88,6 +89,7 @@ public extension MenuStyle { @available(iOS 14.0, macOS 11.0, *) @available(tvOS, unavailable) +@available(watchOS, unavailable) private extension MenuStyleConfiguration { struct Allocator { } init() { diff --git a/Sources/ViewInspector/SwiftUI/OutlineGroup.swift b/Sources/ViewInspector/SwiftUI/OutlineGroup.swift index d2800f21..173a60b1 100644 --- a/Sources/ViewInspector/SwiftUI/OutlineGroup.swift +++ b/Sources/ViewInspector/SwiftUI/OutlineGroup.swift @@ -60,6 +60,7 @@ private protocol LeafContentProvider { @available(iOS 14.0, macOS 11.0, *) @available(tvOS, unavailable) +@available(watchOS, unavailable) extension OutlineGroup: LeafContentProvider { func view(_ element: Any) throws -> Any { guard let data = element as? Data.Element else { diff --git a/Sources/ViewInspector/SwiftUI/ProgressView.swift b/Sources/ViewInspector/SwiftUI/ProgressView.swift index 8b92ca89..c60e5640 100644 --- a/Sources/ViewInspector/SwiftUI/ProgressView.swift +++ b/Sources/ViewInspector/SwiftUI/ProgressView.swift @@ -99,7 +99,7 @@ public extension InspectableView { // MARK: - ProgressViewStyle inspection -@available(iOS 14.0, macOS 11.0, tvOS 14.0, *) +@available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *) public extension ProgressViewStyle { func inspect(fractionCompleted: Double? = nil) throws -> InspectableView { let config = ProgressViewStyleConfiguration(fractionCompleted: fractionCompleted) @@ -110,7 +110,7 @@ public extension ProgressViewStyle { // MARK: - Style Configuration initializer -@available(iOS 14.0, macOS 11.0, tvOS 14.0, *) +@available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *) internal extension ProgressViewStyleConfiguration { private struct Allocator { let fractionCompleted: Double? diff --git a/Sources/ViewInspector/SwiftUI/ScrollViewReader.swift b/Sources/ViewInspector/SwiftUI/ScrollViewReader.swift index ffba3d81..6b6a4805 100644 --- a/Sources/ViewInspector/SwiftUI/ScrollViewReader.swift +++ b/Sources/ViewInspector/SwiftUI/ScrollViewReader.swift @@ -46,7 +46,7 @@ private protocol ScrollViewReaderContentProvider { func view() throws -> Any } -@available(iOS 14.0, macOS 11.0, tvOS 14.0, *) +@available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *) extension ScrollViewReader: ScrollViewReaderContentProvider { func view() throws -> Any { typealias Builder = (ScrollViewProxy) -> Content @@ -56,7 +56,7 @@ extension ScrollViewReader: ScrollViewReaderContentProvider { } } -@available(iOS 14.0, macOS 11.0, tvOS 14.0, *) +@available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *) private extension ScrollViewProxy { struct Allocator8 { let data: Int64 = 0 diff --git a/Sources/ViewInspector/SwiftUI/StyleConfiguration.swift b/Sources/ViewInspector/SwiftUI/StyleConfiguration.swift index 2c8ab7ce..96e84ad3 100644 --- a/Sources/ViewInspector/SwiftUI/StyleConfiguration.swift +++ b/Sources/ViewInspector/SwiftUI/StyleConfiguration.swift @@ -16,9 +16,9 @@ public extension ViewType.StyleConfiguration { ButtonStyleConfiguration.Label.self, ToggleStyleConfiguration.Label.self ] - if #available(iOS 14.0, macOS 11.0, tvOS 14.0, *) { + if #available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *) { types.append(ProgressViewStyleConfiguration.Label.self) - #if !os(tvOS) + #if os(iOS) || os(macOS) types.append(GroupBoxStyleConfiguration.Label.self) types.append(MenuStyleConfiguration.Label.self) #endif @@ -38,7 +38,7 @@ public extension ViewType.StyleConfiguration { public static var namespacedPrefixes: [String] { var types: [Any.Type] = [] if #available(iOS 14.0, macOS 11.0, tvOS 14.0, *) { - #if !os(tvOS) + #if os(iOS) || os(macOS) types.append(GroupBoxStyleConfiguration.Content.self) types.append(MenuStyleConfiguration.Content.self) #endif @@ -57,7 +57,7 @@ public extension ViewType.StyleConfiguration { public static var namespacedPrefixes: [String] { var types: [Any.Type] = [] - if #available(iOS 14.0, macOS 11.0, tvOS 14.0, *) { + if #available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *) { types.append(LabelStyleConfiguration.Title.self) } return types @@ -74,7 +74,7 @@ public extension ViewType.StyleConfiguration { public static var namespacedPrefixes: [String] { var types: [Any.Type] = [] - if #available(iOS 14.0, macOS 11.0, tvOS 14.0, *) { + if #available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *) { types.append(LabelStyleConfiguration.Icon.self) } return types @@ -91,7 +91,7 @@ public extension ViewType.StyleConfiguration { public static var namespacedPrefixes: [String] { var types: [Any.Type] = [] - if #available(iOS 14.0, macOS 11.0, tvOS 14.0, *) { + if #available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *) { types.append(ProgressViewStyleConfiguration.CurrentValueLabel.self) } return types From 3b10e8116d997595a18d769a6c891619c8dc9dcd Mon Sep 17 00:00:00 2001 From: Alexey Naumov Date: Thu, 12 Aug 2021 22:20:35 +0300 Subject: [PATCH 07/99] Update availability in the tests for watchOS --- .../Modifiers/TextInputModifiers.swift | 2 +- .../ViewInspector/SwiftUI/CustomView.swift | 2 +- .../SwiftUI/TextAttributes.swift | 2 +- Sources/ViewInspector/ViewHosting.swift | 31 ++++++++++++++----- Sources/ViewInspector/ViewHostingProxy.swift | 16 ++++++++++ .../CommonComposedGestureChangedTests.swift | 1 + .../CommonComposedGestureEndedTests.swift | 1 + .../Gestures/CommonComposedGestureTests.swift | 1 + .../CommonComposedGestureUpdatingTests.swift | 1 + .../ComposedGestureExampleTests.swift | 4 +++ .../ExclusiveGestureChildrenTests.swift | 1 + .../Gestures/ExclusiveGestureTests.swift | 1 + .../Gestures/MagnificationGestureTests.swift | 1 + .../Gestures/RotationGestureTests.swift | 1 + .../SequenceGestureChildrenTests.swift | 1 + .../Gestures/SequenceGestureTests.swift | 1 + .../SimultaneousGestureChildrenTests.swift | 1 + .../Gestures/SimultaneousGestureTests.swift | 1 + .../SwiftUI/ColorPickerTests.swift | 18 ++++++----- .../SwiftUI/CustomViewTests.swift | 14 ++++++++- .../SwiftUI/DatePickerTests.swift | 2 ++ .../SwiftUI/DisclosureGroupTests.swift | 3 ++ .../SwiftUI/ForEachTests.swift | 2 +- .../SwiftUI/GroupBoxTests.swift | 2 ++ .../SwiftUI/HStackTests.swift | 2 +- .../SwiftUI/ImageTests.swift | 26 +++++++++++----- .../SwiftUI/LabelTests.swift | 20 ++++++------ .../SwiftUI/LazyHGridTests.swift | 20 ++++++------ .../SwiftUI/LazyHStackTests.swift | 16 +++++----- .../SwiftUI/LazyVGridTests.swift | 18 +++++------ .../SwiftUI/LazyVStackTests.swift | 16 +++++----- .../SwiftUI/LinkTests.swift | 10 +++--- .../SwiftUI/MapAnnotationTests.swift | 8 ++--- .../ViewInspectorTests/SwiftUI/MapTests.swift | 26 ++++++++-------- .../SwiftUI/MenuTests.swift | 2 +- .../SwiftUI/NavigationLinkTests.swift | 15 +++++++-- .../SwiftUI/NavigationViewTests.swift | 4 +-- .../SwiftUI/OutlineGroupTests.swift | 4 +++ .../SwiftUI/PopoverTests.swift | 6 ++-- .../SwiftUI/ProgressViewTests.swift | 20 ++++++------ .../SwiftUI/ScrollViewReaderTests.swift | 8 ++--- .../SwiftUI/TabViewTests.swift | 8 +++-- .../SwiftUI/TextAttributesTests.swift | 12 +++---- .../SwiftUI/TextEditorTests.swift | 11 ++++--- .../SwiftUI/TextTests.swift | 14 ++++----- .../SwiftUI/TreeViewTests.swift | 10 +++--- .../SwiftUI/VStackTests.swift | 2 +- .../ViewInspectorTests/ViewHostingTests.swift | 7 +++-- .../AccessibilityModifiersTests.swift | 2 ++ .../ViewModifiers/EventsModifiersTests.swift | 10 +++--- .../TextInputModifiersTests.swift | 6 +++- .../TransitiveModifiersTests.swift | 4 +++ .../ViewInspectorTests/ViewSearchTests.swift | 4 +-- ViewInspector.xcodeproj/project.pbxproj | 4 +++ 54 files changed, 267 insertions(+), 158 deletions(-) create mode 100644 Sources/ViewInspector/ViewHostingProxy.swift diff --git a/Sources/ViewInspector/Modifiers/TextInputModifiers.swift b/Sources/ViewInspector/Modifiers/TextInputModifiers.swift index c20ce9d4..eb591c9d 100644 --- a/Sources/ViewInspector/Modifiers/TextInputModifiers.swift +++ b/Sources/ViewInspector/Modifiers/TextInputModifiers.swift @@ -2,7 +2,7 @@ import SwiftUI // MARK: - Adjusting Text in a View -@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) +@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *) public extension InspectableView { #if os(iOS) || os(tvOS) diff --git a/Sources/ViewInspector/SwiftUI/CustomView.swift b/Sources/ViewInspector/SwiftUI/CustomView.swift index 3dac5507..a7bf21c9 100644 --- a/Sources/ViewInspector/SwiftUI/CustomView.swift +++ b/Sources/ViewInspector/SwiftUI/CustomView.swift @@ -135,7 +135,7 @@ public extension Inspectable where Self: NSViewControllerRepresentable { "Please use `.actualView().viewController()` for inspecting the contents of NSViewControllerRepresentable") } } -#else +#elseif os(iOS) || os(tvOS) @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) public extension UIViewRepresentable where Self: Inspectable { func uiView() throws -> UIViewType { diff --git a/Sources/ViewInspector/SwiftUI/TextAttributes.swift b/Sources/ViewInspector/SwiftUI/TextAttributes.swift index 25d24299..7464020e 100644 --- a/Sources/ViewInspector/SwiftUI/TextAttributes.swift +++ b/Sources/ViewInspector/SwiftUI/TextAttributes.swift @@ -268,7 +268,7 @@ public extension Font { } func isFixedSize() -> Bool { - guard #available(iOS 14.0, macOS 11.0, tvOS 14.0, *) + guard #available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *) else { return false } guard let provider = try? Inspector.attribute(path: "provider|base", value: self), Inspector.typeName(value: provider) == "NamedProvider" diff --git a/Sources/ViewInspector/ViewHosting.swift b/Sources/ViewInspector/ViewHosting.swift index a22afdaa..9b4c3f1b 100644 --- a/Sources/ViewInspector/ViewHosting.swift +++ b/Sources/ViewInspector/ViewHosting.swift @@ -3,9 +3,10 @@ import SwiftUI import UIKit #endif +@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *) public struct ViewHosting { } -@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) +@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *) public extension ViewHosting { struct ViewId: Hashable { @@ -22,6 +23,13 @@ public extension ViewHosting { } return unwrapped.medium }() + #if os(watchOS) + guard let proxy = ViewHosting.proxy else { + // !!! + fatalError("View hosting is not set up. Please follow this guide: ") + } + proxy.host(view: AnyView(view)) + #else let parentVC = rootViewController let childVC = hostVC(view) let size = size ?? parentVC.view.bounds.size @@ -39,16 +47,21 @@ public extension ViewHosting { ]) didMove(childVC, to: parentVC) window.layoutIfNeeded() + #endif } static func expel(function: String = #function) { let viewId = ViewId(function: function) guard let hosted = expel(viewId: viewId) else { return } + #if os(watchOS) + ViewHosting.proxy?.host(view: nil) + #else let childVC = hosted.viewController willMove(childVC, to: nil) childVC.view.removeFromSuperview() childVC.removeFromParent() didMove(childVC, to: nil) + #endif } internal static func medium(function: String = #function) -> Content.Medium { @@ -65,7 +78,7 @@ private extension ViewHosting { struct Hosted { #if os(macOS) let viewController: NSViewController - #else + #elseif os(iOS) || os(tvOS) let viewController: UIViewController #endif let medium: Content.Medium @@ -73,7 +86,7 @@ private extension ViewHosting { private static var hosted: [ViewId: Hosted] = [:] #if os(macOS) static var window: NSWindow = makeWindow() - #else + #elseif os(iOS) || os(tvOS) static var window: UIWindow = makeWindow() #endif @@ -91,7 +104,7 @@ private extension ViewHosting { window.layoutIfNeeded() return window } - #else + #elseif os(iOS) || os(tvOS) static func makeWindow() -> UIWindow { let window = UIWindow(frame: UIScreen.main.bounds) window.rootViewController = UIViewController() @@ -111,7 +124,7 @@ private extension ViewHosting { static func hostVC(_ view: V) -> NSHostingController where V: View { NSHostingController(rootView: view) } - #else + #elseif os(iOS) || os(tvOS) static var rootViewController: UIViewController { window.rootViewController! } @@ -127,7 +140,7 @@ private extension ViewHosting { } static func didMove(_ child: NSViewController, to parent: NSViewController?) { } - #else + #elseif os(iOS) || os(tvOS) static func willMove(_ child: UIViewController, to parent: UIViewController?) { child.willMove(toParent: parent) } @@ -147,6 +160,7 @@ private extension ViewHosting { } } +#if !os(watchOS) @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) private extension NSLayoutConstraint { #if os(macOS) @@ -161,6 +175,7 @@ private extension NSLayoutConstraint { } #endif } +#endif // MARK: - RootViewController for macOS @@ -210,7 +225,7 @@ internal extension ViewHosting { else { throw InspectionError.viewNotFound(parent: name) } return vc } - #else + #elseif os(iOS) || os(tvOS) static func lookup(_ view: V.Type) throws -> V.UIViewType where V: Inspectable & UIViewRepresentable { let name = Inspector.typeName(type: view) @@ -263,7 +278,7 @@ private extension NSViewController { return presented + children } } -#else +#elseif os(iOS) || os(tvOS) @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) private extension UIView { func descendant(nameTraits: [String]) -> UIView? { diff --git a/Sources/ViewInspector/ViewHostingProxy.swift b/Sources/ViewInspector/ViewHostingProxy.swift new file mode 100644 index 00000000..4195de21 --- /dev/null +++ b/Sources/ViewInspector/ViewHostingProxy.swift @@ -0,0 +1,16 @@ +import SwiftUI + +@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *) +public protocol ViewHostingProxy { + static var instance: Self { get } + func host(view: AnyView?) +} + +@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *) +public extension ViewHosting { + private(set) internal static var proxy: ViewHostingProxy? + + static func register(proxy: ViewHostingProxy?) { + self.proxy = proxy + } +} diff --git a/Tests/ViewInspectorTests/Gestures/CommonComposedGestureChangedTests.swift b/Tests/ViewInspectorTests/Gestures/CommonComposedGestureChangedTests.swift index 26a19721..f51119a6 100644 --- a/Tests/ViewInspectorTests/Gestures/CommonComposedGestureChangedTests.swift +++ b/Tests/ViewInspectorTests/Gestures/CommonComposedGestureChangedTests.swift @@ -7,6 +7,7 @@ import Combine @available(iOS 13.0, macOS 10.15, *) @available(tvOS, unavailable) +@available(watchOS, unavailable) final class CommonComposedGestureChangedTests { let testCase: XCTestCase diff --git a/Tests/ViewInspectorTests/Gestures/CommonComposedGestureEndedTests.swift b/Tests/ViewInspectorTests/Gestures/CommonComposedGestureEndedTests.swift index 9848c0a8..b336743c 100644 --- a/Tests/ViewInspectorTests/Gestures/CommonComposedGestureEndedTests.swift +++ b/Tests/ViewInspectorTests/Gestures/CommonComposedGestureEndedTests.swift @@ -7,6 +7,7 @@ import Combine @available(iOS 13.0, macOS 10.15, *) @available(tvOS, unavailable) +@available(watchOS, unavailable) final class CommonComposedGestureEndedTests { let testCase: XCTestCase diff --git a/Tests/ViewInspectorTests/Gestures/CommonComposedGestureTests.swift b/Tests/ViewInspectorTests/Gestures/CommonComposedGestureTests.swift index e932b4b9..4857b2d1 100644 --- a/Tests/ViewInspectorTests/Gestures/CommonComposedGestureTests.swift +++ b/Tests/ViewInspectorTests/Gestures/CommonComposedGestureTests.swift @@ -7,6 +7,7 @@ import Combine @available(iOS 13.0, macOS 10.15, *) @available(tvOS, unavailable) +@available(watchOS, unavailable) final class CommonComposedGestureTests { let type: U.Type diff --git a/Tests/ViewInspectorTests/Gestures/CommonComposedGestureUpdatingTests.swift b/Tests/ViewInspectorTests/Gestures/CommonComposedGestureUpdatingTests.swift index 1e0fdc96..de13e427 100644 --- a/Tests/ViewInspectorTests/Gestures/CommonComposedGestureUpdatingTests.swift +++ b/Tests/ViewInspectorTests/Gestures/CommonComposedGestureUpdatingTests.swift @@ -7,6 +7,7 @@ import Combine @available(iOS 13.0, macOS 10.15, *) @available(tvOS, unavailable) +@available(watchOS, unavailable) final class CommonComposedGestureUpdatingTests { @GestureState var gestureState = CGSize.zero diff --git a/Tests/ViewInspectorTests/Gestures/ComposedGestureExampleTests.swift b/Tests/ViewInspectorTests/Gestures/ComposedGestureExampleTests.swift index c981a562..7de18d9d 100644 --- a/Tests/ViewInspectorTests/Gestures/ComposedGestureExampleTests.swift +++ b/Tests/ViewInspectorTests/Gestures/ComposedGestureExampleTests.swift @@ -5,6 +5,7 @@ import Combine @available(iOS 13.0, macOS 11, *) @available(tvOS, unavailable) +@available(watchOS, unavailable) final class ComposedGestureExampleTests: XCTestCase { func testComposedGestureFirst() throws { @@ -105,6 +106,7 @@ final class ComposedGestureExampleTests: XCTestCase { @available(iOS 13.0, macOS 11, *) @available(tvOS, unavailable) +@available(watchOS, unavailable) struct TestGestureView10: View & Inspectable { @State var scale: CGFloat = 1.0 @State var angle = Angle(degrees: 0) @@ -137,6 +139,7 @@ struct TestGestureView10: View & Inspectable { @available(iOS 13.0, macOS 11, *) @available(tvOS, unavailable) +@available(watchOS, unavailable) struct TestGestureView11: View & Inspectable { @State var scale: CGFloat = 1.0 @State var angle = Angle(degrees: 0) @@ -168,6 +171,7 @@ struct TestGestureView11: View & Inspectable { @available(iOS 13.0, macOS 11, *) @available(tvOS, unavailable) +@available(watchOS, unavailable) struct TestGestureView12: View & Inspectable { internal let inspection = Inspection() diff --git a/Tests/ViewInspectorTests/Gestures/ExclusiveGestureChildrenTests.swift b/Tests/ViewInspectorTests/Gestures/ExclusiveGestureChildrenTests.swift index f6e1a6ef..a5b0f363 100644 --- a/Tests/ViewInspectorTests/Gestures/ExclusiveGestureChildrenTests.swift +++ b/Tests/ViewInspectorTests/Gestures/ExclusiveGestureChildrenTests.swift @@ -7,6 +7,7 @@ import Combine @available(iOS 13.0, macOS 10.15, *) @available(tvOS, unavailable) +@available(watchOS, unavailable) final class ExclusiveGestureChildrenTests: XCTestCase { typealias GUT = ExclusiveGesture diff --git a/Tests/ViewInspectorTests/Gestures/ExclusiveGestureTests.swift b/Tests/ViewInspectorTests/Gestures/ExclusiveGestureTests.swift index 43add667..3c40b6a3 100644 --- a/Tests/ViewInspectorTests/Gestures/ExclusiveGestureTests.swift +++ b/Tests/ViewInspectorTests/Gestures/ExclusiveGestureTests.swift @@ -7,6 +7,7 @@ import Combine @available(iOS 13.0, macOS 10.15, *) @available(tvOS, unavailable) +@available(watchOS, unavailable) final class ExclusiveGestureTests: XCTestCase { @GestureState var gestureState = CGSize.zero diff --git a/Tests/ViewInspectorTests/Gestures/MagnificationGestureTests.swift b/Tests/ViewInspectorTests/Gestures/MagnificationGestureTests.swift index 7df13af7..57096c3e 100644 --- a/Tests/ViewInspectorTests/Gestures/MagnificationGestureTests.swift +++ b/Tests/ViewInspectorTests/Gestures/MagnificationGestureTests.swift @@ -7,6 +7,7 @@ import Combine @available(iOS 13.0, macOS 10.15, *) @available(tvOS, unavailable) +@available(watchOS, unavailable) final class MagnificationGestureTests: XCTestCase { var magnificationMagnifyBy: CGFloat? diff --git a/Tests/ViewInspectorTests/Gestures/RotationGestureTests.swift b/Tests/ViewInspectorTests/Gestures/RotationGestureTests.swift index 0f7e7b1d..1bf26497 100644 --- a/Tests/ViewInspectorTests/Gestures/RotationGestureTests.swift +++ b/Tests/ViewInspectorTests/Gestures/RotationGestureTests.swift @@ -7,6 +7,7 @@ import Combine @available(iOS 13.0, macOS 10.15, *) @available(tvOS, unavailable) +@available(watchOS, unavailable) final class RotationGestureTests: XCTestCase { var rotationAngle: Angle? diff --git a/Tests/ViewInspectorTests/Gestures/SequenceGestureChildrenTests.swift b/Tests/ViewInspectorTests/Gestures/SequenceGestureChildrenTests.swift index 51b8b5d3..f4d7d8f3 100644 --- a/Tests/ViewInspectorTests/Gestures/SequenceGestureChildrenTests.swift +++ b/Tests/ViewInspectorTests/Gestures/SequenceGestureChildrenTests.swift @@ -7,6 +7,7 @@ import Combine @available(iOS 13.0, macOS 10.15, *) @available(tvOS, unavailable) +@available(watchOS, unavailable) final class SequenceGestureChildrenTests: XCTestCase { typealias GUT = SequenceGesture diff --git a/Tests/ViewInspectorTests/Gestures/SequenceGestureTests.swift b/Tests/ViewInspectorTests/Gestures/SequenceGestureTests.swift index 5a81078c..e5b8d803 100644 --- a/Tests/ViewInspectorTests/Gestures/SequenceGestureTests.swift +++ b/Tests/ViewInspectorTests/Gestures/SequenceGestureTests.swift @@ -7,6 +7,7 @@ import Combine @available(iOS 13.0, macOS 10.15, *) @available(tvOS, unavailable) +@available(watchOS, unavailable) final class SequenceGestureTests: XCTestCase { @GestureState var gestureState = CGSize.zero diff --git a/Tests/ViewInspectorTests/Gestures/SimultaneousGestureChildrenTests.swift b/Tests/ViewInspectorTests/Gestures/SimultaneousGestureChildrenTests.swift index 6648bee3..8769f867 100644 --- a/Tests/ViewInspectorTests/Gestures/SimultaneousGestureChildrenTests.swift +++ b/Tests/ViewInspectorTests/Gestures/SimultaneousGestureChildrenTests.swift @@ -7,6 +7,7 @@ import Combine @available(iOS 13.0, macOS 10.15, *) @available(tvOS, unavailable) +@available(watchOS, unavailable) final class SimultaneousGestureChildrenTests: XCTestCase { typealias GUT = SimultaneousGesture diff --git a/Tests/ViewInspectorTests/Gestures/SimultaneousGestureTests.swift b/Tests/ViewInspectorTests/Gestures/SimultaneousGestureTests.swift index fb9cd3c8..36c92942 100644 --- a/Tests/ViewInspectorTests/Gestures/SimultaneousGestureTests.swift +++ b/Tests/ViewInspectorTests/Gestures/SimultaneousGestureTests.swift @@ -7,6 +7,7 @@ import Combine @available(iOS 13.0, macOS 10.15, *) @available(tvOS, unavailable) +@available(watchOS, unavailable) final class SimultaneousGestureTests: XCTestCase { @GestureState var gestureState = CGSize.zero diff --git a/Tests/ViewInspectorTests/SwiftUI/ColorPickerTests.swift b/Tests/ViewInspectorTests/SwiftUI/ColorPickerTests.swift index 74fbb1e2..7299d2b3 100644 --- a/Tests/ViewInspectorTests/SwiftUI/ColorPickerTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/ColorPickerTests.swift @@ -4,23 +4,24 @@ import SwiftUI @available(iOS 13.0, macOS 10.15, *) @available(tvOS, unavailable) +@available(watchOS, unavailable) final class ColorPickerTests: XCTestCase { func testInspect() throws { - guard #available(iOS 14, tvOS 14, macOS 11.0, *) else { return } + guard #available(iOS 14, tvOS 14, macOS 11.0, watchOS 7.0, *) else { return } let binding = Binding(wrappedValue: .test) XCTAssertNoThrow(try ColorPicker("Test", selection: binding).inspect()) } func testExtractionFromSingleViewContainer() throws { - guard #available(iOS 14, tvOS 14, macOS 11.0, *) else { return } + guard #available(iOS 14, tvOS 14, macOS 11.0, watchOS 7.0, *) else { return } let binding = Binding(wrappedValue: .test) let view = AnyView(ColorPicker("Test", selection: binding)) XCTAssertNoThrow(try view.inspect().anyView().colorPicker()) } func testExtractionFromMultipleViewContainer() throws { - guard #available(iOS 14, tvOS 14, macOS 11.0, *) else { return } + guard #available(iOS 14, tvOS 14, macOS 11.0, watchOS 7.0, *) else { return } let binding = Binding(wrappedValue: .test) let view = HStack { Text("") @@ -31,7 +32,7 @@ final class ColorPickerTests: XCTestCase { } func testSearch() throws { - guard #available(iOS 14, tvOS 14, macOS 11.0, *) else { return } + guard #available(iOS 14, tvOS 14, macOS 11.0, watchOS 7.0, *) else { return } let binding = Binding(wrappedValue: .test) let view = Group { ColorPicker(selection: binding, label: { HStack { Text("abc") } @@ -43,7 +44,7 @@ final class ColorPickerTests: XCTestCase { } func testLabelInspection() throws { - guard #available(iOS 14, tvOS 14, macOS 11.0, *) else { return } + guard #available(iOS 14, tvOS 14, macOS 11.0, watchOS 7.0, *) else { return } let binding = Binding(wrappedValue: .red) let sut = ColorPicker(selection: binding, label: { HStack { Text("abc") } @@ -53,7 +54,7 @@ final class ColorPickerTests: XCTestCase { } func testColorSelection() throws { - guard #available(iOS 14, tvOS 14, macOS 11.0, *) else { return } + guard #available(iOS 14, tvOS 14, macOS 11.0, watchOS 7.0, *) else { return } let cgColor = CGColor(red: 0.5, green: 0.2, blue: 0.7, alpha: 0.1) let binding1 = Binding(wrappedValue: cgColor) @@ -70,7 +71,7 @@ final class ColorPickerTests: XCTestCase { } func testColorSelectionWhenDisabled() throws { - guard #available(iOS 14, tvOS 14, macOS 11.0, *) else { return } + guard #available(iOS 14, tvOS 14, macOS 11.0, watchOS 7.0, *) else { return } let cgColor = CGColor(red: 0.5, green: 0.2, blue: 0.7, alpha: 0.1) let binding1 = Binding(wrappedValue: cgColor) @@ -89,7 +90,7 @@ final class ColorPickerTests: XCTestCase { } func testRGBA() throws { - guard #available(iOS 14, tvOS 14, macOS 11.0, *) else { return } + guard #available(iOS 14, tvOS 14, macOS 11.0, watchOS 7.0, *) else { return } #if os(macOS) XCTAssertNotEqual(NSColor.red.rgba(), Color.red.rgba()) #else @@ -139,6 +140,7 @@ private extension UIColor { @available(tvOS, unavailable) private extension Color { @available(tvOS 14.0, *) + @available(watchOS 7.0, *) func rgba() -> ViewType.ColorPicker.RGBA { return .init(color: self) } diff --git a/Tests/ViewInspectorTests/SwiftUI/CustomViewTests.swift b/Tests/ViewInspectorTests/SwiftUI/CustomViewTests.swift index 829ca765..75447764 100644 --- a/Tests/ViewInspectorTests/SwiftUI/CustomViewTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/CustomViewTests.swift @@ -255,7 +255,7 @@ private struct TestViewControllerRepresentable: NSViewControllerRepresentable, I func updateNSViewController(_ uiViewController: NSViewControllerType, context: Context) { } } -#else +#elseif os(iOS) || os(tvOS) @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) private struct TestViewRepresentable: UIViewRepresentable, Inspectable { @@ -281,6 +281,18 @@ private struct TestViewControllerRepresentable: UIViewControllerRepresentable, I func updateUIViewController(_ uiViewController: UIViewControllerType, context: Context) { } } +#elseif os(watchOS) +// !!! +struct TestViewRepresentable: View, Inspectable { + var body: some View { + EmptyView() + } +} +struct TestViewControllerRepresentable: View, Inspectable { + var body: some View { + EmptyView() + } +} #endif // MARK: - Misc diff --git a/Tests/ViewInspectorTests/SwiftUI/DatePickerTests.swift b/Tests/ViewInspectorTests/SwiftUI/DatePickerTests.swift index b5e834fc..383e2c9a 100644 --- a/Tests/ViewInspectorTests/SwiftUI/DatePickerTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/DatePickerTests.swift @@ -4,6 +4,7 @@ import SwiftUI @available(iOS 13.0, macOS 10.15, *) @available(tvOS, unavailable) +@available(watchOS, unavailable) final class DatePickerTests: XCTestCase { class StateObject: ObservableObject { @@ -74,6 +75,7 @@ final class DatePickerTests: XCTestCase { @available(iOS 13.0, macOS 10.15, *) @available(tvOS, unavailable) +@available(watchOS, unavailable) final class GlobalModifiersForDatePicker: XCTestCase { func testDatePickerStyle() throws { diff --git a/Tests/ViewInspectorTests/SwiftUI/DisclosureGroupTests.swift b/Tests/ViewInspectorTests/SwiftUI/DisclosureGroupTests.swift index c0b15600..332fd637 100644 --- a/Tests/ViewInspectorTests/SwiftUI/DisclosureGroupTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/DisclosureGroupTests.swift @@ -4,6 +4,7 @@ import SwiftUI @available(iOS 13.0, macOS 10.15, *) @available(tvOS, unavailable) +@available(watchOS, unavailable) final class DisclosureGroupTests: XCTestCase { func testInspect() throws { @@ -99,6 +100,7 @@ final class DisclosureGroupTests: XCTestCase { @available(iOS 14.0, macOS 11.0, *) @available(tvOS, unavailable) +@available(watchOS, unavailable) private struct TestViewState: View, Inspectable { @ObservedObject var state = ExpansionState() @@ -116,6 +118,7 @@ private struct TestViewState: View, Inspectable { @available(iOS 14.0, macOS 11.0, *) @available(tvOS, unavailable) +@available(watchOS, unavailable) private struct TestViewBinding: View, Inspectable { @Binding var expanded: Bool = false diff --git a/Tests/ViewInspectorTests/SwiftUI/ForEachTests.swift b/Tests/ViewInspectorTests/SwiftUI/ForEachTests.swift index cc74f505..724bdcd6 100644 --- a/Tests/ViewInspectorTests/SwiftUI/ForEachTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/ForEachTests.swift @@ -134,7 +134,7 @@ final class ForEachTests: XCTestCase { #if os(macOS) func testOnInsert() throws { - guard #available(iOS 14.0, macOS 11.0, tvOS 14.0, *) + guard #available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *) else { return } let exp = XCTestExpectation(description: #function) let sut = ForEach([0, 1, 3], id: \.self) { id in Text("\(id)") } diff --git a/Tests/ViewInspectorTests/SwiftUI/GroupBoxTests.swift b/Tests/ViewInspectorTests/SwiftUI/GroupBoxTests.swift index aa007ac8..82a98591 100644 --- a/Tests/ViewInspectorTests/SwiftUI/GroupBoxTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/GroupBoxTests.swift @@ -4,6 +4,7 @@ import SwiftUI @available(iOS 13.0, macOS 10.15, *) @available(tvOS, unavailable) +@available(watchOS, unavailable) final class GroupBoxTests: XCTestCase { func testSingleEnclosedView() throws { @@ -111,6 +112,7 @@ final class GroupBoxTests: XCTestCase { @available(iOS 14.0, macOS 11.0, *) @available(tvOS, unavailable) +@available(watchOS, unavailable) private struct TestGroupBoxStyle: GroupBoxStyle { func makeBody(configuration: Configuration) -> some View { VStack { diff --git a/Tests/ViewInspectorTests/SwiftUI/HStackTests.swift b/Tests/ViewInspectorTests/SwiftUI/HStackTests.swift index fa834678..5b53c457 100644 --- a/Tests/ViewInspectorTests/SwiftUI/HStackTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/HStackTests.swift @@ -71,7 +71,7 @@ final class HStackTests: XCTestCase { } func testSpacingInspection() throws { - guard #available(iOS 14, macOS 11.0, tvOS 14.0, *) else { return } + guard #available(iOS 14, macOS 11.0, tvOS 14.0, watchOS 7.0, *) else { return } let view = HStack(spacing: 7) { Text("") } diff --git a/Tests/ViewInspectorTests/SwiftUI/ImageTests.swift b/Tests/ViewInspectorTests/SwiftUI/ImageTests.swift index d1541dd4..f53a1dc7 100644 --- a/Tests/ViewInspectorTests/SwiftUI/ImageTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/ImageTests.swift @@ -26,7 +26,7 @@ final class ImageTests: XCTestCase { } func testExternalImage() throws { - #if os(iOS) || os(tvOS) + #if !os(macOS) let sut = Image(uiImage: testImage) let image = try sut.uiImage() #else @@ -38,7 +38,7 @@ final class ImageTests: XCTestCase { func testExtractionWithModifiers() throws { let view = AnyView(imageView().resizable().interpolation(.low)) - #if os(iOS) || os(tvOS) + #if !os(macOS) let image = try view.inspect().anyView().image().actualImage().uiImage() #else let image = try view.inspect().anyView().image().actualImage().nsImage() @@ -57,7 +57,7 @@ final class ImageTests: XCTestCase { XCTAssertEqual(scale, 2.0) XCTAssertEqual(orientation, .down) XCTAssertEqual(label, "CGImage") - #if os(iOS) || os(tvOS) + #if !os(macOS) XCTAssertThrows(try image.uiImage(), "Type mismatch: CGImageProvider is not UIImage") #else XCTAssertThrows(try image.nsImage(), "Type mismatch: CGImageProvider is not NSImage") @@ -65,7 +65,7 @@ final class ImageTests: XCTestCase { } func testLabelImageText() throws { - guard #available(iOS 14, macOS 11.0, tvOS 14.0, *) else { return } + guard #available(iOS 14, macOS 11.0, tvOS 14.0, watchOS 7.0, *) else { return } let view = Label("tx", image: "img") let text = try view.inspect().label().icon().image().labelView() XCTAssertEqual(try text.string(), "img") @@ -98,7 +98,7 @@ final class ImageTests: XCTestCase { } private func imageView() -> Image { - #if os(iOS) || os(tvOS) + #if !os(macOS) return Image(uiImage: testImage) #else return Image(nsImage: testImage) @@ -117,7 +117,19 @@ extension UIColor { } } } -#else +#elseif os(watchOS) +extension UIColor { + func image(_ size: CGSize) -> UIImage { + UIGraphicsBeginImageContextWithOptions(size, false, 0) + defer { + UIGraphicsEndImageContext() + } + self.setFill() + UIRectFill(.init(origin: .zero, size: size)) + return UIGraphicsGetImageFromCurrentImageContext() ?? UIImage() + } +} +#elseif os(macOS) extension NSColor { func image(_ size: CGSize) -> NSImage { let image = NSImage(size: size) @@ -134,7 +146,7 @@ extension NSImage { } #endif -#if os(iOS) || os(tvOS) +#if !os(macOS) let testColor = UIColor.red #else let testColor = NSColor.red diff --git a/Tests/ViewInspectorTests/SwiftUI/LabelTests.swift b/Tests/ViewInspectorTests/SwiftUI/LabelTests.swift index 5681b9b4..4323a508 100644 --- a/Tests/ViewInspectorTests/SwiftUI/LabelTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/LabelTests.swift @@ -6,18 +6,18 @@ import SwiftUI final class LabelTests: XCTestCase { func testInspect() throws { - guard #available(iOS 14, macOS 11.0, tvOS 14.0, *) else { return } + guard #available(iOS 14, macOS 11.0, tvOS 14.0, watchOS 7.0, *) else { return } XCTAssertNoThrow(try Label("title", image: "image").inspect()) } func testExtractionFromSingleViewContainer() throws { - guard #available(iOS 14, macOS 11.0, tvOS 14.0, *) else { return } + guard #available(iOS 14, macOS 11.0, tvOS 14.0, watchOS 7.0, *) else { return } let view = AnyView(Label("title", image: "image")) XCTAssertNoThrow(try view.inspect().anyView().label()) } func testExtractionFromMultipleViewContainer() throws { - guard #available(iOS 14, macOS 11.0, tvOS 14.0, *) else { return } + guard #available(iOS 14, macOS 11.0, tvOS 14.0, watchOS 7.0, *) else { return } let view = HStack { Text("") Label("title", image: "image") @@ -27,7 +27,7 @@ final class LabelTests: XCTestCase { } func testSearch() throws { - guard #available(iOS 14, macOS 11.0, tvOS 14.0, *) else { return } + guard #available(iOS 14, macOS 11.0, tvOS 14.0, watchOS 7.0, *) else { return } let view = HStack { Label("tx", image: "img") } XCTAssertEqual(try view.inspect().find(ViewType.Label.self).pathToRoot, "hStack().label(0)") @@ -38,7 +38,7 @@ final class LabelTests: XCTestCase { } func testTitleInspection() throws { - guard #available(iOS 14, macOS 11.0, tvOS 14.0, *) else { return } + guard #available(iOS 14, macOS 11.0, tvOS 14.0, watchOS 7.0, *) else { return } let view = Label(title: { HStack { Text("abc") } }, icon: { @@ -49,7 +49,7 @@ final class LabelTests: XCTestCase { } func testIconInspection() throws { - guard #available(iOS 14, macOS 11.0, tvOS 14.0, *) else { return } + guard #available(iOS 14, macOS 11.0, tvOS 14.0, watchOS 7.0, *) else { return } let view = Label(title: { HStack { Text("abc") } }, icon: { @@ -66,19 +66,19 @@ final class LabelTests: XCTestCase { final class GlobalModifiersForLabel: XCTestCase { func testLabelStyle() throws { - guard #available(iOS 14, macOS 11.0, tvOS 14.0, *) else { return } + guard #available(iOS 14, macOS 11.0, tvOS 14.0, watchOS 7.0, *) else { return } let sut = EmptyView().labelStyle(IconOnlyLabelStyle()) XCTAssertNoThrow(try sut.inspect().emptyView()) } func testLabelStyleInspection() throws { - guard #available(iOS 14, macOS 11.0, tvOS 14.0, *) else { return } + guard #available(iOS 14, macOS 11.0, tvOS 14.0, watchOS 7.0, *) else { return } let sut = EmptyView().labelStyle(IconOnlyLabelStyle()) XCTAssertTrue(try sut.inspect().labelStyle() is IconOnlyLabelStyle) } func testCustomLabelStyleInspection() throws { - guard #available(iOS 14, macOS 11.0, tvOS 14.0, *) else { return } + guard #available(iOS 14, macOS 11.0, tvOS 14.0, watchOS 7.0, *) else { return } let sut = TestLabelStyle() let title = try sut.inspect().vStack().styleConfigurationTitle(0) let icon = try sut.inspect().vStack().styleConfigurationIcon(1) @@ -95,7 +95,7 @@ final class GlobalModifiersForLabel: XCTestCase { } } -@available(iOS 14.0, macOS 11.0, tvOS 14.0, *) +@available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *) struct TestLabelStyle: LabelStyle { func makeBody(configuration: Configuration) -> some View { VStack { diff --git a/Tests/ViewInspectorTests/SwiftUI/LazyHGridTests.swift b/Tests/ViewInspectorTests/SwiftUI/LazyHGridTests.swift index 881463e2..833cde94 100644 --- a/Tests/ViewInspectorTests/SwiftUI/LazyHGridTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/LazyHGridTests.swift @@ -6,19 +6,19 @@ import SwiftUI final class LazyHGridTests: XCTestCase { func testInspect() throws { - guard #available(iOS 14, macOS 11.0, tvOS 14.0, *) else { return } + guard #available(iOS 14, macOS 11.0, tvOS 14.0, watchOS 7.0, *) else { return } let view = LazyHGrid(rows: [], content: { Text("abc") }) XCTAssertNoThrow(try view.inspect()) } func testExtractionFromSingleViewContainer() throws { - guard #available(iOS 14, macOS 11.0, tvOS 14.0, *) else { return } + guard #available(iOS 14, macOS 11.0, tvOS 14.0, watchOS 7.0, *) else { return } let view = AnyView(LazyHGrid(rows: [], content: { Text("abc") })) XCTAssertNoThrow(try view.inspect().anyView().lazyHGrid()) } func testExtractionFromMultipleViewContainer() throws { - guard #available(iOS 14, macOS 11.0, tvOS 14.0, *) else { return } + guard #available(iOS 14, macOS 11.0, tvOS 14.0, watchOS 7.0, *) else { return } let view = HStack { Text("") LazyHGrid(rows: [], content: { Text("abc") }) @@ -28,7 +28,7 @@ final class LazyHGridTests: XCTestCase { } func testSearch() throws { - guard #available(iOS 14, macOS 11.0, tvOS 14.0, *) else { return } + guard #available(iOS 14, macOS 11.0, tvOS 14.0, watchOS 7.0, *) else { return } let view = HStack { LazyHGrid(rows: [], content: { Text("abc") }) } XCTAssertEqual(try view.inspect().find(ViewType.LazyHGrid.self).pathToRoot, "hStack().lazyHGrid(0)") @@ -37,7 +37,7 @@ final class LazyHGridTests: XCTestCase { } func testContentViewInspection() throws { - guard #available(iOS 14, macOS 11.0, tvOS 14.0, *) else { return } + guard #available(iOS 14, macOS 11.0, tvOS 14.0, watchOS 7.0, *) else { return } let view = LazyHGrid(rows: [], content: { ForEach((0...10), id: \.self) { Text("\($0)") } }) @@ -46,28 +46,28 @@ final class LazyHGridTests: XCTestCase { } func testAlignmentInspection() throws { - guard #available(iOS 14, macOS 11.0, tvOS 14.0, *) else { return } + guard #available(iOS 14, macOS 11.0, tvOS 14.0, watchOS 7.0, *) else { return } let view = LazyHGrid(rows: [], alignment: .top) { Text("") } let sut = try view.inspect().lazyHGrid().alignment() XCTAssertEqual(sut, .top) } func testSpacingInspection() throws { - guard #available(iOS 14, macOS 11.0, tvOS 14.0, *) else { return } + guard #available(iOS 14, macOS 11.0, tvOS 14.0, watchOS 7.0, *) else { return } let view = LazyHGrid(rows: [], spacing: 5) { Text("") } let sut = try view.inspect().lazyHGrid().spacing() XCTAssertEqual(sut, 5) } func testPinnedViewsInspection() throws { - guard #available(iOS 14, macOS 11.0, tvOS 14.0, *) else { return } + guard #available(iOS 14, macOS 11.0, tvOS 14.0, watchOS 7.0, *) else { return } let view = LazyHGrid(rows: [], pinnedViews: .sectionFooters) { Text("") } let sut = try view.inspect().lazyHGrid().pinnedViews() XCTAssertEqual(sut, .sectionFooters) } func testRowsInspection() throws { - guard #available(iOS 14, macOS 11.0, tvOS 14.0, *) else { return } + guard #available(iOS 14, macOS 11.0, tvOS 14.0, watchOS 7.0, *) else { return } let view = LazyHGrid(rows: [GridItem(.fixed(10))]) { Text("") } let sut = try view.inspect().lazyHGrid().rows() XCTAssertEqual(sut, [GridItem(.fixed(10))]) @@ -77,7 +77,7 @@ final class LazyHGridTests: XCTestCase { @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) final class GridItemTests: XCTestCase { func testEquatable() throws { - guard #available(iOS 14, macOS 11.0, tvOS 14.0, *) else { return } + guard #available(iOS 14, macOS 11.0, tvOS 14.0, watchOS 7.0, *) else { return } let items = [ GridItem(.fixed(5), spacing: 40, alignment: .bottomLeading), GridItem(.adaptive(minimum: 10, maximum: 20)), diff --git a/Tests/ViewInspectorTests/SwiftUI/LazyHStackTests.swift b/Tests/ViewInspectorTests/SwiftUI/LazyHStackTests.swift index 7e9db40d..a47c7501 100644 --- a/Tests/ViewInspectorTests/SwiftUI/LazyHStackTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/LazyHStackTests.swift @@ -6,19 +6,19 @@ import SwiftUI final class LazyHStackTests: XCTestCase { func testInspect() throws { - guard #available(iOS 14, macOS 11.0, tvOS 14.0, *) else { return } + guard #available(iOS 14, macOS 11.0, tvOS 14.0, watchOS 7.0, *) else { return } let view = LazyHStack(content: { Text("abc") }) XCTAssertNoThrow(try view.inspect()) } func testExtractionFromSingleViewContainer() throws { - guard #available(iOS 14, macOS 11.0, tvOS 14.0, *) else { return } + guard #available(iOS 14, macOS 11.0, tvOS 14.0, watchOS 7.0, *) else { return } let view = AnyView(LazyHStack(content: { Text("abc") })) XCTAssertNoThrow(try view.inspect().anyView().lazyHStack()) } func testExtractionFromMultipleViewContainer() throws { - guard #available(iOS 14, macOS 11.0, tvOS 14.0, *) else { return } + guard #available(iOS 14, macOS 11.0, tvOS 14.0, watchOS 7.0, *) else { return } let view = HStack { Text("") LazyHStack(content: { Text("abc") }) @@ -28,7 +28,7 @@ final class LazyHStackTests: XCTestCase { } func testSearch() throws { - guard #available(iOS 14, macOS 11.0, tvOS 14.0, *) else { return } + guard #available(iOS 14, macOS 11.0, tvOS 14.0, watchOS 7.0, *) else { return } let view = HStack { LazyHStack(content: { Text("abc") }) } XCTAssertEqual(try view.inspect().find(ViewType.LazyHStack.self).pathToRoot, "hStack().lazyHStack(0)") @@ -37,7 +37,7 @@ final class LazyHStackTests: XCTestCase { } func testContentViewInspection() throws { - guard #available(iOS 14, macOS 11.0, tvOS 14.0, *) else { return } + guard #available(iOS 14, macOS 11.0, tvOS 14.0, watchOS 7.0, *) else { return } let view = LazyHStack(content: { ForEach((0...10), id: \.self) { Text("\($0)") } }) @@ -46,21 +46,21 @@ final class LazyHStackTests: XCTestCase { } func testAlignmentInspection() throws { - guard #available(iOS 14, macOS 11.0, tvOS 14.0, *) else { return } + guard #available(iOS 14, macOS 11.0, tvOS 14.0, watchOS 7.0, *) else { return } let view = LazyHStack(alignment: .top) { Text("") } let sut = try view.inspect().lazyHStack().alignment() XCTAssertEqual(sut, .top) } func testSpacingInspection() throws { - guard #available(iOS 14, macOS 11.0, tvOS 14.0, *) else { return } + guard #available(iOS 14, macOS 11.0, tvOS 14.0, watchOS 7.0, *) else { return } let view = LazyHStack(spacing: 5) { Text("") } let sut = try view.inspect().lazyHStack().spacing() XCTAssertEqual(sut, 5) } func testPinnedViewsInspection() throws { - guard #available(iOS 14, macOS 11.0, tvOS 14.0, *) else { return } + guard #available(iOS 14, macOS 11.0, tvOS 14.0, watchOS 7.0, *) else { return } let view = LazyHStack(pinnedViews: .sectionFooters) { Text("") } let sut = try view.inspect().lazyHStack().pinnedViews() XCTAssertEqual(sut, .sectionFooters) diff --git a/Tests/ViewInspectorTests/SwiftUI/LazyVGridTests.swift b/Tests/ViewInspectorTests/SwiftUI/LazyVGridTests.swift index 119c356e..a10e8c17 100644 --- a/Tests/ViewInspectorTests/SwiftUI/LazyVGridTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/LazyVGridTests.swift @@ -6,19 +6,19 @@ import SwiftUI final class LazyVGridTests: XCTestCase { func testInspect() throws { - guard #available(iOS 14, macOS 11.0, tvOS 14.0, *) else { return } + guard #available(iOS 14, macOS 11.0, tvOS 14.0, watchOS 7.0, *) else { return } let view = LazyVGrid(columns: [], content: { Text("abc") }) XCTAssertNoThrow(try view.inspect()) } func testExtractionFromSingleViewContainer() throws { - guard #available(iOS 14, macOS 11.0, tvOS 14.0, *) else { return } + guard #available(iOS 14, macOS 11.0, tvOS 14.0, watchOS 7.0, *) else { return } let view = AnyView(LazyVGrid(columns: [], content: { Text("abc") })) XCTAssertNoThrow(try view.inspect().anyView().lazyVGrid()) } func testExtractionFromMultipleViewContainer() throws { - guard #available(iOS 14, macOS 11.0, tvOS 14.0, *) else { return } + guard #available(iOS 14, macOS 11.0, tvOS 14.0, watchOS 7.0, *) else { return } let view = HStack { Text("") LazyVGrid(columns: [], content: { Text("abc") }) @@ -28,7 +28,7 @@ final class LazyVGridTests: XCTestCase { } func testSearch() throws { - guard #available(iOS 14, macOS 11.0, tvOS 14.0, *) else { return } + guard #available(iOS 14, macOS 11.0, tvOS 14.0, watchOS 7.0, *) else { return } let view = HStack { LazyVGrid(columns: [], content: { Text("abc") }) } XCTAssertEqual(try view.inspect().find(ViewType.LazyVGrid.self).pathToRoot, "hStack().lazyVGrid(0)") @@ -37,7 +37,7 @@ final class LazyVGridTests: XCTestCase { } func testContentViewInspection() throws { - guard #available(iOS 14, macOS 11.0, tvOS 14.0, *) else { return } + guard #available(iOS 14, macOS 11.0, tvOS 14.0, watchOS 7.0, *) else { return } let view = LazyVGrid(columns: [], content: { ForEach((0...10), id: \.self) { Text("\($0)") } }) @@ -46,28 +46,28 @@ final class LazyVGridTests: XCTestCase { } func testAlignmentInspection() throws { - guard #available(iOS 14, macOS 11.0, tvOS 14.0, *) else { return } + guard #available(iOS 14, macOS 11.0, tvOS 14.0, watchOS 7.0, *) else { return } let view = LazyVGrid(columns: [], alignment: .leading) { Text("") } let sut = try view.inspect().lazyVGrid().alignment() XCTAssertEqual(sut, .leading) } func testSpacingInspection() throws { - guard #available(iOS 14, macOS 11.0, tvOS 14.0, *) else { return } + guard #available(iOS 14, macOS 11.0, tvOS 14.0, watchOS 7.0, *) else { return } let view = LazyVGrid(columns: [], spacing: 5) { Text("") } let sut = try view.inspect().lazyVGrid().spacing() XCTAssertEqual(sut, 5) } func testPinnedViewsInspection() throws { - guard #available(iOS 14, macOS 11.0, tvOS 14.0, *) else { return } + guard #available(iOS 14, macOS 11.0, tvOS 14.0, watchOS 7.0, *) else { return } let view = LazyVGrid(columns: [], pinnedViews: .sectionFooters) { Text("") } let sut = try view.inspect().lazyVGrid().pinnedViews() XCTAssertEqual(sut, .sectionFooters) } func testColumnsInspection() throws { - guard #available(iOS 14, macOS 11.0, tvOS 14.0, *) else { return } + guard #available(iOS 14, macOS 11.0, tvOS 14.0, watchOS 7.0, *) else { return } let view = LazyVGrid(columns: [GridItem(.fixed(10))]) { Text("") } let sut = try view.inspect().lazyVGrid().columns() XCTAssertEqual(sut, [GridItem(.fixed(10))]) diff --git a/Tests/ViewInspectorTests/SwiftUI/LazyVStackTests.swift b/Tests/ViewInspectorTests/SwiftUI/LazyVStackTests.swift index 1f9862c7..11267b54 100644 --- a/Tests/ViewInspectorTests/SwiftUI/LazyVStackTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/LazyVStackTests.swift @@ -6,19 +6,19 @@ import SwiftUI final class LazyVStackTests: XCTestCase { func testInspect() throws { - guard #available(iOS 14, macOS 11.0, tvOS 14.0, *) else { return } + guard #available(iOS 14, macOS 11.0, tvOS 14.0, watchOS 7.0, *) else { return } let view = LazyVStack(content: { Text("abc") }) XCTAssertNoThrow(try view.inspect()) } func testExtractionFromSingleViewContainer() throws { - guard #available(iOS 14, macOS 11.0, tvOS 14.0, *) else { return } + guard #available(iOS 14, macOS 11.0, tvOS 14.0, watchOS 7.0, *) else { return } let view = AnyView(LazyVStack(content: { Text("abc") })) XCTAssertNoThrow(try view.inspect().anyView().lazyVStack()) } func testExtractionFromMultipleViewContainer() throws { - guard #available(iOS 14, macOS 11.0, tvOS 14.0, *) else { return } + guard #available(iOS 14, macOS 11.0, tvOS 14.0, watchOS 7.0, *) else { return } let view = HStack { Text("") LazyVStack(content: { Text("abc") }) @@ -28,7 +28,7 @@ final class LazyVStackTests: XCTestCase { } func testSearch() throws { - guard #available(iOS 14, macOS 11.0, tvOS 14.0, *) else { return } + guard #available(iOS 14, macOS 11.0, tvOS 14.0, watchOS 7.0, *) else { return } let view = HStack { LazyVStack(content: { Text("abc") }) } XCTAssertEqual(try view.inspect().find(ViewType.LazyVStack.self).pathToRoot, "hStack().lazyVStack(0)") @@ -37,7 +37,7 @@ final class LazyVStackTests: XCTestCase { } func testContentViewInspection() throws { - guard #available(iOS 14, macOS 11.0, tvOS 14.0, *) else { return } + guard #available(iOS 14, macOS 11.0, tvOS 14.0, watchOS 7.0, *) else { return } let view = LazyVStack(content: { ForEach((0...10), id: \.self) { Text("\($0)") } }) @@ -46,21 +46,21 @@ final class LazyVStackTests: XCTestCase { } func testAlignmentInspection() throws { - guard #available(iOS 14, macOS 11.0, tvOS 14.0, *) else { return } + guard #available(iOS 14, macOS 11.0, tvOS 14.0, watchOS 7.0, *) else { return } let view = LazyVStack(alignment: .leading) { Text("") } let sut = try view.inspect().lazyVStack().alignment() XCTAssertEqual(sut, .leading) } func testSpacingInspection() throws { - guard #available(iOS 14, macOS 11.0, tvOS 14.0, *) else { return } + guard #available(iOS 14, macOS 11.0, tvOS 14.0, watchOS 7.0, *) else { return } let view = LazyVStack(spacing: 5) { Text("") } let sut = try view.inspect().lazyVStack().spacing() XCTAssertEqual(sut, 5) } func testPinnedViewsInspection() throws { - guard #available(iOS 14, macOS 11.0, tvOS 14.0, *) else { return } + guard #available(iOS 14, macOS 11.0, tvOS 14.0, watchOS 7.0, *) else { return } let view = LazyVStack(pinnedViews: .sectionFooters) { Text("") } let sut = try view.inspect().lazyVStack().pinnedViews() XCTAssertEqual(sut, .sectionFooters) diff --git a/Tests/ViewInspectorTests/SwiftUI/LinkTests.swift b/Tests/ViewInspectorTests/SwiftUI/LinkTests.swift index b70b3f86..d5f160d3 100644 --- a/Tests/ViewInspectorTests/SwiftUI/LinkTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/LinkTests.swift @@ -8,13 +8,13 @@ final class LinkTests: XCTestCase { let url = URL(fileURLWithPath: "test") func testExtractionFromSingleViewContainer() throws { - guard #available(iOS 14, macOS 11.0, tvOS 14.0, *) else { return } + guard #available(iOS 14, macOS 11.0, tvOS 14.0, watchOS 7.0, *) else { return } let view = AnyView(Link("abc", destination: url)) XCTAssertNoThrow(try view.inspect().anyView().link()) } func testExtractionFromMultipleViewContainer() throws { - guard #available(iOS 14, macOS 11.0, tvOS 14.0, *) else { return } + guard #available(iOS 14, macOS 11.0, tvOS 14.0, watchOS 7.0, *) else { return } let view = HStack { Text("") Link("abc", destination: url) @@ -24,7 +24,7 @@ final class LinkTests: XCTestCase { } func testSearch() throws { - guard #available(iOS 14, macOS 11.0, tvOS 14.0, *) else { return } + guard #available(iOS 14, macOS 11.0, tvOS 14.0, watchOS 7.0, *) else { return } let view = AnyView(Link(destination: url, label: { HStack { Text("xyz") } })) @@ -34,13 +34,13 @@ final class LinkTests: XCTestCase { } func testURLInspection() throws { - guard #available(iOS 14, macOS 11.0, tvOS 14.0, *) else { return } + guard #available(iOS 14, macOS 11.0, tvOS 14.0, watchOS 7.0, *) else { return } let view = Link("abc", destination: url) XCTAssertEqual(try view.inspect().link().url(), url) } func testLabelInspection() throws { - guard #available(iOS 14, macOS 11.0, tvOS 14.0, *) else { return } + guard #available(iOS 14, macOS 11.0, tvOS 14.0, watchOS 7.0, *) else { return } let view = Link(destination: url, label: { HStack { Text("xyz") } }) diff --git a/Tests/ViewInspectorTests/SwiftUI/MapAnnotationTests.swift b/Tests/ViewInspectorTests/SwiftUI/MapAnnotationTests.swift index 4d206c91..e92e8439 100644 --- a/Tests/ViewInspectorTests/SwiftUI/MapAnnotationTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/MapAnnotationTests.swift @@ -11,7 +11,7 @@ class MapAnnotationTests: XCTestCase { private let testAnchor = CGPoint(x: 3, y: 4) func testMapAnnotationAttributes() throws { - guard #available(iOS 14.0, tvOS 14.0, macOS 11.0, *) else { return } + guard #available(iOS 14.0, tvOS 14.0, macOS 11.0, watchOS 7.0, *) else { return } let sut = MapAnnotation(coordinate: testCoordinate, anchorPoint: testAnchor) { EmptyView() Text("abc") @@ -24,21 +24,21 @@ class MapAnnotationTests: XCTestCase { } func testMapMarkerAttributes() throws { - guard #available(iOS 14.0, tvOS 14.0, macOS 11.0, *) else { return } + guard #available(iOS 14.0, tvOS 14.0, macOS 11.0, watchOS 7.0, *) else { return } let sut = MapMarker(coordinate: testCoordinate, tint: .red) XCTAssertEqual(try sut.coordinate(), testCoordinate) XCTAssertEqual(try sut.tintColor(), .red) } func testMapPinAttributes() throws { - guard #available(iOS 14.0, tvOS 14.0, macOS 11.0, *) else { return } + guard #available(iOS 14.0, tvOS 14.0, macOS 11.0, watchOS 7.0, *) else { return } let sut = MapPin(coordinate: testCoordinate, tint: .blue) XCTAssertEqual(try sut.coordinate(), testCoordinate) XCTAssertEqual(try sut.tintColor(), .blue) } func testExtractionFromMap() throws { - guard #available(iOS 14.0, tvOS 14.0, macOS 11.0, *) else { return } + guard #available(iOS 14.0, tvOS 14.0, macOS 11.0, watchOS 7.0, *) else { return } let coord = CLLocationCoordinate2D(latitude: 1, longitude: 2) let region = Binding(wrappedValue: .init()) let items = Array(0...5) diff --git a/Tests/ViewInspectorTests/SwiftUI/MapTests.swift b/Tests/ViewInspectorTests/SwiftUI/MapTests.swift index 794c9353..f084b8fc 100644 --- a/Tests/ViewInspectorTests/SwiftUI/MapTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/MapTests.swift @@ -12,13 +12,13 @@ class MapTests: XCTestCase { latitudinalMeters: 987, longitudinalMeters: 6) func testExtractionFromSingleViewContainer() throws { - guard #available(iOS 14.0, tvOS 14.0, macOS 11.0, *) else { return } + guard #available(iOS 14.0, tvOS 14.0, macOS 11.0, watchOS 7.0, *) else { return } let sut = AnyView(Map(coordinateRegion: .constant(MKCoordinateRegion()))) XCTAssertNoThrow(try sut.inspect().anyView().map()) } func testExtractionFromMultipleViewContainer() throws { - guard #available(iOS 14.0, tvOS 14.0, macOS 11.0, *) else { return } + guard #available(iOS 14.0, tvOS 14.0, macOS 11.0, watchOS 7.0, *) else { return } let view = HStack { Map(coordinateRegion: .constant(MKCoordinateRegion())) Map(coordinateRegion: .constant(MKCoordinateRegion())) @@ -28,19 +28,19 @@ class MapTests: XCTestCase { } func testSearch() throws { - guard #available(iOS 14.0, tvOS 14.0, macOS 11.0, *) else { return } + guard #available(iOS 14.0, tvOS 14.0, macOS 11.0, watchOS 7.0, *) else { return } let view = AnyView(Map(coordinateRegion: .constant(MKCoordinateRegion()))) XCTAssertEqual(try view.inspect().find(ViewType.Map.self).pathToRoot, "anyView().map()") } func testExtractingCoordinateRegionValue() throws { - guard #available(iOS 14.0, tvOS 14.0, macOS 11.0, *) else { return } + guard #available(iOS 14.0, tvOS 14.0, macOS 11.0, watchOS 7.0, *) else { return } let sut = Map(coordinateRegion: .constant(testRegion)) XCTAssertEqual(try sut.inspect().map().coordinateRegion(), testRegion) } func testSettingCoordinateRegionValue() throws { - guard #available(iOS 14.0, tvOS 14.0, macOS 11.0, *) else { return } + guard #available(iOS 14.0, tvOS 14.0, macOS 11.0, watchOS 7.0, *) else { return } let binding = Binding(wrappedValue: MKCoordinateRegion()) let sut = Map(coordinateRegion: binding) XCTAssertEqual(try sut.inspect().map().coordinateRegion(), MKCoordinateRegion()) @@ -50,7 +50,7 @@ class MapTests: XCTestCase { } func testErrorOnSettingCoordinateRegionWhenNonResponsive() throws { - guard #available(iOS 14.0, tvOS 14.0, macOS 11.0, *) else { return } + guard #available(iOS 14.0, tvOS 14.0, macOS 11.0, watchOS 7.0, *) else { return } let binding = Binding(wrappedValue: MKCoordinateRegion()) let sut = Map(coordinateRegion: binding).hidden() XCTAssertEqual(try sut.inspect().map().coordinateRegion(), MKCoordinateRegion()) @@ -60,7 +60,7 @@ class MapTests: XCTestCase { } func testExtractingMapRectValue() throws { - guard #available(iOS 14.0, tvOS 14.0, macOS 11.0, *) else { return } + guard #available(iOS 14.0, tvOS 14.0, macOS 11.0, watchOS 7.0, *) else { return } let rect = MKMapRect(x: 3, y: 5, width: 1, height: 8) let sut = Map(mapRect: .constant(rect), interactionModes: .all, @@ -70,7 +70,7 @@ class MapTests: XCTestCase { } func testSettingMapRectValue() throws { - guard #available(iOS 14.0, tvOS 14.0, macOS 11.0, *) else { return } + guard #available(iOS 14.0, tvOS 14.0, macOS 11.0, watchOS 7.0, *) else { return } let binding = Binding(wrappedValue: MKMapRect()) let sut = Map(mapRect: binding, interactionModes: .all, @@ -84,7 +84,7 @@ class MapTests: XCTestCase { } func testErrorOnSettingMapRectWhenNonResponsive() throws { - guard #available(iOS 14.0, tvOS 14.0, macOS 11.0, *) else { return } + guard #available(iOS 14.0, tvOS 14.0, macOS 11.0, watchOS 7.0, *) else { return } let binding = Binding(wrappedValue: MKMapRect()) let sut = Map(mapRect: binding, interactionModes: .all, @@ -99,7 +99,7 @@ class MapTests: XCTestCase { } func testExtractingInteractionModes() throws { - guard #available(iOS 14.0, tvOS 14.0, macOS 11.0, *) else { return } + guard #available(iOS 14.0, tvOS 14.0, macOS 11.0, watchOS 7.0, *) else { return } let region = MKCoordinateRegion() let sut = Map(coordinateRegion: .constant(region), interactionModes: .pan, @@ -110,7 +110,7 @@ class MapTests: XCTestCase { } func testExtractingShowsUserLocation() throws { - guard #available(iOS 14.0, tvOS 14.0, macOS 11.0, *) else { return } + guard #available(iOS 14.0, tvOS 14.0, macOS 11.0, watchOS 7.0, *) else { return } let region = MKCoordinateRegion() let sut = Map(coordinateRegion: .constant(region), interactionModes: .all, @@ -121,7 +121,7 @@ class MapTests: XCTestCase { } func testExtractingUserTrackingMode() throws { - guard #available(iOS 14.0, tvOS 14.0, macOS 11.0, *) else { return } + guard #available(iOS 14.0, tvOS 14.0, macOS 11.0, watchOS 7.0, *) else { return } let region = MKCoordinateRegion() let sut = Map(coordinateRegion: .constant(region), interactionModes: .all, @@ -132,7 +132,7 @@ class MapTests: XCTestCase { } func testSettingUserTrackingMode() throws { - guard #available(iOS 14.0, tvOS 14.0, macOS 11.0, *) else { return } + guard #available(iOS 14.0, tvOS 14.0, macOS 11.0, watchOS 7.0, *) else { return } let binding = Binding(wrappedValue: MapUserTrackingMode.follow) let sut = Map(coordinateRegion: .constant(MKCoordinateRegion()), interactionModes: .all, diff --git a/Tests/ViewInspectorTests/SwiftUI/MenuTests.swift b/Tests/ViewInspectorTests/SwiftUI/MenuTests.swift index 8e5e9f61..c08ec0e8 100644 --- a/Tests/ViewInspectorTests/SwiftUI/MenuTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/MenuTests.swift @@ -2,7 +2,7 @@ import XCTest import SwiftUI @testable import ViewInspector -#if !os(tvOS) +#if os(iOS) || os(macOS) @available(iOS 13.0, macOS 10.15, *) @available(tvOS, unavailable) final class MenuTests: XCTestCase { diff --git a/Tests/ViewInspectorTests/SwiftUI/NavigationLinkTests.swift b/Tests/ViewInspectorTests/SwiftUI/NavigationLinkTests.swift index 9a12d564..f15d6f55 100644 --- a/Tests/ViewInspectorTests/SwiftUI/NavigationLinkTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/NavigationLinkTests.swift @@ -34,6 +34,7 @@ final class NavigationLinkTests: XCTestCase { XCTAssertNoThrow(try view.inspect().anyView().navigationLink()) } + @available(watchOS 7.0, *) func testExtractionFromMultipleViewContainer() throws { let view = NavigationView { NavigationLink( @@ -45,6 +46,7 @@ final class NavigationLinkTests: XCTestCase { XCTAssertNoThrow(try view.inspect().navigationView().navigationLink(1)) } + @available(watchOS 7.0, *) func testSearch() throws { let view = AnyView(NavigationView { NavigationLink( @@ -64,6 +66,7 @@ final class NavigationLinkTests: XCTestCase { "anyView().navigationView().navigationLink(1).labelView().text()") } + @available(watchOS 7.0, *) func testNavigationWithoutBindingAndState() throws { guard #available(iOS 13.1, macOS 10.16, tvOS 13.1, *) else { return } let view = NavigationView { @@ -77,6 +80,7 @@ final class NavigationLinkTests: XCTestCase { "Enable programmatic navigation by using `NavigationLink(destination:, tag:, selection:)`") } + @available(watchOS 7.0, *) func testNavigationWithStateActivation() throws { let view = TestViewState() XCTAssertNil(view.state.selection) @@ -92,6 +96,7 @@ final class NavigationLinkTests: XCTestCase { XCTAssertFalse(isActiveAfter2) } + @available(watchOS 7.0, *) func testNavigationWithBindingActivation() throws { let selection = Binding(wrappedValue: nil) let view = TestViewBinding(selection: selection) @@ -108,6 +113,7 @@ final class NavigationLinkTests: XCTestCase { XCTAssertFalse(isActiveAfter2) } + @available(watchOS 7.0, *) func testNavigationWithStateDeactivation() throws { let view = TestViewState() view.state.selection = view.tag2 @@ -123,6 +129,7 @@ final class NavigationLinkTests: XCTestCase { XCTAssertFalse(isActiveAfter2) } + @available(watchOS 7.0, *) func testNavigationWithBindingDeactivation() throws { let selection = Binding(wrappedValue: nil) let view = TestViewBinding(selection: selection) @@ -139,6 +146,7 @@ final class NavigationLinkTests: XCTestCase { XCTAssertFalse(isActiveAfter2) } + @available(watchOS 7.0, *) func testNavigationWithStateReactivation() throws { let view = TestViewState() try view.inspect().navigationView().navigationLink(1).activate() @@ -151,6 +159,7 @@ final class NavigationLinkTests: XCTestCase { XCTAssertFalse(isActiveAfter2) } + @available(watchOS 7.0, *) func testNavigationWithBindingReactivation() throws { let selection = Binding(wrappedValue: nil) let view = TestViewBinding(selection: selection) @@ -174,7 +183,7 @@ private struct TestView: View, Inspectable { } } -@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) +@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 7.0, *) private struct TestViewState: View, Inspectable { @ObservedObject var state = NavigationState() @@ -191,7 +200,7 @@ private struct TestViewState: View, Inspectable { } } -@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) +@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 7.0, *) private struct TestViewBinding: View, Inspectable { @Binding var selection: String? @@ -209,7 +218,7 @@ private struct TestViewBinding: View, Inspectable { } } -@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) +@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 7.0, *) extension TestViewState { class NavigationState: ObservableObject { @Published var selection: String? diff --git a/Tests/ViewInspectorTests/SwiftUI/NavigationViewTests.swift b/Tests/ViewInspectorTests/SwiftUI/NavigationViewTests.swift index 51f1c5b1..a66ee565 100644 --- a/Tests/ViewInspectorTests/SwiftUI/NavigationViewTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/NavigationViewTests.swift @@ -2,7 +2,7 @@ import XCTest import SwiftUI @testable import ViewInspector -@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) +@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 7.0, *) final class NavigationViewTests: XCTestCase { func testSingleEnclosedView() throws { @@ -56,7 +56,7 @@ final class NavigationViewTests: XCTestCase { // MARK: - View Modifiers -@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) +@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 7.0, *) final class GlobalModifiersForNavigationView: XCTestCase { func testNavigationViewStyle() throws { diff --git a/Tests/ViewInspectorTests/SwiftUI/OutlineGroupTests.swift b/Tests/ViewInspectorTests/SwiftUI/OutlineGroupTests.swift index 2d3366dd..ae413d14 100644 --- a/Tests/ViewInspectorTests/SwiftUI/OutlineGroupTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/OutlineGroupTests.swift @@ -28,6 +28,7 @@ final class OutlineGroupTests: XCTestCase { ) ] + @available(watchOS, unavailable) func testExtractionFromSingleViewContainer() throws { guard #available(iOS 14, tvOS 14, macOS 11.0, *) else { return } let view = AnyView(OutlineGroup(values[0], id: \.testValue, children: \.testChildren) { _ in @@ -36,6 +37,7 @@ final class OutlineGroupTests: XCTestCase { XCTAssertNoThrow(try view.inspect().anyView().outlineGroup()) } + @available(watchOS, unavailable) func testExtractionFromMultipleViewContainer() throws { guard #available(iOS 14, tvOS 14, macOS 11.0, *) else { return } let view = HStack { @@ -48,6 +50,7 @@ final class OutlineGroupTests: XCTestCase { XCTAssertNoThrow(try view.inspect().hStack().outlineGroup(1)) } + @available(watchOS, unavailable) func testSourceDataInspection() throws { guard #available(iOS 14, tvOS 14, macOS 11.0, *) else { return } let view1 = OutlineGroup(values, id: \.testValue, children: \.testChildren) { _ in @@ -64,6 +67,7 @@ final class OutlineGroupTests: XCTestCase { "Type mismatch: TestTree is not Array>") } + @available(watchOS, unavailable) func testLeafInspection() throws { guard #available(iOS 14, tvOS 14, macOS 11.0, *) else { return } let view = OutlineGroup(values[0], id: \.testValue, children: \.testChildren) { element in diff --git a/Tests/ViewInspectorTests/SwiftUI/PopoverTests.swift b/Tests/ViewInspectorTests/SwiftUI/PopoverTests.swift index 33a4e152..56a6dab1 100644 --- a/Tests/ViewInspectorTests/SwiftUI/PopoverTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/PopoverTests.swift @@ -2,9 +2,9 @@ import XCTest import SwiftUI @testable import ViewInspector -#if !os(tvOS) - @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) +@available(tvOS, unavailable) +@available(watchOS, unavailable) final class PopoverTests: XCTestCase { func testBaseView() throws { @@ -101,5 +101,3 @@ final class PopoverAttachmentAnchorTests: XCTestCase { } } } - -#endif diff --git a/Tests/ViewInspectorTests/SwiftUI/ProgressViewTests.swift b/Tests/ViewInspectorTests/SwiftUI/ProgressViewTests.swift index 9027573e..35bd3b06 100644 --- a/Tests/ViewInspectorTests/SwiftUI/ProgressViewTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/ProgressViewTests.swift @@ -6,13 +6,13 @@ import SwiftUI final class ProgressViewTests: XCTestCase { func testExtractionFromSingleViewContainer() throws { - guard #available(iOS 14, macOS 11.0, tvOS 14.0, *) else { return } + guard #available(iOS 14, macOS 11.0, tvOS 14.0, watchOS 7.0, *) else { return } let view = AnyView(ProgressView()) XCTAssertNoThrow(try view.inspect().anyView().progressView()) } func testExtractionFromMultipleViewContainer() throws { - guard #available(iOS 14, macOS 11.0, tvOS 14.0, *) else { return } + guard #available(iOS 14, macOS 11.0, tvOS 14.0, watchOS 7.0, *) else { return } let view = HStack { Text("") ProgressView() @@ -22,7 +22,7 @@ final class ProgressViewTests: XCTestCase { } func testSearch() throws { - guard #available(iOS 14, macOS 11.0, tvOS 14.0, *) else { return } + guard #available(iOS 14, macOS 11.0, tvOS 14.0, watchOS 7.0, *) else { return } let view = AnyView(ProgressView(value: 0, label: { AnyView(Text("abc")) }, currentValueLabel: { Text("xyz") })) XCTAssertEqual(try view.inspect().find(ViewType.ProgressView.self).pathToRoot, @@ -34,7 +34,7 @@ final class ProgressViewTests: XCTestCase { } func testFractionCompletedInspection() throws { - guard #available(iOS 14, macOS 11.0, tvOS 14.0, *) else { return } + guard #available(iOS 14, macOS 11.0, tvOS 14.0, watchOS 7.0, *) else { return } let view1 = ProgressView() let view2 = ProgressView("test", value: 0.35) XCTAssertNil(try view1.inspect().progressView().fractionCompleted()) @@ -42,7 +42,7 @@ final class ProgressViewTests: XCTestCase { } func testProgressInspection() throws { - guard #available(iOS 14, macOS 11.0, tvOS 14.0, *) else { return } + guard #available(iOS 14, macOS 11.0, tvOS 14.0, watchOS 7.0, *) else { return } let progress = Progress(totalUnitCount: 100) progress.completedUnitCount = 10 let view = ProgressView(progress) @@ -52,7 +52,7 @@ final class ProgressViewTests: XCTestCase { } func testLabelViewInspection() throws { - guard #available(iOS 14, macOS 11.0, tvOS 14.0, *) else { return } + guard #available(iOS 14, macOS 11.0, tvOS 14.0, watchOS 7.0, *) else { return } let view = ProgressView(value: 0, label: { HStack { Text("abc") } }, currentValueLabel: { EmptyView() }) let sut = try view.inspect().progressView().labelView().hStack(0).text(0).string() @@ -60,7 +60,7 @@ final class ProgressViewTests: XCTestCase { } func testCurrentValueLabelViewInspection() throws { - guard #available(iOS 14, macOS 11.0, tvOS 14.0, *) else { return } + guard #available(iOS 14, macOS 11.0, tvOS 14.0, watchOS 7.0, *) else { return } let view = ProgressView(value: 0, label: { EmptyView() }, currentValueLabel: { HStack { Text("abc") } }) let sut = try view.inspect().progressView().currentValueLabelView().hStack(0).text(0).string() @@ -68,13 +68,13 @@ final class ProgressViewTests: XCTestCase { } func testProgressViewStyleInspection() throws { - guard #available(iOS 14, macOS 11.0, tvOS 14.0, *) else { return } + guard #available(iOS 14, macOS 11.0, tvOS 14.0, watchOS 7.0, *) else { return } let sut = EmptyView().progressViewStyle(CircularProgressViewStyle()) XCTAssertTrue(try sut.inspect().progressViewStyle() is CircularProgressViewStyle) } func testProgressViewStyleConfiguration() throws { - guard #available(iOS 14, macOS 11.0, tvOS 14.0, *) else { return } + guard #available(iOS 14, macOS 11.0, tvOS 14.0, watchOS 7.0, *) else { return } let sut1 = ProgressViewStyleConfiguration(fractionCompleted: nil) XCTAssertNil(sut1.fractionCompleted) let sut2 = ProgressViewStyleConfiguration(fractionCompleted: 0.9) @@ -82,7 +82,7 @@ final class ProgressViewTests: XCTestCase { } func testCustomProgressViewStyleInspection() throws { - guard #available(iOS 14, macOS 11.0, tvOS 14.0, *) else { return } + guard #available(iOS 14, macOS 11.0, tvOS 14.0, watchOS 7.0, *) else { return } let sut = TestProgressViewStyle() XCTAssertEqual(try sut.inspect(fractionCompleted: nil) .vStack().styleConfigurationLabel(0).brightness(), 3) diff --git a/Tests/ViewInspectorTests/SwiftUI/ScrollViewReaderTests.swift b/Tests/ViewInspectorTests/SwiftUI/ScrollViewReaderTests.swift index c17683bc..af3126a9 100644 --- a/Tests/ViewInspectorTests/SwiftUI/ScrollViewReaderTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/ScrollViewReaderTests.swift @@ -6,13 +6,13 @@ import SwiftUI final class ScrollViewReaderTests: XCTestCase { func testExtractionFromSingleViewContainer() throws { - guard #available(iOS 14, macOS 11.0, tvOS 14.0, *) else { return } + guard #available(iOS 14, macOS 11.0, tvOS 14.0, watchOS 7.0, *) else { return } let view = AnyView(ScrollViewReader { _ in EmptyView() }) XCTAssertNoThrow(try view.inspect().anyView().scrollViewReader()) } func testExtractionFromMultipleViewContainer() throws { - guard #available(iOS 14, macOS 11.0, tvOS 14.0, *) else { return } + guard #available(iOS 14, macOS 11.0, tvOS 14.0, watchOS 7.0, *) else { return } let view = HStack { Text("") ScrollViewReader { _ in EmptyView() } @@ -22,7 +22,7 @@ final class ScrollViewReaderTests: XCTestCase { } func testSearch() throws { - guard #available(iOS 14, macOS 11.0, tvOS 14.0, *) else { return } + guard #available(iOS 14, macOS 11.0, tvOS 14.0, watchOS 7.0, *) else { return } let view = AnyView(ScrollViewReader { _ in Text("abc") }) XCTAssertEqual(try view.inspect().find(ViewType.ScrollViewReader.self).pathToRoot, "anyView().scrollViewReader()") @@ -31,7 +31,7 @@ final class ScrollViewReaderTests: XCTestCase { } func testEnclosedView() throws { - guard #available(iOS 14, macOS 11.0, tvOS 14.0, *) else { return } + guard #available(iOS 14, macOS 11.0, tvOS 14.0, watchOS 7.0, *) else { return } let view = ScrollViewReader { _ in Text("abc") } let value = try view.inspect().scrollViewReader().text().string() XCTAssertEqual(value, "abc") diff --git a/Tests/ViewInspectorTests/SwiftUI/TabViewTests.swift b/Tests/ViewInspectorTests/SwiftUI/TabViewTests.swift index c5a5a1d1..c11549ba 100644 --- a/Tests/ViewInspectorTests/SwiftUI/TabViewTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/TabViewTests.swift @@ -2,7 +2,7 @@ import XCTest import SwiftUI @testable import ViewInspector -@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) +@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 7.0, *) final class TabViewTests: XCTestCase { func testEnclosedView() throws { @@ -71,11 +71,13 @@ final class GlobalModifiersForTabView: XCTestCase { XCTAssertEqual(sut, tag) } + @available(watchOS 7.0, *) func testTabItem() throws { let sut = EmptyView().tabItem { Text("") } XCTAssertNoThrow(try sut.inspect().emptyView()) } + @available(watchOS 7.0, *) func testTabItemInspection() throws { let string = "abc" let tabItem = try EmptyView().tabItem { Text(string).blur(radius: 3) } @@ -85,12 +87,13 @@ final class GlobalModifiersForTabView: XCTestCase { XCTAssertEqual(try sut.blur().radius, 3) } + @available(watchOS 7.0, *) func testTabItemSearch() throws { let view = EmptyView().tabItem { Text("abc") } XCTAssertNoThrow(try view.inspect().find(text: "abc")) } - #if !os(macOS) && !targetEnvironment(macCatalyst) + #if !os(macOS) && !targetEnvironment(macCatalyst) && !os(watchOS) func testTabViewStyleInspection() throws { guard #available(iOS 14, macOS 11.0, tvOS 14.0, *) else { return } let style = PageTabViewStyle(indexDisplayMode: .never) @@ -112,6 +115,7 @@ final class GlobalModifiersForTabView: XCTestCase { #endif @available(macOS, unavailable) + @available(watchOS, unavailable) func testIndexViewStyleInspection() throws { guard #available(iOS 14, tvOS 14, *) else { return } let sut = EmptyView().indexViewStyle(PageIndexViewStyle()) diff --git a/Tests/ViewInspectorTests/SwiftUI/TextAttributesTests.swift b/Tests/ViewInspectorTests/SwiftUI/TextAttributesTests.swift index 43b1c13d..03e4c61f 100644 --- a/Tests/ViewInspectorTests/SwiftUI/TextAttributesTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/TextAttributesTests.swift @@ -37,7 +37,7 @@ final class TextAttributesTests: XCTestCase { } func testFontAttribute() throws { - let system = Font.system(size: 24, weight: .semibold, design: .monospaced) + let system = Font.system(size: 24, weight: .semibold, design: .rounded) let view1 = Text("Test").kerning(2).font(system) let sut1 = try view1.inspect().text().attributes() XCTAssertEqual(try sut1.font(), system) @@ -190,7 +190,7 @@ final class FontAttributesTests: XCTestCase { func testSizeAttribute() throws { let sut1 = Font.custom("abc", size: 13) - let sut2 = Font.system(size: 15, weight: .bold, design: .monospaced) + let sut2 = Font.system(size: 15, weight: .bold, design: .rounded) let sut3 = Font.headline XCTAssertEqual(try sut1.size(), 13) XCTAssertFalse(sut1.isFixedSize()) @@ -199,7 +199,7 @@ final class FontAttributesTests: XCTestCase { XCTAssertThrows(try sut3.size(), "Font does not have 'size' attribute") XCTAssertFalse(sut3.isFixedSize()) - if #available(iOS 14.0, macOS 11.0, tvOS 14.0, *) { + if #available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *) { let sut4 = Font.custom("abc", fixedSize: 16) XCTAssertEqual(try sut4.size(), 16) XCTAssertTrue(sut4.isFixedSize()) @@ -223,10 +223,10 @@ final class FontAttributesTests: XCTestCase { } func testDesignAttribute() throws { - let sut1 = Font.system(size: 14, design: .monospaced) + let sut1 = Font.system(size: 14, design: .rounded) let sut2 = Font.system(size: 13) let sut3 = Font.custom("abc", size: 14) - XCTAssertEqual(try sut1.design(), .monospaced) + XCTAssertEqual(try sut1.design(), .rounded) XCTAssertEqual(try sut2.design(), .`default`) XCTAssertThrows(try sut3.design(), "Font does not have 'design' attribute") } @@ -242,7 +242,7 @@ final class FontAttributesTests: XCTestCase { } else { XCTAssertThrows(try sut3.style(), "Font does not have 'style' attribute") } - if #available(iOS 14.0, macOS 11.0, tvOS 14.0, *) { + if #available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *) { let sut4 = Font.custom("abc", size: 14, relativeTo: .caption2) XCTAssertEqual(try sut4.style(), .caption2) } diff --git a/Tests/ViewInspectorTests/SwiftUI/TextEditorTests.swift b/Tests/ViewInspectorTests/SwiftUI/TextEditorTests.swift index f3ba47d3..f18a35e6 100644 --- a/Tests/ViewInspectorTests/SwiftUI/TextEditorTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/TextEditorTests.swift @@ -4,17 +4,18 @@ import SwiftUI @available(iOS 13.0, macOS 10.15, *) @available(tvOS, unavailable) +@available(watchOS, unavailable) final class TextEditorTests: XCTestCase { func testExtractionFromSingleViewContainer() throws { - guard #available(iOS 14, tvOS 14, macOS 11.0, *) else { return } + guard #available(iOS 14, tvOS 14, macOS 11.0, watchOS 7.0, *) else { return } let binding = Binding(wrappedValue: "") let view = AnyView(TextEditor(text: binding)) XCTAssertNoThrow(try view.inspect().anyView().textEditor()) } func testExtractionFromMultipleViewContainer() throws { - guard #available(iOS 14, tvOS 14, macOS 11.0, *) else { return } + guard #available(iOS 14, tvOS 14, macOS 11.0, watchOS 7.0, *) else { return } let binding = Binding(wrappedValue: "") let view = HStack { Text("Test") @@ -24,7 +25,7 @@ final class TextEditorTests: XCTestCase { } func testSearch() throws { - guard #available(iOS 14, tvOS 14, macOS 11.0, *) else { return } + guard #available(iOS 14, tvOS 14, macOS 11.0, watchOS 7.0, *) else { return } let binding = Binding(wrappedValue: "") let view = AnyView(TextEditor(text: binding)) XCTAssertEqual(try view.inspect().find(ViewType.TextEditor.self).pathToRoot, @@ -32,7 +33,7 @@ final class TextEditorTests: XCTestCase { } func testInput() throws { - guard #available(iOS 14, tvOS 14, macOS 11.0, *) else { return } + guard #available(iOS 14, tvOS 14, macOS 11.0, watchOS 7.0, *) else { return } let binding = Binding(wrappedValue: "123") let view = TextEditor(text: binding) let sut = try view.inspect().textEditor() @@ -42,7 +43,7 @@ final class TextEditorTests: XCTestCase { } func testSetInputWhenDisabled() throws { - guard #available(iOS 14, tvOS 14, macOS 11.0, *) else { return } + guard #available(iOS 14, tvOS 14, macOS 11.0, watchOS 7.0, *) else { return } let binding = Binding(wrappedValue: "123") let view = TextEditor(text: binding).disabled(true) let sut = try view.inspect().textEditor() diff --git a/Tests/ViewInspectorTests/SwiftUI/TextTests.swift b/Tests/ViewInspectorTests/SwiftUI/TextTests.swift index c639591c..1fa3a8a9 100644 --- a/Tests/ViewInspectorTests/SwiftUI/TextTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/TextTests.swift @@ -91,7 +91,7 @@ final class TextTests: XCTestCase { } func testObjectInitialization() throws { - guard #available(iOS 14.0, macOS 11.0, tvOS 14.0, *) + guard #available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *) else { return } let formatter = NumberFormatter() formatter.numberStyle = .decimal @@ -118,7 +118,7 @@ final class TextTests: XCTestCase { } func testReferenceConvertibleInitialization() throws { - guard #available(iOS 14.0, macOS 11.0, tvOS 14.0, *) + guard #available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *) else { return } let formatter = DateFormatter() formatter.dateFormat = "yyyy-mm-ss" @@ -138,7 +138,7 @@ final class TextTests: XCTestCase { } func testDateStyleInitialization() throws { - guard #available(iOS 14.0, macOS 11.0, tvOS 14.0, *) + guard #available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *) else { return } let date = Date(timeIntervalSinceReferenceDate: 123) let sut = Text(date, style: .timer) @@ -147,7 +147,7 @@ final class TextTests: XCTestCase { } func testDateIntervalInitialization() throws { - guard #available(iOS 14.0, macOS 11.0, tvOS 14.0, *) + guard #available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *) else { return } let date1 = Date(timeIntervalSinceReferenceDate: 123) let date2 = Date(timeIntervalSinceReferenceDate: 123456) @@ -161,7 +161,7 @@ final class TextTests: XCTestCase { } func testTextInterpolation() throws { - guard #available(iOS 14.0, macOS 11.0, tvOS 14.0, *) + guard #available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *) else { return } let sut = Text("abc \(Text("xyz").bold()) \(Text("qwe"))") let value = try sut.inspect().text().string() @@ -169,7 +169,7 @@ final class TextTests: XCTestCase { } func testImageInterpolation() throws { - guard #available(iOS 14.0, macOS 11.0, tvOS 14.0, *) + guard #available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *) else { return } let sut = Text("abc \(Image("test"))") let value = try sut.inspect().text().string() @@ -189,7 +189,7 @@ final class TextTests: XCTestCase { } func testImageExtraction() throws { - guard #available(iOS 14.0, macOS 11.0, tvOS 14.0, *) + guard #available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *) else { return } let image1 = Image("abc").antialiased(true) let image2 = Image("def").resizable() diff --git a/Tests/ViewInspectorTests/SwiftUI/TreeViewTests.swift b/Tests/ViewInspectorTests/SwiftUI/TreeViewTests.swift index 4e2a55c7..08492c93 100644 --- a/Tests/ViewInspectorTests/SwiftUI/TreeViewTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/TreeViewTests.swift @@ -2,9 +2,8 @@ import XCTest import SwiftUI @testable import ViewInspector -#if !os(tvOS) - -@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) +@available(iOS 13.0, macOS 10.15, *) +@available(tvOS, unavailable) final class TreeViewTests: XCTestCase { func testEnclosedView() throws { @@ -25,7 +24,8 @@ final class TreeViewTests: XCTestCase { // MARK: - View Modifiers -@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) +@available(iOS 13.0, macOS 10.15, *) +@available(tvOS, unavailable) final class GlobalModifiersForTreeView: XCTestCase { func testContextMenu() throws { @@ -33,5 +33,3 @@ final class GlobalModifiersForTreeView: XCTestCase { XCTAssertNoThrow(try sut.inspect().emptyView()) } } - -#endif diff --git a/Tests/ViewInspectorTests/SwiftUI/VStackTests.swift b/Tests/ViewInspectorTests/SwiftUI/VStackTests.swift index 07285d21..84a96bf5 100644 --- a/Tests/ViewInspectorTests/SwiftUI/VStackTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/VStackTests.swift @@ -71,7 +71,7 @@ final class VStackTests: XCTestCase { } func testSpacingInspection() throws { - guard #available(iOS 14, macOS 11.0, tvOS 14.0, *) else { return } + guard #available(iOS 14, macOS 11.0, tvOS 14.0, watchOS 7.0, *) else { return } let view = VStack(spacing: 6) { Text("") } diff --git a/Tests/ViewInspectorTests/ViewHostingTests.swift b/Tests/ViewInspectorTests/ViewHostingTests.swift index 05bfd861..58dc10f2 100644 --- a/Tests/ViewInspectorTests/ViewHostingTests.swift +++ b/Tests/ViewInspectorTests/ViewHostingTests.swift @@ -78,7 +78,7 @@ final class ViewHostingTests: XCTestCase { wait(for: [exp], timeout: 0.2) } } -#else +#elseif os(iOS) || os(tvOS) @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) final class ViewHostingTests: XCTestCase { @@ -191,7 +191,8 @@ extension NSTestView { } } } -#else +#elseif os(iOS) || os(tvOS) + @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) private struct UITestView: UIViewRepresentable, Inspectable { @@ -257,7 +258,7 @@ private struct NSTestVC: NSViewControllerRepresentable, Inspectable { func updateNSViewController(_ nsViewController: TestVC, context: UpdateContext) { } } -#else +#elseif os(iOS) || os(tvOS) @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) private struct UITestVC: UIViewControllerRepresentable, Inspectable { diff --git a/Tests/ViewInspectorTests/ViewModifiers/AccessibilityModifiersTests.swift b/Tests/ViewInspectorTests/ViewModifiers/AccessibilityModifiersTests.swift index a3a80c18..7d81cadd 100644 --- a/Tests/ViewInspectorTests/ViewModifiers/AccessibilityModifiersTests.swift +++ b/Tests/ViewInspectorTests/ViewModifiers/AccessibilityModifiersTests.swift @@ -73,6 +73,7 @@ final class ViewAccessibilityTests: XCTestCase { @available(iOS, deprecated, introduced: 13.0) @available(tvOS, deprecated, introduced: 13.0) @available(macOS, deprecated, introduced: 10.15) + @available(watchOS, deprecated, introduced: 6) func testAccessibilitySelectionIdentifier() throws { guard #available(iOS 13.2, macOS 10.17, tvOS 13.2, *) else { return } let sut = EmptyView().accessibility(selectionIdentifier: "") @@ -82,6 +83,7 @@ final class ViewAccessibilityTests: XCTestCase { @available(iOS, deprecated, introduced: 13.0) @available(tvOS, deprecated, introduced: 13.0) @available(macOS, deprecated, introduced: 10.15) + @available(watchOS, deprecated, introduced: 6) func testAccessibilitySelectionIdentifierInspection() throws { guard #available(iOS 13.2, macOS 10.17, tvOS 13.2, *) else { return } let string = "abc" diff --git a/Tests/ViewInspectorTests/ViewModifiers/EventsModifiersTests.swift b/Tests/ViewInspectorTests/ViewModifiers/EventsModifiersTests.swift index 169d71fb..acd32144 100644 --- a/Tests/ViewInspectorTests/ViewModifiers/EventsModifiersTests.swift +++ b/Tests/ViewInspectorTests/ViewModifiers/EventsModifiersTests.swift @@ -38,7 +38,7 @@ final class ViewEventsTests: XCTestCase { } func testOnChange() throws { - guard #available(iOS 14.0, macOS 11.0, tvOS 14.0, *) + guard #available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *) else { return } let val = "" let sut = EmptyView().onChange(of: val) { value in } @@ -46,7 +46,7 @@ final class ViewEventsTests: XCTestCase { } func testOnChangeInspection() throws { - guard #available(iOS 14.0, macOS 11.0, tvOS 14.0, *) + guard #available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *) else { return } let val = "initial" let exp = XCTestExpectation(description: #function) @@ -60,7 +60,7 @@ final class ViewEventsTests: XCTestCase { } func testMultipleOnChangeModifiersSameTypeCallFirst() throws { - guard #available(iOS 14.0, macOS 11.0, tvOS 14.0, *) + guard #available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *) else { return } var val = "initial" let other = "" @@ -78,7 +78,7 @@ final class ViewEventsTests: XCTestCase { } func testMultipleOnChangeModifiersSameTypeCallByIndex() throws { - guard #available(iOS 14.0, macOS 11.0, tvOS 14.0, *) + guard #available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *) else { return } var val = "initial" let other = "" @@ -98,7 +98,7 @@ final class ViewEventsTests: XCTestCase { } func testMultipleOnChangeModifiersDifferentTypes() throws { - guard #available(iOS 14.0, macOS 11.0, tvOS 14.0, *) + guard #available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *) else { return } let exp1 = XCTestExpectation(description: "onChange1") let exp2 = XCTestExpectation(description: "onChange2") diff --git a/Tests/ViewInspectorTests/ViewModifiers/TextInputModifiersTests.swift b/Tests/ViewInspectorTests/ViewModifiers/TextInputModifiersTests.swift index 3503556b..398032e4 100644 --- a/Tests/ViewInspectorTests/ViewModifiers/TextInputModifiersTests.swift +++ b/Tests/ViewInspectorTests/ViewModifiers/TextInputModifiersTests.swift @@ -7,12 +7,14 @@ import SwiftUI @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) final class TextInputModifiersTests: XCTestCase { - #if !os(macOS) + #if os(iOS) || os(tvOS) || os(watchOS) func testTextContentType() throws { let sut = EmptyView().textContentType(.emailAddress) XCTAssertNoThrow(try sut.inspect().emptyView()) } + #endif + #if os(iOS) || os(tvOS) func testTextContentTypeInspection() throws { let sut = AnyView(EmptyView()).textContentType(.emailAddress) XCTAssertEqual(try sut.inspect().anyView().textContentType(), .emailAddress) @@ -136,11 +138,13 @@ final class TextInputModifiersTests: XCTestCase { XCTAssertTrue(try sut.inspect().anyView().emptyView().allowsTightening()) } + @available(watchOS, unavailable) func testDisableAutocorrection() throws { let sut = EmptyView().disableAutocorrection(false) XCTAssertNoThrow(try sut.inspect().emptyView()) } + @available(watchOS, unavailable) func testDisableAutocorrectionInspection() throws { let sut = AnyView(EmptyView()).disableAutocorrection(false) XCTAssertEqual(try sut.inspect().anyView().disableAutocorrection(), false) diff --git a/Tests/ViewInspectorTests/ViewModifiers/TransitiveModifiersTests.swift b/Tests/ViewInspectorTests/ViewModifiers/TransitiveModifiersTests.swift index fac3d543..7c8eac03 100644 --- a/Tests/ViewInspectorTests/ViewModifiers/TransitiveModifiersTests.swift +++ b/Tests/ViewInspectorTests/ViewModifiers/TransitiveModifiersTests.swift @@ -23,6 +23,7 @@ final class TransitiveModifiersTests: XCTestCase { } @available(tvOS, unavailable) + @available(watchOS, unavailable) func testFlipsRightToLeftInheritance() throws { let sut = try FlipsRightToLeftTestView().inspect() if #available(iOS 14.0, *) { @@ -65,6 +66,7 @@ final class TransitiveModifiersTests: XCTestCase { } @available(tvOS, unavailable) + @available(watchOS, unavailable) func testLabelsHiddenInheritance() throws { let sut = try TestLabelsHiddenView().inspect() let text1 = try sut.find(text: "1") @@ -111,6 +113,7 @@ private struct TestDisabledView: View, Inspectable { @available(iOS 13.0, macOS 10.15, *) @available(tvOS, unavailable) +@available(watchOS, unavailable) private struct FlipsRightToLeftTestView: View, Inspectable { var body: some View { VStack { @@ -160,6 +163,7 @@ private struct AllowsHitTestingTestView: View, Inspectable { @available(iOS 13.0, macOS 10.15, *) @available(tvOS, unavailable) +@available(watchOS, unavailable) private struct TestLabelsHiddenView: View, Inspectable { var body: some View { VStack { diff --git a/Tests/ViewInspectorTests/ViewSearchTests.swift b/Tests/ViewInspectorTests/ViewSearchTests.swift index 5bd1cdcd..865f91c2 100644 --- a/Tests/ViewInspectorTests/ViewSearchTests.swift +++ b/Tests/ViewInspectorTests/ViewSearchTests.swift @@ -71,7 +71,7 @@ private struct Test { Text("empty") } } - @available(iOS 14.0, macOS 11.0, tvOS 14.0, *) + @available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *) struct ConflictingViewTypeNamesStyle: ButtonStyle { public func makeBody(configuration: Configuration) -> some View { Group { @@ -225,7 +225,7 @@ final class ViewSearchTests: XCTestCase { } func testConflictingViewTypeNames() throws { - guard #available(iOS 14.0, macOS 11.0, tvOS 14.0, *) else { return } + guard #available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *) else { return } let style = Test.ConflictingViewTypeNamesStyle() let sut = try style.inspect(isPressed: true) XCTAssertEqual(try sut.find(text: "empty").pathToRoot, diff --git a/ViewInspector.xcodeproj/project.pbxproj b/ViewInspector.xcodeproj/project.pbxproj index 5a5f4d8e..62d9cea7 100644 --- a/ViewInspector.xcodeproj/project.pbxproj +++ b/ViewInspector.xcodeproj/project.pbxproj @@ -40,6 +40,7 @@ 52A4A7642621F4AE0063E00B /* Overlay.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52A4A7632621F4AE0063E00B /* Overlay.swift */; }; 52A5CA0425E1139E00773CF5 /* EnvironmentModifiers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52A5CA0325E1139E00773CF5 /* EnvironmentModifiers.swift */; }; 52D37480262B1F0C00B1BFBA /* NestedModifiersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52D3747F262B1F0C00B1BFBA /* NestedModifiersTests.swift */; }; + 52E55CF826C2C18B00A266B9 /* ViewHostingProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52E55CF726C2C18B00A266B9 /* ViewHostingProxy.swift */; }; 52F356AA267692D100695E43 /* MapAnnotation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52F356A9267692D100695E43 /* MapAnnotation.swift */; }; 52F356AC2676940A00695E43 /* MapAnnotationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52F356AB2676940A00695E43 /* MapAnnotationTests.swift */; }; 79069A6B238E8490000F6B58 /* OptionalContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 79069A6A238E8490000F6B58 /* OptionalContent.swift */; }; @@ -281,6 +282,7 @@ 52A4A7632621F4AE0063E00B /* Overlay.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Overlay.swift; sourceTree = ""; }; 52A5CA0325E1139E00773CF5 /* EnvironmentModifiers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EnvironmentModifiers.swift; sourceTree = ""; }; 52D3747F262B1F0C00B1BFBA /* NestedModifiersTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NestedModifiersTests.swift; sourceTree = ""; }; + 52E55CF726C2C18B00A266B9 /* ViewHostingProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewHostingProxy.swift; sourceTree = ""; }; 52F356A9267692D100695E43 /* MapAnnotation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapAnnotation.swift; sourceTree = ""; }; 52F356AB2676940A00695E43 /* MapAnnotationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapAnnotationTests.swift; sourceTree = ""; }; 79069A6A238E8490000F6B58 /* OptionalContent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OptionalContent.swift; sourceTree = ""; }; @@ -573,6 +575,7 @@ F64105C3257BF9A70033D82D /* ViewSearch.swift */, F660849A2594AA6700AF59A2 /* ViewSearchIndex.swift */, F6D58B9223C4A0F3000CEE3B /* ViewHosting.swift */, + 52E55CF726C2C18B00A266B9 /* ViewHostingProxy.swift */, F68108A423A5833D00B32145 /* Modifiers */, F60EEBBD2382EED0007DB53A /* SwiftUI */, ); @@ -978,6 +981,7 @@ F63E926A249FCF92005861F0 /* TransformingModifiers.swift in Sources */, F6F08E6D23A2A9D4001F04DF /* EnvironmentReaderView.swift in Sources */, F6119FD62549EECC0000C54A /* Label.swift in Sources */, + 52E55CF826C2C18B00A266B9 /* ViewHostingProxy.swift in Sources */, F6DFD88423830E9F0028E84D /* List.swift in Sources */, CDA84478262B6C3E00C56C98 /* Gesture.swift in Sources */, F6DFD880238303AF0028E84D /* NavigationView.swift in Sources */, From 29e720804f19de50eecae0245f70fd58acb3abea Mon Sep 17 00:00:00 2001 From: Alexey Naumov Date: Sat, 14 Aug 2021 01:47:51 +0300 Subject: [PATCH 08/99] Add watchOS platform to package --- Package.swift | 2 +- ViewInspector.podspec | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Package.swift b/Package.swift index b9dd8548..58e05143 100644 --- a/Package.swift +++ b/Package.swift @@ -7,7 +7,7 @@ let package = Package( name: "ViewInspector", defaultLocalization: "en", platforms: [ - .macOS(.v10_15), .iOS(.v11), .tvOS(.v13) + .macOS(.v10_15), .iOS(.v11), .tvOS(.v13), .watchOS(.v6) ], products: [ .library( diff --git a/ViewInspector.podspec b/ViewInspector.podspec index be5db423..464ef92b 100644 --- a/ViewInspector.podspec +++ b/ViewInspector.podspec @@ -11,6 +11,7 @@ Pod::Spec.new do |s| s.ios.deployment_target = '13.0' s.osx.deployment_target = '10.15' #s.tvos.deployment_target = '13.0' + #s.watchos.deployment_target = '6.0' s.swift_version = '5.0' s.framework = 'XCTest' s.source = { :git => "https://github.com/nalexn/ViewInspector.git", :tag => "#{s.version}" } From c62ff5392f0381cb7fc1d6c7d2e5b2b7eace976d Mon Sep 17 00:00:00 2001 From: Alexey Naumov Date: Sat, 14 Aug 2021 02:10:25 +0300 Subject: [PATCH 09/99] Setup a test watchOS project --- .watchOS/watchOS-App/App-Info.plist | 31 + .watchOS/watchOS-Ext/Ext-Info.plist | 36 ++ .watchOS/watchOS-Ext/watchOSApp.swift | 12 + .watchOS/watchOS-Tests/Tests-Info.plist | 22 + .watchOS/watchOS-Tests/watchOS_Tests.swift | 10 + .watchOS/watchOS.xcodeproj/project.pbxproj | 641 +++++++++++++++++++++ 6 files changed, 752 insertions(+) create mode 100644 .watchOS/watchOS-App/App-Info.plist create mode 100644 .watchOS/watchOS-Ext/Ext-Info.plist create mode 100644 .watchOS/watchOS-Ext/watchOSApp.swift create mode 100644 .watchOS/watchOS-Tests/Tests-Info.plist create mode 100644 .watchOS/watchOS-Tests/watchOS_Tests.swift create mode 100644 .watchOS/watchOS.xcodeproj/project.pbxproj diff --git a/.watchOS/watchOS-App/App-Info.plist b/.watchOS/watchOS-App/App-Info.plist new file mode 100644 index 00000000..7b67af9c --- /dev/null +++ b/.watchOS/watchOS-App/App-Info.plist @@ -0,0 +1,31 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + watchOS-App + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + + WKWatchKitApp + + + diff --git a/.watchOS/watchOS-Ext/Ext-Info.plist b/.watchOS/watchOS-Ext/Ext-Info.plist new file mode 100644 index 00000000..a12d981d --- /dev/null +++ b/.watchOS/watchOS-Ext/Ext-Info.plist @@ -0,0 +1,36 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + watchOS-Ext + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + NSExtension + + NSExtensionAttributes + + WKAppBundleIdentifier + com.viewinspector.watchOS.watchkitapp + + NSExtensionPointIdentifier + com.apple.watchkit + + WKWatchOnly + + + diff --git a/.watchOS/watchOS-Ext/watchOSApp.swift b/.watchOS/watchOS-Ext/watchOSApp.swift new file mode 100644 index 00000000..23fbb9ac --- /dev/null +++ b/.watchOS/watchOS-Ext/watchOSApp.swift @@ -0,0 +1,12 @@ +import SwiftUI + +@main +struct watchOSApp: App { + var body: some Scene { + WindowGroup { + NavigationView { + Text("Hi") + } + } + } +} diff --git a/.watchOS/watchOS-Tests/Tests-Info.plist b/.watchOS/watchOS-Tests/Tests-Info.plist new file mode 100644 index 00000000..64d65ca4 --- /dev/null +++ b/.watchOS/watchOS-Tests/Tests-Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/.watchOS/watchOS-Tests/watchOS_Tests.swift b/.watchOS/watchOS-Tests/watchOS_Tests.swift new file mode 100644 index 00000000..fc027db5 --- /dev/null +++ b/.watchOS/watchOS-Tests/watchOS_Tests.swift @@ -0,0 +1,10 @@ +import XCTest +import SwiftUI +@testable import watchOS_Ext + +class watchOS_Tests: XCTestCase { + + func testExample() throws { + + } +} diff --git a/.watchOS/watchOS.xcodeproj/project.pbxproj b/.watchOS/watchOS.xcodeproj/project.pbxproj new file mode 100644 index 00000000..49dbc82c --- /dev/null +++ b/.watchOS/watchOS.xcodeproj/project.pbxproj @@ -0,0 +1,641 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 50; + objects = { + +/* Begin PBXBuildFile section */ + 5216473E26C7343E00B3EC2B /* watchOS_Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5216473D26C7343E00B3EC2B /* watchOS_Tests.swift */; }; + 52E3258F26C72E7800CCE47E /* watchOS-App.app in Embed Watch Content */ = {isa = PBXBuildFile; fileRef = 52E3258E26C72E7800CCE47E /* watchOS-App.app */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; + 52E3259B26C72E7900CCE47E /* watchOS-Ext.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 52E3259A26C72E7900CCE47E /* watchOS-Ext.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; + 52E325A226C72E7900CCE47E /* watchOSApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52E325A126C72E7900CCE47E /* watchOSApp.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 5216474026C7343E00B3EC2B /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 52E3258426C72E7800CCE47E /* Project object */; + proxyType = 1; + remoteGlobalIDString = 52E3259926C72E7900CCE47E; + remoteInfo = "watchOS-Ext"; + }; + 52E3259026C72E7800CCE47E /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 52E3258426C72E7800CCE47E /* Project object */; + proxyType = 1; + remoteGlobalIDString = 52E3258D26C72E7800CCE47E; + remoteInfo = "watchOS WatchKit App"; + }; + 52E3259C26C72E7900CCE47E /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 52E3258426C72E7800CCE47E /* Project object */; + proxyType = 1; + remoteGlobalIDString = 52E3259926C72E7900CCE47E; + remoteInfo = "watchOS WatchKit Extension"; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 52E325B026C72E7900CCE47E /* Embed App Extensions */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 13; + files = ( + 52E3259B26C72E7900CCE47E /* watchOS-Ext.appex in Embed App Extensions */, + ); + name = "Embed App Extensions"; + runOnlyForDeploymentPostprocessing = 0; + }; + 52E325B426C72E7900CCE47E /* Embed Watch Content */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = "$(CONTENTS_FOLDER_PATH)/Watch"; + dstSubfolderSpec = 16; + files = ( + 52E3258F26C72E7800CCE47E /* watchOS-App.app in Embed Watch Content */, + ); + name = "Embed Watch Content"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 5216473B26C7343E00B3EC2B /* watchOS-Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "watchOS-Tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; + 5216473D26C7343E00B3EC2B /* watchOS_Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = watchOS_Tests.swift; sourceTree = ""; }; + 5216473F26C7343E00B3EC2B /* Tests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Tests-Info.plist"; sourceTree = ""; }; + 52E3258A26C72E7800CCE47E /* watchOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = watchOS.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 52E3258E26C72E7800CCE47E /* watchOS-App.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "watchOS-App.app"; sourceTree = BUILT_PRODUCTS_DIR; }; + 52E3259526C72E7900CCE47E /* App-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "App-Info.plist"; sourceTree = ""; }; + 52E3259A26C72E7900CCE47E /* watchOS-Ext.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = "watchOS-Ext.appex"; sourceTree = BUILT_PRODUCTS_DIR; }; + 52E325A126C72E7900CCE47E /* watchOSApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = watchOSApp.swift; sourceTree = ""; }; + 52E325AA26C72E7900CCE47E /* Ext-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Ext-Info.plist"; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 5216473826C7343E00B3EC2B /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 52E3259726C72E7900CCE47E /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 5216473C26C7343E00B3EC2B /* watchOS-Tests */ = { + isa = PBXGroup; + children = ( + 5216473D26C7343E00B3EC2B /* watchOS_Tests.swift */, + 5216473F26C7343E00B3EC2B /* Tests-Info.plist */, + ); + path = "watchOS-Tests"; + sourceTree = ""; + }; + 52E3258326C72E7800CCE47E = { + isa = PBXGroup; + children = ( + 52E3259226C72E7800CCE47E /* watchOS-App */, + 52E3259E26C72E7900CCE47E /* watchOS-Ext */, + 5216473C26C7343E00B3EC2B /* watchOS-Tests */, + 52E3258B26C72E7800CCE47E /* Products */, + ); + sourceTree = ""; + }; + 52E3258B26C72E7800CCE47E /* Products */ = { + isa = PBXGroup; + children = ( + 52E3258A26C72E7800CCE47E /* watchOS.app */, + 52E3258E26C72E7800CCE47E /* watchOS-App.app */, + 52E3259A26C72E7900CCE47E /* watchOS-Ext.appex */, + 5216473B26C7343E00B3EC2B /* watchOS-Tests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 52E3259226C72E7800CCE47E /* watchOS-App */ = { + isa = PBXGroup; + children = ( + 52E3259526C72E7900CCE47E /* App-Info.plist */, + ); + path = "watchOS-App"; + sourceTree = ""; + }; + 52E3259E26C72E7900CCE47E /* watchOS-Ext */ = { + isa = PBXGroup; + children = ( + 52E325A126C72E7900CCE47E /* watchOSApp.swift */, + 52E325AA26C72E7900CCE47E /* Ext-Info.plist */, + ); + path = "watchOS-Ext"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 5216473A26C7343E00B3EC2B /* watchOS-Tests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5216474426C7343E00B3EC2B /* Build configuration list for PBXNativeTarget "watchOS-Tests" */; + buildPhases = ( + 5216473726C7343E00B3EC2B /* Sources */, + 5216473826C7343E00B3EC2B /* Frameworks */, + 5216473926C7343E00B3EC2B /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 5216474126C7343E00B3EC2B /* PBXTargetDependency */, + ); + name = "watchOS-Tests"; + productName = "watchOS-Tests"; + productReference = 5216473B26C7343E00B3EC2B /* watchOS-Tests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 52E3258926C72E7800CCE47E /* watchOS */ = { + isa = PBXNativeTarget; + buildConfigurationList = 52E325B526C72E7900CCE47E /* Build configuration list for PBXNativeTarget "watchOS" */; + buildPhases = ( + 52E3258826C72E7800CCE47E /* Resources */, + 52E325B426C72E7900CCE47E /* Embed Watch Content */, + ); + buildRules = ( + ); + dependencies = ( + 52E3259126C72E7800CCE47E /* PBXTargetDependency */, + ); + name = watchOS; + productName = watchOS; + productReference = 52E3258A26C72E7800CCE47E /* watchOS.app */; + productType = "com.apple.product-type.application.watchapp2-container"; + }; + 52E3258D26C72E7800CCE47E /* watchOS-App */ = { + isa = PBXNativeTarget; + buildConfigurationList = 52E325B126C72E7900CCE47E /* Build configuration list for PBXNativeTarget "watchOS-App" */; + buildPhases = ( + 52E3258C26C72E7800CCE47E /* Resources */, + 52E325B026C72E7900CCE47E /* Embed App Extensions */, + ); + buildRules = ( + ); + dependencies = ( + 52E3259D26C72E7900CCE47E /* PBXTargetDependency */, + ); + name = "watchOS-App"; + productName = "watchOS WatchKit App"; + productReference = 52E3258E26C72E7800CCE47E /* watchOS-App.app */; + productType = "com.apple.product-type.application.watchapp2"; + }; + 52E3259926C72E7900CCE47E /* watchOS-Ext */ = { + isa = PBXNativeTarget; + buildConfigurationList = 52E325AD26C72E7900CCE47E /* Build configuration list for PBXNativeTarget "watchOS-Ext" */; + buildPhases = ( + 52E3259626C72E7900CCE47E /* Sources */, + 52E3259726C72E7900CCE47E /* Frameworks */, + 52E3259826C72E7900CCE47E /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "watchOS-Ext"; + productName = "watchOS WatchKit Extension"; + productReference = 52E3259A26C72E7900CCE47E /* watchOS-Ext.appex */; + productType = "com.apple.product-type.watchkit2-extension"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 52E3258426C72E7800CCE47E /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 1250; + LastUpgradeCheck = 1250; + TargetAttributes = { + 5216473A26C7343E00B3EC2B = { + CreatedOnToolsVersion = 12.5.1; + TestTargetID = 52E3259926C72E7900CCE47E; + }; + 52E3258926C72E7800CCE47E = { + CreatedOnToolsVersion = 12.5.1; + }; + 52E3258D26C72E7800CCE47E = { + CreatedOnToolsVersion = 12.5.1; + }; + 52E3259926C72E7900CCE47E = { + CreatedOnToolsVersion = 12.5.1; + }; + }; + }; + buildConfigurationList = 52E3258726C72E7800CCE47E /* Build configuration list for PBXProject "watchOS" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 52E3258326C72E7800CCE47E; + productRefGroup = 52E3258B26C72E7800CCE47E /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 52E3258926C72E7800CCE47E /* watchOS */, + 52E3258D26C72E7800CCE47E /* watchOS-App */, + 52E3259926C72E7900CCE47E /* watchOS-Ext */, + 5216473A26C7343E00B3EC2B /* watchOS-Tests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 5216473926C7343E00B3EC2B /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 52E3258826C72E7800CCE47E /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 52E3258C26C72E7800CCE47E /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 52E3259826C72E7900CCE47E /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 5216473726C7343E00B3EC2B /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5216473E26C7343E00B3EC2B /* watchOS_Tests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 52E3259626C72E7900CCE47E /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 52E325A226C72E7900CCE47E /* watchOSApp.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 5216474126C7343E00B3EC2B /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 52E3259926C72E7900CCE47E /* watchOS-Ext */; + targetProxy = 5216474026C7343E00B3EC2B /* PBXContainerItemProxy */; + }; + 52E3259126C72E7800CCE47E /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 52E3258D26C72E7800CCE47E /* watchOS-App */; + targetProxy = 52E3259026C72E7800CCE47E /* PBXContainerItemProxy */; + }; + 52E3259D26C72E7900CCE47E /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 52E3259926C72E7900CCE47E /* watchOS-Ext */; + targetProxy = 52E3259C26C72E7900CCE47E /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin XCBuildConfiguration section */ + 5216474226C7343E00B3EC2B /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + INFOPLIST_FILE = "watchOS-Tests/Tests-Info.plist"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = "com.viewinspector.watchOS-Tests"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = watchos; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = 4; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/watchOS-Ext.appex/watchOS-Ext"; + WATCHOS_DEPLOYMENT_TARGET = 7.4; + }; + name = Debug; + }; + 5216474326C7343E00B3EC2B /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + INFOPLIST_FILE = "watchOS-Tests/Tests-Info.plist"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = "com.viewinspector.watchOS-Tests"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = watchos; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = 4; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/watchOS-Ext.appex/watchOS-Ext"; + WATCHOS_DEPLOYMENT_TARGET = 7.4; + }; + name = Release; + }; + 52E325AB26C72E7900CCE47E /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 52E325AC26C72E7900CCE47E /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 52E325AE26C72E7900CCE47E /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + ENABLE_PREVIEWS = YES; + INFOPLIST_FILE = "$(SRCROOT)/watchOS-Ext/Ext-Info.plist"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@executable_path/../../Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.viewinspector.watchOS.watchkitapp.watchkitextension; + PRODUCT_NAME = "${TARGET_NAME}"; + SDKROOT = watchos; + SKIP_INSTALL = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = 4; + WATCHOS_DEPLOYMENT_TARGET = 7.0; + }; + name = Debug; + }; + 52E325AF26C72E7900CCE47E /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + ENABLE_PREVIEWS = YES; + INFOPLIST_FILE = "$(SRCROOT)/watchOS-Ext/Ext-Info.plist"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@executable_path/../../Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.viewinspector.watchOS.watchkitapp.watchkitextension; + PRODUCT_NAME = "${TARGET_NAME}"; + SDKROOT = watchos; + SKIP_INSTALL = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = 4; + WATCHOS_DEPLOYMENT_TARGET = 7.0; + }; + name = Release; + }; + 52E325B226C72E7900CCE47E /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_STYLE = Automatic; + IBSC_MODULE = watchOS_WatchKit_Extension; + INFOPLIST_FILE = "watchOS-App/App-Info.plist"; + PRODUCT_BUNDLE_IDENTIFIER = com.viewinspector.watchOS.watchkitapp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = watchos; + SKIP_INSTALL = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = 4; + WATCHOS_DEPLOYMENT_TARGET = 7.0; + }; + name = Debug; + }; + 52E325B326C72E7900CCE47E /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_STYLE = Automatic; + IBSC_MODULE = watchOS_WatchKit_Extension; + INFOPLIST_FILE = "watchOS-App/App-Info.plist"; + PRODUCT_BUNDLE_IDENTIFIER = com.viewinspector.watchOS.watchkitapp; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = watchos; + SKIP_INSTALL = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = 4; + WATCHOS_DEPLOYMENT_TARGET = 7.0; + }; + name = Release; + }; + 52E325B626C72E7900CCE47E /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.viewinspector.watchOS; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + WATCHOS_DEPLOYMENT_TARGET = 7.0; + }; + name = Debug; + }; + 52E325B726C72E7900CCE47E /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.viewinspector.watchOS; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + WATCHOS_DEPLOYMENT_TARGET = 7.0; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 5216474426C7343E00B3EC2B /* Build configuration list for PBXNativeTarget "watchOS-Tests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5216474226C7343E00B3EC2B /* Debug */, + 5216474326C7343E00B3EC2B /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 52E3258726C72E7800CCE47E /* Build configuration list for PBXProject "watchOS" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 52E325AB26C72E7900CCE47E /* Debug */, + 52E325AC26C72E7900CCE47E /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 52E325AD26C72E7900CCE47E /* Build configuration list for PBXNativeTarget "watchOS-Ext" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 52E325AE26C72E7900CCE47E /* Debug */, + 52E325AF26C72E7900CCE47E /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 52E325B126C72E7900CCE47E /* Build configuration list for PBXNativeTarget "watchOS-App" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 52E325B226C72E7900CCE47E /* Debug */, + 52E325B326C72E7900CCE47E /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 52E325B526C72E7900CCE47E /* Build configuration list for PBXNativeTarget "watchOS" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 52E325B626C72E7900CCE47E /* Debug */, + 52E325B726C72E7900CCE47E /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 52E3258426C72E7800CCE47E /* Project object */; +} From db4074b338ff4ea2ac0603453816806ee014cd3e Mon Sep 17 00:00:00 2001 From: Alexey Naumov Date: Sat, 14 Aug 2021 03:02:45 +0300 Subject: [PATCH 10/99] Add a workspace --- .gitignore | 2 +- .watchOS/watchOS-Tests/Tests-Info.plist | 22 -- .watchOS/watchOS-Tests/watchOS_Tests.swift | 10 - .watchOS/watchOS.xcodeproj/project.pbxproj | 212 ------------------ .../contents.xcworkspacedata | 7 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../xcschemes/watchOS-App.xcscheme | 88 ++++++++ .../contents.xcworkspacedata | 10 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../contents.xcworkspacedata | 7 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + 11 files changed, 137 insertions(+), 245 deletions(-) delete mode 100644 .watchOS/watchOS-Tests/Tests-Info.plist delete mode 100644 .watchOS/watchOS-Tests/watchOS_Tests.swift create mode 100644 .watchOS/watchOS.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 .watchOS/watchOS.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 .watchOS/watchOS.xcodeproj/xcshareddata/xcschemes/watchOS-App.xcscheme create mode 100644 .watchOS/watchOS.xcworkspace/contents.xcworkspacedata create mode 100644 .watchOS/watchOS.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 ViewInspector.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 ViewInspector.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/.gitignore b/.gitignore index 54956470..4cb80c40 100755 --- a/.gitignore +++ b/.gitignore @@ -2,7 +2,7 @@ .DS_Store ## Xcode workspace -*.xcworkspace +#*.xcworkspace ## Build generated build/ diff --git a/.watchOS/watchOS-Tests/Tests-Info.plist b/.watchOS/watchOS-Tests/Tests-Info.plist deleted file mode 100644 index 64d65ca4..00000000 --- a/.watchOS/watchOS-Tests/Tests-Info.plist +++ /dev/null @@ -1,22 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - $(PRODUCT_BUNDLE_PACKAGE_TYPE) - CFBundleShortVersionString - 1.0 - CFBundleVersion - 1 - - diff --git a/.watchOS/watchOS-Tests/watchOS_Tests.swift b/.watchOS/watchOS-Tests/watchOS_Tests.swift deleted file mode 100644 index fc027db5..00000000 --- a/.watchOS/watchOS-Tests/watchOS_Tests.swift +++ /dev/null @@ -1,10 +0,0 @@ -import XCTest -import SwiftUI -@testable import watchOS_Ext - -class watchOS_Tests: XCTestCase { - - func testExample() throws { - - } -} diff --git a/.watchOS/watchOS.xcodeproj/project.pbxproj b/.watchOS/watchOS.xcodeproj/project.pbxproj index 49dbc82c..e90c646d 100644 --- a/.watchOS/watchOS.xcodeproj/project.pbxproj +++ b/.watchOS/watchOS.xcodeproj/project.pbxproj @@ -7,27 +7,11 @@ objects = { /* Begin PBXBuildFile section */ - 5216473E26C7343E00B3EC2B /* watchOS_Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5216473D26C7343E00B3EC2B /* watchOS_Tests.swift */; }; - 52E3258F26C72E7800CCE47E /* watchOS-App.app in Embed Watch Content */ = {isa = PBXBuildFile; fileRef = 52E3258E26C72E7800CCE47E /* watchOS-App.app */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 52E3259B26C72E7900CCE47E /* watchOS-Ext.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 52E3259A26C72E7900CCE47E /* watchOS-Ext.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 52E325A226C72E7900CCE47E /* watchOSApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52E325A126C72E7900CCE47E /* watchOSApp.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ - 5216474026C7343E00B3EC2B /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 52E3258426C72E7800CCE47E /* Project object */; - proxyType = 1; - remoteGlobalIDString = 52E3259926C72E7900CCE47E; - remoteInfo = "watchOS-Ext"; - }; - 52E3259026C72E7800CCE47E /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 52E3258426C72E7800CCE47E /* Project object */; - proxyType = 1; - remoteGlobalIDString = 52E3258D26C72E7800CCE47E; - remoteInfo = "watchOS WatchKit App"; - }; 52E3259C26C72E7900CCE47E /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 52E3258426C72E7800CCE47E /* Project object */; @@ -49,24 +33,9 @@ name = "Embed App Extensions"; runOnlyForDeploymentPostprocessing = 0; }; - 52E325B426C72E7900CCE47E /* Embed Watch Content */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = "$(CONTENTS_FOLDER_PATH)/Watch"; - dstSubfolderSpec = 16; - files = ( - 52E3258F26C72E7800CCE47E /* watchOS-App.app in Embed Watch Content */, - ); - name = "Embed Watch Content"; - runOnlyForDeploymentPostprocessing = 0; - }; /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ - 5216473B26C7343E00B3EC2B /* watchOS-Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "watchOS-Tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; - 5216473D26C7343E00B3EC2B /* watchOS_Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = watchOS_Tests.swift; sourceTree = ""; }; - 5216473F26C7343E00B3EC2B /* Tests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Tests-Info.plist"; sourceTree = ""; }; - 52E3258A26C72E7800CCE47E /* watchOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = watchOS.app; sourceTree = BUILT_PRODUCTS_DIR; }; 52E3258E26C72E7800CCE47E /* watchOS-App.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "watchOS-App.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 52E3259526C72E7900CCE47E /* App-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "App-Info.plist"; sourceTree = ""; }; 52E3259A26C72E7900CCE47E /* watchOS-Ext.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = "watchOS-Ext.appex"; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -75,13 +44,6 @@ /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ - 5216473826C7343E00B3EC2B /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; 52E3259726C72E7900CCE47E /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -92,21 +54,11 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ - 5216473C26C7343E00B3EC2B /* watchOS-Tests */ = { - isa = PBXGroup; - children = ( - 5216473D26C7343E00B3EC2B /* watchOS_Tests.swift */, - 5216473F26C7343E00B3EC2B /* Tests-Info.plist */, - ); - path = "watchOS-Tests"; - sourceTree = ""; - }; 52E3258326C72E7800CCE47E = { isa = PBXGroup; children = ( 52E3259226C72E7800CCE47E /* watchOS-App */, 52E3259E26C72E7900CCE47E /* watchOS-Ext */, - 5216473C26C7343E00B3EC2B /* watchOS-Tests */, 52E3258B26C72E7800CCE47E /* Products */, ); sourceTree = ""; @@ -114,10 +66,8 @@ 52E3258B26C72E7800CCE47E /* Products */ = { isa = PBXGroup; children = ( - 52E3258A26C72E7800CCE47E /* watchOS.app */, 52E3258E26C72E7800CCE47E /* watchOS-App.app */, 52E3259A26C72E7900CCE47E /* watchOS-Ext.appex */, - 5216473B26C7343E00B3EC2B /* watchOS-Tests.xctest */, ); name = Products; sourceTree = ""; @@ -142,41 +92,6 @@ /* End PBXGroup section */ /* Begin PBXNativeTarget section */ - 5216473A26C7343E00B3EC2B /* watchOS-Tests */ = { - isa = PBXNativeTarget; - buildConfigurationList = 5216474426C7343E00B3EC2B /* Build configuration list for PBXNativeTarget "watchOS-Tests" */; - buildPhases = ( - 5216473726C7343E00B3EC2B /* Sources */, - 5216473826C7343E00B3EC2B /* Frameworks */, - 5216473926C7343E00B3EC2B /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - 5216474126C7343E00B3EC2B /* PBXTargetDependency */, - ); - name = "watchOS-Tests"; - productName = "watchOS-Tests"; - productReference = 5216473B26C7343E00B3EC2B /* watchOS-Tests.xctest */; - productType = "com.apple.product-type.bundle.unit-test"; - }; - 52E3258926C72E7800CCE47E /* watchOS */ = { - isa = PBXNativeTarget; - buildConfigurationList = 52E325B526C72E7900CCE47E /* Build configuration list for PBXNativeTarget "watchOS" */; - buildPhases = ( - 52E3258826C72E7800CCE47E /* Resources */, - 52E325B426C72E7900CCE47E /* Embed Watch Content */, - ); - buildRules = ( - ); - dependencies = ( - 52E3259126C72E7800CCE47E /* PBXTargetDependency */, - ); - name = watchOS; - productName = watchOS; - productReference = 52E3258A26C72E7800CCE47E /* watchOS.app */; - productType = "com.apple.product-type.application.watchapp2-container"; - }; 52E3258D26C72E7800CCE47E /* watchOS-App */ = { isa = PBXNativeTarget; buildConfigurationList = 52E325B126C72E7900CCE47E /* Build configuration list for PBXNativeTarget "watchOS-App" */; @@ -220,13 +135,6 @@ LastSwiftUpdateCheck = 1250; LastUpgradeCheck = 1250; TargetAttributes = { - 5216473A26C7343E00B3EC2B = { - CreatedOnToolsVersion = 12.5.1; - TestTargetID = 52E3259926C72E7900CCE47E; - }; - 52E3258926C72E7800CCE47E = { - CreatedOnToolsVersion = 12.5.1; - }; 52E3258D26C72E7800CCE47E = { CreatedOnToolsVersion = 12.5.1; }; @@ -248,29 +156,13 @@ projectDirPath = ""; projectRoot = ""; targets = ( - 52E3258926C72E7800CCE47E /* watchOS */, 52E3258D26C72E7800CCE47E /* watchOS-App */, 52E3259926C72E7900CCE47E /* watchOS-Ext */, - 5216473A26C7343E00B3EC2B /* watchOS-Tests */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ - 5216473926C7343E00B3EC2B /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 52E3258826C72E7800CCE47E /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; 52E3258C26C72E7800CCE47E /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -288,14 +180,6 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ - 5216473726C7343E00B3EC2B /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 5216473E26C7343E00B3EC2B /* watchOS_Tests.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; 52E3259626C72E7900CCE47E /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -307,16 +191,6 @@ /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ - 5216474126C7343E00B3EC2B /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 52E3259926C72E7900CCE47E /* watchOS-Ext */; - targetProxy = 5216474026C7343E00B3EC2B /* PBXContainerItemProxy */; - }; - 52E3259126C72E7800CCE47E /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 52E3258D26C72E7800CCE47E /* watchOS-App */; - targetProxy = 52E3259026C72E7800CCE47E /* PBXContainerItemProxy */; - }; 52E3259D26C72E7900CCE47E /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 52E3259926C72E7900CCE47E /* watchOS-Ext */; @@ -325,48 +199,6 @@ /* End PBXTargetDependency section */ /* Begin XCBuildConfiguration section */ - 5216474226C7343E00B3EC2B /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - CODE_SIGN_STYLE = Automatic; - INFOPLIST_FILE = "watchOS-Tests/Tests-Info.plist"; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = "com.viewinspector.watchOS-Tests"; - PRODUCT_NAME = "$(TARGET_NAME)"; - SDKROOT = watchos; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 4; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/watchOS-Ext.appex/watchOS-Ext"; - WATCHOS_DEPLOYMENT_TARGET = 7.4; - }; - name = Debug; - }; - 5216474326C7343E00B3EC2B /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - CODE_SIGN_STYLE = Automatic; - INFOPLIST_FILE = "watchOS-Tests/Tests-Info.plist"; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = "com.viewinspector.watchOS-Tests"; - PRODUCT_NAME = "$(TARGET_NAME)"; - SDKROOT = watchos; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 4; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/watchOS-Ext.appex/watchOS-Ext"; - WATCHOS_DEPLOYMENT_TARGET = 7.4; - }; - name = Release; - }; 52E325AB26C72E7900CCE47E /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -561,44 +393,9 @@ }; name = Release; }; - 52E325B626C72E7900CCE47E /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.viewinspector.watchOS; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 5.0; - WATCHOS_DEPLOYMENT_TARGET = 7.0; - }; - name = Debug; - }; - 52E325B726C72E7900CCE47E /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.viewinspector.watchOS; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 5.0; - WATCHOS_DEPLOYMENT_TARGET = 7.0; - }; - name = Release; - }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ - 5216474426C7343E00B3EC2B /* Build configuration list for PBXNativeTarget "watchOS-Tests" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 5216474226C7343E00B3EC2B /* Debug */, - 5216474326C7343E00B3EC2B /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; 52E3258726C72E7800CCE47E /* Build configuration list for PBXProject "watchOS" */ = { isa = XCConfigurationList; buildConfigurations = ( @@ -626,15 +423,6 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 52E325B526C72E7900CCE47E /* Build configuration list for PBXNativeTarget "watchOS" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 52E325B626C72E7900CCE47E /* Debug */, - 52E325B726C72E7900CCE47E /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; /* End XCConfigurationList section */ }; rootObject = 52E3258426C72E7800CCE47E /* Project object */; diff --git a/.watchOS/watchOS.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/.watchOS/watchOS.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..919434a6 --- /dev/null +++ b/.watchOS/watchOS.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/.watchOS/watchOS.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/.watchOS/watchOS.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/.watchOS/watchOS.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/.watchOS/watchOS.xcodeproj/xcshareddata/xcschemes/watchOS-App.xcscheme b/.watchOS/watchOS.xcodeproj/xcshareddata/xcschemes/watchOS-App.xcscheme new file mode 100644 index 00000000..bf748de3 --- /dev/null +++ b/.watchOS/watchOS.xcodeproj/xcshareddata/xcschemes/watchOS-App.xcscheme @@ -0,0 +1,88 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.watchOS/watchOS.xcworkspace/contents.xcworkspacedata b/.watchOS/watchOS.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..d4558c9b --- /dev/null +++ b/.watchOS/watchOS.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/.watchOS/watchOS.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/.watchOS/watchOS.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/.watchOS/watchOS.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/ViewInspector.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/ViewInspector.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 00000000..919434a6 --- /dev/null +++ b/ViewInspector.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/ViewInspector.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/ViewInspector.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000..18d98100 --- /dev/null +++ b/ViewInspector.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + From 9675e58320b2759981c9f4bdb50fb8e14050da3a Mon Sep 17 00:00:00 2001 From: Alexey Naumov Date: Wed, 18 Aug 2021 23:38:20 +0300 Subject: [PATCH 11/99] Fix crashes in iOS 15 --- Sources/ViewInspector/SwiftUI/Button.swift | 38 +++++++++++++++++++--- Sources/ViewInspector/SwiftUI/Menu.swift | 14 ++++++-- 2 files changed, 46 insertions(+), 6 deletions(-) diff --git a/Sources/ViewInspector/SwiftUI/Button.swift b/Sources/ViewInspector/SwiftUI/Button.swift index 8be7c1b5..ed218b40 100644 --- a/Sources/ViewInspector/SwiftUI/Button.swift +++ b/Sources/ViewInspector/SwiftUI/Button.swift @@ -93,23 +93,53 @@ public extension PrimitiveButtonStyle { @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) internal extension ButtonStyleConfiguration { - private struct Allocator { + private struct Allocator3 { + let data: (Bool, Bool, Bool) + init(flag: Bool) { + data = (false, false, flag) + } + } + private struct Allocator24 { let data: (Int64, Int64, Int64) init(flag: Bool) { data = (flag ? -1 : 0, 0, 0) } } init(isPressed: Bool) { - self = unsafeBitCast(Allocator(flag: isPressed), to: Self.self) + switch MemoryLayout.size { + case 3: + self = unsafeBitCast(Allocator3(flag: isPressed), to: Self.self) + case 24: + self = unsafeBitCast(Allocator24(flag: isPressed), to: Self.self) + default: + fatalError(MemoryLayout.actualSize()) + } } } @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) public extension PrimitiveButtonStyleConfiguration { - private struct Allocator { + private struct Allocator16 { + let onTrigger: () -> Void + } + private struct Allocator24 { + let buffer: Int8 = 0 let onTrigger: () -> Void } init(onTrigger: @escaping () -> Void) { - self = unsafeBitCast(Allocator(onTrigger: onTrigger), to: Self.self) + switch MemoryLayout.size { + case 16: + self = unsafeBitCast(Allocator16(onTrigger: onTrigger), to: Self.self) + case 24: + self = unsafeBitCast(Allocator24(onTrigger: onTrigger), to: Self.self) + default: + fatalError(MemoryLayout.actualSize()) + } + } +} + +internal extension MemoryLayout { + static func actualSize() -> String { + fatalError("New size of \(String(describing: type(of: T.self))) is \(Self.size)") } } diff --git a/Sources/ViewInspector/SwiftUI/Menu.swift b/Sources/ViewInspector/SwiftUI/Menu.swift index 55f53e43..c2de1da9 100644 --- a/Sources/ViewInspector/SwiftUI/Menu.swift +++ b/Sources/ViewInspector/SwiftUI/Menu.swift @@ -89,8 +89,18 @@ public extension MenuStyle { @available(iOS 14.0, macOS 11.0, *) @available(tvOS, unavailable) private extension MenuStyleConfiguration { - struct Allocator { } + struct Allocator0 { } + struct Allocator16 { + let data: (Int64, Int64) = (0, 0) + } init() { - self = unsafeBitCast(Allocator(), to: Self.self) + switch MemoryLayout.size { + case 0: + self = unsafeBitCast(Allocator0(), to: Self.self) + case 16: + self = unsafeBitCast(Allocator16(), to: Self.self) + default: + fatalError(MemoryLayout.actualSize()) + } } } From 05cccb97da4299bcea075b957e73bf21610cc990 Mon Sep 17 00:00:00 2001 From: Alexey Naumov Date: Wed, 18 Aug 2021 23:46:31 +0300 Subject: [PATCH 12/99] Fix button's label inspection for iOS 15 --- Sources/ViewInspector/SwiftUI/Button.swift | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Sources/ViewInspector/SwiftUI/Button.swift b/Sources/ViewInspector/SwiftUI/Button.swift index ed218b40..91fa22c3 100644 --- a/Sources/ViewInspector/SwiftUI/Button.swift +++ b/Sources/ViewInspector/SwiftUI/Button.swift @@ -32,7 +32,13 @@ public extension InspectableView where View: MultipleViewContent { @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) extension ViewType.Button: SupplementaryChildrenLabelView { - static var labelViewPath: String { "_label" } + static var labelViewPath: String { + if #available(iOS 15.0, tvOS 15.0, *) { + return "label" + } else { + return "_label" + } + } } // MARK: - Custom Attributes From e4e4d05b08f1cdf40231ee21376575a39fc3b7d5 Mon Sep 17 00:00:00 2001 From: Alexey Naumov Date: Wed, 18 Aug 2021 23:55:22 +0300 Subject: [PATCH 13/99] Fix tests for Color and SecureField --- Sources/ViewInspector/SwiftUI/Color.swift | 2 +- Sources/ViewInspector/SwiftUI/SecureField.swift | 16 +++++++++++++--- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/Sources/ViewInspector/SwiftUI/Color.swift b/Sources/ViewInspector/SwiftUI/Color.swift index 9ee94cd2..df9d08d5 100644 --- a/Sources/ViewInspector/SwiftUI/Color.swift +++ b/Sources/ViewInspector/SwiftUI/Color.swift @@ -40,7 +40,7 @@ public extension InspectableView where View == ViewType.Color { func rgba() throws -> (red: Float, green: Float, blue: Float, alpha: Float) { let colorProvider = try Inspector.attribute(path: "provider|base", value: content.view) let providerName = Inspector.typeName(value: colorProvider) - if providerName == "_Resolved" { + if ["_Resolved", "Resolved"].contains(providerName) { let red = try Inspector.attribute(label: "linearRed", value: colorProvider, type: Float.self) let green = try Inspector.attribute(label: "linearGreen", value: colorProvider, type: Float.self) let blue = try Inspector.attribute(label: "linearBlue", value: colorProvider, type: Float.self) diff --git a/Sources/ViewInspector/SwiftUI/SecureField.swift b/Sources/ViewInspector/SwiftUI/SecureField.swift index a8526704..073325f5 100644 --- a/Sources/ViewInspector/SwiftUI/SecureField.swift +++ b/Sources/ViewInspector/SwiftUI/SecureField.swift @@ -53,14 +53,24 @@ public extension InspectableView where View == ViewType.SecureField { } private func inputBinding() throws -> Binding { + if let binding = try? Inspector.attribute( + label: "text", value: content.view, type: Binding.self) { + return binding + } return try Inspector.attribute( - label: "text", value: content.view, type: Binding.self) + label: "_text", value: content.view, type: Binding.self) } func callOnCommit() throws { typealias Callback = () -> Void - let callback = try Inspector - .attribute(label: "onCommit", value: content.view, type: Callback.self) + let callback: Callback = try { + if let value = try? Inspector + .attribute(label: "onCommit", value: content.view, type: Callback.self) { + return value + } + return try Inspector + .attribute(path: "deprecatedActions|some|commit", value: content.view, type: Callback.self) + }() callback() } } From c5847925d74e27cfcd3d61b7f84d9355e09ebf96 Mon Sep 17 00:00:00 2001 From: Alexey Naumov Date: Thu, 19 Aug 2021 00:11:48 +0300 Subject: [PATCH 14/99] Fix TextAttributes tests, add line style inspection --- .../SwiftUI/TextAttributes.swift | 44 +++++++++++++++---- .../SwiftUI/TextAttributesTests.swift | 6 +++ 2 files changed, 42 insertions(+), 8 deletions(-) diff --git a/Sources/ViewInspector/SwiftUI/TextAttributes.swift b/Sources/ViewInspector/SwiftUI/TextAttributes.swift index 25d24299..441594f8 100644 --- a/Sources/ViewInspector/SwiftUI/TextAttributes.swift +++ b/Sources/ViewInspector/SwiftUI/TextAttributes.swift @@ -108,11 +108,13 @@ public extension ViewType.Text.Attributes { func isStrikethrough() throws -> Bool { return try commonTrait(name: "strikethrough") { modifier -> Bool? in guard let child = try? Inspector.attribute(label: "anyTextModifier", value: modifier), - Inspector.typeName(value: child) == "StrikethroughTextModifier", - let active = try? Inspector - .attribute(path: "lineStyle|some|active", value: child, type: Bool.self) + Inspector.typeName(value: child) == "StrikethroughTextModifier" else { return nil } - return active + if let active = try? Inspector + .attribute(path: "lineStyle|some|active", value: child, type: Bool.self) { + return active + } + return (try? Inspector.attribute(path: "lineStyle|some|nsUnderlineStyle", value: child)) != nil } } @@ -127,14 +129,28 @@ public extension ViewType.Text.Attributes { } } + @available(iOS 15.0, tvOS 15.0, macOS 11.6, *) + func strikethroughStyle() throws -> NSUnderlineStyle { + return try commonTrait(name: "strikethrough") { modifier -> NSUnderlineStyle? in + guard let child = try? Inspector.attribute(label: "anyTextModifier", value: modifier), + Inspector.typeName(value: child) == "StrikethroughTextModifier", + let value = try? Inspector + .attribute(path: "lineStyle|some|nsUnderlineStyle", value: child, type: NSUnderlineStyle.self) + else { return nil } + return value + } + } + func isUnderline() throws -> Bool { return try commonTrait(name: "underline") { modifier -> Bool? in guard let child = try? Inspector.attribute(label: "anyTextModifier", value: modifier), - Inspector.typeName(value: child) == "UnderlineTextModifier", - let active = try? Inspector - .attribute(path: "lineStyle|some|active", value: child, type: Bool.self) + Inspector.typeName(value: child) == "UnderlineTextModifier" else { return nil } - return active + if let active = try? Inspector + .attribute(path: "lineStyle|some|active", value: child, type: Bool.self) { + return active + } + return (try? Inspector.attribute(path: "lineStyle|some|nsUnderlineStyle", value: child)) != nil } } @@ -149,6 +165,18 @@ public extension ViewType.Text.Attributes { } } + @available(iOS 15.0, tvOS 15.0, macOS 11.6, *) + func underlineStyle() throws -> NSUnderlineStyle { + return try commonTrait(name: "underline") { modifier -> NSUnderlineStyle? in + guard let child = try? Inspector.attribute(label: "anyTextModifier", value: modifier), + Inspector.typeName(value: child) == "UnderlineTextModifier", + let value = try? Inspector + .attribute(path: "lineStyle|some|nsUnderlineStyle", value: child, type: NSUnderlineStyle.self) + else { return nil } + return value + } + } + func kerning() throws -> CGFloat { return try commonTrait(name: "kerning") { modifier -> CGFloat? in guard let kerning = try? Inspector diff --git a/Tests/ViewInspectorTests/SwiftUI/TextAttributesTests.swift b/Tests/ViewInspectorTests/SwiftUI/TextAttributesTests.swift index 43b1c13d..baa61a52 100644 --- a/Tests/ViewInspectorTests/SwiftUI/TextAttributesTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/TextAttributesTests.swift @@ -96,6 +96,9 @@ final class TextAttributesTests: XCTestCase { let sut = try view.inspect().text().attributes() XCTAssertTrue(try sut.isStrikethrough()) XCTAssertEqual(try sut.strikethroughColor(), .black) + if #available(iOS 15.0, tvOS 15.0, macOS 11.6, *) { + XCTAssertEqual(try sut.strikethroughStyle(), .single) + } } func testUnderlineAttribute() throws { @@ -103,6 +106,9 @@ final class TextAttributesTests: XCTestCase { let sut = try view.inspect().text().attributes() XCTAssertTrue(try sut.isUnderline()) XCTAssertEqual(try sut.underlineColor(), .black) + if #available(iOS 15.0, tvOS 15.0, macOS 11.6, *) { + XCTAssertEqual(try sut.underlineStyle(), .single) + } } func testKerningAttribute() throws { From 38465d0c5d9432495730d7832c2b707d54f5c78c Mon Sep 17 00:00:00 2001 From: Alexey Naumov Date: Thu, 19 Aug 2021 00:19:06 +0300 Subject: [PATCH 15/99] Fix tests for Popover and TextField --- Sources/ViewInspector/SwiftUI/Popover.swift | 7 +++--- Sources/ViewInspector/SwiftUI/TextField.swift | 24 +++++++++++++++---- 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/Sources/ViewInspector/SwiftUI/Popover.swift b/Sources/ViewInspector/SwiftUI/Popover.swift index 53fdf530..e5c80a37 100644 --- a/Sources/ViewInspector/SwiftUI/Popover.swift +++ b/Sources/ViewInspector/SwiftUI/Popover.swift @@ -77,9 +77,10 @@ public extension InspectableView where View == ViewType.Popover { func dismiss() throws { typealias OnDismiss = () -> Void - let onDismiss = try Inspector.attribute( - label: "onDismiss", value: content.view, type: OnDismiss.self) - onDismiss() + if let onDismiss = try? Inspector.attribute( + label: "onDismiss", value: content.view, type: OnDismiss.self) { + onDismiss() + } try isPresentedBinding().wrappedValue = false } diff --git a/Sources/ViewInspector/SwiftUI/TextField.swift b/Sources/ViewInspector/SwiftUI/TextField.swift index 88425b28..d6d22af9 100644 --- a/Sources/ViewInspector/SwiftUI/TextField.swift +++ b/Sources/ViewInspector/SwiftUI/TextField.swift @@ -46,19 +46,35 @@ public extension InspectableView where View == ViewType.TextField { func callOnEditingChanged() throws { try guardIsResponsive() typealias Callback = (Bool) -> Void - let callback = try Inspector - .attribute(label: "onEditingChanged", value: content.view, type: Callback.self) + let callback: Callback = try { + if let value = try? Inspector + .attribute(label: "onEditingChanged", value: content.view, type: Callback.self) { + return value + } + return try Inspector + .attribute(path: deprecatedActionsPath("editingChanged"), value: content.view, type: Callback.self) + }() callback(false) } func callOnCommit() throws { try guardIsResponsive() typealias Callback = () -> Void - let callback = try Inspector - .attribute(label: "onCommit", value: content.view, type: Callback.self) + let callback: Callback = try { + if let value = try? Inspector + .attribute(label: "onCommit", value: content.view, type: Callback.self) { + return value + } + return try Inspector + .attribute(path: deprecatedActionsPath("commit"), value: content.view, type: Callback.self) + }() callback() } + private func deprecatedActionsPath(_ action: String) -> String { + return "_state|state|_value|deprecatedActions|some|\(action)" + } + func input() throws -> String { return try inputBinding().wrappedValue } From 8b1bf672fb72a0fae86a84726d785cee5acd9872 Mon Sep 17 00:00:00 2001 From: Alexey Naumov Date: Thu, 19 Aug 2021 00:59:04 +0300 Subject: [PATCH 16/99] Fix tests for TextInputModifiers --- .../Modifiers/EnvironmentModifiers.swift | 20 ++++++++++- .../Modifiers/TextInputModifiers.swift | 33 +++++++++++++++++++ .../TextInputModifiersTests.swift | 7 ++++ 3 files changed, 59 insertions(+), 1 deletion(-) diff --git a/Sources/ViewInspector/Modifiers/EnvironmentModifiers.swift b/Sources/ViewInspector/Modifiers/EnvironmentModifiers.swift index b10b2796..01fc17c4 100644 --- a/Sources/ViewInspector/Modifiers/EnvironmentModifiers.swift +++ b/Sources/ViewInspector/Modifiers/EnvironmentModifiers.swift @@ -13,6 +13,11 @@ public extension InspectableView { @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) internal extension InspectableView { func environment(_ reference: WritableKeyPath, call: String) throws -> T { + return try environment(reference, call: call, valueType: T.self) + } + + func environment(_ reference: WritableKeyPath, + call: String, valueType: V.Type) throws -> V { guard let modifier = content.medium.environmentModifiers.last(where: { modifier in guard let keyPath = try? modifier.keyPath() as? WritableKeyPath else { return false } @@ -21,7 +26,7 @@ internal extension InspectableView { throw InspectionError.modifierNotFound( parent: Inspector.typeName(value: content.view), modifier: call, index: 0) } - return try Inspector.cast(value: try modifier.value(), type: T.self) + return try Inspector.cast(value: try modifier.value(), type: V.self) } } @@ -63,3 +68,16 @@ extension _EnvironmentKeyWritingModifier: EnvironmentModifier { return try Inspector.attribute(label: "value", value: self) } } + +@available(iOS 15.0, tvOS 15.0, watchOS 8.0, *) +@available(macOS, unavailable) +extension _EnvironmentKeyTransformModifier: EnvironmentModifier where Value == TextInputAutocapitalization { + + func keyPath() throws -> Any { + return try Inspector.attribute(label: "keyPath", value: self) + } + + func value() throws -> Any { + return try Inspector.attribute(label: "transform", value: self) + } +} diff --git a/Sources/ViewInspector/Modifiers/TextInputModifiers.swift b/Sources/ViewInspector/Modifiers/TextInputModifiers.swift index 2c4b6188..052e6ce3 100644 --- a/Sources/ViewInspector/Modifiers/TextInputModifiers.swift +++ b/Sources/ViewInspector/Modifiers/TextInputModifiers.swift @@ -24,6 +24,21 @@ public extension InspectableView { func autocapitalization() throws -> UITextAutocapitalizationType { let reference = EmptyView().autocapitalization(.none) + if #available(iOS 15.0, tvOS 15.0, watchOS 8.0, *) { + typealias Closure = (inout TextInputAutocapitalization) -> Void + if let keyPath = try? Inspector + .environmentKeyPath(TextInputAutocapitalization.self, reference) { + let closure = try environment(keyPath, call: "autocapitalization", valueType: Closure.self) + var value = TextInputAutocapitalization.never + closure(&value) + let behavior = try Inspector.attribute(label: "behavior", value: value) + let stringValue = String(describing: behavior) + guard let style = TextInputAutocapitalization.Behavior(rawValue: stringValue) else { + throw InspectionError.notSupported("Unknown TextInputAutocapitalization.Behavior: \(stringValue)") + } + return style.autocapitalizationType + } + } let keyPath = try Inspector.environmentKeyPath(Int.self, reference) let value = try environment(keyPath, call: "autocapitalization") return UITextAutocapitalizationType(rawValue: value)! @@ -109,3 +124,21 @@ public extension InspectableView { .contains(true) } } + +#if os(iOS) || os(tvOS) +@available(iOS 15.0, tvOS 15.0, watchOS 8.0, *) +extension TextInputAutocapitalization { + enum Behavior: String { + case never, words, sentences, characters + + var autocapitalizationType: UITextAutocapitalizationType { + switch self { + case .never: return .none + case .words: return .words + case .sentences: return .sentences + case .characters: return .allCharacters + } + } + } +} +#endif diff --git a/Tests/ViewInspectorTests/ViewModifiers/TextInputModifiersTests.swift b/Tests/ViewInspectorTests/ViewModifiers/TextInputModifiersTests.swift index 3503556b..2b8561f6 100644 --- a/Tests/ViewInspectorTests/ViewModifiers/TextInputModifiersTests.swift +++ b/Tests/ViewInspectorTests/ViewModifiers/TextInputModifiersTests.swift @@ -27,6 +27,13 @@ final class TextInputModifiersTests: XCTestCase { } func testKeyboardTypeInspection() throws { + if #available(iOS 15.0, tvOS 15.0, watchOS 8.0, *) { + throw XCTSkip( + """ + Implementation should be similar to 'autocapitalization', but new \ + 'KeyboardType' is a private type in SwiftUI + """) + } let sut = AnyView(EmptyView()).keyboardType(.namePhonePad) XCTAssertEqual(try sut.inspect().anyView().keyboardType(), .namePhonePad) XCTAssertEqual(try sut.inspect().anyView().emptyView().keyboardType(), .namePhonePad) From abbbfda86a703a95ec3ea4640c81f283603543aa Mon Sep 17 00:00:00 2001 From: Alexey Naumov Date: Thu, 19 Aug 2021 01:09:42 +0300 Subject: [PATCH 17/99] Fix tests for Toggle --- Sources/ViewInspector/SwiftUI/Toggle.swift | 14 ++++++++++++-- .../ViewInspectorTests/SwiftUI/ForEachTests.swift | 2 +- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/Sources/ViewInspector/SwiftUI/Toggle.swift b/Sources/ViewInspector/SwiftUI/Toggle.swift index a9816d13..55dfcbd8 100644 --- a/Sources/ViewInspector/SwiftUI/Toggle.swift +++ b/Sources/ViewInspector/SwiftUI/Toggle.swift @@ -32,7 +32,13 @@ public extension InspectableView where View: MultipleViewContent { @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) extension ViewType.Toggle: SupplementaryChildrenLabelView { - static var labelViewPath: String { "_label" } + static var labelViewPath: String { + if #available(iOS 15.0, tvOS 15.0, *) { + return "label" + } else { + return "_label" + } + } } // MARK: - Custom Attributes @@ -55,8 +61,12 @@ public extension InspectableView where View == ViewType.Toggle { } private func isOnBinding() throws -> Binding { + if let binding = try? Inspector + .attribute(label: "__isOn", value: content.view, type: Binding.self) { + return binding + } return try Inspector - .attribute(label: "__isOn", value: content.view, type: Binding.self) + .attribute(label: "_isOn", value: content.view, type: Binding.self) } } diff --git a/Tests/ViewInspectorTests/SwiftUI/ForEachTests.swift b/Tests/ViewInspectorTests/SwiftUI/ForEachTests.swift index cc74f505..bb4b7ed7 100644 --- a/Tests/ViewInspectorTests/SwiftUI/ForEachTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/ForEachTests.swift @@ -83,7 +83,7 @@ final class ForEachTests: XCTestCase { func testRangeBased() throws { let range = 0..<5 - let view = ForEach(range) { Text(verbatim: "\($0)") } + let view = ForEach(0..<5) { Text(verbatim: "\($0)") } let sut = try view.inspect().forEach() XCTAssertEqual(sut.count, 5) From 2d78729922385d1a4bd615ca5a68d16206b24283 Mon Sep 17 00:00:00 2001 From: Alexey Naumov Date: Thu, 19 Aug 2021 01:25:37 +0300 Subject: [PATCH 18/99] Fix tests for Label and TabView --- Sources/ViewInspector/SwiftUI/Label.swift | 3 ++- Sources/ViewInspector/SwiftUI/TabView.swift | 17 +++++++++++++---- Sources/ViewInspector/ViewSearchIndex.swift | 3 +++ 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/Sources/ViewInspector/SwiftUI/Label.swift b/Sources/ViewInspector/SwiftUI/Label.swift index bd32b23f..93c7368f 100644 --- a/Sources/ViewInspector/SwiftUI/Label.swift +++ b/Sources/ViewInspector/SwiftUI/Label.swift @@ -73,7 +73,8 @@ public extension InspectableView { func labelStyle() throws -> Any { let modifier = try self.modifier({ modifier -> Bool in - return modifier.modifierType.hasPrefix("LabelStyleModifier") + return ["LabelStyleModifier", "LabelStyleWritingModifier"] + .contains(where: { modifier.modifierType.hasPrefix($0) }) }, call: "labelStyle") return try Inspector.attribute(path: "modifier|style", value: modifier) } diff --git a/Sources/ViewInspector/SwiftUI/TabView.swift b/Sources/ViewInspector/SwiftUI/TabView.swift index 596c0666..f9e7ec8c 100644 --- a/Sources/ViewInspector/SwiftUI/TabView.swift +++ b/Sources/ViewInspector/SwiftUI/TabView.swift @@ -76,13 +76,22 @@ public extension InspectableView { internal extension Content { func tabItem(parent: UnwrappedView) throws -> InspectableView { - let rootView = try modifierAttribute( - modifierName: "TabItemTraitKey", path: "modifier|value|some|storage|view|content", - type: Any.self, call: "tabItem") + let rootView: Any = try { + if let view = try? modifierAttribute( + modifierName: "TabItemTraitKey", path: "modifier|value|some|storage|view|content", + type: Any.self, call: "tabItem") { + return view + } + return try modifierAttribute( + modifierName: "PlatformItemTraitWriter", path: "modifier|source|content|content|content", + type: Any.self, call: "tabItem") + }() let medium = self.medium.resettingViewModifiers() let view = try InspectableView( try Inspector.unwrap(content: Content(rootView, medium: medium)), parent: parent, call: "tabItem()") - if #available(iOS 14.2, tvOS 14.2, *) { + if #available(iOS 15.0, tvOS 15.0, *) { + return view + } else if #available(iOS 14.2, tvOS 14.2, *) { return try InspectableView( try Inspector.unwrap(content: try view.zStack().child(at: 0)), parent: parent, call: "tabItem()") } else { diff --git a/Sources/ViewInspector/ViewSearchIndex.swift b/Sources/ViewInspector/ViewSearchIndex.swift index 2fc3a530..df96caba 100644 --- a/Sources/ViewInspector/ViewSearchIndex.swift +++ b/Sources/ViewInspector/ViewSearchIndex.swift @@ -249,6 +249,9 @@ internal extension ViewSearch { .init(name: "_TraitWritingModifier", builder: { parent, index in try parent.content.tabItem(parent: parent) }), + .init(name: "PlatformItemTraitWriter", builder: { parent, index in try parent.content.listRowBackground(parent: parent) }), From a1cb2de5eea391a7926cab92c3f440548f6a66b0 Mon Sep 17 00:00:00 2001 From: Alexey Naumov Date: Thu, 19 Aug 2021 01:53:40 +0300 Subject: [PATCH 19/99] Unwrap UnaryViewAdaptor --- Sources/ViewInspector/Inspector.swift | 2 ++ .../SwiftUI/UnaryViewAdaptor.swift | 17 +++++++++++++++++ .../SwiftUI/EnvironmentReaderViewTests.swift | 2 +- ViewInspector.xcodeproj/project.pbxproj | 4 ++++ 4 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 Sources/ViewInspector/SwiftUI/UnaryViewAdaptor.swift diff --git a/Sources/ViewInspector/Inspector.swift b/Sources/ViewInspector/Inspector.swift index 13d0fc89..c2ed1fb2 100644 --- a/Sources/ViewInspector/Inspector.swift +++ b/Sources/ViewInspector/Inspector.swift @@ -177,6 +177,8 @@ extension Inspector { return try ViewType.ViewModifier.child(content) case "SubscriptionView": return try ViewType.SubscriptionView.child(content) + case "_UnaryViewAdaptor": + return try ViewType.UnaryViewAdaptor.child(content) case "_ConditionalContent": return try ViewType.ConditionalContent.child(content) case "EnvironmentReaderView": diff --git a/Sources/ViewInspector/SwiftUI/UnaryViewAdaptor.swift b/Sources/ViewInspector/SwiftUI/UnaryViewAdaptor.swift new file mode 100644 index 00000000..6d4c6688 --- /dev/null +++ b/Sources/ViewInspector/SwiftUI/UnaryViewAdaptor.swift @@ -0,0 +1,17 @@ +import SwiftUI + +@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) +internal extension ViewType { + struct UnaryViewAdaptor { } +} + +// MARK: - Content Extraction + +@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) +extension ViewType.UnaryViewAdaptor: SingleViewContent { + + static func child(_ content: Content) throws -> Content { + let view = try Inspector.attribute(label: "content", value: content.view) + return try Inspector.unwrap(view: view, medium: content.medium) + } +} diff --git a/Tests/ViewInspectorTests/SwiftUI/EnvironmentReaderViewTests.swift b/Tests/ViewInspectorTests/SwiftUI/EnvironmentReaderViewTests.swift index 54c3a470..a5bbca0c 100644 --- a/Tests/ViewInspectorTests/SwiftUI/EnvironmentReaderViewTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/EnvironmentReaderViewTests.swift @@ -12,7 +12,7 @@ final class EnvironmentReaderViewTests: XCTestCase { .navigationBarItems(trailing: Text("")) } XCTAssertThrows( - try view.inspect().navigationView().list(0), + try view.inspect().navigationView().list(0).text(0), "Please insert '.navigationBarItems()' before list(0) for unwrapping the underlying view hierarchy.") } diff --git a/ViewInspector.xcodeproj/project.pbxproj b/ViewInspector.xcodeproj/project.pbxproj index 1b4f4658..9f3cf5e9 100644 --- a/ViewInspector.xcodeproj/project.pbxproj +++ b/ViewInspector.xcodeproj/project.pbxproj @@ -26,6 +26,7 @@ 5214800325F4EA4F002D974D /* EnvironmentObjectInjectionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5214800225F4EA4F002D974D /* EnvironmentObjectInjectionTests.swift */; }; 5214802B25F803B7002D974D /* CustomStyleModifiers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5214802A25F803B7002D974D /* CustomStyleModifiers.swift */; }; 5214803A25F803DC002D974D /* CustomStyleModifiersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5214803025F803D5002D974D /* CustomStyleModifiersTests.swift */; }; + 5236C34326CDC2F4007432E1 /* UnaryViewAdaptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5236C34226CDC2F4007432E1 /* UnaryViewAdaptor.swift */; }; 52507626264FC0F400ADE4E7 /* Alert.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52507625264FC0F400ADE4E7 /* Alert.swift */; }; 525076282650000600ADE4E7 /* AlertTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 525076272650000600ADE4E7 /* AlertTests.swift */; }; 52507647265155C000ADE4E7 /* TransitiveModifiersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52507646265155C000ADE4E7 /* TransitiveModifiersTests.swift */; }; @@ -269,6 +270,7 @@ 5214800225F4EA4F002D974D /* EnvironmentObjectInjectionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EnvironmentObjectInjectionTests.swift; sourceTree = ""; }; 5214802A25F803B7002D974D /* CustomStyleModifiers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomStyleModifiers.swift; sourceTree = ""; }; 5214803025F803D5002D974D /* CustomStyleModifiersTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomStyleModifiersTests.swift; sourceTree = ""; }; + 5236C34226CDC2F4007432E1 /* UnaryViewAdaptor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnaryViewAdaptor.swift; sourceTree = ""; }; 52507625264FC0F400ADE4E7 /* Alert.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Alert.swift; sourceTree = ""; }; 525076272650000600ADE4E7 /* AlertTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertTests.swift; sourceTree = ""; }; 52507646265155C000ADE4E7 /* TransitiveModifiersTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransitiveModifiersTests.swift; sourceTree = ""; }; @@ -653,6 +655,7 @@ F639DBC223A7DDA2003A6FED /* TouchBar.swift */, F64A2C6723A3FD3A00A4853A /* TreeView.swift */, F653BDE2255698A6001FA688 /* TupleView.swift */, + 5236C34226CDC2F4007432E1 /* UnaryViewAdaptor.swift */, F6D933B22385ED1400358E0E /* VSplitView.swift */, F60EEBC92382EED0007DB53A /* VStack.swift */, F60EEBC12382EED0007DB53A /* ZStack.swift */, @@ -997,6 +1000,7 @@ F6C15ADD254F26B9000240F1 /* StyleConfiguration.swift in Sources */, F639DBC323A7DDA2003A6FED /* TouchBar.swift in Sources */, 52507626264FC0F400ADE4E7 /* Alert.swift in Sources */, + 5236C34326CDC2F4007432E1 /* UnaryViewAdaptor.swift in Sources */, F60EEBD32382EED0007DB53A /* ZStack.swift in Sources */, 5214802B25F803B7002D974D /* CustomStyleModifiers.swift in Sources */, F6ECF6CE23A67C64000FC591 /* SizingModifiers.swift in Sources */, From f5ab9cff14836cfffe0adfdb379f9e754a734de0 Mon Sep 17 00:00:00 2001 From: Alexey Naumov Date: Tue, 24 Aug 2021 20:14:59 +0600 Subject: [PATCH 20/99] Silence a linter warning --- Sources/ViewInspector/Inspector.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Sources/ViewInspector/Inspector.swift b/Sources/ViewInspector/Inspector.swift index c2ed1fb2..c6e3c6f0 100644 --- a/Sources/ViewInspector/Inspector.swift +++ b/Sources/ViewInspector/Inspector.swift @@ -163,6 +163,7 @@ extension Inspector { return try unwrap(content: Content(view, medium: medium)) } + // swiftlint:disable cyclomatic_complexity static func unwrap(content: Content) throws -> Content { switch Inspector.typeName(value: content.view, prefixOnly: true) { case "Tree": @@ -189,6 +190,7 @@ extension Inspector { return content } } + // swiftlint:enable cyclomatic_complexity static func guardType(value: Any, namespacedPrefixes: [String], inspectionCall: String) throws { guard let firstPrefix = namespacedPrefixes.first From 22ffc3ea544dece3576a46214c24a5ff7fcf7571 Mon Sep 17 00:00:00 2001 From: Alexey Naumov Date: Tue, 24 Aug 2021 20:37:29 +0600 Subject: [PATCH 21/99] print out ivars from superclasses --- Sources/ViewInspector/Inspector.swift | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Sources/ViewInspector/Inspector.swift b/Sources/ViewInspector/Inspector.swift index c6e3c6f0..96d007ea 100644 --- a/Sources/ViewInspector/Inspector.swift +++ b/Sources/ViewInspector/Inspector.swift @@ -101,9 +101,14 @@ extension Inspector { return array.map { attributesTree(value: $0, medium: medium) } } let medium = (try? unwrap(content: Content(value, medium: medium)).medium) ?? medium - let mirror = Mirror(reflecting: value) + var mirror = Mirror(reflecting: value) + var children = Array(mirror.children) + while let superclass = mirror.superclassMirror { + mirror = superclass + children.append(contentsOf: superclass.children) + } var dict: [String: Any] = [:] - mirror.children.enumerated().forEach { child in + children.enumerated().forEach { child in let childName = child.element.label ?? "[\(child.offset)]" let childType = typeName(value: child.element.value) dict[childName + ": " + childType] = attributesTree(value: child.element.value, medium: medium) From cf7d68e357a4a03764a4acabcf4596ba76e982c2 Mon Sep 17 00:00:00 2001 From: Alexey Naumov Date: Tue, 24 Aug 2021 22:42:38 +0600 Subject: [PATCH 22/99] New accessibility attributes parser for iOS 15 --- .../Modifiers/AccessibilityModifiers.swift | 112 +++++++++++++++--- 1 file changed, 93 insertions(+), 19 deletions(-) diff --git a/Sources/ViewInspector/Modifiers/AccessibilityModifiers.swift b/Sources/ViewInspector/Modifiers/AccessibilityModifiers.swift index ca41c993..20a69310 100644 --- a/Sources/ViewInspector/Modifiers/AccessibilityModifiers.swift +++ b/Sources/ViewInspector/Modifiers/AccessibilityModifiers.swift @@ -6,29 +6,47 @@ import SwiftUI public extension InspectableView { func accessibilityLabel() throws -> InspectableView { - let text = try accessibilityElement( - "LabelKey", type: Text.self, call: "accessibilityLabel") + let text: Text + if #available(iOS 15.0, tvOS 15.0, *) { + text = try v3AccessibilityElement( + type: Text.self, call: "accessibilityLabel", { $0.accessibilityLabel("") }) + } else { + text = try v2AccessibilityElement( + "LabelKey", type: Text.self, call: "accessibilityLabel") + } let medium = content.medium.resettingViewModifiers() return try .init(try Inspector.unwrap(content: Content(text, medium: medium)), parent: self) } func accessibilityValue() throws -> InspectableView { - let text = try accessibilityElement( + let text: Text + if #available(iOS 15.0, tvOS 15.0, *) { + text = try v3AccessibilityElement( + type: Text.self, call: "accessibilityValue", { $0.accessibilityValue("") }) + } else { + text = try v2AccessibilityElement( "TypedValueKey", path: "value|some|description|some", type: Text.self, call: "accessibilityValue") + } let medium = content.medium.resettingViewModifiers() return try .init(try Inspector.unwrap(content: Content(text, medium: medium)), parent: self) } func accessibilityHint() throws -> InspectableView { - let text = try accessibilityElement( + let text: Text + if #available(iOS 15.0, tvOS 15.0, *) { + text = try v3AccessibilityElement( + type: Text.self, call: "accessibilityHint", { $0.accessibilityHint("") }) + } else { + text = try v2AccessibilityElement( "HintKey", type: Text.self, call: "accessibilityHint") + } let medium = content.medium.resettingViewModifiers() return try .init(try Inspector.unwrap(content: Content(text, medium: medium)), parent: self) } func accessibilityHidden() throws -> Bool { - let visibility = try accessibilityElement( + let visibility = try v2AccessibilityElement( "VisibilityKey", path: "value", type: (Any?).self, call: "accessibility(hidden:)") switch visibility { case let .some(value): @@ -39,18 +57,18 @@ public extension InspectableView { } func accessibilityIdentifier() throws -> String { - return try accessibilityElement( + return try v2AccessibilityElement( "IdentifierKey", type: String.self, call: "accessibility(identifier:)") } func accessibilitySelectionIdentifier() throws -> AnyHashable { - return try accessibilityElement( + return try v2AccessibilityElement( "SelectionIdentifierKey", type: AnyHashable.self, call: "accessibility(selectionIdentifier:)") } func accessibilityActivationPoint() throws -> UnitPoint { - return try accessibilityElement( + return try v2AccessibilityElement( "ActivationPointKey", path: "value|some|unitPoint", type: UnitPoint.self, call: "accessibility(activationPoint:)") } @@ -62,14 +80,14 @@ public extension InspectableView { .filter { $0.count > 0 }.last! let call = "accessibilityAction(.\(shortName))" typealias Callback = (()) -> Void - let callback = try accessibilityAction(name: kindString, path: "box|action|kind", + let callback = try v2AccessibilityAction(name: kindString, path: "box|action|kind", type: Callback.self, call: call) callback(()) } func callAccessibilityAdjustableAction(_ direction: AccessibilityAdjustmentDirection = .increment) throws { typealias Callback = (AccessibilityAdjustmentDirection) -> Void - let callback = try accessibilityAction( + let callback = try v2AccessibilityAction( name: "AccessibilityAdjustableAction()", path: "box|action", type: Callback.self, call: "accessibilityAdjustableAction") callback(direction) @@ -77,30 +95,86 @@ public extension InspectableView { func callAccessibilityScrollAction(_ edge: Edge) throws { typealias Callback = (Edge) -> Void - let callback = try accessibilityAction( + let callback = try v2AccessibilityAction( name: "AccessibilityScrollAction()", path: "box|action", type: Callback.self, call: "accessibilityScrollAction") callback(edge) } func accessibilitySortPriority() throws -> Double { - return try accessibilityElement( + return try v2AccessibilityElement( "SortPriorityKey", type: Double.self, call: "accessibility(sortPriority:)") } } // MARK: - Private +@available(iOS 15.0, tvOS 15.0, macOS 10.15, *) +private struct AccessibilityProperty { + + let keyPointerValue: UInt64 + let value: Any + + init(property: Any) throws { + self.keyPointerValue = try Inspector.attribute( + path: "super|key|rawValue|pointerValue", value: property, type: UInt64.self) + self.value = try Inspector.attribute(path: "super|value", value: property) + } + + static var noisePointerValues: Set = { + let view1 = EmptyView().accessibilityLabel(Text("")) + let view2 = EmptyView().accessibilityHint(Text("")) + do { + let props1 = try view1.inspect() + .v3AccessibilityProperties(call: "") + .map { $0.keyPointerValue } + let props2 = try view2.inspect() + .v3AccessibilityProperties(call: "") + .map { $0.keyPointerValue } + return Set(props1).intersection(Set(props2)) + } catch { return .init() } + }() +} + +@available(iOS 15.0, tvOS 15.0, macOS 10.15, *) +private extension InspectableView { + func v3AccessibilityElement( + type: T.Type, call: String, _ reference: (EmptyView) -> V + ) throws -> T where V: SwiftUI.View { + let noiseValues = AccessibilityProperty.noisePointerValues + guard let referenceValue = try reference(EmptyView()).inspect() + .v3AccessibilityProperties(call: call) + .map({ $0.keyPointerValue }) + .first(where: { !noiseValues.contains($0) }), + let property = try v3AccessibilityProperties(call: call) + .first(where: { $0.keyPointerValue == referenceValue }) + else { + throw InspectionError + .modifierNotFound(parent: Inspector.typeName(value: content.view), + modifier: call, index: 0) + } + return try Inspector.cast(value: property.value, type: T.self) + } + + func v3AccessibilityProperties(call: String) throws -> [AccessibilityProperty] { + return try modifierAttribute( + modifierName: "AccessibilityAttachmentModifier", + path: "modifier|storage|propertiesComponent", + type: [Any].self, call: call) + .map { try AccessibilityProperty(property: $0) } + } +} + @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) private extension InspectableView { - func accessibilityElement(_ name: String, path: String = "value|some", - type: T.Type, call: String) throws -> T { + func v2AccessibilityElement(_ name: String, path: String = "value|some", + type: T.Type, call: String) throws -> T { let item = try modifierAttribute( modifierName: "AccessibilityAttachmentModifier", path: "modifier|attachment|some|properties|plist|elements|some", type: Any.self, call: call) - guard let attribute = lookupAttributeWithName(name, item: item), + guard let attribute = v2LookupAttributeWithName(name, item: item), let value = try? Inspector.attribute(path: path, value: attribute) as? T else { throw InspectionError.modifierNotFound(parent: Inspector.typeName(value: content.view), modifier: call, index: 0) @@ -108,18 +182,18 @@ private extension InspectableView { return value } - func lookupAttributeWithName(_ name: String, item: Any) -> Any? { + func v2LookupAttributeWithName(_ name: String, item: Any) -> Any? { if Inspector.typeName(value: item).contains(name) { return item } if let nextItem = try? Inspector.attribute(path: "super|after|some", value: item) { - return lookupAttributeWithName(name, item: nextItem) + return v2LookupAttributeWithName(name, item: nextItem) } return nil } - func accessibilityAction(name: String, path: String, type: T.Type, call: String) throws -> T { - let actionHandlers = try accessibilityElement( + func v2AccessibilityAction(name: String, path: String, type: T.Type, call: String) throws -> T { + let actionHandlers = try v2AccessibilityElement( "ActionsKey", path: "value", type: [Any].self, call: call) guard let handler = actionHandlers.first(where: { handler -> Bool in From a1c20d059a40f7e28ad698784afca649eb3d5063 Mon Sep 17 00:00:00 2001 From: Alexey Naumov Date: Tue, 24 Aug 2021 23:00:31 +0600 Subject: [PATCH 23/99] Fix accessibilityValue extraction, add iOS 15 tests --- .../Modifiers/AccessibilityModifiers.swift | 11 ++++-- .../AccessibilityModifiersTests.swift | 36 +++++++++++++++---- 2 files changed, 38 insertions(+), 9 deletions(-) diff --git a/Sources/ViewInspector/Modifiers/AccessibilityModifiers.swift b/Sources/ViewInspector/Modifiers/AccessibilityModifiers.swift index 20a69310..f069c683 100644 --- a/Sources/ViewInspector/Modifiers/AccessibilityModifiers.swift +++ b/Sources/ViewInspector/Modifiers/AccessibilityModifiers.swift @@ -22,7 +22,8 @@ public extension InspectableView { let text: Text if #available(iOS 15.0, tvOS 15.0, *) { text = try v3AccessibilityElement( - type: Text.self, call: "accessibilityValue", { $0.accessibilityValue("") }) + path: "some|description|some", type: Text.self, + call: "accessibilityValue", { $0.accessibilityValue("") }) } else { text = try v2AccessibilityElement( "TypedValueKey", path: "value|some|description|some", @@ -139,7 +140,7 @@ private struct AccessibilityProperty { @available(iOS 15.0, tvOS 15.0, macOS 10.15, *) private extension InspectableView { func v3AccessibilityElement( - type: T.Type, call: String, _ reference: (EmptyView) -> V + path: String? = nil, type: T.Type, call: String, _ reference: (EmptyView) -> V ) throws -> T where V: SwiftUI.View { let noiseValues = AccessibilityProperty.noisePointerValues guard let referenceValue = try reference(EmptyView()).inspect() @@ -153,7 +154,11 @@ private extension InspectableView { .modifierNotFound(parent: Inspector.typeName(value: content.view), modifier: call, index: 0) } - return try Inspector.cast(value: property.value, type: T.self) + if let path = path { + return try Inspector.attribute(path: path, value: property.value, type: T.self) + } else { + return try Inspector.cast(value: property.value, type: T.self) + } } func v3AccessibilityProperties(call: String) throws -> [AccessibilityProperty] { diff --git a/Tests/ViewInspectorTests/ViewModifiers/AccessibilityModifiersTests.swift b/Tests/ViewInspectorTests/ViewModifiers/AccessibilityModifiersTests.swift index a3a80c18..f2c69f8e 100644 --- a/Tests/ViewInspectorTests/ViewModifiers/AccessibilityModifiersTests.swift +++ b/Tests/ViewInspectorTests/ViewModifiers/AccessibilityModifiersTests.swift @@ -15,9 +15,17 @@ final class ViewAccessibilityTests: XCTestCase { func testAccessibilityLabelInspection() throws { let string = "abc" - let sut = try EmptyView().accessibility(label: Text(string)) + let sut1 = try EmptyView().accessibility(label: Text(string)) .inspect().emptyView().accessibilityLabel().string() - XCTAssertEqual(sut, string) + XCTAssertEqual(sut1, string) + if #available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *) { + let sut2 = try EmptyView().accessibilityLabel(Text(string)) + .inspect().emptyView().accessibilityLabel().string() + let sut3 = try EmptyView().accessibilityLabel(string) + .inspect().emptyView().accessibilityLabel().string() + XCTAssertEqual(sut2, string) + XCTAssertEqual(sut3, string) + } } func testAccessibilityValue() throws { @@ -27,9 +35,17 @@ final class ViewAccessibilityTests: XCTestCase { func testAccessibilityValueInspection() throws { let string = "abc" - let sut = try EmptyView().accessibility(value: Text(string)) + let sut1 = try EmptyView().accessibility(value: Text(string)) .inspect().emptyView().accessibilityValue().string() - XCTAssertEqual(sut, string) + XCTAssertEqual(sut1, string) + if #available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *) { + let sut2 = try EmptyView().accessibilityValue(Text(string)) + .inspect().emptyView().accessibilityValue().string() + let sut3 = try EmptyView().accessibilityValue(string) + .inspect().emptyView().accessibilityValue().string() + XCTAssertEqual(sut2, string) + XCTAssertEqual(sut3, string) + } } func testAccessibilityHint() throws { @@ -39,9 +55,17 @@ final class ViewAccessibilityTests: XCTestCase { func testAccessibilityHintInspection() throws { let string = "abc" - let sut = try EmptyView().accessibility(hint: Text(string)) + let sut1 = try EmptyView().accessibility(hint: Text(string)) .inspect().emptyView().accessibilityHint().string() - XCTAssertEqual(sut, string) + XCTAssertEqual(sut1, string) + if #available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *) { + let sut2 = try EmptyView().accessibilityHint(Text(string)) + .inspect().emptyView().accessibilityHint().string() + let sut3 = try EmptyView().accessibilityHint(string) + .inspect().emptyView().accessibilityHint().string() + XCTAssertEqual(sut2, string) + XCTAssertEqual(sut3, string) + } } func testAccessibilityHidden() throws { From 0bd1b59ad5113b7fcaf66011263c47eb71a6c38c Mon Sep 17 00:00:00 2001 From: Alexey Naumov Date: Tue, 24 Aug 2021 23:09:54 +0600 Subject: [PATCH 24/99] Fix accessibilityHidden --- .../Modifiers/AccessibilityModifiers.swift | 21 ++++++++++++------- .../AccessibilityModifiersTests.swift | 8 +++++++ 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/Sources/ViewInspector/Modifiers/AccessibilityModifiers.swift b/Sources/ViewInspector/Modifiers/AccessibilityModifiers.swift index f069c683..cba87e28 100644 --- a/Sources/ViewInspector/Modifiers/AccessibilityModifiers.swift +++ b/Sources/ViewInspector/Modifiers/AccessibilityModifiers.swift @@ -47,13 +47,20 @@ public extension InspectableView { } func accessibilityHidden() throws -> Bool { - let visibility = try v2AccessibilityElement( - "VisibilityKey", path: "value", type: (Any?).self, call: "accessibility(hidden:)") - switch visibility { - case let .some(value): - return String(describing: value) == "hidden" - case .none: - return false + if #available(iOS 15.0, tvOS 15.0, *) { + let value = try v3AccessibilityElement( + path: "value|rawValue", type: UInt32.self, + call: "accessibilityHidden", { $0.accessibilityHidden(true) }) + return value != 0 + } else { + let visibility = try v2AccessibilityElement( + "VisibilityKey", path: "value", type: (Any?).self, call: "accessibility(hidden:)") + switch visibility { + case let .some(value): + return String(describing: value) == "hidden" + case .none: + return false + } } } diff --git a/Tests/ViewInspectorTests/ViewModifiers/AccessibilityModifiersTests.swift b/Tests/ViewInspectorTests/ViewModifiers/AccessibilityModifiersTests.swift index f2c69f8e..25851d26 100644 --- a/Tests/ViewInspectorTests/ViewModifiers/AccessibilityModifiersTests.swift +++ b/Tests/ViewInspectorTests/ViewModifiers/AccessibilityModifiersTests.swift @@ -80,6 +80,14 @@ final class ViewAccessibilityTests: XCTestCase { let sut2 = try EmptyView().accessibility(hidden: false) .inspect().emptyView().accessibilityHidden() XCTAssertFalse(sut2) + if #available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *) { + let sut3 = try EmptyView().accessibilityHidden(true) + .inspect().emptyView().accessibilityHidden() + let sut4 = try EmptyView().accessibilityHidden(false) + .inspect().emptyView().accessibilityHidden() + XCTAssertTrue(sut3) + XCTAssertFalse(sut4) + } } func testAccessibilityIdentifier() throws { From fa6b6361d05bd8461bd4a6f86a205d6d4b3833b7 Mon Sep 17 00:00:00 2001 From: Alexey Naumov Date: Tue, 24 Aug 2021 23:25:55 +0600 Subject: [PATCH 25/99] Fix three more accessibility modifier tests --- .../Modifiers/AccessibilityModifiers.swift | 19 +++++++++++++++-- .../AccessibilityModifiersTests.swift | 21 +++++++++++++++---- 2 files changed, 34 insertions(+), 6 deletions(-) diff --git a/Sources/ViewInspector/Modifiers/AccessibilityModifiers.swift b/Sources/ViewInspector/Modifiers/AccessibilityModifiers.swift index cba87e28..1b34ddba 100644 --- a/Sources/ViewInspector/Modifiers/AccessibilityModifiers.swift +++ b/Sources/ViewInspector/Modifiers/AccessibilityModifiers.swift @@ -65,10 +65,19 @@ public extension InspectableView { } func accessibilityIdentifier() throws -> String { - return try v2AccessibilityElement( + if #available(iOS 15.0, tvOS 15.0, *) { + return try v3AccessibilityElement(type: String.self, + call: "accessibilityIdentifier", { $0.accessibilityIdentifier("") }) + } else { + return try v2AccessibilityElement( "IdentifierKey", type: String.self, call: "accessibility(identifier:)") + } } + @available(iOS, deprecated, introduced: 13.0) + @available(macOS, deprecated, introduced: 10.15) + @available(tvOS, deprecated, introduced: 13.0) + @available(watchOS, deprecated, introduced: 6) func accessibilitySelectionIdentifier() throws -> AnyHashable { return try v2AccessibilityElement( "SelectionIdentifierKey", type: AnyHashable.self, @@ -76,9 +85,15 @@ public extension InspectableView { } func accessibilityActivationPoint() throws -> UnitPoint { - return try v2AccessibilityElement( + if #available(iOS 15.0, tvOS 15.0, *) { + return try v3AccessibilityElement( + path: "some|unitPoint", type: UnitPoint.self, + call: "accessibilityIdentifier", { $0.accessibilityActivationPoint(.center) }) + } else { + return try v2AccessibilityElement( "ActivationPointKey", path: "value|some|unitPoint", type: UnitPoint.self, call: "accessibility(activationPoint:)") + } } func callAccessibilityAction(_ kind: AccessibilityActionKind) throws { diff --git a/Tests/ViewInspectorTests/ViewModifiers/AccessibilityModifiersTests.swift b/Tests/ViewInspectorTests/ViewModifiers/AccessibilityModifiersTests.swift index 25851d26..a79e6e09 100644 --- a/Tests/ViewInspectorTests/ViewModifiers/AccessibilityModifiersTests.swift +++ b/Tests/ViewInspectorTests/ViewModifiers/AccessibilityModifiersTests.swift @@ -97,9 +97,14 @@ final class ViewAccessibilityTests: XCTestCase { func testAccessibilityIdentifierInspection() throws { let string = "abc" - let sut = try EmptyView().accessibility(identifier: string) + let sut1 = try EmptyView().accessibility(identifier: string) .inspect().emptyView().accessibilityIdentifier() - XCTAssertEqual(sut, string) + XCTAssertEqual(sut1, string) + if #available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *) { + let sut2 = try EmptyView().accessibilityIdentifier(string) + .inspect().emptyView().accessibilityIdentifier() + XCTAssertEqual(sut2, string) + } } @available(iOS, deprecated, introduced: 13.0) @@ -116,6 +121,9 @@ final class ViewAccessibilityTests: XCTestCase { @available(macOS, deprecated, introduced: 10.15) func testAccessibilitySelectionIdentifierInspection() throws { guard #available(iOS 13.2, macOS 10.17, tvOS 13.2, *) else { return } + if #available(iOS 15, tvOS 15, *) { + throw XCTSkip("Deprecated modifier with no replacement in iOS 15") + } let string = "abc" let sut = try EmptyView().accessibility(selectionIdentifier: string) .inspect().emptyView().accessibilitySelectionIdentifier() @@ -129,9 +137,14 @@ final class ViewAccessibilityTests: XCTestCase { func testAccessibilityActivationPointInspection() throws { let point: UnitPoint = .bottomTrailing - let sut = try EmptyView().accessibility(activationPoint: point) + let sut1 = try EmptyView().accessibility(activationPoint: point) .inspect().emptyView().accessibilityActivationPoint() - XCTAssertEqual(sut, point) + XCTAssertEqual(sut1, point) + if #available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *) { + let sut2 = try EmptyView().accessibilityActivationPoint(point) + .inspect().emptyView().accessibilityActivationPoint() + XCTAssertEqual(sut2, point) + } } func testAccessibilityAction() throws { From 92187d79a1adba215c3ac1341658b52847e92b85 Mon Sep 17 00:00:00 2001 From: Alexey Naumov Date: Thu, 26 Aug 2021 01:16:10 +0600 Subject: [PATCH 26/99] Fix remaning accessibility tests --- .../Modifiers/AccessibilityModifiers.swift | 211 +++++++++++++----- .../AccessibilityModifiersTests.swift | 9 + readiness.md | 34 +-- 3 files changed, 186 insertions(+), 68 deletions(-) diff --git a/Sources/ViewInspector/Modifiers/AccessibilityModifiers.swift b/Sources/ViewInspector/Modifiers/AccessibilityModifiers.swift index 1b34ddba..e91752c3 100644 --- a/Sources/ViewInspector/Modifiers/AccessibilityModifiers.swift +++ b/Sources/ViewInspector/Modifiers/AccessibilityModifiers.swift @@ -7,12 +7,12 @@ public extension InspectableView { func accessibilityLabel() throws -> InspectableView { let text: Text - if #available(iOS 15.0, tvOS 15.0, *) { + let call = "accessibilityLabel" + if #available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) { text = try v3AccessibilityElement( - type: Text.self, call: "accessibilityLabel", { $0.accessibilityLabel("") }) + type: Text.self, call: call, { $0.accessibilityLabel("") }) } else { - text = try v2AccessibilityElement( - "LabelKey", type: Text.self, call: "accessibilityLabel") + text = try v2AccessibilityElement("LabelKey", type: Text.self, call: call) } let medium = content.medium.resettingViewModifiers() return try .init(try Inspector.unwrap(content: Content(text, medium: medium)), parent: self) @@ -20,14 +20,14 @@ public extension InspectableView { func accessibilityValue() throws -> InspectableView { let text: Text - if #available(iOS 15.0, tvOS 15.0, *) { + let call = "accessibilityValue" + if #available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) { text = try v3AccessibilityElement( path: "some|description|some", type: Text.self, - call: "accessibilityValue", { $0.accessibilityValue("") }) + call: call, { $0.accessibilityValue("") }) } else { text = try v2AccessibilityElement( - "TypedValueKey", path: "value|some|description|some", - type: Text.self, call: "accessibilityValue") + "TypedValueKey", path: "value|some|description|some", type: Text.self, call: call) } let medium = content.medium.resettingViewModifiers() return try .init(try Inspector.unwrap(content: Content(text, medium: medium)), parent: self) @@ -35,26 +35,27 @@ public extension InspectableView { func accessibilityHint() throws -> InspectableView { let text: Text - if #available(iOS 15.0, tvOS 15.0, *) { + let call = "accessibilityHint" + if #available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) { text = try v3AccessibilityElement( - type: Text.self, call: "accessibilityHint", { $0.accessibilityHint("") }) + type: Text.self, call: call, { $0.accessibilityHint("") }) } else { - text = try v2AccessibilityElement( - "HintKey", type: Text.self, call: "accessibilityHint") + text = try v2AccessibilityElement("HintKey", type: Text.self, call: call) } let medium = content.medium.resettingViewModifiers() return try .init(try Inspector.unwrap(content: Content(text, medium: medium)), parent: self) } func accessibilityHidden() throws -> Bool { - if #available(iOS 15.0, tvOS 15.0, *) { + let call = "accessibilityHidden" + if #available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) { let value = try v3AccessibilityElement( path: "value|rawValue", type: UInt32.self, - call: "accessibilityHidden", { $0.accessibilityHidden(true) }) + call: call, { $0.accessibilityHidden(true) }) return value != 0 } else { let visibility = try v2AccessibilityElement( - "VisibilityKey", path: "value", type: (Any?).self, call: "accessibility(hidden:)") + "VisibilityKey", path: "value", type: (Any?).self, call: call) switch visibility { case let .some(value): return String(describing: value) == "hidden" @@ -65,12 +66,22 @@ public extension InspectableView { } func accessibilityIdentifier() throws -> String { - if #available(iOS 15.0, tvOS 15.0, *) { - return try v3AccessibilityElement(type: String.self, - call: "accessibilityIdentifier", { $0.accessibilityIdentifier("") }) + let call = "accessibilityIdentifier" + if #available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) { + return try v3AccessibilityElement( + type: String.self, call: call, { $0.accessibilityIdentifier("") }) } else { - return try v2AccessibilityElement( - "IdentifierKey", type: String.self, call: "accessibility(identifier:)") + return try v2AccessibilityElement("IdentifierKey", type: String.self, call: call) + } + } + + func accessibilitySortPriority() throws -> Double { + let call = "accessibilitySortPriority" + if #available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) { + return try v3AccessibilityElement( + type: Double.self, call: call, { $0.accessibilitySortPriority(0) }) + } else { + return try v2AccessibilityElement("SortPriorityKey", type: Double.self, call: call) } } @@ -85,7 +96,7 @@ public extension InspectableView { } func accessibilityActivationPoint() throws -> UnitPoint { - if #available(iOS 15.0, tvOS 15.0, *) { + if #available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) { return try v3AccessibilityElement( path: "some|unitPoint", type: UnitPoint.self, call: "accessibilityIdentifier", { $0.accessibilityActivationPoint(.center) }) @@ -96,43 +107,89 @@ public extension InspectableView { } } + func callAccessibilityAction(_ named: S) throws where S: StringProtocol { + try callAccessibilityAction(AccessibilityActionKind(named: Text(named))) + } + func callAccessibilityAction(_ kind: AccessibilityActionKind) throws { - let kindString = String(describing: kind) - let shortName = kindString - .components(separatedBy: CharacterSet(charactersIn: ".)")) - .filter { $0.count > 0 }.last! - let call = "accessibilityAction(.\(shortName))" + let shortName: String = { + if let name = try? kind.name().string() { + return "named: \"\(name)\"" + } + return "." + String(describing: kind) + .components(separatedBy: CharacterSet(charactersIn: ".)")) + .filter { $0.count > 0 }.last! + }() + let call = "accessibilityAction(\(shortName))" typealias Callback = (()) -> Void - let callback = try v2AccessibilityAction(name: kindString, path: "box|action|kind", - type: Callback.self, call: call) + let callback: Callback + if #available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) { + callback = try v3AccessibilityAction(kind: kind, type: Callback.self, call: call) + } else { + callback = try v2AccessibilityAction(kind: kind, type: Callback.self, call: call) + } callback(()) } func callAccessibilityAdjustableAction(_ direction: AccessibilityAdjustmentDirection = .increment) throws { typealias Callback = (AccessibilityAdjustmentDirection) -> Void - let callback = try v2AccessibilityAction( - name: "AccessibilityAdjustableAction()", path: "box|action", - type: Callback.self, call: "accessibilityAdjustableAction") + let callback: Callback + if #available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) { + callback = try v3AccessibilityAction( + name: "AccessibilityAdjustableAction", + type: Callback.self, + call: "accessibilityAdjustableAction") + } else { + callback = try v2AccessibilityAction( + name: "AccessibilityAdjustableAction()", + type: Callback.self, + call: "accessibilityAdjustableAction") + } callback(direction) } func callAccessibilityScrollAction(_ edge: Edge) throws { typealias Callback = (Edge) -> Void - let callback = try v2AccessibilityAction( - name: "AccessibilityScrollAction()", path: "box|action", - type: Callback.self, call: "accessibilityScrollAction") + let callback: Callback + if #available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) { + callback = try v3AccessibilityAction( + name: "AccessibilityScrollAction", + type: Callback.self, + call: "accessibilityScrollAction") + } else { + callback = try v2AccessibilityAction( + name: "AccessibilityScrollAction()", + type: Callback.self, + call: "accessibilityScrollAction") + } callback(edge) } - - func accessibilitySortPriority() throws -> Double { - return try v2AccessibilityElement( - "SortPriorityKey", type: Double.self, call: "accessibility(sortPriority:)") - } } // MARK: - Private -@available(iOS 15.0, tvOS 15.0, macOS 10.15, *) +@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) +private extension AccessibilityActionKind { + func name() throws -> InspectableView { + let view: Any = try { + if let view = try? Inspector.attribute(path: "kind|named", value: self) { + return view + } + return try Inspector.attribute(path: "kind|custom", value: self) + }() + return try .init(Content(view), parent: nil, index: nil) + } + + func isEqual(to other: AccessibilityActionKind) -> Bool { + if let lhsName = try? self.name().string(), + let rhsName = try? other.name().string() { + return lhsName == rhsName + } + return self == other + } +} + +@available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) private struct AccessibilityProperty { let keyPointerValue: UInt64 @@ -145,8 +202,8 @@ private struct AccessibilityProperty { } static var noisePointerValues: Set = { - let view1 = EmptyView().accessibilityLabel(Text("")) - let view2 = EmptyView().accessibilityHint(Text("")) + let view1 = EmptyView().accessibility(label: Text("")) + let view2 = EmptyView().accessibility(hint: Text("")) do { let props1 = try view1.inspect() .v3AccessibilityProperties(call: "") @@ -159,7 +216,7 @@ private struct AccessibilityProperty { }() } -@available(iOS 15.0, tvOS 15.0, macOS 10.15, *) +@available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) private extension InspectableView { func v3AccessibilityElement( path: String? = nil, type: T.Type, call: String, _ reference: (EmptyView) -> V @@ -178,9 +235,51 @@ private extension InspectableView { } if let path = path { return try Inspector.attribute(path: path, value: property.value, type: T.self) - } else { - return try Inspector.cast(value: property.value, type: T.self) } + return try Inspector.cast(value: property.value, type: T.self) + } + + func v3AccessibilityAction(kind: AccessibilityActionKind, type: T.Type, call: String) throws -> T { + return try v3AccessibilityAction(trait: { action in + try Inspector.attribute( + path: "action|kind", value: action, type: AccessibilityActionKind.self) + .isEqual(to: kind) + }, type: type, call: call) + } + + func v3AccessibilityAction(name: String, type: T.Type, call: String) throws -> T { + return try v3AccessibilityAction(trait: { action in + Inspector.typeName(value: action).contains(name) + }, type: type, call: call) + } + + func v3AccessibilityAction(trait: (Any) throws -> Bool, type: T.Type, call: String) throws -> T { + let actions = try v3AccessibilityActions(call: call) + guard let action = actions.first(where: { (try? trait($0)) == true }) else { + throw InspectionError + .modifierNotFound(parent: Inspector.typeName(value: content.view), + modifier: call, index: 0) + } + return try Inspector.attribute(label: "handler", value: action, type: T.self) + } + + func v3AccessibilityActions(call: String) throws -> [Any] { + let noiseValues = AccessibilityProperty.noisePointerValues + guard let referenceValue = try EmptyView().accessibilityAction(.default, { }) + .inspect() + .v3AccessibilityProperties(call: call) + .map({ $0.keyPointerValue }) + .first(where: { !noiseValues.contains($0) }) + else { + throw InspectionError + .modifierNotFound(parent: Inspector.typeName(value: content.view), + modifier: call, index: 0) + } + return try v3AccessibilityProperties(call: call) + .filter({ $0.keyPointerValue == referenceValue }) + .compactMap { $0.value as? [Any] } + .flatMap { $0 } + .map { try Inspector.attribute(path: "base|base", value: $0) } } func v3AccessibilityProperties(call: String) throws -> [AccessibilityProperty] { @@ -218,16 +317,26 @@ private extension InspectableView { } return nil } + + func v2AccessibilityAction(kind: AccessibilityActionKind, type: T.Type, call: String) throws -> T { + return try v2AccessibilityAction(type: type, call: call, trait: { handler in + try Inspector.attribute(path: "box|action|kind", value: handler, type: AccessibilityActionKind.self) + .isEqual(to: kind) + }) + } + func v2AccessibilityAction(name: String, type: T.Type, call: String) throws -> T { + return try v2AccessibilityAction(type: type, call: call, trait: { handler in + let actionName = try Inspector.attribute(path: "box|action", value: handler) + return name == String(describing: actionName) + }) + } - func v2AccessibilityAction(name: String, path: String, type: T.Type, call: String) throws -> T { + func v2AccessibilityAction(type: T.Type, call: String, trait: (Any) throws -> Bool) throws -> T { let actionHandlers = try v2AccessibilityElement( "ActionsKey", path: "value", type: [Any].self, call: call) - guard let handler = actionHandlers.first(where: { handler -> Bool in - guard let actionName = try? Inspector.attribute(path: path, value: handler) - else { return false } - return name == String(describing: actionName) - }), let callback = try? Inspector.attribute(path: "box|handler", value: handler) as? T + guard let handler = actionHandlers.first(where: { (try? trait($0)) == true }), + let callback = try? Inspector.attribute(path: "box|handler", value: handler) as? T else { throw InspectionError.modifierNotFound(parent: Inspector.typeName(value: content.view), modifier: call, index: 0) diff --git a/Tests/ViewInspectorTests/ViewModifiers/AccessibilityModifiersTests.swift b/Tests/ViewInspectorTests/ViewModifiers/AccessibilityModifiersTests.swift index a79e6e09..fc00d4c2 100644 --- a/Tests/ViewInspectorTests/ViewModifiers/AccessibilityModifiersTests.swift +++ b/Tests/ViewInspectorTests/ViewModifiers/AccessibilityModifiersTests.swift @@ -153,11 +153,17 @@ final class ViewAccessibilityTests: XCTestCase { } func testAccessibilityActionInspection() throws { + guard #available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *) + else { return } let exp = XCTestExpectation(description: "accessibilityAction") + exp.expectedFulfillmentCount = 2 let sut = EmptyView().accessibilityAction(.default) { exp.fulfill() + }.accessibilityAction(named: "custom") { + exp.fulfill() } try sut.inspect().emptyView().callAccessibilityAction(.default) + try sut.inspect().emptyView().callAccessibilityAction("custom") wait(for: [exp], timeout: 0.1) } @@ -166,6 +172,9 @@ final class ViewAccessibilityTests: XCTestCase { XCTAssertThrows( try sut.inspect().emptyView().callAccessibilityAction(.default), "EmptyView does not have 'accessibilityAction(.default)' modifier") + XCTAssertThrows( + try sut.inspect().emptyView().callAccessibilityAction(.init(named: Text("123"))), + "EmptyView does not have 'accessibilityAction(named: \"123\")' modifier") } func testAccessibilityActionInspectionMultipleCallbacks() throws { diff --git a/readiness.md b/readiness.md index ce962264..883d3ea4 100644 --- a/readiness.md +++ b/readiness.md @@ -590,28 +590,28 @@ Visit [this discussion](https://github.com/nalexn/ViewInspector/discussions/60) | Status | Modifier | |:---:|---| -|:technologist:| `func accessibilityLabel(S) -> ModifiedContent` | -|:technologist:| `func accessibilityLabel(Text) -> ModifiedContent` | -|:technologist:| `func accessibilityLabel(LocalizedStringKey) -> ModifiedContent` | -|:technologist:| `func accessibilityValue(S) -> ModifiedContent` | -|:technologist:| `func accessibilityValue(LocalizedStringKey) -> ModifiedContent` | -|:technologist:| `func accessibilityValue(Text) -> ModifiedContent` | -|:technologist:| `func accessibilityHidden(Bool) -> ModifiedContent` | -|:technologist:| `func accessibilityIdentifier(String) -> ModifiedContent` | +|:white_check_mark:| `func accessibilityLabel(S) -> ModifiedContent` | +|:white_check_mark:| `func accessibilityLabel(Text) -> ModifiedContent` | +|:white_check_mark:| `func accessibilityLabel(LocalizedStringKey) -> ModifiedContent` | +|:white_check_mark:| `func accessibilityValue(S) -> ModifiedContent` | +|:white_check_mark:| `func accessibilityValue(LocalizedStringKey) -> ModifiedContent` | +|:white_check_mark:| `func accessibilityValue(Text) -> ModifiedContent` | +|:white_check_mark:| `func accessibilityHidden(Bool) -> ModifiedContent` | +|:white_check_mark:| `func accessibilityIdentifier(String) -> ModifiedContent` | ### Customizing Accessibility Interactions of a View | Status | Modifier | |:---:|---| -|:technologist:| `func accessibilityHint(LocalizedStringKey) -> ModifiedContent` | -|:technologist:| `func accessibilityHint(Text) -> ModifiedContent` | -|:technologist:| `func accessibilityHint(S) -> ModifiedContent` | -|:technologist:| `func accessibilityActivationPoint(CGPoint) -> ModifiedContent` | -|:technologist:| `func accessibilityActivationPoint(UnitPoint) -> ModifiedContent` | +|:white_check_mark:| `func accessibilityHint(LocalizedStringKey) -> ModifiedContent` | +|:white_check_mark:| `func accessibilityHint(Text) -> ModifiedContent` | +|:white_check_mark:| `func accessibilityHint(S) -> ModifiedContent` | +|:white_check_mark:| `func accessibilityActivationPoint(CGPoint) -> ModifiedContent` | +|:white_check_mark:| `func accessibilityActivationPoint(UnitPoint) -> ModifiedContent` | |:white_check_mark:| `func accessibilityAction(AccessibilityActionKind, () -> Void) -> ModifiedContent` | -|:heavy_check_mark:| `func accessibilityAction(named: Text, () -> Void) -> ModifiedContent` | -|:technologist:| `func accessibilityAction(named: S, () -> Void) -> ModifiedContent` | -|:technologist:| `func accessibilityAction(named: LocalizedStringKey, () -> Void) -> ModifiedContent` | +|:white_check_mark:| `func accessibilityAction(named: Text, () -> Void) -> ModifiedContent` | +|:white_check_mark:| `func accessibilityAction(named: S, () -> Void) -> ModifiedContent` | +|:white_check_mark:| `func accessibilityAction(named: LocalizedStringKey, () -> Void) -> ModifiedContent` | |:white_check_mark:| `func accessibilityAdjustableAction((AccessibilityAdjustmentDirection) -> Void) -> ModifiedContent` | |:white_check_mark:| `func accessibilityScrollAction((Edge) -> Void) -> ModifiedContent` | |:technologist:| `func accessibilityIgnoresInvertColors(Bool) -> some View` | @@ -627,7 +627,7 @@ Visit [this discussion](https://github.com/nalexn/ViewInspector/discussions/60) |:technologist:| `func accessibilityInputLabels([Text]) -> ModifiedContent` | |:technologist:| `func accessibilityAddTraits(AccessibilityTraits) -> ModifiedContent` | |:technologist:| `func accessibilityRemoveTraits(AccessibilityTraits) -> ModifiedContent` | -|:technologist:| `func accessibilitySortPriority(Double) -> ModifiedContent` |` | +|:white_check_mark:| `func accessibilitySortPriority(Double) -> ModifiedContent` |` | |:technologist:| `func accessibilityLinkedGroup(id: ID, in: Namespace.ID) -> some View` | ### Customizing the Help Text of a View From f4041808a719005d99c863aa1f3997c945383ea2 Mon Sep 17 00:00:00 2001 From: Alexey Naumov Date: Thu, 26 Aug 2021 01:17:30 +0600 Subject: [PATCH 27/99] Fix compilation issues on macOS --- Sources/ViewInspector/Modifiers/EnvironmentModifiers.swift | 2 ++ Sources/ViewInspector/SwiftUI/Button.swift | 2 +- Sources/ViewInspector/SwiftUI/TabView.swift | 2 +- Sources/ViewInspector/SwiftUI/Toggle.swift | 2 +- Tests/ViewInspectorTests/BaseTypesTests.swift | 2 +- .../ViewModifiers/InteractionModifiersTests.swift | 6 +++--- 6 files changed, 9 insertions(+), 7 deletions(-) diff --git a/Sources/ViewInspector/Modifiers/EnvironmentModifiers.swift b/Sources/ViewInspector/Modifiers/EnvironmentModifiers.swift index 01fc17c4..ad6bf8d8 100644 --- a/Sources/ViewInspector/Modifiers/EnvironmentModifiers.swift +++ b/Sources/ViewInspector/Modifiers/EnvironmentModifiers.swift @@ -69,6 +69,7 @@ extension _EnvironmentKeyWritingModifier: EnvironmentModifier { } } +#if !os(macOS) @available(iOS 15.0, tvOS 15.0, watchOS 8.0, *) @available(macOS, unavailable) extension _EnvironmentKeyTransformModifier: EnvironmentModifier where Value == TextInputAutocapitalization { @@ -81,3 +82,4 @@ extension _EnvironmentKeyTransformModifier: EnvironmentModifier where Value == T return try Inspector.attribute(label: "transform", value: self) } } +#endif diff --git a/Sources/ViewInspector/SwiftUI/Button.swift b/Sources/ViewInspector/SwiftUI/Button.swift index 91fa22c3..0e0bfebb 100644 --- a/Sources/ViewInspector/SwiftUI/Button.swift +++ b/Sources/ViewInspector/SwiftUI/Button.swift @@ -33,7 +33,7 @@ public extension InspectableView where View: MultipleViewContent { @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) extension ViewType.Button: SupplementaryChildrenLabelView { static var labelViewPath: String { - if #available(iOS 15.0, tvOS 15.0, *) { + if #available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) { return "label" } else { return "_label" diff --git a/Sources/ViewInspector/SwiftUI/TabView.swift b/Sources/ViewInspector/SwiftUI/TabView.swift index f9e7ec8c..5ec96066 100644 --- a/Sources/ViewInspector/SwiftUI/TabView.swift +++ b/Sources/ViewInspector/SwiftUI/TabView.swift @@ -89,7 +89,7 @@ internal extension Content { let medium = self.medium.resettingViewModifiers() let view = try InspectableView( try Inspector.unwrap(content: Content(rootView, medium: medium)), parent: parent, call: "tabItem()") - if #available(iOS 15.0, tvOS 15.0, *) { + if #available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) { return view } else if #available(iOS 14.2, tvOS 14.2, *) { return try InspectableView( diff --git a/Sources/ViewInspector/SwiftUI/Toggle.swift b/Sources/ViewInspector/SwiftUI/Toggle.swift index 55dfcbd8..c831d59b 100644 --- a/Sources/ViewInspector/SwiftUI/Toggle.swift +++ b/Sources/ViewInspector/SwiftUI/Toggle.swift @@ -33,7 +33,7 @@ public extension InspectableView where View: MultipleViewContent { @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) extension ViewType.Toggle: SupplementaryChildrenLabelView { static var labelViewPath: String { - if #available(iOS 15.0, tvOS 15.0, *) { + if #available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) { return "label" } else { return "_label" diff --git a/Tests/ViewInspectorTests/BaseTypesTests.swift b/Tests/ViewInspectorTests/BaseTypesTests.swift index acda8918..a042ebae 100644 --- a/Tests/ViewInspectorTests/BaseTypesTests.swift +++ b/Tests/ViewInspectorTests/BaseTypesTests.swift @@ -51,7 +51,7 @@ func XCTAssertThrows(_ expression: @autoclosure () throws -> T, _ message: St file: StaticString = #file, line: UInt = #line) { do { _ = try expression() - XCTFail("Expression did not throw any error") + XCTFail("Expression did not throw any error", file: file, line: line) } catch let error { XCTAssertEqual(error.localizedDescription, message, file: file, line: line) } diff --git a/Tests/ViewInspectorTests/ViewModifiers/InteractionModifiersTests.swift b/Tests/ViewInspectorTests/ViewModifiers/InteractionModifiersTests.swift index fa16b337..2c3841f5 100644 --- a/Tests/ViewInspectorTests/ViewModifiers/InteractionModifiersTests.swift +++ b/Tests/ViewInspectorTests/ViewModifiers/InteractionModifiersTests.swift @@ -131,16 +131,16 @@ final class InteractionTests: XCTestCase { #if os(macOS) func testOnCommand() throws { - let sut = EmptyView().onCommand(#selector(setUp)) { } + let sut = EmptyView().onCommand(#selector(Self.setUp)) { } XCTAssertNoThrow(try sut.inspect().emptyView()) } func testOnCommandInspection() throws { let exp = XCTestExpectation(description: "onCommand") - let sut = EmptyView().onCommand(#selector(setUp)) { + let sut = EmptyView().onCommand(#selector(Self.setUp)) { exp.fulfill() } - try sut.inspect().emptyView().callOnCommand(#selector(setUp)) + try sut.inspect().emptyView().callOnCommand(#selector(Self.setUp)) wait(for: [exp], timeout: 0.1) } #endif From 13db34a14df4505a8b619c36efbdf1e19d87ae24 Mon Sep 17 00:00:00 2001 From: Alexey Naumov Date: Thu, 26 Aug 2021 01:18:03 +0600 Subject: [PATCH 28/99] Add Toolbar support --- Sources/ViewInspector/BaseTypes.swift | 4 +- Sources/ViewInspector/SwiftUI/Toolbar.swift | 144 ++++++++++++++++++ .../SwiftUI/ToolbarTests.swift | 138 +++++++++++++++++ ViewInspector.xcodeproj/project.pbxproj | 8 + 4 files changed, 292 insertions(+), 2 deletions(-) create mode 100644 Sources/ViewInspector/SwiftUI/Toolbar.swift create mode 100644 Tests/ViewInspectorTests/SwiftUI/ToolbarTests.swift diff --git a/Sources/ViewInspector/BaseTypes.swift b/Sources/ViewInspector/BaseTypes.swift index f39440a7..a6fe4da1 100644 --- a/Sources/ViewInspector/BaseTypes.swift +++ b/Sources/ViewInspector/BaseTypes.swift @@ -281,11 +281,11 @@ extension InspectionError: CustomStringConvertible, LocalizedError { // MARK: - BinaryEquatable @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) -internal protocol BinaryEquatable: Equatable { } +public protocol BinaryEquatable: Equatable { } @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) extension BinaryEquatable { - static func == (lhs: Self, rhs: Self) -> Bool { + public static func == (lhs: Self, rhs: Self) -> Bool { withUnsafeBytes(of: lhs) { lhsBytes -> Bool in withUnsafeBytes(of: rhs) { rhsBytes -> Bool in lhsBytes.elementsEqual(rhsBytes) diff --git a/Sources/ViewInspector/SwiftUI/Toolbar.swift b/Sources/ViewInspector/SwiftUI/Toolbar.swift new file mode 100644 index 00000000..1c187b30 --- /dev/null +++ b/Sources/ViewInspector/SwiftUI/Toolbar.swift @@ -0,0 +1,144 @@ +import SwiftUI + +@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) +public extension ViewType { + + struct Toolbar: KnownViewType { + public static var typePrefix: String = "ToolbarModifier" + } +} + +@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) +public extension ViewType.Toolbar { + struct Item: KnownViewType { + public static var typePrefix: String = "ToolbarItem" + } + struct ItemGroup: KnownViewType { + public static var typePrefix: String = "ToolbarItemGroup" + } +} + +// MARK: - Extraction + +@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) +public extension InspectableView { + + func toolbar(_ index: Int? = nil) throws -> InspectableView { + return try contentForModifierLookup.toolbar(parent: self, index: index) + } +} + +@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) +internal extension Content { + + func toolbar(parent: UnwrappedView, index: Int?) throws -> InspectableView { + let modifier = try self.modifier({ modifier -> Bool in + return modifier.modifierType.contains("ToolbarModifier") + }, call: "toolbar", index: index ?? 0) + let root = try Inspector.attribute(label: "modifier", value: modifier) + let medium = self.medium.resettingViewModifiers() + let content = try Inspector.unwrap(content: Content(root, medium: medium)) + return try .init(content, parent: parent, call: "toolbar", index: index) + } +} + +// MARK: - Content + +@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) +extension ViewType.Toolbar.Item: SingleViewContent { + + public static func child(_ content: Content) throws -> Content { + let view = try Inspector.attribute(label: "content", value: content.view) + return try Inspector.unwrap(view: view, medium: content.medium) + } +} + +@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) +extension ViewType.Toolbar.Item: MultipleViewContent { + + public static func children(_ content: Content) throws -> LazyGroup { + let view = try Inspector.attribute(label: "content", value: content.view) + return try Inspector.viewsInContainer(view: view, medium: content.medium) + } +} + +@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) +extension ViewType.Toolbar.ItemGroup: SingleViewContent { + + public static func child(_ content: Content) throws -> Content { + let view = try Inspector.attribute(label: "content", value: content.view) + return try Inspector.unwrap(view: view, medium: content.medium) + } +} + +@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) +extension ViewType.Toolbar.ItemGroup: MultipleViewContent { + + public static func children(_ content: Content) throws -> LazyGroup { + let view = try Inspector.attribute(label: "content", value: content.view) + return try Inspector.viewsInContainer(view: view, medium: content.medium) + } +} + +// MARK: - Custom Attributes + +@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) +public extension InspectableView where View == ViewType.Toolbar { + + func identifier() throws -> String? { + return try Inspector.attribute( + label: "id", value: content.view, type: String?.self) + } + + func item(_ index: Int = 0) throws -> InspectableView { + let element = try self.element(index) + return try .init(Content(element, medium: content.medium), parent: self, index: index) + } + + func itemGroup(_ index: Int = 0) throws -> InspectableView { + let element = try self.element(index) + return try .init(Content(element, medium: content.medium), parent: self, index: index) + } + + private func element(_ index: Int) throws -> Any { + do { + return try Inspector.attribute(path: "content|value|.\(index)", value: content.view) + } catch { + if index == 0, let value = try? Inspector + .attribute(path: "content|value", value: content.view) { + return value + } + throw InspectionError.viewNotFound(parent: "toolbar item at index \(index)") + } + } +} + +@available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *) +public extension InspectableView where View == ViewType.Toolbar.Item { + + func identifier() throws -> String { + return try Inspector.attribute( + label: "identifier", value: content.view, type: String.self) + } + + func placement() throws -> ToolbarItemPlacement { + return try Inspector.attribute( + label: "placement", value: content.view, type: ToolbarItemPlacement.self) + } + + func showsByDefault() throws -> Bool { + return try Inspector.attribute( + label: "showsByDefault", value: content.view, type: Bool.self) + } +} + +@available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *) +public extension InspectableView where View == ViewType.Toolbar.ItemGroup { + func placement() throws -> ToolbarItemPlacement { + return try Inspector.attribute( + label: "placement", value: content.view, type: ToolbarItemPlacement.self) + } +} + +@available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *) +extension ToolbarItemPlacement: BinaryEquatable { } diff --git a/Tests/ViewInspectorTests/SwiftUI/ToolbarTests.swift b/Tests/ViewInspectorTests/SwiftUI/ToolbarTests.swift new file mode 100644 index 00000000..410b5471 --- /dev/null +++ b/Tests/ViewInspectorTests/SwiftUI/ToolbarTests.swift @@ -0,0 +1,138 @@ +import XCTest +import SwiftUI +@testable import ViewInspector + +@available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *) +final class ToolbarTests: XCTestCase { + + func testToolbarItemPlacementEquatable() throws { + let values: [ToolbarItemPlacement] = [ + .automatic, .principal, .bottomBar, + .primaryAction, .cancellationAction, .confirmationAction, .destructiveAction, + .navigation, .navigationBarLeading, .navigationBarTrailing] + values.enumerated().forEach { lhs in + values.enumerated().forEach { rhs in + if lhs.offset == rhs.offset { + XCTAssertEqual(lhs.element, rhs.element) + } else { + XCTAssertNotEqual(lhs.element, rhs.element) + } + } + } + } + + func testDoesNotBlockInspection() throws { + let sut = Group { + EmptyView().offset().toolbar { Text("") }.padding() + } + XCTAssertNoThrow(try sut.inspect().group().emptyView(0).offset()) + } + + func testSimpleExtraction() throws { + let sut = EmptyView() + .toolbar { ToolbarItem { Text("abc") } } + let text = try sut.inspect().toolbar().item().text().string() + XCTAssertEqual(text, "abc") + } + + func testMultipleToolbarsExtraction() throws { + let sut = EmptyView() + .toolbar { ToolbarItem { Text("abc1") } } + .padding() + .toolbar { ToolbarItem { Text("abc2") } } + let text1 = try sut.inspect().toolbar().item().text().string() + XCTAssertEqual(text1, "abc1") + let text2 = try sut.inspect().toolbar(1).item().text().string() + XCTAssertEqual(text2, "abc2") + } + + func testMultipleItemsExtraction() throws { + let sut = EmptyView() + .toolbar { + ToolbarItem { Text("1") } + ToolbarItemGroup { + Text("2") + } + ToolbarItem { Text("3") } + } + let toolbar = try sut.inspect().toolbar() + XCTAssertEqual(try toolbar.item(0).text().string(), "1") + XCTAssertEqual(try toolbar.itemGroup(1).text().string(), "2") + XCTAssertEqual(try toolbar.item(2).text().string(), "3") + } + + func testMultipleChildViewsExtraction() throws { + let sut = EmptyView() + .toolbar { + ToolbarItem { Text("1"); Text("2") } + ToolbarItemGroup { Text("3"); Text("4") } + } + let item = try sut.inspect().toolbar().item(0) + let itemGroup = try sut.inspect().toolbar().itemGroup(1) + XCTAssertEqual(try item.text(0).string(), "1") + XCTAssertEqual(try item.text(1).string(), "2") + XCTAssertEqual(try itemGroup.text(0).string(), "3") + XCTAssertEqual(try itemGroup.text(1).string(), "4") + XCTAssertThrows(try sut.inspect().toolbar().item(2), + "View for toolbar item at index 2 is absent") + } + + func testImplicitToolbarItemGroup() throws { + let sut = EmptyView().toolbar { Text("abc") } + let text = try sut.inspect().toolbar().itemGroup().text().string() + XCTAssertEqual(text, "abc") + } + + func testToolbarIdentifier() throws { + let sut = EmptyView() + .toolbar { Text("") } + .toolbar(id: "abc") { ToolbarItem(id: "") { Text("") } } + XCTAssertNil(try sut.inspect().toolbar(0).identifier()) + XCTAssertEqual(try sut.inspect().toolbar(1).identifier(), "abc") + } + + func testToolbarItemIdentifier() throws { + let sut = EmptyView().toolbar { + ToolbarItem(id: "abc") { Text("") } + ToolbarItem(id: "xyz") { EmptyView() } + } + XCTAssertEqual(try sut.inspect().toolbar().item(0).identifier(), "abc") + XCTAssertEqual(try sut.inspect().toolbar().item(1).identifier(), "xyz") + XCTAssertThrows(try sut.inspect().toolbar().item(0).id(), + "ToolbarItem does not have 'id' modifier") + } + + func testToolbarItemPlacement() throws { + let sut = EmptyView().toolbar { + ToolbarItem(placement: .destructiveAction) { EmptyView() } + ToolbarItem(placement: .principal) { EmptyView() } + ToolbarItem { EmptyView() } + } + let toolbar = try sut.inspect().toolbar() + XCTAssertEqual(try toolbar.item(0).placement(), .destructiveAction) + XCTAssertEqual(try toolbar.item(1).placement(), .principal) + XCTAssertEqual(try toolbar.item(2).placement(), .automatic) + } + + func testToolbarItemGroupPlacement() throws { + let sut = EmptyView().toolbar { + ToolbarItemGroup(placement: .destructiveAction) { EmptyView() } + ToolbarItemGroup(placement: .principal) { EmptyView() } + ToolbarItemGroup { EmptyView() } + } + let toolbar = try sut.inspect().toolbar() + XCTAssertEqual(try toolbar.itemGroup(0).placement(), .destructiveAction) + XCTAssertEqual(try toolbar.itemGroup(1).placement(), .principal) + XCTAssertEqual(try toolbar.itemGroup(2).placement(), .automatic) + } + + func testToolbarItemShowsByDefault() throws { + let sut = EmptyView().toolbar { + ToolbarItem(id: "", showsByDefault: false) { EmptyView() } + ToolbarItem { EmptyView() } + } + let toolbar = try sut.inspect().toolbar() + XCTAssertFalse(try toolbar.item(0).showsByDefault()) + XCTAssertTrue(try toolbar.item(1).showsByDefault()) + } +} diff --git a/ViewInspector.xcodeproj/project.pbxproj b/ViewInspector.xcodeproj/project.pbxproj index 9f3cf5e9..48d4d354 100644 --- a/ViewInspector.xcodeproj/project.pbxproj +++ b/ViewInspector.xcodeproj/project.pbxproj @@ -26,6 +26,8 @@ 5214800325F4EA4F002D974D /* EnvironmentObjectInjectionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5214800225F4EA4F002D974D /* EnvironmentObjectInjectionTests.swift */; }; 5214802B25F803B7002D974D /* CustomStyleModifiers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5214802A25F803B7002D974D /* CustomStyleModifiers.swift */; }; 5214803A25F803DC002D974D /* CustomStyleModifiersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5214803025F803D5002D974D /* CustomStyleModifiersTests.swift */; }; + 5223540026D62CB2008DA52F /* ToolbarTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 522353FF26D62CB2008DA52F /* ToolbarTests.swift */; }; + 5223540226D63B7A008DA52F /* Toolbar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5223540126D63B79008DA52F /* Toolbar.swift */; }; 5236C34326CDC2F4007432E1 /* UnaryViewAdaptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5236C34226CDC2F4007432E1 /* UnaryViewAdaptor.swift */; }; 52507626264FC0F400ADE4E7 /* Alert.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52507625264FC0F400ADE4E7 /* Alert.swift */; }; 525076282650000600ADE4E7 /* AlertTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 525076272650000600ADE4E7 /* AlertTests.swift */; }; @@ -270,6 +272,8 @@ 5214800225F4EA4F002D974D /* EnvironmentObjectInjectionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EnvironmentObjectInjectionTests.swift; sourceTree = ""; }; 5214802A25F803B7002D974D /* CustomStyleModifiers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomStyleModifiers.swift; sourceTree = ""; }; 5214803025F803D5002D974D /* CustomStyleModifiersTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomStyleModifiersTests.swift; sourceTree = ""; }; + 522353FF26D62CB2008DA52F /* ToolbarTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ToolbarTests.swift; sourceTree = ""; }; + 5223540126D63B79008DA52F /* Toolbar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Toolbar.swift; sourceTree = ""; }; 5236C34226CDC2F4007432E1 /* UnaryViewAdaptor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnaryViewAdaptor.swift; sourceTree = ""; }; 52507625264FC0F400ADE4E7 /* Alert.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Alert.swift; sourceTree = ""; }; 525076272650000600ADE4E7 /* AlertTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertTests.swift; sourceTree = ""; }; @@ -652,6 +656,7 @@ F6C15AC6254EDA79000240F1 /* TextEditor.swift */, F6D933BE2385F5CB00358E0E /* TextField.swift */, F6D933BA2385F42300358E0E /* Toggle.swift */, + 5223540126D63B79008DA52F /* Toolbar.swift */, F639DBC223A7DDA2003A6FED /* TouchBar.swift */, F64A2C6723A3FD3A00A4853A /* TreeView.swift */, F653BDE2255698A6001FA688 /* TupleView.swift */, @@ -759,6 +764,7 @@ F6C15AC0254EDA15000240F1 /* TextEditorTests.swift */, F6D933C02385F62500358E0E /* TextFieldTests.swift */, F6D933BC2385F45A00358E0E /* ToggleTests.swift */, + 522353FF26D62CB2008DA52F /* ToolbarTests.swift */, F639DBC423A7DFA6003A6FED /* TouchBarTests.swift */, F64A2C6923A3FE3100A4853A /* TreeViewTests.swift */, F653BDEC25569D2E001FA688 /* TupleViewTests.swift */, @@ -1001,6 +1007,7 @@ F639DBC323A7DDA2003A6FED /* TouchBar.swift in Sources */, 52507626264FC0F400ADE4E7 /* Alert.swift in Sources */, 5236C34326CDC2F4007432E1 /* UnaryViewAdaptor.swift in Sources */, + 5223540226D63B7A008DA52F /* Toolbar.swift in Sources */, F60EEBD32382EED0007DB53A /* ZStack.swift in Sources */, 5214802B25F803B7002D974D /* CustomStyleModifiers.swift in Sources */, F6ECF6CE23A67C64000FC591 /* SizingModifiers.swift in Sources */, @@ -1195,6 +1202,7 @@ F6A35A4A25B35F710068B8B2 /* LazyGroupTests.swift in Sources */, F60EEBFC2382F004007DB53A /* HStackTests.swift in Sources */, CDA84452262B6A7A00C56C98 /* GestureActionTests.swift in Sources */, + 5223540026D62CB2008DA52F /* ToolbarTests.swift in Sources */, 52F356AC2676940A00695E43 /* MapAnnotationTests.swift in Sources */, F6C15A6B254B669F000240F1 /* MenuTests.swift in Sources */, F64057F1238DBB120029D9BA /* EmptyViewTests.swift in Sources */, From ee47ca551c541e5a254b0361bcb169bb856ffdcb Mon Sep 17 00:00:00 2001 From: Alexey Naumov Date: Mon, 30 Aug 2021 20:16:34 +0600 Subject: [PATCH 29/99] Skip navigationBarItems tests for iOS 15 --- .../SwiftUI/EnvironmentReaderView.swift | 8 +++++++- .../SwiftUI/EnvironmentReaderViewTests.swift | 17 ++++++++++++++++- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/Sources/ViewInspector/SwiftUI/EnvironmentReaderView.swift b/Sources/ViewInspector/SwiftUI/EnvironmentReaderView.swift index 4b899060..b8832472 100644 --- a/Sources/ViewInspector/SwiftUI/EnvironmentReaderView.swift +++ b/Sources/ViewInspector/SwiftUI/EnvironmentReaderView.swift @@ -17,13 +17,19 @@ extension ViewType.EnvironmentReaderView: SingleViewContent { // MARK: - Extraction from SingleViewContent parent -@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) +@available(iOS 13.0, tvOS 13.0, *) +@available(macOS, unavailable) +@available(watchOS, unavailable) public extension InspectableView where View: SingleViewContent { + @available(iOS, deprecated: 100000.0, message: "Please use `toolbar()` for inspecting `navigationBarItems`") + @available(tvOS, deprecated: 100000.0, message: "Please use `toolbar()` for inspecting `navigationBarItems`") func navigationBarItems() throws -> InspectableView { return try navigationBarItems(AnyView.self) } + @available(iOS, deprecated: 100000.0, message: "Please use `toolbar()` for inspecting `navigationBarItems`") + @available(tvOS, deprecated: 100000.0, message: "Please use `toolbar()` for inspecting `navigationBarItems`") func navigationBarItems(_ viewType: V.Type) throws -> InspectableView where V: SwiftUI.View { return try navigationBarItems(viewType: viewType, content: try child()) diff --git a/Tests/ViewInspectorTests/SwiftUI/EnvironmentReaderViewTests.swift b/Tests/ViewInspectorTests/SwiftUI/EnvironmentReaderViewTests.swift index a5bbca0c..962f9eac 100644 --- a/Tests/ViewInspectorTests/SwiftUI/EnvironmentReaderViewTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/EnvironmentReaderViewTests.swift @@ -3,10 +3,17 @@ import SwiftUI @testable import ViewInspector #if os(iOS) || os(tvOS) -@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) +@available(iOS 13.0, tvOS 13.0, *) final class EnvironmentReaderViewTests: XCTestCase { + func skipForiOS15(file: StaticString = #file, line: UInt = #line) throws { + if #available(iOS 15.0, tvOS 15.0, *) { + throw XCTSkip("Not relevant for iOS 15", file: file, line: line) + } + } + func testIncorrectUnwrap() throws { + try skipForiOS15() let view = NavigationView { List { Text("") } .navigationBarItems(trailing: Text("")) @@ -17,6 +24,7 @@ final class EnvironmentReaderViewTests: XCTestCase { } func testUnknownHierarchyTypeUnwrap() throws { + try skipForiOS15() let view = NavigationView { List { Text("") } .navigationBarItems(trailing: Text("")) @@ -27,6 +35,7 @@ final class EnvironmentReaderViewTests: XCTestCase { } func testKnownHierarchyTypeUnwrap() throws { + try skipForiOS15() let string = "abc" let view = NavigationView { List { Text(string) } @@ -39,6 +48,7 @@ final class EnvironmentReaderViewTests: XCTestCase { } func testSearchBlocker() throws { + try skipForiOS15() let view = AnyView(NavigationView { Text("abc") .navigationBarItems(trailing: Text("")) @@ -49,6 +59,7 @@ final class EnvironmentReaderViewTests: XCTestCase { } func testRetainsModifiers() throws { + try skipForiOS15() let view = NavigationView { Text("") .padding() @@ -62,6 +73,7 @@ final class EnvironmentReaderViewTests: XCTestCase { } func testMissingModifier() throws { + try skipForiOS15() let sut = EmptyView().padding() XCTAssertThrows( try sut.inspect().navigationBarItems(), @@ -69,6 +81,7 @@ final class EnvironmentReaderViewTests: XCTestCase { } func testCustomViewUnwrapStepOne() throws { + try skipForiOS15() let sut = TestView() let exp = sut.inspection.inspect { view in XCTAssertThrows(try view.vStack(), @@ -79,6 +92,7 @@ final class EnvironmentReaderViewTests: XCTestCase { } func testCustomViewUnwrapStepTwo() throws { + try skipForiOS15() let sut = TestView() let exp = sut.inspection.inspect { view in XCTAssertThrows(try view.navigationBarItems().vStack(), @@ -89,6 +103,7 @@ final class EnvironmentReaderViewTests: XCTestCase { } func testCustomViewUnwrapStepThree() throws { + try skipForiOS15() let sut = TestView() let exp = sut.inspection.inspect { view in typealias WrappedView = VStack From a4e3004bda41dda77923c7d393bb45a45b0206ea Mon Sep 17 00:00:00 2001 From: Alexey Naumov Date: Mon, 30 Aug 2021 20:36:45 +0600 Subject: [PATCH 30/99] Fix toolbar tests for iOS 14 --- Sources/ViewInspector/SwiftUI/Toolbar.swift | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/Sources/ViewInspector/SwiftUI/Toolbar.swift b/Sources/ViewInspector/SwiftUI/Toolbar.swift index 1c187b30..966c9e9f 100644 --- a/Sources/ViewInspector/SwiftUI/Toolbar.swift +++ b/Sources/ViewInspector/SwiftUI/Toolbar.swift @@ -4,7 +4,7 @@ import SwiftUI public extension ViewType { struct Toolbar: KnownViewType { - public static var typePrefix: String = "ToolbarModifier" + public static var typePrefix: String = "" } } @@ -32,8 +32,14 @@ public extension InspectableView { internal extension Content { func toolbar(parent: UnwrappedView, index: Int?) throws -> InspectableView { + let modifierName: String + if #available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) { + modifierName = "ToolbarModifier" + } else { + modifierName = "_ToolbarItemGroupModifier" + } let modifier = try self.modifier({ modifier -> Bool in - return modifier.modifierType.contains("ToolbarModifier") + return modifier.modifierType.contains(modifierName) }, call: "toolbar", index: index ?? 0) let root = try Inspector.attribute(label: "modifier", value: modifier) let medium = self.medium.resettingViewModifiers() From 7176f97cee1967027d23cc1f024d30d26a2e5246 Mon Sep 17 00:00:00 2001 From: Richard Gist Date: Thu, 2 Sep 2021 16:19:18 -0600 Subject: [PATCH 31/99] Partially adds FullScreenCover. Needs documentation and documentation error. --- .../SwiftUI/FullScreenCover.swift | 181 ++++++++++++++ Sources/ViewInspector/ViewSearchIndex.swift | 5 + .../SwiftUI/FullScreenCoverTests.swift | 236 ++++++++++++++++++ ViewInspector.xcodeproj/project.pbxproj | 8 + 4 files changed, 430 insertions(+) create mode 100644 Sources/ViewInspector/SwiftUI/FullScreenCover.swift create mode 100644 Tests/ViewInspectorTests/SwiftUI/FullScreenCoverTests.swift diff --git a/Sources/ViewInspector/SwiftUI/FullScreenCover.swift b/Sources/ViewInspector/SwiftUI/FullScreenCover.swift new file mode 100644 index 00000000..ca489602 --- /dev/null +++ b/Sources/ViewInspector/SwiftUI/FullScreenCover.swift @@ -0,0 +1,181 @@ +// +// FullScreenCover.swift +// ViewInspector +// +// Created by Richard Gist on 9/2/21. +// + +import SwiftUI + +// MARK: - FullScreenCover + +@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) +public extension ViewType { + + struct FullScreenCover: KnownViewType { + public static var typePrefix: String = "ViewType.FullScreenCover.Container" + public static var namespacedPrefixes: [String] { + return ["ViewInspector." + typePrefix] + } + public static func inspectionCall(typeName: String) -> String { + return "fullScreenCover(\(ViewType.indexPlaceholder))" + } + } +} + +// MARK: - Content Extraction + +@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) +extension ViewType.FullScreenCover: SingleViewContent { + + public static func child(_ content: Content) throws -> Content { + let view = try Inspector.attribute(label: "view", value: content.view) + let medium = content.medium.resettingViewModifiers() + return try Inspector.unwrap(view: view, medium: medium) + } +} + +@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) +extension ViewType.FullScreenCover: MultipleViewContent { + + public static func children(_ content: Content) throws -> LazyGroup { + let view = try Inspector.attribute(label: "view", value: content.view) + let medium = content.medium.resettingViewModifiers() + return try Inspector.viewsInContainer(view: view, medium: medium) + } +} + +// MARK: - Extraction + +@available(iOS 13.0, tvOS 13.0, *) +@available(macOS, unavailable) +public extension InspectableView { + + func fullScreenCover(_ index: Int? = nil) throws -> InspectableView { + return try contentForModifierLookup.fullScreenCover(parent: self, index: index) + } +} + +@available(iOS 13.0, tvOS 13.0, *) +@available(macOS, unavailable) +internal extension Content { + + func fullScreenCover(parent: UnwrappedView, index: Int?) throws -> InspectableView { + guard let fullScreenCoverBuilder = try? self.modifierAttribute( + modifierLookup: { isFullScreenCoverBuilder(modifier: $0) }, path: "modifier", + type: FullScreenCoverBuilder.self, call: "", index: index ?? 0) + else { + _ = try self.modifier({ + $0.modifierType == "IdentifiedPreferenceTransformModifier" + || $0.modifierType.contains("FullScreenCoverPresentationModifier") + }, call: "fullScreenCover") + throw InspectionError.notSupported( + """ + Please refer to the Guide for inspecting the FullScreenCover: \ + https://github.com/nalexn/ViewInspector/blob/master/guide.md#fullScreenCover + """) + } + let view = try fullScreenCoverBuilder.buildFullScreenCover() + let container = ViewType.FullScreenCover.Container(view: view, builder: fullScreenCoverBuilder) + let medium = self.medium.resettingViewModifiers() + let content = Content(container, medium: medium) + let call = ViewType.inspectionCall( + base: ViewType.FullScreenCover.inspectionCall(typeName: ""), index: index) + return try .init(content, parent: parent, call: call, index: index) + } + + func fullScreenCoversForSearch() -> [ViewSearch.ModifierIdentity] { + let count = medium.viewModifiers + .compactMap { isFullScreenCoverBuilder(modifier: $0) } + .count + return Array(0.. Bool { + return (try? Inspector.attribute( + label: "modifier", value: modifier, type: FullScreenCoverBuilder.self)) != nil + } +} + +@available(iOS 13.0, tvOS 13.0, *) +@available(macOS, unavailable) +internal extension ViewType.FullScreenCover { + struct Container: CustomViewIdentityMapping { + let view: Any + let builder: FullScreenCoverBuilder + + var viewTypeForSearch: KnownViewType.Type { ViewType.FullScreenCover.self } + } +} + +// MARK: - Custom Attributes + +@available(iOS 13.0, tvOS 13.0, *) +@available(macOS, unavailable) +public extension InspectableView where View == ViewType.FullScreenCover { + + func callOnDismiss() throws { + let fullScreenCover = try Inspector.cast(value: content.view, type: ViewType.FullScreenCover.Container.self) + fullScreenCover.builder.dismissPopup() + } +} + +@available(iOS 13.0, tvOS 13.0, *) +@available(macOS, unavailable) +public protocol FullScreenCoverBuilder: SystemPopupPresenter { + var onDismiss: (() -> Void)? { get } + func buildFullScreenCover() throws -> Any +} + +@available(iOS 13.0, tvOS 13.0, *) +@available(macOS, unavailable) +public protocol FullScreenCoverProvider: FullScreenCoverBuilder { + var isPresented: Binding { get } + var fullScreenCoverBuilder: () -> Any { get } +} + +@available(iOS 13.0, tvOS 13.0, *) +@available(macOS, unavailable) +public protocol FullScreenCoverItemProvider: FullScreenCoverBuilder { + associatedtype Item: Identifiable + var item: Binding { get } + var fullScreenCoverBuilder: (Item) -> Any { get } +} + +@available(iOS 13.0, tvOS 13.0, *) +@available(macOS, unavailable) +public extension FullScreenCoverProvider { + + func buildFullScreenCover() throws -> Any { + guard isPresented.wrappedValue else { + throw InspectionError.viewNotFound(parent: "FullScreenCover") + } + return fullScreenCoverBuilder() + } + + func dismissPopup() { + isPresented.wrappedValue = false + onDismiss?() + } +} + +@available(iOS 13.0, tvOS 13.0, *) +@available(macOS, unavailable) +public extension FullScreenCoverItemProvider { + + func buildFullScreenCover() throws -> Any { + guard let value = item.wrappedValue else { + throw InspectionError.viewNotFound(parent: "FullScreenCover") + } + return fullScreenCoverBuilder(value) + } + + func dismissPopup() { + item.wrappedValue = nil + onDismiss?() + } +} diff --git a/Sources/ViewInspector/ViewSearchIndex.swift b/Sources/ViewInspector/ViewSearchIndex.swift index 2fc3a530..d4b64ca5 100644 --- a/Sources/ViewInspector/ViewSearchIndex.swift +++ b/Sources/ViewInspector/ViewSearchIndex.swift @@ -15,6 +15,7 @@ internal extension ViewSearch { .init(ViewType.Divider.self), .init(ViewType.EditButton.self), .init(ViewType.EmptyView.self), .init(ViewType.ForEach.self), .init(ViewType.Form.self), + .init(ViewType.Sheet.self, genericTypeName: nil), .init(ViewType.GeometryReader.self), .init(ViewType.Group.self), .init(ViewType.GroupBox.self), .init(ViewType.HSplitView.self), .init(ViewType.HStack.self), @@ -312,8 +313,10 @@ internal extension Content { let sheetModifiers = sheetsForSearch() #if os(macOS) let actionSheetModifiers: [ViewSearch.ModifierIdentity] = [] + let fullScreenCoverModifiers: [ViewSearch.ModifierIdentity] = [] #else let actionSheetModifiers = actionSheetsForSearch() + let fullScreenCoverModifiers = fullScreenCoversForSearch() #endif let alertModifiers = alertsForSearch() return .init(count: sheetModifiers.count, { index -> UnwrappedView in @@ -322,6 +325,8 @@ internal extension Content { try actionSheetModifiers[index].builder(parent, index) }) + .init(count: alertModifiers.count, { index -> UnwrappedView in try alertModifiers[index].builder(parent, index) + }) + .init(count: fullScreenCoverModifiers.count, { index -> UnwrappedView in + try fullScreenCoverModifiers[index].builder(parent, index) }) } } diff --git a/Tests/ViewInspectorTests/SwiftUI/FullScreenCoverTests.swift b/Tests/ViewInspectorTests/SwiftUI/FullScreenCoverTests.swift new file mode 100644 index 00000000..61e0a912 --- /dev/null +++ b/Tests/ViewInspectorTests/SwiftUI/FullScreenCoverTests.swift @@ -0,0 +1,236 @@ +// +// FullScreenCoverTests.swift +// ViewInspector +// +// Created by Richard Gist on 9/2/21. +// + +import XCTest +import SwiftUI +@testable import ViewInspector + +#if !os(macOS) +@available(iOS 14.0, tvOS 14.0, watchOS 7.0, *) +@available(macOS, unavailable) +final class FullScreenCoverTests: XCTestCase { + + func testFullScreenCover() throws { + let binding = Binding(wrappedValue: true) + let sut = EmptyView().fullScreenCover(isPresented: binding) { Text("") } + print("\(Inspector.print(sut) as AnyObject)") + XCTAssertNoThrow(try sut.inspect().emptyView()) + } + + func testInspectionErrorNoModifier() throws { + let sut = EmptyView().offset() + XCTAssertThrows(try sut.inspect().emptyView().fullScreenCover(), + "EmptyView does not have 'fullScreenCover' modifier") + } + + func testInspectionErrorCustomModifierRequired() throws { + let binding = Binding(wrappedValue: true) + let sut = EmptyView().fullScreenCover(isPresented: binding) { Text("") } + XCTAssertThrows(try sut.inspect().emptyView().fullScreenCover(), + """ + Please refer to the Guide for inspecting the FullScreenCover: \ + https://github.com/nalexn/ViewInspector/blob/master/guide.md#fullScreenCover + """) + } + + func testInspectionErrorFullScreenCoverNotPresented() throws { + let binding = Binding(wrappedValue: false) + let sut = EmptyView().fullScreenCover2(isPresented: binding) { Text("") } + XCTAssertThrows(try sut.inspect().emptyView().fullScreenCover(), + "View for FullScreenCover is absent") + } + + func testInspectionErrorFullScreenCoverWithItemNotPresented() throws { + let binding = Binding(wrappedValue: nil) + let sut = EmptyView().fullScreenCover2(item: binding) { Text("\($0)") } + XCTAssertThrows(try sut.inspect().emptyView().fullScreenCover(), + "View for FullScreenCover is absent") + } + + func testContentInspection() throws { + let binding = Binding(wrappedValue: true) + let sut = EmptyView().fullScreenCover2(isPresented: binding) { + Text("abc") + } + let title = try sut.inspect().emptyView().fullScreenCover().text() + XCTAssertEqual(try title.string(), "abc") + XCTAssertEqual(title.pathToRoot, "emptyView().fullScreenCover().text()") + } + + func testContentInteraction() throws { + let binding = Binding(wrappedValue: true) + let sut = EmptyView().fullScreenCover2(isPresented: binding) { + Text("abc") + Button("xyz", action: { binding.wrappedValue = false }) + } + let button = try sut.inspect().emptyView().fullScreenCover().button(1) + try button.tap() + XCTAssertFalse(binding.wrappedValue) + XCTAssertEqual(button.pathToRoot, "emptyView().fullScreenCover().button(1)") + } + + func testOnDismiss() throws { + let exp = XCTestExpectation(description: #function) + let binding = Binding(wrappedValue: true) + let sut = EmptyView().fullScreenCover2(isPresented: binding, onDismiss: { + exp.fulfill() + }, content: { Text("") }) + XCTAssertTrue(binding.wrappedValue) + try sut.inspect().fullScreenCover().callOnDismiss() + XCTAssertFalse(binding.wrappedValue) + wait(for: [exp], timeout: 0.1) + } + + func testContentWithItemInspection() throws { + let binding = Binding(wrappedValue: 6) + let sut = EmptyView().fullScreenCover2(item: binding) { Text("\($0)") } + let fullScreenCover = try sut.inspect().emptyView().fullScreenCover() + XCTAssertEqual(try fullScreenCover.text().string(), "6") + XCTAssertEqual(binding.wrappedValue, 6) + try fullScreenCover.callOnDismiss() + XCTAssertNil(binding.wrappedValue) + } + + func testMultipleFullScreenCoversInspection() throws { + let binding1 = Binding(wrappedValue: true) + let binding2 = Binding(wrappedValue: true) + let binding3 = Binding(wrappedValue: true) + let sut = FullScreenCoverFindTestView(fullScreenCover1: binding1, fullScreenCover2: binding2, fullScreenCover3: binding3) + let title1 = try sut.inspect().hStack().emptyView(0).fullScreenCover().text(0) + XCTAssertEqual(try title1.string(), "title_1") + XCTAssertEqual(title1.pathToRoot, + "view(FullScreenCoverFindTestView.self).hStack().emptyView(0).fullScreenCover().text(0)") + let title2 = try sut.inspect().hStack().emptyView(0).fullScreenCover(1).text(0) + XCTAssertEqual(try title2.string(), "title_3") + XCTAssertEqual(title2.pathToRoot, + "view(FullScreenCoverFindTestView.self).hStack().emptyView(0).fullScreenCover(1).text(0)") + + XCTAssertEqual(try sut.inspect().find(ViewType.FullScreenCover.self).text(0).string(), "title_1") + binding1.wrappedValue = false + XCTAssertEqual(try sut.inspect().find(ViewType.FullScreenCover.self).text(0).string(), "title_3") + binding3.wrappedValue = false + XCTAssertThrows(try sut.inspect().find(ViewType.FullScreenCover.self), + "Search did not find a match") + } + + func testFindAndPathToRoots() throws { + let binding = Binding(wrappedValue: true) + let sut = FullScreenCoverFindTestView(fullScreenCover1: binding, fullScreenCover2: binding, fullScreenCover3: binding) + + // 1 + XCTAssertEqual(try sut.inspect().find(text: "title_1").pathToRoot, + "view(FullScreenCoverFindTestView.self).hStack().emptyView(0).fullScreenCover().text(0)") + XCTAssertEqual(try sut.inspect().find(text: "button_1").pathToRoot, + "view(FullScreenCoverFindTestView.self).hStack().emptyView(0).fullScreenCover().button(1).labelView().text()") + // 2 + XCTAssertThrows(try sut.inspect().find(text: "title_2").pathToRoot, + "Search did not find a match") + + // 3 + XCTAssertEqual(try sut.inspect().find(text: "title_3").pathToRoot, + "view(FullScreenCoverFindTestView.self).hStack().emptyView(0).fullScreenCover(1).text(0)") + + XCTAssertThrows(try sut.inspect().find(text: "message_3").pathToRoot, + "Search did not find a match") + XCTAssertEqual(try sut.inspect().find(text: "button_3").pathToRoot, + "view(FullScreenCoverFindTestView.self).hStack().emptyView(0).fullScreenCover(1).button(1).labelView().text()") + } +} + +@available(iOS 14.0, tvOS 14.0, watchOS 7.0, *) +@available(macOS, unavailable) +private extension View { + func fullScreenCover2(isPresented: Binding, + onDismiss: (() -> Void)? = nil, + @ViewBuilder content: @escaping () -> FullScreenCover + ) -> some View where FullScreenCover: View { + return self.modifier(InspectableFullScreenCover(isPresented: isPresented, onDismiss: onDismiss, content: content)) + } + + func fullScreenCover2(item: Binding, + onDismiss: (() -> Void)? = nil, + content: @escaping (Item) -> FullScreenCover + ) -> some View where Item: Identifiable, FullScreenCover: View { + return self.modifier(InspectableFullScreenCoverWithItem(item: item, onDismiss: onDismiss, content: content)) + } +} + +@available(iOS 14.0, tvOS 14.0, watchOS 7.0, *) +@available(macOS, unavailable) +private struct InspectableFullScreenCover: ViewModifier, FullScreenCoverProvider where FullScreenCover: View { + + let isPresented: Binding + let onDismiss: (() -> Void)? + let content: () -> FullScreenCover + let fullScreenCoverBuilder: () -> Any + + init(isPresented: Binding, onDismiss: (() -> Void)?, content: @escaping () -> FullScreenCover) { + self.isPresented = isPresented + self.onDismiss = onDismiss + self.content = content + self.fullScreenCoverBuilder = { content() as Any } + } + + func body(content: Self.Content) -> some View { + content.fullScreenCover(isPresented: isPresented, content: self.content) + } +} + +@available(iOS 14.0, tvOS 14.0, watchOS 7.0, *) +@available(macOS, unavailable) +private struct InspectableFullScreenCoverWithItem: ViewModifier, FullScreenCoverItemProvider +where Item: Identifiable, FullScreenCover: View { + + let item: Binding + let onDismiss: (() -> Void)? + let content: (Item) -> FullScreenCover + let fullScreenCoverBuilder: (Item) -> Any + + init(item: Binding, onDismiss: (() -> Void)?, content: @escaping (Item) -> FullScreenCover) { + self.item = item + self.onDismiss = onDismiss + self.content = content + self.fullScreenCoverBuilder = { content($0) as Any } + } + + func body(content: Self.Content) -> some View { + content.fullScreenCover(item: item, onDismiss: onDismiss, content: self.content) + } +} + +@available(iOS 14.0, tvOS 14.0, watchOS 7.0, *) +@available(macOS, unavailable) +private struct FullScreenCoverFindTestView: View, Inspectable { + + @Binding var isFullScreenCover1Presented = false + @Binding var isFullScreenCover2Presented = false + @Binding var isFullScreenCover3Presented = false + + init(fullScreenCover1: Binding, fullScreenCover2: Binding, fullScreenCover3: Binding) { + _isFullScreenCover1Presented = fullScreenCover1 + _isFullScreenCover2Presented = fullScreenCover2 + _isFullScreenCover3Presented = fullScreenCover3 + } + + var body: some View { + HStack { + EmptyView() + .fullScreenCover2(isPresented: $isFullScreenCover1Presented) { + Text("title_1") + Button("button_1", action: { }) + } + .fullScreenCover(isPresented: $isFullScreenCover2Presented) { + Text("title_2") + } + .fullScreenCover2(isPresented: $isFullScreenCover3Presented) { + Text("title_3") + Button("button_3", action: { }) + } + } + } +} +#endif diff --git a/ViewInspector.xcodeproj/project.pbxproj b/ViewInspector.xcodeproj/project.pbxproj index 1b4f4658..54e62584 100644 --- a/ViewInspector.xcodeproj/project.pbxproj +++ b/ViewInspector.xcodeproj/project.pbxproj @@ -69,6 +69,8 @@ CDA8450C262CBF5700C56C98 /* CommonComposedGestureEndedTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDA8450B262CBF5700C56C98 /* CommonComposedGestureEndedTests.swift */; }; CDA84516262CC1F800C56C98 /* CommonComposedGestureUpdatingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDA84515262CC1F800C56C98 /* CommonComposedGestureUpdatingTests.swift */; }; CDA8451C262CC34D00C56C98 /* CommonComposedGestureChangedTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDA8451B262CC34D00C56C98 /* CommonComposedGestureChangedTests.swift */; }; + D766E67026E17F01004AAA80 /* FullScreenCoverTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D766E66F26E17F01004AAA80 /* FullScreenCoverTests.swift */; }; + D7A6CE8926E17AE900599824 /* FullScreenCover.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7A6CE8826E17AE900599824 /* FullScreenCover.swift */; }; F6026A27256A7D1900CA31E5 /* TextAttributes.swift in Sources */ = {isa = PBXBuildFile; fileRef = F6026A26256A7D1900CA31E5 /* TextAttributes.swift */; }; F6026A31256A7E3D00CA31E5 /* TextAttributesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F6026A30256A7E3D00CA31E5 /* TextAttributesTests.swift */; }; F60385D523D3C74B008F31BD /* InspectionEmissary.swift in Sources */ = {isa = PBXBuildFile; fileRef = F60385D423D3C74B008F31BD /* InspectionEmissary.swift */; }; @@ -310,6 +312,8 @@ CDA8450B262CBF5700C56C98 /* CommonComposedGestureEndedTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommonComposedGestureEndedTests.swift; sourceTree = ""; }; CDA84515262CC1F800C56C98 /* CommonComposedGestureUpdatingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommonComposedGestureUpdatingTests.swift; sourceTree = ""; }; CDA8451B262CC34D00C56C98 /* CommonComposedGestureChangedTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommonComposedGestureChangedTests.swift; sourceTree = ""; }; + D766E66F26E17F01004AAA80 /* FullScreenCoverTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FullScreenCoverTests.swift; sourceTree = ""; }; + D7A6CE8826E17AE900599824 /* FullScreenCover.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FullScreenCover.swift; sourceTree = ""; }; F6026A26256A7D1900CA31E5 /* TextAttributes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextAttributes.swift; sourceTree = ""; }; F6026A30256A7E3D00CA31E5 /* TextAttributesTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextAttributesTests.swift; sourceTree = ""; }; F60385D423D3C74B008F31BD /* InspectionEmissary.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InspectionEmissary.swift; sourceTree = ""; }; @@ -656,6 +660,7 @@ F6D933B22385ED1400358E0E /* VSplitView.swift */, F60EEBC92382EED0007DB53A /* VStack.swift */, F60EEBC12382EED0007DB53A /* ZStack.swift */, + D7A6CE8826E17AE900599824 /* FullScreenCover.swift */, ); path = SwiftUI; sourceTree = ""; @@ -711,6 +716,7 @@ 5214800225F4EA4F002D974D /* EnvironmentObjectInjectionTests.swift */, F60EEBED2382F004007DB53A /* ForEachTests.swift */, F60EEBEB2382F004007DB53A /* FormTests.swift */, + D766E66F26E17F01004AAA80 /* FullScreenCoverTests.swift */, F6D9339C2385ADA500358E0E /* GeometryReaderTests.swift */, F60EEBF12382F004007DB53A /* GroupTests.swift */, F6D933AC2385EB0100358E0E /* GroupBoxTests.swift */, @@ -1021,6 +1027,7 @@ F6ECF6C823A66E54000FC591 /* InteractionModifiers.swift in Sources */, 52A5CA0425E1139E00773CF5 /* EnvironmentModifiers.swift in Sources */, F60EEBDC2382EED0007DB53A /* Text.swift in Sources */, + D7A6CE8926E17AE900599824 /* FullScreenCover.swift in Sources */, F620C7FB2537B090006D856D /* ConfigurationModifiers.swift in Sources */, F6684BFE23AA863400DECCB3 /* RadialGradient.swift in Sources */, F60EEBD42382EED0007DB53A /* ScrollView.swift in Sources */, @@ -1196,6 +1203,7 @@ F64057F1238DBB120029D9BA /* EmptyViewTests.swift in Sources */, CDA844C8262B7F3100C56C98 /* TapGestureTests.swift in Sources */, F6D933B12385EC5F00358E0E /* HSplitViewTests.swift in Sources */, + D766E67026E17F01004AAA80 /* FullScreenCoverTests.swift in Sources */, F64057F3238E9F600029D9BA /* OptionalViewTests.swift in Sources */, F6684BFC23AA842000DECCB3 /* LinearGradientTests.swift in Sources */, F62AEAFC23E705D6003E69D9 /* ViewHostingTests.swift in Sources */, From 4f023f012c7fa11c98488d8f722ee84cba50ed88 Mon Sep 17 00:00:00 2001 From: Richard Gist Date: Thu, 2 Sep 2021 16:28:28 -0600 Subject: [PATCH 32/99] Fixes InspectionError.notSupported link for Sheet and ActionSheet --- Sources/ViewInspector/SwiftUI/ActionSheet.swift | 2 +- Sources/ViewInspector/SwiftUI/Sheet.swift | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/ViewInspector/SwiftUI/ActionSheet.swift b/Sources/ViewInspector/SwiftUI/ActionSheet.swift index b6b4bfe3..de442d8d 100644 --- a/Sources/ViewInspector/SwiftUI/ActionSheet.swift +++ b/Sources/ViewInspector/SwiftUI/ActionSheet.swift @@ -43,7 +43,7 @@ internal extension Content { throw InspectionError.notSupported( """ Please refer to the Guide for inspecting the ActionSheet: \ - https://github.com/nalexn/ViewInspector/blob/master/guide.md#actionsheet + https://github.com/nalexn/ViewInspector/blob/master/guide.md#alert-sheet-and-actionsheet """) } let sheet = try sheetBuilder.buildSheet() diff --git a/Sources/ViewInspector/SwiftUI/Sheet.swift b/Sources/ViewInspector/SwiftUI/Sheet.swift index cc9f9f1e..965c34fc 100644 --- a/Sources/ViewInspector/SwiftUI/Sheet.swift +++ b/Sources/ViewInspector/SwiftUI/Sheet.swift @@ -63,7 +63,7 @@ internal extension Content { throw InspectionError.notSupported( """ Please refer to the Guide for inspecting the Sheet: \ - https://github.com/nalexn/ViewInspector/blob/master/guide.md#sheet + https://github.com/nalexn/ViewInspector/blob/master/guide.md#alert-sheet-and-actionsheet """) } let view = try sheetBuilder.buildSheet() From d0e85090fe4e11f3e420fd18e585141b8f141bad Mon Sep 17 00:00:00 2001 From: Richard Gist Date: Thu, 2 Sep 2021 16:44:00 -0600 Subject: [PATCH 33/99] Completes FullScreenCover implementation --- .../ViewInspector/SwiftUI/ActionSheet.swift | 2 +- Sources/ViewInspector/SwiftUI/Alert.swift | 2 +- .../SwiftUI/FullScreenCover.swift | 4 +- Sources/ViewInspector/SwiftUI/Sheet.swift | 2 +- Sources/ViewInspector/ViewSearchIndex.swift | 2 +- .../SwiftUI/ActionSheetTests.swift | 2 +- .../SwiftUI/AlertTests.swift | 2 +- .../SwiftUI/FullScreenCoverTests.swift | 2 +- .../SwiftUI/SheetTests.swift | 2 +- guide.md | 82 ++++++++++++++++++- 10 files changed, 90 insertions(+), 12 deletions(-) diff --git a/Sources/ViewInspector/SwiftUI/ActionSheet.swift b/Sources/ViewInspector/SwiftUI/ActionSheet.swift index de442d8d..7daa6222 100644 --- a/Sources/ViewInspector/SwiftUI/ActionSheet.swift +++ b/Sources/ViewInspector/SwiftUI/ActionSheet.swift @@ -43,7 +43,7 @@ internal extension Content { throw InspectionError.notSupported( """ Please refer to the Guide for inspecting the ActionSheet: \ - https://github.com/nalexn/ViewInspector/blob/master/guide.md#alert-sheet-and-actionsheet + https://github.com/nalexn/ViewInspector/blob/master/guide.md#alert-sheet-actionsheet-and-fullscreencover """) } let sheet = try sheetBuilder.buildSheet() diff --git a/Sources/ViewInspector/SwiftUI/Alert.swift b/Sources/ViewInspector/SwiftUI/Alert.swift index d7822222..42015e9e 100644 --- a/Sources/ViewInspector/SwiftUI/Alert.swift +++ b/Sources/ViewInspector/SwiftUI/Alert.swift @@ -41,7 +41,7 @@ internal extension Content { throw InspectionError.notSupported( """ Please refer to the Guide for inspecting the Alert: \ - https://github.com/nalexn/ViewInspector/blob/master/guide.md#alert-sheet-and-actionsheet + https://github.com/nalexn/ViewInspector/blob/master/guide.md#alert-sheet-actionsheet-and-fullscreencover """) } let alert = try alertBuilder.buildAlert() diff --git a/Sources/ViewInspector/SwiftUI/FullScreenCover.swift b/Sources/ViewInspector/SwiftUI/FullScreenCover.swift index ca489602..27b823c8 100644 --- a/Sources/ViewInspector/SwiftUI/FullScreenCover.swift +++ b/Sources/ViewInspector/SwiftUI/FullScreenCover.swift @@ -67,12 +67,12 @@ internal extension Content { else { _ = try self.modifier({ $0.modifierType == "IdentifiedPreferenceTransformModifier" - || $0.modifierType.contains("FullScreenCoverPresentationModifier") + || $0.modifierType.contains("SheetPresentationModifier") }, call: "fullScreenCover") throw InspectionError.notSupported( """ Please refer to the Guide for inspecting the FullScreenCover: \ - https://github.com/nalexn/ViewInspector/blob/master/guide.md#fullScreenCover + https://github.com/nalexn/ViewInspector/blob/master/guide.md#guide.md#alert-sheet-actionsheet-and-fullscreencover """) } let view = try fullScreenCoverBuilder.buildFullScreenCover() diff --git a/Sources/ViewInspector/SwiftUI/Sheet.swift b/Sources/ViewInspector/SwiftUI/Sheet.swift index 965c34fc..ce8875da 100644 --- a/Sources/ViewInspector/SwiftUI/Sheet.swift +++ b/Sources/ViewInspector/SwiftUI/Sheet.swift @@ -63,7 +63,7 @@ internal extension Content { throw InspectionError.notSupported( """ Please refer to the Guide for inspecting the Sheet: \ - https://github.com/nalexn/ViewInspector/blob/master/guide.md#alert-sheet-and-actionsheet + https://github.com/nalexn/ViewInspector/blob/master/guide.md#alert-sheet-actionsheet-and-fullscreencover """) } let view = try sheetBuilder.buildSheet() diff --git a/Sources/ViewInspector/ViewSearchIndex.swift b/Sources/ViewInspector/ViewSearchIndex.swift index d4b64ca5..6c9f343e 100644 --- a/Sources/ViewInspector/ViewSearchIndex.swift +++ b/Sources/ViewInspector/ViewSearchIndex.swift @@ -15,7 +15,7 @@ internal extension ViewSearch { .init(ViewType.Divider.self), .init(ViewType.EditButton.self), .init(ViewType.EmptyView.self), .init(ViewType.ForEach.self), .init(ViewType.Form.self), - .init(ViewType.Sheet.self, genericTypeName: nil), + .init(ViewType.FullScreenCover.self, genericTypeName: nil), .init(ViewType.GeometryReader.self), .init(ViewType.Group.self), .init(ViewType.GroupBox.self), .init(ViewType.HSplitView.self), .init(ViewType.HStack.self), diff --git a/Tests/ViewInspectorTests/SwiftUI/ActionSheetTests.swift b/Tests/ViewInspectorTests/SwiftUI/ActionSheetTests.swift index 97094a62..d36ff16c 100644 --- a/Tests/ViewInspectorTests/SwiftUI/ActionSheetTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/ActionSheetTests.swift @@ -24,7 +24,7 @@ final class ActionSheetTests: XCTestCase { XCTAssertThrows(try sut.inspect().emptyView().actionSheet(), """ Please refer to the Guide for inspecting the ActionSheet: \ - https://github.com/nalexn/ViewInspector/blob/master/guide.md#actionsheet + https://github.com/nalexn/ViewInspector/blob/master/guide.md#alert-sheet-actionsheet-and-fullscreencover """) } diff --git a/Tests/ViewInspectorTests/SwiftUI/AlertTests.swift b/Tests/ViewInspectorTests/SwiftUI/AlertTests.swift index 171b5bdc..a90bf807 100644 --- a/Tests/ViewInspectorTests/SwiftUI/AlertTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/AlertTests.swift @@ -23,7 +23,7 @@ final class AlertTests: XCTestCase { XCTAssertThrows(try sut.inspect().emptyView().alert(), """ Please refer to the Guide for inspecting the Alert: \ - https://github.com/nalexn/ViewInspector/blob/master/guide.md#alert-sheet-and-actionsheet + https://github.com/nalexn/ViewInspector/blob/master/guide.md#alert-sheet-actionsheet-and-fullscreencover """) } diff --git a/Tests/ViewInspectorTests/SwiftUI/FullScreenCoverTests.swift b/Tests/ViewInspectorTests/SwiftUI/FullScreenCoverTests.swift index 61e0a912..6496c9e8 100644 --- a/Tests/ViewInspectorTests/SwiftUI/FullScreenCoverTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/FullScreenCoverTests.swift @@ -33,7 +33,7 @@ final class FullScreenCoverTests: XCTestCase { XCTAssertThrows(try sut.inspect().emptyView().fullScreenCover(), """ Please refer to the Guide for inspecting the FullScreenCover: \ - https://github.com/nalexn/ViewInspector/blob/master/guide.md#fullScreenCover + https://github.com/nalexn/ViewInspector/blob/master/guide.md#alert-sheet-actionsheet-and-fullscreencover """) } diff --git a/Tests/ViewInspectorTests/SwiftUI/SheetTests.swift b/Tests/ViewInspectorTests/SwiftUI/SheetTests.swift index 18577663..23a8b14e 100644 --- a/Tests/ViewInspectorTests/SwiftUI/SheetTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/SheetTests.swift @@ -24,7 +24,7 @@ final class SheetTests: XCTestCase { XCTAssertThrows(try sut.inspect().emptyView().sheet(), """ Please refer to the Guide for inspecting the Sheet: \ - https://github.com/nalexn/ViewInspector/blob/master/guide.md#sheet + https://github.com/nalexn/ViewInspector/blob/master/guide.md#alert-sheet-actionsheet-and-fullscreencover """) } diff --git a/guide.md b/guide.md index 4d835060..3108c639 100644 --- a/guide.md +++ b/guide.md @@ -577,9 +577,9 @@ let view = EmptyView().modifier(sut).environmentObject(envObject) ViewHosting.host(view: view) ``` -## Alert, Sheet and ActionSheet +## Alert, Sheet, ActionSheet, and FullScreenCover -These three types of views have many in common, so is their inspection mechanism. Due to limited capabilities of what can be achieved in reflection, the native SwiftUI modifiers for presenting these views (`.alert`, `.sheet`, `.actionSheet`) cannot be inspected as-is by the ViewInspector. +These four types of views have many in common, so is their inspection mechanism. Due to limited capabilities of what can be achieved in reflection, the native SwiftUI modifiers for presenting these views (`.alert`, `.sheet`, `.actionSheet`, `.fullScreenCover`) cannot be inspected as-is by the ViewInspector. This section discusses how you still can gain the full access to the internals of these views by adding a couple of code snippets to your source code while not making ViewInspector a dependency for the main target. @@ -797,6 +797,84 @@ extension InspectableSheetWithItem: SheetItemProvider { } Don't forget that you'll need to use `sheet2` in place of `sheet` in your views. +### Making `FullScreenCover` inspectable + +Similarly to the `Alert` and `Sheet`, there are two APIs for presenting the `FullScreenCover` thus two sets of snippets to add to the project, depending on your needs. + +Variant with `isPresented: Binding` - main target snippet: + +```swift +extension View { + func fullScreenCover2(isPresented: Binding, onDismiss: (() -> Void)? = nil, @ViewBuilder content: @escaping () -> FullScreenCover + ) -> some View where FullScreenCover: View { + return self.modifier(InspectableFullScreenCover(isPresented: isPresented, onDismiss: onDismiss, content: content)) + } +} + +struct InspectableFullScreenCover: ViewModifier where FullScreenCover: View { + + let isPresented: Binding + let onDismiss: (() -> Void)? + let content: () -> FullScreenCover + let fullScreenCoverBuilder: () -> Any + + init(isPresented: Binding, onDismiss: (() -> Void)?, content: @escaping () -> FullScreenCover) { + self.isPresented = isPresented + self.onDismiss = onDismiss + self.content = content + self.fullScreenCoverBuilder = { content() as Any } + } + + func body(content: Self.Content) -> some View { + content.fullScreenCover(isPresented: isPresented, content: self.content) + } +} +``` + +Test target: + +```swift +extension InspectableFullScreenCover: FullScreenCoverProvider { } +``` + +Variant with `item: Binding` - main target snippet: + +```swift +extension View { + func fullScreenCover2(item: Binding, onDismiss: (() -> Void)? = nil, content: @escaping (Item) -> FullScreenCover + ) -> some View where Item: Identifiable, FullScreenCover: View { + return self.modifier(InspectableFullScreenCoverWithItem(item: item, onDismiss: onDismiss, content: content)) + } +} + +struct InspectableFullScreenCoverWithItem: ViewModifier where Item: Identifiable, FullScreenCover: View { + + let item: Binding + let onDismiss: (() -> Void)? + let content: (Item) -> FullScreenCover + let fullScreenCoverBuilder: (Item) -> Any + + init(item: Binding, onDismiss: (() -> Void)?, content: @escaping (Item) -> FullScreenCover) { + self.item = item + self.onDismiss = onDismiss + self.content = content + self.fullScreenCoverBuilder = { content($0) as Any } + } + + func body(content: Self.Content) -> some View { + content.fullScreenCover(item: item, onDismiss: onDismiss, content: self.content) + } +} +``` + +Test target: + +```swift +extension InspectableFullScreenCoverWithItem: FullScreenCoverItemProvider { } +``` + +Don't forget that you'll need to use `fullScreenCover2` in place of `fullScreenCover` in your views. + ## Advanced topics - [Styles](guide_styles.md) From db4d3b8ed2f8b08c1f6dbdd9cc99540ecab3244f Mon Sep 17 00:00:00 2001 From: Richard Gist Date: Thu, 2 Sep 2021 17:11:47 -0600 Subject: [PATCH 34/99] [master] - Missed an error message fix --- Sources/ViewInspector/SwiftUI/FullScreenCover.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/ViewInspector/SwiftUI/FullScreenCover.swift b/Sources/ViewInspector/SwiftUI/FullScreenCover.swift index 27b823c8..1e75ebd5 100644 --- a/Sources/ViewInspector/SwiftUI/FullScreenCover.swift +++ b/Sources/ViewInspector/SwiftUI/FullScreenCover.swift @@ -72,7 +72,7 @@ internal extension Content { throw InspectionError.notSupported( """ Please refer to the Guide for inspecting the FullScreenCover: \ - https://github.com/nalexn/ViewInspector/blob/master/guide.md#guide.md#alert-sheet-actionsheet-and-fullscreencover + https://github.com/nalexn/ViewInspector/blob/master/guide.md#alert-sheet-actionsheet-and-fullscreencover """) } let view = try fullScreenCoverBuilder.buildFullScreenCover() From f3c90311616b75484e24da20051bed9c42e3d5ef Mon Sep 17 00:00:00 2001 From: Alexey Naumov Date: Sun, 5 Sep 2021 13:54:09 +0300 Subject: [PATCH 35/99] Improve search for overlays, search support for Toolbar --- Sources/ViewInspector/BaseTypes.swift | 13 +++++ .../Modifiers/VisualEffectModifiers.swift | 15 ++++-- .../ViewInspector/SwiftUI/ActionSheet.swift | 9 ++-- Sources/ViewInspector/SwiftUI/Alert.swift | 9 ++-- Sources/ViewInspector/SwiftUI/List.swift | 10 ++-- Sources/ViewInspector/SwiftUI/Overlay.swift | 28 +++++++---- Sources/ViewInspector/SwiftUI/Popover.swift | 18 +++++-- Sources/ViewInspector/SwiftUI/Sheet.swift | 9 ++-- Sources/ViewInspector/SwiftUI/TabView.swift | 8 ++-- Sources/ViewInspector/SwiftUI/Toolbar.swift | 48 +++++++++++++++++-- Sources/ViewInspector/SwiftUI/TouchBar.swift | 12 +++-- Sources/ViewInspector/ViewSearchIndex.swift | 31 +++++++----- .../SwiftUI/ActionSheetTests.swift | 2 +- .../SwiftUI/AlertTests.swift | 2 +- .../SwiftUI/SheetTests.swift | 2 +- .../SwiftUI/ToolbarTests.swift | 20 ++++++++ .../SwiftUI/TouchBarTests.swift | 2 +- 17 files changed, 175 insertions(+), 63 deletions(-) diff --git a/Sources/ViewInspector/BaseTypes.swift b/Sources/ViewInspector/BaseTypes.swift index a6fe4da1..5743894c 100644 --- a/Sources/ViewInspector/BaseTypes.swift +++ b/Sources/ViewInspector/BaseTypes.swift @@ -130,6 +130,19 @@ internal extension ViewType { } } +@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) +internal extension Content { + func optionalizeIndex(_ index: Int, hasMore: () throws -> Any) -> Int? { + if index > 0 { return index } + do { + _ = try hasMore() + return 0 + } catch { + return nil + } + } +} + // MARK: - Content @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) diff --git a/Sources/ViewInspector/Modifiers/VisualEffectModifiers.swift b/Sources/ViewInspector/Modifiers/VisualEffectModifiers.swift index 7a9113f2..bcec9f88 100644 --- a/Sources/ViewInspector/Modifiers/VisualEffectModifiers.swift +++ b/Sources/ViewInspector/Modifiers/VisualEffectModifiers.swift @@ -127,20 +127,25 @@ public extension InspectableView { return shape.cornerSize.width } - func mask() throws -> InspectableView { - return try contentForModifierLookup.mask(parent: self) + func mask(_ index: Int = 0) throws -> InspectableView { + return try contentForModifierLookup.mask(parent: self, index: index) } } @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) internal extension Content { - func mask(parent: UnwrappedView) throws -> InspectableView { + func mask(parent: UnwrappedView, index: Int) throws -> InspectableView { let rootView = try modifierAttribute( modifierName: "_MaskEffect", path: "modifier|mask", - type: Any.self, call: "mask") + type: Any.self, call: "mask", index: index) let medium = self.medium.resettingViewModifiers() + let index = self.optionalizeIndex(index) { + try self.mask(parent: parent, index: 1) + } + let call = ViewType.inspectionCall( + base: "mask(\(ViewType.indexPlaceholder))", index: index) return try .init(try Inspector.unwrap(content: Content(rootView, medium: medium)), - parent: parent, call: "mask()") + parent: parent, call: call, index: index) } } diff --git a/Sources/ViewInspector/SwiftUI/ActionSheet.swift b/Sources/ViewInspector/SwiftUI/ActionSheet.swift index b6b4bfe3..34e1f876 100644 --- a/Sources/ViewInspector/SwiftUI/ActionSheet.swift +++ b/Sources/ViewInspector/SwiftUI/ActionSheet.swift @@ -22,7 +22,7 @@ public extension ViewType { @available(macOS, unavailable) public extension InspectableView { - func actionSheet(_ index: Int? = nil) throws -> InspectableView { + func actionSheet(_ index: Int = 0) throws -> InspectableView { return try contentForModifierLookup.actionSheet(parent: self, index: index) } } @@ -31,10 +31,10 @@ public extension InspectableView { @available(macOS, unavailable) internal extension Content { - func actionSheet(parent: UnwrappedView, index: Int?) throws -> InspectableView { + func actionSheet(parent: UnwrappedView, index: Int) throws -> InspectableView { guard let sheetBuilder = try? self.modifierAttribute( modifierLookup: { isActionSheetBuilder(modifier: $0) }, path: "modifier", - type: ActionSheetBuilder.self, call: "", index: index ?? 0) + type: ActionSheetBuilder.self, call: "", index: index) else { _ = try self.modifier({ $0.modifierType == "IdentifiedPreferenceTransformModifier" @@ -50,6 +50,9 @@ internal extension Content { let container = ViewType.ActionSheet.Container(sheet: sheet, builder: sheetBuilder) let medium = self.medium.resettingViewModifiers() let content = Content(container, medium: medium) + let index = self.optionalizeIndex(index) { + try self.actionSheet(parent: parent, index: 1) + } let call = ViewType.inspectionCall( base: ViewType.ActionSheet.inspectionCall(typeName: ""), index: index) return try .init(content, parent: parent, call: call, index: index) diff --git a/Sources/ViewInspector/SwiftUI/Alert.swift b/Sources/ViewInspector/SwiftUI/Alert.swift index d7822222..16cefdb6 100644 --- a/Sources/ViewInspector/SwiftUI/Alert.swift +++ b/Sources/ViewInspector/SwiftUI/Alert.swift @@ -21,7 +21,7 @@ public extension ViewType { @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) public extension InspectableView { - func alert(_ index: Int? = nil) throws -> InspectableView { + func alert(_ index: Int = 0) throws -> InspectableView { return try contentForModifierLookup.alert(parent: self, index: index) } } @@ -29,10 +29,10 @@ public extension InspectableView { @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) internal extension Content { - func alert(parent: UnwrappedView, index: Int?) throws -> InspectableView { + func alert(parent: UnwrappedView, index: Int) throws -> InspectableView { guard let alertBuilder = try? self.modifierAttribute( modifierLookup: { isAlertBuilder(modifier: $0) }, path: "modifier", - type: AlertBuilder.self, call: "", index: index ?? 0) + type: AlertBuilder.self, call: "", index: index) else { _ = try self.modifier({ $0.modifierType == "IdentifiedPreferenceTransformModifier" @@ -48,6 +48,9 @@ internal extension Content { let container = ViewType.Alert.Container(alert: alert, builder: alertBuilder) let medium = self.medium.resettingViewModifiers() let content = Content(container, medium: medium) + let index = self.optionalizeIndex(index) { + try self.alert(parent: parent, index: 1) + } let call = ViewType.inspectionCall( base: ViewType.Alert.inspectionCall(typeName: ""), index: index) return try .init(content, parent: parent, call: call, index: index) diff --git a/Sources/ViewInspector/SwiftUI/List.swift b/Sources/ViewInspector/SwiftUI/List.swift index 48bdcd68..beb8006a 100644 --- a/Sources/ViewInspector/SwiftUI/List.swift +++ b/Sources/ViewInspector/SwiftUI/List.swift @@ -51,7 +51,7 @@ public extension InspectableView { } func listRowBackground() throws -> InspectableView { - return try contentForModifierLookup.listRowBackground(parent: self) + return try contentForModifierLookup.listRowBackground(parent: self, index: 0) } func listStyle() throws -> Any { @@ -65,11 +65,13 @@ public extension InspectableView { @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) internal extension Content { - func listRowBackground(parent: UnwrappedView) throws -> InspectableView { + func listRowBackground(parent: UnwrappedView, index: Int) throws -> InspectableView { let view = try modifierAttribute( modifierName: "_TraitWritingModifier", - path: "modifier|value|some|storage|view", type: Any.self, call: "listRowBackground") + path: "modifier|value|some|storage|view", type: Any.self, + call: "listRowBackground", index: index) let medium = self.medium.resettingViewModifiers() - return try .init(try Inspector.unwrap(content: Content(view, medium: medium)), parent: parent) + let content = try Inspector.unwrap(content: Content(view, medium: medium)) + return try .init(content, parent: parent, call: "listRowBackground()", index: nil) } } diff --git a/Sources/ViewInspector/SwiftUI/Overlay.swift b/Sources/ViewInspector/SwiftUI/Overlay.swift index 5d897fef..642cf72e 100644 --- a/Sources/ViewInspector/SwiftUI/Overlay.swift +++ b/Sources/ViewInspector/SwiftUI/Overlay.swift @@ -14,12 +14,12 @@ public extension ViewType { @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) public extension InspectableView { - func overlay() throws -> InspectableView { - return try contentForModifierLookup.overlay(parent: self) + func overlay(_ index: Int = 0) throws -> InspectableView { + return try contentForModifierLookup.overlay(parent: self, index: index) } - func background() throws -> InspectableView { - return try contentForModifierLookup.background(parent: self) + func background(_ index: Int = 0) throws -> InspectableView { + return try contentForModifierLookup.background(parent: self, index: index) } } @@ -44,30 +44,38 @@ extension ViewType.Overlay: MultipleViewContent { @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) internal extension Content { - func overlay(parent: UnwrappedView) throws -> InspectableView { + func overlay(parent: UnwrappedView, index: Int) throws -> InspectableView { let modifier = try self.modifier({ modifier -> Bool in return modifier.modifierType.contains("_OverlayModifier") - }, call: "overlay") + }, call: "overlay", index: index) let rootView = try Inspector.attribute(path: "modifier|overlay", value: modifier) let alignment = try Inspector.attribute(path: "modifier|alignment", value: modifier, type: Alignment.self) let overlayParams = ViewType.Overlay.Params(alignment: alignment) let medium = self.medium.resettingViewModifiers() .appending(viewModifier: overlayParams) let content = try Inspector.unwrap(content: Content(rootView, medium: medium)) - return try .init(content, parent: parent, call: "overlay()") + let index = self.optionalizeIndex(index) { + try self.overlay(parent: parent, index: 1) + } + let call = ViewType.inspectionCall(base: "overlay(\(ViewType.indexPlaceholder))", index: index) + return try .init(content, parent: parent, call: call, index: index) } - func background(parent: UnwrappedView) throws -> InspectableView { + func background(parent: UnwrappedView, index: Int) throws -> InspectableView { let modifier = try self.modifier({ modifier -> Bool in return modifier.modifierType.contains("_BackgroundModifier") - }, call: "background") + }, call: "background", index: index) let rootView = try Inspector.attribute(path: "modifier|background", value: modifier) let alignment = try Inspector.attribute(path: "modifier|alignment", value: modifier, type: Alignment.self) let overlayParams = ViewType.Overlay.Params(alignment: alignment) let medium = self.medium.resettingViewModifiers() .appending(viewModifier: overlayParams) let content = try Inspector.unwrap(content: Content(rootView, medium: medium)) - return try .init(content, parent: parent, call: "background()") + let index = self.optionalizeIndex(index) { + try self.background(parent: parent, index: 1) + } + let call = ViewType.inspectionCall(base: "background(\(ViewType.indexPlaceholder))", index: index) + return try .init(content, parent: parent, call: call, index: index) } } diff --git a/Sources/ViewInspector/SwiftUI/Popover.swift b/Sources/ViewInspector/SwiftUI/Popover.swift index e5c80a37..f5043012 100644 --- a/Sources/ViewInspector/SwiftUI/Popover.swift +++ b/Sources/ViewInspector/SwiftUI/Popover.swift @@ -6,6 +6,9 @@ public extension ViewType { struct Popover: KnownViewType { public static var typePrefix: String = "" public static var isTransitive: Bool { true } + public static func inspectionCall(typeName: String) -> String { + return "popover(\(ViewType.indexPlaceholder))" + } } } @@ -15,21 +18,26 @@ public extension ViewType { @available(tvOS, unavailable) public extension InspectableView { - func popover() throws -> InspectableView { - return try contentForModifierLookup.popover(parent: self) + func popover(_ index: Int = 0) throws -> InspectableView { + return try contentForModifierLookup.popover(parent: self, index: index) } } @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) internal extension Content { - func popover(parent: UnwrappedView) throws -> InspectableView { + func popover(parent: UnwrappedView, index: Int) throws -> InspectableView { let modifier = try modifierAttribute( modifierName: "PopoverPresentationModifier", path: "modifier", - type: Any.self, call: "popover") + type: Any.self, call: "popover", index: index) let medium = self.medium.resettingViewModifiers() + let index = self.optionalizeIndex(index) { + try self.popover(parent: parent, index: 1) + } + let call = ViewType.inspectionCall( + base: ViewType.Popover.inspectionCall(typeName: ""), index: index) return try .init(try Inspector.unwrap(content: Content(modifier, medium: medium)), - parent: parent, call: "popover()") + parent: parent, call: call, index: index) } } diff --git a/Sources/ViewInspector/SwiftUI/Sheet.swift b/Sources/ViewInspector/SwiftUI/Sheet.swift index cc9f9f1e..23411960 100644 --- a/Sources/ViewInspector/SwiftUI/Sheet.swift +++ b/Sources/ViewInspector/SwiftUI/Sheet.swift @@ -43,7 +43,7 @@ extension ViewType.Sheet: MultipleViewContent { @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) public extension InspectableView { - func sheet(_ index: Int? = nil) throws -> InspectableView { + func sheet(_ index: Int = 0) throws -> InspectableView { return try contentForModifierLookup.sheet(parent: self, index: index) } } @@ -51,10 +51,10 @@ public extension InspectableView { @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) internal extension Content { - func sheet(parent: UnwrappedView, index: Int?) throws -> InspectableView { + func sheet(parent: UnwrappedView, index: Int) throws -> InspectableView { guard let sheetBuilder = try? self.modifierAttribute( modifierLookup: { isSheetBuilder(modifier: $0) }, path: "modifier", - type: SheetBuilder.self, call: "", index: index ?? 0) + type: SheetBuilder.self, call: "", index: index) else { _ = try self.modifier({ $0.modifierType == "IdentifiedPreferenceTransformModifier" @@ -70,6 +70,9 @@ internal extension Content { let container = ViewType.Sheet.Container(view: view, builder: sheetBuilder) let medium = self.medium.resettingViewModifiers() let content = Content(container, medium: medium) + let index = self.optionalizeIndex(index) { + try self.sheet(parent: parent, index: 1) + } let call = ViewType.inspectionCall( base: ViewType.Sheet.inspectionCall(typeName: ""), index: index) return try .init(content, parent: parent, call: call, index: index) diff --git a/Sources/ViewInspector/SwiftUI/TabView.swift b/Sources/ViewInspector/SwiftUI/TabView.swift index 5ec96066..c078ce34 100644 --- a/Sources/ViewInspector/SwiftUI/TabView.swift +++ b/Sources/ViewInspector/SwiftUI/TabView.swift @@ -51,7 +51,7 @@ public extension InspectableView { } func tabItem() throws -> InspectableView { - return try contentForModifierLookup.tabItem(parent: self) + return try contentForModifierLookup.tabItem(parent: self, index: 0) } @available(iOS 14.0, macOS 11.0, tvOS 14.0, *) @@ -75,16 +75,16 @@ public extension InspectableView { @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) internal extension Content { - func tabItem(parent: UnwrappedView) throws -> InspectableView { + func tabItem(parent: UnwrappedView, index: Int) throws -> InspectableView { let rootView: Any = try { if let view = try? modifierAttribute( modifierName: "TabItemTraitKey", path: "modifier|value|some|storage|view|content", - type: Any.self, call: "tabItem") { + type: Any.self, call: "tabItem", index: index) { return view } return try modifierAttribute( modifierName: "PlatformItemTraitWriter", path: "modifier|source|content|content|content", - type: Any.self, call: "tabItem") + type: Any.self, call: "tabItem", index: index) }() let medium = self.medium.resettingViewModifiers() let view = try InspectableView( diff --git a/Sources/ViewInspector/SwiftUI/Toolbar.swift b/Sources/ViewInspector/SwiftUI/Toolbar.swift index 966c9e9f..294cfe4e 100644 --- a/Sources/ViewInspector/SwiftUI/Toolbar.swift +++ b/Sources/ViewInspector/SwiftUI/Toolbar.swift @@ -4,7 +4,10 @@ import SwiftUI public extension ViewType { struct Toolbar: KnownViewType { - public static var typePrefix: String = "" + public static var typePrefix: String = "ToolbarModifier" + public static func inspectionCall(typeName: String) -> String { + return "toolbar(\(ViewType.indexPlaceholder))" + } } } @@ -23,7 +26,7 @@ public extension ViewType.Toolbar { @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) public extension InspectableView { - func toolbar(_ index: Int? = nil) throws -> InspectableView { + func toolbar(_ index: Int = 0) throws -> InspectableView { return try contentForModifierLookup.toolbar(parent: self, index: index) } } @@ -31,7 +34,7 @@ public extension InspectableView { @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) internal extension Content { - func toolbar(parent: UnwrappedView, index: Int?) throws -> InspectableView { + func toolbar(parent: UnwrappedView, index: Int) throws -> InspectableView { let modifierName: String if #available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) { modifierName = "ToolbarModifier" @@ -40,11 +43,16 @@ internal extension Content { } let modifier = try self.modifier({ modifier -> Bool in return modifier.modifierType.contains(modifierName) - }, call: "toolbar", index: index ?? 0) + }, call: "toolbar", index: index) let root = try Inspector.attribute(label: "modifier", value: modifier) let medium = self.medium.resettingViewModifiers() let content = try Inspector.unwrap(content: Content(root, medium: medium)) - return try .init(content, parent: parent, call: "toolbar", index: index) + let index = self.optionalizeIndex(index) { + try self.toolbar(parent: parent, index: 1) + } + let call = ViewType.inspectionCall( + base: ViewType.Toolbar.inspectionCall(typeName: ""), index: index) + return try .init(content, parent: parent, call: call, index: index) } } @@ -119,6 +127,36 @@ public extension InspectableView where View == ViewType.Toolbar { } } +@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) +private extension Content { + func toolbarElementsCount() -> Int { + var index: Int = -1 + var couldLocateItem = false + repeat { + index += 1 + couldLocateItem = (try? Inspector.attribute(path: "content|value|.\(index)", value: view)) != nil + } while couldLocateItem + if index == 0, (try? Inspector.attribute(path: "content|value", value: view)) != nil { + return 1 + } + return index + } +} + +@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) +extension ViewType.Toolbar: SupplementaryChildren { + static func supplementaryChildren(_ parent: UnwrappedView) throws -> LazyGroup { + guard let toolbar = parent as? InspectableView + else { return .empty } + return .init(count: parent.content.toolbarElementsCount()) { index in + if let itemGroup = try? toolbar.itemGroup(index) { + return itemGroup + } + return try toolbar.item(index) + } + } +} + @available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *) public extension InspectableView where View == ViewType.Toolbar.Item { diff --git a/Sources/ViewInspector/SwiftUI/TouchBar.swift b/Sources/ViewInspector/SwiftUI/TouchBar.swift index 7e141286..f5eabe5f 100644 --- a/Sources/ViewInspector/SwiftUI/TouchBar.swift +++ b/Sources/ViewInspector/SwiftUI/TouchBar.swift @@ -45,7 +45,7 @@ public extension InspectableView where View == ViewType.TouchBar { public extension InspectableView { func touchBar() throws -> InspectableView { - return try contentForModifierLookup.touchBar(parent: self) + return try contentForModifierLookup.touchBar(parent: self, index: 0) } func touchBarItemPrincipal() throws -> Bool { @@ -70,19 +70,21 @@ public extension InspectableView { @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) internal extension Content { - func touchBar(parent: UnwrappedView) throws -> InspectableView { + func touchBar(parent: UnwrappedView, index: Int) throws -> InspectableView { let rootView = try modifierAttribute( modifierName: "_TouchBarModifier", path: "modifier|touchBar", - type: Any.self, call: "touchBar") + type: Any.self, call: "touchBar", index: index) let content = try Inspector.unwrap(content: Content(rootView)) - return try .init(content, parent: parent, call: "touchBar()") + let call = ViewType.inspectionCall( + base: ViewType.TouchBar.inspectionCall(typeName: ""), index: nil) + return try .init(content, parent: parent, call: call) } } #else @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) internal extension Content { - func touchBar(parent: UnwrappedView) throws -> InspectableView { + func touchBar(parent: UnwrappedView, index: Int) throws -> InspectableView { throw InspectionError.notSupported("Not supported on this platform") } } diff --git a/Sources/ViewInspector/ViewSearchIndex.swift b/Sources/ViewInspector/ViewSearchIndex.swift index df96caba..44122497 100644 --- a/Sources/ViewInspector/ViewSearchIndex.swift +++ b/Sources/ViewInspector/ViewSearchIndex.swift @@ -40,7 +40,10 @@ internal extension ViewSearch { .init(ViewType.StyleConfiguration.CurrentValueLabel.self), .init(ViewType.TabView.self), .init(ViewType.Text.self), .init(ViewType.TextEditor.self), .init(ViewType.TextField.self), - .init(ViewType.Toggle.self), .init(ViewType.TouchBar.self), .init(ViewType.TupleView.self), + .init(ViewType.Toggle.self), .init(ViewType.TouchBar.self), + .init(ViewType.TupleView.self), .init(ViewType.Toolbar.self), + .init(ViewType.Toolbar.Item.self, genericTypeName: nil), + .init(ViewType.Toolbar.ItemGroup.self, genericTypeName: nil), .init(ViewType.ViewModifierContent.self), .init(ViewType.VSplitView.self), .init(ViewType.VStack.self), .init(ViewType.ZStack.self) ] @@ -235,33 +238,36 @@ internal extension ViewSearch { static private(set) var modifierIdentities: [ModifierIdentity] = [ .init(name: "_OverlayModifier", builder: { parent, index in - try parent.content.overlay(parent: parent) + try parent.content.overlay(parent: parent, index: index) }), .init(name: "_BackgroundModifier", builder: { parent, index in - try parent.content.background(parent: parent) + try parent.content.background(parent: parent, index: index) + }), + .init(name: "ToolbarModifier", builder: { parent, index in + try parent.content.toolbar(parent: parent, index: index) }), .init(name: "PopoverPresentationModifier", builder: { parent, index in - try parent.content.popover(parent: parent) + try parent.content.popover(parent: parent, index: index) }), .init(name: "_MaskEffect", builder: { parent, index in - try parent.content.mask(parent: parent) + try parent.content.mask(parent: parent, index: index) }), .init(name: "_TraitWritingModifier", builder: { parent, index in - try parent.content.tabItem(parent: parent) + try parent.content.tabItem(parent: parent, index: index) }), .init(name: "PlatformItemTraitWriter", builder: { parent, index in - try parent.content.listRowBackground(parent: parent) + try parent.content.listRowBackground(parent: parent, index: index) }), .init(name: "_TouchBarModifier", builder: { parent, index in - try parent.content.touchBar(parent: parent) + try parent.content.touchBar(parent: parent, index: index) }), ] struct ModifierIdentity { - typealias Builder = (UnwrappedView, Int?) throws -> UnwrappedView + typealias Builder = (UnwrappedView, Int) throws -> UnwrappedView let name: String let builder: Builder @@ -292,8 +298,9 @@ internal extension Content { }) let sheets = sheetModifierDescendants(parent: parent) let customModifiers = customViewModifiers() - return .init(count: identities.count, { index -> UnwrappedView in - try identities[index].builder(parent, nil) + let modifiersCount = modifierNames.count + return .init(count: identities.count * modifiersCount, { index -> UnwrappedView in + try identities[index / modifiersCount].builder(parent, index % modifiersCount) }) + sheets + .init(count: customModifiers.count, { index -> UnwrappedView in let modifier = customModifiers[index] let name = Inspector.typeName(value: modifier) diff --git a/Tests/ViewInspectorTests/SwiftUI/ActionSheetTests.swift b/Tests/ViewInspectorTests/SwiftUI/ActionSheetTests.swift index 97094a62..5315eb10 100644 --- a/Tests/ViewInspectorTests/SwiftUI/ActionSheetTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/ActionSheetTests.swift @@ -142,7 +142,7 @@ final class ActionSheetTests: XCTestCase { let title1 = try sut.inspect().hStack().emptyView(0).actionSheet().title() XCTAssertEqual(try title1.string(), "title_1") XCTAssertEqual(title1.pathToRoot, - "view(ActionSheetFindTestView.self).hStack().emptyView(0).actionSheet().title()") + "view(ActionSheetFindTestView.self).hStack().emptyView(0).actionSheet(0).title()") let title2 = try sut.inspect().hStack().emptyView(0).actionSheet(1).title() XCTAssertEqual(try title2.string(), "title_3") XCTAssertEqual(title2.pathToRoot, diff --git a/Tests/ViewInspectorTests/SwiftUI/AlertTests.swift b/Tests/ViewInspectorTests/SwiftUI/AlertTests.swift index 171b5bdc..30abc2d3 100644 --- a/Tests/ViewInspectorTests/SwiftUI/AlertTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/AlertTests.swift @@ -186,7 +186,7 @@ final class AlertTests: XCTestCase { let title1 = try sut.inspect().hStack().emptyView(0).alert().title() XCTAssertEqual(try title1.string(), "title_1") XCTAssertEqual(title1.pathToRoot, - "view(AlertFindTestView.self).hStack().emptyView(0).alert().title()") + "view(AlertFindTestView.self).hStack().emptyView(0).alert(0).title()") let title2 = try sut.inspect().hStack().emptyView(0).alert(1).title() XCTAssertEqual(try title2.string(), "title_3") XCTAssertEqual(title2.pathToRoot, diff --git a/Tests/ViewInspectorTests/SwiftUI/SheetTests.swift b/Tests/ViewInspectorTests/SwiftUI/SheetTests.swift index 18577663..f3f5ef34 100644 --- a/Tests/ViewInspectorTests/SwiftUI/SheetTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/SheetTests.swift @@ -94,7 +94,7 @@ final class SheetTests: XCTestCase { let title1 = try sut.inspect().hStack().emptyView(0).sheet().text(0) XCTAssertEqual(try title1.string(), "title_1") XCTAssertEqual(title1.pathToRoot, - "view(SheetFindTestView.self).hStack().emptyView(0).sheet().text(0)") + "view(SheetFindTestView.self).hStack().emptyView(0).sheet(0).text(0)") let title2 = try sut.inspect().hStack().emptyView(0).sheet(1).text(0) XCTAssertEqual(try title2.string(), "title_3") XCTAssertEqual(title2.pathToRoot, diff --git a/Tests/ViewInspectorTests/SwiftUI/ToolbarTests.swift b/Tests/ViewInspectorTests/SwiftUI/ToolbarTests.swift index 410b5471..24208b06 100644 --- a/Tests/ViewInspectorTests/SwiftUI/ToolbarTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/ToolbarTests.swift @@ -135,4 +135,24 @@ final class ToolbarTests: XCTestCase { XCTAssertFalse(try toolbar.item(0).showsByDefault()) XCTAssertTrue(try toolbar.item(1).showsByDefault()) } + + func testSearchAndPathToRoot() throws { + let sut = Group { + EmptyView() + .toolbar { + ToolbarItem { Text("1"); Text("2") } + ToolbarItemGroup { HStack { Text("3"); Text("4") } } + } + .padding() + .toolbar { + ToolbarItem { Text("5") } + } + } + XCTAssertEqual(try sut.inspect().find(text: "2").pathToRoot, + "group().emptyView(0).toolbar().item(0).text(1)") + XCTAssertEqual(try sut.inspect().find(text: "3").pathToRoot, + "group().emptyView(0).toolbar().itemGroup(1).hStack().text(0)") + XCTAssertEqual(try sut.inspect().find(text: "5").pathToRoot, + "group().emptyView(0).toolbar(1).item(0).text()") + } } diff --git a/Tests/ViewInspectorTests/SwiftUI/TouchBarTests.swift b/Tests/ViewInspectorTests/SwiftUI/TouchBarTests.swift index 354b566d..f122b832 100644 --- a/Tests/ViewInspectorTests/SwiftUI/TouchBarTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/TouchBarTests.swift @@ -94,7 +94,7 @@ extension TouchBarItemPresence: BinaryEquatable { } final class TouchBarTests: XCTestCase { func testNotSupported() throws { let view = try EmptyView().inspect() - XCTAssertThrows(try view.content.touchBar(parent: view), + XCTAssertThrows(try view.content.touchBar(parent: view, index: 0), "Not supported on this platform") } } From eae5d5f42bda24a9f7ca3be25ad215c5ebd7847f Mon Sep 17 00:00:00 2001 From: Alexey Naumov Date: Sun, 5 Sep 2021 14:18:30 +0300 Subject: [PATCH 36/99] Fix Toolbar tests for macOS --- Sources/ViewInspector/Inspector.swift | 15 +++++++++++++-- Sources/ViewInspector/SwiftUI/Toolbar.swift | 15 ++++++++------- Sources/ViewInspector/ViewSearchIndex.swift | 2 +- .../ViewInspectorTests/SwiftUI/ToolbarTests.swift | 12 +++++++++--- 4 files changed, 31 insertions(+), 13 deletions(-) diff --git a/Sources/ViewInspector/Inspector.swift b/Sources/ViewInspector/Inspector.swift index 96d007ea..ee561338 100644 --- a/Sources/ViewInspector/Inspector.swift +++ b/Sources/ViewInspector/Inspector.swift @@ -52,8 +52,19 @@ extension Inspector { prefixOnly: Bool = false) -> String { let typeName = namespaced ? String(reflecting: type) : String(describing: type) guard prefixOnly else { return typeName } - return typeName.components(separatedBy: "<").first! - } + let name = typeName.components(separatedBy: "<").first! + guard namespaced else { return name } + let string = NSMutableString(string: name) + let range = NSRange(location: 0, length: string.length) + namespaceSanitizeRegex.replaceMatches(in: string, options: [], range: range, withTemplate: "SwiftUI") + return String(string) + } + + private static var namespaceSanitizeRegex: NSRegularExpression = { + guard let regex = try? NSRegularExpression(pattern: "SwiftUI.\\(unknown context at .*\\)", options: []) + else { fatalError() } + return regex + }() } // MARK: - Attributes lookup diff --git a/Sources/ViewInspector/SwiftUI/Toolbar.swift b/Sources/ViewInspector/SwiftUI/Toolbar.swift index 294cfe4e..9bfe042f 100644 --- a/Sources/ViewInspector/SwiftUI/Toolbar.swift +++ b/Sources/ViewInspector/SwiftUI/Toolbar.swift @@ -4,7 +4,13 @@ import SwiftUI public extension ViewType { struct Toolbar: KnownViewType { - public static var typePrefix: String = "ToolbarModifier" + public static let typePrefix: String = { + if #available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) { + return "ToolbarModifier" + } else { + return "_ToolbarItemGroupModifier" + } + }() public static func inspectionCall(typeName: String) -> String { return "toolbar(\(ViewType.indexPlaceholder))" } @@ -35,12 +41,7 @@ public extension InspectableView { internal extension Content { func toolbar(parent: UnwrappedView, index: Int) throws -> InspectableView { - let modifierName: String - if #available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) { - modifierName = "ToolbarModifier" - } else { - modifierName = "_ToolbarItemGroupModifier" - } + let modifierName = ViewType.Toolbar.typePrefix let modifier = try self.modifier({ modifier -> Bool in return modifier.modifierType.contains(modifierName) }, call: "toolbar", index: index) diff --git a/Sources/ViewInspector/ViewSearchIndex.swift b/Sources/ViewInspector/ViewSearchIndex.swift index 44122497..8b982612 100644 --- a/Sources/ViewInspector/ViewSearchIndex.swift +++ b/Sources/ViewInspector/ViewSearchIndex.swift @@ -243,7 +243,7 @@ internal extension ViewSearch { .init(name: "_BackgroundModifier", builder: { parent, index in try parent.content.background(parent: parent, index: index) }), - .init(name: "ToolbarModifier", builder: { parent, index in + .init(name: ViewType.Toolbar.typePrefix, builder: { parent, index in try parent.content.toolbar(parent: parent, index: index) }), .init(name: "PopoverPresentationModifier", builder: { parent, index in diff --git a/Tests/ViewInspectorTests/SwiftUI/ToolbarTests.swift b/Tests/ViewInspectorTests/SwiftUI/ToolbarTests.swift index 24208b06..ce9ea199 100644 --- a/Tests/ViewInspectorTests/SwiftUI/ToolbarTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/ToolbarTests.swift @@ -6,10 +6,16 @@ import SwiftUI final class ToolbarTests: XCTestCase { func testToolbarItemPlacementEquatable() throws { + #if os(iOS) let values: [ToolbarItemPlacement] = [ - .automatic, .principal, .bottomBar, - .primaryAction, .cancellationAction, .confirmationAction, .destructiveAction, - .navigation, .navigationBarLeading, .navigationBarTrailing] + .automatic, .principal, .bottomBar, .navigation, + .navigationBarLeading, .navigationBarTrailing, + .primaryAction, .cancellationAction, .confirmationAction, .destructiveAction] + #else + let values: [ToolbarItemPlacement] = [ + .automatic, .principal, .navigation, + .primaryAction, .cancellationAction, .confirmationAction, .destructiveAction] + #endif values.enumerated().forEach { lhs in values.enumerated().forEach { rhs in if lhs.offset == rhs.offset { From 9cc2618b86f28fe3ef127ca132130f4d7969acef Mon Sep 17 00:00:00 2001 From: Alexey Naumov Date: Mon, 6 Sep 2021 12:52:01 +0300 Subject: [PATCH 37/99] Fix tests for other platforms and os versions --- .../Modifiers/EnvironmentModifiers.swift | 46 ++++++++++++++----- .../SwiftUI/CustomViewModifier.swift | 3 +- Sources/ViewInspector/SwiftUI/TabView.swift | 2 +- .../SwiftUI/ToolbarTests.swift | 28 ++++++++++- 4 files changed, 65 insertions(+), 14 deletions(-) diff --git a/Sources/ViewInspector/Modifiers/EnvironmentModifiers.swift b/Sources/ViewInspector/Modifiers/EnvironmentModifiers.swift index ad6bf8d8..5436d660 100644 --- a/Sources/ViewInspector/Modifiers/EnvironmentModifiers.swift +++ b/Sources/ViewInspector/Modifiers/EnvironmentModifiers.swift @@ -38,8 +38,27 @@ internal extension Inspector { } } +@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) +internal protocol EnvironmentModifier { + static func qualifiesAsEnvironmentModifier() -> Bool + func keyPath() throws -> Any + func value() throws -> Any +} + +@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) +extension EnvironmentModifier { + func qualifiesAsEnvironmentModifier() -> Bool { + return Self.qualifiesAsEnvironmentModifier() + } +} + @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) extension ModifiedContent: EnvironmentModifier where Modifier: EnvironmentModifier { + + static func qualifiesAsEnvironmentModifier() -> Bool { + return Modifier.qualifiesAsEnvironmentModifier() + } + func keyPath() throws -> Any { return try Inspector.attribute(label: "modifier", value: self, type: Modifier.self).keyPath() @@ -51,15 +70,13 @@ extension ModifiedContent: EnvironmentModifier where Modifier: EnvironmentModifi } } -@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) -internal protocol EnvironmentModifier { - func keyPath() throws -> Any - func value() throws -> Any -} - @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) extension _EnvironmentKeyWritingModifier: EnvironmentModifier { + static func qualifiesAsEnvironmentModifier() -> Bool { + return true + } + func keyPath() throws -> Any { return try Inspector.attribute(label: "keyPath", value: self) } @@ -69,10 +86,18 @@ extension _EnvironmentKeyWritingModifier: EnvironmentModifier { } } -#if !os(macOS) -@available(iOS 15.0, tvOS 15.0, watchOS 8.0, *) -@available(macOS, unavailable) -extension _EnvironmentKeyTransformModifier: EnvironmentModifier where Value == TextInputAutocapitalization { +@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) +extension _EnvironmentKeyTransformModifier: EnvironmentModifier { + + static func qualifiesAsEnvironmentModifier() -> Bool { + #if !os(macOS) + if #available(iOS 15.0, tvOS 15.0, watchOS 8.0, *), + Value.self == TextInputAutocapitalization.self { + return true + } + #endif + return false + } func keyPath() throws -> Any { return try Inspector.attribute(label: "keyPath", value: self) @@ -82,4 +107,3 @@ extension _EnvironmentKeyTransformModifier: EnvironmentModifier where Value == T return try Inspector.attribute(label: "transform", value: self) } } -#endif diff --git a/Sources/ViewInspector/SwiftUI/CustomViewModifier.swift b/Sources/ViewInspector/SwiftUI/CustomViewModifier.swift index 10dc8b30..5b0b6c3d 100644 --- a/Sources/ViewInspector/SwiftUI/CustomViewModifier.swift +++ b/Sources/ViewInspector/SwiftUI/CustomViewModifier.swift @@ -66,7 +66,8 @@ internal extension Content { func unwrappedModifiedContent() throws -> Content { let view = try Inspector.attribute(label: "content", value: self.view) var medium: Content.Medium - if let modifier = self.view as? EnvironmentModifier { + if let modifier = self.view as? EnvironmentModifier, + modifier.qualifiesAsEnvironmentModifier() { if let value = try? modifier.value(), let object = try? Inspector.attribute(label: "some", value: value, type: AnyObject.self), !(object is NSObject) { diff --git a/Sources/ViewInspector/SwiftUI/TabView.swift b/Sources/ViewInspector/SwiftUI/TabView.swift index c078ce34..c902f842 100644 --- a/Sources/ViewInspector/SwiftUI/TabView.swift +++ b/Sources/ViewInspector/SwiftUI/TabView.swift @@ -83,7 +83,7 @@ internal extension Content { return view } return try modifierAttribute( - modifierName: "PlatformItemTraitWriter", path: "modifier|source|content|content|content", + modifierName: "PlatformItemTraitWriter", path: "modifier|source|content|content", type: Any.self, call: "tabItem", index: index) }() let medium = self.medium.resettingViewModifiers() diff --git a/Tests/ViewInspectorTests/SwiftUI/ToolbarTests.swift b/Tests/ViewInspectorTests/SwiftUI/ToolbarTests.swift index ce9ea199..06373948 100644 --- a/Tests/ViewInspectorTests/SwiftUI/ToolbarTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/ToolbarTests.swift @@ -2,10 +2,12 @@ import XCTest import SwiftUI @testable import ViewInspector -@available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *) +@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) final class ToolbarTests: XCTestCase { func testToolbarItemPlacementEquatable() throws { + guard #available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *) + else { return } #if os(iOS) let values: [ToolbarItemPlacement] = [ .automatic, .principal, .bottomBar, .navigation, @@ -28,6 +30,8 @@ final class ToolbarTests: XCTestCase { } func testDoesNotBlockInspection() throws { + guard #available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *) + else { return } let sut = Group { EmptyView().offset().toolbar { Text("") }.padding() } @@ -35,6 +39,8 @@ final class ToolbarTests: XCTestCase { } func testSimpleExtraction() throws { + guard #available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *) + else { return } let sut = EmptyView() .toolbar { ToolbarItem { Text("abc") } } let text = try sut.inspect().toolbar().item().text().string() @@ -42,6 +48,8 @@ final class ToolbarTests: XCTestCase { } func testMultipleToolbarsExtraction() throws { + guard #available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *) + else { return } let sut = EmptyView() .toolbar { ToolbarItem { Text("abc1") } } .padding() @@ -53,6 +61,8 @@ final class ToolbarTests: XCTestCase { } func testMultipleItemsExtraction() throws { + guard #available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *) + else { return } let sut = EmptyView() .toolbar { ToolbarItem { Text("1") } @@ -68,6 +78,8 @@ final class ToolbarTests: XCTestCase { } func testMultipleChildViewsExtraction() throws { + guard #available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *) + else { return } let sut = EmptyView() .toolbar { ToolbarItem { Text("1"); Text("2") } @@ -84,12 +96,16 @@ final class ToolbarTests: XCTestCase { } func testImplicitToolbarItemGroup() throws { + guard #available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *) + else { return } let sut = EmptyView().toolbar { Text("abc") } let text = try sut.inspect().toolbar().itemGroup().text().string() XCTAssertEqual(text, "abc") } func testToolbarIdentifier() throws { + guard #available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *) + else { return } let sut = EmptyView() .toolbar { Text("") } .toolbar(id: "abc") { ToolbarItem(id: "") { Text("") } } @@ -98,6 +114,8 @@ final class ToolbarTests: XCTestCase { } func testToolbarItemIdentifier() throws { + guard #available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *) + else { return } let sut = EmptyView().toolbar { ToolbarItem(id: "abc") { Text("") } ToolbarItem(id: "xyz") { EmptyView() } @@ -109,6 +127,8 @@ final class ToolbarTests: XCTestCase { } func testToolbarItemPlacement() throws { + guard #available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *) + else { return } let sut = EmptyView().toolbar { ToolbarItem(placement: .destructiveAction) { EmptyView() } ToolbarItem(placement: .principal) { EmptyView() } @@ -121,6 +141,8 @@ final class ToolbarTests: XCTestCase { } func testToolbarItemGroupPlacement() throws { + guard #available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *) + else { return } let sut = EmptyView().toolbar { ToolbarItemGroup(placement: .destructiveAction) { EmptyView() } ToolbarItemGroup(placement: .principal) { EmptyView() } @@ -133,6 +155,8 @@ final class ToolbarTests: XCTestCase { } func testToolbarItemShowsByDefault() throws { + guard #available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *) + else { return } let sut = EmptyView().toolbar { ToolbarItem(id: "", showsByDefault: false) { EmptyView() } ToolbarItem { EmptyView() } @@ -143,6 +167,8 @@ final class ToolbarTests: XCTestCase { } func testSearchAndPathToRoot() throws { + guard #available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *) + else { return } let sut = Group { EmptyView() .toolbar { From b31165fb8e9e3ea7096c4e4f37b96c5b9573f2fa Mon Sep 17 00:00:00 2001 From: Alexey Naumov Date: Mon, 6 Sep 2021 13:09:05 +0300 Subject: [PATCH 38/99] Clean up after merging --- .../SwiftUI/FullScreenCover.swift | 34 ++++--------- .../SwiftUI/FullScreenCoverTests.swift | 50 ++++++++++++------- ViewInspector.xcodeproj/project.pbxproj | 2 +- 3 files changed, 41 insertions(+), 45 deletions(-) diff --git a/Sources/ViewInspector/SwiftUI/FullScreenCover.swift b/Sources/ViewInspector/SwiftUI/FullScreenCover.swift index 1e75ebd5..be5afcfb 100644 --- a/Sources/ViewInspector/SwiftUI/FullScreenCover.swift +++ b/Sources/ViewInspector/SwiftUI/FullScreenCover.swift @@ -1,14 +1,5 @@ -// -// FullScreenCover.swift -// ViewInspector -// -// Created by Richard Gist on 9/2/21. -// - import SwiftUI -// MARK: - FullScreenCover - @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) public extension ViewType { @@ -47,7 +38,7 @@ extension ViewType.FullScreenCover: MultipleViewContent { // MARK: - Extraction -@available(iOS 13.0, tvOS 13.0, *) +@available(iOS 14.0, tvOS 14.0, watchOS 7.0, *) @available(macOS, unavailable) public extension InspectableView { @@ -56,8 +47,7 @@ public extension InspectableView { } } -@available(iOS 13.0, tvOS 13.0, *) -@available(macOS, unavailable) +@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) internal extension Content { func fullScreenCover(parent: UnwrappedView, index: Int?) throws -> InspectableView { @@ -101,8 +91,7 @@ internal extension Content { } } -@available(iOS 13.0, tvOS 13.0, *) -@available(macOS, unavailable) +@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) internal extension ViewType.FullScreenCover { struct Container: CustomViewIdentityMapping { let view: Any @@ -114,7 +103,7 @@ internal extension ViewType.FullScreenCover { // MARK: - Custom Attributes -@available(iOS 13.0, tvOS 13.0, *) +@available(iOS 14.0, tvOS 14.0, watchOS 7.0, *) @available(macOS, unavailable) public extension InspectableView where View == ViewType.FullScreenCover { @@ -124,30 +113,26 @@ public extension InspectableView where View == ViewType.FullScreenCover { } } -@available(iOS 13.0, tvOS 13.0, *) -@available(macOS, unavailable) +@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) public protocol FullScreenCoverBuilder: SystemPopupPresenter { var onDismiss: (() -> Void)? { get } func buildFullScreenCover() throws -> Any } -@available(iOS 13.0, tvOS 13.0, *) -@available(macOS, unavailable) +@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) public protocol FullScreenCoverProvider: FullScreenCoverBuilder { var isPresented: Binding { get } var fullScreenCoverBuilder: () -> Any { get } } -@available(iOS 13.0, tvOS 13.0, *) -@available(macOS, unavailable) +@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) public protocol FullScreenCoverItemProvider: FullScreenCoverBuilder { associatedtype Item: Identifiable var item: Binding { get } var fullScreenCoverBuilder: (Item) -> Any { get } } -@available(iOS 13.0, tvOS 13.0, *) -@available(macOS, unavailable) +@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) public extension FullScreenCoverProvider { func buildFullScreenCover() throws -> Any { @@ -163,8 +148,7 @@ public extension FullScreenCoverProvider { } } -@available(iOS 13.0, tvOS 13.0, *) -@available(macOS, unavailable) +@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) public extension FullScreenCoverItemProvider { func buildFullScreenCover() throws -> Any { diff --git a/Tests/ViewInspectorTests/SwiftUI/FullScreenCoverTests.swift b/Tests/ViewInspectorTests/SwiftUI/FullScreenCoverTests.swift index 6496c9e8..5e921d23 100644 --- a/Tests/ViewInspectorTests/SwiftUI/FullScreenCoverTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/FullScreenCoverTests.swift @@ -1,20 +1,12 @@ -// -// FullScreenCoverTests.swift -// ViewInspector -// -// Created by Richard Gist on 9/2/21. -// - import XCTest import SwiftUI @testable import ViewInspector #if !os(macOS) -@available(iOS 14.0, tvOS 14.0, watchOS 7.0, *) -@available(macOS, unavailable) final class FullScreenCoverTests: XCTestCase { func testFullScreenCover() throws { + guard #available(iOS 14.0, tvOS 14.0, watchOS 7.0, *) else { return } let binding = Binding(wrappedValue: true) let sut = EmptyView().fullScreenCover(isPresented: binding) { Text("") } print("\(Inspector.print(sut) as AnyObject)") @@ -22,12 +14,14 @@ final class FullScreenCoverTests: XCTestCase { } func testInspectionErrorNoModifier() throws { + guard #available(iOS 14.0, tvOS 14.0, watchOS 7.0, *) else { return } let sut = EmptyView().offset() XCTAssertThrows(try sut.inspect().emptyView().fullScreenCover(), "EmptyView does not have 'fullScreenCover' modifier") } func testInspectionErrorCustomModifierRequired() throws { + guard #available(iOS 14.0, tvOS 14.0, watchOS 7.0, *) else { return } let binding = Binding(wrappedValue: true) let sut = EmptyView().fullScreenCover(isPresented: binding) { Text("") } XCTAssertThrows(try sut.inspect().emptyView().fullScreenCover(), @@ -38,6 +32,7 @@ final class FullScreenCoverTests: XCTestCase { } func testInspectionErrorFullScreenCoverNotPresented() throws { + guard #available(iOS 14.0, tvOS 14.0, watchOS 7.0, *) else { return } let binding = Binding(wrappedValue: false) let sut = EmptyView().fullScreenCover2(isPresented: binding) { Text("") } XCTAssertThrows(try sut.inspect().emptyView().fullScreenCover(), @@ -45,6 +40,7 @@ final class FullScreenCoverTests: XCTestCase { } func testInspectionErrorFullScreenCoverWithItemNotPresented() throws { + guard #available(iOS 14.0, tvOS 14.0, watchOS 7.0, *) else { return } let binding = Binding(wrappedValue: nil) let sut = EmptyView().fullScreenCover2(item: binding) { Text("\($0)") } XCTAssertThrows(try sut.inspect().emptyView().fullScreenCover(), @@ -52,6 +48,7 @@ final class FullScreenCoverTests: XCTestCase { } func testContentInspection() throws { + guard #available(iOS 14.0, tvOS 14.0, watchOS 7.0, *) else { return } let binding = Binding(wrappedValue: true) let sut = EmptyView().fullScreenCover2(isPresented: binding) { Text("abc") @@ -62,6 +59,7 @@ final class FullScreenCoverTests: XCTestCase { } func testContentInteraction() throws { + guard #available(iOS 14.0, tvOS 14.0, watchOS 7.0, *) else { return } let binding = Binding(wrappedValue: true) let sut = EmptyView().fullScreenCover2(isPresented: binding) { Text("abc") @@ -74,6 +72,7 @@ final class FullScreenCoverTests: XCTestCase { } func testOnDismiss() throws { + guard #available(iOS 14.0, tvOS 14.0, watchOS 7.0, *) else { return } let exp = XCTestExpectation(description: #function) let binding = Binding(wrappedValue: true) let sut = EmptyView().fullScreenCover2(isPresented: binding, onDismiss: { @@ -86,6 +85,7 @@ final class FullScreenCoverTests: XCTestCase { } func testContentWithItemInspection() throws { + guard #available(iOS 14.0, tvOS 14.0, watchOS 7.0, *) else { return } let binding = Binding(wrappedValue: 6) let sut = EmptyView().fullScreenCover2(item: binding) { Text("\($0)") } let fullScreenCover = try sut.inspect().emptyView().fullScreenCover() @@ -96,10 +96,12 @@ final class FullScreenCoverTests: XCTestCase { } func testMultipleFullScreenCoversInspection() throws { + guard #available(iOS 14.0, tvOS 14.0, watchOS 7.0, *) else { return } let binding1 = Binding(wrappedValue: true) let binding2 = Binding(wrappedValue: true) let binding3 = Binding(wrappedValue: true) - let sut = FullScreenCoverFindTestView(fullScreenCover1: binding1, fullScreenCover2: binding2, fullScreenCover3: binding3) + let sut = FullScreenCoverFindTestView( + fullScreenCover1: binding1, fullScreenCover2: binding2, fullScreenCover3: binding3) let title1 = try sut.inspect().hStack().emptyView(0).fullScreenCover().text(0) XCTAssertEqual(try title1.string(), "title_1") XCTAssertEqual(title1.pathToRoot, @@ -118,14 +120,19 @@ final class FullScreenCoverTests: XCTestCase { } func testFindAndPathToRoots() throws { + guard #available(iOS 14.0, tvOS 14.0, watchOS 7.0, *) else { return } let binding = Binding(wrappedValue: true) - let sut = FullScreenCoverFindTestView(fullScreenCover1: binding, fullScreenCover2: binding, fullScreenCover3: binding) + let sut = FullScreenCoverFindTestView( + fullScreenCover1: binding, fullScreenCover2: binding, fullScreenCover3: binding) // 1 XCTAssertEqual(try sut.inspect().find(text: "title_1").pathToRoot, "view(FullScreenCoverFindTestView.self).hStack().emptyView(0).fullScreenCover().text(0)") XCTAssertEqual(try sut.inspect().find(text: "button_1").pathToRoot, - "view(FullScreenCoverFindTestView.self).hStack().emptyView(0).fullScreenCover().button(1).labelView().text()") + """ + view(FullScreenCoverFindTestView.self).hStack().emptyView(0)\ + .fullScreenCover().button(1).labelView().text() + """) // 2 XCTAssertThrows(try sut.inspect().find(text: "title_2").pathToRoot, "Search did not find a match") @@ -137,7 +144,10 @@ final class FullScreenCoverTests: XCTestCase { XCTAssertThrows(try sut.inspect().find(text: "message_3").pathToRoot, "Search did not find a match") XCTAssertEqual(try sut.inspect().find(text: "button_3").pathToRoot, - "view(FullScreenCoverFindTestView.self).hStack().emptyView(0).fullScreenCover(1).button(1).labelView().text()") + """ + view(FullScreenCoverFindTestView.self).hStack().emptyView(0)\ + .fullScreenCover(1).button(1).labelView().text() + """) } } @@ -145,15 +155,16 @@ final class FullScreenCoverTests: XCTestCase { @available(macOS, unavailable) private extension View { func fullScreenCover2(isPresented: Binding, - onDismiss: (() -> Void)? = nil, - @ViewBuilder content: @escaping () -> FullScreenCover + onDismiss: (() -> Void)? = nil, + @ViewBuilder content: @escaping () -> FullScreenCover ) -> some View where FullScreenCover: View { - return self.modifier(InspectableFullScreenCover(isPresented: isPresented, onDismiss: onDismiss, content: content)) + return self.modifier(InspectableFullScreenCover( + isPresented: isPresented, onDismiss: onDismiss, content: content)) } func fullScreenCover2(item: Binding, - onDismiss: (() -> Void)? = nil, - content: @escaping (Item) -> FullScreenCover + onDismiss: (() -> Void)? = nil, + content: @escaping (Item) -> FullScreenCover ) -> some View where Item: Identifiable, FullScreenCover: View { return self.modifier(InspectableFullScreenCoverWithItem(item: item, onDismiss: onDismiss, content: content)) } @@ -161,7 +172,8 @@ private extension View { @available(iOS 14.0, tvOS 14.0, watchOS 7.0, *) @available(macOS, unavailable) -private struct InspectableFullScreenCover: ViewModifier, FullScreenCoverProvider where FullScreenCover: View { +private struct InspectableFullScreenCover: ViewModifier, FullScreenCoverProvider +where FullScreenCover: View { let isPresented: Binding let onDismiss: (() -> Void)? diff --git a/ViewInspector.xcodeproj/project.pbxproj b/ViewInspector.xcodeproj/project.pbxproj index 18bb4d6f..15a50878 100644 --- a/ViewInspector.xcodeproj/project.pbxproj +++ b/ViewInspector.xcodeproj/project.pbxproj @@ -613,6 +613,7 @@ F6D933A62385E9E000358E0E /* EquatableView.swift */, F60EEBCC2382EED0007DB53A /* ForEach.swift */, F60EEBC52382EED0007DB53A /* Form.swift */, + D7A6CE8826E17AE900599824 /* FullScreenCover.swift */, F6D9339A2385AD9100358E0E /* GeometryReader.swift */, CDA84477262B6C3E00C56C98 /* Gesture.swift */, F60EEBC62382EED0007DB53A /* Group.swift */, @@ -668,7 +669,6 @@ F6D933B22385ED1400358E0E /* VSplitView.swift */, F60EEBC92382EED0007DB53A /* VStack.swift */, F60EEBC12382EED0007DB53A /* ZStack.swift */, - D7A6CE8826E17AE900599824 /* FullScreenCover.swift */, ); path = SwiftUI; sourceTree = ""; From 6c7151442c8bd7318b2e49dc2c689f0316af0d16 Mon Sep 17 00:00:00 2001 From: Alexey Naumov Date: Mon, 6 Sep 2021 13:14:57 +0300 Subject: [PATCH 39/99] Tiny refactor of the sheets search --- Sources/ViewInspector/SwiftUI/ActionSheet.swift | 2 +- Sources/ViewInspector/SwiftUI/Alert.swift | 2 +- Sources/ViewInspector/SwiftUI/FullScreenCover.swift | 2 +- Sources/ViewInspector/SwiftUI/Sheet.swift | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Sources/ViewInspector/SwiftUI/ActionSheet.swift b/Sources/ViewInspector/SwiftUI/ActionSheet.swift index 4f9bb2db..7e7ecd4b 100644 --- a/Sources/ViewInspector/SwiftUI/ActionSheet.swift +++ b/Sources/ViewInspector/SwiftUI/ActionSheet.swift @@ -60,7 +60,7 @@ internal extension Content { func actionSheetsForSearch() -> [ViewSearch.ModifierIdentity] { let count = medium.viewModifiers - .compactMap { isActionSheetBuilder(modifier: $0) } + .filter { isActionSheetBuilder(modifier: $0) } .count return Array(0.. [ViewSearch.ModifierIdentity] { let count = medium.viewModifiers - .compactMap { isAlertBuilder(modifier: $0) } + .filter { isAlertBuilder(modifier: $0) } .count return Array(0.. [ViewSearch.ModifierIdentity] { let count = medium.viewModifiers - .compactMap { isFullScreenCoverBuilder(modifier: $0) } + .filter { isFullScreenCoverBuilder(modifier: $0) } .count return Array(0.. [ViewSearch.ModifierIdentity] { let count = medium.viewModifiers - .compactMap { isSheetBuilder(modifier: $0) } + .filter { isSheetBuilder(modifier: $0) } .count return Array(0.. Date: Mon, 6 Sep 2021 13:36:50 +0300 Subject: [PATCH 40/99] Revert changes for overlay unwrapping indices --- Sources/ViewInspector/BaseTypes.swift | 13 ------------- .../Modifiers/VisualEffectModifiers.swift | 9 +++------ .../ViewInspector/SwiftUI/ActionSheet.swift | 9 +++------ Sources/ViewInspector/SwiftUI/Alert.swift | 9 +++------ Sources/ViewInspector/SwiftUI/List.swift | 12 +++++++----- Sources/ViewInspector/SwiftUI/Overlay.swift | 18 ++++++------------ Sources/ViewInspector/SwiftUI/Popover.swift | 9 +++------ Sources/ViewInspector/SwiftUI/Sheet.swift | 9 +++------ Sources/ViewInspector/SwiftUI/TabView.swift | 6 +++--- Sources/ViewInspector/SwiftUI/Toolbar.swift | 9 +++------ Sources/ViewInspector/SwiftUI/TouchBar.swift | 4 ++-- Sources/ViewInspector/ViewSearchIndex.swift | 11 +++++++++-- .../SwiftUI/ActionSheetTests.swift | 2 +- .../SwiftUI/AlertTests.swift | 2 +- .../SwiftUI/SheetTests.swift | 2 +- 15 files changed, 48 insertions(+), 76 deletions(-) diff --git a/Sources/ViewInspector/BaseTypes.swift b/Sources/ViewInspector/BaseTypes.swift index 5743894c..a6fe4da1 100644 --- a/Sources/ViewInspector/BaseTypes.swift +++ b/Sources/ViewInspector/BaseTypes.swift @@ -130,19 +130,6 @@ internal extension ViewType { } } -@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) -internal extension Content { - func optionalizeIndex(_ index: Int, hasMore: () throws -> Any) -> Int? { - if index > 0 { return index } - do { - _ = try hasMore() - return 0 - } catch { - return nil - } - } -} - // MARK: - Content @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) diff --git a/Sources/ViewInspector/Modifiers/VisualEffectModifiers.swift b/Sources/ViewInspector/Modifiers/VisualEffectModifiers.swift index bcec9f88..46c76d0a 100644 --- a/Sources/ViewInspector/Modifiers/VisualEffectModifiers.swift +++ b/Sources/ViewInspector/Modifiers/VisualEffectModifiers.swift @@ -127,21 +127,18 @@ public extension InspectableView { return shape.cornerSize.width } - func mask(_ index: Int = 0) throws -> InspectableView { + func mask(_ index: Int? = nil) throws -> InspectableView { return try contentForModifierLookup.mask(parent: self, index: index) } } @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) internal extension Content { - func mask(parent: UnwrappedView, index: Int) throws -> InspectableView { + func mask(parent: UnwrappedView, index: Int?) throws -> InspectableView { let rootView = try modifierAttribute( modifierName: "_MaskEffect", path: "modifier|mask", - type: Any.self, call: "mask", index: index) + type: Any.self, call: "mask", index: index ?? 0) let medium = self.medium.resettingViewModifiers() - let index = self.optionalizeIndex(index) { - try self.mask(parent: parent, index: 1) - } let call = ViewType.inspectionCall( base: "mask(\(ViewType.indexPlaceholder))", index: index) return try .init(try Inspector.unwrap(content: Content(rootView, medium: medium)), diff --git a/Sources/ViewInspector/SwiftUI/ActionSheet.swift b/Sources/ViewInspector/SwiftUI/ActionSheet.swift index 7e7ecd4b..e5e56353 100644 --- a/Sources/ViewInspector/SwiftUI/ActionSheet.swift +++ b/Sources/ViewInspector/SwiftUI/ActionSheet.swift @@ -22,7 +22,7 @@ public extension ViewType { @available(macOS, unavailable) public extension InspectableView { - func actionSheet(_ index: Int = 0) throws -> InspectableView { + func actionSheet(_ index: Int? = nil) throws -> InspectableView { return try contentForModifierLookup.actionSheet(parent: self, index: index) } } @@ -31,10 +31,10 @@ public extension InspectableView { @available(macOS, unavailable) internal extension Content { - func actionSheet(parent: UnwrappedView, index: Int) throws -> InspectableView { + func actionSheet(parent: UnwrappedView, index: Int?) throws -> InspectableView { guard let sheetBuilder = try? self.modifierAttribute( modifierLookup: { isActionSheetBuilder(modifier: $0) }, path: "modifier", - type: ActionSheetBuilder.self, call: "", index: index) + type: ActionSheetBuilder.self, call: "", index: index ?? 0) else { _ = try self.modifier({ $0.modifierType == "IdentifiedPreferenceTransformModifier" @@ -50,9 +50,6 @@ internal extension Content { let container = ViewType.ActionSheet.Container(sheet: sheet, builder: sheetBuilder) let medium = self.medium.resettingViewModifiers() let content = Content(container, medium: medium) - let index = self.optionalizeIndex(index) { - try self.actionSheet(parent: parent, index: 1) - } let call = ViewType.inspectionCall( base: ViewType.ActionSheet.inspectionCall(typeName: ""), index: index) return try .init(content, parent: parent, call: call, index: index) diff --git a/Sources/ViewInspector/SwiftUI/Alert.swift b/Sources/ViewInspector/SwiftUI/Alert.swift index 849b6712..d8b6ea05 100644 --- a/Sources/ViewInspector/SwiftUI/Alert.swift +++ b/Sources/ViewInspector/SwiftUI/Alert.swift @@ -21,7 +21,7 @@ public extension ViewType { @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) public extension InspectableView { - func alert(_ index: Int = 0) throws -> InspectableView { + func alert(_ index: Int? = nil) throws -> InspectableView { return try contentForModifierLookup.alert(parent: self, index: index) } } @@ -29,10 +29,10 @@ public extension InspectableView { @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) internal extension Content { - func alert(parent: UnwrappedView, index: Int) throws -> InspectableView { + func alert(parent: UnwrappedView, index: Int?) throws -> InspectableView { guard let alertBuilder = try? self.modifierAttribute( modifierLookup: { isAlertBuilder(modifier: $0) }, path: "modifier", - type: AlertBuilder.self, call: "", index: index) + type: AlertBuilder.self, call: "", index: index ?? 0) else { _ = try self.modifier({ $0.modifierType == "IdentifiedPreferenceTransformModifier" @@ -48,9 +48,6 @@ internal extension Content { let container = ViewType.Alert.Container(alert: alert, builder: alertBuilder) let medium = self.medium.resettingViewModifiers() let content = Content(container, medium: medium) - let index = self.optionalizeIndex(index) { - try self.alert(parent: parent, index: 1) - } let call = ViewType.inspectionCall( base: ViewType.Alert.inspectionCall(typeName: ""), index: index) return try .init(content, parent: parent, call: call, index: index) diff --git a/Sources/ViewInspector/SwiftUI/List.swift b/Sources/ViewInspector/SwiftUI/List.swift index beb8006a..041dd93f 100644 --- a/Sources/ViewInspector/SwiftUI/List.swift +++ b/Sources/ViewInspector/SwiftUI/List.swift @@ -50,8 +50,8 @@ public extension InspectableView { path: "modifier|value|some", type: EdgeInsets.self, call: "listRowInsets") } - func listRowBackground() throws -> InspectableView { - return try contentForModifierLookup.listRowBackground(parent: self, index: 0) + func listRowBackground(_ index: Int? = nil) throws -> InspectableView { + return try contentForModifierLookup.listRowBackground(parent: self, index: index) } func listStyle() throws -> Any { @@ -65,13 +65,15 @@ public extension InspectableView { @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) internal extension Content { - func listRowBackground(parent: UnwrappedView, index: Int) throws -> InspectableView { + func listRowBackground(parent: UnwrappedView, index: Int?) throws -> InspectableView { let view = try modifierAttribute( modifierName: "_TraitWritingModifier", path: "modifier|value|some|storage|view", type: Any.self, - call: "listRowBackground", index: index) + call: "listRowBackground", index: index ?? 0) let medium = self.medium.resettingViewModifiers() let content = try Inspector.unwrap(content: Content(view, medium: medium)) - return try .init(content, parent: parent, call: "listRowBackground()", index: nil) + let call = ViewType.inspectionCall( + base: "listRowBackground(\(ViewType.indexPlaceholder))", index: index) + return try .init(content, parent: parent, call: call, index: index) } } diff --git a/Sources/ViewInspector/SwiftUI/Overlay.swift b/Sources/ViewInspector/SwiftUI/Overlay.swift index 642cf72e..bd29650a 100644 --- a/Sources/ViewInspector/SwiftUI/Overlay.swift +++ b/Sources/ViewInspector/SwiftUI/Overlay.swift @@ -14,11 +14,11 @@ public extension ViewType { @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) public extension InspectableView { - func overlay(_ index: Int = 0) throws -> InspectableView { + func overlay(_ index: Int? = nil) throws -> InspectableView { return try contentForModifierLookup.overlay(parent: self, index: index) } - func background(_ index: Int = 0) throws -> InspectableView { + func background(_ index: Int? = nil) throws -> InspectableView { return try contentForModifierLookup.background(parent: self, index: index) } } @@ -44,36 +44,30 @@ extension ViewType.Overlay: MultipleViewContent { @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) internal extension Content { - func overlay(parent: UnwrappedView, index: Int) throws -> InspectableView { + func overlay(parent: UnwrappedView, index: Int?) throws -> InspectableView { let modifier = try self.modifier({ modifier -> Bool in return modifier.modifierType.contains("_OverlayModifier") - }, call: "overlay", index: index) + }, call: "overlay", index: index ?? 0) let rootView = try Inspector.attribute(path: "modifier|overlay", value: modifier) let alignment = try Inspector.attribute(path: "modifier|alignment", value: modifier, type: Alignment.self) let overlayParams = ViewType.Overlay.Params(alignment: alignment) let medium = self.medium.resettingViewModifiers() .appending(viewModifier: overlayParams) let content = try Inspector.unwrap(content: Content(rootView, medium: medium)) - let index = self.optionalizeIndex(index) { - try self.overlay(parent: parent, index: 1) - } let call = ViewType.inspectionCall(base: "overlay(\(ViewType.indexPlaceholder))", index: index) return try .init(content, parent: parent, call: call, index: index) } - func background(parent: UnwrappedView, index: Int) throws -> InspectableView { + func background(parent: UnwrappedView, index: Int?) throws -> InspectableView { let modifier = try self.modifier({ modifier -> Bool in return modifier.modifierType.contains("_BackgroundModifier") - }, call: "background", index: index) + }, call: "background", index: index ?? 0) let rootView = try Inspector.attribute(path: "modifier|background", value: modifier) let alignment = try Inspector.attribute(path: "modifier|alignment", value: modifier, type: Alignment.self) let overlayParams = ViewType.Overlay.Params(alignment: alignment) let medium = self.medium.resettingViewModifiers() .appending(viewModifier: overlayParams) let content = try Inspector.unwrap(content: Content(rootView, medium: medium)) - let index = self.optionalizeIndex(index) { - try self.background(parent: parent, index: 1) - } let call = ViewType.inspectionCall(base: "background(\(ViewType.indexPlaceholder))", index: index) return try .init(content, parent: parent, call: call, index: index) } diff --git a/Sources/ViewInspector/SwiftUI/Popover.swift b/Sources/ViewInspector/SwiftUI/Popover.swift index f5043012..2c866f13 100644 --- a/Sources/ViewInspector/SwiftUI/Popover.swift +++ b/Sources/ViewInspector/SwiftUI/Popover.swift @@ -18,7 +18,7 @@ public extension ViewType { @available(tvOS, unavailable) public extension InspectableView { - func popover(_ index: Int = 0) throws -> InspectableView { + func popover(_ index: Int? = nil) throws -> InspectableView { return try contentForModifierLookup.popover(parent: self, index: index) } } @@ -26,14 +26,11 @@ public extension InspectableView { @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) internal extension Content { - func popover(parent: UnwrappedView, index: Int) throws -> InspectableView { + func popover(parent: UnwrappedView, index: Int?) throws -> InspectableView { let modifier = try modifierAttribute( modifierName: "PopoverPresentationModifier", path: "modifier", - type: Any.self, call: "popover", index: index) + type: Any.self, call: "popover", index: index ?? 0) let medium = self.medium.resettingViewModifiers() - let index = self.optionalizeIndex(index) { - try self.popover(parent: parent, index: 1) - } let call = ViewType.inspectionCall( base: ViewType.Popover.inspectionCall(typeName: ""), index: index) return try .init(try Inspector.unwrap(content: Content(modifier, medium: medium)), diff --git a/Sources/ViewInspector/SwiftUI/Sheet.swift b/Sources/ViewInspector/SwiftUI/Sheet.swift index 9e25eed9..6a553adc 100644 --- a/Sources/ViewInspector/SwiftUI/Sheet.swift +++ b/Sources/ViewInspector/SwiftUI/Sheet.swift @@ -43,7 +43,7 @@ extension ViewType.Sheet: MultipleViewContent { @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) public extension InspectableView { - func sheet(_ index: Int = 0) throws -> InspectableView { + func sheet(_ index: Int? = nil) throws -> InspectableView { return try contentForModifierLookup.sheet(parent: self, index: index) } } @@ -51,10 +51,10 @@ public extension InspectableView { @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) internal extension Content { - func sheet(parent: UnwrappedView, index: Int) throws -> InspectableView { + func sheet(parent: UnwrappedView, index: Int?) throws -> InspectableView { guard let sheetBuilder = try? self.modifierAttribute( modifierLookup: { isSheetBuilder(modifier: $0) }, path: "modifier", - type: SheetBuilder.self, call: "", index: index) + type: SheetBuilder.self, call: "", index: index ?? 0) else { _ = try self.modifier({ $0.modifierType == "IdentifiedPreferenceTransformModifier" @@ -70,9 +70,6 @@ internal extension Content { let container = ViewType.Sheet.Container(view: view, builder: sheetBuilder) let medium = self.medium.resettingViewModifiers() let content = Content(container, medium: medium) - let index = self.optionalizeIndex(index) { - try self.sheet(parent: parent, index: 1) - } let call = ViewType.inspectionCall( base: ViewType.Sheet.inspectionCall(typeName: ""), index: index) return try .init(content, parent: parent, call: call, index: index) diff --git a/Sources/ViewInspector/SwiftUI/TabView.swift b/Sources/ViewInspector/SwiftUI/TabView.swift index c902f842..6e6098fc 100644 --- a/Sources/ViewInspector/SwiftUI/TabView.swift +++ b/Sources/ViewInspector/SwiftUI/TabView.swift @@ -75,16 +75,16 @@ public extension InspectableView { @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) internal extension Content { - func tabItem(parent: UnwrappedView, index: Int) throws -> InspectableView { + func tabItem(parent: UnwrappedView, index: Int?) throws -> InspectableView { let rootView: Any = try { if let view = try? modifierAttribute( modifierName: "TabItemTraitKey", path: "modifier|value|some|storage|view|content", - type: Any.self, call: "tabItem", index: index) { + type: Any.self, call: "tabItem") { return view } return try modifierAttribute( modifierName: "PlatformItemTraitWriter", path: "modifier|source|content|content", - type: Any.self, call: "tabItem", index: index) + type: Any.self, call: "tabItem") }() let medium = self.medium.resettingViewModifiers() let view = try InspectableView( diff --git a/Sources/ViewInspector/SwiftUI/Toolbar.swift b/Sources/ViewInspector/SwiftUI/Toolbar.swift index 9bfe042f..3ed43c34 100644 --- a/Sources/ViewInspector/SwiftUI/Toolbar.swift +++ b/Sources/ViewInspector/SwiftUI/Toolbar.swift @@ -32,7 +32,7 @@ public extension ViewType.Toolbar { @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) public extension InspectableView { - func toolbar(_ index: Int = 0) throws -> InspectableView { + func toolbar(_ index: Int? = nil) throws -> InspectableView { return try contentForModifierLookup.toolbar(parent: self, index: index) } } @@ -40,17 +40,14 @@ public extension InspectableView { @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) internal extension Content { - func toolbar(parent: UnwrappedView, index: Int) throws -> InspectableView { + func toolbar(parent: UnwrappedView, index: Int?) throws -> InspectableView { let modifierName = ViewType.Toolbar.typePrefix let modifier = try self.modifier({ modifier -> Bool in return modifier.modifierType.contains(modifierName) - }, call: "toolbar", index: index) + }, call: "toolbar", index: index ?? 0) let root = try Inspector.attribute(label: "modifier", value: modifier) let medium = self.medium.resettingViewModifiers() let content = try Inspector.unwrap(content: Content(root, medium: medium)) - let index = self.optionalizeIndex(index) { - try self.toolbar(parent: parent, index: 1) - } let call = ViewType.inspectionCall( base: ViewType.Toolbar.inspectionCall(typeName: ""), index: index) return try .init(content, parent: parent, call: call, index: index) diff --git a/Sources/ViewInspector/SwiftUI/TouchBar.swift b/Sources/ViewInspector/SwiftUI/TouchBar.swift index f5eabe5f..51277046 100644 --- a/Sources/ViewInspector/SwiftUI/TouchBar.swift +++ b/Sources/ViewInspector/SwiftUI/TouchBar.swift @@ -70,7 +70,7 @@ public extension InspectableView { @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) internal extension Content { - func touchBar(parent: UnwrappedView, index: Int) throws -> InspectableView { + func touchBar(parent: UnwrappedView, index: Int?) throws -> InspectableView { let rootView = try modifierAttribute( modifierName: "_TouchBarModifier", path: "modifier|touchBar", type: Any.self, call: "touchBar", index: index) @@ -84,7 +84,7 @@ internal extension Content { @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) internal extension Content { - func touchBar(parent: UnwrappedView, index: Int) throws -> InspectableView { + func touchBar(parent: UnwrappedView, index: Int?) throws -> InspectableView { throw InspectionError.notSupported("Not supported on this platform") } } diff --git a/Sources/ViewInspector/ViewSearchIndex.swift b/Sources/ViewInspector/ViewSearchIndex.swift index ebe83799..bd9e6dc6 100644 --- a/Sources/ViewInspector/ViewSearchIndex.swift +++ b/Sources/ViewInspector/ViewSearchIndex.swift @@ -268,7 +268,7 @@ internal extension ViewSearch { ] struct ModifierIdentity { - typealias Builder = (UnwrappedView, Int) throws -> UnwrappedView + typealias Builder = (UnwrappedView, Int?) throws -> UnwrappedView let name: String let builder: Builder @@ -301,7 +301,8 @@ internal extension Content { let customModifiers = customViewModifiers() let modifiersCount = modifierNames.count return .init(count: identities.count * modifiersCount, { index -> UnwrappedView in - try identities[index / modifiersCount].builder(parent, index % modifiersCount) + try identities[index / modifiersCount] + .builder(parent, (index % modifiersCount).nilIfZero) }) + sheets + .init(count: customModifiers.count, { index -> UnwrappedView in let modifier = customModifiers[index] let name = Inspector.typeName(value: modifier) @@ -340,3 +341,9 @@ internal extension Content { }) } } + +private extension Int { + var nilIfZero: Int? { + return self == 0 ? nil : self + } +} diff --git a/Tests/ViewInspectorTests/SwiftUI/ActionSheetTests.swift b/Tests/ViewInspectorTests/SwiftUI/ActionSheetTests.swift index 7bcebff5..d36ff16c 100644 --- a/Tests/ViewInspectorTests/SwiftUI/ActionSheetTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/ActionSheetTests.swift @@ -142,7 +142,7 @@ final class ActionSheetTests: XCTestCase { let title1 = try sut.inspect().hStack().emptyView(0).actionSheet().title() XCTAssertEqual(try title1.string(), "title_1") XCTAssertEqual(title1.pathToRoot, - "view(ActionSheetFindTestView.self).hStack().emptyView(0).actionSheet(0).title()") + "view(ActionSheetFindTestView.self).hStack().emptyView(0).actionSheet().title()") let title2 = try sut.inspect().hStack().emptyView(0).actionSheet(1).title() XCTAssertEqual(try title2.string(), "title_3") XCTAssertEqual(title2.pathToRoot, diff --git a/Tests/ViewInspectorTests/SwiftUI/AlertTests.swift b/Tests/ViewInspectorTests/SwiftUI/AlertTests.swift index 1c0d0704..a90bf807 100644 --- a/Tests/ViewInspectorTests/SwiftUI/AlertTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/AlertTests.swift @@ -186,7 +186,7 @@ final class AlertTests: XCTestCase { let title1 = try sut.inspect().hStack().emptyView(0).alert().title() XCTAssertEqual(try title1.string(), "title_1") XCTAssertEqual(title1.pathToRoot, - "view(AlertFindTestView.self).hStack().emptyView(0).alert(0).title()") + "view(AlertFindTestView.self).hStack().emptyView(0).alert().title()") let title2 = try sut.inspect().hStack().emptyView(0).alert(1).title() XCTAssertEqual(try title2.string(), "title_3") XCTAssertEqual(title2.pathToRoot, diff --git a/Tests/ViewInspectorTests/SwiftUI/SheetTests.swift b/Tests/ViewInspectorTests/SwiftUI/SheetTests.swift index 6bc66438..23a8b14e 100644 --- a/Tests/ViewInspectorTests/SwiftUI/SheetTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/SheetTests.swift @@ -94,7 +94,7 @@ final class SheetTests: XCTestCase { let title1 = try sut.inspect().hStack().emptyView(0).sheet().text(0) XCTAssertEqual(try title1.string(), "title_1") XCTAssertEqual(title1.pathToRoot, - "view(SheetFindTestView.self).hStack().emptyView(0).sheet(0).text(0)") + "view(SheetFindTestView.self).hStack().emptyView(0).sheet().text(0)") let title2 = try sut.inspect().hStack().emptyView(0).sheet(1).text(0) XCTAssertEqual(try title2.string(), "title_3") XCTAssertEqual(title2.pathToRoot, From c422e14e7ffc48f39213cce67263927126aa0dd8 Mon Sep 17 00:00:00 2001 From: Alexey Naumov Date: Mon, 6 Sep 2021 15:07:08 +0300 Subject: [PATCH 41/99] Test standard environment value modifier --- .../ViewModifiers/EnvironmentModifiersTests.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Tests/ViewInspectorTests/ViewModifiers/EnvironmentModifiersTests.swift b/Tests/ViewInspectorTests/ViewModifiers/EnvironmentModifiersTests.swift index bbb2a5e1..1736f374 100644 --- a/Tests/ViewInspectorTests/ViewModifiers/EnvironmentModifiersTests.swift +++ b/Tests/ViewInspectorTests/ViewModifiers/EnvironmentModifiersTests.swift @@ -14,6 +14,8 @@ final class ViewEnvironmentTests: XCTestCase { XCTAssertNoThrow(try sut.inspect().emptyView().environment(\.testKey)) XCTAssertThrows(try EmptyView().inspect().emptyView().environment(\.testKey), "EmptyView does not have 'environment(TestEnvKey)' modifier") + let sut2 = EmptyView().environment(\.colorScheme, .light) + XCTAssertEqual(try sut2.inspect().emptyView().environment(\.colorScheme), .light) } func testEnvironmentObject() throws { From 26ccc9a0eb5431391f132fff26b74e4d667ff5e7 Mon Sep 17 00:00:00 2001 From: Alexey Naumov Date: Mon, 6 Sep 2021 16:39:15 +0300 Subject: [PATCH 42/99] Move EnvironmentInjection to a separate file --- Sources/ViewInspector/BaseTypes.swift | 80 ------------------ .../ViewInspector/EnvironmentInjection.swift | 81 +++++++++++++++++++ ViewInspector.xcodeproj/project.pbxproj | 4 + 3 files changed, 85 insertions(+), 80 deletions(-) create mode 100644 Sources/ViewInspector/EnvironmentInjection.swift diff --git a/Sources/ViewInspector/BaseTypes.swift b/Sources/ViewInspector/BaseTypes.swift index a6fe4da1..18135a4f 100644 --- a/Sources/ViewInspector/BaseTypes.swift +++ b/Sources/ViewInspector/BaseTypes.swift @@ -293,83 +293,3 @@ extension BinaryEquatable { } } } - -// MARK: - EnvironmentObject injection - -@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) -internal extension Inspectable { - var missingEnvironmentObjects: [String] { - let prefix = "SwiftUI.EnvironmentObject<" - let mirror = Mirror(reflecting: self) - return mirror.children.compactMap { - let fullName = Inspector.typeName(value: $0.value, namespaced: true) - guard fullName.hasPrefix(prefix), - (try? Inspector.attribute(path: "_store|some", value: $0.value)) == nil, - let ivarName = $0.label - else { return nil } - var objName = Inspector.typeName(value: $0.value) - objName = objName[18...size - var offset = MemoryLayout.stride - envObjSize - let step = MemoryLayout.alignment - while offset + envObjSize > viewSize { - offset -= step - } - withUnsafeBytes(of: EnvObject.Forgery(object: nil)) { reference in - while offset >= 0 { - var copy = self - withUnsafeMutableBytes(of: ©) { bytes in - guard bytes[offset..) -> String { - let range = Range(uncheckedBounds: (lower: max(0, min(count, intRange.lowerBound)), - upper: min(count, max(0, intRange.upperBound)))) - let start = index(startIndex, offsetBy: range.lowerBound) - let end = index(start, offsetBy: range.upperBound - range.lowerBound) - return String(self[start ..< end]) - } -} diff --git a/Sources/ViewInspector/EnvironmentInjection.swift b/Sources/ViewInspector/EnvironmentInjection.swift new file mode 100644 index 00000000..4c6cb3d6 --- /dev/null +++ b/Sources/ViewInspector/EnvironmentInjection.swift @@ -0,0 +1,81 @@ +import SwiftUI + +// MARK: - EnvironmentObject injection + +@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) +internal extension Inspectable { + var missingEnvironmentObjects: [String] { + let prefix = "SwiftUI.EnvironmentObject<" + let mirror = Mirror(reflecting: self) + return mirror.children.compactMap { + let fullName = Inspector.typeName(value: $0.value, namespaced: true) + guard fullName.hasPrefix(prefix), + (try? Inspector.attribute(path: "_store|some", value: $0.value)) == nil, + let ivarName = $0.label + else { return nil } + var objName = Inspector.typeName(value: $0.value) + objName = objName[18...size + var offset = MemoryLayout.stride - envObjSize + let step = MemoryLayout.alignment + while offset + envObjSize > viewSize { + offset -= step + } + withUnsafeBytes(of: EnvObject.Forgery(object: nil)) { reference in + while offset >= 0 { + var copy = self + withUnsafeMutableBytes(of: ©) { bytes in + guard bytes[offset..) -> String { + let range = Range(uncheckedBounds: (lower: max(0, min(count, intRange.lowerBound)), + upper: min(count, max(0, intRange.upperBound)))) + let start = index(startIndex, offsetBy: range.lowerBound) + let end = index(start, offsetBy: range.upperBound - range.lowerBound) + return String(self[start ..< end]) + } +} diff --git a/ViewInspector.xcodeproj/project.pbxproj b/ViewInspector.xcodeproj/project.pbxproj index 15a50878..ee7024d0 100644 --- a/ViewInspector.xcodeproj/project.pbxproj +++ b/ViewInspector.xcodeproj/project.pbxproj @@ -22,6 +22,7 @@ /* Begin PBXBuildFile section */ 355B2D57BFF536BCD0B555B8 /* ViewPaddingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 355B2B0F773087003E9F5A49 /* ViewPaddingTests.swift */; }; + 520E915C26E64F210090BD1F /* EnvironmentInjection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520E915B26E64F210090BD1F /* EnvironmentInjection.swift */; }; 520F8C13266D0E600026BC57 /* CustomViewModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520F8C12266D0E600026BC57 /* CustomViewModifier.swift */; }; 5214800325F4EA4F002D974D /* EnvironmentObjectInjectionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5214800225F4EA4F002D974D /* EnvironmentObjectInjectionTests.swift */; }; 5214802B25F803B7002D974D /* CustomStyleModifiers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5214802A25F803B7002D974D /* CustomStyleModifiers.swift */; }; @@ -270,6 +271,7 @@ /* Begin PBXFileReference section */ 355B2B0F773087003E9F5A49 /* ViewPaddingTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewPaddingTests.swift; sourceTree = ""; }; + 520E915B26E64F210090BD1F /* EnvironmentInjection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EnvironmentInjection.swift; sourceTree = ""; }; 520F8C12266D0E600026BC57 /* CustomViewModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomViewModifier.swift; sourceTree = ""; }; 5214800225F4EA4F002D974D /* EnvironmentObjectInjectionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EnvironmentObjectInjectionTests.swift; sourceTree = ""; }; 5214802A25F803B7002D974D /* CustomStyleModifiers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomStyleModifiers.swift; sourceTree = ""; }; @@ -583,6 +585,7 @@ F64105C3257BF9A70033D82D /* ViewSearch.swift */, F660849A2594AA6700AF59A2 /* ViewSearchIndex.swift */, F6D58B9223C4A0F3000CEE3B /* ViewHosting.swift */, + 520E915B26E64F210090BD1F /* EnvironmentInjection.swift */, F68108A423A5833D00B32145 /* Modifiers */, F60EEBBD2382EED0007DB53A /* SwiftUI */, ); @@ -1043,6 +1046,7 @@ F6684BFE23AA863400DECCB3 /* RadialGradient.swift in Sources */, F60EEBD42382EED0007DB53A /* ScrollView.swift in Sources */, F64C4E2C250CD60800A69FF9 /* Color.swift in Sources */, + 520E915C26E64F210090BD1F /* EnvironmentInjection.swift in Sources */, F682A016254776F2005F1B70 /* DisclosureGroup.swift in Sources */, F6119FF4254A00FC0000C54A /* LazyHGrid.swift in Sources */, F653BDE3255698A6001FA688 /* TupleView.swift in Sources */, From ebdd4040f50b122a315771b5bc244e1150ce4cd6 Mon Sep 17 00:00:00 2001 From: Alexey Naumov Date: Mon, 6 Sep 2021 20:48:53 +0300 Subject: [PATCH 43/99] Rework Popover inspection in Sheet style --- Sources/ViewInspector/SwiftUI/Popover.swift | 206 +++++++++--- Sources/ViewInspector/ViewSearchIndex.swift | 32 +- .../SwiftUI/ConditionalContentTests.swift | 1 - .../SwiftUI/FullScreenCoverTests.swift | 1 - .../SwiftUI/PopoverTests.swift | 292 +++++++++++++++--- .../SwiftUI/SheetTests.swift | 3 +- .../TransitiveModifiersTests.swift | 6 +- 7 files changed, 432 insertions(+), 109 deletions(-) diff --git a/Sources/ViewInspector/SwiftUI/Popover.swift b/Sources/ViewInspector/SwiftUI/Popover.swift index 2c866f13..cf5e5b1a 100644 --- a/Sources/ViewInspector/SwiftUI/Popover.swift +++ b/Sources/ViewInspector/SwiftUI/Popover.swift @@ -4,18 +4,43 @@ import SwiftUI public extension ViewType { struct Popover: KnownViewType { - public static var typePrefix: String = "" - public static var isTransitive: Bool { true } + public static var typePrefix: String = "ViewType.Popover.Container" + public static var namespacedPrefixes: [String] { + return ["ViewInspector." + typePrefix] + } public static func inspectionCall(typeName: String) -> String { return "popover(\(ViewType.indexPlaceholder))" } } } +// MARK: - Content Extraction + +@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) +extension ViewType.Popover: SingleViewContent { + + public static func child(_ content: Content) throws -> Content { + let view = try Inspector.attribute(label: "view", value: content.view) + let medium = content.medium.resettingViewModifiers() + return try Inspector.unwrap(view: view, medium: medium) + } +} + +@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) +extension ViewType.Popover: MultipleViewContent { + + public static func children(_ content: Content) throws -> LazyGroup { + let view = try Inspector.attribute(label: "view", value: content.view) + let medium = content.medium.resettingViewModifiers() + return try Inspector.viewsInContainer(view: view, medium: medium) + } +} + // MARK: - Extraction -@available(iOS 14.2, macOS 11.0, *) +@available(iOS 13.0, macOS 10.15, *) @available(tvOS, unavailable) +@available(watchOS, unavailable) public extension InspectableView { func popover(_ index: Int? = nil) throws -> InspectableView { @@ -27,71 +52,164 @@ public extension InspectableView { internal extension Content { func popover(parent: UnwrappedView, index: Int?) throws -> InspectableView { - let modifier = try modifierAttribute( - modifierName: "PopoverPresentationModifier", path: "modifier", - type: Any.self, call: "popover", index: index ?? 0) + guard let popoverBuilder = try? self.modifierAttribute( + modifierLookup: { isPopoverBuilder(modifier: $0) }, path: "modifier", + type: PopoverBuilder.self, call: "", index: index ?? 0) + else { + _ = try modifierAttribute( + modifierName: "PopoverPresentationModifier", path: "modifier", + type: Any.self, call: "popover") + throw InspectionError.notSupported( + """ + Please refer to the Guide for inspecting the Popover: \ + https://github.com/nalexn/ViewInspector/blob/master/guide.md#alert-sheet-actionsheet-and-fullscreencover + """) + } + let view = try popoverBuilder.buildPopover() + let container = ViewType.Popover.Container(view: view, builder: popoverBuilder) let medium = self.medium.resettingViewModifiers() + let content = Content(container, medium: medium) let call = ViewType.inspectionCall( base: ViewType.Popover.inspectionCall(typeName: ""), index: index) - return try .init(try Inspector.unwrap(content: Content(modifier, medium: medium)), - parent: parent, call: call, index: index) + return try .init(content, parent: parent, call: call, index: index) + } + + func popoversForSearch() -> [ViewSearch.ModifierIdentity] { + let count = medium.viewModifiers + .filter { isPopoverBuilder(modifier: $0) } + .count + return Array(0.. Bool { + return (try? Inspector.attribute( + label: "modifier", value: modifier, type: PopoverBuilder.self)) != nil } } -// MARK: - Custom Attributes +@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) +internal extension ViewType.Popover { + struct Container: CustomViewIdentityMapping { + let view: Any + let builder: PopoverBuilder + + var viewTypeForSearch: KnownViewType.Type { ViewType.Popover.self } + } +} -@available(iOS 14.2, macOS 11.0, *) +@available(iOS 13.0, macOS 10.15, *) @available(tvOS, unavailable) -public extension InspectableView where View == ViewType.Popover { +@available(watchOS, unavailable) +public protocol PopoverBuilder: SystemPopupPresenter { + var attachmentAnchor: PopoverAttachmentAnchor { get } + var arrowEdge: Edge { get } + func buildPopover() throws -> Any +} + +@available(iOS 13.0, macOS 10.15, *) +@available(tvOS, unavailable) +@available(watchOS, unavailable) +public protocol PopoverProvider: PopoverBuilder { + var isPresented: Binding { get } + var popoverBuilder: () -> Any { get } +} + +@available(iOS 13.0, macOS 10.15, *) +@available(tvOS, unavailable) +@available(watchOS, unavailable) +public protocol PopoverItemProvider: PopoverBuilder { + associatedtype Item: Identifiable + var item: Binding { get } + var popoverBuilder: (Item) -> Any { get } +} + +@available(iOS 13.0, macOS 10.15, *) +@available(tvOS, unavailable) +@available(watchOS, unavailable) +public extension PopoverProvider { - func contentView() throws -> InspectableView { - return try contentView(EmptyView.self) + func buildPopover() throws -> Any { + guard isPresented.wrappedValue else { + throw InspectionError.viewNotFound(parent: "Popover") + } + return popoverBuilder() } - func contentView(_ viewType: T.Type) throws -> InspectableView { - - typealias Closure = () -> T - let closure = try Inspector.attribute(label: "popoverContent", value: content.view) - let closureDesc = Inspector.typeName(value: closure) - - let expectedViewType = closureDesc.components(separatedBy: "() -> ").last ?? "" - guard Inspector.typeName(type: viewType) == expectedViewType else { - throw InspectionError.notSupported( - "Please substitute '\(expectedViewType).self' as the parameter for 'contentView()' inspection call") + func dismissPopup() { + isPresented.wrappedValue = false + } +} + +@available(iOS 13.0, macOS 10.15, *) +@available(tvOS, unavailable) +@available(watchOS, unavailable) +public extension PopoverItemProvider { + + func buildPopover() throws -> Any { + guard let value = item.wrappedValue else { + throw InspectionError.viewNotFound(parent: "Popover") } - guard let typedClosure = withUnsafeBytes(of: closure, { - $0.bindMemory(to: Closure.self).first - }) else { throw InspectionError.typeMismatch(closure, Closure.self) } - let view = typedClosure() - let medium = content.medium.resettingViewModifiers() - return try .init(try Inspector.unwrap(content: Content(view, medium: medium)), parent: self) + return popoverBuilder(value) + } + + func dismissPopup() { + item.wrappedValue = nil + } +} + +// MARK: - Custom Attributes + +@available(iOS 13.0, macOS 10.15, *) +@available(tvOS, unavailable) +@available(watchOS, unavailable) +public extension InspectableView where View == ViewType.Popover { + + func callOnDismiss() throws { + let popover = try Inspector.cast(value: content.view, type: ViewType.Popover.Container.self) + popover.builder.dismissPopup() } func arrowEdge() throws -> Edge { - return try Inspector.attribute(label: "arrowEdge", value: content.view, type: Edge.self) + let popover = try Inspector.cast(value: content.view, type: ViewType.Popover.Container.self) + return popover.builder.arrowEdge } func attachmentAnchor() throws -> PopoverAttachmentAnchor { - return try Inspector.attribute(label: "attachmentAnchor", value: content.view, - type: PopoverAttachmentAnchor.self) + let popover = try Inspector.cast(value: content.view, type: ViewType.Popover.Container.self) + return popover.builder.attachmentAnchor } +} + +// MARK: - Deprecated: + +@available(iOS 13.0, macOS 10.15, *) +@available(tvOS, unavailable) +@available(watchOS, unavailable) +public extension InspectableView where View == ViewType.Popover { - func isPresented() throws -> Bool { - return try isPresentedBinding().wrappedValue + @available(*, deprecated, message: "Simply remove `contentView()` from the inspection chain") + func contentView() throws -> InspectableView { + return try contentView(EmptyView.self) } - func dismiss() throws { - typealias OnDismiss = () -> Void - if let onDismiss = try? Inspector.attribute( - label: "onDismiss", value: content.view, type: OnDismiss.self) { - onDismiss() - } - try isPresentedBinding().wrappedValue = false + @available(*, deprecated, message: "Simply remove `contentView()` from the inspection chain") + func contentView(_ viewType: T.Type) throws -> InspectableView { + let content = try ViewType.Popover.child(self.content) + return try .init(content, parent: self, index: nil) } - private func isPresentedBinding() throws -> Binding { - return try Inspector.attribute( - label: "_isPresented", value: content.view, type: Binding.self) + @available(*, deprecated, message: "Use `popover` inspection call - it throws if Popover is not presented") + func isPresented() throws -> Bool { + return true + } + + @available(*, deprecated, renamed: "callOnDismiss") + func dismiss() throws { + try callOnDismiss() } } diff --git a/Sources/ViewInspector/ViewSearchIndex.swift b/Sources/ViewInspector/ViewSearchIndex.swift index bd9e6dc6..2777a4df 100644 --- a/Sources/ViewInspector/ViewSearchIndex.swift +++ b/Sources/ViewInspector/ViewSearchIndex.swift @@ -30,7 +30,8 @@ internal extension ViewSearch { .init(ViewType.NavigationLink.self), .init(ViewType.NavigationView.self), .init(ViewType.OutlineGroup.self), .init(ViewType.PasteButton.self), .init(ViewType.Picker.self), - .init(ViewType.Popover.self), .init(ViewType.ProgressView.self), + .init(ViewType.Popover.self, genericTypeName: nil), + .init(ViewType.ProgressView.self), .init(ViewType.RadialGradient.self), .init(ViewType.ScrollView.self), .init(ViewType.ScrollViewReader.self), .init(ViewType.Section.self), .init(ViewType.SecureField.self), @@ -329,16 +330,27 @@ internal extension Content { let actionSheetModifiers = actionSheetsForSearch() let fullScreenCoverModifiers = fullScreenCoversForSearch() #endif + #if os(iOS) || os(macOS) + let popoverModifiers = popoversForSearch() + #else + let popoverModifiers: [ViewSearch.ModifierIdentity] = [] + #endif let alertModifiers = alertsForSearch() - return .init(count: sheetModifiers.count, { index -> UnwrappedView in - try sheetModifiers[index].builder(parent, index) - }) + .init(count: actionSheetModifiers.count, { index -> UnwrappedView in - try actionSheetModifiers[index].builder(parent, index) - }) + .init(count: alertModifiers.count, { index -> UnwrappedView in - try alertModifiers[index].builder(parent, index) - }) + .init(count: fullScreenCoverModifiers.count, { index -> UnwrappedView in - try fullScreenCoverModifiers[index].builder(parent, index) - }) + let group1: LazyGroup = + .init(count: sheetModifiers.count, { index -> UnwrappedView in + try sheetModifiers[index].builder(parent, index) + }) + .init(count: actionSheetModifiers.count, { index -> UnwrappedView in + try actionSheetModifiers[index].builder(parent, index) + }) + .init(count: alertModifiers.count, { index -> UnwrappedView in + try alertModifiers[index].builder(parent, index) + }) + let group2: LazyGroup = + .init(count: fullScreenCoverModifiers.count, { index -> UnwrappedView in + try fullScreenCoverModifiers[index].builder(parent, index) + }) + .init(count: popoverModifiers.count, { index -> UnwrappedView in + try popoverModifiers[index].builder(parent, index) + }) + return group1 + group2 } } diff --git a/Tests/ViewInspectorTests/SwiftUI/ConditionalContentTests.swift b/Tests/ViewInspectorTests/SwiftUI/ConditionalContentTests.swift index eeaec139..f6869c51 100644 --- a/Tests/ViewInspectorTests/SwiftUI/ConditionalContentTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/ConditionalContentTests.swift @@ -24,7 +24,6 @@ final class ConditionalContentTests: XCTestCase { func testRetainsModifiers() throws { let sut = ConditionalViewWithModifier(value: true) - print(">> \(Inspector.print(sut) as AnyObject)") let text = try sut.inspect().text() XCTAssertEqual(try text.string(), "True") XCTAssertEqual(try text.padding(), EdgeInsets(top: 8, leading: 8, bottom: 8, trailing: 8)) diff --git a/Tests/ViewInspectorTests/SwiftUI/FullScreenCoverTests.swift b/Tests/ViewInspectorTests/SwiftUI/FullScreenCoverTests.swift index 5e921d23..ef9ec52d 100644 --- a/Tests/ViewInspectorTests/SwiftUI/FullScreenCoverTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/FullScreenCoverTests.swift @@ -9,7 +9,6 @@ final class FullScreenCoverTests: XCTestCase { guard #available(iOS 14.0, tvOS 14.0, watchOS 7.0, *) else { return } let binding = Binding(wrappedValue: true) let sut = EmptyView().fullScreenCover(isPresented: binding) { Text("") } - print("\(Inspector.print(sut) as AnyObject)") XCTAssertNoThrow(try sut.inspect().emptyView()) } diff --git a/Tests/ViewInspectorTests/SwiftUI/PopoverTests.swift b/Tests/ViewInspectorTests/SwiftUI/PopoverTests.swift index 33a4e152..0b10f2a4 100644 --- a/Tests/ViewInspectorTests/SwiftUI/PopoverTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/PopoverTests.swift @@ -2,57 +2,139 @@ import XCTest import SwiftUI @testable import ViewInspector -#if !os(tvOS) +#if os(iOS) || os(macOS) @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) final class PopoverTests: XCTestCase { - func testBaseView() throws { + func testPopover() throws { let binding = Binding(wrappedValue: true) - let sut = EmptyView().popover(isPresented: binding, content: { Text("") }) - if #available(iOS 14.2, macOS 11.0, *) { - XCTAssertNoThrow(try sut.inspect().emptyView()) - } else if #available(iOS 14, macOS 10.16, *) { - XCTAssertThrows(try sut.inspect().emptyView(), - "Unwrapping the view under popover is not supported on iOS 14.0 and 14.1") - } else { - XCTAssertNoThrow(try sut.inspect().emptyView()) + let sut = EmptyView().popover(isPresented: binding) { Text("") } + XCTAssertNoThrow(try sut.inspect().emptyView()) + } + + func testInspectionErrorNoModifier() throws { + let sut = EmptyView().offset() + XCTAssertThrows(try sut.inspect().emptyView().popover(), + "EmptyView does not have 'popover' modifier") + } + + func testInspectionErrorCustomModifierRequired() throws { + let binding = Binding(wrappedValue: true) + let sut = EmptyView().popover(isPresented: binding) { Text("") } + XCTAssertThrows(try sut.inspect().emptyView().popover(), + """ + Please refer to the Guide for inspecting the Popover: \ + https://github.com/nalexn/ViewInspector/blob/master/guide.md#alert-sheet-actionsheet-and-fullscreencover + """) + } + + func testInspectionErrorPopoverNotPresented() throws { + let binding = Binding(wrappedValue: false) + let sut = EmptyView().popover2(isPresented: binding) { Text("") } + XCTAssertThrows(try sut.inspect().emptyView().popover(), + "View for Popover is absent") + } + + func testInspectionErrorPopoverWithItemNotPresented() throws { + let binding = Binding(wrappedValue: nil) + let sut = EmptyView().popover2(item: binding) { Text("\($0)") } + XCTAssertThrows(try sut.inspect().emptyView().popover(), + "View for Popover is absent") + } + + func testContentInspection() throws { + let binding = Binding(wrappedValue: true) + let sut = EmptyView().popover2(isPresented: binding) { + Text("abc") } + let title = try sut.inspect().emptyView().popover().text() + XCTAssertEqual(try title.string(), "abc") + XCTAssertEqual(title.pathToRoot, "emptyView().popover().text()") } - func testPopoverUnwrapping() throws { - guard #available(iOS 14.2, macOS 11.0, *) else { return } + func testContentInteraction() throws { let binding = Binding(wrappedValue: true) - let sut = EmptyView().popover(isPresented: binding, content: { Text("") }) - XCTAssertNoThrow(try sut.inspect().emptyView().popover()) + let sut = EmptyView().popover2(isPresented: binding) { + Text("abc") + Button("xyz", action: { binding.wrappedValue = false }) + } + let button = try sut.inspect().emptyView().popover().button(1) + try button.tap() + XCTAssertFalse(binding.wrappedValue) + XCTAssertEqual(button.pathToRoot, "emptyView().popover().button(1)") } - func testPopoverContentView() throws { - guard #available(iOS 14.2, macOS 11.0, *) else { return } + func testOnDismiss() throws { let binding = Binding(wrappedValue: true) - let sut = EmptyView().popover(isPresented: binding, content: { Text("test") }) + let sut = EmptyView().popover2(isPresented: binding, content: { Text("") }) + XCTAssertTrue(binding.wrappedValue) + try sut.inspect().popover().callOnDismiss() + XCTAssertFalse(binding.wrappedValue) + } + + func testContentWithItemInspection() throws { + let binding = Binding(wrappedValue: 6) + let sut = EmptyView().popover2(item: binding) { Text("\($0)") } let popover = try sut.inspect().emptyView().popover() - XCTAssertThrows(try popover.contentView(), - "Please substitute 'Text.self' as the parameter for 'contentView()' inspection call") - let value = try popover.contentView(Text.self).text().string() - XCTAssertEqual(value, "test") + XCTAssertEqual(try popover.text().string(), "6") + XCTAssertEqual(binding.wrappedValue, 6) + try popover.callOnDismiss() + XCTAssertNil(binding.wrappedValue) } - func testSearchBlocker() throws { - guard #available(iOS 14.2, macOS 11.0, *) else { return } + func testMultiplePopoversInspection() throws { + let binding1 = Binding(wrappedValue: true) + let binding2 = Binding(wrappedValue: true) + let binding3 = Binding(wrappedValue: true) + let sut = PopoverFindTestView(popover1: binding1, popover2: binding2, popover3: binding3) + let title1 = try sut.inspect().hStack().emptyView(0).popover().text(0) + XCTAssertEqual(try title1.string(), "title_1") + XCTAssertEqual(title1.pathToRoot, + "view(PopoverFindTestView.self).hStack().emptyView(0).popover().text(0)") + let title2 = try sut.inspect().hStack().emptyView(0).popover(1).text(0) + XCTAssertEqual(try title2.string(), "title_3") + XCTAssertEqual(title2.pathToRoot, + "view(PopoverFindTestView.self).hStack().emptyView(0).popover(1).text(0)") + + XCTAssertEqual(try sut.inspect().find(ViewType.Popover.self).text(0).string(), "title_1") + binding1.wrappedValue = false + XCTAssertEqual(try sut.inspect().find(ViewType.Popover.self).text(0).string(), "title_3") + binding3.wrappedValue = false + XCTAssertThrows(try sut.inspect().find(ViewType.Popover.self), + "Search did not find a match") + } + + func testFindAndPathToRoots() throws { let binding = Binding(wrappedValue: true) - let sut = EmptyView().popover(isPresented: binding, content: { Text("abc") }) - XCTAssertThrows(try sut.inspect().find(text: "abc"), - "Search did not find a match. Possible blockers: popover") + let sut = PopoverFindTestView(popover1: binding, popover2: binding, popover3: binding) + + // 1 + XCTAssertEqual(try sut.inspect().find(text: "title_1").pathToRoot, + "view(PopoverFindTestView.self).hStack().emptyView(0).popover().text(0)") + XCTAssertEqual(try sut.inspect().find(text: "button_1").pathToRoot, + "view(PopoverFindTestView.self).hStack().emptyView(0).popover().button(1).labelView().text()") + // 2 + XCTAssertThrows(try sut.inspect().find(text: "title_2").pathToRoot, + "Search did not find a match") + + // 3 + XCTAssertEqual(try sut.inspect().find(text: "title_3").pathToRoot, + "view(PopoverFindTestView.self).hStack().emptyView(0).popover(1).text(0)") + + XCTAssertThrows(try sut.inspect().find(text: "message_3").pathToRoot, + "Search did not find a match") + XCTAssertEqual(try sut.inspect().find(text: "button_3").pathToRoot, + "view(PopoverFindTestView.self).hStack().emptyView(0).popover(1).button(1).labelView().text()") } func testArrowEdge() throws { guard #available(iOS 14.2, macOS 11.0, *) else { return } let binding = Binding(wrappedValue: true) let sut = EmptyView() - .popover(isPresented: binding, arrowEdge: .top) { Text("") } + .popover2(isPresented: binding, arrowEdge: .trailing) { Text("") } let value = try sut.inspect().emptyView().popover().arrowEdge() - XCTAssertEqual(value, .top) + XCTAssertEqual(value, .trailing) } func testAttachmentAnchor() throws { @@ -60,29 +142,11 @@ final class PopoverTests: XCTestCase { let binding = Binding(wrappedValue: true) let anchor = PopoverAttachmentAnchor.point(.bottom) let sut = EmptyView() - .popover(isPresented: binding, - attachmentAnchor: anchor) { Text("") } + .popover2(isPresented: binding, + attachmentAnchor: anchor) { Text("") } let value = try sut.inspect().emptyView().popover().attachmentAnchor() XCTAssertEqual(value, anchor) } - - func testIsPresentedAndDismiss() throws { - guard #available(iOS 14.2, macOS 11.0, *) else { return } - let binding = Binding(wrappedValue: true) - let sut = EmptyView().popover(isPresented: binding) { Text("") } - let popover = try sut.inspect().emptyView().popover() - XCTAssertTrue(try popover.isPresented()) - try popover.dismiss() - XCTAssertFalse(try popover.isPresented()) - } - - func testPathToRoot() throws { - guard #available(iOS 14.2, macOS 11.0, *) else { return } - let binding = Binding(wrappedValue: true) - let view = EmptyView().popover(isPresented: binding) { Text("") } - let sut = try view.inspect().emptyView().popover().pathToRoot - XCTAssertEqual(sut, "emptyView().popover()") - } } @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) @@ -102,4 +166,136 @@ final class PopoverAttachmentAnchorTests: XCTestCase { } } +@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) +final class PopoverDeprecatedTests: XCTestCase { + + @available(*, deprecated) + func testContentView() throws { + let binding = Binding(wrappedValue: true) + let sut = EmptyView().popover2(isPresented: binding) { Text("") } + let popover = try sut.inspect().emptyView().popover() + XCTAssertNoThrow(try popover.contentView().text()) + XCTAssertNoThrow(try popover.contentView(Text.self).text()) + } + + @available(*, deprecated) + func testIsPresentedAndDismiss() throws { + let binding = Binding(wrappedValue: true) + let sut = EmptyView().popover2(isPresented: binding) { Text("") } + XCTAssertTrue(try sut.inspect().emptyView().popover().isPresented()) + try sut.inspect().emptyView().popover().dismiss() + XCTAssertThrows(try sut.inspect().emptyView().popover(), + "View for Popover is absent") + } +} + +@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) +private extension View { + func popover2(isPresented: Binding, + attachmentAnchor: PopoverAttachmentAnchor = .rect(.bounds), + arrowEdge: Edge = .top, + @ViewBuilder content: @escaping () -> Popover + ) -> some View where Popover: View { + return self.modifier(InspectablePopover( + isPresented: isPresented, + attachmentAnchor: attachmentAnchor, + arrowEdge: arrowEdge, + content: content)) + } + + func popover2(item: Binding, + attachmentAnchor: PopoverAttachmentAnchor = .rect(.bounds), + arrowEdge: Edge = .top, + content: @escaping (Item) -> Popover + ) -> some View where Item: Identifiable, Popover: View { + return self.modifier(InspectablePopoverWithItem( + item: item, + attachmentAnchor: attachmentAnchor, + arrowEdge: arrowEdge, + content: content)) + } +} + +@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) +private struct InspectablePopover: ViewModifier, PopoverProvider where Popover: View { + + let isPresented: Binding + let attachmentAnchor: PopoverAttachmentAnchor + let arrowEdge: Edge + let content: () -> Popover + let popoverBuilder: () -> Any + + init(isPresented: Binding, + attachmentAnchor: PopoverAttachmentAnchor, + arrowEdge: Edge, + content: @escaping () -> Popover) { + self.isPresented = isPresented + self.attachmentAnchor = attachmentAnchor + self.arrowEdge = arrowEdge + self.content = content + self.popoverBuilder = { content() as Any } + } + + func body(content: Self.Content) -> some View { + content.popover(isPresented: isPresented, content: self.content) + } +} + +@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) +private struct InspectablePopoverWithItem: ViewModifier, PopoverItemProvider +where Item: Identifiable, Popover: View { + + let item: Binding + let attachmentAnchor: PopoverAttachmentAnchor + let arrowEdge: Edge + let content: (Item) -> Popover + let popoverBuilder: (Item) -> Any + + init(item: Binding, + attachmentAnchor: PopoverAttachmentAnchor, + arrowEdge: Edge, + content: @escaping (Item) -> Popover) { + self.item = item + self.attachmentAnchor = attachmentAnchor + self.arrowEdge = arrowEdge + self.content = content + self.popoverBuilder = { content($0) as Any } + } + + func body(content: Self.Content) -> some View { + content.popover(item: item, content: self.content) + } +} + +@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) +private struct PopoverFindTestView: View, Inspectable { + + @Binding var isPopover1Presented = false + @Binding var isPopover2Presented = false + @Binding var isPopover3Presented = false + + init(popover1: Binding, popover2: Binding, popover3: Binding) { + _isPopover1Presented = popover1 + _isPopover2Presented = popover2 + _isPopover3Presented = popover3 + } + + var body: some View { + HStack { + EmptyView() + .popover2(isPresented: $isPopover1Presented) { + Text("title_1") + Button("button_1", action: { }) + } + .popover(isPresented: $isPopover2Presented) { + Text("title_2") + } + .popover2(isPresented: $isPopover3Presented) { + Text("title_3") + Button("button_3", action: { }) + } + } + } +} + #endif diff --git a/Tests/ViewInspectorTests/SwiftUI/SheetTests.swift b/Tests/ViewInspectorTests/SwiftUI/SheetTests.swift index 23a8b14e..fe2e2968 100644 --- a/Tests/ViewInspectorTests/SwiftUI/SheetTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/SheetTests.swift @@ -8,7 +8,6 @@ final class SheetTests: XCTestCase { func testSheet() throws { let binding = Binding(wrappedValue: true) let sut = EmptyView().sheet(isPresented: binding) { Text("") } - print("\(Inspector.print(sut) as AnyObject)") XCTAssertNoThrow(try sut.inspect().emptyView()) } @@ -165,7 +164,7 @@ private struct InspectableSheet: ViewModifier, SheetProvider where Sheet: } func body(content: Self.Content) -> some View { - content.sheet(isPresented: isPresented, content: self.content) + content.sheet(isPresented: isPresented, onDismiss: onDismiss, content: self.content) } } diff --git a/Tests/ViewInspectorTests/ViewModifiers/TransitiveModifiersTests.swift b/Tests/ViewInspectorTests/ViewModifiers/TransitiveModifiersTests.swift index fac3d543..b3fcdde6 100644 --- a/Tests/ViewInspectorTests/ViewModifiers/TransitiveModifiersTests.swift +++ b/Tests/ViewInspectorTests/ViewModifiers/TransitiveModifiersTests.swift @@ -146,11 +146,11 @@ private struct AllowsHitTestingTestView: View, Inspectable { var body: some View { VStack { - Button("1", action: { print("1") }) + Button("1", action: { }) VStack { - Button("2", action: { print("2") }) + Button("2", action: { }) VStack { - Button("3", action: { print("3") }) + Button("3", action: { }) .allowsHitTesting(true) }.allowsHitTesting(false) }.allowsHitTesting(true) From 24b96afd5b32a1e82c6c46dff78caffff2aba87e Mon Sep 17 00:00:00 2001 From: Alexey Naumov Date: Tue, 7 Sep 2021 01:14:13 +0300 Subject: [PATCH 44/99] Unified PopupPresenter protocol --- Sources/ViewInspector/PopupPresenter.swift | 143 ++++++++++++++++++ .../ViewInspector/SwiftUI/ActionSheet.swift | 71 ++------- Sources/ViewInspector/SwiftUI/Alert.swift | 81 ++-------- .../SwiftUI/FullScreenCover.swift | 80 +++------- Sources/ViewInspector/SwiftUI/Popover.swift | 95 +++--------- Sources/ViewInspector/SwiftUI/Sheet.swift | 80 +++------- .../SwiftUI/ActionSheetTests.swift | 19 +-- .../SwiftUI/AlertTests.swift | 19 +-- .../SwiftUI/FullScreenCoverTests.swift | 20 +-- .../SwiftUI/PopoverTests.swift | 24 +-- .../SwiftUI/SheetTests.swift | 20 +-- ViewInspector.xcodeproj/project.pbxproj | 4 + 12 files changed, 274 insertions(+), 382 deletions(-) create mode 100644 Sources/ViewInspector/PopupPresenter.swift diff --git a/Sources/ViewInspector/PopupPresenter.swift b/Sources/ViewInspector/PopupPresenter.swift new file mode 100644 index 00000000..06315988 --- /dev/null +++ b/Sources/ViewInspector/PopupPresenter.swift @@ -0,0 +1,143 @@ +import SwiftUI + +@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) +public protocol PopupPresenter { + func buildPopup() throws -> Any + func dismissPopup() + func content() throws -> ViewInspector.Content + var isAlertPresenter: Bool { get } + var isActionSheetPresenter: Bool { get } + var isPopoverPresenter: Bool { get } + var isSheetPresenter: Bool { get } + var isFullScreenCoverPresenter: Bool { get } +} + +@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) +public protocol SimplePopupPresenter: PopupPresenter { + associatedtype Popup + var isPresented: Binding { get } + var popupBuilder: () -> Popup { get } + var onDismiss: (() -> Void)? { get } +} + +@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) +public protocol ItemPopupPresenter: PopupPresenter { + associatedtype Popup + associatedtype Item: Identifiable + var item: Binding { get } + var popupBuilder: (Item) -> Popup { get } + var onDismiss: (() -> Void)? { get } +} + +// MARK: - Extensions + +@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) +extension PopupPresenter { + func subject(_ type: T.Type) -> String { + if isPopoverPresenter { return "Popover" } + if isSheetPresenter { return "Sheet" } + if isFullScreenCoverPresenter { return "FullScreenCover" } + return Inspector.typeName(type: T.self) + } +} + +@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) +public extension SimplePopupPresenter { + func buildPopup() throws -> Any { + guard isPresented.wrappedValue else { + throw InspectionError.viewNotFound(parent: subject(Popup.self)) + } + return popupBuilder() + } + + func dismissPopup() { + isPresented.wrappedValue = false + onDismiss?() + } +} + +@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) +public extension ItemPopupPresenter { + func buildPopup() throws -> Any { + guard let value = item.wrappedValue else { + throw InspectionError.viewNotFound(parent: subject(Popup.self)) + } + return popupBuilder(value) + } + + func dismissPopup() { + item.wrappedValue = nil + onDismiss?() + } +} + +// MARK: - Alert + +@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) +public extension SimplePopupPresenter where Popup == Alert { + var isAlertPresenter: Bool { true } +} + +@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) +public extension ItemPopupPresenter where Popup == Alert { + var isAlertPresenter: Bool { true } +} + +// MARK: - ActionSheet + +@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) +public extension SimplePopupPresenter where Popup == ActionSheet { + var isActionSheetPresenter: Bool { true } +} + +@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) +public extension ItemPopupPresenter where Popup == ActionSheet { + var isActionSheetPresenter: Bool { true } +} + +// MARK: - Popover, Sheet & FullScreenCover + +@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) +public extension ViewModifier where Self: PopupPresenter { + func content() throws -> ViewInspector.Content { + let view = body(content: _ViewModifier_Content()) + return try view.inspect().viewModifierContent().content + } +} + +@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) +public extension ViewModifier where Self: SimplePopupPresenter { + var isPopoverPresenter: Bool { + return (try? content().standardPopoverModifier()) != nil + } + var isSheetPresenter: Bool { + return (try? content().standardSheetModifier()) != nil + } + var isFullScreenCoverPresenter: Bool { + return (try? content().standardFullScreenCoverModifier()) != nil + } +} + +@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) +public extension ViewModifier where Self: ItemPopupPresenter { + var isPopoverPresenter: Bool { + return (try? content().standardPopoverModifier()) != nil + } + var isSheetPresenter: Bool { + return (try? content().standardSheetModifier()) != nil + } + var isFullScreenCoverPresenter: Bool { + return (try? content().standardFullScreenCoverModifier()) != nil + } +} + +// MARK: - Default + +@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) +public extension PopupPresenter { + var isAlertPresenter: Bool { false } + var isActionSheetPresenter: Bool { false } + var isPopoverPresenter: Bool { false } + var isSheetPresenter: Bool { false } + var isFullScreenCoverPresenter: Bool { false } +} diff --git a/Sources/ViewInspector/SwiftUI/ActionSheet.swift b/Sources/ViewInspector/SwiftUI/ActionSheet.swift index e5e56353..7a1d845e 100644 --- a/Sources/ViewInspector/SwiftUI/ActionSheet.swift +++ b/Sources/ViewInspector/SwiftUI/ActionSheet.swift @@ -32,9 +32,9 @@ public extension InspectableView { internal extension Content { func actionSheet(parent: UnwrappedView, index: Int?) throws -> InspectableView { - guard let sheetBuilder = try? self.modifierAttribute( + guard let sheetPresenter = try? self.modifierAttribute( modifierLookup: { isActionSheetBuilder(modifier: $0) }, path: "modifier", - type: ActionSheetBuilder.self, call: "", index: index ?? 0) + type: PopupPresenter.self, call: "", index: index ?? 0) else { _ = try self.modifier({ $0.modifierType == "IdentifiedPreferenceTransformModifier" @@ -46,8 +46,8 @@ internal extension Content { https://github.com/nalexn/ViewInspector/blob/master/guide.md#alert-sheet-actionsheet-and-fullscreencover """) } - let sheet = try sheetBuilder.buildSheet() - let container = ViewType.ActionSheet.Container(sheet: sheet, builder: sheetBuilder) + let sheet = try sheetPresenter.buildPopup() + let container = ViewType.ActionSheet.Container(sheet: sheet, presenter: sheetPresenter) let medium = self.medium.resettingViewModifiers() let content = Content(container, medium: medium) let call = ViewType.inspectionCall( @@ -67,8 +67,9 @@ internal extension Content { } private func isActionSheetBuilder(modifier: Any) -> Bool { - return (try? Inspector.attribute( - label: "modifier", value: modifier, type: ActionSheetBuilder.self)) != nil + let modifier = try? Inspector.attribute( + label: "modifier", value: modifier, type: PopupPresenter.self) + return modifier?.isActionSheetPresenter == true } } @@ -76,9 +77,8 @@ internal extension Content { @available(macOS, unavailable) internal extension ViewType.ActionSheet { struct Container: CustomViewIdentityMapping { - let sheet: SwiftUI.ActionSheet - let builder: ActionSheetBuilder - + let sheet: Any + let presenter: PopupPresenter var viewTypeForSearch: KnownViewType.Type { ViewType.ActionSheet.self } } } @@ -145,56 +145,3 @@ extension ViewType.ActionSheet: SupplementaryChildren { } } } - -// MARK: - ActionSheet inspection protocols - -@available(iOS 13.0, tvOS 13.0, *) -@available(macOS, unavailable) -public protocol ActionSheetBuilder: SystemPopupPresenter { - func buildSheet() throws -> ActionSheet -} - -@available(iOS 13.0, tvOS 13.0, *) -@available(macOS, unavailable) -public protocol ActionSheetProvider: ActionSheetBuilder { - var isPresented: Binding { get } - var sheetBuilder: () -> ActionSheet { get } -} - -@available(iOS 13.0, tvOS 13.0, *) -@available(macOS, unavailable) -public protocol ActionSheetItemProvider: ActionSheetBuilder { - associatedtype Item: Identifiable - var item: Binding { get } - var sheetBuilder: (Item) -> ActionSheet { get } -} - -@available(iOS 13.0, tvOS 13.0, *) -@available(macOS, unavailable) -public extension ActionSheetProvider { - func buildSheet() throws -> ActionSheet { - guard isPresented.wrappedValue else { - throw InspectionError.viewNotFound(parent: "ActionSheet") - } - return sheetBuilder() - } - - func dismissPopup() { - isPresented.wrappedValue = false - } -} - -@available(iOS 13.0, tvOS 13.0, *) -@available(macOS, unavailable) -public extension ActionSheetItemProvider { - func buildSheet() throws -> ActionSheet { - guard let value = item.wrappedValue else { - throw InspectionError.viewNotFound(parent: "ActionSheet") - } - return sheetBuilder(value) - } - - func dismissPopup() { - item.wrappedValue = nil - } -} diff --git a/Sources/ViewInspector/SwiftUI/Alert.swift b/Sources/ViewInspector/SwiftUI/Alert.swift index d8b6ea05..a959ca9a 100644 --- a/Sources/ViewInspector/SwiftUI/Alert.swift +++ b/Sources/ViewInspector/SwiftUI/Alert.swift @@ -30,9 +30,9 @@ public extension InspectableView { internal extension Content { func alert(parent: UnwrappedView, index: Int?) throws -> InspectableView { - guard let alertBuilder = try? self.modifierAttribute( - modifierLookup: { isAlertBuilder(modifier: $0) }, path: "modifier", - type: AlertBuilder.self, call: "", index: index ?? 0) + guard let alertPresenter = try? self.modifierAttribute( + modifierLookup: { isAlertPresenter(modifier: $0) }, path: "modifier", + type: PopupPresenter.self, call: "", index: index ?? 0) else { _ = try self.modifier({ $0.modifierType == "IdentifiedPreferenceTransformModifier" @@ -44,8 +44,8 @@ internal extension Content { https://github.com/nalexn/ViewInspector/blob/master/guide.md#alert-sheet-actionsheet-and-fullscreencover """) } - let alert = try alertBuilder.buildAlert() - let container = ViewType.Alert.Container(alert: alert, builder: alertBuilder) + let alert = try alertPresenter.buildPopup() + let container = ViewType.Alert.Container(alert: alert, presenter: alertPresenter) let medium = self.medium.resettingViewModifiers() let content = Content(container, medium: medium) let call = ViewType.inspectionCall( @@ -55,7 +55,7 @@ internal extension Content { func alertsForSearch() -> [ViewSearch.ModifierIdentity] { let count = medium.viewModifiers - .filter { isAlertBuilder(modifier: $0) } + .filter { isAlertPresenter(modifier: $0) } .count return Array(0.. Bool { - return (try? Inspector.attribute( - label: "modifier", value: modifier, type: AlertBuilder.self)) != nil + private func isAlertPresenter(modifier: Any) -> Bool { + let modifier = try? Inspector.attribute( + label: "modifier", value: modifier, type: PopupPresenter.self) + return modifier?.isAlertPresenter == true } } @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) internal extension ViewType.Alert { struct Container: CustomViewIdentityMapping { - let alert: SwiftUI.Alert - let builder: AlertBuilder - + let alert: Any + let presenter: PopupPresenter var viewTypeForSearch: KnownViewType.Type { ViewType.Alert.self } } } @@ -205,8 +205,8 @@ public extension InspectableView where View == ViewType.AlertButton { func tap() throws { guard let container = self.parentView?.content.view, let presenter = try? Inspector.attribute( - label: "builder", value: container, - type: SystemPopupPresenter.self) + label: "presenter", value: container, + type: PopupPresenter.self) else { throw InspectionError.parentViewNotFound(view: "Alert.Button") } presenter.dismissPopup() typealias Callback = () -> Void @@ -215,56 +215,3 @@ public extension InspectableView where View == ViewType.AlertButton { callback() } } - -// MARK: - Alert inspection protocols - -@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) -public protocol SystemPopupPresenter { - func dismissPopup() -} - -@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) -public protocol AlertBuilder: SystemPopupPresenter { - func buildAlert() throws -> Alert -} - -@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) -public protocol AlertProvider: AlertBuilder { - var isPresented: Binding { get } - var alertBuilder: () -> Alert { get } -} - -@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) -public protocol AlertItemProvider: AlertBuilder { - associatedtype Item: Identifiable - var item: Binding { get } - var alertBuilder: (Item) -> Alert { get } -} - -@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) -public extension AlertProvider { - func buildAlert() throws -> Alert { - guard isPresented.wrappedValue else { - throw InspectionError.viewNotFound(parent: "Alert") - } - return alertBuilder() - } - - func dismissPopup() { - isPresented.wrappedValue = false - } -} - -@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) -public extension AlertItemProvider { - func buildAlert() throws -> Alert { - guard let value = item.wrappedValue else { - throw InspectionError.viewNotFound(parent: "Alert") - } - return alertBuilder(value) - } - - func dismissPopup() { - item.wrappedValue = nil - } -} diff --git a/Sources/ViewInspector/SwiftUI/FullScreenCover.swift b/Sources/ViewInspector/SwiftUI/FullScreenCover.swift index 34ecaafb..43e634f3 100644 --- a/Sources/ViewInspector/SwiftUI/FullScreenCover.swift +++ b/Sources/ViewInspector/SwiftUI/FullScreenCover.swift @@ -51,28 +51,32 @@ public extension InspectableView { internal extension Content { func fullScreenCover(parent: UnwrappedView, index: Int?) throws -> InspectableView { - guard let fullScreenCoverBuilder = try? self.modifierAttribute( + guard let fullScreenCoverPresenter = try? self.modifierAttribute( modifierLookup: { isFullScreenCoverBuilder(modifier: $0) }, path: "modifier", - type: FullScreenCoverBuilder.self, call: "", index: index ?? 0) + type: PopupPresenter.self, call: "", index: index ?? 0) else { - _ = try self.modifier({ - $0.modifierType == "IdentifiedPreferenceTransformModifier" - || $0.modifierType.contains("SheetPresentationModifier") - }, call: "fullScreenCover") + _ = try standardFullScreenCoverModifier() throw InspectionError.notSupported( """ Please refer to the Guide for inspecting the FullScreenCover: \ https://github.com/nalexn/ViewInspector/blob/master/guide.md#alert-sheet-actionsheet-and-fullscreencover """) } - let view = try fullScreenCoverBuilder.buildFullScreenCover() - let container = ViewType.FullScreenCover.Container(view: view, builder: fullScreenCoverBuilder) + let view = try fullScreenCoverPresenter.buildPopup() + let container = ViewType.FullScreenCover.Container(view: view, presenter: fullScreenCoverPresenter) let medium = self.medium.resettingViewModifiers() let content = Content(container, medium: medium) let call = ViewType.inspectionCall( base: ViewType.FullScreenCover.inspectionCall(typeName: ""), index: index) return try .init(content, parent: parent, call: call, index: index) } + + func standardFullScreenCoverModifier() throws -> Any { + return try self.modifier({ + $0.modifierType == "IdentifiedPreferenceTransformModifier" + || $0.modifierType.contains("SheetPresentationModifier") + }, call: "fullScreenCover") + } func fullScreenCoversForSearch() -> [ViewSearch.ModifierIdentity] { let count = medium.viewModifiers @@ -86,8 +90,9 @@ internal extension Content { } private func isFullScreenCoverBuilder(modifier: Any) -> Bool { - return (try? Inspector.attribute( - label: "modifier", value: modifier, type: FullScreenCoverBuilder.self)) != nil + let modifier = try? Inspector.attribute( + label: "modifier", value: modifier, type: PopupPresenter.self) + return modifier?.isFullScreenCoverPresenter == true } } @@ -95,7 +100,7 @@ internal extension Content { internal extension ViewType.FullScreenCover { struct Container: CustomViewIdentityMapping { let view: Any - let builder: FullScreenCoverBuilder + let presenter: PopupPresenter var viewTypeForSearch: KnownViewType.Type { ViewType.FullScreenCover.self } } @@ -109,57 +114,6 @@ public extension InspectableView where View == ViewType.FullScreenCover { func callOnDismiss() throws { let fullScreenCover = try Inspector.cast(value: content.view, type: ViewType.FullScreenCover.Container.self) - fullScreenCover.builder.dismissPopup() - } -} - -@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) -public protocol FullScreenCoverBuilder: SystemPopupPresenter { - var onDismiss: (() -> Void)? { get } - func buildFullScreenCover() throws -> Any -} - -@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) -public protocol FullScreenCoverProvider: FullScreenCoverBuilder { - var isPresented: Binding { get } - var fullScreenCoverBuilder: () -> Any { get } -} - -@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) -public protocol FullScreenCoverItemProvider: FullScreenCoverBuilder { - associatedtype Item: Identifiable - var item: Binding { get } - var fullScreenCoverBuilder: (Item) -> Any { get } -} - -@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) -public extension FullScreenCoverProvider { - - func buildFullScreenCover() throws -> Any { - guard isPresented.wrappedValue else { - throw InspectionError.viewNotFound(parent: "FullScreenCover") - } - return fullScreenCoverBuilder() - } - - func dismissPopup() { - isPresented.wrappedValue = false - onDismiss?() - } -} - -@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) -public extension FullScreenCoverItemProvider { - - func buildFullScreenCover() throws -> Any { - guard let value = item.wrappedValue else { - throw InspectionError.viewNotFound(parent: "FullScreenCover") - } - return fullScreenCoverBuilder(value) - } - - func dismissPopup() { - item.wrappedValue = nil - onDismiss?() + fullScreenCover.presenter.dismissPopup() } } diff --git a/Sources/ViewInspector/SwiftUI/Popover.swift b/Sources/ViewInspector/SwiftUI/Popover.swift index cf5e5b1a..85458b83 100644 --- a/Sources/ViewInspector/SwiftUI/Popover.swift +++ b/Sources/ViewInspector/SwiftUI/Popover.swift @@ -52,21 +52,19 @@ public extension InspectableView { internal extension Content { func popover(parent: UnwrappedView, index: Int?) throws -> InspectableView { - guard let popoverBuilder = try? self.modifierAttribute( + guard let popoverPresenter = try? self.modifierAttribute( modifierLookup: { isPopoverBuilder(modifier: $0) }, path: "modifier", - type: PopoverBuilder.self, call: "", index: index ?? 0) + type: PopupPresenter.self, call: "", index: index ?? 0) else { - _ = try modifierAttribute( - modifierName: "PopoverPresentationModifier", path: "modifier", - type: Any.self, call: "popover") + _ = try standardPopoverModifier() throw InspectionError.notSupported( """ Please refer to the Guide for inspecting the Popover: \ https://github.com/nalexn/ViewInspector/blob/master/guide.md#alert-sheet-actionsheet-and-fullscreencover """) } - let view = try popoverBuilder.buildPopover() - let container = ViewType.Popover.Container(view: view, builder: popoverBuilder) + let view = try popoverPresenter.buildPopup() + let container = ViewType.Popover.Container(view: view, presenter: popoverPresenter) let medium = self.medium.resettingViewModifiers() let content = Content(container, medium: medium) let call = ViewType.inspectionCall( @@ -74,6 +72,12 @@ internal extension Content { return try .init(content, parent: parent, call: call, index: index) } + func standardPopoverModifier() throws -> Any { + return try modifierAttribute( + modifierName: "PopoverPresentationModifier", path: "modifier", + type: Any.self, call: "popover") + } + func popoversForSearch() -> [ViewSearch.ModifierIdentity] { let count = medium.viewModifiers .filter { isPopoverBuilder(modifier: $0) } @@ -86,8 +90,9 @@ internal extension Content { } private func isPopoverBuilder(modifier: Any) -> Bool { - return (try? Inspector.attribute( - label: "modifier", value: modifier, type: PopoverBuilder.self)) != nil + let modifier = try? Inspector.attribute( + label: "modifier", value: modifier, type: PopupPresenter.self) + return modifier?.isPopoverPresenter == true } } @@ -95,72 +100,12 @@ internal extension Content { internal extension ViewType.Popover { struct Container: CustomViewIdentityMapping { let view: Any - let builder: PopoverBuilder + let presenter: PopupPresenter var viewTypeForSearch: KnownViewType.Type { ViewType.Popover.self } } } -@available(iOS 13.0, macOS 10.15, *) -@available(tvOS, unavailable) -@available(watchOS, unavailable) -public protocol PopoverBuilder: SystemPopupPresenter { - var attachmentAnchor: PopoverAttachmentAnchor { get } - var arrowEdge: Edge { get } - func buildPopover() throws -> Any -} - -@available(iOS 13.0, macOS 10.15, *) -@available(tvOS, unavailable) -@available(watchOS, unavailable) -public protocol PopoverProvider: PopoverBuilder { - var isPresented: Binding { get } - var popoverBuilder: () -> Any { get } -} - -@available(iOS 13.0, macOS 10.15, *) -@available(tvOS, unavailable) -@available(watchOS, unavailable) -public protocol PopoverItemProvider: PopoverBuilder { - associatedtype Item: Identifiable - var item: Binding { get } - var popoverBuilder: (Item) -> Any { get } -} - -@available(iOS 13.0, macOS 10.15, *) -@available(tvOS, unavailable) -@available(watchOS, unavailable) -public extension PopoverProvider { - - func buildPopover() throws -> Any { - guard isPresented.wrappedValue else { - throw InspectionError.viewNotFound(parent: "Popover") - } - return popoverBuilder() - } - - func dismissPopup() { - isPresented.wrappedValue = false - } -} - -@available(iOS 13.0, macOS 10.15, *) -@available(tvOS, unavailable) -@available(watchOS, unavailable) -public extension PopoverItemProvider { - - func buildPopover() throws -> Any { - guard let value = item.wrappedValue else { - throw InspectionError.viewNotFound(parent: "Popover") - } - return popoverBuilder(value) - } - - func dismissPopup() { - item.wrappedValue = nil - } -} - // MARK: - Custom Attributes @available(iOS 13.0, macOS 10.15, *) @@ -170,17 +115,21 @@ public extension InspectableView where View == ViewType.Popover { func callOnDismiss() throws { let popover = try Inspector.cast(value: content.view, type: ViewType.Popover.Container.self) - popover.builder.dismissPopup() + popover.presenter.dismissPopup() } func arrowEdge() throws -> Edge { let popover = try Inspector.cast(value: content.view, type: ViewType.Popover.Container.self) - return popover.builder.arrowEdge + let modifier = try popover.presenter.content().standardPopoverModifier() + return try Inspector.attribute( + label: "arrowEdge", value: modifier, type: Edge.self) } func attachmentAnchor() throws -> PopoverAttachmentAnchor { let popover = try Inspector.cast(value: content.view, type: ViewType.Popover.Container.self) - return popover.builder.attachmentAnchor + let modifier = try popover.presenter.content().standardPopoverModifier() + return try Inspector.attribute( + label: "attachmentAnchor", value: modifier, type: PopoverAttachmentAnchor.self) } } diff --git a/Sources/ViewInspector/SwiftUI/Sheet.swift b/Sources/ViewInspector/SwiftUI/Sheet.swift index 6a553adc..ea68a727 100644 --- a/Sources/ViewInspector/SwiftUI/Sheet.swift +++ b/Sources/ViewInspector/SwiftUI/Sheet.swift @@ -52,22 +52,19 @@ public extension InspectableView { internal extension Content { func sheet(parent: UnwrappedView, index: Int?) throws -> InspectableView { - guard let sheetBuilder = try? self.modifierAttribute( + guard let sheetPresenter = try? self.modifierAttribute( modifierLookup: { isSheetBuilder(modifier: $0) }, path: "modifier", - type: SheetBuilder.self, call: "", index: index ?? 0) + type: PopupPresenter.self, call: "", index: index ?? 0) else { - _ = try self.modifier({ - $0.modifierType == "IdentifiedPreferenceTransformModifier" - || $0.modifierType.contains("SheetPresentationModifier") - }, call: "sheet") + _ = try standardSheetModifier() throw InspectionError.notSupported( """ Please refer to the Guide for inspecting the Sheet: \ https://github.com/nalexn/ViewInspector/blob/master/guide.md#alert-sheet-actionsheet-and-fullscreencover """) } - let view = try sheetBuilder.buildSheet() - let container = ViewType.Sheet.Container(view: view, builder: sheetBuilder) + let view = try sheetPresenter.buildPopup() + let container = ViewType.Sheet.Container(view: view, presenter: sheetPresenter) let medium = self.medium.resettingViewModifiers() let content = Content(container, medium: medium) let call = ViewType.inspectionCall( @@ -75,6 +72,13 @@ internal extension Content { return try .init(content, parent: parent, call: call, index: index) } + func standardSheetModifier() throws -> Any { + return try self.modifier({ + $0.modifierType == "IdentifiedPreferenceTransformModifier" + || $0.modifierType.contains("SheetPresentationModifier") + }, call: "sheet") + } + func sheetsForSearch() -> [ViewSearch.ModifierIdentity] { let count = medium.viewModifiers .filter { isSheetBuilder(modifier: $0) } @@ -87,8 +91,9 @@ internal extension Content { } private func isSheetBuilder(modifier: Any) -> Bool { - return (try? Inspector.attribute( - label: "modifier", value: modifier, type: SheetBuilder.self)) != nil + let modifier = try? Inspector.attribute( + label: "modifier", value: modifier, type: PopupPresenter.self) + return modifier?.isSheetPresenter == true } } @@ -96,7 +101,7 @@ internal extension Content { internal extension ViewType.Sheet { struct Container: CustomViewIdentityMapping { let view: Any - let builder: SheetBuilder + let presenter: PopupPresenter var viewTypeForSearch: KnownViewType.Type { ViewType.Sheet.self } } @@ -109,57 +114,6 @@ public extension InspectableView where View == ViewType.Sheet { func callOnDismiss() throws { let sheet = try Inspector.cast(value: content.view, type: ViewType.Sheet.Container.self) - sheet.builder.dismissPopup() - } -} - -@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) -public protocol SheetBuilder: SystemPopupPresenter { - var onDismiss: (() -> Void)? { get } - func buildSheet() throws -> Any -} - -@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) -public protocol SheetProvider: SheetBuilder { - var isPresented: Binding { get } - var sheetBuilder: () -> Any { get } -} - -@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) -public protocol SheetItemProvider: SheetBuilder { - associatedtype Item: Identifiable - var item: Binding { get } - var sheetBuilder: (Item) -> Any { get } -} - -@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) -public extension SheetProvider { - - func buildSheet() throws -> Any { - guard isPresented.wrappedValue else { - throw InspectionError.viewNotFound(parent: "Sheet") - } - return sheetBuilder() - } - - func dismissPopup() { - isPresented.wrappedValue = false - onDismiss?() - } -} - -@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) -public extension SheetItemProvider { - - func buildSheet() throws -> Any { - guard let value = item.wrappedValue else { - throw InspectionError.viewNotFound(parent: "Sheet") - } - return sheetBuilder(value) - } - - func dismissPopup() { - item.wrappedValue = nil - onDismiss?() + sheet.presenter.dismissPopup() } } diff --git a/Tests/ViewInspectorTests/SwiftUI/ActionSheetTests.swift b/Tests/ViewInspectorTests/SwiftUI/ActionSheetTests.swift index d36ff16c..cd71a29c 100644 --- a/Tests/ViewInspectorTests/SwiftUI/ActionSheetTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/ActionSheetTests.swift @@ -190,35 +190,36 @@ final class ActionSheetTests: XCTestCase { private extension View { func actionSheet2(isPresented: Binding, content: @escaping () -> ActionSheet) -> some View { - return self.modifier(InspectableActionSheet(isPresented: isPresented, sheetBuilder: content)) + return self.modifier(InspectableActionSheet(isPresented: isPresented, popupBuilder: content)) } func actionSheet2(item: Binding, content: @escaping (Item) -> ActionSheet ) -> some View where Item: Identifiable { - return self.modifier(InspectableActionSheetWithItem(item: item, sheetBuilder: content)) + return self.modifier(InspectableActionSheetWithItem(item: item, popupBuilder: content)) } } @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) -private struct InspectableActionSheet: ViewModifier, ActionSheetProvider { - +private struct InspectableActionSheet: ViewModifier, SimplePopupPresenter { let isPresented: Binding - let sheetBuilder: () -> ActionSheet + let popupBuilder: () -> ActionSheet + let onDismiss: (() -> Void)? = nil func body(content: Self.Content) -> some View { - content.actionSheet(isPresented: isPresented, content: sheetBuilder) + content.actionSheet(isPresented: isPresented, content: popupBuilder) } } @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) -private struct InspectableActionSheetWithItem: ViewModifier, ActionSheetItemProvider { +private struct InspectableActionSheetWithItem: ViewModifier, ItemPopupPresenter { let item: Binding - let sheetBuilder: (Item) -> ActionSheet + let popupBuilder: (Item) -> ActionSheet + let onDismiss: (() -> Void)? = nil func body(content: Self.Content) -> some View { - content.actionSheet(item: item, content: sheetBuilder) + content.actionSheet(item: item, content: popupBuilder) } } diff --git a/Tests/ViewInspectorTests/SwiftUI/AlertTests.swift b/Tests/ViewInspectorTests/SwiftUI/AlertTests.swift index a90bf807..ba0aeea2 100644 --- a/Tests/ViewInspectorTests/SwiftUI/AlertTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/AlertTests.swift @@ -238,35 +238,36 @@ extension String: Identifiable { private extension View { func alert2(isPresented: Binding, content: @escaping () -> Alert) -> some View { - return self.modifier(InspectableAlert(isPresented: isPresented, alertBuilder: content)) + return self.modifier(InspectableAlert(isPresented: isPresented, popupBuilder: content)) } func alert2(item: Binding, content: @escaping (Item) -> Alert ) -> some View where Item: Identifiable { - return self.modifier(InspectableAlertWithItem(item: item, alertBuilder: content)) + return self.modifier(InspectableAlertWithItem(item: item, popupBuilder: content)) } } @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) -private struct InspectableAlert: ViewModifier, AlertProvider { +private struct InspectableAlert: ViewModifier, SimplePopupPresenter { let isPresented: Binding - let alertBuilder: () -> Alert + let popupBuilder: () -> Alert + let onDismiss: (() -> Void)? = nil func body(content: Self.Content) -> some View { - content.alert(isPresented: isPresented, content: alertBuilder) + content.alert(isPresented: isPresented, content: popupBuilder) } } @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) -private struct InspectableAlertWithItem: ViewModifier, AlertItemProvider { - +private struct InspectableAlertWithItem: ViewModifier, ItemPopupPresenter { let item: Binding - let alertBuilder: (Item) -> Alert + let popupBuilder: (Item) -> Alert + let onDismiss: (() -> Void)? = nil func body(content: Self.Content) -> some View { - content.alert(item: item, content: alertBuilder) + content.alert(item: item, content: popupBuilder) } } diff --git a/Tests/ViewInspectorTests/SwiftUI/FullScreenCoverTests.swift b/Tests/ViewInspectorTests/SwiftUI/FullScreenCoverTests.swift index ef9ec52d..41fdbb97 100644 --- a/Tests/ViewInspectorTests/SwiftUI/FullScreenCoverTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/FullScreenCoverTests.swift @@ -171,45 +171,41 @@ private extension View { @available(iOS 14.0, tvOS 14.0, watchOS 7.0, *) @available(macOS, unavailable) -private struct InspectableFullScreenCover: ViewModifier, FullScreenCoverProvider +private struct InspectableFullScreenCover: ViewModifier, SimplePopupPresenter where FullScreenCover: View { let isPresented: Binding let onDismiss: (() -> Void)? - let content: () -> FullScreenCover - let fullScreenCoverBuilder: () -> Any + let popupBuilder: () -> FullScreenCover init(isPresented: Binding, onDismiss: (() -> Void)?, content: @escaping () -> FullScreenCover) { self.isPresented = isPresented self.onDismiss = onDismiss - self.content = content - self.fullScreenCoverBuilder = { content() as Any } + self.popupBuilder = content } func body(content: Self.Content) -> some View { - content.fullScreenCover(isPresented: isPresented, content: self.content) + content.fullScreenCover(isPresented: isPresented, onDismiss: onDismiss, content: popupBuilder) } } @available(iOS 14.0, tvOS 14.0, watchOS 7.0, *) @available(macOS, unavailable) -private struct InspectableFullScreenCoverWithItem: ViewModifier, FullScreenCoverItemProvider +private struct InspectableFullScreenCoverWithItem: ViewModifier, ItemPopupPresenter where Item: Identifiable, FullScreenCover: View { let item: Binding let onDismiss: (() -> Void)? - let content: (Item) -> FullScreenCover - let fullScreenCoverBuilder: (Item) -> Any + let popupBuilder: (Item) -> FullScreenCover init(item: Binding, onDismiss: (() -> Void)?, content: @escaping (Item) -> FullScreenCover) { self.item = item self.onDismiss = onDismiss - self.content = content - self.fullScreenCoverBuilder = { content($0) as Any } + self.popupBuilder = content } func body(content: Self.Content) -> some View { - content.fullScreenCover(item: item, onDismiss: onDismiss, content: self.content) + content.fullScreenCover(item: item, onDismiss: onDismiss, content: popupBuilder) } } diff --git a/Tests/ViewInspectorTests/SwiftUI/PopoverTests.swift b/Tests/ViewInspectorTests/SwiftUI/PopoverTests.swift index 0b10f2a4..b8b33f5c 100644 --- a/Tests/ViewInspectorTests/SwiftUI/PopoverTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/PopoverTests.swift @@ -217,13 +217,13 @@ private extension View { } @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) -private struct InspectablePopover: ViewModifier, PopoverProvider where Popover: View { +private struct InspectablePopover: ViewModifier, SimplePopupPresenter where Popover: View { let isPresented: Binding let attachmentAnchor: PopoverAttachmentAnchor let arrowEdge: Edge - let content: () -> Popover - let popoverBuilder: () -> Any + let popupBuilder: () -> Popover + let onDismiss: (() -> Void)? = nil init(isPresented: Binding, attachmentAnchor: PopoverAttachmentAnchor, @@ -232,24 +232,24 @@ private struct InspectablePopover: ViewModifier, PopoverProvider where self.isPresented = isPresented self.attachmentAnchor = attachmentAnchor self.arrowEdge = arrowEdge - self.content = content - self.popoverBuilder = { content() as Any } + self.popupBuilder = content } func body(content: Self.Content) -> some View { - content.popover(isPresented: isPresented, content: self.content) + content.popover(isPresented: isPresented, attachmentAnchor: attachmentAnchor, + arrowEdge: arrowEdge, content: popupBuilder) } } @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) -private struct InspectablePopoverWithItem: ViewModifier, PopoverItemProvider +private struct InspectablePopoverWithItem: ViewModifier, ItemPopupPresenter where Item: Identifiable, Popover: View { let item: Binding let attachmentAnchor: PopoverAttachmentAnchor let arrowEdge: Edge - let content: (Item) -> Popover - let popoverBuilder: (Item) -> Any + let popupBuilder: (Item) -> Popover + let onDismiss: (() -> Void)? = nil init(item: Binding, attachmentAnchor: PopoverAttachmentAnchor, @@ -258,12 +258,12 @@ where Item: Identifiable, Popover: View { self.item = item self.attachmentAnchor = attachmentAnchor self.arrowEdge = arrowEdge - self.content = content - self.popoverBuilder = { content($0) as Any } + self.popupBuilder = content } func body(content: Self.Content) -> some View { - content.popover(item: item, content: self.content) + content.popover(item: item, attachmentAnchor: attachmentAnchor, + arrowEdge: arrowEdge, content: popupBuilder) } } diff --git a/Tests/ViewInspectorTests/SwiftUI/SheetTests.swift b/Tests/ViewInspectorTests/SwiftUI/SheetTests.swift index fe2e2968..7e042e5a 100644 --- a/Tests/ViewInspectorTests/SwiftUI/SheetTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/SheetTests.swift @@ -149,43 +149,39 @@ private extension View { } @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) -private struct InspectableSheet: ViewModifier, SheetProvider where Sheet: View { +private struct InspectableSheet: ViewModifier, SimplePopupPresenter where Sheet: View { let isPresented: Binding let onDismiss: (() -> Void)? - let content: () -> Sheet - let sheetBuilder: () -> Any + let popupBuilder: () -> Sheet init(isPresented: Binding, onDismiss: (() -> Void)?, content: @escaping () -> Sheet) { self.isPresented = isPresented self.onDismiss = onDismiss - self.content = content - self.sheetBuilder = { content() as Any } + self.popupBuilder = content } func body(content: Self.Content) -> some View { - content.sheet(isPresented: isPresented, onDismiss: onDismiss, content: self.content) + content.sheet(isPresented: isPresented, onDismiss: onDismiss, content: popupBuilder) } } @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) -private struct InspectableSheetWithItem: ViewModifier, SheetItemProvider +private struct InspectableSheetWithItem: ViewModifier, ItemPopupPresenter where Item: Identifiable, Sheet: View { let item: Binding let onDismiss: (() -> Void)? - let content: (Item) -> Sheet - let sheetBuilder: (Item) -> Any + let popupBuilder: (Item) -> Sheet init(item: Binding, onDismiss: (() -> Void)?, content: @escaping (Item) -> Sheet) { self.item = item self.onDismiss = onDismiss - self.content = content - self.sheetBuilder = { content($0) as Any } + self.popupBuilder = content } func body(content: Self.Content) -> some View { - content.sheet(item: item, onDismiss: onDismiss, content: self.content) + content.sheet(item: item, onDismiss: onDismiss, content: popupBuilder) } } diff --git a/ViewInspector.xcodeproj/project.pbxproj b/ViewInspector.xcodeproj/project.pbxproj index ee7024d0..c871c836 100644 --- a/ViewInspector.xcodeproj/project.pbxproj +++ b/ViewInspector.xcodeproj/project.pbxproj @@ -23,6 +23,7 @@ /* Begin PBXBuildFile section */ 355B2D57BFF536BCD0B555B8 /* ViewPaddingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 355B2B0F773087003E9F5A49 /* ViewPaddingTests.swift */; }; 520E915C26E64F210090BD1F /* EnvironmentInjection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520E915B26E64F210090BD1F /* EnvironmentInjection.swift */; }; + 520E916226E69E540090BD1F /* PopupPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520E916126E69E540090BD1F /* PopupPresenter.swift */; }; 520F8C13266D0E600026BC57 /* CustomViewModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520F8C12266D0E600026BC57 /* CustomViewModifier.swift */; }; 5214800325F4EA4F002D974D /* EnvironmentObjectInjectionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5214800225F4EA4F002D974D /* EnvironmentObjectInjectionTests.swift */; }; 5214802B25F803B7002D974D /* CustomStyleModifiers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5214802A25F803B7002D974D /* CustomStyleModifiers.swift */; }; @@ -272,6 +273,7 @@ /* Begin PBXFileReference section */ 355B2B0F773087003E9F5A49 /* ViewPaddingTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewPaddingTests.swift; sourceTree = ""; }; 520E915B26E64F210090BD1F /* EnvironmentInjection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EnvironmentInjection.swift; sourceTree = ""; }; + 520E916126E69E540090BD1F /* PopupPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PopupPresenter.swift; sourceTree = ""; }; 520F8C12266D0E600026BC57 /* CustomViewModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomViewModifier.swift; sourceTree = ""; }; 5214800225F4EA4F002D974D /* EnvironmentObjectInjectionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EnvironmentObjectInjectionTests.swift; sourceTree = ""; }; 5214802A25F803B7002D974D /* CustomStyleModifiers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomStyleModifiers.swift; sourceTree = ""; }; @@ -586,6 +588,7 @@ F660849A2594AA6700AF59A2 /* ViewSearchIndex.swift */, F6D58B9223C4A0F3000CEE3B /* ViewHosting.swift */, 520E915B26E64F210090BD1F /* EnvironmentInjection.swift */, + 520E916126E69E540090BD1F /* PopupPresenter.swift */, F68108A423A5833D00B32145 /* Modifiers */, F60EEBBD2382EED0007DB53A /* SwiftUI */, ); @@ -1044,6 +1047,7 @@ D7A6CE8926E17AE900599824 /* FullScreenCover.swift in Sources */, F620C7FB2537B090006D856D /* ConfigurationModifiers.swift in Sources */, F6684BFE23AA863400DECCB3 /* RadialGradient.swift in Sources */, + 520E916226E69E540090BD1F /* PopupPresenter.swift in Sources */, F60EEBD42382EED0007DB53A /* ScrollView.swift in Sources */, F64C4E2C250CD60800A69FF9 /* Color.swift in Sources */, 520E915C26E64F210090BD1F /* EnvironmentInjection.swift in Sources */, From 790e5d791e8e8a964c2d87adea8a451a224fd2ba Mon Sep 17 00:00:00 2001 From: Alexey Naumov Date: Tue, 7 Sep 2021 22:16:41 +0300 Subject: [PATCH 45/99] Reuse more code with popups --- Sources/ViewInspector/Inspector.swift | 3 +- Sources/ViewInspector/PopupPresenter.swift | 45 ++++++++++++++++ .../ViewInspector/SwiftUI/ActionSheet.swift | 53 ++++++------------ Sources/ViewInspector/SwiftUI/Alert.swift | 54 ++++++------------- .../SwiftUI/FullScreenCover.swift | 44 ++++----------- Sources/ViewInspector/SwiftUI/Popover.swift | 47 ++++------------ Sources/ViewInspector/SwiftUI/Sheet.swift | 43 +++------------ 7 files changed, 105 insertions(+), 184 deletions(-) diff --git a/Sources/ViewInspector/Inspector.swift b/Sources/ViewInspector/Inspector.swift index ee561338..b7d48690 100644 --- a/Sources/ViewInspector/Inspector.swift +++ b/Sources/ViewInspector/Inspector.swift @@ -212,7 +212,8 @@ extension Inspector { guard let firstPrefix = namespacedPrefixes.first else { return } let typeWithParams = typeName(type: type(of: value)) - let typePrefix = typeName(type: type(of: value), namespaced: true, prefixOnly: true) + let withGenericParams = firstPrefix.contains("<") + let typePrefix = typeName(type: type(of: value), namespaced: true, prefixOnly: !withGenericParams) if typePrefix == "SwiftUI.EnvironmentReaderView" { if typeWithParams.contains("NavigationBarItemsKey") { throw InspectionError.notSupported( diff --git a/Sources/ViewInspector/PopupPresenter.swift b/Sources/ViewInspector/PopupPresenter.swift index 06315988..9b920b07 100644 --- a/Sources/ViewInspector/PopupPresenter.swift +++ b/Sources/ViewInspector/PopupPresenter.swift @@ -141,3 +141,48 @@ public extension PopupPresenter { var isSheetPresenter: Bool { false } var isFullScreenCoverPresenter: Bool { false } } + +// MARK: - PopupContainer + +@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) +internal extension ViewType { + struct PopupContainer: CustomViewIdentityMapping { + let popup: Any + let presenter: PopupPresenter + var viewTypeForSearch: KnownViewType.Type { Popup.self } + } +} + +@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) +internal extension ViewType.PopupContainer { + static var typePrefix: String { + "ViewInspector.ViewType.PopupContainer" + } +} + +@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) +internal extension Content { + func popup( + parent: UnwrappedView, index: Int?, + modifierPredicate: ModifierLookupClosure, standardPredicate: () throws -> Any + ) throws -> InspectableView { + guard let popupPresenter = try? self.modifierAttribute( + modifierLookup: modifierPredicate, path: "modifier", + type: PopupPresenter.self, call: "", index: index ?? 0) + else { + _ = try standardPredicate() + throw InspectionError.notSupported( + """ + Please refer to the Guide for inspecting the \(Inspector.typeName(type: Popup.self)): \ + https://github.com/nalexn/ViewInspector/blob/master/guide.md#alert-sheet-actionsheet-and-fullscreencover + """) + } + let popup = try popupPresenter.buildPopup() + let container = ViewType.PopupContainer(popup: popup, presenter: popupPresenter) + let medium = self.medium.resettingViewModifiers() + let content = Content(container, medium: medium) + let call = ViewType.inspectionCall( + base: Popup.inspectionCall(typeName: ""), index: index) + return try .init(content, parent: parent, call: call, index: index) + } +} diff --git a/Sources/ViewInspector/SwiftUI/ActionSheet.swift b/Sources/ViewInspector/SwiftUI/ActionSheet.swift index 7a1d845e..044611f8 100644 --- a/Sources/ViewInspector/SwiftUI/ActionSheet.swift +++ b/Sources/ViewInspector/SwiftUI/ActionSheet.swift @@ -6,10 +6,8 @@ import SwiftUI public extension ViewType { struct ActionSheet: KnownViewType { - public static var typePrefix: String = "ViewType.ActionSheet.Container" - public static var namespacedPrefixes: [String] { - return ["ViewInspector." + typePrefix] - } + public static var typePrefix: String = ViewType.PopupContainer.typePrefix + public static var namespacedPrefixes: [String] { [typePrefix] } public static func inspectionCall(typeName: String) -> String { return "actionSheet(\(ViewType.indexPlaceholder))" } @@ -32,27 +30,16 @@ public extension InspectableView { internal extension Content { func actionSheet(parent: UnwrappedView, index: Int?) throws -> InspectableView { - guard let sheetPresenter = try? self.modifierAttribute( - modifierLookup: { isActionSheetBuilder(modifier: $0) }, path: "modifier", - type: PopupPresenter.self, call: "", index: index ?? 0) - else { - _ = try self.modifier({ - $0.modifierType == "IdentifiedPreferenceTransformModifier" - || $0.modifierType.contains("AlertTransformModifier") - }, call: "actionSheet") - throw InspectionError.notSupported( - """ - Please refer to the Guide for inspecting the ActionSheet: \ - https://github.com/nalexn/ViewInspector/blob/master/guide.md#alert-sheet-actionsheet-and-fullscreencover - """) - } - let sheet = try sheetPresenter.buildPopup() - let container = ViewType.ActionSheet.Container(sheet: sheet, presenter: sheetPresenter) - let medium = self.medium.resettingViewModifiers() - let content = Content(container, medium: medium) - let call = ViewType.inspectionCall( - base: ViewType.ActionSheet.inspectionCall(typeName: ""), index: index) - return try .init(content, parent: parent, call: call, index: index) + return try popup(parent: parent, index: index, + modifierPredicate: isActionSheetBuilder(modifier:), + standardPredicate: standardActionSheetModifier) + } + + func standardActionSheetModifier() throws -> Any { + return try self.modifier({ + $0.modifierType == "IdentifiedPreferenceTransformModifier" + || $0.modifierType.contains("AlertTransformModifier") + }, call: "actionSheet") } func actionSheetsForSearch() -> [ViewSearch.ModifierIdentity] { @@ -73,16 +60,6 @@ internal extension Content { } } -@available(iOS 13.0, tvOS 13.0, *) -@available(macOS, unavailable) -internal extension ViewType.ActionSheet { - struct Container: CustomViewIdentityMapping { - let sheet: Any - let presenter: PopupPresenter - var viewTypeForSearch: KnownViewType.Type { ViewType.ActionSheet.self } - } -} - // MARK: - Custom Attributes @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) @@ -114,18 +91,18 @@ public extension InspectableView where View == ViewType.ActionSheet { extension ViewType.ActionSheet: SupplementaryChildren { static func supplementaryChildren(_ parent: UnwrappedView) throws -> LazyGroup { let buttons = try Inspector.attribute( - path: "sheet|buttons", value: parent.content.view, type: [Any].self) + path: "popup|buttons", value: parent.content.view, type: [Any].self) return .init(count: 2 + buttons.count) { index in let medium = parent.content.medium.resettingViewModifiers() switch index { case 0: - let view = try Inspector.attribute(path: "sheet|title", value: parent.content.view) + let view = try Inspector.attribute(path: "popup|title", value: parent.content.view) let content = try Inspector.unwrap(content: Content(view, medium: medium)) return try InspectableView( content, parent: parent, call: "title()") case 1: let maybeView = try Inspector.attribute( - path: "sheet|message", value: parent.content.view, type: Text?.self) + path: "popup|message", value: parent.content.view, type: Text?.self) guard let view = maybeView else { throw InspectionError.viewNotFound(parent: "message") } diff --git a/Sources/ViewInspector/SwiftUI/Alert.swift b/Sources/ViewInspector/SwiftUI/Alert.swift index a959ca9a..f115029b 100644 --- a/Sources/ViewInspector/SwiftUI/Alert.swift +++ b/Sources/ViewInspector/SwiftUI/Alert.swift @@ -6,10 +6,8 @@ import SwiftUI public extension ViewType { struct Alert: KnownViewType { - public static var typePrefix: String = "ViewType.Alert.Container" - public static var namespacedPrefixes: [String] { - return ["ViewInspector." + typePrefix] - } + public static var typePrefix: String = ViewType.PopupContainer.typePrefix + public static var namespacedPrefixes: [String] { [typePrefix] } public static func inspectionCall(typeName: String) -> String { return "alert(\(ViewType.indexPlaceholder))" } @@ -30,27 +28,16 @@ public extension InspectableView { internal extension Content { func alert(parent: UnwrappedView, index: Int?) throws -> InspectableView { - guard let alertPresenter = try? self.modifierAttribute( - modifierLookup: { isAlertPresenter(modifier: $0) }, path: "modifier", - type: PopupPresenter.self, call: "", index: index ?? 0) - else { - _ = try self.modifier({ - $0.modifierType == "IdentifiedPreferenceTransformModifier" - || $0.modifierType.contains("AlertTransformModifier") - }, call: "alert") - throw InspectionError.notSupported( - """ - Please refer to the Guide for inspecting the Alert: \ - https://github.com/nalexn/ViewInspector/blob/master/guide.md#alert-sheet-actionsheet-and-fullscreencover - """) - } - let alert = try alertPresenter.buildPopup() - let container = ViewType.Alert.Container(alert: alert, presenter: alertPresenter) - let medium = self.medium.resettingViewModifiers() - let content = Content(container, medium: medium) - let call = ViewType.inspectionCall( - base: ViewType.Alert.inspectionCall(typeName: ""), index: index) - return try .init(content, parent: parent, call: call, index: index) + return try popup(parent: parent, index: index, + modifierPredicate: isAlertPresenter(modifier:), + standardPredicate: standardAlertModifier) + } + + func standardAlertModifier() throws -> Any { + return try self.modifier({ + $0.modifierType == "IdentifiedPreferenceTransformModifier" + || $0.modifierType.contains("AlertTransformModifier") + }, call: "alert") } func alertsForSearch() -> [ViewSearch.ModifierIdentity] { @@ -71,15 +58,6 @@ internal extension Content { } } -@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) -internal extension ViewType.Alert { - struct Container: CustomViewIdentityMapping { - let alert: Any - let presenter: PopupPresenter - var viewTypeForSearch: KnownViewType.Type { ViewType.Alert.self } - } -} - // MARK: - Custom Attributes @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) @@ -115,13 +93,13 @@ extension ViewType.Alert: SupplementaryChildren { let medium = parent.content.medium.resettingViewModifiers() switch index { case 0: - let view = try Inspector.attribute(path: "alert|title", value: parent.content.view) + let view = try Inspector.attribute(path: "popup|title", value: parent.content.view) let content = try Inspector.unwrap(content: Content(view, medium: medium)) return try InspectableView( content, parent: parent, call: "title()") case 1: let maybeView = try Inspector.attribute( - path: "alert|message", value: parent.content.view, type: Text?.self) + path: "popup|message", value: parent.content.view, type: Text?.self) guard let view = maybeView else { throw InspectionError.viewNotFound(parent: "message") } @@ -129,13 +107,13 @@ extension ViewType.Alert: SupplementaryChildren { return try InspectableView( content, parent: parent, call: "message()") case 2: - let view = try Inspector.attribute(path: "alert|primaryButton", value: parent.content.view) + let view = try Inspector.attribute(path: "popup|primaryButton", value: parent.content.view) let content = try Inspector.unwrap(content: Content(view, medium: medium)) return try InspectableView( content, parent: parent, call: "primaryButton()") default: let maybeView = try Inspector.attribute( - path: "alert|secondaryButton", value: parent.content.view, type: Alert.Button?.self) + path: "popup|secondaryButton", value: parent.content.view, type: Alert.Button?.self) guard let view = maybeView else { throw InspectionError.viewNotFound(parent: "secondaryButton") } diff --git a/Sources/ViewInspector/SwiftUI/FullScreenCover.swift b/Sources/ViewInspector/SwiftUI/FullScreenCover.swift index 43e634f3..1b4ac9c8 100644 --- a/Sources/ViewInspector/SwiftUI/FullScreenCover.swift +++ b/Sources/ViewInspector/SwiftUI/FullScreenCover.swift @@ -4,10 +4,8 @@ import SwiftUI public extension ViewType { struct FullScreenCover: KnownViewType { - public static var typePrefix: String = "ViewType.FullScreenCover.Container" - public static var namespacedPrefixes: [String] { - return ["ViewInspector." + typePrefix] - } + public static var typePrefix: String = ViewType.PopupContainer.typePrefix + public static var namespacedPrefixes: [String] { [typePrefix] } public static func inspectionCall(typeName: String) -> String { return "fullScreenCover(\(ViewType.indexPlaceholder))" } @@ -20,7 +18,7 @@ public extension ViewType { extension ViewType.FullScreenCover: SingleViewContent { public static func child(_ content: Content) throws -> Content { - let view = try Inspector.attribute(label: "view", value: content.view) + let view = try Inspector.attribute(label: "popup", value: content.view) let medium = content.medium.resettingViewModifiers() return try Inspector.unwrap(view: view, medium: medium) } @@ -30,7 +28,7 @@ extension ViewType.FullScreenCover: SingleViewContent { extension ViewType.FullScreenCover: MultipleViewContent { public static func children(_ content: Content) throws -> LazyGroup { - let view = try Inspector.attribute(label: "view", value: content.view) + let view = try Inspector.attribute(label: "popup", value: content.view) let medium = content.medium.resettingViewModifiers() return try Inspector.viewsInContainer(view: view, medium: medium) } @@ -51,24 +49,9 @@ public extension InspectableView { internal extension Content { func fullScreenCover(parent: UnwrappedView, index: Int?) throws -> InspectableView { - guard let fullScreenCoverPresenter = try? self.modifierAttribute( - modifierLookup: { isFullScreenCoverBuilder(modifier: $0) }, path: "modifier", - type: PopupPresenter.self, call: "", index: index ?? 0) - else { - _ = try standardFullScreenCoverModifier() - throw InspectionError.notSupported( - """ - Please refer to the Guide for inspecting the FullScreenCover: \ - https://github.com/nalexn/ViewInspector/blob/master/guide.md#alert-sheet-actionsheet-and-fullscreencover - """) - } - let view = try fullScreenCoverPresenter.buildPopup() - let container = ViewType.FullScreenCover.Container(view: view, presenter: fullScreenCoverPresenter) - let medium = self.medium.resettingViewModifiers() - let content = Content(container, medium: medium) - let call = ViewType.inspectionCall( - base: ViewType.FullScreenCover.inspectionCall(typeName: ""), index: index) - return try .init(content, parent: parent, call: call, index: index) + return try popup(parent: parent, index: index, + modifierPredicate: isFullScreenCoverBuilder(modifier:), + standardPredicate: standardFullScreenCoverModifier) } func standardFullScreenCoverModifier() throws -> Any { @@ -96,16 +79,6 @@ internal extension Content { } } -@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) -internal extension ViewType.FullScreenCover { - struct Container: CustomViewIdentityMapping { - let view: Any - let presenter: PopupPresenter - - var viewTypeForSearch: KnownViewType.Type { ViewType.FullScreenCover.self } - } -} - // MARK: - Custom Attributes @available(iOS 14.0, tvOS 14.0, watchOS 7.0, *) @@ -113,7 +86,8 @@ internal extension ViewType.FullScreenCover { public extension InspectableView where View == ViewType.FullScreenCover { func callOnDismiss() throws { - let fullScreenCover = try Inspector.cast(value: content.view, type: ViewType.FullScreenCover.Container.self) + let fullScreenCover = try Inspector.cast( + value: content.view, type: ViewType.PopupContainer.self) fullScreenCover.presenter.dismissPopup() } } diff --git a/Sources/ViewInspector/SwiftUI/Popover.swift b/Sources/ViewInspector/SwiftUI/Popover.swift index 85458b83..af7890e6 100644 --- a/Sources/ViewInspector/SwiftUI/Popover.swift +++ b/Sources/ViewInspector/SwiftUI/Popover.swift @@ -4,10 +4,8 @@ import SwiftUI public extension ViewType { struct Popover: KnownViewType { - public static var typePrefix: String = "ViewType.Popover.Container" - public static var namespacedPrefixes: [String] { - return ["ViewInspector." + typePrefix] - } + public static var typePrefix: String = ViewType.PopupContainer.typePrefix + public static var namespacedPrefixes: [String] { [typePrefix] } public static func inspectionCall(typeName: String) -> String { return "popover(\(ViewType.indexPlaceholder))" } @@ -20,7 +18,7 @@ public extension ViewType { extension ViewType.Popover: SingleViewContent { public static func child(_ content: Content) throws -> Content { - let view = try Inspector.attribute(label: "view", value: content.view) + let view = try Inspector.attribute(label: "popup", value: content.view) let medium = content.medium.resettingViewModifiers() return try Inspector.unwrap(view: view, medium: medium) } @@ -30,7 +28,7 @@ extension ViewType.Popover: SingleViewContent { extension ViewType.Popover: MultipleViewContent { public static func children(_ content: Content) throws -> LazyGroup { - let view = try Inspector.attribute(label: "view", value: content.view) + let view = try Inspector.attribute(label: "popup", value: content.view) let medium = content.medium.resettingViewModifiers() return try Inspector.viewsInContainer(view: view, medium: medium) } @@ -52,24 +50,9 @@ public extension InspectableView { internal extension Content { func popover(parent: UnwrappedView, index: Int?) throws -> InspectableView { - guard let popoverPresenter = try? self.modifierAttribute( - modifierLookup: { isPopoverBuilder(modifier: $0) }, path: "modifier", - type: PopupPresenter.self, call: "", index: index ?? 0) - else { - _ = try standardPopoverModifier() - throw InspectionError.notSupported( - """ - Please refer to the Guide for inspecting the Popover: \ - https://github.com/nalexn/ViewInspector/blob/master/guide.md#alert-sheet-actionsheet-and-fullscreencover - """) - } - let view = try popoverPresenter.buildPopup() - let container = ViewType.Popover.Container(view: view, presenter: popoverPresenter) - let medium = self.medium.resettingViewModifiers() - let content = Content(container, medium: medium) - let call = ViewType.inspectionCall( - base: ViewType.Popover.inspectionCall(typeName: ""), index: index) - return try .init(content, parent: parent, call: call, index: index) + return try popup(parent: parent, index: index, + modifierPredicate: isPopoverBuilder(modifier:), + standardPredicate: standardPopoverModifier) } func standardPopoverModifier() throws -> Any { @@ -96,16 +79,6 @@ internal extension Content { } } -@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) -internal extension ViewType.Popover { - struct Container: CustomViewIdentityMapping { - let view: Any - let presenter: PopupPresenter - - var viewTypeForSearch: KnownViewType.Type { ViewType.Popover.self } - } -} - // MARK: - Custom Attributes @available(iOS 13.0, macOS 10.15, *) @@ -114,19 +87,19 @@ internal extension ViewType.Popover { public extension InspectableView where View == ViewType.Popover { func callOnDismiss() throws { - let popover = try Inspector.cast(value: content.view, type: ViewType.Popover.Container.self) + let popover = try Inspector.cast(value: content.view, type: ViewType.PopupContainer.self) popover.presenter.dismissPopup() } func arrowEdge() throws -> Edge { - let popover = try Inspector.cast(value: content.view, type: ViewType.Popover.Container.self) + let popover = try Inspector.cast(value: content.view, type: ViewType.PopupContainer.self) let modifier = try popover.presenter.content().standardPopoverModifier() return try Inspector.attribute( label: "arrowEdge", value: modifier, type: Edge.self) } func attachmentAnchor() throws -> PopoverAttachmentAnchor { - let popover = try Inspector.cast(value: content.view, type: ViewType.Popover.Container.self) + let popover = try Inspector.cast(value: content.view, type: ViewType.PopupContainer.self) let modifier = try popover.presenter.content().standardPopoverModifier() return try Inspector.attribute( label: "attachmentAnchor", value: modifier, type: PopoverAttachmentAnchor.self) diff --git a/Sources/ViewInspector/SwiftUI/Sheet.swift b/Sources/ViewInspector/SwiftUI/Sheet.swift index ea68a727..03af66da 100644 --- a/Sources/ViewInspector/SwiftUI/Sheet.swift +++ b/Sources/ViewInspector/SwiftUI/Sheet.swift @@ -6,10 +6,8 @@ import SwiftUI public extension ViewType { struct Sheet: KnownViewType { - public static var typePrefix: String = "ViewType.Sheet.Container" - public static var namespacedPrefixes: [String] { - return ["ViewInspector." + typePrefix] - } + public static var typePrefix: String = ViewType.PopupContainer.typePrefix + public static var namespacedPrefixes: [String] { [typePrefix] } public static func inspectionCall(typeName: String) -> String { return "sheet(\(ViewType.indexPlaceholder))" } @@ -22,7 +20,7 @@ public extension ViewType { extension ViewType.Sheet: SingleViewContent { public static func child(_ content: Content) throws -> Content { - let view = try Inspector.attribute(label: "view", value: content.view) + let view = try Inspector.attribute(label: "popup", value: content.view) let medium = content.medium.resettingViewModifiers() return try Inspector.unwrap(view: view, medium: medium) } @@ -32,7 +30,7 @@ extension ViewType.Sheet: SingleViewContent { extension ViewType.Sheet: MultipleViewContent { public static func children(_ content: Content) throws -> LazyGroup { - let view = try Inspector.attribute(label: "view", value: content.view) + let view = try Inspector.attribute(label: "popup", value: content.view) let medium = content.medium.resettingViewModifiers() return try Inspector.viewsInContainer(view: view, medium: medium) } @@ -52,24 +50,9 @@ public extension InspectableView { internal extension Content { func sheet(parent: UnwrappedView, index: Int?) throws -> InspectableView { - guard let sheetPresenter = try? self.modifierAttribute( - modifierLookup: { isSheetBuilder(modifier: $0) }, path: "modifier", - type: PopupPresenter.self, call: "", index: index ?? 0) - else { - _ = try standardSheetModifier() - throw InspectionError.notSupported( - """ - Please refer to the Guide for inspecting the Sheet: \ - https://github.com/nalexn/ViewInspector/blob/master/guide.md#alert-sheet-actionsheet-and-fullscreencover - """) - } - let view = try sheetPresenter.buildPopup() - let container = ViewType.Sheet.Container(view: view, presenter: sheetPresenter) - let medium = self.medium.resettingViewModifiers() - let content = Content(container, medium: medium) - let call = ViewType.inspectionCall( - base: ViewType.Sheet.inspectionCall(typeName: ""), index: index) - return try .init(content, parent: parent, call: call, index: index) + return try popup(parent: parent, index: index, + modifierPredicate: isSheetBuilder(modifier:), + standardPredicate: standardSheetModifier) } func standardSheetModifier() throws -> Any { @@ -97,23 +80,13 @@ internal extension Content { } } -@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) -internal extension ViewType.Sheet { - struct Container: CustomViewIdentityMapping { - let view: Any - let presenter: PopupPresenter - - var viewTypeForSearch: KnownViewType.Type { ViewType.Sheet.self } - } -} - // MARK: - Custom Attributes @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) public extension InspectableView where View == ViewType.Sheet { func callOnDismiss() throws { - let sheet = try Inspector.cast(value: content.view, type: ViewType.Sheet.Container.self) + let sheet = try Inspector.cast(value: content.view, type: ViewType.PopupContainer.self) sheet.presenter.dismissPopup() } } From 9a807bb12f9a815cbe4d0bdcccf92986d9b81dd2 Mon Sep 17 00:00:00 2001 From: Alexey Naumov Date: Wed, 8 Sep 2021 21:16:01 +0300 Subject: [PATCH 46/99] Fix Shape being a blocker for search --- Sources/ViewInspector/SwiftUI/Shape.swift | 31 ++++++++++++++----- Sources/ViewInspector/ViewSearchIndex.swift | 3 ++ .../ViewInspectorTests/ViewSearchTests.swift | 16 ++++++++++ 3 files changed, 42 insertions(+), 8 deletions(-) diff --git a/Sources/ViewInspector/SwiftUI/Shape.swift b/Sources/ViewInspector/SwiftUI/Shape.swift index fee25c71..7fdd22a7 100644 --- a/Sources/ViewInspector/SwiftUI/Shape.swift +++ b/Sources/ViewInspector/SwiftUI/Shape.swift @@ -5,6 +5,9 @@ public extension ViewType { struct Shape: KnownViewType { public static var typePrefix: String = "" + public static func inspectionCall(typeName: String) -> String { + return "shape(\(ViewType.indexPlaceholder))" + } } } @@ -15,7 +18,7 @@ public extension InspectableView where View: SingleViewContent { func shape() throws -> InspectableView { let content = try child() - try guardShapeIsInspectable(content.view) + try content.throwIfNotShape() return try .init(content, parent: self) } } @@ -27,7 +30,7 @@ public extension InspectableView where View: MultipleViewContent { func shape(_ index: Int) throws -> InspectableView { let content = try child(at: index) - try guardShapeIsInspectable(content.view) + try content.throwIfNotShape() return try .init(content, parent: self, index: index) } } @@ -97,12 +100,6 @@ public extension InspectableView where View == ViewType.Shape { @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) private extension InspectableView { - func guardShapeIsInspectable(_ view: Any) throws { - guard view is InspectableShape || Inspector.typeName(value: view) == "_Inset" else { - throw InspectionError.typeMismatch(view, InspectableShape.self) - } - } - func shapeAttribute(_ view: Any, _ shapeType: String, _ label: String, _ attributeType: T.Type ) throws -> T { let shape = try lookupShape(view, typeName: shapeType, label: label) @@ -122,6 +119,24 @@ private extension InspectableView { } } +@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) +internal extension Content { + var isShape: Bool { + do { + try throwIfNotShape() + return true + } catch { + return false + } + } + + fileprivate func throwIfNotShape() throws { + guard view is InspectableShape || Inspector.typeName(value: view) == "_Inset" else { + throw InspectionError.typeMismatch(view, InspectableShape.self) + } + } +} + // MARK: - InspectableShape @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) diff --git a/Sources/ViewInspector/ViewSearchIndex.swift b/Sources/ViewInspector/ViewSearchIndex.swift index 2777a4df..eddd3184 100644 --- a/Sources/ViewInspector/ViewSearchIndex.swift +++ b/Sources/ViewInspector/ViewSearchIndex.swift @@ -65,6 +65,9 @@ internal extension ViewSearch { let letter = String(viewType.typePrefix.prefix(1)) return index[letter]?.first(where: { $0.viewType == viewType }) } + if content.isShape { + return .init(ViewType.Shape.self) + } let shortPrefix = Inspector.typeName(value: content.view, prefixOnly: true) let longPrefix = Inspector.typeName(value: content.view, namespaced: true, prefixOnly: true) if shortPrefix.count > 0, diff --git a/Tests/ViewInspectorTests/ViewSearchTests.swift b/Tests/ViewInspectorTests/ViewSearchTests.swift index 5bd1cdcd..784655ff 100644 --- a/Tests/ViewInspectorTests/ViewSearchTests.swift +++ b/Tests/ViewInspectorTests/ViewSearchTests.swift @@ -235,4 +235,20 @@ final class ViewSearchTests: XCTestCase { XCTAssertEqual(try sut.find(ViewType.StyleConfiguration.Label.self).pathToRoot, "group().styleConfigurationLabel(2)") } + + func testShapesSearching() throws { + let sut = Group { + Circle().inset(by: 5) + Rectangle() + Ellipse().offset(x: 2, y: 3) + } + XCTAssertThrows(try sut.inspect().find(text: "none"), + "Search did not find a match") + let testRect = CGRect(x: 0, y: 0, width: 10, height: 100) + let refPath = Ellipse().offset(x: 2, y: 3).path(in: testRect) + let ellipse = try sut.inspect().find(where: { + try $0.shape().path(in: testRect) == refPath + }) + XCTAssertEqual(ellipse.pathToRoot, "group().shape(2)") + } } From 0117d54da66b3c35fd12144ac4beac6854804817 Mon Sep 17 00:00:00 2001 From: Alexey Naumov Date: Wed, 8 Sep 2021 21:22:17 +0300 Subject: [PATCH 47/99] Fix tests for macOS --- Sources/ViewInspector/PopupPresenter.swift | 6 ++++-- Sources/ViewInspector/SwiftUI/TouchBar.swift | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Sources/ViewInspector/PopupPresenter.swift b/Sources/ViewInspector/PopupPresenter.swift index 9b920b07..7ccc2610 100644 --- a/Sources/ViewInspector/PopupPresenter.swift +++ b/Sources/ViewInspector/PopupPresenter.swift @@ -85,12 +85,14 @@ public extension ItemPopupPresenter where Popup == Alert { // MARK: - ActionSheet -@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) +@available(iOS 13.0, tvOS 13.0, *) +@available(macOS, unavailable) public extension SimplePopupPresenter where Popup == ActionSheet { var isActionSheetPresenter: Bool { true } } -@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) +@available(iOS 13.0, tvOS 13.0, *) +@available(macOS, unavailable) public extension ItemPopupPresenter where Popup == ActionSheet { var isActionSheetPresenter: Bool { true } } diff --git a/Sources/ViewInspector/SwiftUI/TouchBar.swift b/Sources/ViewInspector/SwiftUI/TouchBar.swift index 51277046..44c0d4ba 100644 --- a/Sources/ViewInspector/SwiftUI/TouchBar.swift +++ b/Sources/ViewInspector/SwiftUI/TouchBar.swift @@ -73,7 +73,7 @@ internal extension Content { func touchBar(parent: UnwrappedView, index: Int?) throws -> InspectableView { let rootView = try modifierAttribute( modifierName: "_TouchBarModifier", path: "modifier|touchBar", - type: Any.self, call: "touchBar", index: index) + type: Any.self, call: "touchBar", index: index ?? 0) let content = try Inspector.unwrap(content: Content(rootView)) let call = ViewType.inspectionCall( base: ViewType.TouchBar.inspectionCall(typeName: ""), index: nil) From 6784dc76e3fe7b2d6921017fcc7e734b967c25f4 Mon Sep 17 00:00:00 2001 From: Alexey Naumov Date: Wed, 8 Sep 2021 21:36:07 +0300 Subject: [PATCH 48/99] Tiny refactor of popups --- Sources/ViewInspector/SwiftUI/ActionSheet.swift | 2 +- Sources/ViewInspector/SwiftUI/Alert.swift | 2 +- Sources/ViewInspector/SwiftUI/FullScreenCover.swift | 2 +- Sources/ViewInspector/SwiftUI/Popover.swift | 2 +- Sources/ViewInspector/SwiftUI/Sheet.swift | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Sources/ViewInspector/SwiftUI/ActionSheet.swift b/Sources/ViewInspector/SwiftUI/ActionSheet.swift index 044611f8..f200e97c 100644 --- a/Sources/ViewInspector/SwiftUI/ActionSheet.swift +++ b/Sources/ViewInspector/SwiftUI/ActionSheet.swift @@ -44,7 +44,7 @@ internal extension Content { func actionSheetsForSearch() -> [ViewSearch.ModifierIdentity] { let count = medium.viewModifiers - .filter { isActionSheetBuilder(modifier: $0) } + .filter(isActionSheetBuilder(modifier:)) .count return Array(0.. [ViewSearch.ModifierIdentity] { let count = medium.viewModifiers - .filter { isAlertPresenter(modifier: $0) } + .filter(isAlertPresenter(modifier:)) .count return Array(0.. [ViewSearch.ModifierIdentity] { let count = medium.viewModifiers - .filter { isFullScreenCoverBuilder(modifier: $0) } + .filter(isFullScreenCoverBuilder(modifier:)) .count return Array(0.. [ViewSearch.ModifierIdentity] { let count = medium.viewModifiers - .filter { isPopoverBuilder(modifier: $0) } + .filter(isPopoverBuilder(modifier:)) .count return Array(0.. [ViewSearch.ModifierIdentity] { let count = medium.viewModifiers - .filter { isSheetBuilder(modifier: $0) } + .filter(isSheetBuilder(modifier:)) .count return Array(0.. Date: Wed, 8 Sep 2021 23:38:59 +0300 Subject: [PATCH 49/99] Add ConfirmationDialog support --- .../SwiftUI/ConfirmationDialog.swift | 114 +++++++++++++++++ Sources/ViewInspector/ViewSearchIndex.swift | 4 + .../SwiftUI/ConfirmationDialogTests.swift | 121 ++++++++++++++++++ ViewInspector.xcodeproj/project.pbxproj | 8 ++ 4 files changed, 247 insertions(+) create mode 100644 Sources/ViewInspector/SwiftUI/ConfirmationDialog.swift create mode 100644 Tests/ViewInspectorTests/SwiftUI/ConfirmationDialogTests.swift diff --git a/Sources/ViewInspector/SwiftUI/ConfirmationDialog.swift b/Sources/ViewInspector/SwiftUI/ConfirmationDialog.swift new file mode 100644 index 00000000..7a95f02b --- /dev/null +++ b/Sources/ViewInspector/SwiftUI/ConfirmationDialog.swift @@ -0,0 +1,114 @@ +import SwiftUI + +// MARK: - Alert + +@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) +public extension ViewType { + + struct ConfirmationDialog: KnownViewType { + public static var typePrefix: String = "ConfirmationDialogModifier" + public static func inspectionCall(typeName: String) -> String { + return "confirmationDialog(\(ViewType.indexPlaceholder))" + } + } +} + +// MARK: - Extraction + +@available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) +public extension InspectableView { + + func confirmationDialog(_ index: Int? = nil) throws -> InspectableView { + return try contentForModifierLookup.confirmationDialog(parent: self, index: index) + } +} + +@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) +internal extension Content { + + func confirmationDialog(parent: UnwrappedView, index: Int?) throws -> InspectableView { + let modifier = try self.modifierAttribute( + modifierLookup: isConfirmationDialog(modifier:), path: "modifier", + type: Any.self, call: "confirmationDialog", index: index ?? 0) + let medium = self.medium.resettingViewModifiers() + let content = Content(modifier, medium: medium) + let call = ViewType.inspectionCall( + base: ViewType.ConfirmationDialog.inspectionCall(typeName: ""), index: index) + let view = try InspectableView( + content, parent: parent, call: call, index: index) + guard try view.isPresented().wrappedValue else { + throw InspectionError.viewNotFound(parent: "ConfirmationDialog") + } + return view + } + + private func isConfirmationDialog(modifier: Any) -> Bool { + guard let modifier = modifier as? ModifierNameProvider + else { return false } + return modifier.modifierType.contains("ConfirmationDialogModifier") + } +} + +// MARK: - Non Standard Children + +@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) +extension ViewType.ConfirmationDialog: SupplementaryChildren { + static func supplementaryChildren(_ parent: UnwrappedView) throws -> LazyGroup { + return .init(count: 3) { index in + let medium = parent.content.medium.resettingViewModifiers() + switch index { + case 0: + let view = try Inspector.attribute(path: "title", value: parent.content.view) + let content = try Inspector.unwrap(content: Content(view, medium: medium)) + return try InspectableView( + content, parent: parent, call: "title()") + case 1: + let view = try Inspector.attribute(path: "message", value: parent.content.view) + let content = try Inspector.unwrap(content: Content(view, medium: medium)) + return try InspectableView( + content, parent: parent, call: "message()") + default: + let view = try Inspector.attribute(path: "actions", value: parent.content.view) + let content = try Inspector.unwrap(content: Content(view, medium: medium)) + return try InspectableView( + content, parent: parent, call: "actions()") + } + } + } +} + +@available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) +public extension InspectableView where View == ViewType.ConfirmationDialog { + + func title() throws -> InspectableView { + return try View.supplementaryChildren(self).element(at: 0) + .asInspectableView(ofType: ViewType.Text.self) + } + + func message() throws -> InspectableView { + return try View.supplementaryChildren(self).element(at: 1) + .asInspectableView(ofType: ViewType.ClassifiedView.self) + } + + func actions() throws -> InspectableView { + return try View.supplementaryChildren(self).element(at: 2) + .asInspectableView(ofType: ViewType.ClassifiedView.self) + } + + func titleVisibility() throws -> Visibility { + return try Inspector.attribute( + label: "titleVisibility", value: content.view, type: Visibility.self) + } + + func dismiss() throws { + try isPresented().wrappedValue = false + } +} + +@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) +private extension InspectableView where View == ViewType.ConfirmationDialog { + func isPresented() throws -> Binding { + return try Inspector.attribute( + label: "isPresented", value: content.view, type: Binding.self) + } +} diff --git a/Sources/ViewInspector/ViewSearchIndex.swift b/Sources/ViewInspector/ViewSearchIndex.swift index eddd3184..fd483f82 100644 --- a/Sources/ViewInspector/ViewSearchIndex.swift +++ b/Sources/ViewInspector/ViewSearchIndex.swift @@ -11,6 +11,7 @@ internal extension ViewSearch { .init(ViewType.AngularGradient.self), .init(ViewType.AnyView.self), .init(ViewType.Button.self), .init(ViewType.Color.self), .init(ViewType.ColorPicker.self), + .init(ViewType.ConfirmationDialog.self), .init(ViewType.DatePicker.self), .init(ViewType.DisclosureGroup.self), .init(ViewType.Divider.self), .init(ViewType.EditButton.self), .init(ViewType.EmptyView.self), @@ -251,6 +252,9 @@ internal extension ViewSearch { .init(name: ViewType.Toolbar.typePrefix, builder: { parent, index in try parent.content.toolbar(parent: parent, index: index) }), + .init(name: ViewType.ConfirmationDialog.typePrefix, builder: { parent, index in + try parent.content.confirmationDialog(parent: parent, index: index) + }), .init(name: "PopoverPresentationModifier", builder: { parent, index in try parent.content.popover(parent: parent, index: index) }), diff --git a/Tests/ViewInspectorTests/SwiftUI/ConfirmationDialogTests.swift b/Tests/ViewInspectorTests/SwiftUI/ConfirmationDialogTests.swift new file mode 100644 index 00000000..e61a131e --- /dev/null +++ b/Tests/ViewInspectorTests/SwiftUI/ConfirmationDialogTests.swift @@ -0,0 +1,121 @@ +import XCTest +import SwiftUI +@testable import ViewInspector + +@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) +final class ConfirmationDialogTests: XCTestCase { + + func testInspectionNotBlocked() throws { + guard #available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) + else { return } + let binding = Binding(wrappedValue: true) + let sut = EmptyView().confirmationDialog(Text("title"), isPresented: binding, actions: { EmptyView() }) + XCTAssertNoThrow(try sut.inspect().emptyView()) + } + + func testInspectionErrorNoModifier() throws { + guard #available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) + else { return } + let sut = EmptyView().offset() + XCTAssertThrows(try sut.inspect().emptyView().confirmationDialog(), + "EmptyView does not have 'confirmationDialog' modifier") + } + + func testInspectionErrorWhenNotPresented() throws { + guard #available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) + else { return } + let binding = Binding(wrappedValue: false) + let sut = EmptyView().confirmationDialog(Text("title"), isPresented: binding, actions: { EmptyView() }) + XCTAssertThrows(try sut.inspect().emptyView().confirmationDialog(), + "View for ConfirmationDialog is absent") + } + + func testSimpleUnwrap() throws { + guard #available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) + else { return } + let binding = Binding(wrappedValue: true) + let sut = EmptyView().confirmationDialog(Text("title"), isPresented: binding, actions: { EmptyView() }) + XCTAssertEqual(try sut.inspect().emptyView().confirmationDialog().pathToRoot, + "emptyView().confirmationDialog()") + } + + func testTitleVisibility() throws { + guard #available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) + else { return } + let binding = Binding(wrappedValue: true) + let sut = EmptyView().confirmationDialog( + Text("abc"), isPresented: binding, + titleVisibility: .visible, actions: { EmptyView() }) + let visibility = try sut.inspect().emptyView().confirmationDialog().titleVisibility() + XCTAssertEqual(visibility, .visible) + } + + func testTitleInspection() throws { + guard #available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) + else { return } + let binding = Binding(wrappedValue: true) + let sut = EmptyView().confirmationDialog(Text("abc"), isPresented: binding, actions: { EmptyView() }) + let title = try sut.inspect().emptyView().confirmationDialog().title() + XCTAssertEqual(try title.string(), "abc") + XCTAssertEqual(title.pathToRoot, "emptyView().confirmationDialog().title()") + } + + func testMessageInspection() throws { + guard #available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) + else { return } + let binding = Binding(wrappedValue: true) + let sut = EmptyView().confirmationDialog( + Text("title"), isPresented: binding, actions: { EmptyView() }, + message: { AnyView(Text("abc")) }) + let message = try sut.inspect().emptyView().confirmationDialog().message().anyView().text() + XCTAssertEqual(try message.string(), "abc") + XCTAssertEqual(message.pathToRoot, + "emptyView().confirmationDialog().message().anyView().text()") + } + + func testActionsInspection() throws { + guard #available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) + else { return } + let binding = Binding(wrappedValue: true) + let sut = EmptyView().confirmationDialog( + Text(""), isPresented: binding, presenting: "abc") { AnyView(Text($0)) } + let message = try sut.inspect().emptyView().confirmationDialog().actions().anyView().text() + XCTAssertEqual(try message.string(), "abc") + XCTAssertEqual(message.pathToRoot, + "emptyView().confirmationDialog().actions().anyView().text()") + } + + func testDismiss() throws { + guard #available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) + else { return } + let binding = Binding(wrappedValue: true) + let sut = EmptyView().confirmationDialog( + Text("abc"), isPresented: binding, actions: { EmptyView() }) + try sut.inspect().emptyView().confirmationDialog().dismiss() + XCTAssertThrows(try sut.inspect().emptyView().confirmationDialog(), + "View for ConfirmationDialog is absent") + } + + func testSearch() throws { + guard #available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) + else { return } + let binding = Binding(wrappedValue: true) + let sut = Group { + EmptyView() + Text("") + .confirmationDialog(Text("1"), isPresented: binding, + actions: { EmptyView() }, message: { Text("2") }) + .padding() + .confirmationDialog(Text("3"), isPresented: binding, + actions: { Text("4") }) + } + XCTAssertEqual(try sut.inspect().find(text: "1").pathToRoot, + "group().text(1).confirmationDialog().title()") + XCTAssertEqual(try sut.inspect().find(text: "2").pathToRoot, + "group().text(1).confirmationDialog().message().text()") + XCTAssertEqual(try sut.inspect().find(text: "3").pathToRoot, + "group().text(1).confirmationDialog(1).title()") + XCTAssertEqual(try sut.inspect().find(text: "4").pathToRoot, + "group().text(1).confirmationDialog(1).actions().text()") + } +} diff --git a/ViewInspector.xcodeproj/project.pbxproj b/ViewInspector.xcodeproj/project.pbxproj index c871c836..5da1626f 100644 --- a/ViewInspector.xcodeproj/project.pbxproj +++ b/ViewInspector.xcodeproj/project.pbxproj @@ -45,6 +45,8 @@ 52A4A7642621F4AE0063E00B /* Overlay.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52A4A7632621F4AE0063E00B /* Overlay.swift */; }; 52A5CA0425E1139E00773CF5 /* EnvironmentModifiers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52A5CA0325E1139E00773CF5 /* EnvironmentModifiers.swift */; }; 52D37480262B1F0C00B1BFBA /* NestedModifiersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52D3747F262B1F0C00B1BFBA /* NestedModifiersTests.swift */; }; + 52E24E9926E9378A00711987 /* ConfirmationDialog.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52E24E9826E9378A00711987 /* ConfirmationDialog.swift */; }; + 52E24E9B26E93A4700711987 /* ConfirmationDialogTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52E24E9A26E93A4700711987 /* ConfirmationDialogTests.swift */; }; 52F356AA267692D100695E43 /* MapAnnotation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52F356A9267692D100695E43 /* MapAnnotation.swift */; }; 52F356AC2676940A00695E43 /* MapAnnotationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52F356AB2676940A00695E43 /* MapAnnotationTests.swift */; }; 79069A6B238E8490000F6B58 /* OptionalContent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 79069A6A238E8490000F6B58 /* OptionalContent.swift */; }; @@ -293,6 +295,8 @@ 52A4A7632621F4AE0063E00B /* Overlay.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Overlay.swift; sourceTree = ""; }; 52A5CA0325E1139E00773CF5 /* EnvironmentModifiers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EnvironmentModifiers.swift; sourceTree = ""; }; 52D3747F262B1F0C00B1BFBA /* NestedModifiersTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NestedModifiersTests.swift; sourceTree = ""; }; + 52E24E9826E9378A00711987 /* ConfirmationDialog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfirmationDialog.swift; sourceTree = ""; }; + 52E24E9A26E93A4700711987 /* ConfirmationDialogTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfirmationDialogTests.swift; sourceTree = ""; }; 52F356A9267692D100695E43 /* MapAnnotation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapAnnotation.swift; sourceTree = ""; }; 52F356AB2676940A00695E43 /* MapAnnotationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapAnnotationTests.swift; sourceTree = ""; }; 79069A6A238E8490000F6B58 /* OptionalContent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OptionalContent.swift; sourceTree = ""; }; @@ -607,6 +611,7 @@ F64C4E2B250CD60800A69FF9 /* Color.swift */, F6FB7F5725476431006658EF /* ColorPicker.swift */, F64057EC238DB1530029D9BA /* ConditionalContent.swift */, + 52E24E9826E9378A00711987 /* ConfirmationDialog.swift */, F60EEBBE2382EED0007DB53A /* CustomView.swift */, 520F8C12266D0E600026BC57 /* CustomViewModifier.swift */, F60EEBBF2382EED0007DB53A /* DatePicker.swift */, @@ -716,6 +721,7 @@ F64C4E2F250CD71400A69FF9 /* ColorTests.swift */, F6FB7F6125476480006658EF /* ColorPickerTests.swift */, F6F08E6723A2A67D001F04DF /* ConditionalContentTests.swift */, + 52E24E9A26E93A4700711987 /* ConfirmationDialogTests.swift */, F60EEBEF2382F004007DB53A /* CustomViewTests.swift */, F6B7D0092494E12F00ABB5E0 /* CustomViewBuilderTests.swift */, F69C91CB2383189200515A91 /* CustomViewModifierTests.swift */, @@ -1068,6 +1074,7 @@ F609EFBD23A40B8800B9256A /* DelayedPreferenceView.swift in Sources */, F6684BF223AA554500DECCB3 /* PasteButton.swift in Sources */, F60EEBD12382EED0007DB53A /* DatePicker.swift in Sources */, + 52E24E9926E9378A00711987 /* ConfirmationDialog.swift in Sources */, F64A2C6823A3FD3A00A4853A /* TreeView.swift in Sources */, F6A35A4025B35E920068B8B2 /* LazyGroup.swift in Sources */, F64057EF238DBA800029D9BA /* EmptyView.swift in Sources */, @@ -1148,6 +1155,7 @@ F614E66625B36ACC000C4F66 /* InspectableViewTests.swift in Sources */, F6684BF823AA58F200DECCB3 /* AngularGradientTests.swift in Sources */, F6684C0023AA864F00DECCB3 /* RadialGradientTests.swift in Sources */, + 52E24E9B26E93A4700711987 /* ConfirmationDialogTests.swift in Sources */, F6C15A31254A0F29000240F1 /* LazyVStackTests.swift in Sources */, CDA844DA262B81CD00C56C98 /* SimultaneousGestureTests.swift in Sources */, F6D933B92385EDDF00358E0E /* PickerTests.swift in Sources */, From a938d8cc08883bd34a0274abcda736876125b248 Mon Sep 17 00:00:00 2001 From: Alexey Naumov Date: Fri, 10 Sep 2021 00:02:39 +0300 Subject: [PATCH 50/99] Unify popup dismissing API, rename presenter protocols --- Sources/ViewInspector/PopupPresenter.swift | 24 +++++++++---------- .../ViewInspector/SwiftUI/ActionSheet.swift | 8 ++++++- Sources/ViewInspector/SwiftUI/Alert.swift | 10 ++++++-- .../SwiftUI/ConfirmationDialog.swift | 6 ++--- .../SwiftUI/FullScreenCover.swift | 8 +++---- Sources/ViewInspector/SwiftUI/Popover.swift | 17 +++++-------- Sources/ViewInspector/SwiftUI/Sheet.swift | 11 ++++++--- .../SwiftUI/ActionSheetTests.swift | 23 +++++++++++++++++- .../SwiftUI/AlertTests.swift | 23 +++++++++++++++++- .../SwiftUI/FullScreenCoverTests.swift | 14 ++++++----- .../SwiftUI/PopoverTests.swift | 12 ++++++---- .../SwiftUI/SheetTests.swift | 12 ++++++---- 12 files changed, 114 insertions(+), 54 deletions(-) diff --git a/Sources/ViewInspector/PopupPresenter.swift b/Sources/ViewInspector/PopupPresenter.swift index 7ccc2610..b5fbb188 100644 --- a/Sources/ViewInspector/PopupPresenter.swift +++ b/Sources/ViewInspector/PopupPresenter.swift @@ -1,7 +1,7 @@ import SwiftUI @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) -public protocol PopupPresenter { +public protocol BasePopupPresenter { func buildPopup() throws -> Any func dismissPopup() func content() throws -> ViewInspector.Content @@ -13,7 +13,7 @@ public protocol PopupPresenter { } @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) -public protocol SimplePopupPresenter: PopupPresenter { +public protocol PopupPresenter: BasePopupPresenter { associatedtype Popup var isPresented: Binding { get } var popupBuilder: () -> Popup { get } @@ -21,7 +21,7 @@ public protocol SimplePopupPresenter: PopupPresenter { } @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) -public protocol ItemPopupPresenter: PopupPresenter { +public protocol ItemPopupPresenter: BasePopupPresenter { associatedtype Popup associatedtype Item: Identifiable var item: Binding { get } @@ -32,7 +32,7 @@ public protocol ItemPopupPresenter: PopupPresenter { // MARK: - Extensions @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) -extension PopupPresenter { +extension BasePopupPresenter { func subject(_ type: T.Type) -> String { if isPopoverPresenter { return "Popover" } if isSheetPresenter { return "Sheet" } @@ -42,7 +42,7 @@ extension PopupPresenter { } @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) -public extension SimplePopupPresenter { +public extension PopupPresenter { func buildPopup() throws -> Any { guard isPresented.wrappedValue else { throw InspectionError.viewNotFound(parent: subject(Popup.self)) @@ -74,7 +74,7 @@ public extension ItemPopupPresenter { // MARK: - Alert @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) -public extension SimplePopupPresenter where Popup == Alert { +public extension PopupPresenter where Popup == Alert { var isAlertPresenter: Bool { true } } @@ -87,7 +87,7 @@ public extension ItemPopupPresenter where Popup == Alert { @available(iOS 13.0, tvOS 13.0, *) @available(macOS, unavailable) -public extension SimplePopupPresenter where Popup == ActionSheet { +public extension PopupPresenter where Popup == ActionSheet { var isActionSheetPresenter: Bool { true } } @@ -100,7 +100,7 @@ public extension ItemPopupPresenter where Popup == ActionSheet { // MARK: - Popover, Sheet & FullScreenCover @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) -public extension ViewModifier where Self: PopupPresenter { +public extension ViewModifier where Self: BasePopupPresenter { func content() throws -> ViewInspector.Content { let view = body(content: _ViewModifier_Content()) return try view.inspect().viewModifierContent().content @@ -108,7 +108,7 @@ public extension ViewModifier where Self: PopupPresenter { } @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) -public extension ViewModifier where Self: SimplePopupPresenter { +public extension ViewModifier where Self: PopupPresenter { var isPopoverPresenter: Bool { return (try? content().standardPopoverModifier()) != nil } @@ -136,7 +136,7 @@ public extension ViewModifier where Self: ItemPopupPresenter { // MARK: - Default @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) -public extension PopupPresenter { +public extension BasePopupPresenter { var isAlertPresenter: Bool { false } var isActionSheetPresenter: Bool { false } var isPopoverPresenter: Bool { false } @@ -150,7 +150,7 @@ public extension PopupPresenter { internal extension ViewType { struct PopupContainer: CustomViewIdentityMapping { let popup: Any - let presenter: PopupPresenter + let presenter: BasePopupPresenter var viewTypeForSearch: KnownViewType.Type { Popup.self } } } @@ -170,7 +170,7 @@ internal extension Content { ) throws -> InspectableView { guard let popupPresenter = try? self.modifierAttribute( modifierLookup: modifierPredicate, path: "modifier", - type: PopupPresenter.self, call: "", index: index ?? 0) + type: BasePopupPresenter.self, call: "", index: index ?? 0) else { _ = try standardPredicate() throw InspectionError.notSupported( diff --git a/Sources/ViewInspector/SwiftUI/ActionSheet.swift b/Sources/ViewInspector/SwiftUI/ActionSheet.swift index f200e97c..c6f0ec67 100644 --- a/Sources/ViewInspector/SwiftUI/ActionSheet.swift +++ b/Sources/ViewInspector/SwiftUI/ActionSheet.swift @@ -55,7 +55,7 @@ internal extension Content { private func isActionSheetBuilder(modifier: Any) -> Bool { let modifier = try? Inspector.attribute( - label: "modifier", value: modifier, type: PopupPresenter.self) + label: "modifier", value: modifier, type: BasePopupPresenter.self) return modifier?.isActionSheetPresenter == true } } @@ -83,6 +83,12 @@ public extension InspectableView where View == ViewType.ActionSheet { return try allViews.element(at: index + 2) .asInspectableView(ofType: ViewType.AlertButton.self) } + + func dismiss() throws { + let container = try Inspector.cast( + value: content.view, type: ViewType.PopupContainer.self) + container.presenter.dismissPopup() + } } // MARK: - Non Standard Children diff --git a/Sources/ViewInspector/SwiftUI/Alert.swift b/Sources/ViewInspector/SwiftUI/Alert.swift index 01e3ebde..40dcc717 100644 --- a/Sources/ViewInspector/SwiftUI/Alert.swift +++ b/Sources/ViewInspector/SwiftUI/Alert.swift @@ -53,7 +53,7 @@ internal extension Content { private func isAlertPresenter(modifier: Any) -> Bool { let modifier = try? Inspector.attribute( - label: "modifier", value: modifier, type: PopupPresenter.self) + label: "modifier", value: modifier, type: BasePopupPresenter.self) return modifier?.isAlertPresenter == true } } @@ -82,6 +82,12 @@ public extension InspectableView where View == ViewType.Alert { return try View.supplementaryChildren(self).element(at: 3) .asInspectableView(ofType: ViewType.AlertButton.self) } + + func dismiss() throws { + let container = try Inspector.cast( + value: content.view, type: ViewType.PopupContainer.self) + container.presenter.dismissPopup() + } } // MARK: - Non Standard Children @@ -184,7 +190,7 @@ public extension InspectableView where View == ViewType.AlertButton { guard let container = self.parentView?.content.view, let presenter = try? Inspector.attribute( label: "presenter", value: container, - type: PopupPresenter.self) + type: BasePopupPresenter.self) else { throw InspectionError.parentViewNotFound(view: "Alert.Button") } presenter.dismissPopup() typealias Callback = () -> Void diff --git a/Sources/ViewInspector/SwiftUI/ConfirmationDialog.swift b/Sources/ViewInspector/SwiftUI/ConfirmationDialog.swift index 7a95f02b..69407a44 100644 --- a/Sources/ViewInspector/SwiftUI/ConfirmationDialog.swift +++ b/Sources/ViewInspector/SwiftUI/ConfirmationDialog.swift @@ -36,7 +36,7 @@ internal extension Content { base: ViewType.ConfirmationDialog.inspectionCall(typeName: ""), index: index) let view = try InspectableView( content, parent: parent, call: call, index: index) - guard try view.isPresented().wrappedValue else { + guard try view.isPresentedBinding().wrappedValue else { throw InspectionError.viewNotFound(parent: "ConfirmationDialog") } return view @@ -101,13 +101,13 @@ public extension InspectableView where View == ViewType.ConfirmationDialog { } func dismiss() throws { - try isPresented().wrappedValue = false + try isPresentedBinding().wrappedValue = false } } @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) private extension InspectableView where View == ViewType.ConfirmationDialog { - func isPresented() throws -> Binding { + func isPresentedBinding() throws -> Binding { return try Inspector.attribute( label: "isPresented", value: content.view, type: Binding.self) } diff --git a/Sources/ViewInspector/SwiftUI/FullScreenCover.swift b/Sources/ViewInspector/SwiftUI/FullScreenCover.swift index b0f5218c..22296d92 100644 --- a/Sources/ViewInspector/SwiftUI/FullScreenCover.swift +++ b/Sources/ViewInspector/SwiftUI/FullScreenCover.swift @@ -74,7 +74,7 @@ internal extension Content { private func isFullScreenCoverBuilder(modifier: Any) -> Bool { let modifier = try? Inspector.attribute( - label: "modifier", value: modifier, type: PopupPresenter.self) + label: "modifier", value: modifier, type: BasePopupPresenter.self) return modifier?.isFullScreenCoverPresenter == true } } @@ -85,9 +85,9 @@ internal extension Content { @available(macOS, unavailable) public extension InspectableView where View == ViewType.FullScreenCover { - func callOnDismiss() throws { - let fullScreenCover = try Inspector.cast( + func dismiss() throws { + let container = try Inspector.cast( value: content.view, type: ViewType.PopupContainer.self) - fullScreenCover.presenter.dismissPopup() + container.presenter.dismissPopup() } } diff --git a/Sources/ViewInspector/SwiftUI/Popover.swift b/Sources/ViewInspector/SwiftUI/Popover.swift index 64b92c5f..c1a6727a 100644 --- a/Sources/ViewInspector/SwiftUI/Popover.swift +++ b/Sources/ViewInspector/SwiftUI/Popover.swift @@ -74,7 +74,7 @@ internal extension Content { private func isPopoverBuilder(modifier: Any) -> Bool { let modifier = try? Inspector.attribute( - label: "modifier", value: modifier, type: PopupPresenter.self) + label: "modifier", value: modifier, type: BasePopupPresenter.self) return modifier?.isPopoverPresenter == true } } @@ -86,11 +86,6 @@ internal extension Content { @available(watchOS, unavailable) public extension InspectableView where View == ViewType.Popover { - func callOnDismiss() throws { - let popover = try Inspector.cast(value: content.view, type: ViewType.PopupContainer.self) - popover.presenter.dismissPopup() - } - func arrowEdge() throws -> Edge { let popover = try Inspector.cast(value: content.view, type: ViewType.PopupContainer.self) let modifier = try popover.presenter.content().standardPopoverModifier() @@ -104,6 +99,11 @@ public extension InspectableView where View == ViewType.Popover { return try Inspector.attribute( label: "attachmentAnchor", value: modifier, type: PopoverAttachmentAnchor.self) } + + func dismiss() throws { + let container = try Inspector.cast(value: content.view, type: ViewType.PopupContainer.self) + container.presenter.dismissPopup() + } } // MARK: - Deprecated: @@ -128,11 +128,6 @@ public extension InspectableView where View == ViewType.Popover { func isPresented() throws -> Bool { return true } - - @available(*, deprecated, renamed: "callOnDismiss") - func dismiss() throws { - try callOnDismiss() - } } @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) diff --git a/Sources/ViewInspector/SwiftUI/Sheet.swift b/Sources/ViewInspector/SwiftUI/Sheet.swift index c7527087..f91b9907 100644 --- a/Sources/ViewInspector/SwiftUI/Sheet.swift +++ b/Sources/ViewInspector/SwiftUI/Sheet.swift @@ -75,7 +75,7 @@ internal extension Content { private func isSheetBuilder(modifier: Any) -> Bool { let modifier = try? Inspector.attribute( - label: "modifier", value: modifier, type: PopupPresenter.self) + label: "modifier", value: modifier, type: BasePopupPresenter.self) return modifier?.isSheetPresenter == true } } @@ -85,8 +85,13 @@ internal extension Content { @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) public extension InspectableView where View == ViewType.Sheet { + func dismiss() throws { + let container = try Inspector.cast(value: content.view, type: ViewType.PopupContainer.self) + container.presenter.dismissPopup() + } + + @available(*, deprecated, renamed: "dismiss") func callOnDismiss() throws { - let sheet = try Inspector.cast(value: content.view, type: ViewType.PopupContainer.self) - sheet.presenter.dismissPopup() + try dismiss() } } diff --git a/Tests/ViewInspectorTests/SwiftUI/ActionSheetTests.swift b/Tests/ViewInspectorTests/SwiftUI/ActionSheetTests.swift index cd71a29c..02b10dc4 100644 --- a/Tests/ViewInspectorTests/SwiftUI/ActionSheetTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/ActionSheetTests.swift @@ -134,6 +134,27 @@ final class ActionSheetTests: XCTestCase { XCTAssertNil(binding.wrappedValue) } + func testDismiss() throws { + let binding = Binding(wrappedValue: true) + let sut = EmptyView().actionSheet2(isPresented: binding) { + ActionSheet(title: Text("abc")) + } + XCTAssertTrue(binding.wrappedValue) + try sut.inspect().actionSheet().dismiss() + XCTAssertFalse(binding.wrappedValue) + XCTAssertThrows(try sut.inspect().actionSheet(), "View for ActionSheet is absent") + } + + func testDismissForItemVersion() throws { + let binding = Binding(wrappedValue: 6) + let sut = EmptyView().actionSheet2(item: binding) { value in + ActionSheet(title: Text("\(value)")) + } + try sut.inspect().emptyView().actionSheet().dismiss() + XCTAssertNil(binding.wrappedValue) + XCTAssertThrows(try sut.inspect().actionSheet(), "View for ActionSheet is absent") + } + func testMultipleSheetsInspection() throws { let binding1 = Binding(wrappedValue: true) let binding2 = Binding(wrappedValue: true) @@ -201,7 +222,7 @@ private extension View { } @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) -private struct InspectableActionSheet: ViewModifier, SimplePopupPresenter { +private struct InspectableActionSheet: ViewModifier, PopupPresenter { let isPresented: Binding let popupBuilder: () -> ActionSheet let onDismiss: (() -> Void)? = nil diff --git a/Tests/ViewInspectorTests/SwiftUI/AlertTests.swift b/Tests/ViewInspectorTests/SwiftUI/AlertTests.swift index ba0aeea2..aef2ff5a 100644 --- a/Tests/ViewInspectorTests/SwiftUI/AlertTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/AlertTests.swift @@ -178,6 +178,27 @@ final class AlertTests: XCTestCase { XCTAssertNil(binding.wrappedValue) } + func testDismiss() throws { + let binding = Binding(wrappedValue: true) + let sut = EmptyView().alert2(isPresented: binding) { + Alert(title: Text("abc")) + } + XCTAssertTrue(binding.wrappedValue) + try sut.inspect().alert().dismiss() + XCTAssertFalse(binding.wrappedValue) + XCTAssertThrows(try sut.inspect().alert(), "View for Alert is absent") + } + + func testDismissForItemVersion() throws { + let binding = Binding(wrappedValue: 6) + let sut = EmptyView().alert2(item: binding) { value in + Alert(title: Text("\(value)")) + } + try sut.inspect().emptyView().alert().dismiss() + XCTAssertNil(binding.wrappedValue) + XCTAssertThrows(try sut.inspect().alert(), "View for Alert is absent") + } + func testMultipleAlertsInspection() throws { let binding1 = Binding(wrappedValue: true) let binding2 = Binding(wrappedValue: true) @@ -249,7 +270,7 @@ private extension View { } @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) -private struct InspectableAlert: ViewModifier, SimplePopupPresenter { +private struct InspectableAlert: ViewModifier, PopupPresenter { let isPresented: Binding let popupBuilder: () -> Alert diff --git a/Tests/ViewInspectorTests/SwiftUI/FullScreenCoverTests.swift b/Tests/ViewInspectorTests/SwiftUI/FullScreenCoverTests.swift index 41fdbb97..88695fce 100644 --- a/Tests/ViewInspectorTests/SwiftUI/FullScreenCoverTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/FullScreenCoverTests.swift @@ -70,7 +70,7 @@ final class FullScreenCoverTests: XCTestCase { XCTAssertEqual(button.pathToRoot, "emptyView().fullScreenCover().button(1)") } - func testOnDismiss() throws { + func testDismiss() throws { guard #available(iOS 14.0, tvOS 14.0, watchOS 7.0, *) else { return } let exp = XCTestExpectation(description: #function) let binding = Binding(wrappedValue: true) @@ -78,20 +78,22 @@ final class FullScreenCoverTests: XCTestCase { exp.fulfill() }, content: { Text("") }) XCTAssertTrue(binding.wrappedValue) - try sut.inspect().fullScreenCover().callOnDismiss() + try sut.inspect().fullScreenCover().dismiss() XCTAssertFalse(binding.wrappedValue) + XCTAssertThrows(try sut.inspect().fullScreenCover(), "View for Sheet is absent") wait(for: [exp], timeout: 0.1) } - func testContentWithItemInspection() throws { + func testDismissForItemVersion() throws { guard #available(iOS 14.0, tvOS 14.0, watchOS 7.0, *) else { return } let binding = Binding(wrappedValue: 6) let sut = EmptyView().fullScreenCover2(item: binding) { Text("\($0)") } - let fullScreenCover = try sut.inspect().emptyView().fullScreenCover() + let fullScreenCover = try sut.inspect().fullScreenCover() XCTAssertEqual(try fullScreenCover.text().string(), "6") XCTAssertEqual(binding.wrappedValue, 6) - try fullScreenCover.callOnDismiss() + try fullScreenCover.dismiss() XCTAssertNil(binding.wrappedValue) + XCTAssertThrows(try sut.inspect().fullScreenCover(), "View for Sheet is absent") } func testMultipleFullScreenCoversInspection() throws { @@ -171,7 +173,7 @@ private extension View { @available(iOS 14.0, tvOS 14.0, watchOS 7.0, *) @available(macOS, unavailable) -private struct InspectableFullScreenCover: ViewModifier, SimplePopupPresenter +private struct InspectableFullScreenCover: ViewModifier, PopupPresenter where FullScreenCover: View { let isPresented: Binding diff --git a/Tests/ViewInspectorTests/SwiftUI/PopoverTests.swift b/Tests/ViewInspectorTests/SwiftUI/PopoverTests.swift index b8b33f5c..50252575 100644 --- a/Tests/ViewInspectorTests/SwiftUI/PopoverTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/PopoverTests.swift @@ -65,22 +65,24 @@ final class PopoverTests: XCTestCase { XCTAssertEqual(button.pathToRoot, "emptyView().popover().button(1)") } - func testOnDismiss() throws { + func testDismiss() throws { let binding = Binding(wrappedValue: true) let sut = EmptyView().popover2(isPresented: binding, content: { Text("") }) XCTAssertTrue(binding.wrappedValue) - try sut.inspect().popover().callOnDismiss() + try sut.inspect().popover().dismiss() XCTAssertFalse(binding.wrappedValue) + XCTAssertThrows(try sut.inspect().popover(), "View for Popover is absent") } - func testContentWithItemInspection() throws { + func testDismissForItemVersion() throws { let binding = Binding(wrappedValue: 6) let sut = EmptyView().popover2(item: binding) { Text("\($0)") } let popover = try sut.inspect().emptyView().popover() XCTAssertEqual(try popover.text().string(), "6") XCTAssertEqual(binding.wrappedValue, 6) - try popover.callOnDismiss() + try popover.dismiss() XCTAssertNil(binding.wrappedValue) + XCTAssertThrows(try sut.inspect().popover(), "View for Popover is absent") } func testMultiplePopoversInspection() throws { @@ -217,7 +219,7 @@ private extension View { } @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) -private struct InspectablePopover: ViewModifier, SimplePopupPresenter where Popover: View { +private struct InspectablePopover: ViewModifier, PopupPresenter where Popover: View { let isPresented: Binding let attachmentAnchor: PopoverAttachmentAnchor diff --git a/Tests/ViewInspectorTests/SwiftUI/SheetTests.swift b/Tests/ViewInspectorTests/SwiftUI/SheetTests.swift index 7e042e5a..fec5fee7 100644 --- a/Tests/ViewInspectorTests/SwiftUI/SheetTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/SheetTests.swift @@ -63,26 +63,28 @@ final class SheetTests: XCTestCase { XCTAssertEqual(button.pathToRoot, "emptyView().sheet().button(1)") } - func testOnDismiss() throws { + func testDismiss() throws { let exp = XCTestExpectation(description: #function) let binding = Binding(wrappedValue: true) let sut = EmptyView().sheet2(isPresented: binding, onDismiss: { exp.fulfill() }, content: { Text("") }) XCTAssertTrue(binding.wrappedValue) - try sut.inspect().sheet().callOnDismiss() + try sut.inspect().sheet().dismiss() XCTAssertFalse(binding.wrappedValue) + XCTAssertThrows(try sut.inspect().sheet(), "View for Sheet is absent") wait(for: [exp], timeout: 0.1) } - func testContentWithItemInspection() throws { + func testDismissForItemVersion() throws { let binding = Binding(wrappedValue: 6) let sut = EmptyView().sheet2(item: binding) { Text("\($0)") } let sheet = try sut.inspect().emptyView().sheet() XCTAssertEqual(try sheet.text().string(), "6") XCTAssertEqual(binding.wrappedValue, 6) - try sheet.callOnDismiss() + try sheet.dismiss() XCTAssertNil(binding.wrappedValue) + XCTAssertThrows(try sut.inspect().sheet(), "View for Sheet is absent") } func testMultipleSheetsInspection() throws { @@ -149,7 +151,7 @@ private extension View { } @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) -private struct InspectableSheet: ViewModifier, SimplePopupPresenter where Sheet: View { +private struct InspectableSheet: ViewModifier, PopupPresenter where Sheet: View { let isPresented: Binding let onDismiss: (() -> Void)? From c5e473bc0c05c24324e6505dcdf8dcf582ff4826 Mon Sep 17 00:00:00 2001 From: Alexey Naumov Date: Sat, 11 Sep 2021 11:21:38 +0300 Subject: [PATCH 51/99] Add SafeAreaInset support --- .../ViewInspector/SwiftUI/SafeAreaInset.swift | 87 +++++++++++++++++++ .../SwiftUI/SafeAreaInsetTests.swift | 77 ++++++++++++++++ ViewInspector.xcodeproj/project.pbxproj | 8 ++ 3 files changed, 172 insertions(+) create mode 100644 Sources/ViewInspector/SwiftUI/SafeAreaInset.swift create mode 100644 Tests/ViewInspectorTests/SwiftUI/SafeAreaInsetTests.swift diff --git a/Sources/ViewInspector/SwiftUI/SafeAreaInset.swift b/Sources/ViewInspector/SwiftUI/SafeAreaInset.swift new file mode 100644 index 00000000..1f700960 --- /dev/null +++ b/Sources/ViewInspector/SwiftUI/SafeAreaInset.swift @@ -0,0 +1,87 @@ +import SwiftUI + +// MARK: - Alert + +@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) +public extension ViewType { + + struct SafeAreaInset: KnownViewType { + public static var typePrefix: String = "_InsetViewModifier" + public static func inspectionCall(typeName: String) -> String { + return "safeAreaInset(\(ViewType.indexPlaceholder))" + } + } +} + +// MARK: - Extraction + +@available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) +public extension InspectableView { + + func safeAreaInset(_ index: Int? = nil) throws -> InspectableView { + return try contentForModifierLookup.safeAreaInset(parent: self, index: index) + } +} + +@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) +internal extension Content { + + func safeAreaInset(parent: UnwrappedView, index: Int?) throws -> InspectableView { + let modifier = try self.modifierAttribute( + modifierLookup: isSafeAreaInset(modifier:), path: "modifier", + type: Any.self, call: "safeAreaInset", index: index ?? 0) + let medium = self.medium.resettingViewModifiers() + let content = Content(modifier, medium: medium) + let call = ViewType.inspectionCall( + base: ViewType.SafeAreaInset.inspectionCall(typeName: ""), index: index) + return try .init(content, parent: parent, call: call, index: index) + } + + private func isSafeAreaInset(modifier: Any) -> Bool { + guard let modifier = modifier as? ModifierNameProvider + else { return false } + return modifier.modifierType.contains(ViewType.SafeAreaInset.typePrefix) + } +} + +// MARK: - Content Extraction + +@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) +extension ViewType.SafeAreaInset: SingleViewContent { + + public static func child(_ content: Content) throws -> Content { + let view = try Inspector.attribute(path: "content", value: content.view) + let medium = content.medium.resettingViewModifiers() + return try Inspector.unwrap(view: view, medium: medium) + } +} + +@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) +extension ViewType.SafeAreaInset: MultipleViewContent { + + public static func children(_ content: Content) throws -> LazyGroup { + let view = try Inspector.attribute(label: "content", value: content.view) + return try Inspector.viewsInContainer(view: view, medium: content.medium) + } +} + +// MARK: - Custom Attributes + +@available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) +public extension InspectableView where View == ViewType.SafeAreaInset { + + func regions() throws -> SafeAreaRegions { + return try Inspector.attribute( + path: "properties|regions", value: content.view, type: SafeAreaRegions.self) + } + + func spacing() throws -> CGFloat? { + return try Inspector.attribute( + path: "properties|spacing", value: content.view, type: CGFloat?.self) + } + + func edge() throws -> Edge { + return try Inspector.attribute( + path: "properties|edge", value: content.view, type: Edge.self) + } +} diff --git a/Tests/ViewInspectorTests/SwiftUI/SafeAreaInsetTests.swift b/Tests/ViewInspectorTests/SwiftUI/SafeAreaInsetTests.swift new file mode 100644 index 00000000..3eda832f --- /dev/null +++ b/Tests/ViewInspectorTests/SwiftUI/SafeAreaInsetTests.swift @@ -0,0 +1,77 @@ +import XCTest +import SwiftUI +@testable import ViewInspector + +@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) +final class SafeAreaInsetTests: XCTestCase { + + func testInspectionNotBlocked() throws { + guard #available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) + else { return } + let sut = EmptyView().safeAreaInset(edge: .bottom) { Text("") } + XCTAssertNoThrow(try sut.inspect().emptyView()) + } + + func testInspectionErrorNoModifier() throws { + guard #available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) + else { return } + let sut = EmptyView().offset() + XCTAssertThrows(try sut.inspect().emptyView().safeAreaInset(), + "EmptyView does not have 'safeAreaInset' modifier") + } + + func testSimpleUnwrap() throws { + guard #available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) + else { return } + let sut = EmptyView().safeAreaInset(edge: .bottom) { Text("") } + XCTAssertEqual(try sut.inspect().emptyView().safeAreaInset().pathToRoot, + "emptyView().safeAreaInset()") + } + + func testContentUnwrap() throws { + guard #available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) + else { return } + let sut = EmptyView().safeAreaInset(edge: .bottom) { Text("abc") } + let text = try sut.inspect().safeAreaInset().text() + XCTAssertEqual(try text.string(), "abc") + } + + func testEdge() throws { + guard #available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) + else { return } + let sut = EmptyView().safeAreaInset(edge: .bottom) { Text("") } + XCTAssertEqual(try sut.inspect().safeAreaInset().edge(), .bottom) + } + + func testSpacing() throws { + guard #available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) + else { return } + let sut1 = EmptyView().safeAreaInset(edge: .bottom, spacing: 19) { Text("") } + let sut2 = EmptyView().safeAreaInset(edge: .bottom) { Text("") } + XCTAssertEqual(try sut1.inspect().safeAreaInset().spacing(), 19) + XCTAssertNil(try sut2.inspect().safeAreaInset().spacing()) + } + + func testRegions() throws { + guard #available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) + else { return } + let sut = EmptyView().safeAreaInset(edge: .bottom) { Text("") } + XCTAssertEqual(try sut.inspect().safeAreaInset().regions(), .container) + } + + func testSearch() throws { + guard #available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) + else { return } + let sut = Group { + EmptyView() + Text("") + .safeAreaInset(edge: .top) { EmptyView(); Text("1") } + .padding() + .safeAreaInset(edge: .leading) { Text("2") } + } + XCTAssertEqual(try sut.inspect().find(text: "1").pathToRoot, + "group().text(1).safeAreaInset().text(1)") + XCTAssertEqual(try sut.inspect().find(text: "2").pathToRoot, + "group().text(1).safeAreaInset(1).text()") + } +} diff --git a/ViewInspector.xcodeproj/project.pbxproj b/ViewInspector.xcodeproj/project.pbxproj index 5da1626f..fb0264c4 100644 --- a/ViewInspector.xcodeproj/project.pbxproj +++ b/ViewInspector.xcodeproj/project.pbxproj @@ -44,6 +44,8 @@ 52A3B51C26591F79001FE17E /* SheetTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52A3B51B26591F79001FE17E /* SheetTests.swift */; }; 52A4A7642621F4AE0063E00B /* Overlay.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52A4A7632621F4AE0063E00B /* Overlay.swift */; }; 52A5CA0425E1139E00773CF5 /* EnvironmentModifiers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52A5CA0325E1139E00773CF5 /* EnvironmentModifiers.swift */; }; + 52B71AA626EB5BED00B719D4 /* SafeAreaInsetTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52B71AA526EB5BED00B719D4 /* SafeAreaInsetTests.swift */; }; + 52B71AAA26EB5C4500B719D4 /* SafeAreaInset.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52B71AA926EB5C4500B719D4 /* SafeAreaInset.swift */; }; 52D37480262B1F0C00B1BFBA /* NestedModifiersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52D3747F262B1F0C00B1BFBA /* NestedModifiersTests.swift */; }; 52E24E9926E9378A00711987 /* ConfirmationDialog.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52E24E9826E9378A00711987 /* ConfirmationDialog.swift */; }; 52E24E9B26E93A4700711987 /* ConfirmationDialogTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52E24E9A26E93A4700711987 /* ConfirmationDialogTests.swift */; }; @@ -294,6 +296,8 @@ 52A3B51B26591F79001FE17E /* SheetTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SheetTests.swift; sourceTree = ""; }; 52A4A7632621F4AE0063E00B /* Overlay.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Overlay.swift; sourceTree = ""; }; 52A5CA0325E1139E00773CF5 /* EnvironmentModifiers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EnvironmentModifiers.swift; sourceTree = ""; }; + 52B71AA526EB5BED00B719D4 /* SafeAreaInsetTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SafeAreaInsetTests.swift; sourceTree = ""; }; + 52B71AA926EB5C4500B719D4 /* SafeAreaInset.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SafeAreaInset.swift; sourceTree = ""; }; 52D3747F262B1F0C00B1BFBA /* NestedModifiersTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NestedModifiersTests.swift; sourceTree = ""; }; 52E24E9826E9378A00711987 /* ConfirmationDialog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfirmationDialog.swift; sourceTree = ""; }; 52E24E9A26E93A4700711987 /* ConfirmationDialogTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfirmationDialogTests.swift; sourceTree = ""; }; @@ -655,6 +659,7 @@ F6C15AA2254DA270000240F1 /* ProgressView.swift */, F6684BFD23AA863400DECCB3 /* RadialGradient.swift */, 52A4A7632621F4AE0063E00B /* Overlay.swift */, + 52B71AA926EB5C4500B719D4 /* SafeAreaInset.swift */, F60EEBC22382EED0007DB53A /* ScrollView.swift */, F6C15AB6254DB173000240F1 /* ScrollViewReader.swift */, F60EEBC42382EED0007DB53A /* Section.swift */, @@ -766,6 +771,7 @@ F6BD82092565AD5D00A772D4 /* PopoverTests.swift */, F6C15A98254D9F24000240F1 /* ProgressViewTests.swift */, F6684BFF23AA864F00DECCB3 /* RadialGradientTests.swift */, + 52B71AA526EB5BED00B719D4 /* SafeAreaInsetTests.swift */, F60EEBF42382F004007DB53A /* ScrollViewTests.swift */, F6C15AAC254DB0AA000240F1 /* ScrollViewReaderTests.swift */, F60EEBF22382F004007DB53A /* SectionTests.swift */, @@ -1051,6 +1057,7 @@ 52A5CA0425E1139E00773CF5 /* EnvironmentModifiers.swift in Sources */, F60EEBDC2382EED0007DB53A /* Text.swift in Sources */, D7A6CE8926E17AE900599824 /* FullScreenCover.swift in Sources */, + 52B71AAA26EB5C4500B719D4 /* SafeAreaInset.swift in Sources */, F620C7FB2537B090006D856D /* ConfigurationModifiers.swift in Sources */, F6684BFE23AA863400DECCB3 /* RadialGradient.swift in Sources */, 520E916226E69E540090BD1F /* PopupPresenter.swift in Sources */, @@ -1167,6 +1174,7 @@ F639DBC523A7DFA6003A6FED /* TouchBarTests.swift in Sources */, F67540EF23A3D8B30022AC33 /* PositioningModifiersTests.swift in Sources */, F6D933B52385ED2700358E0E /* VSplitViewTests.swift in Sources */, + 52B71AA626EB5BED00B719D4 /* SafeAreaInsetTests.swift in Sources */, F60EEC002382F004007DB53A /* ForEachTests.swift in Sources */, CDA844EC262B84FD00C56C98 /* SimultaneousGestureChildrenTests.swift in Sources */, F64A2C6423A3E74E00A4853A /* PresentationModifiersTests.swift in Sources */, From ba5b4712a52f54140b97e356ce20592b24372111 Mon Sep 17 00:00:00 2001 From: Alexey Naumov Date: Sat, 11 Sep 2021 11:22:14 +0300 Subject: [PATCH 52/99] Unify FullScreenCover and Sheet implementation --- Sources/ViewInspector/BaseTypes.swift | 8 +- Sources/ViewInspector/PopupPresenter.swift | 30 +++--- .../ViewInspector/SwiftUI/ActionSheet.swift | 4 +- Sources/ViewInspector/SwiftUI/Alert.swift | 4 +- .../SwiftUI/ConfirmationDialog.swift | 4 +- .../SwiftUI/FullScreenCover.swift | 92 +------------------ Sources/ViewInspector/SwiftUI/Popover.swift | 4 +- Sources/ViewInspector/SwiftUI/Sheet.swift | 20 +++- Sources/ViewInspector/ViewSearchIndex.swift | 18 ++-- .../SwiftUI/FullScreenCoverTests.swift | 12 +-- 10 files changed, 61 insertions(+), 135 deletions(-) diff --git a/Sources/ViewInspector/BaseTypes.swift b/Sources/ViewInspector/BaseTypes.swift index 18135a4f..2db51bb3 100644 --- a/Sources/ViewInspector/BaseTypes.swift +++ b/Sources/ViewInspector/BaseTypes.swift @@ -104,11 +104,17 @@ public extension KnownViewType { } static var isTransitive: Bool { false } static func inspectionCall(typeName: String) -> String { - let baseName = typePrefix.prefix(1).lowercased() + typePrefix.dropFirst() + let baseName = typePrefix.firstLetterLowercased return "\(baseName)(\(ViewType.indexPlaceholder))" } } +internal extension String { + var firstLetterLowercased: String { + prefix(1).lowercased() + dropFirst() + } +} + @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) public struct ViewType { } diff --git a/Sources/ViewInspector/PopupPresenter.swift b/Sources/ViewInspector/PopupPresenter.swift index b5fbb188..7f79e741 100644 --- a/Sources/ViewInspector/PopupPresenter.swift +++ b/Sources/ViewInspector/PopupPresenter.swift @@ -9,7 +9,6 @@ public protocol BasePopupPresenter { var isActionSheetPresenter: Bool { get } var isPopoverPresenter: Bool { get } var isSheetPresenter: Bool { get } - var isFullScreenCoverPresenter: Bool { get } } @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) @@ -36,7 +35,6 @@ extension BasePopupPresenter { func subject(_ type: T.Type) -> String { if isPopoverPresenter { return "Popover" } if isSheetPresenter { return "Sheet" } - if isFullScreenCoverPresenter { return "FullScreenCover" } return Inspector.typeName(type: T.self) } } @@ -115,9 +113,6 @@ public extension ViewModifier where Self: PopupPresenter { var isSheetPresenter: Bool { return (try? content().standardSheetModifier()) != nil } - var isFullScreenCoverPresenter: Bool { - return (try? content().standardFullScreenCoverModifier()) != nil - } } @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) @@ -128,9 +123,6 @@ public extension ViewModifier where Self: ItemPopupPresenter { var isSheetPresenter: Bool { return (try? content().standardSheetModifier()) != nil } - var isFullScreenCoverPresenter: Bool { - return (try? content().standardFullScreenCoverModifier()) != nil - } } // MARK: - Default @@ -141,7 +133,6 @@ public extension BasePopupPresenter { var isActionSheetPresenter: Bool { false } var isPopoverPresenter: Bool { false } var isSheetPresenter: Bool { false } - var isFullScreenCoverPresenter: Bool { false } } // MARK: - PopupContainer @@ -166,25 +157,36 @@ internal extension ViewType.PopupContainer { internal extension Content { func popup( parent: UnwrappedView, index: Int?, - modifierPredicate: ModifierLookupClosure, standardPredicate: () throws -> Any + name: String = Inspector.typeName(type: Popup.self), + modifierPredicate: ModifierLookupClosure, + standardPredicate: (String) throws -> Any ) throws -> InspectableView { guard let popupPresenter = try? self.modifierAttribute( modifierLookup: modifierPredicate, path: "modifier", type: BasePopupPresenter.self, call: "", index: index ?? 0) else { - _ = try standardPredicate() + _ = try standardPredicate(name) throw InspectionError.notSupported( """ - Please refer to the Guide for inspecting the \(Inspector.typeName(type: Popup.self)): \ + Please refer to the Guide for inspecting the \(name): \ https://github.com/nalexn/ViewInspector/blob/master/guide.md#alert-sheet-actionsheet-and-fullscreencover """) } - let popup = try popupPresenter.buildPopup() + let popup: Any = try { + do { + return try popupPresenter.buildPopup() + } catch { + if case InspectionError.viewNotFound = error { + throw InspectionError.viewNotFound(parent: name) + } + throw error + } + }() let container = ViewType.PopupContainer(popup: popup, presenter: popupPresenter) let medium = self.medium.resettingViewModifiers() let content = Content(container, medium: medium) let call = ViewType.inspectionCall( - base: Popup.inspectionCall(typeName: ""), index: index) + base: Popup.inspectionCall(typeName: name), index: index) return try .init(content, parent: parent, call: call, index: index) } } diff --git a/Sources/ViewInspector/SwiftUI/ActionSheet.swift b/Sources/ViewInspector/SwiftUI/ActionSheet.swift index c6f0ec67..9ff0bafc 100644 --- a/Sources/ViewInspector/SwiftUI/ActionSheet.swift +++ b/Sources/ViewInspector/SwiftUI/ActionSheet.swift @@ -35,11 +35,11 @@ internal extension Content { standardPredicate: standardActionSheetModifier) } - func standardActionSheetModifier() throws -> Any { + func standardActionSheetModifier(_ name: String = "ActionSheet") throws -> Any { return try self.modifier({ $0.modifierType == "IdentifiedPreferenceTransformModifier" || $0.modifierType.contains("AlertTransformModifier") - }, call: "actionSheet") + }, call: name.firstLetterLowercased) } func actionSheetsForSearch() -> [ViewSearch.ModifierIdentity] { diff --git a/Sources/ViewInspector/SwiftUI/Alert.swift b/Sources/ViewInspector/SwiftUI/Alert.swift index 40dcc717..b2c36bff 100644 --- a/Sources/ViewInspector/SwiftUI/Alert.swift +++ b/Sources/ViewInspector/SwiftUI/Alert.swift @@ -33,11 +33,11 @@ internal extension Content { standardPredicate: standardAlertModifier) } - func standardAlertModifier() throws -> Any { + func standardAlertModifier(_ name: String = "Alert") throws -> Any { return try self.modifier({ $0.modifierType == "IdentifiedPreferenceTransformModifier" || $0.modifierType.contains("AlertTransformModifier") - }, call: "alert") + }, call: name.firstLetterLowercased) } func alertsForSearch() -> [ViewSearch.ModifierIdentity] { diff --git a/Sources/ViewInspector/SwiftUI/ConfirmationDialog.swift b/Sources/ViewInspector/SwiftUI/ConfirmationDialog.swift index 69407a44..71b6e2cd 100644 --- a/Sources/ViewInspector/SwiftUI/ConfirmationDialog.swift +++ b/Sources/ViewInspector/SwiftUI/ConfirmationDialog.swift @@ -45,7 +45,7 @@ internal extension Content { private func isConfirmationDialog(modifier: Any) -> Bool { guard let modifier = modifier as? ModifierNameProvider else { return false } - return modifier.modifierType.contains("ConfirmationDialogModifier") + return modifier.modifierType.contains(ViewType.ConfirmationDialog.typePrefix) } } @@ -77,6 +77,8 @@ extension ViewType.ConfirmationDialog: SupplementaryChildren { } } +// MARK: - Custom Attributes + @available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) public extension InspectableView where View == ViewType.ConfirmationDialog { diff --git a/Sources/ViewInspector/SwiftUI/FullScreenCover.swift b/Sources/ViewInspector/SwiftUI/FullScreenCover.swift index 22296d92..15456d2b 100644 --- a/Sources/ViewInspector/SwiftUI/FullScreenCover.swift +++ b/Sources/ViewInspector/SwiftUI/FullScreenCover.swift @@ -1,93 +1,3 @@ import SwiftUI -@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) -public extension ViewType { - - struct FullScreenCover: KnownViewType { - public static var typePrefix: String = ViewType.PopupContainer.typePrefix - public static var namespacedPrefixes: [String] { [typePrefix] } - public static func inspectionCall(typeName: String) -> String { - return "fullScreenCover(\(ViewType.indexPlaceholder))" - } - } -} - -// MARK: - Content Extraction - -@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) -extension ViewType.FullScreenCover: SingleViewContent { - - public static func child(_ content: Content) throws -> Content { - let view = try Inspector.attribute(label: "popup", value: content.view) - let medium = content.medium.resettingViewModifiers() - return try Inspector.unwrap(view: view, medium: medium) - } -} - -@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) -extension ViewType.FullScreenCover: MultipleViewContent { - - public static func children(_ content: Content) throws -> LazyGroup { - let view = try Inspector.attribute(label: "popup", value: content.view) - let medium = content.medium.resettingViewModifiers() - return try Inspector.viewsInContainer(view: view, medium: medium) - } -} - -// MARK: - Extraction - -@available(iOS 14.0, tvOS 14.0, watchOS 7.0, *) -@available(macOS, unavailable) -public extension InspectableView { - - func fullScreenCover(_ index: Int? = nil) throws -> InspectableView { - return try contentForModifierLookup.fullScreenCover(parent: self, index: index) - } -} - -@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) -internal extension Content { - - func fullScreenCover(parent: UnwrappedView, index: Int?) throws -> InspectableView { - return try popup(parent: parent, index: index, - modifierPredicate: isFullScreenCoverBuilder(modifier:), - standardPredicate: standardFullScreenCoverModifier) - } - - func standardFullScreenCoverModifier() throws -> Any { - return try self.modifier({ - $0.modifierType == "IdentifiedPreferenceTransformModifier" - || $0.modifierType.contains("SheetPresentationModifier") - }, call: "fullScreenCover") - } - - func fullScreenCoversForSearch() -> [ViewSearch.ModifierIdentity] { - let count = medium.viewModifiers - .filter(isFullScreenCoverBuilder(modifier:)) - .count - return Array(0.. Bool { - let modifier = try? Inspector.attribute( - label: "modifier", value: modifier, type: BasePopupPresenter.self) - return modifier?.isFullScreenCoverPresenter == true - } -} - -// MARK: - Custom Attributes - -@available(iOS 14.0, tvOS 14.0, watchOS 7.0, *) -@available(macOS, unavailable) -public extension InspectableView where View == ViewType.FullScreenCover { - - func dismiss() throws { - let container = try Inspector.cast( - value: content.view, type: ViewType.PopupContainer.self) - container.presenter.dismissPopup() - } -} +// !!! diff --git a/Sources/ViewInspector/SwiftUI/Popover.swift b/Sources/ViewInspector/SwiftUI/Popover.swift index c1a6727a..9729899a 100644 --- a/Sources/ViewInspector/SwiftUI/Popover.swift +++ b/Sources/ViewInspector/SwiftUI/Popover.swift @@ -55,10 +55,10 @@ internal extension Content { standardPredicate: standardPopoverModifier) } - func standardPopoverModifier() throws -> Any { + func standardPopoverModifier(_ name: String = "Popover") throws -> Any { return try modifierAttribute( modifierName: "PopoverPresentationModifier", path: "modifier", - type: Any.self, call: "popover") + type: Any.self, call: name.firstLetterLowercased) } func popoversForSearch() -> [ViewSearch.ModifierIdentity] { diff --git a/Sources/ViewInspector/SwiftUI/Sheet.swift b/Sources/ViewInspector/SwiftUI/Sheet.swift index f91b9907..5119d4ca 100644 --- a/Sources/ViewInspector/SwiftUI/Sheet.swift +++ b/Sources/ViewInspector/SwiftUI/Sheet.swift @@ -9,9 +9,10 @@ public extension ViewType { public static var typePrefix: String = ViewType.PopupContainer.typePrefix public static var namespacedPrefixes: [String] { [typePrefix] } public static func inspectionCall(typeName: String) -> String { - return "sheet(\(ViewType.indexPlaceholder))" + return "\(typeName.firstLetterLowercased)(\(ViewType.indexPlaceholder))" } } + typealias FullScreenCover = Sheet } // MARK: - Content Extraction @@ -46,20 +47,29 @@ public extension InspectableView { } } +@available(iOS 14.0, tvOS 14.0, watchOS 7.0, *) +@available(macOS, unavailable) +public extension InspectableView { + + func fullScreenCover(_ index: Int? = nil) throws -> InspectableView { + return try contentForModifierLookup.sheet(parent: self, index: index, name: "FullScreenCover") + } +} + @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) internal extension Content { - func sheet(parent: UnwrappedView, index: Int?) throws -> InspectableView { - return try popup(parent: parent, index: index, + func sheet(parent: UnwrappedView, index: Int?, name: String = "Sheet") throws -> InspectableView { + return try popup(parent: parent, index: index, name: name, modifierPredicate: isSheetBuilder(modifier:), standardPredicate: standardSheetModifier) } - func standardSheetModifier() throws -> Any { + func standardSheetModifier(_ name: String = "Sheet") throws -> Any { return try self.modifier({ $0.modifierType == "IdentifiedPreferenceTransformModifier" || $0.modifierType.contains("SheetPresentationModifier") - }, call: "sheet") + }, call: name.firstLetterLowercased) } func sheetsForSearch() -> [ViewSearch.ModifierIdentity] { diff --git a/Sources/ViewInspector/ViewSearchIndex.swift b/Sources/ViewInspector/ViewSearchIndex.swift index fd483f82..9c2c0c43 100644 --- a/Sources/ViewInspector/ViewSearchIndex.swift +++ b/Sources/ViewInspector/ViewSearchIndex.swift @@ -16,7 +16,6 @@ internal extension ViewSearch { .init(ViewType.Divider.self), .init(ViewType.EditButton.self), .init(ViewType.EmptyView.self), .init(ViewType.ForEach.self), .init(ViewType.Form.self), - .init(ViewType.FullScreenCover.self, genericTypeName: nil), .init(ViewType.GeometryReader.self), .init(ViewType.Group.self), .init(ViewType.GroupBox.self), .init(ViewType.HSplitView.self), .init(ViewType.HStack.self), @@ -34,9 +33,10 @@ internal extension ViewSearch { .init(ViewType.Popover.self, genericTypeName: nil), .init(ViewType.ProgressView.self), .init(ViewType.RadialGradient.self), + .init(ViewType.SafeAreaInset.self, genericTypeName: nil), .init(ViewType.ScrollView.self), .init(ViewType.ScrollViewReader.self), .init(ViewType.Section.self), .init(ViewType.SecureField.self), - .init(ViewType.Sheet.self, genericTypeName: nil), + .init(ViewType.Sheet.self, genericTypeName: "Sheet"), .init(ViewType.Slider.self), .init(ViewType.Spacer.self), .init(ViewType.Stepper.self), .init(ViewType.StyleConfiguration.Label.self), .init(ViewType.StyleConfiguration.Content.self), .init(ViewType.StyleConfiguration.Title.self), .init(ViewType.StyleConfiguration.Icon.self), @@ -255,6 +255,9 @@ internal extension ViewSearch { .init(name: ViewType.ConfirmationDialog.typePrefix, builder: { parent, index in try parent.content.confirmationDialog(parent: parent, index: index) }), + .init(name: ViewType.SafeAreaInset.typePrefix, builder: { parent, index in + try parent.content.safeAreaInset(parent: parent, index: index) + }), .init(name: "PopoverPresentationModifier", builder: { parent, index in try parent.content.popover(parent: parent, index: index) }), @@ -330,34 +333,27 @@ internal extension Content { private func sheetModifierDescendants(parent: UnwrappedView) -> LazyGroup { let sheetModifiers = sheetsForSearch() + let alertModifiers = alertsForSearch() #if os(macOS) let actionSheetModifiers: [ViewSearch.ModifierIdentity] = [] - let fullScreenCoverModifiers: [ViewSearch.ModifierIdentity] = [] #else let actionSheetModifiers = actionSheetsForSearch() - let fullScreenCoverModifiers = fullScreenCoversForSearch() #endif #if os(iOS) || os(macOS) let popoverModifiers = popoversForSearch() #else let popoverModifiers: [ViewSearch.ModifierIdentity] = [] #endif - let alertModifiers = alertsForSearch() - let group1: LazyGroup = + return .init(count: sheetModifiers.count, { index -> UnwrappedView in try sheetModifiers[index].builder(parent, index) }) + .init(count: actionSheetModifiers.count, { index -> UnwrappedView in try actionSheetModifiers[index].builder(parent, index) }) + .init(count: alertModifiers.count, { index -> UnwrappedView in try alertModifiers[index].builder(parent, index) - }) - let group2: LazyGroup = - .init(count: fullScreenCoverModifiers.count, { index -> UnwrappedView in - try fullScreenCoverModifiers[index].builder(parent, index) }) + .init(count: popoverModifiers.count, { index -> UnwrappedView in try popoverModifiers[index].builder(parent, index) }) - return group1 + group2 } } diff --git a/Tests/ViewInspectorTests/SwiftUI/FullScreenCoverTests.swift b/Tests/ViewInspectorTests/SwiftUI/FullScreenCoverTests.swift index 88695fce..ac331d16 100644 --- a/Tests/ViewInspectorTests/SwiftUI/FullScreenCoverTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/FullScreenCoverTests.swift @@ -80,7 +80,7 @@ final class FullScreenCoverTests: XCTestCase { XCTAssertTrue(binding.wrappedValue) try sut.inspect().fullScreenCover().dismiss() XCTAssertFalse(binding.wrappedValue) - XCTAssertThrows(try sut.inspect().fullScreenCover(), "View for Sheet is absent") + XCTAssertThrows(try sut.inspect().fullScreenCover(), "View for FullScreenCover is absent") wait(for: [exp], timeout: 0.1) } @@ -93,7 +93,7 @@ final class FullScreenCoverTests: XCTestCase { XCTAssertEqual(binding.wrappedValue, 6) try fullScreenCover.dismiss() XCTAssertNil(binding.wrappedValue) - XCTAssertThrows(try sut.inspect().fullScreenCover(), "View for Sheet is absent") + XCTAssertThrows(try sut.inspect().fullScreenCover(), "View for FullScreenCover is absent") } func testMultipleFullScreenCoversInspection() throws { @@ -128,11 +128,11 @@ final class FullScreenCoverTests: XCTestCase { // 1 XCTAssertEqual(try sut.inspect().find(text: "title_1").pathToRoot, - "view(FullScreenCoverFindTestView.self).hStack().emptyView(0).fullScreenCover().text(0)") + "view(FullScreenCoverFindTestView.self).hStack().emptyView(0).sheet().text(0)") XCTAssertEqual(try sut.inspect().find(text: "button_1").pathToRoot, """ view(FullScreenCoverFindTestView.self).hStack().emptyView(0)\ - .fullScreenCover().button(1).labelView().text() + .sheet().button(1).labelView().text() """) // 2 XCTAssertThrows(try sut.inspect().find(text: "title_2").pathToRoot, @@ -140,14 +140,14 @@ final class FullScreenCoverTests: XCTestCase { // 3 XCTAssertEqual(try sut.inspect().find(text: "title_3").pathToRoot, - "view(FullScreenCoverFindTestView.self).hStack().emptyView(0).fullScreenCover(1).text(0)") + "view(FullScreenCoverFindTestView.self).hStack().emptyView(0).sheet(1).text(0)") XCTAssertThrows(try sut.inspect().find(text: "message_3").pathToRoot, "Search did not find a match") XCTAssertEqual(try sut.inspect().find(text: "button_3").pathToRoot, """ view(FullScreenCoverFindTestView.self).hStack().emptyView(0)\ - .fullScreenCover(1).button(1).labelView().text() + .sheet(1).button(1).labelView().text() """) } } From edad6e5554e4c1d5725752be2bea478fc3d181ca Mon Sep 17 00:00:00 2001 From: Alexey Naumov Date: Sat, 11 Sep 2021 11:45:02 +0300 Subject: [PATCH 53/99] Fix tests compilation for watchOS --- .../ViewInspector/Modifiers/TextInputModifiers.swift | 3 ++- Tests/ViewInspectorTests/SwiftUI/TabViewTests.swift | 6 ++---- Tests/ViewInspectorTests/SwiftUI/ToolbarTests.swift | 12 ++++++------ .../ViewModifiers/TextInputModifiersTests.swift | 4 ++-- 4 files changed, 12 insertions(+), 13 deletions(-) diff --git a/Sources/ViewInspector/Modifiers/TextInputModifiers.swift b/Sources/ViewInspector/Modifiers/TextInputModifiers.swift index 638170b2..cd4ffb8e 100644 --- a/Sources/ViewInspector/Modifiers/TextInputModifiers.swift +++ b/Sources/ViewInspector/Modifiers/TextInputModifiers.swift @@ -104,7 +104,7 @@ public extension InspectableView { return false } - @available(watchOS, unavailable) + #if !os(watchOS) func disableAutocorrection() -> Bool { let reference = EmptyView().disableAutocorrection(false) if let keyPath = try? Inspector.environmentKeyPath(Optional.self, reference), @@ -113,6 +113,7 @@ public extension InspectableView { } return false } + #endif func flipsForRightToLeftLayoutDirection() -> Bool { return modifiersMatching({ $0.modifierType == "_FlipForRTLEffect" }, diff --git a/Tests/ViewInspectorTests/SwiftUI/TabViewTests.swift b/Tests/ViewInspectorTests/SwiftUI/TabViewTests.swift index c11549ba..ed1cdd79 100644 --- a/Tests/ViewInspectorTests/SwiftUI/TabViewTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/TabViewTests.swift @@ -93,7 +93,7 @@ final class GlobalModifiersForTabView: XCTestCase { XCTAssertNoThrow(try view.inspect().find(text: "abc")) } - #if !os(macOS) && !targetEnvironment(macCatalyst) && !os(watchOS) + #if os(iOS) || os(tvOS) func testTabViewStyleInspection() throws { guard #available(iOS 14, macOS 11.0, tvOS 14.0, *) else { return } let style = PageTabViewStyle(indexDisplayMode: .never) @@ -112,13 +112,11 @@ final class GlobalModifiersForTabView: XCTestCase { XCTAssertNotEqual(styles[index], styles[(index + 1) % styles.count]) } } - #endif - @available(macOS, unavailable) - @available(watchOS, unavailable) func testIndexViewStyleInspection() throws { guard #available(iOS 14, tvOS 14, *) else { return } let sut = EmptyView().indexViewStyle(PageIndexViewStyle()) XCTAssertTrue(try sut.inspect().indexViewStyle() is PageIndexViewStyle) } + #endif } diff --git a/Tests/ViewInspectorTests/SwiftUI/ToolbarTests.swift b/Tests/ViewInspectorTests/SwiftUI/ToolbarTests.swift index 06373948..054f8788 100644 --- a/Tests/ViewInspectorTests/SwiftUI/ToolbarTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/ToolbarTests.swift @@ -15,8 +15,8 @@ final class ToolbarTests: XCTestCase { .primaryAction, .cancellationAction, .confirmationAction, .destructiveAction] #else let values: [ToolbarItemPlacement] = [ - .automatic, .principal, .navigation, - .primaryAction, .cancellationAction, .confirmationAction, .destructiveAction] + .automatic, .primaryAction, .cancellationAction, + .confirmationAction, .destructiveAction] #endif values.enumerated().forEach { lhs in values.enumerated().forEach { rhs in @@ -131,12 +131,12 @@ final class ToolbarTests: XCTestCase { else { return } let sut = EmptyView().toolbar { ToolbarItem(placement: .destructiveAction) { EmptyView() } - ToolbarItem(placement: .principal) { EmptyView() } + ToolbarItem(placement: .primaryAction) { EmptyView() } ToolbarItem { EmptyView() } } let toolbar = try sut.inspect().toolbar() XCTAssertEqual(try toolbar.item(0).placement(), .destructiveAction) - XCTAssertEqual(try toolbar.item(1).placement(), .principal) + XCTAssertEqual(try toolbar.item(1).placement(), .primaryAction) XCTAssertEqual(try toolbar.item(2).placement(), .automatic) } @@ -145,12 +145,12 @@ final class ToolbarTests: XCTestCase { else { return } let sut = EmptyView().toolbar { ToolbarItemGroup(placement: .destructiveAction) { EmptyView() } - ToolbarItemGroup(placement: .principal) { EmptyView() } + ToolbarItemGroup(placement: .primaryAction) { EmptyView() } ToolbarItemGroup { EmptyView() } } let toolbar = try sut.inspect().toolbar() XCTAssertEqual(try toolbar.itemGroup(0).placement(), .destructiveAction) - XCTAssertEqual(try toolbar.itemGroup(1).placement(), .principal) + XCTAssertEqual(try toolbar.itemGroup(1).placement(), .primaryAction) XCTAssertEqual(try toolbar.itemGroup(2).placement(), .automatic) } diff --git a/Tests/ViewInspectorTests/ViewModifiers/TextInputModifiersTests.swift b/Tests/ViewInspectorTests/ViewModifiers/TextInputModifiersTests.swift index 2fc2374a..93763377 100644 --- a/Tests/ViewInspectorTests/ViewModifiers/TextInputModifiersTests.swift +++ b/Tests/ViewInspectorTests/ViewModifiers/TextInputModifiersTests.swift @@ -145,18 +145,18 @@ final class TextInputModifiersTests: XCTestCase { XCTAssertTrue(try sut.inspect().anyView().emptyView().allowsTightening()) } - @available(watchOS, unavailable) + #if !os(watchOS) func testDisableAutocorrection() throws { let sut = EmptyView().disableAutocorrection(false) XCTAssertNoThrow(try sut.inspect().emptyView()) } - @available(watchOS, unavailable) func testDisableAutocorrectionInspection() throws { let sut = AnyView(EmptyView()).disableAutocorrection(false) XCTAssertEqual(try sut.inspect().anyView().disableAutocorrection(), false) XCTAssertEqual(try sut.inspect().anyView().emptyView().disableAutocorrection(), false) } + #endif func testFlipsForRightToLeftLayoutDirection() throws { let sut = EmptyView().flipsForRightToLeftLayoutDirection(true) From 95757d03469594c42a7f1834ba8658b38587f5c6 Mon Sep 17 00:00:00 2001 From: Alexey Naumov Date: Sat, 11 Sep 2021 12:27:41 +0300 Subject: [PATCH 54/99] Remove workspace --- .../project.xcworkspace/contents.xcworkspacedata | 7 ------- .../xcshareddata/xcschemes/watchOS-App.xcscheme | 10 ---------- .watchOS/watchOS.xcworkspace/contents.xcworkspacedata | 10 ---------- .../xcshareddata/IDEWorkspaceChecks.plist | 8 -------- 4 files changed, 35 deletions(-) delete mode 100644 .watchOS/watchOS.xcodeproj/project.xcworkspace/contents.xcworkspacedata delete mode 100644 .watchOS/watchOS.xcworkspace/contents.xcworkspacedata delete mode 100644 .watchOS/watchOS.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/.watchOS/watchOS.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/.watchOS/watchOS.xcodeproj/project.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 919434a6..00000000 --- a/.watchOS/watchOS.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/.watchOS/watchOS.xcodeproj/xcshareddata/xcschemes/watchOS-App.xcscheme b/.watchOS/watchOS.xcodeproj/xcshareddata/xcschemes/watchOS-App.xcscheme index bf748de3..c9e3745d 100644 --- a/.watchOS/watchOS.xcodeproj/xcshareddata/xcschemes/watchOS-App.xcscheme +++ b/.watchOS/watchOS.xcodeproj/xcshareddata/xcschemes/watchOS-App.xcscheme @@ -28,16 +28,6 @@ selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" shouldUseLaunchSchemeArgsEnv = "YES"> - - - - - - - - - - diff --git a/.watchOS/watchOS.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/.watchOS/watchOS.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d98100..00000000 --- a/.watchOS/watchOS.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - From 1e25802e091bb54f8de5e54a73a88b8fd6fe0ecb Mon Sep 17 00:00:00 2001 From: Alexey Naumov Date: Sat, 11 Sep 2021 13:06:17 +0300 Subject: [PATCH 55/99] Add test target --- .watchOS/watchOS-Tests/watchOS_Tests.swift | 13 ++ .watchOS/watchOS.xcodeproj/project.pbxproj | 131 +++++++++++++++++- .../xcschemes/watchOS-App.xcscheme | 35 ++++- 3 files changed, 172 insertions(+), 7 deletions(-) create mode 100644 .watchOS/watchOS-Tests/watchOS_Tests.swift diff --git a/.watchOS/watchOS-Tests/watchOS_Tests.swift b/.watchOS/watchOS-Tests/watchOS_Tests.swift new file mode 100644 index 00000000..b91e9f92 --- /dev/null +++ b/.watchOS/watchOS-Tests/watchOS_Tests.swift @@ -0,0 +1,13 @@ +import XCTest +import SwiftUI +import WatchKit +@testable import watchOS_Ext + +class watchOS_Tests: XCTestCase { + + func testExample() throws { + let ext = WKExtension.shared() + let ic = ext.rootInterfaceController + print(">>> \(ext) \(ic)") + } +} diff --git a/.watchOS/watchOS.xcodeproj/project.pbxproj b/.watchOS/watchOS.xcodeproj/project.pbxproj index e90c646d..43a96593 100644 --- a/.watchOS/watchOS.xcodeproj/project.pbxproj +++ b/.watchOS/watchOS.xcodeproj/project.pbxproj @@ -7,11 +7,19 @@ objects = { /* Begin PBXBuildFile section */ + 520213A726ECB45D00E94C6E /* watchOS_Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520213A626ECB45D00E94C6E /* watchOS_Tests.swift */; }; 52E3259B26C72E7900CCE47E /* watchOS-Ext.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 52E3259A26C72E7900CCE47E /* watchOS-Ext.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 52E325A226C72E7900CCE47E /* watchOSApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52E325A126C72E7900CCE47E /* watchOSApp.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ + 520213A826ECB45D00E94C6E /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 52E3258426C72E7800CCE47E /* Project object */; + proxyType = 1; + remoteGlobalIDString = 52E3259926C72E7900CCE47E; + remoteInfo = "watchOS-Ext"; + }; 52E3259C26C72E7900CCE47E /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 52E3258426C72E7800CCE47E /* Project object */; @@ -36,6 +44,8 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 520213A426ECB45D00E94C6E /* watchOS-Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "watchOS-Tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; + 520213A626ECB45D00E94C6E /* watchOS_Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = watchOS_Tests.swift; sourceTree = ""; }; 52E3258E26C72E7800CCE47E /* watchOS-App.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "watchOS-App.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 52E3259526C72E7900CCE47E /* App-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "App-Info.plist"; sourceTree = ""; }; 52E3259A26C72E7900CCE47E /* watchOS-Ext.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = "watchOS-Ext.appex"; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -44,6 +54,13 @@ /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ + 520213A126ECB45D00E94C6E /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; 52E3259726C72E7900CCE47E /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -54,11 +71,20 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 520213A526ECB45D00E94C6E /* watchOS-Tests */ = { + isa = PBXGroup; + children = ( + 520213A626ECB45D00E94C6E /* watchOS_Tests.swift */, + ); + path = "watchOS-Tests"; + sourceTree = ""; + }; 52E3258326C72E7800CCE47E = { isa = PBXGroup; children = ( 52E3259226C72E7800CCE47E /* watchOS-App */, 52E3259E26C72E7900CCE47E /* watchOS-Ext */, + 520213A526ECB45D00E94C6E /* watchOS-Tests */, 52E3258B26C72E7800CCE47E /* Products */, ); sourceTree = ""; @@ -68,6 +94,7 @@ children = ( 52E3258E26C72E7800CCE47E /* watchOS-App.app */, 52E3259A26C72E7900CCE47E /* watchOS-Ext.appex */, + 520213A426ECB45D00E94C6E /* watchOS-Tests.xctest */, ); name = Products; sourceTree = ""; @@ -92,6 +119,24 @@ /* End PBXGroup section */ /* Begin PBXNativeTarget section */ + 520213A326ECB45D00E94C6E /* watchOS-Tests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 520213AC26ECB45D00E94C6E /* Build configuration list for PBXNativeTarget "watchOS-Tests" */; + buildPhases = ( + 520213A026ECB45D00E94C6E /* Sources */, + 520213A126ECB45D00E94C6E /* Frameworks */, + 520213A226ECB45D00E94C6E /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 520213A926ECB45D00E94C6E /* PBXTargetDependency */, + ); + name = "watchOS-Tests"; + productName = "watchOS-Tests"; + productReference = 520213A426ECB45D00E94C6E /* watchOS-Tests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; 52E3258D26C72E7800CCE47E /* watchOS-App */ = { isa = PBXNativeTarget; buildConfigurationList = 52E325B126C72E7900CCE47E /* Build configuration list for PBXNativeTarget "watchOS-App" */; @@ -132,9 +177,13 @@ 52E3258426C72E7800CCE47E /* Project object */ = { isa = PBXProject; attributes = { - LastSwiftUpdateCheck = 1250; + LastSwiftUpdateCheck = 1300; LastUpgradeCheck = 1250; TargetAttributes = { + 520213A326ECB45D00E94C6E = { + CreatedOnToolsVersion = 13.0; + TestTargetID = 52E3259926C72E7900CCE47E; + }; 52E3258D26C72E7800CCE47E = { CreatedOnToolsVersion = 12.5.1; }; @@ -158,11 +207,19 @@ targets = ( 52E3258D26C72E7800CCE47E /* watchOS-App */, 52E3259926C72E7900CCE47E /* watchOS-Ext */, + 520213A326ECB45D00E94C6E /* watchOS-Tests */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ + 520213A226ECB45D00E94C6E /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; 52E3258C26C72E7800CCE47E /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -180,6 +237,14 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ + 520213A026ECB45D00E94C6E /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 520213A726ECB45D00E94C6E /* watchOS_Tests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 52E3259626C72E7900CCE47E /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -191,6 +256,11 @@ /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ + 520213A926ECB45D00E94C6E /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 52E3259926C72E7900CCE47E /* watchOS-Ext */; + targetProxy = 520213A826ECB45D00E94C6E /* PBXContainerItemProxy */; + }; 52E3259D26C72E7900CCE47E /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 52E3259926C72E7900CCE47E /* watchOS-Ext */; @@ -199,6 +269,56 @@ /* End PBXTargetDependency section */ /* Begin XCBuildConfiguration section */ + 520213AA26ECB45D00E94C6E /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = "com.viewinspector.watchOS-Tests"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = watchos; + SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = 4; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/watchOS-Ext.appex/watchOS-Ext"; + WATCHOS_DEPLOYMENT_TARGET = 8.0; + }; + name = Debug; + }; + 520213AB26ECB45D00E94C6E /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = "com.viewinspector.watchOS-Tests"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = watchos; + SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = 4; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/watchOS-Ext.appex/watchOS-Ext"; + WATCHOS_DEPLOYMENT_TARGET = 8.0; + }; + name = Release; + }; 52E325AB26C72E7900CCE47E /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -396,6 +516,15 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ + 520213AC26ECB45D00E94C6E /* Build configuration list for PBXNativeTarget "watchOS-Tests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 520213AA26ECB45D00E94C6E /* Debug */, + 520213AB26ECB45D00E94C6E /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; 52E3258726C72E7800CCE47E /* Build configuration list for PBXProject "watchOS" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/.watchOS/watchOS.xcodeproj/xcshareddata/xcschemes/watchOS-App.xcscheme b/.watchOS/watchOS.xcodeproj/xcshareddata/xcschemes/watchOS-App.xcscheme index c9e3745d..66f9d572 100644 --- a/.watchOS/watchOS.xcodeproj/xcshareddata/xcschemes/watchOS-App.xcscheme +++ b/.watchOS/watchOS.xcodeproj/xcshareddata/xcschemes/watchOS-App.xcscheme @@ -9,9 +9,9 @@ + buildForProfiling = "NO" + buildForArchiving = "NO" + buildForAnalyzing = "NO"> + + + + + + + + - + - + From b4242e4ef4c5000eee3e593291b0c26123c4106a Mon Sep 17 00:00:00 2001 From: Alexey Naumov Date: Sat, 11 Sep 2021 14:10:27 +0300 Subject: [PATCH 56/99] Add framework as package dependency, and tests as source files --- .watchOS/watchOS-Tests/watchOS_Tests.swift | 13 - .watchOS/watchOS.xcodeproj/project.pbxproj | 598 ++++++++++++++++++++- 2 files changed, 593 insertions(+), 18 deletions(-) delete mode 100644 .watchOS/watchOS-Tests/watchOS_Tests.swift diff --git a/.watchOS/watchOS-Tests/watchOS_Tests.swift b/.watchOS/watchOS-Tests/watchOS_Tests.swift deleted file mode 100644 index b91e9f92..00000000 --- a/.watchOS/watchOS-Tests/watchOS_Tests.swift +++ /dev/null @@ -1,13 +0,0 @@ -import XCTest -import SwiftUI -import WatchKit -@testable import watchOS_Ext - -class watchOS_Tests: XCTestCase { - - func testExample() throws { - let ext = WKExtension.shared() - let ic = ext.rootInterfaceController - print(">>> \(ext) \(ic)") - } -} diff --git a/.watchOS/watchOS.xcodeproj/project.pbxproj b/.watchOS/watchOS.xcodeproj/project.pbxproj index 43a96593..91498973 100644 --- a/.watchOS/watchOS.xcodeproj/project.pbxproj +++ b/.watchOS/watchOS.xcodeproj/project.pbxproj @@ -3,11 +3,135 @@ archiveVersion = 1; classes = { }; - objectVersion = 50; + objectVersion = 52; objects = { /* Begin PBXBuildFile section */ - 520213A726ECB45D00E94C6E /* watchOS_Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520213A626ECB45D00E94C6E /* watchOS_Tests.swift */; }; + 52CA2F9626ECC58B00BFD568 /* LazyGroupTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F1226ECC58B00BFD568 /* LazyGroupTests.swift */; }; + 52CA2F9726ECC58B00BFD568 /* ViewHostingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F1326ECC58B00BFD568 /* ViewHostingTests.swift */; }; + 52CA2F9826ECC58B00BFD568 /* InspectionEmissaryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F1426ECC58B00BFD568 /* InspectionEmissaryTests.swift */; }; + 52CA2F9926ECC58B00BFD568 /* BaseTypesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F1526ECC58B00BFD568 /* BaseTypesTests.swift */; }; + 52CA2F9A26ECC58B00BFD568 /* ViewSearchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F1626ECC58B00BFD568 /* ViewSearchTests.swift */; }; + 52CA2F9B26ECC58B00BFD568 /* HitTestingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F1926ECC58B00BFD568 /* HitTestingTests.swift */; }; + 52CA2F9C26ECC58B00BFD568 /* GestureModifierTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F1A26ECC58B00BFD568 /* GestureModifierTests.swift */; }; + 52CA2F9D26ECC58B00BFD568 /* GestureActionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F1B26ECC58B00BFD568 /* GestureActionTests.swift */; }; + 52CA2F9E26ECC58B00BFD568 /* HighPriorityGestureModifierTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F1C26ECC58B00BFD568 /* HighPriorityGestureModifierTests.swift */; }; + 52CA2F9F26ECC58B00BFD568 /* SimultaneousGestureModifierTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F1D26ECC58B00BFD568 /* SimultaneousGestureModifierTests.swift */; }; + 52CA2FA026ECC58B00BFD568 /* ComposedGestureExampleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F1E26ECC58B00BFD568 /* ComposedGestureExampleTests.swift */; }; + 52CA2FA126ECC58B00BFD568 /* SequenceGestureChildrenTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F1F26ECC58B00BFD568 /* SequenceGestureChildrenTests.swift */; }; + 52CA2FA226ECC58B00BFD568 /* RotationGestureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F2026ECC58B00BFD568 /* RotationGestureTests.swift */; }; + 52CA2FA326ECC58B00BFD568 /* ExclusiveGestureChildrenTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F2126ECC58B00BFD568 /* ExclusiveGestureChildrenTests.swift */; }; + 52CA2FA426ECC58B00BFD568 /* TapGestureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F2226ECC58B00BFD568 /* TapGestureTests.swift */; }; + 52CA2FA526ECC58B00BFD568 /* ExclusiveGestureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F2326ECC58B00BFD568 /* ExclusiveGestureTests.swift */; }; + 52CA2FA626ECC58B00BFD568 /* SimultaneousGestureChildrenTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F2426ECC58B00BFD568 /* SimultaneousGestureChildrenTests.swift */; }; + 52CA2FA726ECC58B00BFD568 /* SequenceGestureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F2526ECC58B00BFD568 /* SequenceGestureTests.swift */; }; + 52CA2FA826ECC58B00BFD568 /* GestureExampleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F2626ECC58B00BFD568 /* GestureExampleTests.swift */; }; + 52CA2FA926ECC58B00BFD568 /* DragGestureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F2726ECC58B00BFD568 /* DragGestureTests.swift */; }; + 52CA2FAA26ECC58B00BFD568 /* CommonComposedGestureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F2826ECC58B00BFD568 /* CommonComposedGestureTests.swift */; }; + 52CA2FAB26ECC58B00BFD568 /* CommonComposedGestureUpdatingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F2926ECC58B00BFD568 /* CommonComposedGestureUpdatingTests.swift */; }; + 52CA2FAC26ECC58B00BFD568 /* SimultaneousGestureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F2A26ECC58B00BFD568 /* SimultaneousGestureTests.swift */; }; + 52CA2FAD26ECC58B00BFD568 /* CommonComposedGestureEndedTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F2B26ECC58B00BFD568 /* CommonComposedGestureEndedTests.swift */; }; + 52CA2FAE26ECC58B00BFD568 /* CommonComposedGestureChangedTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F2C26ECC58B00BFD568 /* CommonComposedGestureChangedTests.swift */; }; + 52CA2FAF26ECC58B00BFD568 /* LongPressGestureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F2D26ECC58B00BFD568 /* LongPressGestureTests.swift */; }; + 52CA2FB026ECC58B00BFD568 /* CommonGestureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F2E26ECC58B00BFD568 /* CommonGestureTests.swift */; }; + 52CA2FB126ECC58B00BFD568 /* MagnificationGestureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F2F26ECC58B00BFD568 /* MagnificationGestureTests.swift */; }; + 52CA2FB226ECC58B00BFD568 /* Test.strings in Resources */ = {isa = PBXBuildFile; fileRef = 52CA2F3126ECC58B00BFD568 /* Test.strings */; }; + 52CA2FB326ECC58B00BFD568 /* InspectableViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F3526ECC58B00BFD568 /* InspectableViewTests.swift */; }; + 52CA2FB426ECC58B00BFD568 /* InspectorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F3626ECC58B00BFD568 /* InspectorTests.swift */; }; + 52CA2FB526ECC58B00BFD568 /* ZStackTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F3826ECC58B00BFD568 /* ZStackTests.swift */; }; + 52CA2FB626ECC58B00BFD568 /* OptionalViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F3926ECC58B00BFD568 /* OptionalViewTests.swift */; }; + 52CA2FB726ECC58B00BFD568 /* MenuButtonTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F3A26ECC58B00BFD568 /* MenuButtonTests.swift */; }; + 52CA2FB826ECC58B00BFD568 /* TouchBarTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F3B26ECC58B00BFD568 /* TouchBarTests.swift */; }; + 52CA2FB926ECC58B00BFD568 /* GroupBoxTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F3C26ECC58B00BFD568 /* GroupBoxTests.swift */; }; + 52CA2FBA26ECC58B00BFD568 /* SheetTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F3D26ECC58B00BFD568 /* SheetTests.swift */; }; + 52CA2FBB26ECC58B00BFD568 /* RadialGradientTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F3E26ECC58B00BFD568 /* RadialGradientTests.swift */; }; + 52CA2FBC26ECC58B00BFD568 /* ScrollViewReaderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F3F26ECC58B00BFD568 /* ScrollViewReaderTests.swift */; }; + 52CA2FBD26ECC58B00BFD568 /* MapTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F4026ECC58B00BFD568 /* MapTests.swift */; }; + 52CA2FBE26ECC58B00BFD568 /* SubscriptionViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F4126ECC58B00BFD568 /* SubscriptionViewTests.swift */; }; + 52CA2FBF26ECC58B00BFD568 /* MenuTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F4226ECC58B00BFD568 /* MenuTests.swift */; }; + 52CA2FC026ECC58B00BFD568 /* LabelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F4326ECC58B00BFD568 /* LabelTests.swift */; }; + 52CA2FC126ECC58B00BFD568 /* TextTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F4426ECC58B00BFD568 /* TextTests.swift */; }; + 52CA2FC226ECC58B00BFD568 /* OpaqueViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F4526ECC58B00BFD568 /* OpaqueViewTests.swift */; }; + 52CA2FC326ECC58B00BFD568 /* HStackTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F4626ECC58B00BFD568 /* HStackTests.swift */; }; + 52CA2FC426ECC58B00BFD568 /* TreeViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F4726ECC58B00BFD568 /* TreeViewTests.swift */; }; + 52CA2FC526ECC58B00BFD568 /* EquatableViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F4826ECC58B00BFD568 /* EquatableViewTests.swift */; }; + 52CA2FC626ECC58B00BFD568 /* LinearGradientTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F4926ECC58B00BFD568 /* LinearGradientTests.swift */; }; + 52CA2FC726ECC58B00BFD568 /* ToolbarTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F4A26ECC58B00BFD568 /* ToolbarTests.swift */; }; + 52CA2FC826ECC58B00BFD568 /* DisclosureGroupTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F4B26ECC58B00BFD568 /* DisclosureGroupTests.swift */; }; + 52CA2FC926ECC58B00BFD568 /* GeometryReaderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F4C26ECC58B00BFD568 /* GeometryReaderTests.swift */; }; + 52CA2FCA26ECC58B00BFD568 /* ProgressViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F4D26ECC58B00BFD568 /* ProgressViewTests.swift */; }; + 52CA2FCB26ECC58B00BFD568 /* EnvironmentObjectInjectionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F4E26ECC58B00BFD568 /* EnvironmentObjectInjectionTests.swift */; }; + 52CA2FCC26ECC58B00BFD568 /* TabViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F4F26ECC58B00BFD568 /* TabViewTests.swift */; }; + 52CA2FCD26ECC58B00BFD568 /* PopoverTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F5026ECC58B00BFD568 /* PopoverTests.swift */; }; + 52CA2FCE26ECC58B00BFD568 /* EmptyViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F5126ECC58B00BFD568 /* EmptyViewTests.swift */; }; + 52CA2FCF26ECC58B00BFD568 /* CustomViewModifierTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F5226ECC58B00BFD568 /* CustomViewModifierTests.swift */; }; + 52CA2FD026ECC58B00BFD568 /* ImageTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F5326ECC58B00BFD568 /* ImageTests.swift */; }; + 52CA2FD126ECC58B00BFD568 /* EnvironmentReaderViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F5426ECC58B00BFD568 /* EnvironmentReaderViewTests.swift */; }; + 52CA2FD226ECC58B00BFD568 /* StepperTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F5526ECC58B00BFD568 /* StepperTests.swift */; }; + 52CA2FD326ECC58B00BFD568 /* FormTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F5626ECC58B00BFD568 /* FormTests.swift */; }; + 52CA2FD426ECC58B00BFD568 /* TupleViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F5726ECC58B00BFD568 /* TupleViewTests.swift */; }; + 52CA2FD526ECC58B00BFD568 /* ConfirmationDialogTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F5826ECC58B00BFD568 /* ConfirmationDialogTests.swift */; }; + 52CA2FD626ECC58B00BFD568 /* LazyVGridTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F5926ECC58B00BFD568 /* LazyVGridTests.swift */; }; + 52CA2FD726ECC58B00BFD568 /* LazyHStackTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F5A26ECC58B00BFD568 /* LazyHStackTests.swift */; }; + 52CA2FD826ECC58B00BFD568 /* AlertTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F5B26ECC58B00BFD568 /* AlertTests.swift */; }; + 52CA2FD926ECC58B00BFD568 /* TextAttributesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F5C26ECC58B00BFD568 /* TextAttributesTests.swift */; }; + 52CA2FDA26ECC58B00BFD568 /* PasteButtonTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F5D26ECC58B00BFD568 /* PasteButtonTests.swift */; }; + 52CA2FDB26ECC58B00BFD568 /* DividerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F5E26ECC58B00BFD568 /* DividerTests.swift */; }; + 52CA2FDC26ECC58B00BFD568 /* ForEachTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F5F26ECC58B00BFD568 /* ForEachTests.swift */; }; + 52CA2FDD26ECC58B00BFD568 /* ActionSheetTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F6026ECC58B00BFD568 /* ActionSheetTests.swift */; }; + 52CA2FDE26ECC58B00BFD568 /* DelayedPreferenceViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F6126ECC58B00BFD568 /* DelayedPreferenceViewTests.swift */; }; + 52CA2FDF26ECC58B00BFD568 /* ButtonTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F6226ECC58B00BFD568 /* ButtonTests.swift */; }; + 52CA2FE026ECC58B00BFD568 /* LinkTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F6326ECC58B00BFD568 /* LinkTests.swift */; }; + 52CA2FE126ECC58B00BFD568 /* SliderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F6426ECC58B00BFD568 /* SliderTests.swift */; }; + 52CA2FE226ECC58B00BFD568 /* CustomViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F6526ECC58B00BFD568 /* CustomViewTests.swift */; }; + 52CA2FE326ECC58B00BFD568 /* ColorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F6626ECC58B00BFD568 /* ColorTests.swift */; }; + 52CA2FE426ECC58B00BFD568 /* TextEditorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F6726ECC58B00BFD568 /* TextEditorTests.swift */; }; + 52CA2FE526ECC58B00BFD568 /* MapAnnotationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F6826ECC58B00BFD568 /* MapAnnotationTests.swift */; }; + 52CA2FE626ECC58B00BFD568 /* AngularGradientTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F6926ECC58B00BFD568 /* AngularGradientTests.swift */; }; + 52CA2FE726ECC58B00BFD568 /* ConditionalContentTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F6A26ECC58B00BFD568 /* ConditionalContentTests.swift */; }; + 52CA2FE826ECC58B00BFD568 /* VSplitViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F6B26ECC58B00BFD568 /* VSplitViewTests.swift */; }; + 52CA2FE926ECC58B00BFD568 /* NavigationViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F6C26ECC58B00BFD568 /* NavigationViewTests.swift */; }; + 52CA2FEA26ECC58B00BFD568 /* EditButtonTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F6D26ECC58B00BFD568 /* EditButtonTests.swift */; }; + 52CA2FEB26ECC58B00BFD568 /* IDViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F6E26ECC58B00BFD568 /* IDViewTests.swift */; }; + 52CA2FEC26ECC58B00BFD568 /* CustomViewBuilderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F6F26ECC58B00BFD568 /* CustomViewBuilderTests.swift */; }; + 52CA2FED26ECC58B00BFD568 /* TextFieldTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F7026ECC58B00BFD568 /* TextFieldTests.swift */; }; + 52CA2FEE26ECC58B00BFD568 /* FullScreenCoverTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F7126ECC58B00BFD568 /* FullScreenCoverTests.swift */; }; + 52CA2FEF26ECC58B00BFD568 /* NavigationLinkTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F7226ECC58B00BFD568 /* NavigationLinkTests.swift */; }; + 52CA2FF026ECC58B00BFD568 /* VStackTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F7326ECC58B00BFD568 /* VStackTests.swift */; }; + 52CA2FF126ECC58B00BFD568 /* PickerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F7426ECC58B00BFD568 /* PickerTests.swift */; }; + 52CA2FF226ECC58B00BFD568 /* GroupTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F7526ECC58B00BFD568 /* GroupTests.swift */; }; + 52CA2FF326ECC58B00BFD568 /* SectionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F7626ECC58B00BFD568 /* SectionTests.swift */; }; + 52CA2FF426ECC58B00BFD568 /* ToggleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F7726ECC58B00BFD568 /* ToggleTests.swift */; }; + 52CA2FF526ECC58B00BFD568 /* SpacerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F7826ECC58B00BFD568 /* SpacerTests.swift */; }; + 52CA2FF626ECC58B00BFD568 /* DatePickerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F7926ECC58B00BFD568 /* DatePickerTests.swift */; }; + 52CA2FF726ECC58B00BFD568 /* SafeAreaInsetTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F7A26ECC58B00BFD568 /* SafeAreaInsetTests.swift */; }; + 52CA2FF826ECC58B00BFD568 /* ColorPickerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F7B26ECC58B00BFD568 /* ColorPickerTests.swift */; }; + 52CA2FF926ECC58B00BFD568 /* OutlineGroupTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F7C26ECC58B00BFD568 /* OutlineGroupTests.swift */; }; + 52CA2FFA26ECC58B00BFD568 /* ScrollViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F7D26ECC58B00BFD568 /* ScrollViewTests.swift */; }; + 52CA2FFB26ECC58B00BFD568 /* SecureFieldTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F7E26ECC58B00BFD568 /* SecureFieldTests.swift */; }; + 52CA2FFC26ECC58B00BFD568 /* LazyHGridTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F7F26ECC58B00BFD568 /* LazyHGridTests.swift */; }; + 52CA2FFD26ECC58B00BFD568 /* ShapeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F8026ECC58B00BFD568 /* ShapeTests.swift */; }; + 52CA2FFE26ECC58B00BFD568 /* ListTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F8126ECC58B00BFD568 /* ListTests.swift */; }; + 52CA2FFF26ECC58B00BFD568 /* HSplitViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F8226ECC58B00BFD568 /* HSplitViewTests.swift */; }; + 52CA300026ECC58B00BFD568 /* AnyViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F8326ECC58B00BFD568 /* AnyViewTests.swift */; }; + 52CA300126ECC58B00BFD568 /* LazyVStackTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F8426ECC58B00BFD568 /* LazyVStackTests.swift */; }; + 52CA300226ECC58B00BFD568 /* ConfigurationModifiersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F8626ECC58B00BFD568 /* ConfigurationModifiersTests.swift */; }; + 52CA300326ECC58B00BFD568 /* PresentationModifiersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F8726ECC58B00BFD568 /* PresentationModifiersTests.swift */; }; + 52CA300426ECC58B00BFD568 /* InteractionModifiersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F8826ECC58B00BFD568 /* InteractionModifiersTests.swift */; }; + 52CA300526ECC58B00BFD568 /* EventsModifiersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F8926ECC58B00BFD568 /* EventsModifiersTests.swift */; }; + 52CA300626ECC58B00BFD568 /* SizingModifiersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F8A26ECC58B00BFD568 /* SizingModifiersTests.swift */; }; + 52CA300726ECC58B00BFD568 /* NestedModifiersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F8B26ECC58B00BFD568 /* NestedModifiersTests.swift */; }; + 52CA300826ECC58B00BFD568 /* PositioningModifiersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F8C26ECC58B00BFD568 /* PositioningModifiersTests.swift */; }; + 52CA300926ECC58B00BFD568 /* TextInputModifiersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F8D26ECC58B00BFD568 /* TextInputModifiersTests.swift */; }; + 52CA300A26ECC58B00BFD568 /* CustomStyleModifiersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F8E26ECC58B00BFD568 /* CustomStyleModifiersTests.swift */; }; + 52CA300B26ECC58B00BFD568 /* TransitiveModifiersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F8F26ECC58B00BFD568 /* TransitiveModifiersTests.swift */; }; + 52CA300C26ECC58B00BFD568 /* AccessibilityModifiersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F9026ECC58B00BFD568 /* AccessibilityModifiersTests.swift */; }; + 52CA300D26ECC58B00BFD568 /* AnimationModifiersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F9126ECC58B00BFD568 /* AnimationModifiersTests.swift */; }; + 52CA300E26ECC58B00BFD568 /* VisualEffectModifiersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F9226ECC58B00BFD568 /* VisualEffectModifiersTests.swift */; }; + 52CA300F26ECC58B00BFD568 /* EnvironmentModifiersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F9326ECC58B00BFD568 /* EnvironmentModifiersTests.swift */; }; + 52CA301026ECC58B00BFD568 /* ViewPaddingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F9426ECC58B00BFD568 /* ViewPaddingTests.swift */; }; + 52CA301126ECC58B00BFD568 /* TransformingModifiersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F9526ECC58B00BFD568 /* TransformingModifiersTests.swift */; }; + 52CA301426ECC5D200BFD568 /* ViewInspector in Frameworks */ = {isa = PBXBuildFile; productRef = 52CA301326ECC5D200BFD568 /* ViewInspector */; }; 52E3259B26C72E7900CCE47E /* watchOS-Ext.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 52E3259A26C72E7900CCE47E /* watchOS-Ext.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 52E325A226C72E7900CCE47E /* watchOSApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52E325A126C72E7900CCE47E /* watchOSApp.swift */; }; /* End PBXBuildFile section */ @@ -45,7 +169,133 @@ /* Begin PBXFileReference section */ 520213A426ECB45D00E94C6E /* watchOS-Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "watchOS-Tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; - 520213A626ECB45D00E94C6E /* watchOS_Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = watchOS_Tests.swift; sourceTree = ""; }; + 52CA2F1026ECC56600BFD568 /* ViewInspector */ = {isa = PBXFileReference; lastKnownFileType = folder; name = ViewInspector; path = ..; sourceTree = ""; }; + 52CA2F1226ECC58B00BFD568 /* LazyGroupTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LazyGroupTests.swift; sourceTree = ""; }; + 52CA2F1326ECC58B00BFD568 /* ViewHostingTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewHostingTests.swift; sourceTree = ""; }; + 52CA2F1426ECC58B00BFD568 /* InspectionEmissaryTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InspectionEmissaryTests.swift; sourceTree = ""; }; + 52CA2F1526ECC58B00BFD568 /* BaseTypesTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BaseTypesTests.swift; sourceTree = ""; }; + 52CA2F1626ECC58B00BFD568 /* ViewSearchTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewSearchTests.swift; sourceTree = ""; }; + 52CA2F1926ECC58B00BFD568 /* HitTestingTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HitTestingTests.swift; sourceTree = ""; }; + 52CA2F1A26ECC58B00BFD568 /* GestureModifierTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GestureModifierTests.swift; sourceTree = ""; }; + 52CA2F1B26ECC58B00BFD568 /* GestureActionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GestureActionTests.swift; sourceTree = ""; }; + 52CA2F1C26ECC58B00BFD568 /* HighPriorityGestureModifierTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HighPriorityGestureModifierTests.swift; sourceTree = ""; }; + 52CA2F1D26ECC58B00BFD568 /* SimultaneousGestureModifierTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SimultaneousGestureModifierTests.swift; sourceTree = ""; }; + 52CA2F1E26ECC58B00BFD568 /* ComposedGestureExampleTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ComposedGestureExampleTests.swift; sourceTree = ""; }; + 52CA2F1F26ECC58B00BFD568 /* SequenceGestureChildrenTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SequenceGestureChildrenTests.swift; sourceTree = ""; }; + 52CA2F2026ECC58B00BFD568 /* RotationGestureTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RotationGestureTests.swift; sourceTree = ""; }; + 52CA2F2126ECC58B00BFD568 /* ExclusiveGestureChildrenTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExclusiveGestureChildrenTests.swift; sourceTree = ""; }; + 52CA2F2226ECC58B00BFD568 /* TapGestureTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TapGestureTests.swift; sourceTree = ""; }; + 52CA2F2326ECC58B00BFD568 /* ExclusiveGestureTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExclusiveGestureTests.swift; sourceTree = ""; }; + 52CA2F2426ECC58B00BFD568 /* SimultaneousGestureChildrenTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SimultaneousGestureChildrenTests.swift; sourceTree = ""; }; + 52CA2F2526ECC58B00BFD568 /* SequenceGestureTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SequenceGestureTests.swift; sourceTree = ""; }; + 52CA2F2626ECC58B00BFD568 /* GestureExampleTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GestureExampleTests.swift; sourceTree = ""; }; + 52CA2F2726ECC58B00BFD568 /* DragGestureTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DragGestureTests.swift; sourceTree = ""; }; + 52CA2F2826ECC58B00BFD568 /* CommonComposedGestureTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CommonComposedGestureTests.swift; sourceTree = ""; }; + 52CA2F2926ECC58B00BFD568 /* CommonComposedGestureUpdatingTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CommonComposedGestureUpdatingTests.swift; sourceTree = ""; }; + 52CA2F2A26ECC58B00BFD568 /* SimultaneousGestureTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SimultaneousGestureTests.swift; sourceTree = ""; }; + 52CA2F2B26ECC58B00BFD568 /* CommonComposedGestureEndedTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CommonComposedGestureEndedTests.swift; sourceTree = ""; }; + 52CA2F2C26ECC58B00BFD568 /* CommonComposedGestureChangedTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CommonComposedGestureChangedTests.swift; sourceTree = ""; }; + 52CA2F2D26ECC58B00BFD568 /* LongPressGestureTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LongPressGestureTests.swift; sourceTree = ""; }; + 52CA2F2E26ECC58B00BFD568 /* CommonGestureTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CommonGestureTests.swift; sourceTree = ""; }; + 52CA2F2F26ECC58B00BFD568 /* MagnificationGestureTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MagnificationGestureTests.swift; sourceTree = ""; }; + 52CA2F3226ECC58B00BFD568 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Test.strings; sourceTree = ""; }; + 52CA2F3326ECC58B00BFD568 /* en-AU */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "en-AU"; path = "en-AU.lproj/Test.strings"; sourceTree = ""; }; + 52CA2F3426ECC58B00BFD568 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Test.strings; sourceTree = ""; }; + 52CA2F3526ECC58B00BFD568 /* InspectableViewTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InspectableViewTests.swift; sourceTree = ""; }; + 52CA2F3626ECC58B00BFD568 /* InspectorTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InspectorTests.swift; sourceTree = ""; }; + 52CA2F3826ECC58B00BFD568 /* ZStackTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ZStackTests.swift; sourceTree = ""; }; + 52CA2F3926ECC58B00BFD568 /* OptionalViewTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OptionalViewTests.swift; sourceTree = ""; }; + 52CA2F3A26ECC58B00BFD568 /* MenuButtonTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MenuButtonTests.swift; sourceTree = ""; }; + 52CA2F3B26ECC58B00BFD568 /* TouchBarTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TouchBarTests.swift; sourceTree = ""; }; + 52CA2F3C26ECC58B00BFD568 /* GroupBoxTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GroupBoxTests.swift; sourceTree = ""; }; + 52CA2F3D26ECC58B00BFD568 /* SheetTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SheetTests.swift; sourceTree = ""; }; + 52CA2F3E26ECC58B00BFD568 /* RadialGradientTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RadialGradientTests.swift; sourceTree = ""; }; + 52CA2F3F26ECC58B00BFD568 /* ScrollViewReaderTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScrollViewReaderTests.swift; sourceTree = ""; }; + 52CA2F4026ECC58B00BFD568 /* MapTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MapTests.swift; sourceTree = ""; }; + 52CA2F4126ECC58B00BFD568 /* SubscriptionViewTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SubscriptionViewTests.swift; sourceTree = ""; }; + 52CA2F4226ECC58B00BFD568 /* MenuTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MenuTests.swift; sourceTree = ""; }; + 52CA2F4326ECC58B00BFD568 /* LabelTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LabelTests.swift; sourceTree = ""; }; + 52CA2F4426ECC58B00BFD568 /* TextTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextTests.swift; sourceTree = ""; }; + 52CA2F4526ECC58B00BFD568 /* OpaqueViewTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OpaqueViewTests.swift; sourceTree = ""; }; + 52CA2F4626ECC58B00BFD568 /* HStackTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HStackTests.swift; sourceTree = ""; }; + 52CA2F4726ECC58B00BFD568 /* TreeViewTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TreeViewTests.swift; sourceTree = ""; }; + 52CA2F4826ECC58B00BFD568 /* EquatableViewTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EquatableViewTests.swift; sourceTree = ""; }; + 52CA2F4926ECC58B00BFD568 /* LinearGradientTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LinearGradientTests.swift; sourceTree = ""; }; + 52CA2F4A26ECC58B00BFD568 /* ToolbarTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ToolbarTests.swift; sourceTree = ""; }; + 52CA2F4B26ECC58B00BFD568 /* DisclosureGroupTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DisclosureGroupTests.swift; sourceTree = ""; }; + 52CA2F4C26ECC58B00BFD568 /* GeometryReaderTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeometryReaderTests.swift; sourceTree = ""; }; + 52CA2F4D26ECC58B00BFD568 /* ProgressViewTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProgressViewTests.swift; sourceTree = ""; }; + 52CA2F4E26ECC58B00BFD568 /* EnvironmentObjectInjectionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EnvironmentObjectInjectionTests.swift; sourceTree = ""; }; + 52CA2F4F26ECC58B00BFD568 /* TabViewTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TabViewTests.swift; sourceTree = ""; }; + 52CA2F5026ECC58B00BFD568 /* PopoverTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PopoverTests.swift; sourceTree = ""; }; + 52CA2F5126ECC58B00BFD568 /* EmptyViewTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EmptyViewTests.swift; sourceTree = ""; }; + 52CA2F5226ECC58B00BFD568 /* CustomViewModifierTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomViewModifierTests.swift; sourceTree = ""; }; + 52CA2F5326ECC58B00BFD568 /* ImageTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageTests.swift; sourceTree = ""; }; + 52CA2F5426ECC58B00BFD568 /* EnvironmentReaderViewTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EnvironmentReaderViewTests.swift; sourceTree = ""; }; + 52CA2F5526ECC58B00BFD568 /* StepperTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StepperTests.swift; sourceTree = ""; }; + 52CA2F5626ECC58B00BFD568 /* FormTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FormTests.swift; sourceTree = ""; }; + 52CA2F5726ECC58B00BFD568 /* TupleViewTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TupleViewTests.swift; sourceTree = ""; }; + 52CA2F5826ECC58B00BFD568 /* ConfirmationDialogTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConfirmationDialogTests.swift; sourceTree = ""; }; + 52CA2F5926ECC58B00BFD568 /* LazyVGridTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LazyVGridTests.swift; sourceTree = ""; }; + 52CA2F5A26ECC58B00BFD568 /* LazyHStackTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LazyHStackTests.swift; sourceTree = ""; }; + 52CA2F5B26ECC58B00BFD568 /* AlertTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AlertTests.swift; sourceTree = ""; }; + 52CA2F5C26ECC58B00BFD568 /* TextAttributesTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextAttributesTests.swift; sourceTree = ""; }; + 52CA2F5D26ECC58B00BFD568 /* PasteButtonTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PasteButtonTests.swift; sourceTree = ""; }; + 52CA2F5E26ECC58B00BFD568 /* DividerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DividerTests.swift; sourceTree = ""; }; + 52CA2F5F26ECC58B00BFD568 /* ForEachTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ForEachTests.swift; sourceTree = ""; }; + 52CA2F6026ECC58B00BFD568 /* ActionSheetTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActionSheetTests.swift; sourceTree = ""; }; + 52CA2F6126ECC58B00BFD568 /* DelayedPreferenceViewTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DelayedPreferenceViewTests.swift; sourceTree = ""; }; + 52CA2F6226ECC58B00BFD568 /* ButtonTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ButtonTests.swift; sourceTree = ""; }; + 52CA2F6326ECC58B00BFD568 /* LinkTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LinkTests.swift; sourceTree = ""; }; + 52CA2F6426ECC58B00BFD568 /* SliderTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SliderTests.swift; sourceTree = ""; }; + 52CA2F6526ECC58B00BFD568 /* CustomViewTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomViewTests.swift; sourceTree = ""; }; + 52CA2F6626ECC58B00BFD568 /* ColorTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ColorTests.swift; sourceTree = ""; }; + 52CA2F6726ECC58B00BFD568 /* TextEditorTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextEditorTests.swift; sourceTree = ""; }; + 52CA2F6826ECC58B00BFD568 /* MapAnnotationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MapAnnotationTests.swift; sourceTree = ""; }; + 52CA2F6926ECC58B00BFD568 /* AngularGradientTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AngularGradientTests.swift; sourceTree = ""; }; + 52CA2F6A26ECC58B00BFD568 /* ConditionalContentTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConditionalContentTests.swift; sourceTree = ""; }; + 52CA2F6B26ECC58B00BFD568 /* VSplitViewTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VSplitViewTests.swift; sourceTree = ""; }; + 52CA2F6C26ECC58B00BFD568 /* NavigationViewTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NavigationViewTests.swift; sourceTree = ""; }; + 52CA2F6D26ECC58B00BFD568 /* EditButtonTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EditButtonTests.swift; sourceTree = ""; }; + 52CA2F6E26ECC58B00BFD568 /* IDViewTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IDViewTests.swift; sourceTree = ""; }; + 52CA2F6F26ECC58B00BFD568 /* CustomViewBuilderTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomViewBuilderTests.swift; sourceTree = ""; }; + 52CA2F7026ECC58B00BFD568 /* TextFieldTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextFieldTests.swift; sourceTree = ""; }; + 52CA2F7126ECC58B00BFD568 /* FullScreenCoverTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FullScreenCoverTests.swift; sourceTree = ""; }; + 52CA2F7226ECC58B00BFD568 /* NavigationLinkTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NavigationLinkTests.swift; sourceTree = ""; }; + 52CA2F7326ECC58B00BFD568 /* VStackTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VStackTests.swift; sourceTree = ""; }; + 52CA2F7426ECC58B00BFD568 /* PickerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PickerTests.swift; sourceTree = ""; }; + 52CA2F7526ECC58B00BFD568 /* GroupTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GroupTests.swift; sourceTree = ""; }; + 52CA2F7626ECC58B00BFD568 /* SectionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SectionTests.swift; sourceTree = ""; }; + 52CA2F7726ECC58B00BFD568 /* ToggleTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ToggleTests.swift; sourceTree = ""; }; + 52CA2F7826ECC58B00BFD568 /* SpacerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SpacerTests.swift; sourceTree = ""; }; + 52CA2F7926ECC58B00BFD568 /* DatePickerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DatePickerTests.swift; sourceTree = ""; }; + 52CA2F7A26ECC58B00BFD568 /* SafeAreaInsetTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SafeAreaInsetTests.swift; sourceTree = ""; }; + 52CA2F7B26ECC58B00BFD568 /* ColorPickerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ColorPickerTests.swift; sourceTree = ""; }; + 52CA2F7C26ECC58B00BFD568 /* OutlineGroupTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OutlineGroupTests.swift; sourceTree = ""; }; + 52CA2F7D26ECC58B00BFD568 /* ScrollViewTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScrollViewTests.swift; sourceTree = ""; }; + 52CA2F7E26ECC58B00BFD568 /* SecureFieldTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SecureFieldTests.swift; sourceTree = ""; }; + 52CA2F7F26ECC58B00BFD568 /* LazyHGridTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LazyHGridTests.swift; sourceTree = ""; }; + 52CA2F8026ECC58B00BFD568 /* ShapeTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ShapeTests.swift; sourceTree = ""; }; + 52CA2F8126ECC58B00BFD568 /* ListTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ListTests.swift; sourceTree = ""; }; + 52CA2F8226ECC58B00BFD568 /* HSplitViewTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HSplitViewTests.swift; sourceTree = ""; }; + 52CA2F8326ECC58B00BFD568 /* AnyViewTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnyViewTests.swift; sourceTree = ""; }; + 52CA2F8426ECC58B00BFD568 /* LazyVStackTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LazyVStackTests.swift; sourceTree = ""; }; + 52CA2F8626ECC58B00BFD568 /* ConfigurationModifiersTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConfigurationModifiersTests.swift; sourceTree = ""; }; + 52CA2F8726ECC58B00BFD568 /* PresentationModifiersTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PresentationModifiersTests.swift; sourceTree = ""; }; + 52CA2F8826ECC58B00BFD568 /* InteractionModifiersTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InteractionModifiersTests.swift; sourceTree = ""; }; + 52CA2F8926ECC58B00BFD568 /* EventsModifiersTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EventsModifiersTests.swift; sourceTree = ""; }; + 52CA2F8A26ECC58B00BFD568 /* SizingModifiersTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SizingModifiersTests.swift; sourceTree = ""; }; + 52CA2F8B26ECC58B00BFD568 /* NestedModifiersTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NestedModifiersTests.swift; sourceTree = ""; }; + 52CA2F8C26ECC58B00BFD568 /* PositioningModifiersTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PositioningModifiersTests.swift; sourceTree = ""; }; + 52CA2F8D26ECC58B00BFD568 /* TextInputModifiersTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextInputModifiersTests.swift; sourceTree = ""; }; + 52CA2F8E26ECC58B00BFD568 /* CustomStyleModifiersTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomStyleModifiersTests.swift; sourceTree = ""; }; + 52CA2F8F26ECC58B00BFD568 /* TransitiveModifiersTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TransitiveModifiersTests.swift; sourceTree = ""; }; + 52CA2F9026ECC58B00BFD568 /* AccessibilityModifiersTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AccessibilityModifiersTests.swift; sourceTree = ""; }; + 52CA2F9126ECC58B00BFD568 /* AnimationModifiersTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnimationModifiersTests.swift; sourceTree = ""; }; + 52CA2F9226ECC58B00BFD568 /* VisualEffectModifiersTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VisualEffectModifiersTests.swift; sourceTree = ""; }; + 52CA2F9326ECC58B00BFD568 /* EnvironmentModifiersTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EnvironmentModifiersTests.swift; sourceTree = ""; }; + 52CA2F9426ECC58B00BFD568 /* ViewPaddingTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewPaddingTests.swift; sourceTree = ""; }; + 52CA2F9526ECC58B00BFD568 /* TransformingModifiersTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TransformingModifiersTests.swift; sourceTree = ""; }; 52E3258E26C72E7800CCE47E /* watchOS-App.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "watchOS-App.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 52E3259526C72E7900CCE47E /* App-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "App-Info.plist"; sourceTree = ""; }; 52E3259A26C72E7900CCE47E /* watchOS-Ext.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = "watchOS-Ext.appex"; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -58,6 +308,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 52CA301426ECC5D200BFD568 /* ViewInspector in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -74,18 +325,207 @@ 520213A526ECB45D00E94C6E /* watchOS-Tests */ = { isa = PBXGroup; children = ( - 520213A626ECB45D00E94C6E /* watchOS_Tests.swift */, + 52CA2F1126ECC58B00BFD568 /* ViewInspectorTests */, ); path = "watchOS-Tests"; sourceTree = ""; }; + 52CA2F0F26ECC56600BFD568 /* Packages */ = { + isa = PBXGroup; + children = ( + 52CA2F1026ECC56600BFD568 /* ViewInspector */, + ); + name = Packages; + sourceTree = ""; + }; + 52CA2F1126ECC58B00BFD568 /* ViewInspectorTests */ = { + isa = PBXGroup; + children = ( + 52CA2F1226ECC58B00BFD568 /* LazyGroupTests.swift */, + 52CA2F1326ECC58B00BFD568 /* ViewHostingTests.swift */, + 52CA2F1426ECC58B00BFD568 /* InspectionEmissaryTests.swift */, + 52CA2F1526ECC58B00BFD568 /* BaseTypesTests.swift */, + 52CA2F1626ECC58B00BFD568 /* ViewSearchTests.swift */, + 52CA2F1726ECC58B00BFD568 /* Gestures */, + 52CA2F3026ECC58B00BFD568 /* TestResources */, + 52CA2F3526ECC58B00BFD568 /* InspectableViewTests.swift */, + 52CA2F3626ECC58B00BFD568 /* InspectorTests.swift */, + 52CA2F3726ECC58B00BFD568 /* SwiftUI */, + 52CA2F8526ECC58B00BFD568 /* ViewModifiers */, + ); + name = ViewInspectorTests; + path = ../../Tests/ViewInspectorTests; + sourceTree = ""; + }; + 52CA2F1726ECC58B00BFD568 /* Gestures */ = { + isa = PBXGroup; + children = ( + 52CA2F1826ECC58B00BFD568 /* GestureModifiers */, + 52CA2F1E26ECC58B00BFD568 /* ComposedGestureExampleTests.swift */, + 52CA2F1F26ECC58B00BFD568 /* SequenceGestureChildrenTests.swift */, + 52CA2F2026ECC58B00BFD568 /* RotationGestureTests.swift */, + 52CA2F2126ECC58B00BFD568 /* ExclusiveGestureChildrenTests.swift */, + 52CA2F2226ECC58B00BFD568 /* TapGestureTests.swift */, + 52CA2F2326ECC58B00BFD568 /* ExclusiveGestureTests.swift */, + 52CA2F2426ECC58B00BFD568 /* SimultaneousGestureChildrenTests.swift */, + 52CA2F2526ECC58B00BFD568 /* SequenceGestureTests.swift */, + 52CA2F2626ECC58B00BFD568 /* GestureExampleTests.swift */, + 52CA2F2726ECC58B00BFD568 /* DragGestureTests.swift */, + 52CA2F2826ECC58B00BFD568 /* CommonComposedGestureTests.swift */, + 52CA2F2926ECC58B00BFD568 /* CommonComposedGestureUpdatingTests.swift */, + 52CA2F2A26ECC58B00BFD568 /* SimultaneousGestureTests.swift */, + 52CA2F2B26ECC58B00BFD568 /* CommonComposedGestureEndedTests.swift */, + 52CA2F2C26ECC58B00BFD568 /* CommonComposedGestureChangedTests.swift */, + 52CA2F2D26ECC58B00BFD568 /* LongPressGestureTests.swift */, + 52CA2F2E26ECC58B00BFD568 /* CommonGestureTests.swift */, + 52CA2F2F26ECC58B00BFD568 /* MagnificationGestureTests.swift */, + ); + path = Gestures; + sourceTree = ""; + }; + 52CA2F1826ECC58B00BFD568 /* GestureModifiers */ = { + isa = PBXGroup; + children = ( + 52CA2F1926ECC58B00BFD568 /* HitTestingTests.swift */, + 52CA2F1A26ECC58B00BFD568 /* GestureModifierTests.swift */, + 52CA2F1B26ECC58B00BFD568 /* GestureActionTests.swift */, + 52CA2F1C26ECC58B00BFD568 /* HighPriorityGestureModifierTests.swift */, + 52CA2F1D26ECC58B00BFD568 /* SimultaneousGestureModifierTests.swift */, + ); + path = GestureModifiers; + sourceTree = ""; + }; + 52CA2F3026ECC58B00BFD568 /* TestResources */ = { + isa = PBXGroup; + children = ( + 52CA2F3126ECC58B00BFD568 /* Test.strings */, + ); + path = TestResources; + sourceTree = ""; + }; + 52CA2F3726ECC58B00BFD568 /* SwiftUI */ = { + isa = PBXGroup; + children = ( + 52CA2F3826ECC58B00BFD568 /* ZStackTests.swift */, + 52CA2F3926ECC58B00BFD568 /* OptionalViewTests.swift */, + 52CA2F3A26ECC58B00BFD568 /* MenuButtonTests.swift */, + 52CA2F3B26ECC58B00BFD568 /* TouchBarTests.swift */, + 52CA2F3C26ECC58B00BFD568 /* GroupBoxTests.swift */, + 52CA2F3D26ECC58B00BFD568 /* SheetTests.swift */, + 52CA2F3E26ECC58B00BFD568 /* RadialGradientTests.swift */, + 52CA2F3F26ECC58B00BFD568 /* ScrollViewReaderTests.swift */, + 52CA2F4026ECC58B00BFD568 /* MapTests.swift */, + 52CA2F4126ECC58B00BFD568 /* SubscriptionViewTests.swift */, + 52CA2F4226ECC58B00BFD568 /* MenuTests.swift */, + 52CA2F4326ECC58B00BFD568 /* LabelTests.swift */, + 52CA2F4426ECC58B00BFD568 /* TextTests.swift */, + 52CA2F4526ECC58B00BFD568 /* OpaqueViewTests.swift */, + 52CA2F4626ECC58B00BFD568 /* HStackTests.swift */, + 52CA2F4726ECC58B00BFD568 /* TreeViewTests.swift */, + 52CA2F4826ECC58B00BFD568 /* EquatableViewTests.swift */, + 52CA2F4926ECC58B00BFD568 /* LinearGradientTests.swift */, + 52CA2F4A26ECC58B00BFD568 /* ToolbarTests.swift */, + 52CA2F4B26ECC58B00BFD568 /* DisclosureGroupTests.swift */, + 52CA2F4C26ECC58B00BFD568 /* GeometryReaderTests.swift */, + 52CA2F4D26ECC58B00BFD568 /* ProgressViewTests.swift */, + 52CA2F4E26ECC58B00BFD568 /* EnvironmentObjectInjectionTests.swift */, + 52CA2F4F26ECC58B00BFD568 /* TabViewTests.swift */, + 52CA2F5026ECC58B00BFD568 /* PopoverTests.swift */, + 52CA2F5126ECC58B00BFD568 /* EmptyViewTests.swift */, + 52CA2F5226ECC58B00BFD568 /* CustomViewModifierTests.swift */, + 52CA2F5326ECC58B00BFD568 /* ImageTests.swift */, + 52CA2F5426ECC58B00BFD568 /* EnvironmentReaderViewTests.swift */, + 52CA2F5526ECC58B00BFD568 /* StepperTests.swift */, + 52CA2F5626ECC58B00BFD568 /* FormTests.swift */, + 52CA2F5726ECC58B00BFD568 /* TupleViewTests.swift */, + 52CA2F5826ECC58B00BFD568 /* ConfirmationDialogTests.swift */, + 52CA2F5926ECC58B00BFD568 /* LazyVGridTests.swift */, + 52CA2F5A26ECC58B00BFD568 /* LazyHStackTests.swift */, + 52CA2F5B26ECC58B00BFD568 /* AlertTests.swift */, + 52CA2F5C26ECC58B00BFD568 /* TextAttributesTests.swift */, + 52CA2F5D26ECC58B00BFD568 /* PasteButtonTests.swift */, + 52CA2F5E26ECC58B00BFD568 /* DividerTests.swift */, + 52CA2F5F26ECC58B00BFD568 /* ForEachTests.swift */, + 52CA2F6026ECC58B00BFD568 /* ActionSheetTests.swift */, + 52CA2F6126ECC58B00BFD568 /* DelayedPreferenceViewTests.swift */, + 52CA2F6226ECC58B00BFD568 /* ButtonTests.swift */, + 52CA2F6326ECC58B00BFD568 /* LinkTests.swift */, + 52CA2F6426ECC58B00BFD568 /* SliderTests.swift */, + 52CA2F6526ECC58B00BFD568 /* CustomViewTests.swift */, + 52CA2F6626ECC58B00BFD568 /* ColorTests.swift */, + 52CA2F6726ECC58B00BFD568 /* TextEditorTests.swift */, + 52CA2F6826ECC58B00BFD568 /* MapAnnotationTests.swift */, + 52CA2F6926ECC58B00BFD568 /* AngularGradientTests.swift */, + 52CA2F6A26ECC58B00BFD568 /* ConditionalContentTests.swift */, + 52CA2F6B26ECC58B00BFD568 /* VSplitViewTests.swift */, + 52CA2F6C26ECC58B00BFD568 /* NavigationViewTests.swift */, + 52CA2F6D26ECC58B00BFD568 /* EditButtonTests.swift */, + 52CA2F6E26ECC58B00BFD568 /* IDViewTests.swift */, + 52CA2F6F26ECC58B00BFD568 /* CustomViewBuilderTests.swift */, + 52CA2F7026ECC58B00BFD568 /* TextFieldTests.swift */, + 52CA2F7126ECC58B00BFD568 /* FullScreenCoverTests.swift */, + 52CA2F7226ECC58B00BFD568 /* NavigationLinkTests.swift */, + 52CA2F7326ECC58B00BFD568 /* VStackTests.swift */, + 52CA2F7426ECC58B00BFD568 /* PickerTests.swift */, + 52CA2F7526ECC58B00BFD568 /* GroupTests.swift */, + 52CA2F7626ECC58B00BFD568 /* SectionTests.swift */, + 52CA2F7726ECC58B00BFD568 /* ToggleTests.swift */, + 52CA2F7826ECC58B00BFD568 /* SpacerTests.swift */, + 52CA2F7926ECC58B00BFD568 /* DatePickerTests.swift */, + 52CA2F7A26ECC58B00BFD568 /* SafeAreaInsetTests.swift */, + 52CA2F7B26ECC58B00BFD568 /* ColorPickerTests.swift */, + 52CA2F7C26ECC58B00BFD568 /* OutlineGroupTests.swift */, + 52CA2F7D26ECC58B00BFD568 /* ScrollViewTests.swift */, + 52CA2F7E26ECC58B00BFD568 /* SecureFieldTests.swift */, + 52CA2F7F26ECC58B00BFD568 /* LazyHGridTests.swift */, + 52CA2F8026ECC58B00BFD568 /* ShapeTests.swift */, + 52CA2F8126ECC58B00BFD568 /* ListTests.swift */, + 52CA2F8226ECC58B00BFD568 /* HSplitViewTests.swift */, + 52CA2F8326ECC58B00BFD568 /* AnyViewTests.swift */, + 52CA2F8426ECC58B00BFD568 /* LazyVStackTests.swift */, + ); + path = SwiftUI; + sourceTree = ""; + }; + 52CA2F8526ECC58B00BFD568 /* ViewModifiers */ = { + isa = PBXGroup; + children = ( + 52CA2F8626ECC58B00BFD568 /* ConfigurationModifiersTests.swift */, + 52CA2F8726ECC58B00BFD568 /* PresentationModifiersTests.swift */, + 52CA2F8826ECC58B00BFD568 /* InteractionModifiersTests.swift */, + 52CA2F8926ECC58B00BFD568 /* EventsModifiersTests.swift */, + 52CA2F8A26ECC58B00BFD568 /* SizingModifiersTests.swift */, + 52CA2F8B26ECC58B00BFD568 /* NestedModifiersTests.swift */, + 52CA2F8C26ECC58B00BFD568 /* PositioningModifiersTests.swift */, + 52CA2F8D26ECC58B00BFD568 /* TextInputModifiersTests.swift */, + 52CA2F8E26ECC58B00BFD568 /* CustomStyleModifiersTests.swift */, + 52CA2F8F26ECC58B00BFD568 /* TransitiveModifiersTests.swift */, + 52CA2F9026ECC58B00BFD568 /* AccessibilityModifiersTests.swift */, + 52CA2F9126ECC58B00BFD568 /* AnimationModifiersTests.swift */, + 52CA2F9226ECC58B00BFD568 /* VisualEffectModifiersTests.swift */, + 52CA2F9326ECC58B00BFD568 /* EnvironmentModifiersTests.swift */, + 52CA2F9426ECC58B00BFD568 /* ViewPaddingTests.swift */, + 52CA2F9526ECC58B00BFD568 /* TransformingModifiersTests.swift */, + ); + path = ViewModifiers; + sourceTree = ""; + }; + 52CA301226ECC5D200BFD568 /* Frameworks */ = { + isa = PBXGroup; + children = ( + ); + name = Frameworks; + sourceTree = ""; + }; 52E3258326C72E7800CCE47E = { isa = PBXGroup; children = ( + 52CA2F0F26ECC56600BFD568 /* Packages */, 52E3259226C72E7800CCE47E /* watchOS-App */, 52E3259E26C72E7900CCE47E /* watchOS-Ext */, 520213A526ECB45D00E94C6E /* watchOS-Tests */, 52E3258B26C72E7800CCE47E /* Products */, + 52CA301226ECC5D200BFD568 /* Frameworks */, ); sourceTree = ""; }; @@ -133,6 +573,9 @@ 520213A926ECB45D00E94C6E /* PBXTargetDependency */, ); name = "watchOS-Tests"; + packageProductDependencies = ( + 52CA301326ECC5D200BFD568 /* ViewInspector */, + ); productName = "watchOS-Tests"; productReference = 520213A426ECB45D00E94C6E /* watchOS-Tests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; @@ -199,6 +642,8 @@ knownRegions = ( en, Base, + "en-AU", + ru, ); mainGroup = 52E3258326C72E7800CCE47E; productRefGroup = 52E3258B26C72E7800CCE47E /* Products */; @@ -217,6 +662,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 52CA2FB226ECC58B00BFD568 /* Test.strings in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -241,7 +687,129 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 520213A726ECB45D00E94C6E /* watchOS_Tests.swift in Sources */, + 52CA2FD826ECC58B00BFD568 /* AlertTests.swift in Sources */, + 52CA2FB326ECC58B00BFD568 /* InspectableViewTests.swift in Sources */, + 52CA2FA526ECC58B00BFD568 /* ExclusiveGestureTests.swift in Sources */, + 52CA2FB726ECC58B00BFD568 /* MenuButtonTests.swift in Sources */, + 52CA2FCB26ECC58B00BFD568 /* EnvironmentObjectInjectionTests.swift in Sources */, + 52CA300126ECC58B00BFD568 /* LazyVStackTests.swift in Sources */, + 52CA2FE526ECC58B00BFD568 /* MapAnnotationTests.swift in Sources */, + 52CA2FBF26ECC58B00BFD568 /* MenuTests.swift in Sources */, + 52CA300326ECC58B00BFD568 /* PresentationModifiersTests.swift in Sources */, + 52CA2FE126ECC58B00BFD568 /* SliderTests.swift in Sources */, + 52CA2FCD26ECC58B00BFD568 /* PopoverTests.swift in Sources */, + 52CA2FDD26ECC58B00BFD568 /* ActionSheetTests.swift in Sources */, + 52CA2FF526ECC58B00BFD568 /* SpacerTests.swift in Sources */, + 52CA2FBB26ECC58B00BFD568 /* RadialGradientTests.swift in Sources */, + 52CA2FED26ECC58B00BFD568 /* TextFieldTests.swift in Sources */, + 52CA2FE026ECC58B00BFD568 /* LinkTests.swift in Sources */, + 52CA300526ECC58B00BFD568 /* EventsModifiersTests.swift in Sources */, + 52CA2FD226ECC58B00BFD568 /* StepperTests.swift in Sources */, + 52CA2FD526ECC58B00BFD568 /* ConfirmationDialogTests.swift in Sources */, + 52CA2FFF26ECC58B00BFD568 /* HSplitViewTests.swift in Sources */, + 52CA2FE226ECC58B00BFD568 /* CustomViewTests.swift in Sources */, + 52CA2FFE26ECC58B00BFD568 /* ListTests.swift in Sources */, + 52CA2F9B26ECC58B00BFD568 /* HitTestingTests.swift in Sources */, + 52CA2FF326ECC58B00BFD568 /* SectionTests.swift in Sources */, + 52CA2FE826ECC58B00BFD568 /* VSplitViewTests.swift in Sources */, + 52CA300F26ECC58B00BFD568 /* EnvironmentModifiersTests.swift in Sources */, + 52CA2FFB26ECC58B00BFD568 /* SecureFieldTests.swift in Sources */, + 52CA300E26ECC58B00BFD568 /* VisualEffectModifiersTests.swift in Sources */, + 52CA300026ECC58B00BFD568 /* AnyViewTests.swift in Sources */, + 52CA2FE626ECC58B00BFD568 /* AngularGradientTests.swift in Sources */, + 52CA2FF126ECC58B00BFD568 /* PickerTests.swift in Sources */, + 52CA2FAC26ECC58B00BFD568 /* SimultaneousGestureTests.swift in Sources */, + 52CA300626ECC58B00BFD568 /* SizingModifiersTests.swift in Sources */, + 52CA2FEC26ECC58B00BFD568 /* CustomViewBuilderTests.swift in Sources */, + 52CA2FB526ECC58B00BFD568 /* ZStackTests.swift in Sources */, + 52CA2FAE26ECC58B00BFD568 /* CommonComposedGestureChangedTests.swift in Sources */, + 52CA2FEA26ECC58B00BFD568 /* EditButtonTests.swift in Sources */, + 52CA2FC226ECC58B00BFD568 /* OpaqueViewTests.swift in Sources */, + 52CA2FCE26ECC58B00BFD568 /* EmptyViewTests.swift in Sources */, + 52CA2FB626ECC58B00BFD568 /* OptionalViewTests.swift in Sources */, + 52CA300226ECC58B00BFD568 /* ConfigurationModifiersTests.swift in Sources */, + 52CA300426ECC58B00BFD568 /* InteractionModifiersTests.swift in Sources */, + 52CA300826ECC58B00BFD568 /* PositioningModifiersTests.swift in Sources */, + 52CA300726ECC58B00BFD568 /* NestedModifiersTests.swift in Sources */, + 52CA300B26ECC58B00BFD568 /* TransitiveModifiersTests.swift in Sources */, + 52CA300D26ECC58B00BFD568 /* AnimationModifiersTests.swift in Sources */, + 52CA2FEB26ECC58B00BFD568 /* IDViewTests.swift in Sources */, + 52CA2FBE26ECC58B00BFD568 /* SubscriptionViewTests.swift in Sources */, + 52CA2FA126ECC58B00BFD568 /* SequenceGestureChildrenTests.swift in Sources */, + 52CA2FE426ECC58B00BFD568 /* TextEditorTests.swift in Sources */, + 52CA2F9F26ECC58B00BFD568 /* SimultaneousGestureModifierTests.swift in Sources */, + 52CA2F9E26ECC58B00BFD568 /* HighPriorityGestureModifierTests.swift in Sources */, + 52CA2FFD26ECC58B00BFD568 /* ShapeTests.swift in Sources */, + 52CA2FC726ECC58B00BFD568 /* ToolbarTests.swift in Sources */, + 52CA2FC326ECC58B00BFD568 /* HStackTests.swift in Sources */, + 52CA2FB826ECC58B00BFD568 /* TouchBarTests.swift in Sources */, + 52CA2FCF26ECC58B00BFD568 /* CustomViewModifierTests.swift in Sources */, + 52CA300926ECC58B00BFD568 /* TextInputModifiersTests.swift in Sources */, + 52CA2FA826ECC58B00BFD568 /* GestureExampleTests.swift in Sources */, + 52CA2FA626ECC58B00BFD568 /* SimultaneousGestureChildrenTests.swift in Sources */, + 52CA2F9C26ECC58B00BFD568 /* GestureModifierTests.swift in Sources */, + 52CA2FD026ECC58B00BFD568 /* ImageTests.swift in Sources */, + 52CA2FE326ECC58B00BFD568 /* ColorTests.swift in Sources */, + 52CA2FDF26ECC58B00BFD568 /* ButtonTests.swift in Sources */, + 52CA2FBA26ECC58B00BFD568 /* SheetTests.swift in Sources */, + 52CA2FAB26ECC58B00BFD568 /* CommonComposedGestureUpdatingTests.swift in Sources */, + 52CA2FD126ECC58B00BFD568 /* EnvironmentReaderViewTests.swift in Sources */, + 52CA2FF826ECC58B00BFD568 /* ColorPickerTests.swift in Sources */, + 52CA2FF926ECC58B00BFD568 /* OutlineGroupTests.swift in Sources */, + 52CA2F9826ECC58B00BFD568 /* InspectionEmissaryTests.swift in Sources */, + 52CA2FF426ECC58B00BFD568 /* ToggleTests.swift in Sources */, + 52CA2FA926ECC58B00BFD568 /* DragGestureTests.swift in Sources */, + 52CA2FE726ECC58B00BFD568 /* ConditionalContentTests.swift in Sources */, + 52CA301126ECC58B00BFD568 /* TransformingModifiersTests.swift in Sources */, + 52CA2FCA26ECC58B00BFD568 /* ProgressViewTests.swift in Sources */, + 52CA2FF226ECC58B00BFD568 /* GroupTests.swift in Sources */, + 52CA2FD426ECC58B00BFD568 /* TupleViewTests.swift in Sources */, + 52CA300C26ECC58B00BFD568 /* AccessibilityModifiersTests.swift in Sources */, + 52CA2FBC26ECC58B00BFD568 /* ScrollViewReaderTests.swift in Sources */, + 52CA2FAF26ECC58B00BFD568 /* LongPressGestureTests.swift in Sources */, + 52CA2FF726ECC58B00BFD568 /* SafeAreaInsetTests.swift in Sources */, + 52CA301026ECC58B00BFD568 /* ViewPaddingTests.swift in Sources */, + 52CA300A26ECC58B00BFD568 /* CustomStyleModifiersTests.swift in Sources */, + 52CA2FB426ECC58B00BFD568 /* InspectorTests.swift in Sources */, + 52CA2FC126ECC58B00BFD568 /* TextTests.swift in Sources */, + 52CA2FA426ECC58B00BFD568 /* TapGestureTests.swift in Sources */, + 52CA2FAD26ECC58B00BFD568 /* CommonComposedGestureEndedTests.swift in Sources */, + 52CA2FB026ECC58B00BFD568 /* CommonGestureTests.swift in Sources */, + 52CA2FF626ECC58B00BFD568 /* DatePickerTests.swift in Sources */, + 52CA2FEE26ECC58B00BFD568 /* FullScreenCoverTests.swift in Sources */, + 52CA2FBD26ECC58B00BFD568 /* MapTests.swift in Sources */, + 52CA2FC626ECC58B00BFD568 /* LinearGradientTests.swift in Sources */, + 52CA2FD326ECC58B00BFD568 /* FormTests.swift in Sources */, + 52CA2FC526ECC58B00BFD568 /* EquatableViewTests.swift in Sources */, + 52CA2FDE26ECC58B00BFD568 /* DelayedPreferenceViewTests.swift in Sources */, + 52CA2FFC26ECC58B00BFD568 /* LazyHGridTests.swift in Sources */, + 52CA2F9D26ECC58B00BFD568 /* GestureActionTests.swift in Sources */, + 52CA2FA026ECC58B00BFD568 /* ComposedGestureExampleTests.swift in Sources */, + 52CA2FDA26ECC58B00BFD568 /* PasteButtonTests.swift in Sources */, + 52CA2FDC26ECC58B00BFD568 /* ForEachTests.swift in Sources */, + 52CA2FEF26ECC58B00BFD568 /* NavigationLinkTests.swift in Sources */, + 52CA2FDB26ECC58B00BFD568 /* DividerTests.swift in Sources */, + 52CA2F9626ECC58B00BFD568 /* LazyGroupTests.swift in Sources */, + 52CA2FCC26ECC58B00BFD568 /* TabViewTests.swift in Sources */, + 52CA2F9926ECC58B00BFD568 /* BaseTypesTests.swift in Sources */, + 52CA2FA226ECC58B00BFD568 /* RotationGestureTests.swift in Sources */, + 52CA2FE926ECC58B00BFD568 /* NavigationViewTests.swift in Sources */, + 52CA2FA326ECC58B00BFD568 /* ExclusiveGestureChildrenTests.swift in Sources */, + 52CA2F9726ECC58B00BFD568 /* ViewHostingTests.swift in Sources */, + 52CA2FB926ECC58B00BFD568 /* GroupBoxTests.swift in Sources */, + 52CA2FAA26ECC58B00BFD568 /* CommonComposedGestureTests.swift in Sources */, + 52CA2FC026ECC58B00BFD568 /* LabelTests.swift in Sources */, + 52CA2FB126ECC58B00BFD568 /* MagnificationGestureTests.swift in Sources */, + 52CA2FF026ECC58B00BFD568 /* VStackTests.swift in Sources */, + 52CA2FA726ECC58B00BFD568 /* SequenceGestureTests.swift in Sources */, + 52CA2FD926ECC58B00BFD568 /* TextAttributesTests.swift in Sources */, + 52CA2FFA26ECC58B00BFD568 /* ScrollViewTests.swift in Sources */, + 52CA2FC426ECC58B00BFD568 /* TreeViewTests.swift in Sources */, + 52CA2FD726ECC58B00BFD568 /* LazyHStackTests.swift in Sources */, + 52CA2FC826ECC58B00BFD568 /* DisclosureGroupTests.swift in Sources */, + 52CA2F9A26ECC58B00BFD568 /* ViewSearchTests.swift in Sources */, + 52CA2FD626ECC58B00BFD568 /* LazyVGridTests.swift in Sources */, + 52CA2FC926ECC58B00BFD568 /* GeometryReaderTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -268,6 +836,19 @@ }; /* End PBXTargetDependency section */ +/* Begin PBXVariantGroup section */ + 52CA2F3126ECC58B00BFD568 /* Test.strings */ = { + isa = PBXVariantGroup; + children = ( + 52CA2F3226ECC58B00BFD568 /* en */, + 52CA2F3326ECC58B00BFD568 /* en-AU */, + 52CA2F3426ECC58B00BFD568 /* ru */, + ); + name = Test.strings; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + /* Begin XCBuildConfiguration section */ 520213AA26ECB45D00E94C6E /* Debug */ = { isa = XCBuildConfiguration; @@ -553,6 +1134,13 @@ defaultConfigurationName = Release; }; /* End XCConfigurationList section */ + +/* Begin XCSwiftPackageProductDependency section */ + 52CA301326ECC5D200BFD568 /* ViewInspector */ = { + isa = XCSwiftPackageProductDependency; + productName = ViewInspector; + }; +/* End XCSwiftPackageProductDependency section */ }; rootObject = 52E3258426C72E7800CCE47E /* Project object */; } From f816b65137148beef6300f2e1ad60df1e844efe4 Mon Sep 17 00:00:00 2001 From: Alexey Naumov Date: Sun, 12 Sep 2021 15:50:48 +0300 Subject: [PATCH 57/99] Update print function to handle cyclic references --- Sources/ViewInspector/Inspector.swift | 18 +++++--- Tests/ViewInspectorTests/InspectorTests.swift | 45 +++++++++++++++++++ 2 files changed, 58 insertions(+), 5 deletions(-) diff --git a/Sources/ViewInspector/Inspector.swift b/Sources/ViewInspector/Inspector.swift index b7d48690..58b3d5de 100644 --- a/Sources/ViewInspector/Inspector.swift +++ b/Sources/ViewInspector/Inspector.swift @@ -79,7 +79,7 @@ extension Inspector { ``` */ public static func print(_ value: Any) -> String { - let tree = attributesTree(value: value, medium: .empty) + let tree = attributesTree(value: value, medium: .empty, visited: []) return typeName(value: value) + print(tree, level: 1) } @@ -107,9 +107,16 @@ extension Inspector { return needsNewLine ? "\n" : "" } - private static func attributesTree(value: Any, medium: Content.Medium) -> Any { + private static func attributesTree(value: Any, medium: Content.Medium, visited: [AnyObject]) -> Any { + var visited = visited + if type(of: value) is AnyClass { + let ref = value as AnyObject + guard !visited.contains(where: { $0 === ref }) + else { return " = { cyclic reference }" } + visited.append(ref) + } if let array = value as? [Any] { - return array.map { attributesTree(value: $0, medium: medium) } + return array.map { attributesTree(value: $0, medium: medium, visited: visited) } } let medium = (try? unwrap(content: Content(value, medium: medium)).medium) ?? medium var mirror = Mirror(reflecting: value) @@ -122,12 +129,13 @@ extension Inspector { children.enumerated().forEach { child in let childName = child.element.label ?? "[\(child.offset)]" let childType = typeName(value: child.element.value) - dict[childName + ": " + childType] = attributesTree(value: child.element.value, medium: medium) + dict[childName + ": " + childType] = attributesTree( + value: child.element.value, medium: medium, visited: visited) } if let inspectable = value as? Inspectable, let content = try? inspectable.extractContent(environmentObjects: medium.environmentObjects) { let childType = typeName(value: content) - dict["body: " + childType] = attributesTree(value: content, medium: medium) + dict["body: " + childType] = attributesTree(value: content, medium: medium, visited: visited) } if dict.count == 0 { return " = " + String(describing: value) diff --git a/Tests/ViewInspectorTests/InspectorTests.swift b/Tests/ViewInspectorTests/InspectorTests.swift index 83a3404f..7b277796 100644 --- a/Tests/ViewInspectorTests/InspectorTests.swift +++ b/Tests/ViewInspectorTests/InspectorTests.swift @@ -71,6 +71,44 @@ final class InspectorTests: XCTestCase { XCTAssertEqual(Inspector.print(sut), str) } + func testPrintClassHierarchy() { + let sut = TestDerivedClass() + let str = """ + TestDerivedClass + reference: Optional = nil + value: Int = 5 + + """ + XCTAssertEqual(Inspector.print(sut), str) + } + + func testPrintCyclicReferences() { + let obj1 = TestBaseClass() + obj1.reference = obj1 + let obj2 = TestBaseClass(), obj3 = TestBaseClass(), obj4 = TestBaseClass() + obj2.reference = obj3 + obj3.reference = obj4 + obj4.reference = obj2 + let str1 = """ + TestBaseClass + reference: Optional + some: TestBaseClass = { cyclic reference } + + """ + let str2 = """ + TestBaseClass + reference: Optional + some: TestBaseClass + reference: Optional + some: TestBaseClass + reference: Optional + some: TestBaseClass = { cyclic reference } + + """ + XCTAssertEqual(Inspector.print(obj1), str1) + XCTAssertEqual(Inspector.print(obj2), str2) + } + func testTupleView() throws { let view = HStack { Text(""); Text("") } let content = try Inspector.attribute(path: "_tree|content", value: view) @@ -262,3 +300,10 @@ private struct TestPrintView: View, Inspectable { Text(str[0]) } } + +private class TestBaseClass { + weak var reference: AnyObject? +} +private final class TestDerivedClass: TestBaseClass { + var value: Int = 5 +} From bea0b7245db290d81c97efd00bdf3bfc5ae2c8db Mon Sep 17 00:00:00 2001 From: Alexey Naumov Date: Sun, 12 Sep 2021 15:55:53 +0300 Subject: [PATCH 58/99] Export Inspector.print --- Sources/ViewInspector/Inspector.swift | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Sources/ViewInspector/Inspector.swift b/Sources/ViewInspector/Inspector.swift index 58b3d5de..853525f7 100644 --- a/Sources/ViewInspector/Inspector.swift +++ b/Sources/ViewInspector/Inspector.swift @@ -1,10 +1,10 @@ import SwiftUI @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) -internal struct Inspector { } +public struct Inspector { } @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) -extension Inspector { +internal extension Inspector { static func attribute(label: String, value: Any) throws -> Any { if label == "super", let superclass = Mirror(reflecting: value).superclassMirror { @@ -70,7 +70,7 @@ extension Inspector { // MARK: - Attributes lookup @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) -extension Inspector { +public extension Inspector { /** Use this function to lookup the struct content: @@ -78,7 +78,7 @@ extension Inspector { (lldb) po Inspector.print(view) as AnyObject ``` */ - public static func print(_ value: Any) -> String { + static func print(_ value: Any) -> String { let tree = attributesTree(value: value, medium: .empty, visited: []) return typeName(value: value) + print(tree, level: 1) } @@ -169,7 +169,7 @@ fileprivate extension Array { // MARK: - View Inspection @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) -extension Inspector { +internal extension Inspector { static func viewsInContainer(view: Any, medium: Content.Medium) throws -> LazyGroup { let unwrappedContainer = try Inspector.unwrap(content: Content(view, medium: medium.resettingViewModifiers())) From 19dc2151dacf4c81a19979c5142967778e3d5a90 Mon Sep 17 00:00:00 2001 From: Alexey Naumov Date: Sun, 12 Sep 2021 19:25:39 +0300 Subject: [PATCH 59/99] Implement View hosting for watchOS --- .../watchOS-Ext/watchOSApp+Testable.swift | 41 +++++++++++++++++++ .watchOS/watchOS-Ext/watchOSApp.swift | 8 ++++ .watchOS/watchOS.xcodeproj/project.pbxproj | 4 ++ Sources/ViewInspector/ViewHosting.swift | 33 ++++++++++++--- Sources/ViewInspector/ViewHostingProxy.swift | 16 -------- 5 files changed, 80 insertions(+), 22 deletions(-) create mode 100644 .watchOS/watchOS-Ext/watchOSApp+Testable.swift delete mode 100644 Sources/ViewInspector/ViewHostingProxy.swift diff --git a/.watchOS/watchOS-Ext/watchOSApp+Testable.swift b/.watchOS/watchOS-Ext/watchOSApp+Testable.swift new file mode 100644 index 00000000..2ebdd361 --- /dev/null +++ b/.watchOS/watchOS-Ext/watchOSApp+Testable.swift @@ -0,0 +1,41 @@ +import SwiftUI +import WatchKit +import Combine + +typealias TestViewSubject = CurrentValueSubject + +#if os(watchOS) && DEBUG + +extension View { + func testable(_ injector: TestViewSubject) -> some View { + modifier(TestViewHost(injector: injector)) + } +} + +private struct TestViewHost: ViewModifier { + + @State private var hostedView: AnyView? + let injector: TestViewSubject + + func body(content: Content) -> some View { + Group { + if let view = hostedView { + view + } else { + content + } + } + .onReceive(injector) { hostedView = $0 } + } +} + +#else + +extension View { + @inline(__always) + func testable(_ injector: TestViewSubject) -> some View { + self + } +} + +#endif diff --git a/.watchOS/watchOS-Ext/watchOSApp.swift b/.watchOS/watchOS-Ext/watchOSApp.swift index 23fbb9ac..271041be 100644 --- a/.watchOS/watchOS-Ext/watchOSApp.swift +++ b/.watchOS/watchOS-Ext/watchOSApp.swift @@ -2,11 +2,19 @@ import SwiftUI @main struct watchOSApp: App { + + @WKExtensionDelegateAdaptor(ExtensionDelegate.self) var extDelegate + var body: some Scene { WindowGroup { NavigationView { Text("Hi") } + .testable(extDelegate.testViewSubject) } } } + +final class ExtensionDelegate: NSObject, WKExtensionDelegate { + let testViewSubject = TestViewSubject(nil) +} diff --git a/.watchOS/watchOS.xcodeproj/project.pbxproj b/.watchOS/watchOS.xcodeproj/project.pbxproj index 91498973..495c9815 100644 --- a/.watchOS/watchOS.xcodeproj/project.pbxproj +++ b/.watchOS/watchOS.xcodeproj/project.pbxproj @@ -132,6 +132,7 @@ 52CA301026ECC58B00BFD568 /* ViewPaddingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F9426ECC58B00BFD568 /* ViewPaddingTests.swift */; }; 52CA301126ECC58B00BFD568 /* TransformingModifiersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F9526ECC58B00BFD568 /* TransformingModifiersTests.swift */; }; 52CA301426ECC5D200BFD568 /* ViewInspector in Frameworks */ = {isa = PBXBuildFile; productRef = 52CA301326ECC5D200BFD568 /* ViewInspector */; }; + 52CA301626ECD64400BFD568 /* watchOSApp+Testable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA301526ECD64400BFD568 /* watchOSApp+Testable.swift */; }; 52E3259B26C72E7900CCE47E /* watchOS-Ext.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 52E3259A26C72E7900CCE47E /* watchOS-Ext.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 52E325A226C72E7900CCE47E /* watchOSApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52E325A126C72E7900CCE47E /* watchOSApp.swift */; }; /* End PBXBuildFile section */ @@ -296,6 +297,7 @@ 52CA2F9326ECC58B00BFD568 /* EnvironmentModifiersTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EnvironmentModifiersTests.swift; sourceTree = ""; }; 52CA2F9426ECC58B00BFD568 /* ViewPaddingTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewPaddingTests.swift; sourceTree = ""; }; 52CA2F9526ECC58B00BFD568 /* TransformingModifiersTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TransformingModifiersTests.swift; sourceTree = ""; }; + 52CA301526ECD64400BFD568 /* watchOSApp+Testable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "watchOSApp+Testable.swift"; sourceTree = ""; }; 52E3258E26C72E7800CCE47E /* watchOS-App.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "watchOS-App.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 52E3259526C72E7900CCE47E /* App-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "App-Info.plist"; sourceTree = ""; }; 52E3259A26C72E7900CCE47E /* watchOS-Ext.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = "watchOS-Ext.appex"; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -551,6 +553,7 @@ isa = PBXGroup; children = ( 52E325A126C72E7900CCE47E /* watchOSApp.swift */, + 52CA301526ECD64400BFD568 /* watchOSApp+Testable.swift */, 52E325AA26C72E7900CCE47E /* Ext-Info.plist */, ); path = "watchOS-Ext"; @@ -818,6 +821,7 @@ buildActionMask = 2147483647; files = ( 52E325A226C72E7900CCE47E /* watchOSApp.swift in Sources */, + 52CA301626ECD64400BFD568 /* watchOSApp+Testable.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Sources/ViewInspector/ViewHosting.swift b/Sources/ViewInspector/ViewHosting.swift index 9b4c3f1b..ec6b2944 100644 --- a/Sources/ViewInspector/ViewHosting.swift +++ b/Sources/ViewInspector/ViewHosting.swift @@ -1,4 +1,5 @@ import SwiftUI +import Combine #if canImport(UIKit) import UIKit #endif @@ -24,11 +25,7 @@ public extension ViewHosting { return unwrapped.medium }() #if os(watchOS) - guard let proxy = ViewHosting.proxy else { - // !!! - fatalError("View hosting is not set up. Please follow this guide: ") - } - proxy.host(view: AnyView(view)) + watchOS(host: AnyView(view)) #else let parentVC = rootViewController let childVC = hostVC(view) @@ -54,7 +51,7 @@ public extension ViewHosting { let viewId = ViewId(function: function) guard let hosted = expel(viewId: viewId) else { return } #if os(watchOS) - ViewHosting.proxy?.host(view: nil) + watchOS(host: nil) #else let childVC = hosted.viewController willMove(childVC, to: nil) @@ -64,6 +61,30 @@ public extension ViewHosting { #endif } + #if os(watchOS) + private static func watchOS(host view: AnyView?) { + typealias Subject = CurrentValueSubject + let ext = WKExtension.shared() + guard let subject: Subject = { + if let delegate = ext.delegate, + let subject = try? Inspector + .attribute(path: "fallbackDelegate|some|extension|testViewSubject", + value: delegate, type: Subject.self) { + return subject + } + if let rootIC = ext.rootInterfaceController, + let subject = try? Inspector + .attribute(label: "testViewSubject", value: rootIC, type: Subject.self) { + return subject + } + return nil + }() else { + fatalError("View hosting for watchOS is not set up. Please follow this guide: ") + } + subject.send(view) + } + #endif + internal static func medium(function: String = #function) -> Content.Medium { let viewId = ViewHosting.ViewId(function: function) return hosted[viewId]?.medium ?? .empty diff --git a/Sources/ViewInspector/ViewHostingProxy.swift b/Sources/ViewInspector/ViewHostingProxy.swift deleted file mode 100644 index 4195de21..00000000 --- a/Sources/ViewInspector/ViewHostingProxy.swift +++ /dev/null @@ -1,16 +0,0 @@ -import SwiftUI - -@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *) -public protocol ViewHostingProxy { - static var instance: Self { get } - func host(view: AnyView?) -} - -@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *) -public extension ViewHosting { - private(set) internal static var proxy: ViewHostingProxy? - - static func register(proxy: ViewHostingProxy?) { - self.proxy = proxy - } -} From 856a3a50e4c0a0ab0e415c83e0838792f3850ab8 Mon Sep 17 00:00:00 2001 From: Alexey Naumov Date: Sun, 12 Sep 2021 19:31:36 +0300 Subject: [PATCH 60/99] Remove an empty file --- Sources/ViewInspector/SwiftUI/FullScreenCover.swift | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 Sources/ViewInspector/SwiftUI/FullScreenCover.swift diff --git a/Sources/ViewInspector/SwiftUI/FullScreenCover.swift b/Sources/ViewInspector/SwiftUI/FullScreenCover.swift deleted file mode 100644 index 15456d2b..00000000 --- a/Sources/ViewInspector/SwiftUI/FullScreenCover.swift +++ /dev/null @@ -1,3 +0,0 @@ -import SwiftUI - -// !!! From 8a7c52d829ea4e7c9aa9a9e9203049d699bc5256 Mon Sep 17 00:00:00 2001 From: Alexey Naumov Date: Sun, 12 Sep 2021 20:19:03 +0300 Subject: [PATCH 61/99] Set min deployment target watchOS to 7 --- .watchOS/watchOS.xcodeproj/project.pbxproj | 18 ++++++------------ Package.swift | 2 +- 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/.watchOS/watchOS.xcodeproj/project.pbxproj b/.watchOS/watchOS.xcodeproj/project.pbxproj index 495c9815..eb9e84f3 100644 --- a/.watchOS/watchOS.xcodeproj/project.pbxproj +++ b/.watchOS/watchOS.xcodeproj/project.pbxproj @@ -873,9 +873,7 @@ SDKROOT = watchos; SWIFT_EMIT_LOC_STRINGS = NO; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 4; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/watchOS-Ext.appex/watchOS-Ext"; - WATCHOS_DEPLOYMENT_TARGET = 8.0; }; name = Debug; }; @@ -898,9 +896,7 @@ SDKROOT = watchos; SWIFT_EMIT_LOC_STRINGS = NO; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 4; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/watchOS-Ext.appex/watchOS-Ext"; - WATCHOS_DEPLOYMENT_TARGET = 8.0; }; name = Release; }; @@ -955,12 +951,15 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + TARGETED_DEVICE_FAMILY = 4; + WATCHOS_DEPLOYMENT_TARGET = 7.0; }; name = Debug; }; @@ -1009,12 +1008,15 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; SDKROOT = iphoneos; SWIFT_COMPILATION_MODE = wholemodule; SWIFT_OPTIMIZATION_LEVEL = "-O"; + TARGETED_DEVICE_FAMILY = 4; VALIDATE_PRODUCT = YES; + WATCHOS_DEPLOYMENT_TARGET = 7.0; }; name = Release; }; @@ -1034,8 +1036,6 @@ SDKROOT = watchos; SKIP_INSTALL = YES; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 4; - WATCHOS_DEPLOYMENT_TARGET = 7.0; }; name = Debug; }; @@ -1055,8 +1055,6 @@ SDKROOT = watchos; SKIP_INSTALL = YES; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 4; - WATCHOS_DEPLOYMENT_TARGET = 7.0; }; name = Release; }; @@ -1074,8 +1072,6 @@ SDKROOT = watchos; SKIP_INSTALL = YES; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 4; - WATCHOS_DEPLOYMENT_TARGET = 7.0; }; name = Debug; }; @@ -1093,8 +1089,6 @@ SDKROOT = watchos; SKIP_INSTALL = YES; SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 4; - WATCHOS_DEPLOYMENT_TARGET = 7.0; }; name = Release; }; diff --git a/Package.swift b/Package.swift index 58e05143..047daed4 100644 --- a/Package.swift +++ b/Package.swift @@ -7,7 +7,7 @@ let package = Package( name: "ViewInspector", defaultLocalization: "en", platforms: [ - .macOS(.v10_15), .iOS(.v11), .tvOS(.v13), .watchOS(.v6) + .macOS(.v10_15), .iOS(.v11), .tvOS(.v13), .watchOS(.v7) ], products: [ .library( From ad1f7c1da4d65dfa222a26906850b3490a6a874c Mon Sep 17 00:00:00 2001 From: Alexey Naumov Date: Sun, 12 Sep 2021 20:32:27 +0300 Subject: [PATCH 62/99] Tweak the error for watchOS view hosting --- Sources/ViewInspector/ViewHosting.swift | 17 +++++++++++++---- ViewInspector.xcodeproj/project.pbxproj | 8 -------- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/Sources/ViewInspector/ViewHosting.swift b/Sources/ViewInspector/ViewHosting.swift index ec6b2944..6322b43c 100644 --- a/Sources/ViewInspector/ViewHosting.swift +++ b/Sources/ViewInspector/ViewHosting.swift @@ -25,7 +25,11 @@ public extension ViewHosting { return unwrapped.medium }() #if os(watchOS) - watchOS(host: AnyView(view)) + do { + try watchOS(host: AnyView(view)) + } catch { + fatalError(error.localizedDescription) + } #else let parentVC = rootViewController let childVC = hostVC(view) @@ -51,7 +55,7 @@ public extension ViewHosting { let viewId = ViewId(function: function) guard let hosted = expel(viewId: viewId) else { return } #if os(watchOS) - watchOS(host: nil) + try? watchOS(host: nil) #else let childVC = hosted.viewController willMove(childVC, to: nil) @@ -62,7 +66,7 @@ public extension ViewHosting { } #if os(watchOS) - private static func watchOS(host view: AnyView?) { + private static func watchOS(host view: AnyView?) throws { typealias Subject = CurrentValueSubject let ext = WKExtension.shared() guard let subject: Subject = { @@ -79,7 +83,12 @@ public extension ViewHosting { } return nil }() else { - fatalError("View hosting for watchOS is not set up. Please follow this guide: ") + /* + If you're running ViewInspector's tests on watchOS, launch them + from another Xcode project at ".watchOS/watchOS.xcodeproj" + */ + throw InspectionError.notSupported( + "View hosting for watchOS is not set up. Please follow this guide: ") } subject.send(view) } diff --git a/ViewInspector.xcodeproj/project.pbxproj b/ViewInspector.xcodeproj/project.pbxproj index e6a2b7f2..d94d651f 100644 --- a/ViewInspector.xcodeproj/project.pbxproj +++ b/ViewInspector.xcodeproj/project.pbxproj @@ -47,7 +47,6 @@ 52B71AA626EB5BED00B719D4 /* SafeAreaInsetTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52B71AA526EB5BED00B719D4 /* SafeAreaInsetTests.swift */; }; 52B71AAA26EB5C4500B719D4 /* SafeAreaInset.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52B71AA926EB5C4500B719D4 /* SafeAreaInset.swift */; }; 52D37480262B1F0C00B1BFBA /* NestedModifiersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52D3747F262B1F0C00B1BFBA /* NestedModifiersTests.swift */; }; - 52E55CF826C2C18B00A266B9 /* ViewHostingProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52E55CF726C2C18B00A266B9 /* ViewHostingProxy.swift */; }; 52E24E9926E9378A00711987 /* ConfirmationDialog.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52E24E9826E9378A00711987 /* ConfirmationDialog.swift */; }; 52E24E9B26E93A4700711987 /* ConfirmationDialogTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52E24E9A26E93A4700711987 /* ConfirmationDialogTests.swift */; }; 52F356AA267692D100695E43 /* MapAnnotation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52F356A9267692D100695E43 /* MapAnnotation.swift */; }; @@ -80,7 +79,6 @@ CDA84516262CC1F800C56C98 /* CommonComposedGestureUpdatingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDA84515262CC1F800C56C98 /* CommonComposedGestureUpdatingTests.swift */; }; CDA8451C262CC34D00C56C98 /* CommonComposedGestureChangedTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CDA8451B262CC34D00C56C98 /* CommonComposedGestureChangedTests.swift */; }; D766E67026E17F01004AAA80 /* FullScreenCoverTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D766E66F26E17F01004AAA80 /* FullScreenCoverTests.swift */; }; - D7A6CE8926E17AE900599824 /* FullScreenCover.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7A6CE8826E17AE900599824 /* FullScreenCover.swift */; }; F6026A27256A7D1900CA31E5 /* TextAttributes.swift in Sources */ = {isa = PBXBuildFile; fileRef = F6026A26256A7D1900CA31E5 /* TextAttributes.swift */; }; F6026A31256A7E3D00CA31E5 /* TextAttributesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F6026A30256A7E3D00CA31E5 /* TextAttributesTests.swift */; }; F60385D523D3C74B008F31BD /* InspectionEmissary.swift in Sources */ = {isa = PBXBuildFile; fileRef = F60385D423D3C74B008F31BD /* InspectionEmissary.swift */; }; @@ -300,7 +298,6 @@ 52B71AA526EB5BED00B719D4 /* SafeAreaInsetTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SafeAreaInsetTests.swift; sourceTree = ""; }; 52B71AA926EB5C4500B719D4 /* SafeAreaInset.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SafeAreaInset.swift; sourceTree = ""; }; 52D3747F262B1F0C00B1BFBA /* NestedModifiersTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NestedModifiersTests.swift; sourceTree = ""; }; - 52E55CF726C2C18B00A266B9 /* ViewHostingProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewHostingProxy.swift; sourceTree = ""; }; 52E24E9826E9378A00711987 /* ConfirmationDialog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfirmationDialog.swift; sourceTree = ""; }; 52E24E9A26E93A4700711987 /* ConfirmationDialogTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfirmationDialogTests.swift; sourceTree = ""; }; 52F356A9267692D100695E43 /* MapAnnotation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapAnnotation.swift; sourceTree = ""; }; @@ -333,7 +330,6 @@ CDA84515262CC1F800C56C98 /* CommonComposedGestureUpdatingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommonComposedGestureUpdatingTests.swift; sourceTree = ""; }; CDA8451B262CC34D00C56C98 /* CommonComposedGestureChangedTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommonComposedGestureChangedTests.swift; sourceTree = ""; }; D766E66F26E17F01004AAA80 /* FullScreenCoverTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FullScreenCoverTests.swift; sourceTree = ""; }; - D7A6CE8826E17AE900599824 /* FullScreenCover.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FullScreenCover.swift; sourceTree = ""; }; F6026A26256A7D1900CA31E5 /* TextAttributes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextAttributes.swift; sourceTree = ""; }; F6026A30256A7E3D00CA31E5 /* TextAttributesTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextAttributesTests.swift; sourceTree = ""; }; F60385D423D3C74B008F31BD /* InspectionEmissary.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InspectionEmissary.swift; sourceTree = ""; }; @@ -597,7 +593,6 @@ F64105C3257BF9A70033D82D /* ViewSearch.swift */, F660849A2594AA6700AF59A2 /* ViewSearchIndex.swift */, F6D58B9223C4A0F3000CEE3B /* ViewHosting.swift */, - 52E55CF726C2C18B00A266B9 /* ViewHostingProxy.swift */, 520E915B26E64F210090BD1F /* EnvironmentInjection.swift */, 520E916126E69E540090BD1F /* PopupPresenter.swift */, F68108A423A5833D00B32145 /* Modifiers */, @@ -631,7 +626,6 @@ F6D933A62385E9E000358E0E /* EquatableView.swift */, F60EEBCC2382EED0007DB53A /* ForEach.swift */, F60EEBC52382EED0007DB53A /* Form.swift */, - D7A6CE8826E17AE900599824 /* FullScreenCover.swift */, F6D9339A2385AD9100358E0E /* GeometryReader.swift */, CDA84477262B6C3E00C56C98 /* Gesture.swift */, F60EEBC62382EED0007DB53A /* Group.swift */, @@ -1014,7 +1008,6 @@ F63E926A249FCF92005861F0 /* TransformingModifiers.swift in Sources */, F6F08E6D23A2A9D4001F04DF /* EnvironmentReaderView.swift in Sources */, F6119FD62549EECC0000C54A /* Label.swift in Sources */, - 52E55CF826C2C18B00A266B9 /* ViewHostingProxy.swift in Sources */, F6DFD88423830E9F0028E84D /* List.swift in Sources */, CDA84478262B6C3E00C56C98 /* Gesture.swift in Sources */, F6DFD880238303AF0028E84D /* NavigationView.swift in Sources */, @@ -1060,7 +1053,6 @@ F6ECF6C823A66E54000FC591 /* InteractionModifiers.swift in Sources */, 52A5CA0425E1139E00773CF5 /* EnvironmentModifiers.swift in Sources */, F60EEBDC2382EED0007DB53A /* Text.swift in Sources */, - D7A6CE8926E17AE900599824 /* FullScreenCover.swift in Sources */, 52B71AAA26EB5C4500B719D4 /* SafeAreaInset.swift in Sources */, F620C7FB2537B090006D856D /* ConfigurationModifiers.swift in Sources */, F6684BFE23AA863400DECCB3 /* RadialGradient.swift in Sources */, From 2cc3f88b1554642f131bd1280f2f2eabc3ac6ef5 Mon Sep 17 00:00:00 2001 From: Alexey Naumov Date: Mon, 13 Sep 2021 20:52:47 +0300 Subject: [PATCH 63/99] Fix several tests for watchOS --- .../watchOS-Ext/watchOSApp+Testable.swift | 15 ++++++------- .watchOS/watchOS-Ext/watchOSApp.swift | 2 +- Sources/ViewInspector/ViewHosting.swift | 21 +++++++++++++------ .../SwiftUI/GroupBoxTests.swift | 2 +- .../SwiftUI/TextAttributesTests.swift | 4 ++-- 5 files changed, 25 insertions(+), 19 deletions(-) diff --git a/.watchOS/watchOS-Ext/watchOSApp+Testable.swift b/.watchOS/watchOS-Ext/watchOSApp+Testable.swift index 2ebdd361..9cbba11b 100644 --- a/.watchOS/watchOS-Ext/watchOSApp+Testable.swift +++ b/.watchOS/watchOS-Ext/watchOSApp+Testable.swift @@ -2,7 +2,7 @@ import SwiftUI import WatchKit import Combine -typealias TestViewSubject = CurrentValueSubject +typealias TestViewSubject = CurrentValueSubject<[(String, AnyView)], Never> #if os(watchOS) && DEBUG @@ -14,18 +14,15 @@ extension View { private struct TestViewHost: ViewModifier { - @State private var hostedView: AnyView? + @State private var hostedViews: [(String, AnyView)] = [] let injector: TestViewSubject func body(content: Content) -> some View { - Group { - if let view = hostedView { - view - } else { - content - } + ZStack { + content + ForEach(hostedViews, id: \.0) { $0.1 } } - .onReceive(injector) { hostedView = $0 } + .onReceive(injector) { hostedViews = $0 } } } diff --git a/.watchOS/watchOS-Ext/watchOSApp.swift b/.watchOS/watchOS-Ext/watchOSApp.swift index 271041be..d5ac9a5f 100644 --- a/.watchOS/watchOS-Ext/watchOSApp.swift +++ b/.watchOS/watchOS-Ext/watchOSApp.swift @@ -16,5 +16,5 @@ struct watchOSApp: App { } final class ExtensionDelegate: NSObject, WKExtensionDelegate { - let testViewSubject = TestViewSubject(nil) + let testViewSubject = TestViewSubject([]) } diff --git a/Sources/ViewInspector/ViewHosting.swift b/Sources/ViewInspector/ViewHosting.swift index 6322b43c..a8b4a389 100644 --- a/Sources/ViewInspector/ViewHosting.swift +++ b/Sources/ViewInspector/ViewHosting.swift @@ -12,6 +12,7 @@ public extension ViewHosting { struct ViewId: Hashable { let function: String + var key: String { function } } static func host(view: V, size: CGSize? = nil, function: String = #function) where V: View { @@ -26,7 +27,8 @@ public extension ViewHosting { }() #if os(watchOS) do { - try watchOS(host: AnyView(view)) + store(Hosted(medium: medium), viewId: viewId) + try watchOS(host: AnyView(view), viewId: viewId) } catch { fatalError(error.localizedDescription) } @@ -53,10 +55,11 @@ public extension ViewHosting { static func expel(function: String = #function) { let viewId = ViewId(function: function) - guard let hosted = expel(viewId: viewId) else { return } #if os(watchOS) - try? watchOS(host: nil) + _ = expel(viewId: viewId) + try? watchOS(host: nil, viewId: viewId) #else + guard let hosted = expel(viewId: viewId) else { return } let childVC = hosted.viewController willMove(childVC, to: nil) childVC.view.removeFromSuperview() @@ -66,8 +69,8 @@ public extension ViewHosting { } #if os(watchOS) - private static func watchOS(host view: AnyView?) throws { - typealias Subject = CurrentValueSubject + private static func watchOS(host view: AnyView?, viewId: ViewId) throws { + typealias Subject = CurrentValueSubject<[(String, AnyView)], Never> let ext = WKExtension.shared() guard let subject: Subject = { if let delegate = ext.delegate, @@ -90,7 +93,13 @@ public extension ViewHosting { throw InspectionError.notSupported( "View hosting for watchOS is not set up. Please follow this guide: ") } - subject.send(view) + var array = subject.value + if let view = view { + array.append((viewId.key, view)) + } else if let index = array.firstIndex(where: { $0.0 == viewId.key }) { + array.remove(at: index) + } + subject.send(array) } #endif diff --git a/Tests/ViewInspectorTests/SwiftUI/GroupBoxTests.swift b/Tests/ViewInspectorTests/SwiftUI/GroupBoxTests.swift index 82a98591..00bd4916 100644 --- a/Tests/ViewInspectorTests/SwiftUI/GroupBoxTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/GroupBoxTests.swift @@ -89,7 +89,7 @@ final class GroupBoxTests: XCTestCase { XCTAssertEqual(sut, "abc") } - #if !os(tvOS) && !os(macOS) && !targetEnvironment(macCatalyst) + #if os(iOS) func testGroupBoxStyleInspection() throws { guard #available(iOS 14, *) else { return } let sut = EmptyView().groupBoxStyle(DefaultGroupBoxStyle()) diff --git a/Tests/ViewInspectorTests/SwiftUI/TextAttributesTests.swift b/Tests/ViewInspectorTests/SwiftUI/TextAttributesTests.swift index 0803bebb..7c3ca74d 100644 --- a/Tests/ViewInspectorTests/SwiftUI/TextAttributesTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/TextAttributesTests.swift @@ -96,7 +96,7 @@ final class TextAttributesTests: XCTestCase { let sut = try view.inspect().text().attributes() XCTAssertTrue(try sut.isStrikethrough()) XCTAssertEqual(try sut.strikethroughColor(), .black) - if #available(iOS 15.0, tvOS 15.0, macOS 11.6, *) { + if #available(iOS 15.0, tvOS 15.0, macOS 11.6, watchOS 8.0, *) { XCTAssertEqual(try sut.strikethroughStyle(), .single) } } @@ -106,7 +106,7 @@ final class TextAttributesTests: XCTestCase { let sut = try view.inspect().text().attributes() XCTAssertTrue(try sut.isUnderline()) XCTAssertEqual(try sut.underlineColor(), .black) - if #available(iOS 15.0, tvOS 15.0, macOS 11.6, *) { + if #available(iOS 15.0, tvOS 15.0, macOS 11.6, watchOS 8.0, *) { XCTAssertEqual(try sut.underlineStyle(), .single) } } From 7f27ebb984da91170080871a4a386470343e1d7f Mon Sep 17 00:00:00 2001 From: Alexey Naumov Date: Mon, 13 Sep 2021 21:00:20 +0300 Subject: [PATCH 64/99] Rename host watchOS app --- .../xcschemes/ViewInspector.xcscheme | 101 ------------------ .../{App-Info.plist => App-1-Info.plist} | 0 .../{Ext-Info.plist => Ext-1-Info.plist} | 0 .../{watchOSApp.swift => watchOSApp-1.swift} | 0 .watchOS/watchOS.xcodeproj/project.pbxproj | 68 ++++++------ ...OS-App.xcscheme => watchOS-App-1.xcscheme} | 6 +- 6 files changed, 37 insertions(+), 138 deletions(-) delete mode 100644 .swiftpm/xcode/xcshareddata/xcschemes/ViewInspector.xcscheme rename .watchOS/watchOS-App/{App-Info.plist => App-1-Info.plist} (100%) rename .watchOS/watchOS-Ext/{Ext-Info.plist => Ext-1-Info.plist} (100%) rename .watchOS/watchOS-Ext/{watchOSApp.swift => watchOSApp-1.swift} (100%) rename .watchOS/watchOS.xcodeproj/xcshareddata/xcschemes/{watchOS-App.xcscheme => watchOS-App-1.xcscheme} (96%) diff --git a/.swiftpm/xcode/xcshareddata/xcschemes/ViewInspector.xcscheme b/.swiftpm/xcode/xcshareddata/xcschemes/ViewInspector.xcscheme deleted file mode 100644 index 0cec304d..00000000 --- a/.swiftpm/xcode/xcshareddata/xcschemes/ViewInspector.xcscheme +++ /dev/null @@ -1,101 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/.watchOS/watchOS-App/App-Info.plist b/.watchOS/watchOS-App/App-1-Info.plist similarity index 100% rename from .watchOS/watchOS-App/App-Info.plist rename to .watchOS/watchOS-App/App-1-Info.plist diff --git a/.watchOS/watchOS-Ext/Ext-Info.plist b/.watchOS/watchOS-Ext/Ext-1-Info.plist similarity index 100% rename from .watchOS/watchOS-Ext/Ext-Info.plist rename to .watchOS/watchOS-Ext/Ext-1-Info.plist diff --git a/.watchOS/watchOS-Ext/watchOSApp.swift b/.watchOS/watchOS-Ext/watchOSApp-1.swift similarity index 100% rename from .watchOS/watchOS-Ext/watchOSApp.swift rename to .watchOS/watchOS-Ext/watchOSApp-1.swift diff --git a/.watchOS/watchOS.xcodeproj/project.pbxproj b/.watchOS/watchOS.xcodeproj/project.pbxproj index eb9e84f3..5bbfa177 100644 --- a/.watchOS/watchOS.xcodeproj/project.pbxproj +++ b/.watchOS/watchOS.xcodeproj/project.pbxproj @@ -133,8 +133,8 @@ 52CA301126ECC58B00BFD568 /* TransformingModifiersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F9526ECC58B00BFD568 /* TransformingModifiersTests.swift */; }; 52CA301426ECC5D200BFD568 /* ViewInspector in Frameworks */ = {isa = PBXBuildFile; productRef = 52CA301326ECC5D200BFD568 /* ViewInspector */; }; 52CA301626ECD64400BFD568 /* watchOSApp+Testable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA301526ECD64400BFD568 /* watchOSApp+Testable.swift */; }; - 52E3259B26C72E7900CCE47E /* watchOS-Ext.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 52E3259A26C72E7900CCE47E /* watchOS-Ext.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; - 52E325A226C72E7900CCE47E /* watchOSApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52E325A126C72E7900CCE47E /* watchOSApp.swift */; }; + 52E3259B26C72E7900CCE47E /* watchOS-Ext-1.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 52E3259A26C72E7900CCE47E /* watchOS-Ext-1.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; + 52E325A226C72E7900CCE47E /* watchOSApp-1.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52E325A126C72E7900CCE47E /* watchOSApp-1.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -161,7 +161,7 @@ dstPath = ""; dstSubfolderSpec = 13; files = ( - 52E3259B26C72E7900CCE47E /* watchOS-Ext.appex in Embed App Extensions */, + 52E3259B26C72E7900CCE47E /* watchOS-Ext-1.appex in Embed App Extensions */, ); name = "Embed App Extensions"; runOnlyForDeploymentPostprocessing = 0; @@ -298,11 +298,11 @@ 52CA2F9426ECC58B00BFD568 /* ViewPaddingTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewPaddingTests.swift; sourceTree = ""; }; 52CA2F9526ECC58B00BFD568 /* TransformingModifiersTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TransformingModifiersTests.swift; sourceTree = ""; }; 52CA301526ECD64400BFD568 /* watchOSApp+Testable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "watchOSApp+Testable.swift"; sourceTree = ""; }; - 52E3258E26C72E7800CCE47E /* watchOS-App.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "watchOS-App.app"; sourceTree = BUILT_PRODUCTS_DIR; }; - 52E3259526C72E7900CCE47E /* App-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "App-Info.plist"; sourceTree = ""; }; - 52E3259A26C72E7900CCE47E /* watchOS-Ext.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = "watchOS-Ext.appex"; sourceTree = BUILT_PRODUCTS_DIR; }; - 52E325A126C72E7900CCE47E /* watchOSApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = watchOSApp.swift; sourceTree = ""; }; - 52E325AA26C72E7900CCE47E /* Ext-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Ext-Info.plist"; sourceTree = ""; }; + 52E3258E26C72E7800CCE47E /* watchOS-App-1.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "watchOS-App-1.app"; sourceTree = BUILT_PRODUCTS_DIR; }; + 52E3259526C72E7900CCE47E /* App-1-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "App-1-Info.plist"; sourceTree = ""; }; + 52E3259A26C72E7900CCE47E /* watchOS-Ext-1.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = "watchOS-Ext-1.appex"; sourceTree = BUILT_PRODUCTS_DIR; }; + 52E325A126C72E7900CCE47E /* watchOSApp-1.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "watchOSApp-1.swift"; sourceTree = ""; }; + 52E325AA26C72E7900CCE47E /* Ext-1-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Ext-1-Info.plist"; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -534,8 +534,8 @@ 52E3258B26C72E7800CCE47E /* Products */ = { isa = PBXGroup; children = ( - 52E3258E26C72E7800CCE47E /* watchOS-App.app */, - 52E3259A26C72E7900CCE47E /* watchOS-Ext.appex */, + 52E3258E26C72E7800CCE47E /* watchOS-App-1.app */, + 52E3259A26C72E7900CCE47E /* watchOS-Ext-1.appex */, 520213A426ECB45D00E94C6E /* watchOS-Tests.xctest */, ); name = Products; @@ -544,7 +544,7 @@ 52E3259226C72E7800CCE47E /* watchOS-App */ = { isa = PBXGroup; children = ( - 52E3259526C72E7900CCE47E /* App-Info.plist */, + 52E3259526C72E7900CCE47E /* App-1-Info.plist */, ); path = "watchOS-App"; sourceTree = ""; @@ -552,9 +552,9 @@ 52E3259E26C72E7900CCE47E /* watchOS-Ext */ = { isa = PBXGroup; children = ( - 52E325A126C72E7900CCE47E /* watchOSApp.swift */, + 52E325A126C72E7900CCE47E /* watchOSApp-1.swift */, 52CA301526ECD64400BFD568 /* watchOSApp+Testable.swift */, - 52E325AA26C72E7900CCE47E /* Ext-Info.plist */, + 52E325AA26C72E7900CCE47E /* Ext-1-Info.plist */, ); path = "watchOS-Ext"; sourceTree = ""; @@ -583,9 +583,9 @@ productReference = 520213A426ECB45D00E94C6E /* watchOS-Tests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; - 52E3258D26C72E7800CCE47E /* watchOS-App */ = { + 52E3258D26C72E7800CCE47E /* watchOS-App-1 */ = { isa = PBXNativeTarget; - buildConfigurationList = 52E325B126C72E7900CCE47E /* Build configuration list for PBXNativeTarget "watchOS-App" */; + buildConfigurationList = 52E325B126C72E7900CCE47E /* Build configuration list for PBXNativeTarget "watchOS-App-1" */; buildPhases = ( 52E3258C26C72E7800CCE47E /* Resources */, 52E325B026C72E7900CCE47E /* Embed App Extensions */, @@ -595,14 +595,14 @@ dependencies = ( 52E3259D26C72E7900CCE47E /* PBXTargetDependency */, ); - name = "watchOS-App"; + name = "watchOS-App-1"; productName = "watchOS WatchKit App"; - productReference = 52E3258E26C72E7800CCE47E /* watchOS-App.app */; + productReference = 52E3258E26C72E7800CCE47E /* watchOS-App-1.app */; productType = "com.apple.product-type.application.watchapp2"; }; - 52E3259926C72E7900CCE47E /* watchOS-Ext */ = { + 52E3259926C72E7900CCE47E /* watchOS-Ext-1 */ = { isa = PBXNativeTarget; - buildConfigurationList = 52E325AD26C72E7900CCE47E /* Build configuration list for PBXNativeTarget "watchOS-Ext" */; + buildConfigurationList = 52E325AD26C72E7900CCE47E /* Build configuration list for PBXNativeTarget "watchOS-Ext-1" */; buildPhases = ( 52E3259626C72E7900CCE47E /* Sources */, 52E3259726C72E7900CCE47E /* Frameworks */, @@ -612,9 +612,9 @@ ); dependencies = ( ); - name = "watchOS-Ext"; + name = "watchOS-Ext-1"; productName = "watchOS WatchKit Extension"; - productReference = 52E3259A26C72E7900CCE47E /* watchOS-Ext.appex */; + productReference = 52E3259A26C72E7900CCE47E /* watchOS-Ext-1.appex */; productType = "com.apple.product-type.watchkit2-extension"; }; /* End PBXNativeTarget section */ @@ -653,8 +653,8 @@ projectDirPath = ""; projectRoot = ""; targets = ( - 52E3258D26C72E7800CCE47E /* watchOS-App */, - 52E3259926C72E7900CCE47E /* watchOS-Ext */, + 52E3258D26C72E7800CCE47E /* watchOS-App-1 */, + 52E3259926C72E7900CCE47E /* watchOS-Ext-1 */, 520213A326ECB45D00E94C6E /* watchOS-Tests */, ); }; @@ -820,7 +820,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 52E325A226C72E7900CCE47E /* watchOSApp.swift in Sources */, + 52E325A226C72E7900CCE47E /* watchOSApp-1.swift in Sources */, 52CA301626ECD64400BFD568 /* watchOSApp+Testable.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -830,12 +830,12 @@ /* Begin PBXTargetDependency section */ 520213A926ECB45D00E94C6E /* PBXTargetDependency */ = { isa = PBXTargetDependency; - target = 52E3259926C72E7900CCE47E /* watchOS-Ext */; + target = 52E3259926C72E7900CCE47E /* watchOS-Ext-1 */; targetProxy = 520213A826ECB45D00E94C6E /* PBXContainerItemProxy */; }; 52E3259D26C72E7900CCE47E /* PBXTargetDependency */ = { isa = PBXTargetDependency; - target = 52E3259926C72E7900CCE47E /* watchOS-Ext */; + target = 52E3259926C72E7900CCE47E /* watchOS-Ext-1 */; targetProxy = 52E3259C26C72E7900CCE47E /* PBXContainerItemProxy */; }; /* End PBXTargetDependency section */ @@ -873,7 +873,7 @@ SDKROOT = watchos; SWIFT_EMIT_LOC_STRINGS = NO; SWIFT_VERSION = 5.0; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/watchOS-Ext.appex/watchOS-Ext"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/watchOS-Ext-1.appex/watchOS-Ext-1"; }; name = Debug; }; @@ -896,7 +896,7 @@ SDKROOT = watchos; SWIFT_EMIT_LOC_STRINGS = NO; SWIFT_VERSION = 5.0; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/watchOS-Ext.appex/watchOS-Ext"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/watchOS-Ext-1.appex/watchOS-Ext-1"; }; name = Release; }; @@ -1025,7 +1025,7 @@ buildSettings = { CODE_SIGN_STYLE = Automatic; ENABLE_PREVIEWS = YES; - INFOPLIST_FILE = "$(SRCROOT)/watchOS-Ext/Ext-Info.plist"; + INFOPLIST_FILE = "$(SRCROOT)/watchOS-Ext/Ext-1-Info.plist"; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -1044,7 +1044,7 @@ buildSettings = { CODE_SIGN_STYLE = Automatic; ENABLE_PREVIEWS = YES; - INFOPLIST_FILE = "$(SRCROOT)/watchOS-Ext/Ext-Info.plist"; + INFOPLIST_FILE = "$(SRCROOT)/watchOS-Ext/Ext-1-Info.plist"; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -1066,7 +1066,7 @@ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_STYLE = Automatic; IBSC_MODULE = watchOS_WatchKit_Extension; - INFOPLIST_FILE = "watchOS-App/App-Info.plist"; + INFOPLIST_FILE = "watchOS-App/App-1-Info.plist"; PRODUCT_BUNDLE_IDENTIFIER = com.viewinspector.watchOS.watchkitapp; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = watchos; @@ -1083,7 +1083,7 @@ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_STYLE = Automatic; IBSC_MODULE = watchOS_WatchKit_Extension; - INFOPLIST_FILE = "watchOS-App/App-Info.plist"; + INFOPLIST_FILE = "watchOS-App/App-1-Info.plist"; PRODUCT_BUNDLE_IDENTIFIER = com.viewinspector.watchOS.watchkitapp; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = watchos; @@ -1113,7 +1113,7 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 52E325AD26C72E7900CCE47E /* Build configuration list for PBXNativeTarget "watchOS-Ext" */ = { + 52E325AD26C72E7900CCE47E /* Build configuration list for PBXNativeTarget "watchOS-Ext-1" */ = { isa = XCConfigurationList; buildConfigurations = ( 52E325AE26C72E7900CCE47E /* Debug */, @@ -1122,7 +1122,7 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 52E325B126C72E7900CCE47E /* Build configuration list for PBXNativeTarget "watchOS-App" */ = { + 52E325B126C72E7900CCE47E /* Build configuration list for PBXNativeTarget "watchOS-App-1" */ = { isa = XCConfigurationList; buildConfigurations = ( 52E325B226C72E7900CCE47E /* Debug */, diff --git a/.watchOS/watchOS.xcodeproj/xcshareddata/xcschemes/watchOS-App.xcscheme b/.watchOS/watchOS.xcodeproj/xcshareddata/xcschemes/watchOS-App-1.xcscheme similarity index 96% rename from .watchOS/watchOS.xcodeproj/xcshareddata/xcschemes/watchOS-App.xcscheme rename to .watchOS/watchOS.xcodeproj/xcshareddata/xcschemes/watchOS-App-1.xcscheme index 66f9d572..463014ce 100644 --- a/.watchOS/watchOS.xcodeproj/xcshareddata/xcschemes/watchOS-App.xcscheme +++ b/.watchOS/watchOS.xcodeproj/xcshareddata/xcschemes/watchOS-App-1.xcscheme @@ -16,7 +16,7 @@ BuildableIdentifier = "primary" BlueprintIdentifier = "52E3258D26C72E7800CCE47E" BuildableName = "watchOS-App.app" - BlueprintName = "watchOS-App" + BlueprintName = "watchOS-App-1" ReferencedContainer = "container:watchOS.xcodeproj"> @@ -70,7 +70,7 @@ BuildableIdentifier = "primary" BlueprintIdentifier = "52E3258D26C72E7800CCE47E" BuildableName = "watchOS-App.app" - BlueprintName = "watchOS-App" + BlueprintName = "watchOS-App-1" ReferencedContainer = "container:watchOS.xcodeproj"> @@ -86,7 +86,7 @@ BuildableIdentifier = "primary" BlueprintIdentifier = "52E3258D26C72E7800CCE47E" BuildableName = "watchOS-App.app" - BlueprintName = "watchOS-App" + BlueprintName = "watchOS-App-1" ReferencedContainer = "container:watchOS.xcodeproj"> From 63ed3bba09db24691b4222228c110d662f4a0adc Mon Sep 17 00:00:00 2001 From: Alexey Naumov Date: Sat, 18 Sep 2021 14:44:46 +0300 Subject: [PATCH 65/99] Add second watchOS target --- .watchOS/watchOS-App/App-1-Info.plist | 2 - .../Base.lproj/Interface.storyboard | 18 ++ .watchOS/watchOS-Ext/Ext-1-Info.plist | 4 +- .watchOS/watchOS-Ext/Ext-2-Info.plist | 16 ++ .watchOS/watchOS-Ext/watchOSApp-2.swift | 9 + .watchOS/watchOS.xcodeproj/project.pbxproj | 254 +++++++++++++++++- .../xcschemes/watchOS-App-1.xcscheme | 6 +- .../xcschemes/watchOS-App-2.xcscheme | 101 +++++++ 8 files changed, 394 insertions(+), 16 deletions(-) create mode 100644 .watchOS/watchOS-App/Base.lproj/Interface.storyboard create mode 100644 .watchOS/watchOS-Ext/Ext-2-Info.plist create mode 100644 .watchOS/watchOS-Ext/watchOSApp-2.swift create mode 100644 .watchOS/watchOS.xcodeproj/xcshareddata/xcschemes/watchOS-App-2.xcscheme diff --git a/.watchOS/watchOS-App/App-1-Info.plist b/.watchOS/watchOS-App/App-1-Info.plist index 7b67af9c..1ec145d8 100644 --- a/.watchOS/watchOS-App/App-1-Info.plist +++ b/.watchOS/watchOS-App/App-1-Info.plist @@ -4,8 +4,6 @@ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) - CFBundleDisplayName - watchOS-App CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier diff --git a/.watchOS/watchOS-App/Base.lproj/Interface.storyboard b/.watchOS/watchOS-App/Base.lproj/Interface.storyboard new file mode 100644 index 00000000..e7869ede --- /dev/null +++ b/.watchOS/watchOS-App/Base.lproj/Interface.storyboard @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/.watchOS/watchOS-Ext/Ext-1-Info.plist b/.watchOS/watchOS-Ext/Ext-1-Info.plist index a12d981d..d19652ef 100644 --- a/.watchOS/watchOS-Ext/Ext-1-Info.plist +++ b/.watchOS/watchOS-Ext/Ext-1-Info.plist @@ -4,8 +4,6 @@ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) - CFBundleDisplayName - watchOS-Ext CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier @@ -25,7 +23,7 @@ NSExtensionAttributes WKAppBundleIdentifier - com.viewinspector.watchOS.watchkitapp + com.viewinspector.watchOS1.watchkitapp NSExtensionPointIdentifier com.apple.watchkit diff --git a/.watchOS/watchOS-Ext/Ext-2-Info.plist b/.watchOS/watchOS-Ext/Ext-2-Info.plist new file mode 100644 index 00000000..e253fffe --- /dev/null +++ b/.watchOS/watchOS-Ext/Ext-2-Info.plist @@ -0,0 +1,16 @@ + + + + + NSExtension + + NSExtensionAttributes + + WKAppBundleIdentifier + com.viewinspector.watchOS2.watchkitapp + + NSExtensionPointIdentifier + com.apple.watchkit + + + diff --git a/.watchOS/watchOS-Ext/watchOSApp-2.swift b/.watchOS/watchOS-Ext/watchOSApp-2.swift new file mode 100644 index 00000000..9e337c0f --- /dev/null +++ b/.watchOS/watchOS-Ext/watchOSApp-2.swift @@ -0,0 +1,9 @@ +import WatchKit + +final class RootInterfaceController: WKInterfaceController { + +} + +final class ExtensionDelegate: NSObject, WKExtensionDelegate { + +} diff --git a/.watchOS/watchOS.xcodeproj/project.pbxproj b/.watchOS/watchOS.xcodeproj/project.pbxproj index 5bbfa177..cb346adf 100644 --- a/.watchOS/watchOS.xcodeproj/project.pbxproj +++ b/.watchOS/watchOS.xcodeproj/project.pbxproj @@ -7,6 +7,9 @@ objects = { /* Begin PBXBuildFile section */ + 5293010626EFC96600012E90 /* Interface.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5293010426EFC96600012E90 /* Interface.storyboard */; }; + 5293010E26EFC96700012E90 /* watchOS-Ext-2.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 5293010D26EFC96700012E90 /* watchOS-Ext-2.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; + 5293012726EFCBD300012E90 /* watchOSApp-2.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5293011426EFC96700012E90 /* watchOSApp-2.swift */; }; 52CA2F9626ECC58B00BFD568 /* LazyGroupTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F1226ECC58B00BFD568 /* LazyGroupTests.swift */; }; 52CA2F9726ECC58B00BFD568 /* ViewHostingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F1326ECC58B00BFD568 /* ViewHostingTests.swift */; }; 52CA2F9826ECC58B00BFD568 /* InspectionEmissaryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F1426ECC58B00BFD568 /* InspectionEmissaryTests.swift */; }; @@ -145,6 +148,13 @@ remoteGlobalIDString = 52E3259926C72E7900CCE47E; remoteInfo = "watchOS-Ext"; }; + 5293010F26EFC96700012E90 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 52E3258426C72E7800CCE47E /* Project object */; + proxyType = 1; + remoteGlobalIDString = 5293010C26EFC96700012E90; + remoteInfo = "watchOSApp-2 WatchKit Extension"; + }; 52E3259C26C72E7900CCE47E /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 52E3258426C72E7800CCE47E /* Project object */; @@ -155,6 +165,17 @@ /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ + 5293011E26EFC96800012E90 /* Embed App Extensions */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 13; + files = ( + 5293010E26EFC96700012E90 /* watchOS-Ext-2.appex in Embed App Extensions */, + ); + name = "Embed App Extensions"; + runOnlyForDeploymentPostprocessing = 0; + }; 52E325B026C72E7900CCE47E /* Embed App Extensions */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; @@ -170,6 +191,11 @@ /* Begin PBXFileReference section */ 520213A426ECB45D00E94C6E /* watchOS-Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "watchOS-Tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; + 529300FF26EFC96600012E90 /* watchOS-App-2.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "watchOS-App-2.app"; sourceTree = BUILT_PRODUCTS_DIR; }; + 5293010526EFC96600012E90 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Interface.storyboard; sourceTree = ""; }; + 5293010D26EFC96700012E90 /* watchOS-Ext-2.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = "watchOS-Ext-2.appex"; sourceTree = BUILT_PRODUCTS_DIR; }; + 5293011426EFC96700012E90 /* watchOSApp-2.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "watchOSApp-2.swift"; sourceTree = ""; }; + 5293011A26EFC96800012E90 /* Ext-2-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Ext-2-Info.plist"; sourceTree = ""; }; 52CA2F1026ECC56600BFD568 /* ViewInspector */ = {isa = PBXFileReference; lastKnownFileType = folder; name = ViewInspector; path = ..; sourceTree = ""; }; 52CA2F1226ECC58B00BFD568 /* LazyGroupTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LazyGroupTests.swift; sourceTree = ""; }; 52CA2F1326ECC58B00BFD568 /* ViewHostingTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewHostingTests.swift; sourceTree = ""; }; @@ -314,6 +340,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 5293010A26EFC96700012E90 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; 52E3259726C72E7900CCE47E /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -537,6 +570,8 @@ 52E3258E26C72E7800CCE47E /* watchOS-App-1.app */, 52E3259A26C72E7900CCE47E /* watchOS-Ext-1.appex */, 520213A426ECB45D00E94C6E /* watchOS-Tests.xctest */, + 529300FF26EFC96600012E90 /* watchOS-App-2.app */, + 5293010D26EFC96700012E90 /* watchOS-Ext-2.appex */, ); name = Products; sourceTree = ""; @@ -545,6 +580,7 @@ isa = PBXGroup; children = ( 52E3259526C72E7900CCE47E /* App-1-Info.plist */, + 5293010426EFC96600012E90 /* Interface.storyboard */, ); path = "watchOS-App"; sourceTree = ""; @@ -553,8 +589,10 @@ isa = PBXGroup; children = ( 52E325A126C72E7900CCE47E /* watchOSApp-1.swift */, + 5293011426EFC96700012E90 /* watchOSApp-2.swift */, 52CA301526ECD64400BFD568 /* watchOSApp+Testable.swift */, 52E325AA26C72E7900CCE47E /* Ext-1-Info.plist */, + 5293011A26EFC96800012E90 /* Ext-2-Info.plist */, ); path = "watchOS-Ext"; sourceTree = ""; @@ -583,6 +621,40 @@ productReference = 520213A426ECB45D00E94C6E /* watchOS-Tests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; + 529300FE26EFC96600012E90 /* watchOS-App-2 */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5293011F26EFC96800012E90 /* Build configuration list for PBXNativeTarget "watchOS-App-2" */; + buildPhases = ( + 529300FD26EFC96600012E90 /* Resources */, + 5293011E26EFC96800012E90 /* Embed App Extensions */, + ); + buildRules = ( + ); + dependencies = ( + 5293011026EFC96700012E90 /* PBXTargetDependency */, + ); + name = "watchOS-App-2"; + productName = "watchOSApp-2 WatchKit App"; + productReference = 529300FF26EFC96600012E90 /* watchOS-App-2.app */; + productType = "com.apple.product-type.application.watchapp2"; + }; + 5293010C26EFC96700012E90 /* watchOS-Ext-2 */ = { + isa = PBXNativeTarget; + buildConfigurationList = 5293011B26EFC96800012E90 /* Build configuration list for PBXNativeTarget "watchOS-Ext-2" */; + buildPhases = ( + 5293010926EFC96700012E90 /* Sources */, + 5293010A26EFC96700012E90 /* Frameworks */, + 5293010B26EFC96700012E90 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "watchOS-Ext-2"; + productName = "watchOSApp-2 WatchKit Extension"; + productReference = 5293010D26EFC96700012E90 /* watchOS-Ext-2.appex */; + productType = "com.apple.product-type.watchkit2-extension"; + }; 52E3258D26C72E7800CCE47E /* watchOS-App-1 */ = { isa = PBXNativeTarget; buildConfigurationList = 52E325B126C72E7900CCE47E /* Build configuration list for PBXNativeTarget "watchOS-App-1" */; @@ -630,6 +702,12 @@ CreatedOnToolsVersion = 13.0; TestTargetID = 52E3259926C72E7900CCE47E; }; + 529300FE26EFC96600012E90 = { + CreatedOnToolsVersion = 13.0; + }; + 5293010C26EFC96700012E90 = { + CreatedOnToolsVersion = 13.0; + }; 52E3258D26C72E7800CCE47E = { CreatedOnToolsVersion = 12.5.1; }; @@ -654,7 +732,9 @@ projectRoot = ""; targets = ( 52E3258D26C72E7800CCE47E /* watchOS-App-1 */, + 529300FE26EFC96600012E90 /* watchOS-App-2 */, 52E3259926C72E7900CCE47E /* watchOS-Ext-1 */, + 5293010C26EFC96700012E90 /* watchOS-Ext-2 */, 520213A326ECB45D00E94C6E /* watchOS-Tests */, ); }; @@ -669,6 +749,21 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 529300FD26EFC96600012E90 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5293010626EFC96600012E90 /* Interface.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 5293010B26EFC96700012E90 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; 52E3258C26C72E7800CCE47E /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -816,6 +911,14 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 5293010926EFC96700012E90 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 5293012726EFCBD300012E90 /* watchOSApp-2.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 52E3259626C72E7900CCE47E /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -833,6 +936,11 @@ target = 52E3259926C72E7900CCE47E /* watchOS-Ext-1 */; targetProxy = 520213A826ECB45D00E94C6E /* PBXContainerItemProxy */; }; + 5293011026EFC96700012E90 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 5293010C26EFC96700012E90 /* watchOS-Ext-2 */; + targetProxy = 5293010F26EFC96700012E90 /* PBXContainerItemProxy */; + }; 52E3259D26C72E7900CCE47E /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 52E3259926C72E7900CCE47E /* watchOS-Ext-1 */; @@ -841,6 +949,14 @@ /* End PBXTargetDependency section */ /* Begin PBXVariantGroup section */ + 5293010426EFC96600012E90 /* Interface.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 5293010526EFC96600012E90 /* Base */, + ); + name = Interface.storyboard; + sourceTree = ""; + }; 52CA2F3126ECC58B00BFD568 /* Test.strings */ = { isa = PBXVariantGroup; children = ( @@ -900,6 +1016,104 @@ }; name = Release; }; + 5293011C26EFC96800012E90 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = "$(SRCROOT)/watchOS-Ext/Ext-2-Info.plist"; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + INFOPLIST_KEY_WKExtensionDelegateClassName = watchOS_Ext_2.ExtensionDelegate; + INFOPLIST_KEY_WKWatchOnly = YES; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@executable_path/../../Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.viewinspector.watchOS2.watchkitapp.watchkitextension; + PRODUCT_NAME = "${TARGET_NAME}"; + SDKROOT = watchos; + SKIP_INSTALL = YES; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = 4; + }; + name = Debug; + }; + 5293011D26EFC96800012E90 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = "$(SRCROOT)/watchOS-Ext/Ext-2-Info.plist"; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + INFOPLIST_KEY_WKExtensionDelegateClassName = watchOS_Ext_2.ExtensionDelegate; + INFOPLIST_KEY_WKWatchOnly = YES; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@executable_path/../../Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.viewinspector.watchOS2.watchkitapp.watchkitextension; + PRODUCT_NAME = "${TARGET_NAME}"; + SDKROOT = watchos; + SKIP_INSTALL = YES; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = 4; + }; + name = Release; + }; + 5293012026EFC96800012E90 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + IBSC_MODULE = watchOS_App_2; + INFOPLIST_KEY_UISupportedInterfaceOrientations = UIInterfaceOrientationPortrait; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.viewinspector.watchOS2.watchkitapp; + PRODUCT_NAME = "${TARGET_NAME}"; + SDKROOT = watchos; + SKIP_INSTALL = YES; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 5293012126EFC96800012E90 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + IBSC_MODULE = watchOS_App_2; + INFOPLIST_KEY_UISupportedInterfaceOrientations = UIInterfaceOrientationPortrait; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.viewinspector.watchOS2.watchkitapp; + PRODUCT_NAME = "${TARGET_NAME}"; + SDKROOT = watchos; + SKIP_INSTALL = YES; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; 52E325AB26C72E7900CCE47E /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -1024,6 +1238,7 @@ isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1.0; ENABLE_PREVIEWS = YES; INFOPLIST_FILE = "$(SRCROOT)/watchOS-Ext/Ext-1-Info.plist"; LD_RUNPATH_SEARCH_PATHS = ( @@ -1031,7 +1246,8 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = com.viewinspector.watchOS.watchkitapp.watchkitextension; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.viewinspector.watchOS1.watchkitapp.watchkitextension; PRODUCT_NAME = "${TARGET_NAME}"; SDKROOT = watchos; SKIP_INSTALL = YES; @@ -1043,6 +1259,7 @@ isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1.0; ENABLE_PREVIEWS = YES; INFOPLIST_FILE = "$(SRCROOT)/watchOS-Ext/Ext-1-Info.plist"; LD_RUNPATH_SEARCH_PATHS = ( @@ -1050,7 +1267,8 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = com.viewinspector.watchOS.watchkitapp.watchkitextension; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.viewinspector.watchOS1.watchkitapp.watchkitextension; PRODUCT_NAME = "${TARGET_NAME}"; SDKROOT = watchos; SKIP_INSTALL = YES; @@ -1065,9 +1283,10 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_STYLE = Automatic; - IBSC_MODULE = watchOS_WatchKit_Extension; - INFOPLIST_FILE = "watchOS-App/App-1-Info.plist"; - PRODUCT_BUNDLE_IDENTIFIER = com.viewinspector.watchOS.watchkitapp; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.viewinspector.watchOS1.watchkitapp; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = watchos; SKIP_INSTALL = YES; @@ -1082,9 +1301,10 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_STYLE = Automatic; - IBSC_MODULE = watchOS_WatchKit_Extension; - INFOPLIST_FILE = "watchOS-App/App-1-Info.plist"; - PRODUCT_BUNDLE_IDENTIFIER = com.viewinspector.watchOS.watchkitapp; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.viewinspector.watchOS1.watchkitapp; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = watchos; SKIP_INSTALL = YES; @@ -1104,6 +1324,24 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + 5293011B26EFC96800012E90 /* Build configuration list for PBXNativeTarget "watchOS-Ext-2" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5293011C26EFC96800012E90 /* Debug */, + 5293011D26EFC96800012E90 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 5293011F26EFC96800012E90 /* Build configuration list for PBXNativeTarget "watchOS-App-2" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 5293012026EFC96800012E90 /* Debug */, + 5293012126EFC96800012E90 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; 52E3258726C72E7800CCE47E /* Build configuration list for PBXProject "watchOS" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/.watchOS/watchOS.xcodeproj/xcshareddata/xcschemes/watchOS-App-1.xcscheme b/.watchOS/watchOS.xcodeproj/xcshareddata/xcschemes/watchOS-App-1.xcscheme index 463014ce..efe371a2 100644 --- a/.watchOS/watchOS.xcodeproj/xcshareddata/xcschemes/watchOS-App-1.xcscheme +++ b/.watchOS/watchOS.xcodeproj/xcshareddata/xcschemes/watchOS-App-1.xcscheme @@ -15,7 +15,7 @@ @@ -69,7 +69,7 @@ @@ -85,7 +85,7 @@ diff --git a/.watchOS/watchOS.xcodeproj/xcshareddata/xcschemes/watchOS-App-2.xcscheme b/.watchOS/watchOS.xcodeproj/xcshareddata/xcschemes/watchOS-App-2.xcscheme new file mode 100644 index 00000000..bf959b3b --- /dev/null +++ b/.watchOS/watchOS.xcodeproj/xcshareddata/xcschemes/watchOS-App-2.xcscheme @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 3e21cc6db5c3893de27501edab53b7ff1ec6d116 Mon Sep 17 00:00:00 2001 From: Alexey Naumov Date: Sat, 18 Sep 2021 15:00:46 +0300 Subject: [PATCH 66/99] Re-add tests --- .watchOS/watchOS.xcodeproj/project.pbxproj | 1056 ++++++++--------- .../xcschemes/watchOS-App-2.xcscheme | 9 - 2 files changed, 528 insertions(+), 537 deletions(-) diff --git a/.watchOS/watchOS.xcodeproj/project.pbxproj b/.watchOS/watchOS.xcodeproj/project.pbxproj index cb346adf..befb085b 100644 --- a/.watchOS/watchOS.xcodeproj/project.pbxproj +++ b/.watchOS/watchOS.xcodeproj/project.pbxproj @@ -7,133 +7,133 @@ objects = { /* Begin PBXBuildFile section */ + 520DC60F26F60FBA00FCFFFD /* LazyGroupTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC58B26F60FBA00FCFFFD /* LazyGroupTests.swift */; }; + 520DC61026F60FBA00FCFFFD /* ViewHostingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC58C26F60FBA00FCFFFD /* ViewHostingTests.swift */; }; + 520DC61126F60FBA00FCFFFD /* InspectionEmissaryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC58D26F60FBA00FCFFFD /* InspectionEmissaryTests.swift */; }; + 520DC61226F60FBA00FCFFFD /* BaseTypesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC58E26F60FBA00FCFFFD /* BaseTypesTests.swift */; }; + 520DC61326F60FBA00FCFFFD /* ViewSearchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC58F26F60FBA00FCFFFD /* ViewSearchTests.swift */; }; + 520DC61426F60FBA00FCFFFD /* HitTestingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC59226F60FBA00FCFFFD /* HitTestingTests.swift */; }; + 520DC61526F60FBA00FCFFFD /* GestureModifierTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC59326F60FBA00FCFFFD /* GestureModifierTests.swift */; }; + 520DC61626F60FBA00FCFFFD /* GestureActionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC59426F60FBA00FCFFFD /* GestureActionTests.swift */; }; + 520DC61726F60FBA00FCFFFD /* HighPriorityGestureModifierTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC59526F60FBA00FCFFFD /* HighPriorityGestureModifierTests.swift */; }; + 520DC61826F60FBA00FCFFFD /* SimultaneousGestureModifierTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC59626F60FBA00FCFFFD /* SimultaneousGestureModifierTests.swift */; }; + 520DC61926F60FBA00FCFFFD /* ComposedGestureExampleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC59726F60FBA00FCFFFD /* ComposedGestureExampleTests.swift */; }; + 520DC61A26F60FBA00FCFFFD /* SequenceGestureChildrenTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC59826F60FBA00FCFFFD /* SequenceGestureChildrenTests.swift */; }; + 520DC61B26F60FBA00FCFFFD /* RotationGestureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC59926F60FBA00FCFFFD /* RotationGestureTests.swift */; }; + 520DC61C26F60FBA00FCFFFD /* ExclusiveGestureChildrenTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC59A26F60FBA00FCFFFD /* ExclusiveGestureChildrenTests.swift */; }; + 520DC61D26F60FBA00FCFFFD /* TapGestureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC59B26F60FBA00FCFFFD /* TapGestureTests.swift */; }; + 520DC61E26F60FBA00FCFFFD /* ExclusiveGestureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC59C26F60FBA00FCFFFD /* ExclusiveGestureTests.swift */; }; + 520DC61F26F60FBA00FCFFFD /* SimultaneousGestureChildrenTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC59D26F60FBA00FCFFFD /* SimultaneousGestureChildrenTests.swift */; }; + 520DC62026F60FBA00FCFFFD /* SequenceGestureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC59E26F60FBA00FCFFFD /* SequenceGestureTests.swift */; }; + 520DC62126F60FBA00FCFFFD /* GestureExampleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC59F26F60FBA00FCFFFD /* GestureExampleTests.swift */; }; + 520DC62226F60FBA00FCFFFD /* DragGestureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5A026F60FBA00FCFFFD /* DragGestureTests.swift */; }; + 520DC62326F60FBA00FCFFFD /* CommonComposedGestureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5A126F60FBA00FCFFFD /* CommonComposedGestureTests.swift */; }; + 520DC62426F60FBA00FCFFFD /* CommonComposedGestureUpdatingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5A226F60FBA00FCFFFD /* CommonComposedGestureUpdatingTests.swift */; }; + 520DC62526F60FBB00FCFFFD /* SimultaneousGestureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5A326F60FBA00FCFFFD /* SimultaneousGestureTests.swift */; }; + 520DC62626F60FBB00FCFFFD /* CommonComposedGestureEndedTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5A426F60FBA00FCFFFD /* CommonComposedGestureEndedTests.swift */; }; + 520DC62726F60FBB00FCFFFD /* CommonComposedGestureChangedTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5A526F60FBA00FCFFFD /* CommonComposedGestureChangedTests.swift */; }; + 520DC62826F60FBB00FCFFFD /* LongPressGestureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5A626F60FBA00FCFFFD /* LongPressGestureTests.swift */; }; + 520DC62926F60FBB00FCFFFD /* CommonGestureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5A726F60FBA00FCFFFD /* CommonGestureTests.swift */; }; + 520DC62A26F60FBB00FCFFFD /* MagnificationGestureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5A826F60FBA00FCFFFD /* MagnificationGestureTests.swift */; }; + 520DC62B26F60FBB00FCFFFD /* Test.strings in Resources */ = {isa = PBXBuildFile; fileRef = 520DC5AA26F60FBA00FCFFFD /* Test.strings */; }; + 520DC62C26F60FBB00FCFFFD /* InspectableViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5AE26F60FBA00FCFFFD /* InspectableViewTests.swift */; }; + 520DC62D26F60FBB00FCFFFD /* InspectorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5AF26F60FBA00FCFFFD /* InspectorTests.swift */; }; + 520DC62E26F60FBB00FCFFFD /* ZStackTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5B126F60FBA00FCFFFD /* ZStackTests.swift */; }; + 520DC62F26F60FBB00FCFFFD /* OptionalViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5B226F60FBA00FCFFFD /* OptionalViewTests.swift */; }; + 520DC63026F60FBB00FCFFFD /* MenuButtonTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5B326F60FBA00FCFFFD /* MenuButtonTests.swift */; }; + 520DC63126F60FBB00FCFFFD /* TouchBarTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5B426F60FBA00FCFFFD /* TouchBarTests.swift */; }; + 520DC63226F60FBB00FCFFFD /* GroupBoxTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5B526F60FBA00FCFFFD /* GroupBoxTests.swift */; }; + 520DC63326F60FBB00FCFFFD /* SheetTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5B626F60FBA00FCFFFD /* SheetTests.swift */; }; + 520DC63426F60FBB00FCFFFD /* RadialGradientTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5B726F60FBA00FCFFFD /* RadialGradientTests.swift */; }; + 520DC63526F60FBB00FCFFFD /* ScrollViewReaderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5B826F60FBA00FCFFFD /* ScrollViewReaderTests.swift */; }; + 520DC63626F60FBB00FCFFFD /* MapTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5B926F60FBA00FCFFFD /* MapTests.swift */; }; + 520DC63726F60FBB00FCFFFD /* SubscriptionViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5BA26F60FBA00FCFFFD /* SubscriptionViewTests.swift */; }; + 520DC63826F60FBB00FCFFFD /* MenuTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5BB26F60FBA00FCFFFD /* MenuTests.swift */; }; + 520DC63926F60FBB00FCFFFD /* LabelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5BC26F60FBA00FCFFFD /* LabelTests.swift */; }; + 520DC63A26F60FBB00FCFFFD /* TextTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5BD26F60FBA00FCFFFD /* TextTests.swift */; }; + 520DC63B26F60FBB00FCFFFD /* OpaqueViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5BE26F60FBA00FCFFFD /* OpaqueViewTests.swift */; }; + 520DC63C26F60FBB00FCFFFD /* HStackTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5BF26F60FBA00FCFFFD /* HStackTests.swift */; }; + 520DC63D26F60FBB00FCFFFD /* TreeViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5C026F60FBA00FCFFFD /* TreeViewTests.swift */; }; + 520DC63E26F60FBB00FCFFFD /* EquatableViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5C126F60FBA00FCFFFD /* EquatableViewTests.swift */; }; + 520DC63F26F60FBB00FCFFFD /* LinearGradientTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5C226F60FBA00FCFFFD /* LinearGradientTests.swift */; }; + 520DC64026F60FBB00FCFFFD /* ToolbarTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5C326F60FBA00FCFFFD /* ToolbarTests.swift */; }; + 520DC64126F60FBB00FCFFFD /* DisclosureGroupTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5C426F60FBA00FCFFFD /* DisclosureGroupTests.swift */; }; + 520DC64226F60FBB00FCFFFD /* GeometryReaderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5C526F60FBA00FCFFFD /* GeometryReaderTests.swift */; }; + 520DC64326F60FBB00FCFFFD /* ProgressViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5C626F60FBA00FCFFFD /* ProgressViewTests.swift */; }; + 520DC64426F60FBB00FCFFFD /* EnvironmentObjectInjectionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5C726F60FBA00FCFFFD /* EnvironmentObjectInjectionTests.swift */; }; + 520DC64526F60FBB00FCFFFD /* TabViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5C826F60FBA00FCFFFD /* TabViewTests.swift */; }; + 520DC64626F60FBB00FCFFFD /* PopoverTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5C926F60FBA00FCFFFD /* PopoverTests.swift */; }; + 520DC64726F60FBB00FCFFFD /* EmptyViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5CA26F60FBA00FCFFFD /* EmptyViewTests.swift */; }; + 520DC64826F60FBB00FCFFFD /* CustomViewModifierTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5CB26F60FBA00FCFFFD /* CustomViewModifierTests.swift */; }; + 520DC64926F60FBB00FCFFFD /* ImageTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5CC26F60FBA00FCFFFD /* ImageTests.swift */; }; + 520DC64A26F60FBB00FCFFFD /* EnvironmentReaderViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5CD26F60FBA00FCFFFD /* EnvironmentReaderViewTests.swift */; }; + 520DC64B26F60FBB00FCFFFD /* StepperTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5CE26F60FBA00FCFFFD /* StepperTests.swift */; }; + 520DC64C26F60FBB00FCFFFD /* FormTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5CF26F60FBA00FCFFFD /* FormTests.swift */; }; + 520DC64D26F60FBB00FCFFFD /* TupleViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5D026F60FBA00FCFFFD /* TupleViewTests.swift */; }; + 520DC64E26F60FBB00FCFFFD /* ConfirmationDialogTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5D126F60FBA00FCFFFD /* ConfirmationDialogTests.swift */; }; + 520DC64F26F60FBB00FCFFFD /* LazyVGridTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5D226F60FBA00FCFFFD /* LazyVGridTests.swift */; }; + 520DC65026F60FBB00FCFFFD /* LazyHStackTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5D326F60FBA00FCFFFD /* LazyHStackTests.swift */; }; + 520DC65126F60FBB00FCFFFD /* AlertTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5D426F60FBA00FCFFFD /* AlertTests.swift */; }; + 520DC65226F60FBB00FCFFFD /* TextAttributesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5D526F60FBA00FCFFFD /* TextAttributesTests.swift */; }; + 520DC65326F60FBB00FCFFFD /* PasteButtonTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5D626F60FBA00FCFFFD /* PasteButtonTests.swift */; }; + 520DC65426F60FBB00FCFFFD /* DividerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5D726F60FBA00FCFFFD /* DividerTests.swift */; }; + 520DC65526F60FBB00FCFFFD /* ForEachTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5D826F60FBA00FCFFFD /* ForEachTests.swift */; }; + 520DC65626F60FBB00FCFFFD /* ActionSheetTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5D926F60FBA00FCFFFD /* ActionSheetTests.swift */; }; + 520DC65726F60FBB00FCFFFD /* DelayedPreferenceViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5DA26F60FBA00FCFFFD /* DelayedPreferenceViewTests.swift */; }; + 520DC65826F60FBB00FCFFFD /* ButtonTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5DB26F60FBA00FCFFFD /* ButtonTests.swift */; }; + 520DC65926F60FBB00FCFFFD /* LinkTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5DC26F60FBA00FCFFFD /* LinkTests.swift */; }; + 520DC65A26F60FBB00FCFFFD /* SliderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5DD26F60FBA00FCFFFD /* SliderTests.swift */; }; + 520DC65B26F60FBB00FCFFFD /* CustomViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5DE26F60FBA00FCFFFD /* CustomViewTests.swift */; }; + 520DC65C26F60FBB00FCFFFD /* ColorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5DF26F60FBA00FCFFFD /* ColorTests.swift */; }; + 520DC65D26F60FBB00FCFFFD /* TextEditorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5E026F60FBA00FCFFFD /* TextEditorTests.swift */; }; + 520DC65E26F60FBB00FCFFFD /* MapAnnotationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5E126F60FBA00FCFFFD /* MapAnnotationTests.swift */; }; + 520DC65F26F60FBB00FCFFFD /* AngularGradientTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5E226F60FBA00FCFFFD /* AngularGradientTests.swift */; }; + 520DC66026F60FBB00FCFFFD /* ConditionalContentTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5E326F60FBA00FCFFFD /* ConditionalContentTests.swift */; }; + 520DC66126F60FBB00FCFFFD /* VSplitViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5E426F60FBA00FCFFFD /* VSplitViewTests.swift */; }; + 520DC66226F60FBB00FCFFFD /* NavigationViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5E526F60FBA00FCFFFD /* NavigationViewTests.swift */; }; + 520DC66326F60FBB00FCFFFD /* EditButtonTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5E626F60FBA00FCFFFD /* EditButtonTests.swift */; }; + 520DC66426F60FBB00FCFFFD /* IDViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5E726F60FBA00FCFFFD /* IDViewTests.swift */; }; + 520DC66526F60FBB00FCFFFD /* CustomViewBuilderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5E826F60FBA00FCFFFD /* CustomViewBuilderTests.swift */; }; + 520DC66626F60FBB00FCFFFD /* TextFieldTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5E926F60FBA00FCFFFD /* TextFieldTests.swift */; }; + 520DC66726F60FBB00FCFFFD /* FullScreenCoverTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5EA26F60FBA00FCFFFD /* FullScreenCoverTests.swift */; }; + 520DC66826F60FBB00FCFFFD /* NavigationLinkTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5EB26F60FBA00FCFFFD /* NavigationLinkTests.swift */; }; + 520DC66926F60FBB00FCFFFD /* VStackTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5EC26F60FBA00FCFFFD /* VStackTests.swift */; }; + 520DC66A26F60FBB00FCFFFD /* PickerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5ED26F60FBA00FCFFFD /* PickerTests.swift */; }; + 520DC66B26F60FBB00FCFFFD /* GroupTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5EE26F60FBA00FCFFFD /* GroupTests.swift */; }; + 520DC66C26F60FBB00FCFFFD /* SectionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5EF26F60FBA00FCFFFD /* SectionTests.swift */; }; + 520DC66D26F60FBB00FCFFFD /* ToggleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5F026F60FBA00FCFFFD /* ToggleTests.swift */; }; + 520DC66E26F60FBB00FCFFFD /* SpacerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5F126F60FBA00FCFFFD /* SpacerTests.swift */; }; + 520DC66F26F60FBB00FCFFFD /* DatePickerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5F226F60FBA00FCFFFD /* DatePickerTests.swift */; }; + 520DC67026F60FBB00FCFFFD /* SafeAreaInsetTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5F326F60FBA00FCFFFD /* SafeAreaInsetTests.swift */; }; + 520DC67126F60FBB00FCFFFD /* ColorPickerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5F426F60FBA00FCFFFD /* ColorPickerTests.swift */; }; + 520DC67226F60FBB00FCFFFD /* OutlineGroupTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5F526F60FBA00FCFFFD /* OutlineGroupTests.swift */; }; + 520DC67326F60FBB00FCFFFD /* ScrollViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5F626F60FBA00FCFFFD /* ScrollViewTests.swift */; }; + 520DC67426F60FBB00FCFFFD /* SecureFieldTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5F726F60FBA00FCFFFD /* SecureFieldTests.swift */; }; + 520DC67526F60FBB00FCFFFD /* LazyHGridTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5F826F60FBA00FCFFFD /* LazyHGridTests.swift */; }; + 520DC67626F60FBB00FCFFFD /* ShapeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5F926F60FBA00FCFFFD /* ShapeTests.swift */; }; + 520DC67726F60FBB00FCFFFD /* ListTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5FA26F60FBA00FCFFFD /* ListTests.swift */; }; + 520DC67826F60FBB00FCFFFD /* HSplitViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5FB26F60FBA00FCFFFD /* HSplitViewTests.swift */; }; + 520DC67926F60FBB00FCFFFD /* AnyViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5FC26F60FBA00FCFFFD /* AnyViewTests.swift */; }; + 520DC67A26F60FBB00FCFFFD /* LazyVStackTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5FD26F60FBA00FCFFFD /* LazyVStackTests.swift */; }; + 520DC67B26F60FBB00FCFFFD /* ConfigurationModifiersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5FF26F60FBA00FCFFFD /* ConfigurationModifiersTests.swift */; }; + 520DC67C26F60FBB00FCFFFD /* PresentationModifiersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC60026F60FBA00FCFFFD /* PresentationModifiersTests.swift */; }; + 520DC67D26F60FBB00FCFFFD /* InteractionModifiersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC60126F60FBA00FCFFFD /* InteractionModifiersTests.swift */; }; + 520DC67E26F60FBB00FCFFFD /* EventsModifiersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC60226F60FBA00FCFFFD /* EventsModifiersTests.swift */; }; + 520DC67F26F60FBB00FCFFFD /* SizingModifiersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC60326F60FBA00FCFFFD /* SizingModifiersTests.swift */; }; + 520DC68026F60FBB00FCFFFD /* NestedModifiersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC60426F60FBA00FCFFFD /* NestedModifiersTests.swift */; }; + 520DC68126F60FBB00FCFFFD /* PositioningModifiersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC60526F60FBA00FCFFFD /* PositioningModifiersTests.swift */; }; + 520DC68226F60FBB00FCFFFD /* TextInputModifiersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC60626F60FBA00FCFFFD /* TextInputModifiersTests.swift */; }; + 520DC68326F60FBB00FCFFFD /* CustomStyleModifiersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC60726F60FBA00FCFFFD /* CustomStyleModifiersTests.swift */; }; + 520DC68426F60FBB00FCFFFD /* TransitiveModifiersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC60826F60FBA00FCFFFD /* TransitiveModifiersTests.swift */; }; + 520DC68526F60FBB00FCFFFD /* AccessibilityModifiersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC60926F60FBA00FCFFFD /* AccessibilityModifiersTests.swift */; }; + 520DC68626F60FBB00FCFFFD /* AnimationModifiersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC60A26F60FBA00FCFFFD /* AnimationModifiersTests.swift */; }; + 520DC68726F60FBB00FCFFFD /* VisualEffectModifiersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC60B26F60FBA00FCFFFD /* VisualEffectModifiersTests.swift */; }; + 520DC68826F60FBB00FCFFFD /* EnvironmentModifiersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC60C26F60FBA00FCFFFD /* EnvironmentModifiersTests.swift */; }; + 520DC68926F60FBB00FCFFFD /* ViewPaddingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC60D26F60FBA00FCFFFD /* ViewPaddingTests.swift */; }; + 520DC68A26F60FBB00FCFFFD /* TransformingModifiersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC60E26F60FBA00FCFFFD /* TransformingModifiersTests.swift */; }; 5293010626EFC96600012E90 /* Interface.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5293010426EFC96600012E90 /* Interface.storyboard */; }; 5293010E26EFC96700012E90 /* watchOS-Ext-2.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 5293010D26EFC96700012E90 /* watchOS-Ext-2.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 5293012726EFCBD300012E90 /* watchOSApp-2.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5293011426EFC96700012E90 /* watchOSApp-2.swift */; }; - 52CA2F9626ECC58B00BFD568 /* LazyGroupTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F1226ECC58B00BFD568 /* LazyGroupTests.swift */; }; - 52CA2F9726ECC58B00BFD568 /* ViewHostingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F1326ECC58B00BFD568 /* ViewHostingTests.swift */; }; - 52CA2F9826ECC58B00BFD568 /* InspectionEmissaryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F1426ECC58B00BFD568 /* InspectionEmissaryTests.swift */; }; - 52CA2F9926ECC58B00BFD568 /* BaseTypesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F1526ECC58B00BFD568 /* BaseTypesTests.swift */; }; - 52CA2F9A26ECC58B00BFD568 /* ViewSearchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F1626ECC58B00BFD568 /* ViewSearchTests.swift */; }; - 52CA2F9B26ECC58B00BFD568 /* HitTestingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F1926ECC58B00BFD568 /* HitTestingTests.swift */; }; - 52CA2F9C26ECC58B00BFD568 /* GestureModifierTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F1A26ECC58B00BFD568 /* GestureModifierTests.swift */; }; - 52CA2F9D26ECC58B00BFD568 /* GestureActionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F1B26ECC58B00BFD568 /* GestureActionTests.swift */; }; - 52CA2F9E26ECC58B00BFD568 /* HighPriorityGestureModifierTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F1C26ECC58B00BFD568 /* HighPriorityGestureModifierTests.swift */; }; - 52CA2F9F26ECC58B00BFD568 /* SimultaneousGestureModifierTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F1D26ECC58B00BFD568 /* SimultaneousGestureModifierTests.swift */; }; - 52CA2FA026ECC58B00BFD568 /* ComposedGestureExampleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F1E26ECC58B00BFD568 /* ComposedGestureExampleTests.swift */; }; - 52CA2FA126ECC58B00BFD568 /* SequenceGestureChildrenTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F1F26ECC58B00BFD568 /* SequenceGestureChildrenTests.swift */; }; - 52CA2FA226ECC58B00BFD568 /* RotationGestureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F2026ECC58B00BFD568 /* RotationGestureTests.swift */; }; - 52CA2FA326ECC58B00BFD568 /* ExclusiveGestureChildrenTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F2126ECC58B00BFD568 /* ExclusiveGestureChildrenTests.swift */; }; - 52CA2FA426ECC58B00BFD568 /* TapGestureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F2226ECC58B00BFD568 /* TapGestureTests.swift */; }; - 52CA2FA526ECC58B00BFD568 /* ExclusiveGestureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F2326ECC58B00BFD568 /* ExclusiveGestureTests.swift */; }; - 52CA2FA626ECC58B00BFD568 /* SimultaneousGestureChildrenTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F2426ECC58B00BFD568 /* SimultaneousGestureChildrenTests.swift */; }; - 52CA2FA726ECC58B00BFD568 /* SequenceGestureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F2526ECC58B00BFD568 /* SequenceGestureTests.swift */; }; - 52CA2FA826ECC58B00BFD568 /* GestureExampleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F2626ECC58B00BFD568 /* GestureExampleTests.swift */; }; - 52CA2FA926ECC58B00BFD568 /* DragGestureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F2726ECC58B00BFD568 /* DragGestureTests.swift */; }; - 52CA2FAA26ECC58B00BFD568 /* CommonComposedGestureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F2826ECC58B00BFD568 /* CommonComposedGestureTests.swift */; }; - 52CA2FAB26ECC58B00BFD568 /* CommonComposedGestureUpdatingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F2926ECC58B00BFD568 /* CommonComposedGestureUpdatingTests.swift */; }; - 52CA2FAC26ECC58B00BFD568 /* SimultaneousGestureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F2A26ECC58B00BFD568 /* SimultaneousGestureTests.swift */; }; - 52CA2FAD26ECC58B00BFD568 /* CommonComposedGestureEndedTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F2B26ECC58B00BFD568 /* CommonComposedGestureEndedTests.swift */; }; - 52CA2FAE26ECC58B00BFD568 /* CommonComposedGestureChangedTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F2C26ECC58B00BFD568 /* CommonComposedGestureChangedTests.swift */; }; - 52CA2FAF26ECC58B00BFD568 /* LongPressGestureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F2D26ECC58B00BFD568 /* LongPressGestureTests.swift */; }; - 52CA2FB026ECC58B00BFD568 /* CommonGestureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F2E26ECC58B00BFD568 /* CommonGestureTests.swift */; }; - 52CA2FB126ECC58B00BFD568 /* MagnificationGestureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F2F26ECC58B00BFD568 /* MagnificationGestureTests.swift */; }; - 52CA2FB226ECC58B00BFD568 /* Test.strings in Resources */ = {isa = PBXBuildFile; fileRef = 52CA2F3126ECC58B00BFD568 /* Test.strings */; }; - 52CA2FB326ECC58B00BFD568 /* InspectableViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F3526ECC58B00BFD568 /* InspectableViewTests.swift */; }; - 52CA2FB426ECC58B00BFD568 /* InspectorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F3626ECC58B00BFD568 /* InspectorTests.swift */; }; - 52CA2FB526ECC58B00BFD568 /* ZStackTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F3826ECC58B00BFD568 /* ZStackTests.swift */; }; - 52CA2FB626ECC58B00BFD568 /* OptionalViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F3926ECC58B00BFD568 /* OptionalViewTests.swift */; }; - 52CA2FB726ECC58B00BFD568 /* MenuButtonTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F3A26ECC58B00BFD568 /* MenuButtonTests.swift */; }; - 52CA2FB826ECC58B00BFD568 /* TouchBarTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F3B26ECC58B00BFD568 /* TouchBarTests.swift */; }; - 52CA2FB926ECC58B00BFD568 /* GroupBoxTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F3C26ECC58B00BFD568 /* GroupBoxTests.swift */; }; - 52CA2FBA26ECC58B00BFD568 /* SheetTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F3D26ECC58B00BFD568 /* SheetTests.swift */; }; - 52CA2FBB26ECC58B00BFD568 /* RadialGradientTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F3E26ECC58B00BFD568 /* RadialGradientTests.swift */; }; - 52CA2FBC26ECC58B00BFD568 /* ScrollViewReaderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F3F26ECC58B00BFD568 /* ScrollViewReaderTests.swift */; }; - 52CA2FBD26ECC58B00BFD568 /* MapTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F4026ECC58B00BFD568 /* MapTests.swift */; }; - 52CA2FBE26ECC58B00BFD568 /* SubscriptionViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F4126ECC58B00BFD568 /* SubscriptionViewTests.swift */; }; - 52CA2FBF26ECC58B00BFD568 /* MenuTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F4226ECC58B00BFD568 /* MenuTests.swift */; }; - 52CA2FC026ECC58B00BFD568 /* LabelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F4326ECC58B00BFD568 /* LabelTests.swift */; }; - 52CA2FC126ECC58B00BFD568 /* TextTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F4426ECC58B00BFD568 /* TextTests.swift */; }; - 52CA2FC226ECC58B00BFD568 /* OpaqueViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F4526ECC58B00BFD568 /* OpaqueViewTests.swift */; }; - 52CA2FC326ECC58B00BFD568 /* HStackTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F4626ECC58B00BFD568 /* HStackTests.swift */; }; - 52CA2FC426ECC58B00BFD568 /* TreeViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F4726ECC58B00BFD568 /* TreeViewTests.swift */; }; - 52CA2FC526ECC58B00BFD568 /* EquatableViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F4826ECC58B00BFD568 /* EquatableViewTests.swift */; }; - 52CA2FC626ECC58B00BFD568 /* LinearGradientTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F4926ECC58B00BFD568 /* LinearGradientTests.swift */; }; - 52CA2FC726ECC58B00BFD568 /* ToolbarTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F4A26ECC58B00BFD568 /* ToolbarTests.swift */; }; - 52CA2FC826ECC58B00BFD568 /* DisclosureGroupTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F4B26ECC58B00BFD568 /* DisclosureGroupTests.swift */; }; - 52CA2FC926ECC58B00BFD568 /* GeometryReaderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F4C26ECC58B00BFD568 /* GeometryReaderTests.swift */; }; - 52CA2FCA26ECC58B00BFD568 /* ProgressViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F4D26ECC58B00BFD568 /* ProgressViewTests.swift */; }; - 52CA2FCB26ECC58B00BFD568 /* EnvironmentObjectInjectionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F4E26ECC58B00BFD568 /* EnvironmentObjectInjectionTests.swift */; }; - 52CA2FCC26ECC58B00BFD568 /* TabViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F4F26ECC58B00BFD568 /* TabViewTests.swift */; }; - 52CA2FCD26ECC58B00BFD568 /* PopoverTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F5026ECC58B00BFD568 /* PopoverTests.swift */; }; - 52CA2FCE26ECC58B00BFD568 /* EmptyViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F5126ECC58B00BFD568 /* EmptyViewTests.swift */; }; - 52CA2FCF26ECC58B00BFD568 /* CustomViewModifierTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F5226ECC58B00BFD568 /* CustomViewModifierTests.swift */; }; - 52CA2FD026ECC58B00BFD568 /* ImageTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F5326ECC58B00BFD568 /* ImageTests.swift */; }; - 52CA2FD126ECC58B00BFD568 /* EnvironmentReaderViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F5426ECC58B00BFD568 /* EnvironmentReaderViewTests.swift */; }; - 52CA2FD226ECC58B00BFD568 /* StepperTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F5526ECC58B00BFD568 /* StepperTests.swift */; }; - 52CA2FD326ECC58B00BFD568 /* FormTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F5626ECC58B00BFD568 /* FormTests.swift */; }; - 52CA2FD426ECC58B00BFD568 /* TupleViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F5726ECC58B00BFD568 /* TupleViewTests.swift */; }; - 52CA2FD526ECC58B00BFD568 /* ConfirmationDialogTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F5826ECC58B00BFD568 /* ConfirmationDialogTests.swift */; }; - 52CA2FD626ECC58B00BFD568 /* LazyVGridTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F5926ECC58B00BFD568 /* LazyVGridTests.swift */; }; - 52CA2FD726ECC58B00BFD568 /* LazyHStackTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F5A26ECC58B00BFD568 /* LazyHStackTests.swift */; }; - 52CA2FD826ECC58B00BFD568 /* AlertTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F5B26ECC58B00BFD568 /* AlertTests.swift */; }; - 52CA2FD926ECC58B00BFD568 /* TextAttributesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F5C26ECC58B00BFD568 /* TextAttributesTests.swift */; }; - 52CA2FDA26ECC58B00BFD568 /* PasteButtonTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F5D26ECC58B00BFD568 /* PasteButtonTests.swift */; }; - 52CA2FDB26ECC58B00BFD568 /* DividerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F5E26ECC58B00BFD568 /* DividerTests.swift */; }; - 52CA2FDC26ECC58B00BFD568 /* ForEachTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F5F26ECC58B00BFD568 /* ForEachTests.swift */; }; - 52CA2FDD26ECC58B00BFD568 /* ActionSheetTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F6026ECC58B00BFD568 /* ActionSheetTests.swift */; }; - 52CA2FDE26ECC58B00BFD568 /* DelayedPreferenceViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F6126ECC58B00BFD568 /* DelayedPreferenceViewTests.swift */; }; - 52CA2FDF26ECC58B00BFD568 /* ButtonTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F6226ECC58B00BFD568 /* ButtonTests.swift */; }; - 52CA2FE026ECC58B00BFD568 /* LinkTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F6326ECC58B00BFD568 /* LinkTests.swift */; }; - 52CA2FE126ECC58B00BFD568 /* SliderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F6426ECC58B00BFD568 /* SliderTests.swift */; }; - 52CA2FE226ECC58B00BFD568 /* CustomViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F6526ECC58B00BFD568 /* CustomViewTests.swift */; }; - 52CA2FE326ECC58B00BFD568 /* ColorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F6626ECC58B00BFD568 /* ColorTests.swift */; }; - 52CA2FE426ECC58B00BFD568 /* TextEditorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F6726ECC58B00BFD568 /* TextEditorTests.swift */; }; - 52CA2FE526ECC58B00BFD568 /* MapAnnotationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F6826ECC58B00BFD568 /* MapAnnotationTests.swift */; }; - 52CA2FE626ECC58B00BFD568 /* AngularGradientTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F6926ECC58B00BFD568 /* AngularGradientTests.swift */; }; - 52CA2FE726ECC58B00BFD568 /* ConditionalContentTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F6A26ECC58B00BFD568 /* ConditionalContentTests.swift */; }; - 52CA2FE826ECC58B00BFD568 /* VSplitViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F6B26ECC58B00BFD568 /* VSplitViewTests.swift */; }; - 52CA2FE926ECC58B00BFD568 /* NavigationViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F6C26ECC58B00BFD568 /* NavigationViewTests.swift */; }; - 52CA2FEA26ECC58B00BFD568 /* EditButtonTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F6D26ECC58B00BFD568 /* EditButtonTests.swift */; }; - 52CA2FEB26ECC58B00BFD568 /* IDViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F6E26ECC58B00BFD568 /* IDViewTests.swift */; }; - 52CA2FEC26ECC58B00BFD568 /* CustomViewBuilderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F6F26ECC58B00BFD568 /* CustomViewBuilderTests.swift */; }; - 52CA2FED26ECC58B00BFD568 /* TextFieldTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F7026ECC58B00BFD568 /* TextFieldTests.swift */; }; - 52CA2FEE26ECC58B00BFD568 /* FullScreenCoverTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F7126ECC58B00BFD568 /* FullScreenCoverTests.swift */; }; - 52CA2FEF26ECC58B00BFD568 /* NavigationLinkTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F7226ECC58B00BFD568 /* NavigationLinkTests.swift */; }; - 52CA2FF026ECC58B00BFD568 /* VStackTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F7326ECC58B00BFD568 /* VStackTests.swift */; }; - 52CA2FF126ECC58B00BFD568 /* PickerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F7426ECC58B00BFD568 /* PickerTests.swift */; }; - 52CA2FF226ECC58B00BFD568 /* GroupTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F7526ECC58B00BFD568 /* GroupTests.swift */; }; - 52CA2FF326ECC58B00BFD568 /* SectionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F7626ECC58B00BFD568 /* SectionTests.swift */; }; - 52CA2FF426ECC58B00BFD568 /* ToggleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F7726ECC58B00BFD568 /* ToggleTests.swift */; }; - 52CA2FF526ECC58B00BFD568 /* SpacerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F7826ECC58B00BFD568 /* SpacerTests.swift */; }; - 52CA2FF626ECC58B00BFD568 /* DatePickerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F7926ECC58B00BFD568 /* DatePickerTests.swift */; }; - 52CA2FF726ECC58B00BFD568 /* SafeAreaInsetTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F7A26ECC58B00BFD568 /* SafeAreaInsetTests.swift */; }; - 52CA2FF826ECC58B00BFD568 /* ColorPickerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F7B26ECC58B00BFD568 /* ColorPickerTests.swift */; }; - 52CA2FF926ECC58B00BFD568 /* OutlineGroupTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F7C26ECC58B00BFD568 /* OutlineGroupTests.swift */; }; - 52CA2FFA26ECC58B00BFD568 /* ScrollViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F7D26ECC58B00BFD568 /* ScrollViewTests.swift */; }; - 52CA2FFB26ECC58B00BFD568 /* SecureFieldTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F7E26ECC58B00BFD568 /* SecureFieldTests.swift */; }; - 52CA2FFC26ECC58B00BFD568 /* LazyHGridTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F7F26ECC58B00BFD568 /* LazyHGridTests.swift */; }; - 52CA2FFD26ECC58B00BFD568 /* ShapeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F8026ECC58B00BFD568 /* ShapeTests.swift */; }; - 52CA2FFE26ECC58B00BFD568 /* ListTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F8126ECC58B00BFD568 /* ListTests.swift */; }; - 52CA2FFF26ECC58B00BFD568 /* HSplitViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F8226ECC58B00BFD568 /* HSplitViewTests.swift */; }; - 52CA300026ECC58B00BFD568 /* AnyViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F8326ECC58B00BFD568 /* AnyViewTests.swift */; }; - 52CA300126ECC58B00BFD568 /* LazyVStackTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F8426ECC58B00BFD568 /* LazyVStackTests.swift */; }; - 52CA300226ECC58B00BFD568 /* ConfigurationModifiersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F8626ECC58B00BFD568 /* ConfigurationModifiersTests.swift */; }; - 52CA300326ECC58B00BFD568 /* PresentationModifiersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F8726ECC58B00BFD568 /* PresentationModifiersTests.swift */; }; - 52CA300426ECC58B00BFD568 /* InteractionModifiersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F8826ECC58B00BFD568 /* InteractionModifiersTests.swift */; }; - 52CA300526ECC58B00BFD568 /* EventsModifiersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F8926ECC58B00BFD568 /* EventsModifiersTests.swift */; }; - 52CA300626ECC58B00BFD568 /* SizingModifiersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F8A26ECC58B00BFD568 /* SizingModifiersTests.swift */; }; - 52CA300726ECC58B00BFD568 /* NestedModifiersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F8B26ECC58B00BFD568 /* NestedModifiersTests.swift */; }; - 52CA300826ECC58B00BFD568 /* PositioningModifiersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F8C26ECC58B00BFD568 /* PositioningModifiersTests.swift */; }; - 52CA300926ECC58B00BFD568 /* TextInputModifiersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F8D26ECC58B00BFD568 /* TextInputModifiersTests.swift */; }; - 52CA300A26ECC58B00BFD568 /* CustomStyleModifiersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F8E26ECC58B00BFD568 /* CustomStyleModifiersTests.swift */; }; - 52CA300B26ECC58B00BFD568 /* TransitiveModifiersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F8F26ECC58B00BFD568 /* TransitiveModifiersTests.swift */; }; - 52CA300C26ECC58B00BFD568 /* AccessibilityModifiersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F9026ECC58B00BFD568 /* AccessibilityModifiersTests.swift */; }; - 52CA300D26ECC58B00BFD568 /* AnimationModifiersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F9126ECC58B00BFD568 /* AnimationModifiersTests.swift */; }; - 52CA300E26ECC58B00BFD568 /* VisualEffectModifiersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F9226ECC58B00BFD568 /* VisualEffectModifiersTests.swift */; }; - 52CA300F26ECC58B00BFD568 /* EnvironmentModifiersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F9326ECC58B00BFD568 /* EnvironmentModifiersTests.swift */; }; - 52CA301026ECC58B00BFD568 /* ViewPaddingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F9426ECC58B00BFD568 /* ViewPaddingTests.swift */; }; - 52CA301126ECC58B00BFD568 /* TransformingModifiersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA2F9526ECC58B00BFD568 /* TransformingModifiersTests.swift */; }; 52CA301426ECC5D200BFD568 /* ViewInspector in Frameworks */ = {isa = PBXBuildFile; productRef = 52CA301326ECC5D200BFD568 /* ViewInspector */; }; 52CA301626ECD64400BFD568 /* watchOSApp+Testable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA301526ECD64400BFD568 /* watchOSApp+Testable.swift */; }; 52E3259B26C72E7900CCE47E /* watchOS-Ext-1.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 52E3259A26C72E7900CCE47E /* watchOS-Ext-1.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; @@ -191,138 +191,138 @@ /* Begin PBXFileReference section */ 520213A426ECB45D00E94C6E /* watchOS-Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "watchOS-Tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; + 520DC58B26F60FBA00FCFFFD /* LazyGroupTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LazyGroupTests.swift; sourceTree = ""; }; + 520DC58C26F60FBA00FCFFFD /* ViewHostingTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewHostingTests.swift; sourceTree = ""; }; + 520DC58D26F60FBA00FCFFFD /* InspectionEmissaryTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InspectionEmissaryTests.swift; sourceTree = ""; }; + 520DC58E26F60FBA00FCFFFD /* BaseTypesTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BaseTypesTests.swift; sourceTree = ""; }; + 520DC58F26F60FBA00FCFFFD /* ViewSearchTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewSearchTests.swift; sourceTree = ""; }; + 520DC59226F60FBA00FCFFFD /* HitTestingTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HitTestingTests.swift; sourceTree = ""; }; + 520DC59326F60FBA00FCFFFD /* GestureModifierTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GestureModifierTests.swift; sourceTree = ""; }; + 520DC59426F60FBA00FCFFFD /* GestureActionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GestureActionTests.swift; sourceTree = ""; }; + 520DC59526F60FBA00FCFFFD /* HighPriorityGestureModifierTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HighPriorityGestureModifierTests.swift; sourceTree = ""; }; + 520DC59626F60FBA00FCFFFD /* SimultaneousGestureModifierTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SimultaneousGestureModifierTests.swift; sourceTree = ""; }; + 520DC59726F60FBA00FCFFFD /* ComposedGestureExampleTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ComposedGestureExampleTests.swift; sourceTree = ""; }; + 520DC59826F60FBA00FCFFFD /* SequenceGestureChildrenTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SequenceGestureChildrenTests.swift; sourceTree = ""; }; + 520DC59926F60FBA00FCFFFD /* RotationGestureTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RotationGestureTests.swift; sourceTree = ""; }; + 520DC59A26F60FBA00FCFFFD /* ExclusiveGestureChildrenTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExclusiveGestureChildrenTests.swift; sourceTree = ""; }; + 520DC59B26F60FBA00FCFFFD /* TapGestureTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TapGestureTests.swift; sourceTree = ""; }; + 520DC59C26F60FBA00FCFFFD /* ExclusiveGestureTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExclusiveGestureTests.swift; sourceTree = ""; }; + 520DC59D26F60FBA00FCFFFD /* SimultaneousGestureChildrenTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SimultaneousGestureChildrenTests.swift; sourceTree = ""; }; + 520DC59E26F60FBA00FCFFFD /* SequenceGestureTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SequenceGestureTests.swift; sourceTree = ""; }; + 520DC59F26F60FBA00FCFFFD /* GestureExampleTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GestureExampleTests.swift; sourceTree = ""; }; + 520DC5A026F60FBA00FCFFFD /* DragGestureTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DragGestureTests.swift; sourceTree = ""; }; + 520DC5A126F60FBA00FCFFFD /* CommonComposedGestureTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CommonComposedGestureTests.swift; sourceTree = ""; }; + 520DC5A226F60FBA00FCFFFD /* CommonComposedGestureUpdatingTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CommonComposedGestureUpdatingTests.swift; sourceTree = ""; }; + 520DC5A326F60FBA00FCFFFD /* SimultaneousGestureTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SimultaneousGestureTests.swift; sourceTree = ""; }; + 520DC5A426F60FBA00FCFFFD /* CommonComposedGestureEndedTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CommonComposedGestureEndedTests.swift; sourceTree = ""; }; + 520DC5A526F60FBA00FCFFFD /* CommonComposedGestureChangedTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CommonComposedGestureChangedTests.swift; sourceTree = ""; }; + 520DC5A626F60FBA00FCFFFD /* LongPressGestureTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LongPressGestureTests.swift; sourceTree = ""; }; + 520DC5A726F60FBA00FCFFFD /* CommonGestureTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CommonGestureTests.swift; sourceTree = ""; }; + 520DC5A826F60FBA00FCFFFD /* MagnificationGestureTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MagnificationGestureTests.swift; sourceTree = ""; }; + 520DC5AB26F60FBA00FCFFFD /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Test.strings; sourceTree = ""; }; + 520DC5AC26F60FBA00FCFFFD /* en-AU */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "en-AU"; path = "en-AU.lproj/Test.strings"; sourceTree = ""; }; + 520DC5AD26F60FBA00FCFFFD /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Test.strings; sourceTree = ""; }; + 520DC5AE26F60FBA00FCFFFD /* InspectableViewTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InspectableViewTests.swift; sourceTree = ""; }; + 520DC5AF26F60FBA00FCFFFD /* InspectorTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InspectorTests.swift; sourceTree = ""; }; + 520DC5B126F60FBA00FCFFFD /* ZStackTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ZStackTests.swift; sourceTree = ""; }; + 520DC5B226F60FBA00FCFFFD /* OptionalViewTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OptionalViewTests.swift; sourceTree = ""; }; + 520DC5B326F60FBA00FCFFFD /* MenuButtonTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MenuButtonTests.swift; sourceTree = ""; }; + 520DC5B426F60FBA00FCFFFD /* TouchBarTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TouchBarTests.swift; sourceTree = ""; }; + 520DC5B526F60FBA00FCFFFD /* GroupBoxTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GroupBoxTests.swift; sourceTree = ""; }; + 520DC5B626F60FBA00FCFFFD /* SheetTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SheetTests.swift; sourceTree = ""; }; + 520DC5B726F60FBA00FCFFFD /* RadialGradientTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RadialGradientTests.swift; sourceTree = ""; }; + 520DC5B826F60FBA00FCFFFD /* ScrollViewReaderTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScrollViewReaderTests.swift; sourceTree = ""; }; + 520DC5B926F60FBA00FCFFFD /* MapTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MapTests.swift; sourceTree = ""; }; + 520DC5BA26F60FBA00FCFFFD /* SubscriptionViewTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SubscriptionViewTests.swift; sourceTree = ""; }; + 520DC5BB26F60FBA00FCFFFD /* MenuTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MenuTests.swift; sourceTree = ""; }; + 520DC5BC26F60FBA00FCFFFD /* LabelTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LabelTests.swift; sourceTree = ""; }; + 520DC5BD26F60FBA00FCFFFD /* TextTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextTests.swift; sourceTree = ""; }; + 520DC5BE26F60FBA00FCFFFD /* OpaqueViewTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OpaqueViewTests.swift; sourceTree = ""; }; + 520DC5BF26F60FBA00FCFFFD /* HStackTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HStackTests.swift; sourceTree = ""; }; + 520DC5C026F60FBA00FCFFFD /* TreeViewTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TreeViewTests.swift; sourceTree = ""; }; + 520DC5C126F60FBA00FCFFFD /* EquatableViewTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EquatableViewTests.swift; sourceTree = ""; }; + 520DC5C226F60FBA00FCFFFD /* LinearGradientTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LinearGradientTests.swift; sourceTree = ""; }; + 520DC5C326F60FBA00FCFFFD /* ToolbarTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ToolbarTests.swift; sourceTree = ""; }; + 520DC5C426F60FBA00FCFFFD /* DisclosureGroupTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DisclosureGroupTests.swift; sourceTree = ""; }; + 520DC5C526F60FBA00FCFFFD /* GeometryReaderTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeometryReaderTests.swift; sourceTree = ""; }; + 520DC5C626F60FBA00FCFFFD /* ProgressViewTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProgressViewTests.swift; sourceTree = ""; }; + 520DC5C726F60FBA00FCFFFD /* EnvironmentObjectInjectionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EnvironmentObjectInjectionTests.swift; sourceTree = ""; }; + 520DC5C826F60FBA00FCFFFD /* TabViewTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TabViewTests.swift; sourceTree = ""; }; + 520DC5C926F60FBA00FCFFFD /* PopoverTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PopoverTests.swift; sourceTree = ""; }; + 520DC5CA26F60FBA00FCFFFD /* EmptyViewTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EmptyViewTests.swift; sourceTree = ""; }; + 520DC5CB26F60FBA00FCFFFD /* CustomViewModifierTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomViewModifierTests.swift; sourceTree = ""; }; + 520DC5CC26F60FBA00FCFFFD /* ImageTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageTests.swift; sourceTree = ""; }; + 520DC5CD26F60FBA00FCFFFD /* EnvironmentReaderViewTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EnvironmentReaderViewTests.swift; sourceTree = ""; }; + 520DC5CE26F60FBA00FCFFFD /* StepperTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StepperTests.swift; sourceTree = ""; }; + 520DC5CF26F60FBA00FCFFFD /* FormTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FormTests.swift; sourceTree = ""; }; + 520DC5D026F60FBA00FCFFFD /* TupleViewTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TupleViewTests.swift; sourceTree = ""; }; + 520DC5D126F60FBA00FCFFFD /* ConfirmationDialogTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConfirmationDialogTests.swift; sourceTree = ""; }; + 520DC5D226F60FBA00FCFFFD /* LazyVGridTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LazyVGridTests.swift; sourceTree = ""; }; + 520DC5D326F60FBA00FCFFFD /* LazyHStackTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LazyHStackTests.swift; sourceTree = ""; }; + 520DC5D426F60FBA00FCFFFD /* AlertTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AlertTests.swift; sourceTree = ""; }; + 520DC5D526F60FBA00FCFFFD /* TextAttributesTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextAttributesTests.swift; sourceTree = ""; }; + 520DC5D626F60FBA00FCFFFD /* PasteButtonTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PasteButtonTests.swift; sourceTree = ""; }; + 520DC5D726F60FBA00FCFFFD /* DividerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DividerTests.swift; sourceTree = ""; }; + 520DC5D826F60FBA00FCFFFD /* ForEachTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ForEachTests.swift; sourceTree = ""; }; + 520DC5D926F60FBA00FCFFFD /* ActionSheetTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActionSheetTests.swift; sourceTree = ""; }; + 520DC5DA26F60FBA00FCFFFD /* DelayedPreferenceViewTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DelayedPreferenceViewTests.swift; sourceTree = ""; }; + 520DC5DB26F60FBA00FCFFFD /* ButtonTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ButtonTests.swift; sourceTree = ""; }; + 520DC5DC26F60FBA00FCFFFD /* LinkTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LinkTests.swift; sourceTree = ""; }; + 520DC5DD26F60FBA00FCFFFD /* SliderTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SliderTests.swift; sourceTree = ""; }; + 520DC5DE26F60FBA00FCFFFD /* CustomViewTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomViewTests.swift; sourceTree = ""; }; + 520DC5DF26F60FBA00FCFFFD /* ColorTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ColorTests.swift; sourceTree = ""; }; + 520DC5E026F60FBA00FCFFFD /* TextEditorTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextEditorTests.swift; sourceTree = ""; }; + 520DC5E126F60FBA00FCFFFD /* MapAnnotationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MapAnnotationTests.swift; sourceTree = ""; }; + 520DC5E226F60FBA00FCFFFD /* AngularGradientTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AngularGradientTests.swift; sourceTree = ""; }; + 520DC5E326F60FBA00FCFFFD /* ConditionalContentTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConditionalContentTests.swift; sourceTree = ""; }; + 520DC5E426F60FBA00FCFFFD /* VSplitViewTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VSplitViewTests.swift; sourceTree = ""; }; + 520DC5E526F60FBA00FCFFFD /* NavigationViewTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NavigationViewTests.swift; sourceTree = ""; }; + 520DC5E626F60FBA00FCFFFD /* EditButtonTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EditButtonTests.swift; sourceTree = ""; }; + 520DC5E726F60FBA00FCFFFD /* IDViewTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IDViewTests.swift; sourceTree = ""; }; + 520DC5E826F60FBA00FCFFFD /* CustomViewBuilderTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomViewBuilderTests.swift; sourceTree = ""; }; + 520DC5E926F60FBA00FCFFFD /* TextFieldTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextFieldTests.swift; sourceTree = ""; }; + 520DC5EA26F60FBA00FCFFFD /* FullScreenCoverTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FullScreenCoverTests.swift; sourceTree = ""; }; + 520DC5EB26F60FBA00FCFFFD /* NavigationLinkTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NavigationLinkTests.swift; sourceTree = ""; }; + 520DC5EC26F60FBA00FCFFFD /* VStackTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VStackTests.swift; sourceTree = ""; }; + 520DC5ED26F60FBA00FCFFFD /* PickerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PickerTests.swift; sourceTree = ""; }; + 520DC5EE26F60FBA00FCFFFD /* GroupTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GroupTests.swift; sourceTree = ""; }; + 520DC5EF26F60FBA00FCFFFD /* SectionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SectionTests.swift; sourceTree = ""; }; + 520DC5F026F60FBA00FCFFFD /* ToggleTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ToggleTests.swift; sourceTree = ""; }; + 520DC5F126F60FBA00FCFFFD /* SpacerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SpacerTests.swift; sourceTree = ""; }; + 520DC5F226F60FBA00FCFFFD /* DatePickerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DatePickerTests.swift; sourceTree = ""; }; + 520DC5F326F60FBA00FCFFFD /* SafeAreaInsetTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SafeAreaInsetTests.swift; sourceTree = ""; }; + 520DC5F426F60FBA00FCFFFD /* ColorPickerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ColorPickerTests.swift; sourceTree = ""; }; + 520DC5F526F60FBA00FCFFFD /* OutlineGroupTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OutlineGroupTests.swift; sourceTree = ""; }; + 520DC5F626F60FBA00FCFFFD /* ScrollViewTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScrollViewTests.swift; sourceTree = ""; }; + 520DC5F726F60FBA00FCFFFD /* SecureFieldTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SecureFieldTests.swift; sourceTree = ""; }; + 520DC5F826F60FBA00FCFFFD /* LazyHGridTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LazyHGridTests.swift; sourceTree = ""; }; + 520DC5F926F60FBA00FCFFFD /* ShapeTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ShapeTests.swift; sourceTree = ""; }; + 520DC5FA26F60FBA00FCFFFD /* ListTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ListTests.swift; sourceTree = ""; }; + 520DC5FB26F60FBA00FCFFFD /* HSplitViewTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HSplitViewTests.swift; sourceTree = ""; }; + 520DC5FC26F60FBA00FCFFFD /* AnyViewTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnyViewTests.swift; sourceTree = ""; }; + 520DC5FD26F60FBA00FCFFFD /* LazyVStackTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LazyVStackTests.swift; sourceTree = ""; }; + 520DC5FF26F60FBA00FCFFFD /* ConfigurationModifiersTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConfigurationModifiersTests.swift; sourceTree = ""; }; + 520DC60026F60FBA00FCFFFD /* PresentationModifiersTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PresentationModifiersTests.swift; sourceTree = ""; }; + 520DC60126F60FBA00FCFFFD /* InteractionModifiersTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InteractionModifiersTests.swift; sourceTree = ""; }; + 520DC60226F60FBA00FCFFFD /* EventsModifiersTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EventsModifiersTests.swift; sourceTree = ""; }; + 520DC60326F60FBA00FCFFFD /* SizingModifiersTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SizingModifiersTests.swift; sourceTree = ""; }; + 520DC60426F60FBA00FCFFFD /* NestedModifiersTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NestedModifiersTests.swift; sourceTree = ""; }; + 520DC60526F60FBA00FCFFFD /* PositioningModifiersTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PositioningModifiersTests.swift; sourceTree = ""; }; + 520DC60626F60FBA00FCFFFD /* TextInputModifiersTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextInputModifiersTests.swift; sourceTree = ""; }; + 520DC60726F60FBA00FCFFFD /* CustomStyleModifiersTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomStyleModifiersTests.swift; sourceTree = ""; }; + 520DC60826F60FBA00FCFFFD /* TransitiveModifiersTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TransitiveModifiersTests.swift; sourceTree = ""; }; + 520DC60926F60FBA00FCFFFD /* AccessibilityModifiersTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AccessibilityModifiersTests.swift; sourceTree = ""; }; + 520DC60A26F60FBA00FCFFFD /* AnimationModifiersTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnimationModifiersTests.swift; sourceTree = ""; }; + 520DC60B26F60FBA00FCFFFD /* VisualEffectModifiersTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VisualEffectModifiersTests.swift; sourceTree = ""; }; + 520DC60C26F60FBA00FCFFFD /* EnvironmentModifiersTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EnvironmentModifiersTests.swift; sourceTree = ""; }; + 520DC60D26F60FBA00FCFFFD /* ViewPaddingTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewPaddingTests.swift; sourceTree = ""; }; + 520DC60E26F60FBA00FCFFFD /* TransformingModifiersTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TransformingModifiersTests.swift; sourceTree = ""; }; 529300FF26EFC96600012E90 /* watchOS-App-2.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "watchOS-App-2.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 5293010526EFC96600012E90 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Interface.storyboard; sourceTree = ""; }; 5293010D26EFC96700012E90 /* watchOS-Ext-2.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = "watchOS-Ext-2.appex"; sourceTree = BUILT_PRODUCTS_DIR; }; 5293011426EFC96700012E90 /* watchOSApp-2.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "watchOSApp-2.swift"; sourceTree = ""; }; 5293011A26EFC96800012E90 /* Ext-2-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Ext-2-Info.plist"; sourceTree = ""; }; 52CA2F1026ECC56600BFD568 /* ViewInspector */ = {isa = PBXFileReference; lastKnownFileType = folder; name = ViewInspector; path = ..; sourceTree = ""; }; - 52CA2F1226ECC58B00BFD568 /* LazyGroupTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LazyGroupTests.swift; sourceTree = ""; }; - 52CA2F1326ECC58B00BFD568 /* ViewHostingTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewHostingTests.swift; sourceTree = ""; }; - 52CA2F1426ECC58B00BFD568 /* InspectionEmissaryTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InspectionEmissaryTests.swift; sourceTree = ""; }; - 52CA2F1526ECC58B00BFD568 /* BaseTypesTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BaseTypesTests.swift; sourceTree = ""; }; - 52CA2F1626ECC58B00BFD568 /* ViewSearchTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewSearchTests.swift; sourceTree = ""; }; - 52CA2F1926ECC58B00BFD568 /* HitTestingTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HitTestingTests.swift; sourceTree = ""; }; - 52CA2F1A26ECC58B00BFD568 /* GestureModifierTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GestureModifierTests.swift; sourceTree = ""; }; - 52CA2F1B26ECC58B00BFD568 /* GestureActionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GestureActionTests.swift; sourceTree = ""; }; - 52CA2F1C26ECC58B00BFD568 /* HighPriorityGestureModifierTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HighPriorityGestureModifierTests.swift; sourceTree = ""; }; - 52CA2F1D26ECC58B00BFD568 /* SimultaneousGestureModifierTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SimultaneousGestureModifierTests.swift; sourceTree = ""; }; - 52CA2F1E26ECC58B00BFD568 /* ComposedGestureExampleTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ComposedGestureExampleTests.swift; sourceTree = ""; }; - 52CA2F1F26ECC58B00BFD568 /* SequenceGestureChildrenTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SequenceGestureChildrenTests.swift; sourceTree = ""; }; - 52CA2F2026ECC58B00BFD568 /* RotationGestureTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RotationGestureTests.swift; sourceTree = ""; }; - 52CA2F2126ECC58B00BFD568 /* ExclusiveGestureChildrenTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExclusiveGestureChildrenTests.swift; sourceTree = ""; }; - 52CA2F2226ECC58B00BFD568 /* TapGestureTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TapGestureTests.swift; sourceTree = ""; }; - 52CA2F2326ECC58B00BFD568 /* ExclusiveGestureTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExclusiveGestureTests.swift; sourceTree = ""; }; - 52CA2F2426ECC58B00BFD568 /* SimultaneousGestureChildrenTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SimultaneousGestureChildrenTests.swift; sourceTree = ""; }; - 52CA2F2526ECC58B00BFD568 /* SequenceGestureTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SequenceGestureTests.swift; sourceTree = ""; }; - 52CA2F2626ECC58B00BFD568 /* GestureExampleTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GestureExampleTests.swift; sourceTree = ""; }; - 52CA2F2726ECC58B00BFD568 /* DragGestureTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DragGestureTests.swift; sourceTree = ""; }; - 52CA2F2826ECC58B00BFD568 /* CommonComposedGestureTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CommonComposedGestureTests.swift; sourceTree = ""; }; - 52CA2F2926ECC58B00BFD568 /* CommonComposedGestureUpdatingTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CommonComposedGestureUpdatingTests.swift; sourceTree = ""; }; - 52CA2F2A26ECC58B00BFD568 /* SimultaneousGestureTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SimultaneousGestureTests.swift; sourceTree = ""; }; - 52CA2F2B26ECC58B00BFD568 /* CommonComposedGestureEndedTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CommonComposedGestureEndedTests.swift; sourceTree = ""; }; - 52CA2F2C26ECC58B00BFD568 /* CommonComposedGestureChangedTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CommonComposedGestureChangedTests.swift; sourceTree = ""; }; - 52CA2F2D26ECC58B00BFD568 /* LongPressGestureTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LongPressGestureTests.swift; sourceTree = ""; }; - 52CA2F2E26ECC58B00BFD568 /* CommonGestureTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CommonGestureTests.swift; sourceTree = ""; }; - 52CA2F2F26ECC58B00BFD568 /* MagnificationGestureTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MagnificationGestureTests.swift; sourceTree = ""; }; - 52CA2F3226ECC58B00BFD568 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Test.strings; sourceTree = ""; }; - 52CA2F3326ECC58B00BFD568 /* en-AU */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "en-AU"; path = "en-AU.lproj/Test.strings"; sourceTree = ""; }; - 52CA2F3426ECC58B00BFD568 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Test.strings; sourceTree = ""; }; - 52CA2F3526ECC58B00BFD568 /* InspectableViewTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InspectableViewTests.swift; sourceTree = ""; }; - 52CA2F3626ECC58B00BFD568 /* InspectorTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InspectorTests.swift; sourceTree = ""; }; - 52CA2F3826ECC58B00BFD568 /* ZStackTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ZStackTests.swift; sourceTree = ""; }; - 52CA2F3926ECC58B00BFD568 /* OptionalViewTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OptionalViewTests.swift; sourceTree = ""; }; - 52CA2F3A26ECC58B00BFD568 /* MenuButtonTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MenuButtonTests.swift; sourceTree = ""; }; - 52CA2F3B26ECC58B00BFD568 /* TouchBarTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TouchBarTests.swift; sourceTree = ""; }; - 52CA2F3C26ECC58B00BFD568 /* GroupBoxTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GroupBoxTests.swift; sourceTree = ""; }; - 52CA2F3D26ECC58B00BFD568 /* SheetTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SheetTests.swift; sourceTree = ""; }; - 52CA2F3E26ECC58B00BFD568 /* RadialGradientTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RadialGradientTests.swift; sourceTree = ""; }; - 52CA2F3F26ECC58B00BFD568 /* ScrollViewReaderTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScrollViewReaderTests.swift; sourceTree = ""; }; - 52CA2F4026ECC58B00BFD568 /* MapTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MapTests.swift; sourceTree = ""; }; - 52CA2F4126ECC58B00BFD568 /* SubscriptionViewTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SubscriptionViewTests.swift; sourceTree = ""; }; - 52CA2F4226ECC58B00BFD568 /* MenuTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MenuTests.swift; sourceTree = ""; }; - 52CA2F4326ECC58B00BFD568 /* LabelTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LabelTests.swift; sourceTree = ""; }; - 52CA2F4426ECC58B00BFD568 /* TextTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextTests.swift; sourceTree = ""; }; - 52CA2F4526ECC58B00BFD568 /* OpaqueViewTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OpaqueViewTests.swift; sourceTree = ""; }; - 52CA2F4626ECC58B00BFD568 /* HStackTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HStackTests.swift; sourceTree = ""; }; - 52CA2F4726ECC58B00BFD568 /* TreeViewTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TreeViewTests.swift; sourceTree = ""; }; - 52CA2F4826ECC58B00BFD568 /* EquatableViewTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EquatableViewTests.swift; sourceTree = ""; }; - 52CA2F4926ECC58B00BFD568 /* LinearGradientTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LinearGradientTests.swift; sourceTree = ""; }; - 52CA2F4A26ECC58B00BFD568 /* ToolbarTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ToolbarTests.swift; sourceTree = ""; }; - 52CA2F4B26ECC58B00BFD568 /* DisclosureGroupTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DisclosureGroupTests.swift; sourceTree = ""; }; - 52CA2F4C26ECC58B00BFD568 /* GeometryReaderTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeometryReaderTests.swift; sourceTree = ""; }; - 52CA2F4D26ECC58B00BFD568 /* ProgressViewTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProgressViewTests.swift; sourceTree = ""; }; - 52CA2F4E26ECC58B00BFD568 /* EnvironmentObjectInjectionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EnvironmentObjectInjectionTests.swift; sourceTree = ""; }; - 52CA2F4F26ECC58B00BFD568 /* TabViewTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TabViewTests.swift; sourceTree = ""; }; - 52CA2F5026ECC58B00BFD568 /* PopoverTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PopoverTests.swift; sourceTree = ""; }; - 52CA2F5126ECC58B00BFD568 /* EmptyViewTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EmptyViewTests.swift; sourceTree = ""; }; - 52CA2F5226ECC58B00BFD568 /* CustomViewModifierTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomViewModifierTests.swift; sourceTree = ""; }; - 52CA2F5326ECC58B00BFD568 /* ImageTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageTests.swift; sourceTree = ""; }; - 52CA2F5426ECC58B00BFD568 /* EnvironmentReaderViewTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EnvironmentReaderViewTests.swift; sourceTree = ""; }; - 52CA2F5526ECC58B00BFD568 /* StepperTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StepperTests.swift; sourceTree = ""; }; - 52CA2F5626ECC58B00BFD568 /* FormTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FormTests.swift; sourceTree = ""; }; - 52CA2F5726ECC58B00BFD568 /* TupleViewTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TupleViewTests.swift; sourceTree = ""; }; - 52CA2F5826ECC58B00BFD568 /* ConfirmationDialogTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConfirmationDialogTests.swift; sourceTree = ""; }; - 52CA2F5926ECC58B00BFD568 /* LazyVGridTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LazyVGridTests.swift; sourceTree = ""; }; - 52CA2F5A26ECC58B00BFD568 /* LazyHStackTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LazyHStackTests.swift; sourceTree = ""; }; - 52CA2F5B26ECC58B00BFD568 /* AlertTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AlertTests.swift; sourceTree = ""; }; - 52CA2F5C26ECC58B00BFD568 /* TextAttributesTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextAttributesTests.swift; sourceTree = ""; }; - 52CA2F5D26ECC58B00BFD568 /* PasteButtonTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PasteButtonTests.swift; sourceTree = ""; }; - 52CA2F5E26ECC58B00BFD568 /* DividerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DividerTests.swift; sourceTree = ""; }; - 52CA2F5F26ECC58B00BFD568 /* ForEachTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ForEachTests.swift; sourceTree = ""; }; - 52CA2F6026ECC58B00BFD568 /* ActionSheetTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActionSheetTests.swift; sourceTree = ""; }; - 52CA2F6126ECC58B00BFD568 /* DelayedPreferenceViewTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DelayedPreferenceViewTests.swift; sourceTree = ""; }; - 52CA2F6226ECC58B00BFD568 /* ButtonTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ButtonTests.swift; sourceTree = ""; }; - 52CA2F6326ECC58B00BFD568 /* LinkTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LinkTests.swift; sourceTree = ""; }; - 52CA2F6426ECC58B00BFD568 /* SliderTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SliderTests.swift; sourceTree = ""; }; - 52CA2F6526ECC58B00BFD568 /* CustomViewTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomViewTests.swift; sourceTree = ""; }; - 52CA2F6626ECC58B00BFD568 /* ColorTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ColorTests.swift; sourceTree = ""; }; - 52CA2F6726ECC58B00BFD568 /* TextEditorTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextEditorTests.swift; sourceTree = ""; }; - 52CA2F6826ECC58B00BFD568 /* MapAnnotationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MapAnnotationTests.swift; sourceTree = ""; }; - 52CA2F6926ECC58B00BFD568 /* AngularGradientTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AngularGradientTests.swift; sourceTree = ""; }; - 52CA2F6A26ECC58B00BFD568 /* ConditionalContentTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConditionalContentTests.swift; sourceTree = ""; }; - 52CA2F6B26ECC58B00BFD568 /* VSplitViewTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VSplitViewTests.swift; sourceTree = ""; }; - 52CA2F6C26ECC58B00BFD568 /* NavigationViewTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NavigationViewTests.swift; sourceTree = ""; }; - 52CA2F6D26ECC58B00BFD568 /* EditButtonTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EditButtonTests.swift; sourceTree = ""; }; - 52CA2F6E26ECC58B00BFD568 /* IDViewTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IDViewTests.swift; sourceTree = ""; }; - 52CA2F6F26ECC58B00BFD568 /* CustomViewBuilderTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomViewBuilderTests.swift; sourceTree = ""; }; - 52CA2F7026ECC58B00BFD568 /* TextFieldTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextFieldTests.swift; sourceTree = ""; }; - 52CA2F7126ECC58B00BFD568 /* FullScreenCoverTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FullScreenCoverTests.swift; sourceTree = ""; }; - 52CA2F7226ECC58B00BFD568 /* NavigationLinkTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NavigationLinkTests.swift; sourceTree = ""; }; - 52CA2F7326ECC58B00BFD568 /* VStackTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VStackTests.swift; sourceTree = ""; }; - 52CA2F7426ECC58B00BFD568 /* PickerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PickerTests.swift; sourceTree = ""; }; - 52CA2F7526ECC58B00BFD568 /* GroupTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GroupTests.swift; sourceTree = ""; }; - 52CA2F7626ECC58B00BFD568 /* SectionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SectionTests.swift; sourceTree = ""; }; - 52CA2F7726ECC58B00BFD568 /* ToggleTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ToggleTests.swift; sourceTree = ""; }; - 52CA2F7826ECC58B00BFD568 /* SpacerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SpacerTests.swift; sourceTree = ""; }; - 52CA2F7926ECC58B00BFD568 /* DatePickerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DatePickerTests.swift; sourceTree = ""; }; - 52CA2F7A26ECC58B00BFD568 /* SafeAreaInsetTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SafeAreaInsetTests.swift; sourceTree = ""; }; - 52CA2F7B26ECC58B00BFD568 /* ColorPickerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ColorPickerTests.swift; sourceTree = ""; }; - 52CA2F7C26ECC58B00BFD568 /* OutlineGroupTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OutlineGroupTests.swift; sourceTree = ""; }; - 52CA2F7D26ECC58B00BFD568 /* ScrollViewTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ScrollViewTests.swift; sourceTree = ""; }; - 52CA2F7E26ECC58B00BFD568 /* SecureFieldTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SecureFieldTests.swift; sourceTree = ""; }; - 52CA2F7F26ECC58B00BFD568 /* LazyHGridTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LazyHGridTests.swift; sourceTree = ""; }; - 52CA2F8026ECC58B00BFD568 /* ShapeTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ShapeTests.swift; sourceTree = ""; }; - 52CA2F8126ECC58B00BFD568 /* ListTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ListTests.swift; sourceTree = ""; }; - 52CA2F8226ECC58B00BFD568 /* HSplitViewTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HSplitViewTests.swift; sourceTree = ""; }; - 52CA2F8326ECC58B00BFD568 /* AnyViewTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnyViewTests.swift; sourceTree = ""; }; - 52CA2F8426ECC58B00BFD568 /* LazyVStackTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LazyVStackTests.swift; sourceTree = ""; }; - 52CA2F8626ECC58B00BFD568 /* ConfigurationModifiersTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConfigurationModifiersTests.swift; sourceTree = ""; }; - 52CA2F8726ECC58B00BFD568 /* PresentationModifiersTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PresentationModifiersTests.swift; sourceTree = ""; }; - 52CA2F8826ECC58B00BFD568 /* InteractionModifiersTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InteractionModifiersTests.swift; sourceTree = ""; }; - 52CA2F8926ECC58B00BFD568 /* EventsModifiersTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EventsModifiersTests.swift; sourceTree = ""; }; - 52CA2F8A26ECC58B00BFD568 /* SizingModifiersTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SizingModifiersTests.swift; sourceTree = ""; }; - 52CA2F8B26ECC58B00BFD568 /* NestedModifiersTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NestedModifiersTests.swift; sourceTree = ""; }; - 52CA2F8C26ECC58B00BFD568 /* PositioningModifiersTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PositioningModifiersTests.swift; sourceTree = ""; }; - 52CA2F8D26ECC58B00BFD568 /* TextInputModifiersTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextInputModifiersTests.swift; sourceTree = ""; }; - 52CA2F8E26ECC58B00BFD568 /* CustomStyleModifiersTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomStyleModifiersTests.swift; sourceTree = ""; }; - 52CA2F8F26ECC58B00BFD568 /* TransitiveModifiersTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TransitiveModifiersTests.swift; sourceTree = ""; }; - 52CA2F9026ECC58B00BFD568 /* AccessibilityModifiersTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AccessibilityModifiersTests.swift; sourceTree = ""; }; - 52CA2F9126ECC58B00BFD568 /* AnimationModifiersTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnimationModifiersTests.swift; sourceTree = ""; }; - 52CA2F9226ECC58B00BFD568 /* VisualEffectModifiersTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VisualEffectModifiersTests.swift; sourceTree = ""; }; - 52CA2F9326ECC58B00BFD568 /* EnvironmentModifiersTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EnvironmentModifiersTests.swift; sourceTree = ""; }; - 52CA2F9426ECC58B00BFD568 /* ViewPaddingTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewPaddingTests.swift; sourceTree = ""; }; - 52CA2F9526ECC58B00BFD568 /* TransformingModifiersTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TransformingModifiersTests.swift; sourceTree = ""; }; 52CA301526ECD64400BFD568 /* watchOSApp+Testable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "watchOSApp+Testable.swift"; sourceTree = ""; }; 52E3258E26C72E7800CCE47E /* watchOS-App-1.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "watchOS-App-1.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 52E3259526C72E7900CCE47E /* App-1-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "App-1-Info.plist"; sourceTree = ""; }; @@ -357,194 +357,194 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ - 520213A526ECB45D00E94C6E /* watchOS-Tests */ = { + 520DC58926F60FA600FCFFFD /* watchOS-Tests */ = { isa = PBXGroup; children = ( - 52CA2F1126ECC58B00BFD568 /* ViewInspectorTests */, + 520DC58A26F60FBA00FCFFFD /* ViewInspectorTests */, ); path = "watchOS-Tests"; sourceTree = ""; }; - 52CA2F0F26ECC56600BFD568 /* Packages */ = { - isa = PBXGroup; - children = ( - 52CA2F1026ECC56600BFD568 /* ViewInspector */, - ); - name = Packages; - sourceTree = ""; - }; - 52CA2F1126ECC58B00BFD568 /* ViewInspectorTests */ = { + 520DC58A26F60FBA00FCFFFD /* ViewInspectorTests */ = { isa = PBXGroup; children = ( - 52CA2F1226ECC58B00BFD568 /* LazyGroupTests.swift */, - 52CA2F1326ECC58B00BFD568 /* ViewHostingTests.swift */, - 52CA2F1426ECC58B00BFD568 /* InspectionEmissaryTests.swift */, - 52CA2F1526ECC58B00BFD568 /* BaseTypesTests.swift */, - 52CA2F1626ECC58B00BFD568 /* ViewSearchTests.swift */, - 52CA2F1726ECC58B00BFD568 /* Gestures */, - 52CA2F3026ECC58B00BFD568 /* TestResources */, - 52CA2F3526ECC58B00BFD568 /* InspectableViewTests.swift */, - 52CA2F3626ECC58B00BFD568 /* InspectorTests.swift */, - 52CA2F3726ECC58B00BFD568 /* SwiftUI */, - 52CA2F8526ECC58B00BFD568 /* ViewModifiers */, + 520DC58B26F60FBA00FCFFFD /* LazyGroupTests.swift */, + 520DC58C26F60FBA00FCFFFD /* ViewHostingTests.swift */, + 520DC58D26F60FBA00FCFFFD /* InspectionEmissaryTests.swift */, + 520DC58E26F60FBA00FCFFFD /* BaseTypesTests.swift */, + 520DC58F26F60FBA00FCFFFD /* ViewSearchTests.swift */, + 520DC59026F60FBA00FCFFFD /* Gestures */, + 520DC5A926F60FBA00FCFFFD /* TestResources */, + 520DC5AE26F60FBA00FCFFFD /* InspectableViewTests.swift */, + 520DC5AF26F60FBA00FCFFFD /* InspectorTests.swift */, + 520DC5B026F60FBA00FCFFFD /* SwiftUI */, + 520DC5FE26F60FBA00FCFFFD /* ViewModifiers */, ); name = ViewInspectorTests; path = ../../Tests/ViewInspectorTests; sourceTree = ""; }; - 52CA2F1726ECC58B00BFD568 /* Gestures */ = { + 520DC59026F60FBA00FCFFFD /* Gestures */ = { isa = PBXGroup; children = ( - 52CA2F1826ECC58B00BFD568 /* GestureModifiers */, - 52CA2F1E26ECC58B00BFD568 /* ComposedGestureExampleTests.swift */, - 52CA2F1F26ECC58B00BFD568 /* SequenceGestureChildrenTests.swift */, - 52CA2F2026ECC58B00BFD568 /* RotationGestureTests.swift */, - 52CA2F2126ECC58B00BFD568 /* ExclusiveGestureChildrenTests.swift */, - 52CA2F2226ECC58B00BFD568 /* TapGestureTests.swift */, - 52CA2F2326ECC58B00BFD568 /* ExclusiveGestureTests.swift */, - 52CA2F2426ECC58B00BFD568 /* SimultaneousGestureChildrenTests.swift */, - 52CA2F2526ECC58B00BFD568 /* SequenceGestureTests.swift */, - 52CA2F2626ECC58B00BFD568 /* GestureExampleTests.swift */, - 52CA2F2726ECC58B00BFD568 /* DragGestureTests.swift */, - 52CA2F2826ECC58B00BFD568 /* CommonComposedGestureTests.swift */, - 52CA2F2926ECC58B00BFD568 /* CommonComposedGestureUpdatingTests.swift */, - 52CA2F2A26ECC58B00BFD568 /* SimultaneousGestureTests.swift */, - 52CA2F2B26ECC58B00BFD568 /* CommonComposedGestureEndedTests.swift */, - 52CA2F2C26ECC58B00BFD568 /* CommonComposedGestureChangedTests.swift */, - 52CA2F2D26ECC58B00BFD568 /* LongPressGestureTests.swift */, - 52CA2F2E26ECC58B00BFD568 /* CommonGestureTests.swift */, - 52CA2F2F26ECC58B00BFD568 /* MagnificationGestureTests.swift */, + 520DC59126F60FBA00FCFFFD /* GestureModifiers */, + 520DC59726F60FBA00FCFFFD /* ComposedGestureExampleTests.swift */, + 520DC59826F60FBA00FCFFFD /* SequenceGestureChildrenTests.swift */, + 520DC59926F60FBA00FCFFFD /* RotationGestureTests.swift */, + 520DC59A26F60FBA00FCFFFD /* ExclusiveGestureChildrenTests.swift */, + 520DC59B26F60FBA00FCFFFD /* TapGestureTests.swift */, + 520DC59C26F60FBA00FCFFFD /* ExclusiveGestureTests.swift */, + 520DC59D26F60FBA00FCFFFD /* SimultaneousGestureChildrenTests.swift */, + 520DC59E26F60FBA00FCFFFD /* SequenceGestureTests.swift */, + 520DC59F26F60FBA00FCFFFD /* GestureExampleTests.swift */, + 520DC5A026F60FBA00FCFFFD /* DragGestureTests.swift */, + 520DC5A126F60FBA00FCFFFD /* CommonComposedGestureTests.swift */, + 520DC5A226F60FBA00FCFFFD /* CommonComposedGestureUpdatingTests.swift */, + 520DC5A326F60FBA00FCFFFD /* SimultaneousGestureTests.swift */, + 520DC5A426F60FBA00FCFFFD /* CommonComposedGestureEndedTests.swift */, + 520DC5A526F60FBA00FCFFFD /* CommonComposedGestureChangedTests.swift */, + 520DC5A626F60FBA00FCFFFD /* LongPressGestureTests.swift */, + 520DC5A726F60FBA00FCFFFD /* CommonGestureTests.swift */, + 520DC5A826F60FBA00FCFFFD /* MagnificationGestureTests.swift */, ); path = Gestures; sourceTree = ""; }; - 52CA2F1826ECC58B00BFD568 /* GestureModifiers */ = { + 520DC59126F60FBA00FCFFFD /* GestureModifiers */ = { isa = PBXGroup; children = ( - 52CA2F1926ECC58B00BFD568 /* HitTestingTests.swift */, - 52CA2F1A26ECC58B00BFD568 /* GestureModifierTests.swift */, - 52CA2F1B26ECC58B00BFD568 /* GestureActionTests.swift */, - 52CA2F1C26ECC58B00BFD568 /* HighPriorityGestureModifierTests.swift */, - 52CA2F1D26ECC58B00BFD568 /* SimultaneousGestureModifierTests.swift */, + 520DC59226F60FBA00FCFFFD /* HitTestingTests.swift */, + 520DC59326F60FBA00FCFFFD /* GestureModifierTests.swift */, + 520DC59426F60FBA00FCFFFD /* GestureActionTests.swift */, + 520DC59526F60FBA00FCFFFD /* HighPriorityGestureModifierTests.swift */, + 520DC59626F60FBA00FCFFFD /* SimultaneousGestureModifierTests.swift */, ); path = GestureModifiers; sourceTree = ""; }; - 52CA2F3026ECC58B00BFD568 /* TestResources */ = { + 520DC5A926F60FBA00FCFFFD /* TestResources */ = { isa = PBXGroup; children = ( - 52CA2F3126ECC58B00BFD568 /* Test.strings */, + 520DC5AA26F60FBA00FCFFFD /* Test.strings */, ); path = TestResources; sourceTree = ""; }; - 52CA2F3726ECC58B00BFD568 /* SwiftUI */ = { + 520DC5B026F60FBA00FCFFFD /* SwiftUI */ = { isa = PBXGroup; children = ( - 52CA2F3826ECC58B00BFD568 /* ZStackTests.swift */, - 52CA2F3926ECC58B00BFD568 /* OptionalViewTests.swift */, - 52CA2F3A26ECC58B00BFD568 /* MenuButtonTests.swift */, - 52CA2F3B26ECC58B00BFD568 /* TouchBarTests.swift */, - 52CA2F3C26ECC58B00BFD568 /* GroupBoxTests.swift */, - 52CA2F3D26ECC58B00BFD568 /* SheetTests.swift */, - 52CA2F3E26ECC58B00BFD568 /* RadialGradientTests.swift */, - 52CA2F3F26ECC58B00BFD568 /* ScrollViewReaderTests.swift */, - 52CA2F4026ECC58B00BFD568 /* MapTests.swift */, - 52CA2F4126ECC58B00BFD568 /* SubscriptionViewTests.swift */, - 52CA2F4226ECC58B00BFD568 /* MenuTests.swift */, - 52CA2F4326ECC58B00BFD568 /* LabelTests.swift */, - 52CA2F4426ECC58B00BFD568 /* TextTests.swift */, - 52CA2F4526ECC58B00BFD568 /* OpaqueViewTests.swift */, - 52CA2F4626ECC58B00BFD568 /* HStackTests.swift */, - 52CA2F4726ECC58B00BFD568 /* TreeViewTests.swift */, - 52CA2F4826ECC58B00BFD568 /* EquatableViewTests.swift */, - 52CA2F4926ECC58B00BFD568 /* LinearGradientTests.swift */, - 52CA2F4A26ECC58B00BFD568 /* ToolbarTests.swift */, - 52CA2F4B26ECC58B00BFD568 /* DisclosureGroupTests.swift */, - 52CA2F4C26ECC58B00BFD568 /* GeometryReaderTests.swift */, - 52CA2F4D26ECC58B00BFD568 /* ProgressViewTests.swift */, - 52CA2F4E26ECC58B00BFD568 /* EnvironmentObjectInjectionTests.swift */, - 52CA2F4F26ECC58B00BFD568 /* TabViewTests.swift */, - 52CA2F5026ECC58B00BFD568 /* PopoverTests.swift */, - 52CA2F5126ECC58B00BFD568 /* EmptyViewTests.swift */, - 52CA2F5226ECC58B00BFD568 /* CustomViewModifierTests.swift */, - 52CA2F5326ECC58B00BFD568 /* ImageTests.swift */, - 52CA2F5426ECC58B00BFD568 /* EnvironmentReaderViewTests.swift */, - 52CA2F5526ECC58B00BFD568 /* StepperTests.swift */, - 52CA2F5626ECC58B00BFD568 /* FormTests.swift */, - 52CA2F5726ECC58B00BFD568 /* TupleViewTests.swift */, - 52CA2F5826ECC58B00BFD568 /* ConfirmationDialogTests.swift */, - 52CA2F5926ECC58B00BFD568 /* LazyVGridTests.swift */, - 52CA2F5A26ECC58B00BFD568 /* LazyHStackTests.swift */, - 52CA2F5B26ECC58B00BFD568 /* AlertTests.swift */, - 52CA2F5C26ECC58B00BFD568 /* TextAttributesTests.swift */, - 52CA2F5D26ECC58B00BFD568 /* PasteButtonTests.swift */, - 52CA2F5E26ECC58B00BFD568 /* DividerTests.swift */, - 52CA2F5F26ECC58B00BFD568 /* ForEachTests.swift */, - 52CA2F6026ECC58B00BFD568 /* ActionSheetTests.swift */, - 52CA2F6126ECC58B00BFD568 /* DelayedPreferenceViewTests.swift */, - 52CA2F6226ECC58B00BFD568 /* ButtonTests.swift */, - 52CA2F6326ECC58B00BFD568 /* LinkTests.swift */, - 52CA2F6426ECC58B00BFD568 /* SliderTests.swift */, - 52CA2F6526ECC58B00BFD568 /* CustomViewTests.swift */, - 52CA2F6626ECC58B00BFD568 /* ColorTests.swift */, - 52CA2F6726ECC58B00BFD568 /* TextEditorTests.swift */, - 52CA2F6826ECC58B00BFD568 /* MapAnnotationTests.swift */, - 52CA2F6926ECC58B00BFD568 /* AngularGradientTests.swift */, - 52CA2F6A26ECC58B00BFD568 /* ConditionalContentTests.swift */, - 52CA2F6B26ECC58B00BFD568 /* VSplitViewTests.swift */, - 52CA2F6C26ECC58B00BFD568 /* NavigationViewTests.swift */, - 52CA2F6D26ECC58B00BFD568 /* EditButtonTests.swift */, - 52CA2F6E26ECC58B00BFD568 /* IDViewTests.swift */, - 52CA2F6F26ECC58B00BFD568 /* CustomViewBuilderTests.swift */, - 52CA2F7026ECC58B00BFD568 /* TextFieldTests.swift */, - 52CA2F7126ECC58B00BFD568 /* FullScreenCoverTests.swift */, - 52CA2F7226ECC58B00BFD568 /* NavigationLinkTests.swift */, - 52CA2F7326ECC58B00BFD568 /* VStackTests.swift */, - 52CA2F7426ECC58B00BFD568 /* PickerTests.swift */, - 52CA2F7526ECC58B00BFD568 /* GroupTests.swift */, - 52CA2F7626ECC58B00BFD568 /* SectionTests.swift */, - 52CA2F7726ECC58B00BFD568 /* ToggleTests.swift */, - 52CA2F7826ECC58B00BFD568 /* SpacerTests.swift */, - 52CA2F7926ECC58B00BFD568 /* DatePickerTests.swift */, - 52CA2F7A26ECC58B00BFD568 /* SafeAreaInsetTests.swift */, - 52CA2F7B26ECC58B00BFD568 /* ColorPickerTests.swift */, - 52CA2F7C26ECC58B00BFD568 /* OutlineGroupTests.swift */, - 52CA2F7D26ECC58B00BFD568 /* ScrollViewTests.swift */, - 52CA2F7E26ECC58B00BFD568 /* SecureFieldTests.swift */, - 52CA2F7F26ECC58B00BFD568 /* LazyHGridTests.swift */, - 52CA2F8026ECC58B00BFD568 /* ShapeTests.swift */, - 52CA2F8126ECC58B00BFD568 /* ListTests.swift */, - 52CA2F8226ECC58B00BFD568 /* HSplitViewTests.swift */, - 52CA2F8326ECC58B00BFD568 /* AnyViewTests.swift */, - 52CA2F8426ECC58B00BFD568 /* LazyVStackTests.swift */, + 520DC5B126F60FBA00FCFFFD /* ZStackTests.swift */, + 520DC5B226F60FBA00FCFFFD /* OptionalViewTests.swift */, + 520DC5B326F60FBA00FCFFFD /* MenuButtonTests.swift */, + 520DC5B426F60FBA00FCFFFD /* TouchBarTests.swift */, + 520DC5B526F60FBA00FCFFFD /* GroupBoxTests.swift */, + 520DC5B626F60FBA00FCFFFD /* SheetTests.swift */, + 520DC5B726F60FBA00FCFFFD /* RadialGradientTests.swift */, + 520DC5B826F60FBA00FCFFFD /* ScrollViewReaderTests.swift */, + 520DC5B926F60FBA00FCFFFD /* MapTests.swift */, + 520DC5BA26F60FBA00FCFFFD /* SubscriptionViewTests.swift */, + 520DC5BB26F60FBA00FCFFFD /* MenuTests.swift */, + 520DC5BC26F60FBA00FCFFFD /* LabelTests.swift */, + 520DC5BD26F60FBA00FCFFFD /* TextTests.swift */, + 520DC5BE26F60FBA00FCFFFD /* OpaqueViewTests.swift */, + 520DC5BF26F60FBA00FCFFFD /* HStackTests.swift */, + 520DC5C026F60FBA00FCFFFD /* TreeViewTests.swift */, + 520DC5C126F60FBA00FCFFFD /* EquatableViewTests.swift */, + 520DC5C226F60FBA00FCFFFD /* LinearGradientTests.swift */, + 520DC5C326F60FBA00FCFFFD /* ToolbarTests.swift */, + 520DC5C426F60FBA00FCFFFD /* DisclosureGroupTests.swift */, + 520DC5C526F60FBA00FCFFFD /* GeometryReaderTests.swift */, + 520DC5C626F60FBA00FCFFFD /* ProgressViewTests.swift */, + 520DC5C726F60FBA00FCFFFD /* EnvironmentObjectInjectionTests.swift */, + 520DC5C826F60FBA00FCFFFD /* TabViewTests.swift */, + 520DC5C926F60FBA00FCFFFD /* PopoverTests.swift */, + 520DC5CA26F60FBA00FCFFFD /* EmptyViewTests.swift */, + 520DC5CB26F60FBA00FCFFFD /* CustomViewModifierTests.swift */, + 520DC5CC26F60FBA00FCFFFD /* ImageTests.swift */, + 520DC5CD26F60FBA00FCFFFD /* EnvironmentReaderViewTests.swift */, + 520DC5CE26F60FBA00FCFFFD /* StepperTests.swift */, + 520DC5CF26F60FBA00FCFFFD /* FormTests.swift */, + 520DC5D026F60FBA00FCFFFD /* TupleViewTests.swift */, + 520DC5D126F60FBA00FCFFFD /* ConfirmationDialogTests.swift */, + 520DC5D226F60FBA00FCFFFD /* LazyVGridTests.swift */, + 520DC5D326F60FBA00FCFFFD /* LazyHStackTests.swift */, + 520DC5D426F60FBA00FCFFFD /* AlertTests.swift */, + 520DC5D526F60FBA00FCFFFD /* TextAttributesTests.swift */, + 520DC5D626F60FBA00FCFFFD /* PasteButtonTests.swift */, + 520DC5D726F60FBA00FCFFFD /* DividerTests.swift */, + 520DC5D826F60FBA00FCFFFD /* ForEachTests.swift */, + 520DC5D926F60FBA00FCFFFD /* ActionSheetTests.swift */, + 520DC5DA26F60FBA00FCFFFD /* DelayedPreferenceViewTests.swift */, + 520DC5DB26F60FBA00FCFFFD /* ButtonTests.swift */, + 520DC5DC26F60FBA00FCFFFD /* LinkTests.swift */, + 520DC5DD26F60FBA00FCFFFD /* SliderTests.swift */, + 520DC5DE26F60FBA00FCFFFD /* CustomViewTests.swift */, + 520DC5DF26F60FBA00FCFFFD /* ColorTests.swift */, + 520DC5E026F60FBA00FCFFFD /* TextEditorTests.swift */, + 520DC5E126F60FBA00FCFFFD /* MapAnnotationTests.swift */, + 520DC5E226F60FBA00FCFFFD /* AngularGradientTests.swift */, + 520DC5E326F60FBA00FCFFFD /* ConditionalContentTests.swift */, + 520DC5E426F60FBA00FCFFFD /* VSplitViewTests.swift */, + 520DC5E526F60FBA00FCFFFD /* NavigationViewTests.swift */, + 520DC5E626F60FBA00FCFFFD /* EditButtonTests.swift */, + 520DC5E726F60FBA00FCFFFD /* IDViewTests.swift */, + 520DC5E826F60FBA00FCFFFD /* CustomViewBuilderTests.swift */, + 520DC5E926F60FBA00FCFFFD /* TextFieldTests.swift */, + 520DC5EA26F60FBA00FCFFFD /* FullScreenCoverTests.swift */, + 520DC5EB26F60FBA00FCFFFD /* NavigationLinkTests.swift */, + 520DC5EC26F60FBA00FCFFFD /* VStackTests.swift */, + 520DC5ED26F60FBA00FCFFFD /* PickerTests.swift */, + 520DC5EE26F60FBA00FCFFFD /* GroupTests.swift */, + 520DC5EF26F60FBA00FCFFFD /* SectionTests.swift */, + 520DC5F026F60FBA00FCFFFD /* ToggleTests.swift */, + 520DC5F126F60FBA00FCFFFD /* SpacerTests.swift */, + 520DC5F226F60FBA00FCFFFD /* DatePickerTests.swift */, + 520DC5F326F60FBA00FCFFFD /* SafeAreaInsetTests.swift */, + 520DC5F426F60FBA00FCFFFD /* ColorPickerTests.swift */, + 520DC5F526F60FBA00FCFFFD /* OutlineGroupTests.swift */, + 520DC5F626F60FBA00FCFFFD /* ScrollViewTests.swift */, + 520DC5F726F60FBA00FCFFFD /* SecureFieldTests.swift */, + 520DC5F826F60FBA00FCFFFD /* LazyHGridTests.swift */, + 520DC5F926F60FBA00FCFFFD /* ShapeTests.swift */, + 520DC5FA26F60FBA00FCFFFD /* ListTests.swift */, + 520DC5FB26F60FBA00FCFFFD /* HSplitViewTests.swift */, + 520DC5FC26F60FBA00FCFFFD /* AnyViewTests.swift */, + 520DC5FD26F60FBA00FCFFFD /* LazyVStackTests.swift */, ); path = SwiftUI; sourceTree = ""; }; - 52CA2F8526ECC58B00BFD568 /* ViewModifiers */ = { + 520DC5FE26F60FBA00FCFFFD /* ViewModifiers */ = { isa = PBXGroup; children = ( - 52CA2F8626ECC58B00BFD568 /* ConfigurationModifiersTests.swift */, - 52CA2F8726ECC58B00BFD568 /* PresentationModifiersTests.swift */, - 52CA2F8826ECC58B00BFD568 /* InteractionModifiersTests.swift */, - 52CA2F8926ECC58B00BFD568 /* EventsModifiersTests.swift */, - 52CA2F8A26ECC58B00BFD568 /* SizingModifiersTests.swift */, - 52CA2F8B26ECC58B00BFD568 /* NestedModifiersTests.swift */, - 52CA2F8C26ECC58B00BFD568 /* PositioningModifiersTests.swift */, - 52CA2F8D26ECC58B00BFD568 /* TextInputModifiersTests.swift */, - 52CA2F8E26ECC58B00BFD568 /* CustomStyleModifiersTests.swift */, - 52CA2F8F26ECC58B00BFD568 /* TransitiveModifiersTests.swift */, - 52CA2F9026ECC58B00BFD568 /* AccessibilityModifiersTests.swift */, - 52CA2F9126ECC58B00BFD568 /* AnimationModifiersTests.swift */, - 52CA2F9226ECC58B00BFD568 /* VisualEffectModifiersTests.swift */, - 52CA2F9326ECC58B00BFD568 /* EnvironmentModifiersTests.swift */, - 52CA2F9426ECC58B00BFD568 /* ViewPaddingTests.swift */, - 52CA2F9526ECC58B00BFD568 /* TransformingModifiersTests.swift */, + 520DC5FF26F60FBA00FCFFFD /* ConfigurationModifiersTests.swift */, + 520DC60026F60FBA00FCFFFD /* PresentationModifiersTests.swift */, + 520DC60126F60FBA00FCFFFD /* InteractionModifiersTests.swift */, + 520DC60226F60FBA00FCFFFD /* EventsModifiersTests.swift */, + 520DC60326F60FBA00FCFFFD /* SizingModifiersTests.swift */, + 520DC60426F60FBA00FCFFFD /* NestedModifiersTests.swift */, + 520DC60526F60FBA00FCFFFD /* PositioningModifiersTests.swift */, + 520DC60626F60FBA00FCFFFD /* TextInputModifiersTests.swift */, + 520DC60726F60FBA00FCFFFD /* CustomStyleModifiersTests.swift */, + 520DC60826F60FBA00FCFFFD /* TransitiveModifiersTests.swift */, + 520DC60926F60FBA00FCFFFD /* AccessibilityModifiersTests.swift */, + 520DC60A26F60FBA00FCFFFD /* AnimationModifiersTests.swift */, + 520DC60B26F60FBA00FCFFFD /* VisualEffectModifiersTests.swift */, + 520DC60C26F60FBA00FCFFFD /* EnvironmentModifiersTests.swift */, + 520DC60D26F60FBA00FCFFFD /* ViewPaddingTests.swift */, + 520DC60E26F60FBA00FCFFFD /* TransformingModifiersTests.swift */, ); path = ViewModifiers; sourceTree = ""; }; + 52CA2F0F26ECC56600BFD568 /* Packages */ = { + isa = PBXGroup; + children = ( + 52CA2F1026ECC56600BFD568 /* ViewInspector */, + ); + name = Packages; + sourceTree = ""; + }; 52CA301226ECC5D200BFD568 /* Frameworks */ = { isa = PBXGroup; children = ( @@ -558,7 +558,7 @@ 52CA2F0F26ECC56600BFD568 /* Packages */, 52E3259226C72E7800CCE47E /* watchOS-App */, 52E3259E26C72E7900CCE47E /* watchOS-Ext */, - 520213A526ECB45D00E94C6E /* watchOS-Tests */, + 520DC58926F60FA600FCFFFD /* watchOS-Tests */, 52E3258B26C72E7800CCE47E /* Products */, 52CA301226ECC5D200BFD568 /* Frameworks */, ); @@ -745,7 +745,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - 52CA2FB226ECC58B00BFD568 /* Test.strings in Resources */, + 520DC62B26F60FBB00FCFFFD /* Test.strings in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -785,129 +785,129 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 52CA2FD826ECC58B00BFD568 /* AlertTests.swift in Sources */, - 52CA2FB326ECC58B00BFD568 /* InspectableViewTests.swift in Sources */, - 52CA2FA526ECC58B00BFD568 /* ExclusiveGestureTests.swift in Sources */, - 52CA2FB726ECC58B00BFD568 /* MenuButtonTests.swift in Sources */, - 52CA2FCB26ECC58B00BFD568 /* EnvironmentObjectInjectionTests.swift in Sources */, - 52CA300126ECC58B00BFD568 /* LazyVStackTests.swift in Sources */, - 52CA2FE526ECC58B00BFD568 /* MapAnnotationTests.swift in Sources */, - 52CA2FBF26ECC58B00BFD568 /* MenuTests.swift in Sources */, - 52CA300326ECC58B00BFD568 /* PresentationModifiersTests.swift in Sources */, - 52CA2FE126ECC58B00BFD568 /* SliderTests.swift in Sources */, - 52CA2FCD26ECC58B00BFD568 /* PopoverTests.swift in Sources */, - 52CA2FDD26ECC58B00BFD568 /* ActionSheetTests.swift in Sources */, - 52CA2FF526ECC58B00BFD568 /* SpacerTests.swift in Sources */, - 52CA2FBB26ECC58B00BFD568 /* RadialGradientTests.swift in Sources */, - 52CA2FED26ECC58B00BFD568 /* TextFieldTests.swift in Sources */, - 52CA2FE026ECC58B00BFD568 /* LinkTests.swift in Sources */, - 52CA300526ECC58B00BFD568 /* EventsModifiersTests.swift in Sources */, - 52CA2FD226ECC58B00BFD568 /* StepperTests.swift in Sources */, - 52CA2FD526ECC58B00BFD568 /* ConfirmationDialogTests.swift in Sources */, - 52CA2FFF26ECC58B00BFD568 /* HSplitViewTests.swift in Sources */, - 52CA2FE226ECC58B00BFD568 /* CustomViewTests.swift in Sources */, - 52CA2FFE26ECC58B00BFD568 /* ListTests.swift in Sources */, - 52CA2F9B26ECC58B00BFD568 /* HitTestingTests.swift in Sources */, - 52CA2FF326ECC58B00BFD568 /* SectionTests.swift in Sources */, - 52CA2FE826ECC58B00BFD568 /* VSplitViewTests.swift in Sources */, - 52CA300F26ECC58B00BFD568 /* EnvironmentModifiersTests.swift in Sources */, - 52CA2FFB26ECC58B00BFD568 /* SecureFieldTests.swift in Sources */, - 52CA300E26ECC58B00BFD568 /* VisualEffectModifiersTests.swift in Sources */, - 52CA300026ECC58B00BFD568 /* AnyViewTests.swift in Sources */, - 52CA2FE626ECC58B00BFD568 /* AngularGradientTests.swift in Sources */, - 52CA2FF126ECC58B00BFD568 /* PickerTests.swift in Sources */, - 52CA2FAC26ECC58B00BFD568 /* SimultaneousGestureTests.swift in Sources */, - 52CA300626ECC58B00BFD568 /* SizingModifiersTests.swift in Sources */, - 52CA2FEC26ECC58B00BFD568 /* CustomViewBuilderTests.swift in Sources */, - 52CA2FB526ECC58B00BFD568 /* ZStackTests.swift in Sources */, - 52CA2FAE26ECC58B00BFD568 /* CommonComposedGestureChangedTests.swift in Sources */, - 52CA2FEA26ECC58B00BFD568 /* EditButtonTests.swift in Sources */, - 52CA2FC226ECC58B00BFD568 /* OpaqueViewTests.swift in Sources */, - 52CA2FCE26ECC58B00BFD568 /* EmptyViewTests.swift in Sources */, - 52CA2FB626ECC58B00BFD568 /* OptionalViewTests.swift in Sources */, - 52CA300226ECC58B00BFD568 /* ConfigurationModifiersTests.swift in Sources */, - 52CA300426ECC58B00BFD568 /* InteractionModifiersTests.swift in Sources */, - 52CA300826ECC58B00BFD568 /* PositioningModifiersTests.swift in Sources */, - 52CA300726ECC58B00BFD568 /* NestedModifiersTests.swift in Sources */, - 52CA300B26ECC58B00BFD568 /* TransitiveModifiersTests.swift in Sources */, - 52CA300D26ECC58B00BFD568 /* AnimationModifiersTests.swift in Sources */, - 52CA2FEB26ECC58B00BFD568 /* IDViewTests.swift in Sources */, - 52CA2FBE26ECC58B00BFD568 /* SubscriptionViewTests.swift in Sources */, - 52CA2FA126ECC58B00BFD568 /* SequenceGestureChildrenTests.swift in Sources */, - 52CA2FE426ECC58B00BFD568 /* TextEditorTests.swift in Sources */, - 52CA2F9F26ECC58B00BFD568 /* SimultaneousGestureModifierTests.swift in Sources */, - 52CA2F9E26ECC58B00BFD568 /* HighPriorityGestureModifierTests.swift in Sources */, - 52CA2FFD26ECC58B00BFD568 /* ShapeTests.swift in Sources */, - 52CA2FC726ECC58B00BFD568 /* ToolbarTests.swift in Sources */, - 52CA2FC326ECC58B00BFD568 /* HStackTests.swift in Sources */, - 52CA2FB826ECC58B00BFD568 /* TouchBarTests.swift in Sources */, - 52CA2FCF26ECC58B00BFD568 /* CustomViewModifierTests.swift in Sources */, - 52CA300926ECC58B00BFD568 /* TextInputModifiersTests.swift in Sources */, - 52CA2FA826ECC58B00BFD568 /* GestureExampleTests.swift in Sources */, - 52CA2FA626ECC58B00BFD568 /* SimultaneousGestureChildrenTests.swift in Sources */, - 52CA2F9C26ECC58B00BFD568 /* GestureModifierTests.swift in Sources */, - 52CA2FD026ECC58B00BFD568 /* ImageTests.swift in Sources */, - 52CA2FE326ECC58B00BFD568 /* ColorTests.swift in Sources */, - 52CA2FDF26ECC58B00BFD568 /* ButtonTests.swift in Sources */, - 52CA2FBA26ECC58B00BFD568 /* SheetTests.swift in Sources */, - 52CA2FAB26ECC58B00BFD568 /* CommonComposedGestureUpdatingTests.swift in Sources */, - 52CA2FD126ECC58B00BFD568 /* EnvironmentReaderViewTests.swift in Sources */, - 52CA2FF826ECC58B00BFD568 /* ColorPickerTests.swift in Sources */, - 52CA2FF926ECC58B00BFD568 /* OutlineGroupTests.swift in Sources */, - 52CA2F9826ECC58B00BFD568 /* InspectionEmissaryTests.swift in Sources */, - 52CA2FF426ECC58B00BFD568 /* ToggleTests.swift in Sources */, - 52CA2FA926ECC58B00BFD568 /* DragGestureTests.swift in Sources */, - 52CA2FE726ECC58B00BFD568 /* ConditionalContentTests.swift in Sources */, - 52CA301126ECC58B00BFD568 /* TransformingModifiersTests.swift in Sources */, - 52CA2FCA26ECC58B00BFD568 /* ProgressViewTests.swift in Sources */, - 52CA2FF226ECC58B00BFD568 /* GroupTests.swift in Sources */, - 52CA2FD426ECC58B00BFD568 /* TupleViewTests.swift in Sources */, - 52CA300C26ECC58B00BFD568 /* AccessibilityModifiersTests.swift in Sources */, - 52CA2FBC26ECC58B00BFD568 /* ScrollViewReaderTests.swift in Sources */, - 52CA2FAF26ECC58B00BFD568 /* LongPressGestureTests.swift in Sources */, - 52CA2FF726ECC58B00BFD568 /* SafeAreaInsetTests.swift in Sources */, - 52CA301026ECC58B00BFD568 /* ViewPaddingTests.swift in Sources */, - 52CA300A26ECC58B00BFD568 /* CustomStyleModifiersTests.swift in Sources */, - 52CA2FB426ECC58B00BFD568 /* InspectorTests.swift in Sources */, - 52CA2FC126ECC58B00BFD568 /* TextTests.swift in Sources */, - 52CA2FA426ECC58B00BFD568 /* TapGestureTests.swift in Sources */, - 52CA2FAD26ECC58B00BFD568 /* CommonComposedGestureEndedTests.swift in Sources */, - 52CA2FB026ECC58B00BFD568 /* CommonGestureTests.swift in Sources */, - 52CA2FF626ECC58B00BFD568 /* DatePickerTests.swift in Sources */, - 52CA2FEE26ECC58B00BFD568 /* FullScreenCoverTests.swift in Sources */, - 52CA2FBD26ECC58B00BFD568 /* MapTests.swift in Sources */, - 52CA2FC626ECC58B00BFD568 /* LinearGradientTests.swift in Sources */, - 52CA2FD326ECC58B00BFD568 /* FormTests.swift in Sources */, - 52CA2FC526ECC58B00BFD568 /* EquatableViewTests.swift in Sources */, - 52CA2FDE26ECC58B00BFD568 /* DelayedPreferenceViewTests.swift in Sources */, - 52CA2FFC26ECC58B00BFD568 /* LazyHGridTests.swift in Sources */, - 52CA2F9D26ECC58B00BFD568 /* GestureActionTests.swift in Sources */, - 52CA2FA026ECC58B00BFD568 /* ComposedGestureExampleTests.swift in Sources */, - 52CA2FDA26ECC58B00BFD568 /* PasteButtonTests.swift in Sources */, - 52CA2FDC26ECC58B00BFD568 /* ForEachTests.swift in Sources */, - 52CA2FEF26ECC58B00BFD568 /* NavigationLinkTests.swift in Sources */, - 52CA2FDB26ECC58B00BFD568 /* DividerTests.swift in Sources */, - 52CA2F9626ECC58B00BFD568 /* LazyGroupTests.swift in Sources */, - 52CA2FCC26ECC58B00BFD568 /* TabViewTests.swift in Sources */, - 52CA2F9926ECC58B00BFD568 /* BaseTypesTests.swift in Sources */, - 52CA2FA226ECC58B00BFD568 /* RotationGestureTests.swift in Sources */, - 52CA2FE926ECC58B00BFD568 /* NavigationViewTests.swift in Sources */, - 52CA2FA326ECC58B00BFD568 /* ExclusiveGestureChildrenTests.swift in Sources */, - 52CA2F9726ECC58B00BFD568 /* ViewHostingTests.swift in Sources */, - 52CA2FB926ECC58B00BFD568 /* GroupBoxTests.swift in Sources */, - 52CA2FAA26ECC58B00BFD568 /* CommonComposedGestureTests.swift in Sources */, - 52CA2FC026ECC58B00BFD568 /* LabelTests.swift in Sources */, - 52CA2FB126ECC58B00BFD568 /* MagnificationGestureTests.swift in Sources */, - 52CA2FF026ECC58B00BFD568 /* VStackTests.swift in Sources */, - 52CA2FA726ECC58B00BFD568 /* SequenceGestureTests.swift in Sources */, - 52CA2FD926ECC58B00BFD568 /* TextAttributesTests.swift in Sources */, - 52CA2FFA26ECC58B00BFD568 /* ScrollViewTests.swift in Sources */, - 52CA2FC426ECC58B00BFD568 /* TreeViewTests.swift in Sources */, - 52CA2FD726ECC58B00BFD568 /* LazyHStackTests.swift in Sources */, - 52CA2FC826ECC58B00BFD568 /* DisclosureGroupTests.swift in Sources */, - 52CA2F9A26ECC58B00BFD568 /* ViewSearchTests.swift in Sources */, - 52CA2FD626ECC58B00BFD568 /* LazyVGridTests.swift in Sources */, - 52CA2FC926ECC58B00BFD568 /* GeometryReaderTests.swift in Sources */, + 520DC65126F60FBB00FCFFFD /* AlertTests.swift in Sources */, + 520DC62C26F60FBB00FCFFFD /* InspectableViewTests.swift in Sources */, + 520DC61E26F60FBA00FCFFFD /* ExclusiveGestureTests.swift in Sources */, + 520DC63026F60FBB00FCFFFD /* MenuButtonTests.swift in Sources */, + 520DC64426F60FBB00FCFFFD /* EnvironmentObjectInjectionTests.swift in Sources */, + 520DC67A26F60FBB00FCFFFD /* LazyVStackTests.swift in Sources */, + 520DC65E26F60FBB00FCFFFD /* MapAnnotationTests.swift in Sources */, + 520DC63826F60FBB00FCFFFD /* MenuTests.swift in Sources */, + 520DC67C26F60FBB00FCFFFD /* PresentationModifiersTests.swift in Sources */, + 520DC65A26F60FBB00FCFFFD /* SliderTests.swift in Sources */, + 520DC64626F60FBB00FCFFFD /* PopoverTests.swift in Sources */, + 520DC65626F60FBB00FCFFFD /* ActionSheetTests.swift in Sources */, + 520DC66E26F60FBB00FCFFFD /* SpacerTests.swift in Sources */, + 520DC63426F60FBB00FCFFFD /* RadialGradientTests.swift in Sources */, + 520DC66626F60FBB00FCFFFD /* TextFieldTests.swift in Sources */, + 520DC65926F60FBB00FCFFFD /* LinkTests.swift in Sources */, + 520DC67E26F60FBB00FCFFFD /* EventsModifiersTests.swift in Sources */, + 520DC64B26F60FBB00FCFFFD /* StepperTests.swift in Sources */, + 520DC64E26F60FBB00FCFFFD /* ConfirmationDialogTests.swift in Sources */, + 520DC67826F60FBB00FCFFFD /* HSplitViewTests.swift in Sources */, + 520DC65B26F60FBB00FCFFFD /* CustomViewTests.swift in Sources */, + 520DC67726F60FBB00FCFFFD /* ListTests.swift in Sources */, + 520DC61426F60FBA00FCFFFD /* HitTestingTests.swift in Sources */, + 520DC66C26F60FBB00FCFFFD /* SectionTests.swift in Sources */, + 520DC66126F60FBB00FCFFFD /* VSplitViewTests.swift in Sources */, + 520DC68826F60FBB00FCFFFD /* EnvironmentModifiersTests.swift in Sources */, + 520DC67426F60FBB00FCFFFD /* SecureFieldTests.swift in Sources */, + 520DC68726F60FBB00FCFFFD /* VisualEffectModifiersTests.swift in Sources */, + 520DC67926F60FBB00FCFFFD /* AnyViewTests.swift in Sources */, + 520DC65F26F60FBB00FCFFFD /* AngularGradientTests.swift in Sources */, + 520DC66A26F60FBB00FCFFFD /* PickerTests.swift in Sources */, + 520DC62526F60FBB00FCFFFD /* SimultaneousGestureTests.swift in Sources */, + 520DC67F26F60FBB00FCFFFD /* SizingModifiersTests.swift in Sources */, + 520DC66526F60FBB00FCFFFD /* CustomViewBuilderTests.swift in Sources */, + 520DC62E26F60FBB00FCFFFD /* ZStackTests.swift in Sources */, + 520DC62726F60FBB00FCFFFD /* CommonComposedGestureChangedTests.swift in Sources */, + 520DC66326F60FBB00FCFFFD /* EditButtonTests.swift in Sources */, + 520DC63B26F60FBB00FCFFFD /* OpaqueViewTests.swift in Sources */, + 520DC64726F60FBB00FCFFFD /* EmptyViewTests.swift in Sources */, + 520DC62F26F60FBB00FCFFFD /* OptionalViewTests.swift in Sources */, + 520DC67B26F60FBB00FCFFFD /* ConfigurationModifiersTests.swift in Sources */, + 520DC67D26F60FBB00FCFFFD /* InteractionModifiersTests.swift in Sources */, + 520DC68126F60FBB00FCFFFD /* PositioningModifiersTests.swift in Sources */, + 520DC68026F60FBB00FCFFFD /* NestedModifiersTests.swift in Sources */, + 520DC68426F60FBB00FCFFFD /* TransitiveModifiersTests.swift in Sources */, + 520DC68626F60FBB00FCFFFD /* AnimationModifiersTests.swift in Sources */, + 520DC66426F60FBB00FCFFFD /* IDViewTests.swift in Sources */, + 520DC63726F60FBB00FCFFFD /* SubscriptionViewTests.swift in Sources */, + 520DC61A26F60FBA00FCFFFD /* SequenceGestureChildrenTests.swift in Sources */, + 520DC65D26F60FBB00FCFFFD /* TextEditorTests.swift in Sources */, + 520DC61826F60FBA00FCFFFD /* SimultaneousGestureModifierTests.swift in Sources */, + 520DC61726F60FBA00FCFFFD /* HighPriorityGestureModifierTests.swift in Sources */, + 520DC67626F60FBB00FCFFFD /* ShapeTests.swift in Sources */, + 520DC64026F60FBB00FCFFFD /* ToolbarTests.swift in Sources */, + 520DC63C26F60FBB00FCFFFD /* HStackTests.swift in Sources */, + 520DC63126F60FBB00FCFFFD /* TouchBarTests.swift in Sources */, + 520DC64826F60FBB00FCFFFD /* CustomViewModifierTests.swift in Sources */, + 520DC68226F60FBB00FCFFFD /* TextInputModifiersTests.swift in Sources */, + 520DC62126F60FBA00FCFFFD /* GestureExampleTests.swift in Sources */, + 520DC61F26F60FBA00FCFFFD /* SimultaneousGestureChildrenTests.swift in Sources */, + 520DC61526F60FBA00FCFFFD /* GestureModifierTests.swift in Sources */, + 520DC64926F60FBB00FCFFFD /* ImageTests.swift in Sources */, + 520DC65C26F60FBB00FCFFFD /* ColorTests.swift in Sources */, + 520DC65826F60FBB00FCFFFD /* ButtonTests.swift in Sources */, + 520DC63326F60FBB00FCFFFD /* SheetTests.swift in Sources */, + 520DC62426F60FBA00FCFFFD /* CommonComposedGestureUpdatingTests.swift in Sources */, + 520DC64A26F60FBB00FCFFFD /* EnvironmentReaderViewTests.swift in Sources */, + 520DC67126F60FBB00FCFFFD /* ColorPickerTests.swift in Sources */, + 520DC67226F60FBB00FCFFFD /* OutlineGroupTests.swift in Sources */, + 520DC61126F60FBA00FCFFFD /* InspectionEmissaryTests.swift in Sources */, + 520DC66D26F60FBB00FCFFFD /* ToggleTests.swift in Sources */, + 520DC62226F60FBA00FCFFFD /* DragGestureTests.swift in Sources */, + 520DC66026F60FBB00FCFFFD /* ConditionalContentTests.swift in Sources */, + 520DC68A26F60FBB00FCFFFD /* TransformingModifiersTests.swift in Sources */, + 520DC64326F60FBB00FCFFFD /* ProgressViewTests.swift in Sources */, + 520DC66B26F60FBB00FCFFFD /* GroupTests.swift in Sources */, + 520DC64D26F60FBB00FCFFFD /* TupleViewTests.swift in Sources */, + 520DC68526F60FBB00FCFFFD /* AccessibilityModifiersTests.swift in Sources */, + 520DC63526F60FBB00FCFFFD /* ScrollViewReaderTests.swift in Sources */, + 520DC62826F60FBB00FCFFFD /* LongPressGestureTests.swift in Sources */, + 520DC67026F60FBB00FCFFFD /* SafeAreaInsetTests.swift in Sources */, + 520DC68926F60FBB00FCFFFD /* ViewPaddingTests.swift in Sources */, + 520DC68326F60FBB00FCFFFD /* CustomStyleModifiersTests.swift in Sources */, + 520DC62D26F60FBB00FCFFFD /* InspectorTests.swift in Sources */, + 520DC63A26F60FBB00FCFFFD /* TextTests.swift in Sources */, + 520DC61D26F60FBA00FCFFFD /* TapGestureTests.swift in Sources */, + 520DC62626F60FBB00FCFFFD /* CommonComposedGestureEndedTests.swift in Sources */, + 520DC62926F60FBB00FCFFFD /* CommonGestureTests.swift in Sources */, + 520DC66F26F60FBB00FCFFFD /* DatePickerTests.swift in Sources */, + 520DC66726F60FBB00FCFFFD /* FullScreenCoverTests.swift in Sources */, + 520DC63626F60FBB00FCFFFD /* MapTests.swift in Sources */, + 520DC63F26F60FBB00FCFFFD /* LinearGradientTests.swift in Sources */, + 520DC64C26F60FBB00FCFFFD /* FormTests.swift in Sources */, + 520DC63E26F60FBB00FCFFFD /* EquatableViewTests.swift in Sources */, + 520DC65726F60FBB00FCFFFD /* DelayedPreferenceViewTests.swift in Sources */, + 520DC67526F60FBB00FCFFFD /* LazyHGridTests.swift in Sources */, + 520DC61626F60FBA00FCFFFD /* GestureActionTests.swift in Sources */, + 520DC61926F60FBA00FCFFFD /* ComposedGestureExampleTests.swift in Sources */, + 520DC65326F60FBB00FCFFFD /* PasteButtonTests.swift in Sources */, + 520DC65526F60FBB00FCFFFD /* ForEachTests.swift in Sources */, + 520DC66826F60FBB00FCFFFD /* NavigationLinkTests.swift in Sources */, + 520DC65426F60FBB00FCFFFD /* DividerTests.swift in Sources */, + 520DC60F26F60FBA00FCFFFD /* LazyGroupTests.swift in Sources */, + 520DC64526F60FBB00FCFFFD /* TabViewTests.swift in Sources */, + 520DC61226F60FBA00FCFFFD /* BaseTypesTests.swift in Sources */, + 520DC61B26F60FBA00FCFFFD /* RotationGestureTests.swift in Sources */, + 520DC66226F60FBB00FCFFFD /* NavigationViewTests.swift in Sources */, + 520DC61C26F60FBA00FCFFFD /* ExclusiveGestureChildrenTests.swift in Sources */, + 520DC61026F60FBA00FCFFFD /* ViewHostingTests.swift in Sources */, + 520DC63226F60FBB00FCFFFD /* GroupBoxTests.swift in Sources */, + 520DC62326F60FBA00FCFFFD /* CommonComposedGestureTests.swift in Sources */, + 520DC63926F60FBB00FCFFFD /* LabelTests.swift in Sources */, + 520DC62A26F60FBB00FCFFFD /* MagnificationGestureTests.swift in Sources */, + 520DC66926F60FBB00FCFFFD /* VStackTests.swift in Sources */, + 520DC62026F60FBA00FCFFFD /* SequenceGestureTests.swift in Sources */, + 520DC65226F60FBB00FCFFFD /* TextAttributesTests.swift in Sources */, + 520DC67326F60FBB00FCFFFD /* ScrollViewTests.swift in Sources */, + 520DC63D26F60FBB00FCFFFD /* TreeViewTests.swift in Sources */, + 520DC65026F60FBB00FCFFFD /* LazyHStackTests.swift in Sources */, + 520DC64126F60FBB00FCFFFD /* DisclosureGroupTests.swift in Sources */, + 520DC61326F60FBA00FCFFFD /* ViewSearchTests.swift in Sources */, + 520DC64F26F60FBB00FCFFFD /* LazyVGridTests.swift in Sources */, + 520DC64226F60FBB00FCFFFD /* GeometryReaderTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -949,22 +949,22 @@ /* End PBXTargetDependency section */ /* Begin PBXVariantGroup section */ - 5293010426EFC96600012E90 /* Interface.storyboard */ = { + 520DC5AA26F60FBA00FCFFFD /* Test.strings */ = { isa = PBXVariantGroup; children = ( - 5293010526EFC96600012E90 /* Base */, + 520DC5AB26F60FBA00FCFFFD /* en */, + 520DC5AC26F60FBA00FCFFFD /* en-AU */, + 520DC5AD26F60FBA00FCFFFD /* ru */, ); - name = Interface.storyboard; + name = Test.strings; sourceTree = ""; }; - 52CA2F3126ECC58B00BFD568 /* Test.strings */ = { + 5293010426EFC96600012E90 /* Interface.storyboard */ = { isa = PBXVariantGroup; children = ( - 52CA2F3226ECC58B00BFD568 /* en */, - 52CA2F3326ECC58B00BFD568 /* en-AU */, - 52CA2F3426ECC58B00BFD568 /* ru */, + 5293010526EFC96600012E90 /* Base */, ); - name = Test.strings; + name = Interface.storyboard; sourceTree = ""; }; /* End PBXVariantGroup section */ diff --git a/.watchOS/watchOS.xcodeproj/xcshareddata/xcschemes/watchOS-App-2.xcscheme b/.watchOS/watchOS.xcodeproj/xcshareddata/xcschemes/watchOS-App-2.xcscheme index bf959b3b..ec49b511 100644 --- a/.watchOS/watchOS.xcodeproj/xcshareddata/xcschemes/watchOS-App-2.xcscheme +++ b/.watchOS/watchOS.xcodeproj/xcshareddata/xcschemes/watchOS-App-2.xcscheme @@ -81,15 +81,6 @@ savedToolIdentifier = "" useCustomWorkingDirectory = "NO" debugDocumentVersioning = "YES"> - - - - From 3f8dc49d9396e0b6f3bf863d6cba2f4d554dafa5 Mon Sep 17 00:00:00 2001 From: Alexey Naumov Date: Sat, 18 Sep 2021 15:17:33 +0300 Subject: [PATCH 67/99] Split test target --- .watchOS/watchOS.xcodeproj/project.pbxproj | 398 +++++++++++++++++- .../xcschemes/watchOS-App-1.xcscheme | 4 +- .../xcschemes/watchOS-App-2.xcscheme | 12 +- 3 files changed, 398 insertions(+), 16 deletions(-) diff --git a/.watchOS/watchOS.xcodeproj/project.pbxproj b/.watchOS/watchOS.xcodeproj/project.pbxproj index befb085b..669ee9ce 100644 --- a/.watchOS/watchOS.xcodeproj/project.pbxproj +++ b/.watchOS/watchOS.xcodeproj/project.pbxproj @@ -131,6 +131,131 @@ 520DC68826F60FBB00FCFFFD /* EnvironmentModifiersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC60C26F60FBA00FCFFFD /* EnvironmentModifiersTests.swift */; }; 520DC68926F60FBB00FCFFFD /* ViewPaddingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC60D26F60FBA00FCFFFD /* ViewPaddingTests.swift */; }; 520DC68A26F60FBB00FCFFFD /* TransformingModifiersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC60E26F60FBA00FCFFFD /* TransformingModifiersTests.swift */; }; + 520DC69026F60FF400FCFFFD /* AlertTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5D426F60FBA00FCFFFD /* AlertTests.swift */; }; + 520DC69126F60FF400FCFFFD /* InspectableViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5AE26F60FBA00FCFFFD /* InspectableViewTests.swift */; }; + 520DC69226F60FF400FCFFFD /* ExclusiveGestureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC59C26F60FBA00FCFFFD /* ExclusiveGestureTests.swift */; }; + 520DC69326F60FF400FCFFFD /* MenuButtonTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5B326F60FBA00FCFFFD /* MenuButtonTests.swift */; }; + 520DC69426F60FF400FCFFFD /* EnvironmentObjectInjectionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5C726F60FBA00FCFFFD /* EnvironmentObjectInjectionTests.swift */; }; + 520DC69526F60FF400FCFFFD /* LazyVStackTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5FD26F60FBA00FCFFFD /* LazyVStackTests.swift */; }; + 520DC69626F60FF400FCFFFD /* MapAnnotationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5E126F60FBA00FCFFFD /* MapAnnotationTests.swift */; }; + 520DC69726F60FF400FCFFFD /* MenuTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5BB26F60FBA00FCFFFD /* MenuTests.swift */; }; + 520DC69826F60FF400FCFFFD /* PresentationModifiersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC60026F60FBA00FCFFFD /* PresentationModifiersTests.swift */; }; + 520DC69926F60FF400FCFFFD /* SliderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5DD26F60FBA00FCFFFD /* SliderTests.swift */; }; + 520DC69A26F60FF400FCFFFD /* PopoverTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5C926F60FBA00FCFFFD /* PopoverTests.swift */; }; + 520DC69B26F60FF400FCFFFD /* ActionSheetTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5D926F60FBA00FCFFFD /* ActionSheetTests.swift */; }; + 520DC69C26F60FF400FCFFFD /* SpacerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5F126F60FBA00FCFFFD /* SpacerTests.swift */; }; + 520DC69D26F60FF400FCFFFD /* RadialGradientTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5B726F60FBA00FCFFFD /* RadialGradientTests.swift */; }; + 520DC69E26F60FF400FCFFFD /* TextFieldTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5E926F60FBA00FCFFFD /* TextFieldTests.swift */; }; + 520DC69F26F60FF400FCFFFD /* LinkTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5DC26F60FBA00FCFFFD /* LinkTests.swift */; }; + 520DC6A026F60FF400FCFFFD /* EventsModifiersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC60226F60FBA00FCFFFD /* EventsModifiersTests.swift */; }; + 520DC6A126F60FF400FCFFFD /* StepperTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5CE26F60FBA00FCFFFD /* StepperTests.swift */; }; + 520DC6A226F60FF400FCFFFD /* ConfirmationDialogTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5D126F60FBA00FCFFFD /* ConfirmationDialogTests.swift */; }; + 520DC6A326F60FF400FCFFFD /* HSplitViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5FB26F60FBA00FCFFFD /* HSplitViewTests.swift */; }; + 520DC6A426F60FF400FCFFFD /* CustomViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5DE26F60FBA00FCFFFD /* CustomViewTests.swift */; }; + 520DC6A526F60FF400FCFFFD /* ListTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5FA26F60FBA00FCFFFD /* ListTests.swift */; }; + 520DC6A626F60FF400FCFFFD /* HitTestingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC59226F60FBA00FCFFFD /* HitTestingTests.swift */; }; + 520DC6A726F60FF400FCFFFD /* SectionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5EF26F60FBA00FCFFFD /* SectionTests.swift */; }; + 520DC6A826F60FF400FCFFFD /* VSplitViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5E426F60FBA00FCFFFD /* VSplitViewTests.swift */; }; + 520DC6A926F60FF400FCFFFD /* EnvironmentModifiersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC60C26F60FBA00FCFFFD /* EnvironmentModifiersTests.swift */; }; + 520DC6AA26F60FF400FCFFFD /* SecureFieldTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5F726F60FBA00FCFFFD /* SecureFieldTests.swift */; }; + 520DC6AB26F60FF400FCFFFD /* VisualEffectModifiersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC60B26F60FBA00FCFFFD /* VisualEffectModifiersTests.swift */; }; + 520DC6AC26F60FF400FCFFFD /* AnyViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5FC26F60FBA00FCFFFD /* AnyViewTests.swift */; }; + 520DC6AD26F60FF400FCFFFD /* AngularGradientTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5E226F60FBA00FCFFFD /* AngularGradientTests.swift */; }; + 520DC6AE26F60FF400FCFFFD /* PickerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5ED26F60FBA00FCFFFD /* PickerTests.swift */; }; + 520DC6AF26F60FF400FCFFFD /* SimultaneousGestureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5A326F60FBA00FCFFFD /* SimultaneousGestureTests.swift */; }; + 520DC6B026F60FF400FCFFFD /* SizingModifiersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC60326F60FBA00FCFFFD /* SizingModifiersTests.swift */; }; + 520DC6B126F60FF400FCFFFD /* CustomViewBuilderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5E826F60FBA00FCFFFD /* CustomViewBuilderTests.swift */; }; + 520DC6B226F60FF400FCFFFD /* ZStackTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5B126F60FBA00FCFFFD /* ZStackTests.swift */; }; + 520DC6B326F60FF400FCFFFD /* CommonComposedGestureChangedTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5A526F60FBA00FCFFFD /* CommonComposedGestureChangedTests.swift */; }; + 520DC6B426F60FF400FCFFFD /* EditButtonTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5E626F60FBA00FCFFFD /* EditButtonTests.swift */; }; + 520DC6B526F60FF400FCFFFD /* OpaqueViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5BE26F60FBA00FCFFFD /* OpaqueViewTests.swift */; }; + 520DC6B626F60FF400FCFFFD /* EmptyViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5CA26F60FBA00FCFFFD /* EmptyViewTests.swift */; }; + 520DC6B726F60FF400FCFFFD /* OptionalViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5B226F60FBA00FCFFFD /* OptionalViewTests.swift */; }; + 520DC6B826F60FF400FCFFFD /* ConfigurationModifiersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5FF26F60FBA00FCFFFD /* ConfigurationModifiersTests.swift */; }; + 520DC6B926F60FF400FCFFFD /* InteractionModifiersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC60126F60FBA00FCFFFD /* InteractionModifiersTests.swift */; }; + 520DC6BA26F60FF400FCFFFD /* PositioningModifiersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC60526F60FBA00FCFFFD /* PositioningModifiersTests.swift */; }; + 520DC6BB26F60FF400FCFFFD /* NestedModifiersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC60426F60FBA00FCFFFD /* NestedModifiersTests.swift */; }; + 520DC6BC26F60FF400FCFFFD /* TransitiveModifiersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC60826F60FBA00FCFFFD /* TransitiveModifiersTests.swift */; }; + 520DC6BD26F60FF400FCFFFD /* AnimationModifiersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC60A26F60FBA00FCFFFD /* AnimationModifiersTests.swift */; }; + 520DC6BE26F60FF400FCFFFD /* IDViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5E726F60FBA00FCFFFD /* IDViewTests.swift */; }; + 520DC6BF26F60FF400FCFFFD /* SubscriptionViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5BA26F60FBA00FCFFFD /* SubscriptionViewTests.swift */; }; + 520DC6C026F60FF400FCFFFD /* SequenceGestureChildrenTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC59826F60FBA00FCFFFD /* SequenceGestureChildrenTests.swift */; }; + 520DC6C126F60FF400FCFFFD /* TextEditorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5E026F60FBA00FCFFFD /* TextEditorTests.swift */; }; + 520DC6C226F60FF400FCFFFD /* SimultaneousGestureModifierTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC59626F60FBA00FCFFFD /* SimultaneousGestureModifierTests.swift */; }; + 520DC6C326F60FF400FCFFFD /* HighPriorityGestureModifierTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC59526F60FBA00FCFFFD /* HighPriorityGestureModifierTests.swift */; }; + 520DC6C426F60FF400FCFFFD /* ShapeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5F926F60FBA00FCFFFD /* ShapeTests.swift */; }; + 520DC6C526F60FF400FCFFFD /* ToolbarTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5C326F60FBA00FCFFFD /* ToolbarTests.swift */; }; + 520DC6C626F60FF400FCFFFD /* HStackTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5BF26F60FBA00FCFFFD /* HStackTests.swift */; }; + 520DC6C726F60FF400FCFFFD /* TouchBarTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5B426F60FBA00FCFFFD /* TouchBarTests.swift */; }; + 520DC6C826F60FF400FCFFFD /* CustomViewModifierTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5CB26F60FBA00FCFFFD /* CustomViewModifierTests.swift */; }; + 520DC6C926F60FF400FCFFFD /* TextInputModifiersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC60626F60FBA00FCFFFD /* TextInputModifiersTests.swift */; }; + 520DC6CA26F60FF400FCFFFD /* GestureExampleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC59F26F60FBA00FCFFFD /* GestureExampleTests.swift */; }; + 520DC6CB26F60FF400FCFFFD /* SimultaneousGestureChildrenTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC59D26F60FBA00FCFFFD /* SimultaneousGestureChildrenTests.swift */; }; + 520DC6CC26F60FF400FCFFFD /* GestureModifierTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC59326F60FBA00FCFFFD /* GestureModifierTests.swift */; }; + 520DC6CD26F60FF400FCFFFD /* ImageTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5CC26F60FBA00FCFFFD /* ImageTests.swift */; }; + 520DC6CE26F60FF400FCFFFD /* ColorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5DF26F60FBA00FCFFFD /* ColorTests.swift */; }; + 520DC6CF26F60FF400FCFFFD /* ButtonTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5DB26F60FBA00FCFFFD /* ButtonTests.swift */; }; + 520DC6D026F60FF400FCFFFD /* SheetTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5B626F60FBA00FCFFFD /* SheetTests.swift */; }; + 520DC6D126F60FF400FCFFFD /* CommonComposedGestureUpdatingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5A226F60FBA00FCFFFD /* CommonComposedGestureUpdatingTests.swift */; }; + 520DC6D226F60FF400FCFFFD /* EnvironmentReaderViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5CD26F60FBA00FCFFFD /* EnvironmentReaderViewTests.swift */; }; + 520DC6D326F60FF400FCFFFD /* ColorPickerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5F426F60FBA00FCFFFD /* ColorPickerTests.swift */; }; + 520DC6D426F60FF400FCFFFD /* OutlineGroupTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5F526F60FBA00FCFFFD /* OutlineGroupTests.swift */; }; + 520DC6D526F60FF400FCFFFD /* InspectionEmissaryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC58D26F60FBA00FCFFFD /* InspectionEmissaryTests.swift */; }; + 520DC6D626F60FF400FCFFFD /* ToggleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5F026F60FBA00FCFFFD /* ToggleTests.swift */; }; + 520DC6D726F60FF400FCFFFD /* DragGestureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5A026F60FBA00FCFFFD /* DragGestureTests.swift */; }; + 520DC6D826F60FF400FCFFFD /* ConditionalContentTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5E326F60FBA00FCFFFD /* ConditionalContentTests.swift */; }; + 520DC6D926F60FF400FCFFFD /* TransformingModifiersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC60E26F60FBA00FCFFFD /* TransformingModifiersTests.swift */; }; + 520DC6DA26F60FF400FCFFFD /* ProgressViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5C626F60FBA00FCFFFD /* ProgressViewTests.swift */; }; + 520DC6DB26F60FF400FCFFFD /* GroupTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5EE26F60FBA00FCFFFD /* GroupTests.swift */; }; + 520DC6DC26F60FF400FCFFFD /* TupleViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5D026F60FBA00FCFFFD /* TupleViewTests.swift */; }; + 520DC6DD26F60FF400FCFFFD /* AccessibilityModifiersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC60926F60FBA00FCFFFD /* AccessibilityModifiersTests.swift */; }; + 520DC6DE26F60FF400FCFFFD /* ScrollViewReaderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5B826F60FBA00FCFFFD /* ScrollViewReaderTests.swift */; }; + 520DC6DF26F60FF400FCFFFD /* LongPressGestureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5A626F60FBA00FCFFFD /* LongPressGestureTests.swift */; }; + 520DC6E026F60FF400FCFFFD /* SafeAreaInsetTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5F326F60FBA00FCFFFD /* SafeAreaInsetTests.swift */; }; + 520DC6E126F60FF400FCFFFD /* ViewPaddingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC60D26F60FBA00FCFFFD /* ViewPaddingTests.swift */; }; + 520DC6E226F60FF400FCFFFD /* CustomStyleModifiersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC60726F60FBA00FCFFFD /* CustomStyleModifiersTests.swift */; }; + 520DC6E326F60FF400FCFFFD /* InspectorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5AF26F60FBA00FCFFFD /* InspectorTests.swift */; }; + 520DC6E426F60FF400FCFFFD /* TextTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5BD26F60FBA00FCFFFD /* TextTests.swift */; }; + 520DC6E526F60FF400FCFFFD /* TapGestureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC59B26F60FBA00FCFFFD /* TapGestureTests.swift */; }; + 520DC6E626F60FF400FCFFFD /* CommonComposedGestureEndedTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5A426F60FBA00FCFFFD /* CommonComposedGestureEndedTests.swift */; }; + 520DC6E726F60FF400FCFFFD /* CommonGestureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5A726F60FBA00FCFFFD /* CommonGestureTests.swift */; }; + 520DC6E826F60FF400FCFFFD /* DatePickerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5F226F60FBA00FCFFFD /* DatePickerTests.swift */; }; + 520DC6E926F60FF400FCFFFD /* FullScreenCoverTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5EA26F60FBA00FCFFFD /* FullScreenCoverTests.swift */; }; + 520DC6EA26F60FF400FCFFFD /* MapTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5B926F60FBA00FCFFFD /* MapTests.swift */; }; + 520DC6EB26F60FF400FCFFFD /* LinearGradientTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5C226F60FBA00FCFFFD /* LinearGradientTests.swift */; }; + 520DC6EC26F60FF400FCFFFD /* FormTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5CF26F60FBA00FCFFFD /* FormTests.swift */; }; + 520DC6ED26F60FF400FCFFFD /* EquatableViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5C126F60FBA00FCFFFD /* EquatableViewTests.swift */; }; + 520DC6EE26F60FF400FCFFFD /* DelayedPreferenceViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5DA26F60FBA00FCFFFD /* DelayedPreferenceViewTests.swift */; }; + 520DC6EF26F60FF400FCFFFD /* LazyHGridTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5F826F60FBA00FCFFFD /* LazyHGridTests.swift */; }; + 520DC6F026F60FF400FCFFFD /* GestureActionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC59426F60FBA00FCFFFD /* GestureActionTests.swift */; }; + 520DC6F126F60FF400FCFFFD /* ComposedGestureExampleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC59726F60FBA00FCFFFD /* ComposedGestureExampleTests.swift */; }; + 520DC6F226F60FF400FCFFFD /* PasteButtonTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5D626F60FBA00FCFFFD /* PasteButtonTests.swift */; }; + 520DC6F326F60FF400FCFFFD /* ForEachTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5D826F60FBA00FCFFFD /* ForEachTests.swift */; }; + 520DC6F426F60FF400FCFFFD /* NavigationLinkTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5EB26F60FBA00FCFFFD /* NavigationLinkTests.swift */; }; + 520DC6F526F60FF400FCFFFD /* DividerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5D726F60FBA00FCFFFD /* DividerTests.swift */; }; + 520DC6F626F60FF400FCFFFD /* LazyGroupTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC58B26F60FBA00FCFFFD /* LazyGroupTests.swift */; }; + 520DC6F726F60FF400FCFFFD /* TabViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5C826F60FBA00FCFFFD /* TabViewTests.swift */; }; + 520DC6F826F60FF400FCFFFD /* BaseTypesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC58E26F60FBA00FCFFFD /* BaseTypesTests.swift */; }; + 520DC6F926F60FF400FCFFFD /* RotationGestureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC59926F60FBA00FCFFFD /* RotationGestureTests.swift */; }; + 520DC6FA26F60FF400FCFFFD /* NavigationViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5E526F60FBA00FCFFFD /* NavigationViewTests.swift */; }; + 520DC6FB26F60FF400FCFFFD /* ExclusiveGestureChildrenTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC59A26F60FBA00FCFFFD /* ExclusiveGestureChildrenTests.swift */; }; + 520DC6FC26F60FF400FCFFFD /* ViewHostingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC58C26F60FBA00FCFFFD /* ViewHostingTests.swift */; }; + 520DC6FD26F60FF400FCFFFD /* GroupBoxTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5B526F60FBA00FCFFFD /* GroupBoxTests.swift */; }; + 520DC6FE26F60FF400FCFFFD /* CommonComposedGestureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5A126F60FBA00FCFFFD /* CommonComposedGestureTests.swift */; }; + 520DC6FF26F60FF400FCFFFD /* LabelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5BC26F60FBA00FCFFFD /* LabelTests.swift */; }; + 520DC70026F60FF400FCFFFD /* MagnificationGestureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5A826F60FBA00FCFFFD /* MagnificationGestureTests.swift */; }; + 520DC70126F60FF400FCFFFD /* VStackTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5EC26F60FBA00FCFFFD /* VStackTests.swift */; }; + 520DC70226F60FF400FCFFFD /* SequenceGestureTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC59E26F60FBA00FCFFFD /* SequenceGestureTests.swift */; }; + 520DC70326F60FF400FCFFFD /* TextAttributesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5D526F60FBA00FCFFFD /* TextAttributesTests.swift */; }; + 520DC70426F60FF400FCFFFD /* ScrollViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5F626F60FBA00FCFFFD /* ScrollViewTests.swift */; }; + 520DC70526F60FF400FCFFFD /* TreeViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5C026F60FBA00FCFFFD /* TreeViewTests.swift */; }; + 520DC70626F60FF400FCFFFD /* LazyHStackTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5D326F60FBA00FCFFFD /* LazyHStackTests.swift */; }; + 520DC70726F60FF400FCFFFD /* DisclosureGroupTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5C426F60FBA00FCFFFD /* DisclosureGroupTests.swift */; }; + 520DC70826F60FF400FCFFFD /* ViewSearchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC58F26F60FBA00FCFFFD /* ViewSearchTests.swift */; }; + 520DC70926F60FF400FCFFFD /* LazyVGridTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5D226F60FBA00FCFFFD /* LazyVGridTests.swift */; }; + 520DC70A26F60FF400FCFFFD /* GeometryReaderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5C526F60FBA00FCFFFD /* GeometryReaderTests.swift */; }; + 520DC70C26F60FF400FCFFFD /* ViewInspector in Frameworks */ = {isa = PBXBuildFile; productRef = 520DC68E26F60FF400FCFFFD /* ViewInspector */; }; + 520DC70E26F60FF400FCFFFD /* Test.strings in Resources */ = {isa = PBXBuildFile; fileRef = 520DC5AA26F60FBA00FCFFFD /* Test.strings */; }; 5293010626EFC96600012E90 /* Interface.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5293010426EFC96600012E90 /* Interface.storyboard */; }; 5293010E26EFC96700012E90 /* watchOS-Ext-2.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 5293010D26EFC96700012E90 /* watchOS-Ext-2.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 5293012726EFCBD300012E90 /* watchOSApp-2.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5293011426EFC96700012E90 /* watchOSApp-2.swift */; }; @@ -148,6 +273,20 @@ remoteGlobalIDString = 52E3259926C72E7900CCE47E; remoteInfo = "watchOS-Ext"; }; + 520DC68D26F60FF400FCFFFD /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 52E3258426C72E7800CCE47E /* Project object */; + proxyType = 1; + remoteGlobalIDString = 52E3259926C72E7900CCE47E; + remoteInfo = "watchOS-Ext"; + }; + 520DC71326F6103300FCFFFD /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 52E3258426C72E7800CCE47E /* Project object */; + proxyType = 1; + remoteGlobalIDString = 5293010C26EFC96700012E90; + remoteInfo = "watchOS-Ext-2"; + }; 5293010F26EFC96700012E90 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 52E3258426C72E7800CCE47E /* Project object */; @@ -190,7 +329,7 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ - 520213A426ECB45D00E94C6E /* watchOS-Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "watchOS-Tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; + 520213A426ECB45D00E94C6E /* watchOS-1-Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "watchOS-1-Tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 520DC58B26F60FBA00FCFFFD /* LazyGroupTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LazyGroupTests.swift; sourceTree = ""; }; 520DC58C26F60FBA00FCFFFD /* ViewHostingTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewHostingTests.swift; sourceTree = ""; }; 520DC58D26F60FBA00FCFFFD /* InspectionEmissaryTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InspectionEmissaryTests.swift; sourceTree = ""; }; @@ -317,6 +456,7 @@ 520DC60C26F60FBA00FCFFFD /* EnvironmentModifiersTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EnvironmentModifiersTests.swift; sourceTree = ""; }; 520DC60D26F60FBA00FCFFFD /* ViewPaddingTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewPaddingTests.swift; sourceTree = ""; }; 520DC60E26F60FBA00FCFFFD /* TransformingModifiersTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TransformingModifiersTests.swift; sourceTree = ""; }; + 520DC71226F60FF400FCFFFD /* watchOS-2-Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "watchOS-2-Tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 529300FF26EFC96600012E90 /* watchOS-App-2.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "watchOS-App-2.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 5293010526EFC96600012E90 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Interface.storyboard; sourceTree = ""; }; 5293010D26EFC96700012E90 /* watchOS-Ext-2.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = "watchOS-Ext-2.appex"; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -340,6 +480,14 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 520DC70B26F60FF400FCFFFD /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 520DC70C26F60FF400FCFFFD /* ViewInspector in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 5293010A26EFC96700012E90 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -569,9 +717,10 @@ children = ( 52E3258E26C72E7800CCE47E /* watchOS-App-1.app */, 52E3259A26C72E7900CCE47E /* watchOS-Ext-1.appex */, - 520213A426ECB45D00E94C6E /* watchOS-Tests.xctest */, + 520213A426ECB45D00E94C6E /* watchOS-1-Tests.xctest */, 529300FF26EFC96600012E90 /* watchOS-App-2.app */, 5293010D26EFC96700012E90 /* watchOS-Ext-2.appex */, + 520DC71226F60FF400FCFFFD /* watchOS-2-Tests.xctest */, ); name = Products; sourceTree = ""; @@ -600,9 +749,9 @@ /* End PBXGroup section */ /* Begin PBXNativeTarget section */ - 520213A326ECB45D00E94C6E /* watchOS-Tests */ = { + 520213A326ECB45D00E94C6E /* watchOS-1-Tests */ = { isa = PBXNativeTarget; - buildConfigurationList = 520213AC26ECB45D00E94C6E /* Build configuration list for PBXNativeTarget "watchOS-Tests" */; + buildConfigurationList = 520213AC26ECB45D00E94C6E /* Build configuration list for PBXNativeTarget "watchOS-1-Tests" */; buildPhases = ( 520213A026ECB45D00E94C6E /* Sources */, 520213A126ECB45D00E94C6E /* Frameworks */, @@ -613,12 +762,34 @@ dependencies = ( 520213A926ECB45D00E94C6E /* PBXTargetDependency */, ); - name = "watchOS-Tests"; + name = "watchOS-1-Tests"; packageProductDependencies = ( 52CA301326ECC5D200BFD568 /* ViewInspector */, ); productName = "watchOS-Tests"; - productReference = 520213A426ECB45D00E94C6E /* watchOS-Tests.xctest */; + productReference = 520213A426ECB45D00E94C6E /* watchOS-1-Tests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 520DC68B26F60FF400FCFFFD /* watchOS-2-Tests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 520DC70F26F60FF400FCFFFD /* Build configuration list for PBXNativeTarget "watchOS-2-Tests" */; + buildPhases = ( + 520DC68F26F60FF400FCFFFD /* Sources */, + 520DC70B26F60FF400FCFFFD /* Frameworks */, + 520DC70D26F60FF400FCFFFD /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 520DC68C26F60FF400FCFFFD /* PBXTargetDependency */, + 520DC71426F6103300FCFFFD /* PBXTargetDependency */, + ); + name = "watchOS-2-Tests"; + packageProductDependencies = ( + 520DC68E26F60FF400FCFFFD /* ViewInspector */, + ); + productName = "watchOS-Tests"; + productReference = 520DC71226F60FF400FCFFFD /* watchOS-2-Tests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; 529300FE26EFC96600012E90 /* watchOS-App-2 */ = { @@ -702,6 +873,9 @@ CreatedOnToolsVersion = 13.0; TestTargetID = 52E3259926C72E7900CCE47E; }; + 520DC68B26F60FF400FCFFFD = { + TestTargetID = 5293010C26EFC96700012E90; + }; 529300FE26EFC96600012E90 = { CreatedOnToolsVersion = 13.0; }; @@ -735,7 +909,8 @@ 529300FE26EFC96600012E90 /* watchOS-App-2 */, 52E3259926C72E7900CCE47E /* watchOS-Ext-1 */, 5293010C26EFC96700012E90 /* watchOS-Ext-2 */, - 520213A326ECB45D00E94C6E /* watchOS-Tests */, + 520213A326ECB45D00E94C6E /* watchOS-1-Tests */, + 520DC68B26F60FF400FCFFFD /* watchOS-2-Tests */, ); }; /* End PBXProject section */ @@ -749,6 +924,14 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 520DC70D26F60FF400FCFFFD /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 520DC70E26F60FF400FCFFFD /* Test.strings in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 529300FD26EFC96600012E90 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -911,6 +1094,136 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 520DC68F26F60FF400FCFFFD /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 520DC69026F60FF400FCFFFD /* AlertTests.swift in Sources */, + 520DC69126F60FF400FCFFFD /* InspectableViewTests.swift in Sources */, + 520DC69226F60FF400FCFFFD /* ExclusiveGestureTests.swift in Sources */, + 520DC69326F60FF400FCFFFD /* MenuButtonTests.swift in Sources */, + 520DC69426F60FF400FCFFFD /* EnvironmentObjectInjectionTests.swift in Sources */, + 520DC69526F60FF400FCFFFD /* LazyVStackTests.swift in Sources */, + 520DC69626F60FF400FCFFFD /* MapAnnotationTests.swift in Sources */, + 520DC69726F60FF400FCFFFD /* MenuTests.swift in Sources */, + 520DC69826F60FF400FCFFFD /* PresentationModifiersTests.swift in Sources */, + 520DC69926F60FF400FCFFFD /* SliderTests.swift in Sources */, + 520DC69A26F60FF400FCFFFD /* PopoverTests.swift in Sources */, + 520DC69B26F60FF400FCFFFD /* ActionSheetTests.swift in Sources */, + 520DC69C26F60FF400FCFFFD /* SpacerTests.swift in Sources */, + 520DC69D26F60FF400FCFFFD /* RadialGradientTests.swift in Sources */, + 520DC69E26F60FF400FCFFFD /* TextFieldTests.swift in Sources */, + 520DC69F26F60FF400FCFFFD /* LinkTests.swift in Sources */, + 520DC6A026F60FF400FCFFFD /* EventsModifiersTests.swift in Sources */, + 520DC6A126F60FF400FCFFFD /* StepperTests.swift in Sources */, + 520DC6A226F60FF400FCFFFD /* ConfirmationDialogTests.swift in Sources */, + 520DC6A326F60FF400FCFFFD /* HSplitViewTests.swift in Sources */, + 520DC6A426F60FF400FCFFFD /* CustomViewTests.swift in Sources */, + 520DC6A526F60FF400FCFFFD /* ListTests.swift in Sources */, + 520DC6A626F60FF400FCFFFD /* HitTestingTests.swift in Sources */, + 520DC6A726F60FF400FCFFFD /* SectionTests.swift in Sources */, + 520DC6A826F60FF400FCFFFD /* VSplitViewTests.swift in Sources */, + 520DC6A926F60FF400FCFFFD /* EnvironmentModifiersTests.swift in Sources */, + 520DC6AA26F60FF400FCFFFD /* SecureFieldTests.swift in Sources */, + 520DC6AB26F60FF400FCFFFD /* VisualEffectModifiersTests.swift in Sources */, + 520DC6AC26F60FF400FCFFFD /* AnyViewTests.swift in Sources */, + 520DC6AD26F60FF400FCFFFD /* AngularGradientTests.swift in Sources */, + 520DC6AE26F60FF400FCFFFD /* PickerTests.swift in Sources */, + 520DC6AF26F60FF400FCFFFD /* SimultaneousGestureTests.swift in Sources */, + 520DC6B026F60FF400FCFFFD /* SizingModifiersTests.swift in Sources */, + 520DC6B126F60FF400FCFFFD /* CustomViewBuilderTests.swift in Sources */, + 520DC6B226F60FF400FCFFFD /* ZStackTests.swift in Sources */, + 520DC6B326F60FF400FCFFFD /* CommonComposedGestureChangedTests.swift in Sources */, + 520DC6B426F60FF400FCFFFD /* EditButtonTests.swift in Sources */, + 520DC6B526F60FF400FCFFFD /* OpaqueViewTests.swift in Sources */, + 520DC6B626F60FF400FCFFFD /* EmptyViewTests.swift in Sources */, + 520DC6B726F60FF400FCFFFD /* OptionalViewTests.swift in Sources */, + 520DC6B826F60FF400FCFFFD /* ConfigurationModifiersTests.swift in Sources */, + 520DC6B926F60FF400FCFFFD /* InteractionModifiersTests.swift in Sources */, + 520DC6BA26F60FF400FCFFFD /* PositioningModifiersTests.swift in Sources */, + 520DC6BB26F60FF400FCFFFD /* NestedModifiersTests.swift in Sources */, + 520DC6BC26F60FF400FCFFFD /* TransitiveModifiersTests.swift in Sources */, + 520DC6BD26F60FF400FCFFFD /* AnimationModifiersTests.swift in Sources */, + 520DC6BE26F60FF400FCFFFD /* IDViewTests.swift in Sources */, + 520DC6BF26F60FF400FCFFFD /* SubscriptionViewTests.swift in Sources */, + 520DC6C026F60FF400FCFFFD /* SequenceGestureChildrenTests.swift in Sources */, + 520DC6C126F60FF400FCFFFD /* TextEditorTests.swift in Sources */, + 520DC6C226F60FF400FCFFFD /* SimultaneousGestureModifierTests.swift in Sources */, + 520DC6C326F60FF400FCFFFD /* HighPriorityGestureModifierTests.swift in Sources */, + 520DC6C426F60FF400FCFFFD /* ShapeTests.swift in Sources */, + 520DC6C526F60FF400FCFFFD /* ToolbarTests.swift in Sources */, + 520DC6C626F60FF400FCFFFD /* HStackTests.swift in Sources */, + 520DC6C726F60FF400FCFFFD /* TouchBarTests.swift in Sources */, + 520DC6C826F60FF400FCFFFD /* CustomViewModifierTests.swift in Sources */, + 520DC6C926F60FF400FCFFFD /* TextInputModifiersTests.swift in Sources */, + 520DC6CA26F60FF400FCFFFD /* GestureExampleTests.swift in Sources */, + 520DC6CB26F60FF400FCFFFD /* SimultaneousGestureChildrenTests.swift in Sources */, + 520DC6CC26F60FF400FCFFFD /* GestureModifierTests.swift in Sources */, + 520DC6CD26F60FF400FCFFFD /* ImageTests.swift in Sources */, + 520DC6CE26F60FF400FCFFFD /* ColorTests.swift in Sources */, + 520DC6CF26F60FF400FCFFFD /* ButtonTests.swift in Sources */, + 520DC6D026F60FF400FCFFFD /* SheetTests.swift in Sources */, + 520DC6D126F60FF400FCFFFD /* CommonComposedGestureUpdatingTests.swift in Sources */, + 520DC6D226F60FF400FCFFFD /* EnvironmentReaderViewTests.swift in Sources */, + 520DC6D326F60FF400FCFFFD /* ColorPickerTests.swift in Sources */, + 520DC6D426F60FF400FCFFFD /* OutlineGroupTests.swift in Sources */, + 520DC6D526F60FF400FCFFFD /* InspectionEmissaryTests.swift in Sources */, + 520DC6D626F60FF400FCFFFD /* ToggleTests.swift in Sources */, + 520DC6D726F60FF400FCFFFD /* DragGestureTests.swift in Sources */, + 520DC6D826F60FF400FCFFFD /* ConditionalContentTests.swift in Sources */, + 520DC6D926F60FF400FCFFFD /* TransformingModifiersTests.swift in Sources */, + 520DC6DA26F60FF400FCFFFD /* ProgressViewTests.swift in Sources */, + 520DC6DB26F60FF400FCFFFD /* GroupTests.swift in Sources */, + 520DC6DC26F60FF400FCFFFD /* TupleViewTests.swift in Sources */, + 520DC6DD26F60FF400FCFFFD /* AccessibilityModifiersTests.swift in Sources */, + 520DC6DE26F60FF400FCFFFD /* ScrollViewReaderTests.swift in Sources */, + 520DC6DF26F60FF400FCFFFD /* LongPressGestureTests.swift in Sources */, + 520DC6E026F60FF400FCFFFD /* SafeAreaInsetTests.swift in Sources */, + 520DC6E126F60FF400FCFFFD /* ViewPaddingTests.swift in Sources */, + 520DC6E226F60FF400FCFFFD /* CustomStyleModifiersTests.swift in Sources */, + 520DC6E326F60FF400FCFFFD /* InspectorTests.swift in Sources */, + 520DC6E426F60FF400FCFFFD /* TextTests.swift in Sources */, + 520DC6E526F60FF400FCFFFD /* TapGestureTests.swift in Sources */, + 520DC6E626F60FF400FCFFFD /* CommonComposedGestureEndedTests.swift in Sources */, + 520DC6E726F60FF400FCFFFD /* CommonGestureTests.swift in Sources */, + 520DC6E826F60FF400FCFFFD /* DatePickerTests.swift in Sources */, + 520DC6E926F60FF400FCFFFD /* FullScreenCoverTests.swift in Sources */, + 520DC6EA26F60FF400FCFFFD /* MapTests.swift in Sources */, + 520DC6EB26F60FF400FCFFFD /* LinearGradientTests.swift in Sources */, + 520DC6EC26F60FF400FCFFFD /* FormTests.swift in Sources */, + 520DC6ED26F60FF400FCFFFD /* EquatableViewTests.swift in Sources */, + 520DC6EE26F60FF400FCFFFD /* DelayedPreferenceViewTests.swift in Sources */, + 520DC6EF26F60FF400FCFFFD /* LazyHGridTests.swift in Sources */, + 520DC6F026F60FF400FCFFFD /* GestureActionTests.swift in Sources */, + 520DC6F126F60FF400FCFFFD /* ComposedGestureExampleTests.swift in Sources */, + 520DC6F226F60FF400FCFFFD /* PasteButtonTests.swift in Sources */, + 520DC6F326F60FF400FCFFFD /* ForEachTests.swift in Sources */, + 520DC6F426F60FF400FCFFFD /* NavigationLinkTests.swift in Sources */, + 520DC6F526F60FF400FCFFFD /* DividerTests.swift in Sources */, + 520DC6F626F60FF400FCFFFD /* LazyGroupTests.swift in Sources */, + 520DC6F726F60FF400FCFFFD /* TabViewTests.swift in Sources */, + 520DC6F826F60FF400FCFFFD /* BaseTypesTests.swift in Sources */, + 520DC6F926F60FF400FCFFFD /* RotationGestureTests.swift in Sources */, + 520DC6FA26F60FF400FCFFFD /* NavigationViewTests.swift in Sources */, + 520DC6FB26F60FF400FCFFFD /* ExclusiveGestureChildrenTests.swift in Sources */, + 520DC6FC26F60FF400FCFFFD /* ViewHostingTests.swift in Sources */, + 520DC6FD26F60FF400FCFFFD /* GroupBoxTests.swift in Sources */, + 520DC6FE26F60FF400FCFFFD /* CommonComposedGestureTests.swift in Sources */, + 520DC6FF26F60FF400FCFFFD /* LabelTests.swift in Sources */, + 520DC70026F60FF400FCFFFD /* MagnificationGestureTests.swift in Sources */, + 520DC70126F60FF400FCFFFD /* VStackTests.swift in Sources */, + 520DC70226F60FF400FCFFFD /* SequenceGestureTests.swift in Sources */, + 520DC70326F60FF400FCFFFD /* TextAttributesTests.swift in Sources */, + 520DC70426F60FF400FCFFFD /* ScrollViewTests.swift in Sources */, + 520DC70526F60FF400FCFFFD /* TreeViewTests.swift in Sources */, + 520DC70626F60FF400FCFFFD /* LazyHStackTests.swift in Sources */, + 520DC70726F60FF400FCFFFD /* DisclosureGroupTests.swift in Sources */, + 520DC70826F60FF400FCFFFD /* ViewSearchTests.swift in Sources */, + 520DC70926F60FF400FCFFFD /* LazyVGridTests.swift in Sources */, + 520DC70A26F60FF400FCFFFD /* GeometryReaderTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 5293010926EFC96700012E90 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -936,6 +1249,16 @@ target = 52E3259926C72E7900CCE47E /* watchOS-Ext-1 */; targetProxy = 520213A826ECB45D00E94C6E /* PBXContainerItemProxy */; }; + 520DC68C26F60FF400FCFFFD /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 52E3259926C72E7900CCE47E /* watchOS-Ext-1 */; + targetProxy = 520DC68D26F60FF400FCFFFD /* PBXContainerItemProxy */; + }; + 520DC71426F6103300FCFFFD /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 5293010C26EFC96700012E90 /* watchOS-Ext-2 */; + targetProxy = 520DC71326F6103300FCFFFD /* PBXContainerItemProxy */; + }; 5293011026EFC96700012E90 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 5293010C26EFC96700012E90 /* watchOS-Ext-2 */; @@ -1016,6 +1339,52 @@ }; name = Release; }; + 520DC71026F60FF400FCFFFD /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = "com.viewinspector.watchOS-Tests"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = watchos; + SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/watchOS-Ext-2.appex/watchOS-Ext-2"; + }; + name = Debug; + }; + 520DC71126F60FF400FCFFFD /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = "com.viewinspector.watchOS-Tests"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = watchos; + SWIFT_EMIT_LOC_STRINGS = NO; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/watchOS-Ext-2.appex/watchOS-Ext-2"; + }; + name = Release; + }; 5293011C26EFC96800012E90 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -1315,7 +1684,7 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ - 520213AC26ECB45D00E94C6E /* Build configuration list for PBXNativeTarget "watchOS-Tests" */ = { + 520213AC26ECB45D00E94C6E /* Build configuration list for PBXNativeTarget "watchOS-1-Tests" */ = { isa = XCConfigurationList; buildConfigurations = ( 520213AA26ECB45D00E94C6E /* Debug */, @@ -1324,6 +1693,15 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + 520DC70F26F60FF400FCFFFD /* Build configuration list for PBXNativeTarget "watchOS-2-Tests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 520DC71026F60FF400FCFFFD /* Debug */, + 520DC71126F60FF400FCFFFD /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; 5293011B26EFC96800012E90 /* Build configuration list for PBXNativeTarget "watchOS-Ext-2" */ = { isa = XCConfigurationList; buildConfigurations = ( @@ -1372,6 +1750,10 @@ /* End XCConfigurationList section */ /* Begin XCSwiftPackageProductDependency section */ + 520DC68E26F60FF400FCFFFD /* ViewInspector */ = { + isa = XCSwiftPackageProductDependency; + productName = ViewInspector; + }; 52CA301326ECC5D200BFD568 /* ViewInspector */ = { isa = XCSwiftPackageProductDependency; productName = ViewInspector; diff --git a/.watchOS/watchOS.xcodeproj/xcshareddata/xcschemes/watchOS-App-1.xcscheme b/.watchOS/watchOS.xcodeproj/xcshareddata/xcschemes/watchOS-App-1.xcscheme index efe371a2..44287e7b 100644 --- a/.watchOS/watchOS.xcodeproj/xcshareddata/xcschemes/watchOS-App-1.xcscheme +++ b/.watchOS/watchOS.xcodeproj/xcshareddata/xcschemes/watchOS-App-1.xcscheme @@ -30,7 +30,7 @@ BuildableIdentifier = "primary" BlueprintIdentifier = "520213A326ECB45D00E94C6E" BuildableName = "watchOS-Tests.xctest" - BlueprintName = "watchOS-Tests" + BlueprintName = "watchOS-1-Tests" ReferencedContainer = "container:watchOS.xcodeproj"> @@ -48,7 +48,7 @@ BuildableIdentifier = "primary" BlueprintIdentifier = "520213A326ECB45D00E94C6E" BuildableName = "watchOS-Tests.xctest" - BlueprintName = "watchOS-Tests" + BlueprintName = "watchOS-1-Tests" ReferencedContainer = "container:watchOS.xcodeproj"> diff --git a/.watchOS/watchOS.xcodeproj/xcshareddata/xcschemes/watchOS-App-2.xcscheme b/.watchOS/watchOS.xcodeproj/xcshareddata/xcschemes/watchOS-App-2.xcscheme index ec49b511..50240f00 100644 --- a/.watchOS/watchOS.xcodeproj/xcshareddata/xcschemes/watchOS-App-2.xcscheme +++ b/.watchOS/watchOS.xcodeproj/xcshareddata/xcschemes/watchOS-App-2.xcscheme @@ -28,9 +28,9 @@ buildForAnalyzing = "NO"> @@ -46,9 +46,9 @@ skipped = "NO"> From 28fc167b8d8ca17a10f1aaa2dea9e63fe306994e Mon Sep 17 00:00:00 2001 From: Alexey Naumov Date: Sat, 18 Sep 2021 15:49:40 +0300 Subject: [PATCH 68/99] Enable view hosting for the second app --- .../watchOS-Ext/watchOSApp+Testable.swift | 28 +++++++++++-------- .watchOS/watchOS-Ext/watchOSApp-2.swift | 15 +++++++++- .watchOS/watchOS.xcodeproj/project.pbxproj | 2 ++ 3 files changed, 32 insertions(+), 13 deletions(-) diff --git a/.watchOS/watchOS-Ext/watchOSApp+Testable.swift b/.watchOS/watchOS-Ext/watchOSApp+Testable.swift index 9cbba11b..cc465d23 100644 --- a/.watchOS/watchOS-Ext/watchOSApp+Testable.swift +++ b/.watchOS/watchOS-Ext/watchOSApp+Testable.swift @@ -4,15 +4,28 @@ import Combine typealias TestViewSubject = CurrentValueSubject<[(String, AnyView)], Never> -#if os(watchOS) && DEBUG +#if !(os(watchOS) && DEBUG) + +typealias RootView = T + +extension View { + @inline(__always) + func testable(_ injector: TestViewSubject) -> Self { + self + } +} + +#else + +typealias RootView = ModifiedContent extension View { - func testable(_ injector: TestViewSubject) -> some View { + func testable(_ injector: TestViewSubject) -> ModifiedContent { modifier(TestViewHost(injector: injector)) } } -private struct TestViewHost: ViewModifier { +struct TestViewHost: ViewModifier { @State private var hostedViews: [(String, AnyView)] = [] let injector: TestViewSubject @@ -26,13 +39,4 @@ private struct TestViewHost: ViewModifier { } } -#else - -extension View { - @inline(__always) - func testable(_ injector: TestViewSubject) -> some View { - self - } -} - #endif diff --git a/.watchOS/watchOS-Ext/watchOSApp-2.swift b/.watchOS/watchOS-Ext/watchOSApp-2.swift index 9e337c0f..109a31a2 100644 --- a/.watchOS/watchOS-Ext/watchOSApp-2.swift +++ b/.watchOS/watchOS-Ext/watchOSApp-2.swift @@ -1,7 +1,20 @@ import WatchKit +import SwiftUI -final class RootInterfaceController: WKInterfaceController { +final class RootInterfaceController: WKHostingController> { + let testViewSubject = TestViewSubject([]) + + override var body: RootView { + return ContentView() + .testable(testViewSubject) + } +} + +struct ContentView: View { + var body: some View { + Text("Hi") + } } final class ExtensionDelegate: NSObject, WKExtensionDelegate { diff --git a/.watchOS/watchOS.xcodeproj/project.pbxproj b/.watchOS/watchOS.xcodeproj/project.pbxproj index 669ee9ce..ac2f30ed 100644 --- a/.watchOS/watchOS.xcodeproj/project.pbxproj +++ b/.watchOS/watchOS.xcodeproj/project.pbxproj @@ -256,6 +256,7 @@ 520DC70A26F60FF400FCFFFD /* GeometryReaderTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520DC5C526F60FBA00FCFFFD /* GeometryReaderTests.swift */; }; 520DC70C26F60FF400FCFFFD /* ViewInspector in Frameworks */ = {isa = PBXBuildFile; productRef = 520DC68E26F60FF400FCFFFD /* ViewInspector */; }; 520DC70E26F60FF400FCFFFD /* Test.strings in Resources */ = {isa = PBXBuildFile; fileRef = 520DC5AA26F60FBA00FCFFFD /* Test.strings */; }; + 520DC71526F6115D00FCFFFD /* watchOSApp+Testable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52CA301526ECD64400BFD568 /* watchOSApp+Testable.swift */; }; 5293010626EFC96600012E90 /* Interface.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5293010426EFC96600012E90 /* Interface.storyboard */; }; 5293010E26EFC96700012E90 /* watchOS-Ext-2.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 5293010D26EFC96700012E90 /* watchOS-Ext-2.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 5293012726EFCBD300012E90 /* watchOSApp-2.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5293011426EFC96700012E90 /* watchOSApp-2.swift */; }; @@ -1229,6 +1230,7 @@ buildActionMask = 2147483647; files = ( 5293012726EFCBD300012E90 /* watchOSApp-2.swift in Sources */, + 520DC71526F6115D00FCFFFD /* watchOSApp+Testable.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; From 3bcc2bc3a5cf61d048cdd630a4b82e341b0308ec Mon Sep 17 00:00:00 2001 From: Alexey Naumov Date: Sat, 18 Sep 2021 18:41:04 +0300 Subject: [PATCH 69/99] Add support for WKInterfaceObjectRepresentable --- .../ViewInspector/SwiftUI/CustomView.swift | 16 +++++ Sources/ViewInspector/ViewHosting.swift | 31 +++++++++ .../SwiftUI/CustomViewTests.swift | 39 ++++++++--- .../ViewInspectorTests/ViewHostingTests.swift | 65 +++++++++++++++++++ 4 files changed, 143 insertions(+), 8 deletions(-) diff --git a/Sources/ViewInspector/SwiftUI/CustomView.swift b/Sources/ViewInspector/SwiftUI/CustomView.swift index a7bf21c9..1fe3fbbb 100644 --- a/Sources/ViewInspector/SwiftUI/CustomView.swift +++ b/Sources/ViewInspector/SwiftUI/CustomView.swift @@ -165,4 +165,20 @@ public extension Inspectable where Self: UIViewControllerRepresentable { "Please use `.actualView().viewController()` for inspecting the contents of UIViewControllerRepresentable") } } +#elseif os(watchOS) + +@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 7.0, *) +public extension WKInterfaceObjectRepresentable where Self: Inspectable { + func interfaceObject() throws -> WKInterfaceObjectType { + return try ViewHosting.lookup(Self.self) + } +} + +@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 7.0, *) +public extension Inspectable where Self: WKInterfaceObjectRepresentable { + func extractContent(environmentObjects: [AnyObject]) throws -> Any { + throw InspectionError.notSupported( + "Please use `.actualView().interfaceObject()` for inspecting the contents of WKInterfaceObjectRepresentable") + } +} #endif diff --git a/Sources/ViewInspector/ViewHosting.swift b/Sources/ViewInspector/ViewHosting.swift index a8b4a389..4526f62b 100644 --- a/Sources/ViewInspector/ViewHosting.swift +++ b/Sources/ViewInspector/ViewHosting.swift @@ -283,9 +283,40 @@ internal extension ViewHosting { .first else { throw InspectionError.viewNotFound(parent: name) } return vc } + #elseif os(watchOS) + static func lookup(_ view: V.Type) throws -> V.WKInterfaceObjectType + where V: Inspectable & WKInterfaceObjectRepresentable { + let name = Inspector.typeName(type: view) + guard let rootVC = WKExtension.shared().rootInterfaceController, + let viewCache = try? Inspector.attribute(path: """ + super|$__lazy_storage_$_hostingController|some|\ + host|renderer|renderer|some|viewCache|map + """, value: rootVC, type: ArrayConvertible.self).allValues(), + let object = viewCache.compactMap({ value in + try? Inspector.attribute( + path: "view|representedViewProvider", + value: value, type: V.WKInterfaceObjectType.self) + }).first + else { + throw InspectionError.viewNotFound(parent: name) + } + return object + } #endif } +#if os(watchOS) +@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 7.0, *) +internal protocol ArrayConvertible { + func allValues() -> [Any] +} + +@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 7.0, *) +extension Dictionary: ArrayConvertible { + func allValues() -> [Any] { Array(values) as [Any] } +} +#endif + #if os(macOS) @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) private extension NSView { diff --git a/Tests/ViewInspectorTests/SwiftUI/CustomViewTests.swift b/Tests/ViewInspectorTests/SwiftUI/CustomViewTests.swift index 75447764..3b5eceaa 100644 --- a/Tests/ViewInspectorTests/SwiftUI/CustomViewTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/CustomViewTests.swift @@ -66,6 +66,7 @@ final class CustomViewTests: XCTestCase { wait(for: [exp], timeout: 0.1) } + @available(watchOS, deprecated: 7.0) func testExtractionOfTestViewRepresentable() throws { let view = AnyView(TestViewRepresentable()) let sut = try view.inspect().anyView().view(TestViewRepresentable.self) @@ -73,22 +74,42 @@ final class CustomViewTests: XCTestCase { #if os(macOS) XCTAssertThrows(try sut.hStack(), "Please use `.actualView().nsView()` for inspecting the contents of NSViewRepresentable") + // Needs view hosting: + XCTAssertThrows(try sut.actualView().nsView(), + "View for TestViewRepresentable is absent") + #elseif os(watchOS) + XCTAssertThrows(try sut.hStack(), + "Please use `.actualView().interfaceObject()` for inspecting the contents of WKInterfaceObjectRepresentable") + // Needs view hosting: + XCTAssertThrows(try sut.actualView().interfaceObject(), + "View for TestViewRepresentable is absent") #else XCTAssertThrows(try sut.hStack(), "Please use `.actualView().uiView()` for inspecting the contents of UIViewRepresentable") + // Needs view hosting: + XCTAssertThrows(try sut.actualView().uiView(), + "View for TestViewRepresentable is absent") #endif } func testExtractionOfViewControllerRepresentable() throws { + #if !os(watchOS) let view = AnyView(TestViewControllerRepresentable()) let sut = try view.inspect().anyView().view(TestViewControllerRepresentable.self) XCTAssertNoThrow(try sut.actualView()) #if os(macOS) XCTAssertThrows(try sut.hStack(), "Please use `.actualView().viewController()` for inspecting the contents of NSViewControllerRepresentable") + // Needs view hosting: + XCTAssertThrows(try sut.actualView().viewController(), + "View for TestViewControllerRepresentable is absent") #else XCTAssertThrows(try sut.hStack(), "Please use `.actualView().viewController()` for inspecting the contents of UIViewControllerRepresentable") + // Needs view hosting: + XCTAssertThrows(try sut.actualView().viewController(), + "View for TestViewControllerRepresentable is absent") + #endif #endif } @@ -282,17 +303,19 @@ private struct TestViewControllerRepresentable: UIViewControllerRepresentable, I } } #elseif os(watchOS) -// !!! -struct TestViewRepresentable: View, Inspectable { - var body: some View { - EmptyView() + +@available(watchOS, deprecated: 7.0) +private struct TestViewRepresentable: WKInterfaceObjectRepresentable, Inspectable { + + typealias Context = WKInterfaceObjectRepresentableContext + func makeWKInterfaceObject(context: Context) -> some WKInterfaceObject { + return WKInterfaceMap() } -} -struct TestViewControllerRepresentable: View, Inspectable { - var body: some View { - EmptyView() + + func updateWKInterfaceObject(_ wkInterfaceObject: WKInterfaceObjectType, context: Context) { } } + #endif // MARK: - Misc diff --git a/Tests/ViewInspectorTests/ViewHostingTests.swift b/Tests/ViewInspectorTests/ViewHostingTests.swift index 58dc10f2..a23717e4 100644 --- a/Tests/ViewInspectorTests/ViewHostingTests.swift +++ b/Tests/ViewInspectorTests/ViewHostingTests.swift @@ -149,6 +149,39 @@ final class ViewHostingTests: XCTestCase { wait(for: [exp], timeout: 0.2) } } +#elseif os(watchOS) + +@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 7.0, *) +@available(watchOS, deprecated: 7.0) +final class ViewHostingTests: XCTestCase { + + func testWKTestView() throws { + let exp = XCTestExpectation(description: #function) + exp.expectedFulfillmentCount = 2 + var sut = WKTestView.WrapperView(didUpdate: { + exp.fulfill() + }) + sut.didAppear = { view in + ViewHosting.expel() + } + ViewHosting.host(view: sut) + wait(for: [exp], timeout: 0.1) + } + + func testWKViewExtraction() throws { + let exp = XCTestExpectation(description: #function) + let sut = WKTestView(didUpdate: { }) + DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) { + sut.inspect { view in + XCTAssertNoThrow(try view.actualView().interfaceObject()) + ViewHosting.expel() + exp.fulfill() + } + } + ViewHosting.host(view: sut) + wait(for: [exp], timeout: 1) + } +} #endif // MARK: - Test Views @@ -228,6 +261,38 @@ extension UITestView { } } } +#elseif os(watchOS) + +@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 7.0, *) +@available(watchOS, deprecated: 7.0) +private struct WKTestView: WKInterfaceObjectRepresentable, Inspectable { + + var didUpdate: () -> Void + + typealias Context = WKInterfaceObjectRepresentableContext + func makeWKInterfaceObject(context: Context) -> some WKInterfaceObject { + return WKInterfaceMap() + } + + func updateWKInterfaceObject(_ wkInterfaceObject: WKInterfaceObjectType, context: Context) { + didUpdate() + } +} + +@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 7.0, *) +@available(watchOS, deprecated: 7.0) +extension WKTestView { + struct WrapperView: View, Inspectable { + + var didAppear: ((Self) -> Void)? + var didUpdate: () -> Void + + var body: some View { + WKTestView(didUpdate: didUpdate) + .onAppear { self.didAppear?(self) } + } + } +} #endif #if os(macOS) From c5abfba267aec52b471ddc055e4335f0776d7b04 Mon Sep 17 00:00:00 2001 From: Alexey Naumov Date: Sat, 18 Sep 2021 18:44:34 +0300 Subject: [PATCH 70/99] Fix deprecated warnings --- .watchOS/watchOS.xcodeproj/project.pbxproj | 4 +++- .../xcshareddata/xcschemes/watchOS-App-1.xcscheme | 2 +- .../xcshareddata/xcschemes/watchOS-App-2.xcscheme | 9 +++++++++ Tests/ViewInspectorTests/SwiftUI/TreeViewTests.swift | 3 +++ 4 files changed, 16 insertions(+), 2 deletions(-) diff --git a/.watchOS/watchOS.xcodeproj/project.pbxproj b/.watchOS/watchOS.xcodeproj/project.pbxproj index ac2f30ed..96f546fb 100644 --- a/.watchOS/watchOS.xcodeproj/project.pbxproj +++ b/.watchOS/watchOS.xcodeproj/project.pbxproj @@ -868,7 +868,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 1300; - LastUpgradeCheck = 1250; + LastUpgradeCheck = 1300; TargetAttributes = { 520213A326ECB45D00E94C6E = { CreatedOnToolsVersion = 13.0; @@ -1489,6 +1489,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; @@ -1552,6 +1553,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; diff --git a/.watchOS/watchOS.xcodeproj/xcshareddata/xcschemes/watchOS-App-1.xcscheme b/.watchOS/watchOS.xcodeproj/xcshareddata/xcschemes/watchOS-App-1.xcscheme index 44287e7b..d5ab2364 100644 --- a/.watchOS/watchOS.xcodeproj/xcshareddata/xcschemes/watchOS-App-1.xcscheme +++ b/.watchOS/watchOS.xcodeproj/xcshareddata/xcschemes/watchOS-App-1.xcscheme @@ -1,6 +1,6 @@ + + + + diff --git a/Tests/ViewInspectorTests/SwiftUI/TreeViewTests.swift b/Tests/ViewInspectorTests/SwiftUI/TreeViewTests.swift index 08492c93..b199938a 100644 --- a/Tests/ViewInspectorTests/SwiftUI/TreeViewTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/TreeViewTests.swift @@ -6,12 +6,14 @@ import SwiftUI @available(tvOS, unavailable) final class TreeViewTests: XCTestCase { + @available(watchOS, deprecated: 7.0) func testEnclosedView() throws { let sut = Text("Test").contextMenu(ContextMenu(menuItems: { Text("Menu") })) let text = try sut.inspect().text().string() XCTAssertEqual(text, "Test") } + @available(watchOS, deprecated: 7.0) func testRetainsModifiers() throws { let view = Text("Test") .padding() @@ -28,6 +30,7 @@ final class TreeViewTests: XCTestCase { @available(tvOS, unavailable) final class GlobalModifiersForTreeView: XCTestCase { + @available(watchOS, deprecated: 7.0) func testContextMenu() throws { let sut = EmptyView().contextMenu(ContextMenu(menuItems: { Text("") })) XCTAssertNoThrow(try sut.inspect().emptyView()) From 58efe49865f6f741d3c98b3922a9c778c31b615b Mon Sep 17 00:00:00 2001 From: Alexey Naumov Date: Sat, 18 Sep 2021 20:09:00 +0300 Subject: [PATCH 71/99] Tweak texts --- Sources/ViewInspector/SwiftUI/CustomView.swift | 5 ++++- Sources/ViewInspector/ViewHosting.swift | 8 ++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/Sources/ViewInspector/SwiftUI/CustomView.swift b/Sources/ViewInspector/SwiftUI/CustomView.swift index 1fe3fbbb..6071a8c0 100644 --- a/Sources/ViewInspector/SwiftUI/CustomView.swift +++ b/Sources/ViewInspector/SwiftUI/CustomView.swift @@ -178,7 +178,10 @@ public extension WKInterfaceObjectRepresentable where Self: Inspectable { public extension Inspectable where Self: WKInterfaceObjectRepresentable { func extractContent(environmentObjects: [AnyObject]) throws -> Any { throw InspectionError.notSupported( - "Please use `.actualView().interfaceObject()` for inspecting the contents of WKInterfaceObjectRepresentable") + """ + Please use `.actualView().interfaceObject()` for inspecting \ + the contents of WKInterfaceObjectRepresentable + """) } } #endif diff --git a/Sources/ViewInspector/ViewHosting.swift b/Sources/ViewInspector/ViewHosting.swift index 4526f62b..c2aab6f3 100644 --- a/Sources/ViewInspector/ViewHosting.swift +++ b/Sources/ViewInspector/ViewHosting.swift @@ -31,6 +31,10 @@ public extension ViewHosting { try watchOS(host: AnyView(view), viewId: viewId) } catch { fatalError(error.localizedDescription) + /* + If you're running ViewInspector's tests on watchOS, launch them + from another Xcode project at ".watchOS/watchOS.xcodeproj" + */ } #else let parentVC = rootViewController @@ -86,10 +90,6 @@ public extension ViewHosting { } return nil }() else { - /* - If you're running ViewInspector's tests on watchOS, launch them - from another Xcode project at ".watchOS/watchOS.xcodeproj" - */ throw InspectionError.notSupported( "View hosting for watchOS is not set up. Please follow this guide: ") } From f920efaa8b8073dcd841fd51575fc21306bc0de1 Mon Sep 17 00:00:00 2001 From: Alexey Naumov Date: Sat, 18 Sep 2021 20:14:32 +0300 Subject: [PATCH 72/99] Disable APIs and tests requiring macOS SDK 12.0 --- Sources/ViewInspector/SwiftUI/ConfirmationDialog.swift | 2 ++ .../ViewInspectorTests/SwiftUI/ConfirmationDialogTests.swift | 2 ++ Tests/ViewInspectorTests/SwiftUI/SafeAreaInsetTests.swift | 2 ++ Tests/ViewInspectorTests/SwiftUI/TextAttributesTests.swift | 4 ++-- 4 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Sources/ViewInspector/SwiftUI/ConfirmationDialog.swift b/Sources/ViewInspector/SwiftUI/ConfirmationDialog.swift index 71b6e2cd..3b27fff4 100644 --- a/Sources/ViewInspector/SwiftUI/ConfirmationDialog.swift +++ b/Sources/ViewInspector/SwiftUI/ConfirmationDialog.swift @@ -97,10 +97,12 @@ public extension InspectableView where View == ViewType.ConfirmationDialog { .asInspectableView(ofType: ViewType.ClassifiedView.self) } + #if !os(macOS) // requires macOS SDK 12.0 func titleVisibility() throws -> Visibility { return try Inspector.attribute( label: "titleVisibility", value: content.view, type: Visibility.self) } + #endif func dismiss() throws { try isPresentedBinding().wrappedValue = false diff --git a/Tests/ViewInspectorTests/SwiftUI/ConfirmationDialogTests.swift b/Tests/ViewInspectorTests/SwiftUI/ConfirmationDialogTests.swift index e61a131e..cf33a8b7 100644 --- a/Tests/ViewInspectorTests/SwiftUI/ConfirmationDialogTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/ConfirmationDialogTests.swift @@ -2,6 +2,7 @@ import XCTest import SwiftUI @testable import ViewInspector +#if !os(macOS) // requires macOS SDK 12.0 @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) final class ConfirmationDialogTests: XCTestCase { @@ -119,3 +120,4 @@ final class ConfirmationDialogTests: XCTestCase { "group().text(1).confirmationDialog(1).actions().text()") } } +#endif diff --git a/Tests/ViewInspectorTests/SwiftUI/SafeAreaInsetTests.swift b/Tests/ViewInspectorTests/SwiftUI/SafeAreaInsetTests.swift index 3eda832f..e85212bf 100644 --- a/Tests/ViewInspectorTests/SwiftUI/SafeAreaInsetTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/SafeAreaInsetTests.swift @@ -2,6 +2,7 @@ import XCTest import SwiftUI @testable import ViewInspector +#if !os(macOS) // requires macOS SDK 12.0 @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) final class SafeAreaInsetTests: XCTestCase { @@ -75,3 +76,4 @@ final class SafeAreaInsetTests: XCTestCase { "group().text(1).safeAreaInset(1).text()") } } +#endif diff --git a/Tests/ViewInspectorTests/SwiftUI/TextAttributesTests.swift b/Tests/ViewInspectorTests/SwiftUI/TextAttributesTests.swift index 7c3ca74d..27947b92 100644 --- a/Tests/ViewInspectorTests/SwiftUI/TextAttributesTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/TextAttributesTests.swift @@ -96,7 +96,7 @@ final class TextAttributesTests: XCTestCase { let sut = try view.inspect().text().attributes() XCTAssertTrue(try sut.isStrikethrough()) XCTAssertEqual(try sut.strikethroughColor(), .black) - if #available(iOS 15.0, tvOS 15.0, macOS 11.6, watchOS 8.0, *) { + if #available(iOS 15.0, tvOS 15.0, macOS 12.0, watchOS 8.0, *) { XCTAssertEqual(try sut.strikethroughStyle(), .single) } } @@ -106,7 +106,7 @@ final class TextAttributesTests: XCTestCase { let sut = try view.inspect().text().attributes() XCTAssertTrue(try sut.isUnderline()) XCTAssertEqual(try sut.underlineColor(), .black) - if #available(iOS 15.0, tvOS 15.0, macOS 11.6, watchOS 8.0, *) { + if #available(iOS 15.0, tvOS 15.0, macOS 12.0, watchOS 8.0, *) { XCTAssertEqual(try sut.underlineStyle(), .single) } } From 9aeaa2ccbce383662b5b5cff8c62b2d3e41c72e1 Mon Sep 17 00:00:00 2001 From: Alexey Naumov Date: Sat, 18 Sep 2021 20:33:32 +0300 Subject: [PATCH 73/99] Remove UnaryViewAdaptor --- Sources/ViewInspector/Inspector.swift | 4 ---- .../SwiftUI/UnaryViewAdaptor.swift | 17 ----------------- ViewInspector.xcodeproj/project.pbxproj | 4 ---- 3 files changed, 25 deletions(-) delete mode 100644 Sources/ViewInspector/SwiftUI/UnaryViewAdaptor.swift diff --git a/Sources/ViewInspector/Inspector.swift b/Sources/ViewInspector/Inspector.swift index 853525f7..5a9a2563 100644 --- a/Sources/ViewInspector/Inspector.swift +++ b/Sources/ViewInspector/Inspector.swift @@ -187,7 +187,6 @@ internal extension Inspector { return try unwrap(content: Content(view, medium: medium)) } - // swiftlint:disable cyclomatic_complexity static func unwrap(content: Content) throws -> Content { switch Inspector.typeName(value: content.view, prefixOnly: true) { case "Tree": @@ -202,8 +201,6 @@ internal extension Inspector { return try ViewType.ViewModifier.child(content) case "SubscriptionView": return try ViewType.SubscriptionView.child(content) - case "_UnaryViewAdaptor": - return try ViewType.UnaryViewAdaptor.child(content) case "_ConditionalContent": return try ViewType.ConditionalContent.child(content) case "EnvironmentReaderView": @@ -214,7 +211,6 @@ internal extension Inspector { return content } } - // swiftlint:enable cyclomatic_complexity static func guardType(value: Any, namespacedPrefixes: [String], inspectionCall: String) throws { guard let firstPrefix = namespacedPrefixes.first diff --git a/Sources/ViewInspector/SwiftUI/UnaryViewAdaptor.swift b/Sources/ViewInspector/SwiftUI/UnaryViewAdaptor.swift deleted file mode 100644 index 6d4c6688..00000000 --- a/Sources/ViewInspector/SwiftUI/UnaryViewAdaptor.swift +++ /dev/null @@ -1,17 +0,0 @@ -import SwiftUI - -@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) -internal extension ViewType { - struct UnaryViewAdaptor { } -} - -// MARK: - Content Extraction - -@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) -extension ViewType.UnaryViewAdaptor: SingleViewContent { - - static func child(_ content: Content) throws -> Content { - let view = try Inspector.attribute(label: "content", value: content.view) - return try Inspector.unwrap(view: view, medium: content.medium) - } -} diff --git a/ViewInspector.xcodeproj/project.pbxproj b/ViewInspector.xcodeproj/project.pbxproj index d94d651f..090a7aed 100644 --- a/ViewInspector.xcodeproj/project.pbxproj +++ b/ViewInspector.xcodeproj/project.pbxproj @@ -30,7 +30,6 @@ 5214803A25F803DC002D974D /* CustomStyleModifiersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5214803025F803D5002D974D /* CustomStyleModifiersTests.swift */; }; 5223540026D62CB2008DA52F /* ToolbarTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 522353FF26D62CB2008DA52F /* ToolbarTests.swift */; }; 5223540226D63B7A008DA52F /* Toolbar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5223540126D63B79008DA52F /* Toolbar.swift */; }; - 5236C34326CDC2F4007432E1 /* UnaryViewAdaptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5236C34226CDC2F4007432E1 /* UnaryViewAdaptor.swift */; }; 52507626264FC0F400ADE4E7 /* Alert.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52507625264FC0F400ADE4E7 /* Alert.swift */; }; 525076282650000600ADE4E7 /* AlertTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 525076272650000600ADE4E7 /* AlertTests.swift */; }; 52507647265155C000ADE4E7 /* TransitiveModifiersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52507646265155C000ADE4E7 /* TransitiveModifiersTests.swift */; }; @@ -283,7 +282,6 @@ 5214803025F803D5002D974D /* CustomStyleModifiersTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomStyleModifiersTests.swift; sourceTree = ""; }; 522353FF26D62CB2008DA52F /* ToolbarTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ToolbarTests.swift; sourceTree = ""; }; 5223540126D63B79008DA52F /* Toolbar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Toolbar.swift; sourceTree = ""; }; - 5236C34226CDC2F4007432E1 /* UnaryViewAdaptor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnaryViewAdaptor.swift; sourceTree = ""; }; 52507625264FC0F400ADE4E7 /* Alert.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Alert.swift; sourceTree = ""; }; 525076272650000600ADE4E7 /* AlertTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertTests.swift; sourceTree = ""; }; 52507646265155C000ADE4E7 /* TransitiveModifiersTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransitiveModifiersTests.swift; sourceTree = ""; }; @@ -678,7 +676,6 @@ F639DBC223A7DDA2003A6FED /* TouchBar.swift */, F64A2C6723A3FD3A00A4853A /* TreeView.swift */, F653BDE2255698A6001FA688 /* TupleView.swift */, - 5236C34226CDC2F4007432E1 /* UnaryViewAdaptor.swift */, F6D933B22385ED1400358E0E /* VSplitView.swift */, F60EEBC92382EED0007DB53A /* VStack.swift */, F60EEBC12382EED0007DB53A /* ZStack.swift */, @@ -1027,7 +1024,6 @@ F6C15ADD254F26B9000240F1 /* StyleConfiguration.swift in Sources */, F639DBC323A7DDA2003A6FED /* TouchBar.swift in Sources */, 52507626264FC0F400ADE4E7 /* Alert.swift in Sources */, - 5236C34326CDC2F4007432E1 /* UnaryViewAdaptor.swift in Sources */, 5223540226D63B7A008DA52F /* Toolbar.swift in Sources */, F60EEBD32382EED0007DB53A /* ZStack.swift in Sources */, 5214802B25F803B7002D974D /* CustomStyleModifiers.swift in Sources */, From 7c0f9f7446c213e734f9cbe903103882477448e1 Mon Sep 17 00:00:00 2001 From: Alexey Naumov Date: Sat, 18 Sep 2021 20:50:45 +0300 Subject: [PATCH 74/99] Mark popover inspection available for iOS 14.2 and above --- Sources/ViewInspector/SwiftUI/Popover.swift | 2 +- Tests/ViewInspectorTests/SwiftUI/PopoverTests.swift | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/Sources/ViewInspector/SwiftUI/Popover.swift b/Sources/ViewInspector/SwiftUI/Popover.swift index 9729899a..d86a932b 100644 --- a/Sources/ViewInspector/SwiftUI/Popover.swift +++ b/Sources/ViewInspector/SwiftUI/Popover.swift @@ -36,7 +36,7 @@ extension ViewType.Popover: MultipleViewContent { // MARK: - Extraction -@available(iOS 13.0, macOS 10.15, *) +@available(iOS 14.2, macOS 11.0, *) @available(tvOS, unavailable) @available(watchOS, unavailable) public extension InspectableView { diff --git a/Tests/ViewInspectorTests/SwiftUI/PopoverTests.swift b/Tests/ViewInspectorTests/SwiftUI/PopoverTests.swift index 5116e44f..2fb8ee2e 100644 --- a/Tests/ViewInspectorTests/SwiftUI/PopoverTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/PopoverTests.swift @@ -16,14 +16,17 @@ final class PopoverTests: XCTestCase { } func testInspectionErrorNoModifier() throws { + guard #available(iOS 14.2, macOS 11.0, *) else { return } let sut = EmptyView().offset() XCTAssertThrows(try sut.inspect().emptyView().popover(), "EmptyView does not have 'popover' modifier") } func testInspectionErrorCustomModifierRequired() throws { + guard #available(iOS 14.2, macOS 11.0, *) else { return } let binding = Binding(wrappedValue: true) let sut = EmptyView().popover(isPresented: binding) { Text("") } + print("\(Inspector.print(sut) as AnyObject)") XCTAssertThrows(try sut.inspect().emptyView().popover(), """ Please refer to the Guide for inspecting the Popover: \ @@ -32,6 +35,7 @@ final class PopoverTests: XCTestCase { } func testInspectionErrorPopoverNotPresented() throws { + guard #available(iOS 14.2, macOS 11.0, *) else { return } let binding = Binding(wrappedValue: false) let sut = EmptyView().popover2(isPresented: binding) { Text("") } XCTAssertThrows(try sut.inspect().emptyView().popover(), @@ -39,6 +43,7 @@ final class PopoverTests: XCTestCase { } func testInspectionErrorPopoverWithItemNotPresented() throws { + guard #available(iOS 14.2, macOS 11.0, *) else { return } let binding = Binding(wrappedValue: nil) let sut = EmptyView().popover2(item: binding) { Text("\($0)") } XCTAssertThrows(try sut.inspect().emptyView().popover(), @@ -46,6 +51,7 @@ final class PopoverTests: XCTestCase { } func testContentInspection() throws { + guard #available(iOS 14.2, macOS 11.0, *) else { return } let binding = Binding(wrappedValue: true) let sut = EmptyView().popover2(isPresented: binding) { Text("abc") @@ -56,6 +62,7 @@ final class PopoverTests: XCTestCase { } func testContentInteraction() throws { + guard #available(iOS 14.2, macOS 11.0, *) else { return } let binding = Binding(wrappedValue: true) let sut = EmptyView().popover2(isPresented: binding) { Text("abc") @@ -68,6 +75,7 @@ final class PopoverTests: XCTestCase { } func testDismiss() throws { + guard #available(iOS 14.2, macOS 11.0, *) else { return } let binding = Binding(wrappedValue: true) let sut = EmptyView().popover2(isPresented: binding, content: { Text("") }) XCTAssertTrue(binding.wrappedValue) @@ -77,6 +85,7 @@ final class PopoverTests: XCTestCase { } func testDismissForItemVersion() throws { + guard #available(iOS 14.2, macOS 11.0, *) else { return } let binding = Binding(wrappedValue: 6) let sut = EmptyView().popover2(item: binding) { Text("\($0)") } let popover = try sut.inspect().emptyView().popover() @@ -88,6 +97,7 @@ final class PopoverTests: XCTestCase { } func testMultiplePopoversInspection() throws { + guard #available(iOS 14.2, macOS 11.0, *) else { return } let binding1 = Binding(wrappedValue: true) let binding2 = Binding(wrappedValue: true) let binding3 = Binding(wrappedValue: true) @@ -110,6 +120,7 @@ final class PopoverTests: XCTestCase { } func testFindAndPathToRoots() throws { + guard #available(iOS 14.2, macOS 11.0, *) else { return } let binding = Binding(wrappedValue: true) let sut = PopoverFindTestView(popover1: binding, popover2: binding, popover3: binding) @@ -175,6 +186,7 @@ final class PopoverDeprecatedTests: XCTestCase { @available(*, deprecated) func testContentView() throws { + guard #available(iOS 14.2, macOS 11.0, *) else { return } let binding = Binding(wrappedValue: true) let sut = EmptyView().popover2(isPresented: binding) { Text("") } let popover = try sut.inspect().emptyView().popover() @@ -184,6 +196,7 @@ final class PopoverDeprecatedTests: XCTestCase { @available(*, deprecated) func testIsPresentedAndDismiss() throws { + guard #available(iOS 14.2, macOS 11.0, *) else { return } let binding = Binding(wrappedValue: true) let sut = EmptyView().popover2(isPresented: binding) { Text("") } XCTAssertTrue(try sut.inspect().emptyView().popover().isPresented()) From ab83bb2c7587d62084d2c32242ae283e0c4aa372 Mon Sep 17 00:00:00 2001 From: Alexey Naumov Date: Sat, 18 Sep 2021 20:53:06 +0300 Subject: [PATCH 75/99] Silence a swiftlint warning --- .watchOS/watchOS-Ext/watchOSApp-1.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.watchOS/watchOS-Ext/watchOSApp-1.swift b/.watchOS/watchOS-Ext/watchOSApp-1.swift index d5ac9a5f..6136b5ae 100644 --- a/.watchOS/watchOS-Ext/watchOSApp-1.swift +++ b/.watchOS/watchOS-Ext/watchOSApp-1.swift @@ -3,7 +3,9 @@ import SwiftUI @main struct watchOSApp: App { + // swiftlint:disable weak_delegate @WKExtensionDelegateAdaptor(ExtensionDelegate.self) var extDelegate + // swiftlint:enable weak_delegate var body: some Scene { WindowGroup { From 283363819d05d0b0576ac4ae22daaa6254cbead1 Mon Sep 17 00:00:00 2001 From: Alexey Naumov Date: Sat, 18 Sep 2021 23:01:30 +0300 Subject: [PATCH 76/99] Add the guide for watchOS view hosting --- .../watchOS-Ext/watchOSApp+Testable.swift | 4 +- .watchOS/watchOS-Ext/watchOSApp-2.swift | 4 - .../xcschemes/watchOS-App-1.xcscheme | 4 +- .../xcschemes/watchOS-App-2.xcscheme | 4 +- Sources/ViewInspector/ViewHosting.swift | 5 +- guide_watchOS.md | 78 +++++++++++++++++++ 6 files changed, 88 insertions(+), 11 deletions(-) create mode 100644 guide_watchOS.md diff --git a/.watchOS/watchOS-Ext/watchOSApp+Testable.swift b/.watchOS/watchOS-Ext/watchOSApp+Testable.swift index cc465d23..0fe66c45 100644 --- a/.watchOS/watchOS-Ext/watchOSApp+Testable.swift +++ b/.watchOS/watchOS-Ext/watchOSApp+Testable.swift @@ -2,11 +2,10 @@ import SwiftUI import WatchKit import Combine -typealias TestViewSubject = CurrentValueSubject<[(String, AnyView)], Never> - #if !(os(watchOS) && DEBUG) typealias RootView = T +typealias TestViewSubject = Set extension View { @inline(__always) @@ -18,6 +17,7 @@ extension View { #else typealias RootView = ModifiedContent +typealias TestViewSubject = CurrentValueSubject<[(String, AnyView)], Never> extension View { func testable(_ injector: TestViewSubject) -> ModifiedContent { diff --git a/.watchOS/watchOS-Ext/watchOSApp-2.swift b/.watchOS/watchOS-Ext/watchOSApp-2.swift index 109a31a2..32071b39 100644 --- a/.watchOS/watchOS-Ext/watchOSApp-2.swift +++ b/.watchOS/watchOS-Ext/watchOSApp-2.swift @@ -16,7 +16,3 @@ struct ContentView: View { Text("Hi") } } - -final class ExtensionDelegate: NSObject, WKExtensionDelegate { - -} diff --git a/.watchOS/watchOS.xcodeproj/xcshareddata/xcschemes/watchOS-App-1.xcscheme b/.watchOS/watchOS.xcodeproj/xcshareddata/xcschemes/watchOS-App-1.xcscheme index d5ab2364..3dc144f8 100644 --- a/.watchOS/watchOS.xcodeproj/xcshareddata/xcschemes/watchOS-App-1.xcscheme +++ b/.watchOS/watchOS.xcodeproj/xcshareddata/xcschemes/watchOS-App-1.xcscheme @@ -29,7 +29,7 @@ @@ -47,7 +47,7 @@ diff --git a/.watchOS/watchOS.xcodeproj/xcshareddata/xcschemes/watchOS-App-2.xcscheme b/.watchOS/watchOS.xcodeproj/xcshareddata/xcschemes/watchOS-App-2.xcscheme index 9d3cfcd4..33c5de47 100644 --- a/.watchOS/watchOS.xcodeproj/xcshareddata/xcschemes/watchOS-App-2.xcscheme +++ b/.watchOS/watchOS.xcodeproj/xcshareddata/xcschemes/watchOS-App-2.xcscheme @@ -29,7 +29,7 @@ @@ -47,7 +47,7 @@ diff --git a/Sources/ViewInspector/ViewHosting.swift b/Sources/ViewInspector/ViewHosting.swift index c2aab6f3..b2b79694 100644 --- a/Sources/ViewInspector/ViewHosting.swift +++ b/Sources/ViewInspector/ViewHosting.swift @@ -91,7 +91,10 @@ public extension ViewHosting { return nil }() else { throw InspectionError.notSupported( - "View hosting for watchOS is not set up. Please follow this guide: ") + """ + View hosting for watchOS is not set up. Please follow this guide: \ + https://github.com/nalexn/ViewInspector/blob/master/guide_watchOS.md + """) } var array = subject.value if let view = view { diff --git a/guide_watchOS.md b/guide_watchOS.md new file mode 100644 index 00000000..6d1b9007 --- /dev/null +++ b/guide_watchOS.md @@ -0,0 +1,78 @@ +# View Hosting on watchOS + +Because of WatchKit API limitations **ViewInspector** currently cannot automatically host your views for asynchronous tests - you need to add [this swift file](https://github.com/nalexn/ViewInspector/blob/0.8.2/.watchOS/watchOS-Ext/watchOSApp%2BTestable.swift) to your **watchOS extension target**. + +Then, add the appropriate code snippet, depending on your setup: + +### If your watchOS project is using `@main` + +1. Make sure to add `WKExtensionDelegate` and reference it in the `App` using `@WKExtensionDelegateAdaptor`. +2. Add `let testViewSubject = TestViewSubject([])` as an instance variable to the `ExtensionDelegate`. +3. Add `.testable(extDelegate.testViewSubject)` to your `ContentView` inside `WindowGroup`. + +The final code should look similar to this: + +```swift +final class ExtensionDelegate: NSObject, WKExtensionDelegate { + let testViewSubject = TestViewSubject([]) // #2 +} + +@main +struct MyWatchOSApp: App { + + @WKExtensionDelegateAdaptor(ExtensionDelegate.self) var extDelegate // #1 + + var body: some Scene { + WindowGroup { + ContentView() + .testable(extDelegate.testViewSubject) // #3 + } + } +} +``` + +### If your watchOS project is using `storyboard` + +1. Make sure your root interface controller is a `WKHostingController` descendant. +2. Add `let testViewSubject = TestViewSubject([])` as an instance variable to your root interface controller. +3. Add `.testable(testViewSubject)` to your `ContentView` +4. Replace `var body: ContentView` with `var body: RootView` +5. Replace `WKHostingController` with `WKHostingController>` + +The final code should look similar to this: + +```swift +final class RootInterfaceController: WKHostingController> { // #1 , #5 + + let testViewSubject = TestViewSubject([]) // #2 + + override var body: RootView { // #4 + return ContentView() + .testable(testViewSubject) // #3 + } +} + +struct ContentView: View { + var body: some View { + Text("Hi") + } +} +``` + +## Consequences of intruding the main build target's code + +The proposed code snippets are using `conditional compilation` to minimize the footprint in the main build target. + +The condition `#if !(os(watchOS) && DEBUG)` fully disintegrates the test code in `Release` builds and replaces it with these primitives: + +```swift +typealias RootView = T +typealias TestViewSubject = Set + +extension View { + @inline(__always) + func testable(_ injector: TestViewSubject) -> Self { + self + } +} +``` \ No newline at end of file From 20c31aa7ca7951508318076f6dffe6691bb92b76 Mon Sep 17 00:00:00 2001 From: Alexey Naumov Date: Sat, 18 Sep 2021 23:04:45 +0300 Subject: [PATCH 77/99] Fix compilation issue on watchOS from the main project --- Sources/ViewInspector/ViewHosting.swift | 2 +- Tests/ViewInspectorTests/SwiftUI/CustomViewTests.swift | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/ViewInspector/ViewHosting.swift b/Sources/ViewInspector/ViewHosting.swift index b2b79694..7e49ec98 100644 --- a/Sources/ViewInspector/ViewHosting.swift +++ b/Sources/ViewInspector/ViewHosting.swift @@ -241,7 +241,7 @@ private class RootViewController: NSViewController { // MARK: - UIView lookup -@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) +@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 7.0, *) internal extension ViewHosting { #if os(macOS) static func lookup(_ view: V.Type) throws -> V.NSViewType diff --git a/Tests/ViewInspectorTests/SwiftUI/CustomViewTests.swift b/Tests/ViewInspectorTests/SwiftUI/CustomViewTests.swift index 3b5eceaa..9d4172e4 100644 --- a/Tests/ViewInspectorTests/SwiftUI/CustomViewTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/CustomViewTests.swift @@ -4,7 +4,7 @@ import SwiftUI @testable import ViewInspector -@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) +@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 7.0, *) final class CustomViewTests: XCTestCase { func testLocalStateChanges() throws { From 786873ba52749a05ab82c3739c95dda51c393d97 Mon Sep 17 00:00:00 2001 From: Alexey Naumov Date: Sat, 18 Sep 2021 23:18:20 +0300 Subject: [PATCH 78/99] Fix the tests for macCatalyst --- .../ViewInspector/Modifiers/EnvironmentModifiers.swift | 2 +- Sources/ViewInspector/Modifiers/TextInputModifiers.swift | 4 ++-- Sources/ViewInspector/SwiftUI/ConfirmationDialog.swift | 2 +- .../SwiftUI/ConfirmationDialogTests.swift | 2 +- Tests/ViewInspectorTests/SwiftUI/SafeAreaInsetTests.swift | 2 +- .../ViewModifiers/InteractionModifiersTests.swift | 8 ++++---- .../ViewModifiers/TextInputModifiersTests.swift | 4 ++-- 7 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Sources/ViewInspector/Modifiers/EnvironmentModifiers.swift b/Sources/ViewInspector/Modifiers/EnvironmentModifiers.swift index 5436d660..1bbedfae 100644 --- a/Sources/ViewInspector/Modifiers/EnvironmentModifiers.swift +++ b/Sources/ViewInspector/Modifiers/EnvironmentModifiers.swift @@ -90,7 +90,7 @@ extension _EnvironmentKeyWritingModifier: EnvironmentModifier { extension _EnvironmentKeyTransformModifier: EnvironmentModifier { static func qualifiesAsEnvironmentModifier() -> Bool { - #if !os(macOS) + #if !os(macOS) && !targetEnvironment(macCatalyst) if #available(iOS 15.0, tvOS 15.0, watchOS 8.0, *), Value.self == TextInputAutocapitalization.self { return true diff --git a/Sources/ViewInspector/Modifiers/TextInputModifiers.swift b/Sources/ViewInspector/Modifiers/TextInputModifiers.swift index cd4ffb8e..504afd67 100644 --- a/Sources/ViewInspector/Modifiers/TextInputModifiers.swift +++ b/Sources/ViewInspector/Modifiers/TextInputModifiers.swift @@ -5,7 +5,7 @@ import SwiftUI @available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *) public extension InspectableView { - #if os(iOS) || os(tvOS) + #if (os(iOS) || os(tvOS)) && !targetEnvironment(macCatalyst) func textContentType() throws -> UITextContentType? { let reference = EmptyView().textContentType(.emailAddress) let keyPath = try Inspector.environmentKeyPath(Optional.self, reference) @@ -125,7 +125,7 @@ public extension InspectableView { } } -#if os(iOS) || os(tvOS) +#if (os(iOS) || os(tvOS)) && !targetEnvironment(macCatalyst) @available(iOS 15.0, tvOS 15.0, watchOS 8.0, *) extension TextInputAutocapitalization { enum Behavior: String { diff --git a/Sources/ViewInspector/SwiftUI/ConfirmationDialog.swift b/Sources/ViewInspector/SwiftUI/ConfirmationDialog.swift index 3b27fff4..05b4c6e1 100644 --- a/Sources/ViewInspector/SwiftUI/ConfirmationDialog.swift +++ b/Sources/ViewInspector/SwiftUI/ConfirmationDialog.swift @@ -97,7 +97,7 @@ public extension InspectableView where View == ViewType.ConfirmationDialog { .asInspectableView(ofType: ViewType.ClassifiedView.self) } - #if !os(macOS) // requires macOS SDK 12.0 + #if !os(macOS) && !targetEnvironment(macCatalyst) // requires macOS SDK 12.0 func titleVisibility() throws -> Visibility { return try Inspector.attribute( label: "titleVisibility", value: content.view, type: Visibility.self) diff --git a/Tests/ViewInspectorTests/SwiftUI/ConfirmationDialogTests.swift b/Tests/ViewInspectorTests/SwiftUI/ConfirmationDialogTests.swift index cf33a8b7..e67d9b2a 100644 --- a/Tests/ViewInspectorTests/SwiftUI/ConfirmationDialogTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/ConfirmationDialogTests.swift @@ -2,7 +2,7 @@ import XCTest import SwiftUI @testable import ViewInspector -#if !os(macOS) // requires macOS SDK 12.0 +#if !os(macOS) && !targetEnvironment(macCatalyst) // requires macOS SDK 12.0 @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) final class ConfirmationDialogTests: XCTestCase { diff --git a/Tests/ViewInspectorTests/SwiftUI/SafeAreaInsetTests.swift b/Tests/ViewInspectorTests/SwiftUI/SafeAreaInsetTests.swift index e85212bf..ae8117a5 100644 --- a/Tests/ViewInspectorTests/SwiftUI/SafeAreaInsetTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/SafeAreaInsetTests.swift @@ -2,7 +2,7 @@ import XCTest import SwiftUI @testable import ViewInspector -#if !os(macOS) // requires macOS SDK 12.0 +#if !os(macOS) && !targetEnvironment(macCatalyst) // requires macOS SDK 12.0 @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) final class SafeAreaInsetTests: XCTestCase { diff --git a/Tests/ViewInspectorTests/ViewModifiers/InteractionModifiersTests.swift b/Tests/ViewInspectorTests/ViewModifiers/InteractionModifiersTests.swift index 2c3841f5..df173e37 100644 --- a/Tests/ViewInspectorTests/ViewModifiers/InteractionModifiersTests.swift +++ b/Tests/ViewInspectorTests/ViewModifiers/InteractionModifiersTests.swift @@ -40,7 +40,7 @@ final class InteractionTests: XCTestCase { } func testOnPasteCommand() throws { - let sut = EmptyView().onPasteCommand(of: []) { _ in } + let sut = EmptyView().onPasteCommand(of: [String]()) { _ in } XCTAssertNoThrow(try sut.inspect().emptyView()) } @@ -58,7 +58,7 @@ final class InteractionTests: XCTestCase { func testOnPasteCommandPayload() throws { let sut = EmptyView() - .onPasteCommand(of: [], validator: { _ in nil as Void? }, perform: { _ in }) + .onPasteCommand(of: [String](), validator: { _ in nil as Void? }, perform: { _ in }) XCTAssertNoThrow(try sut.inspect().emptyView()) } @@ -211,13 +211,13 @@ final class ViewDragDropTests: XCTestCase { } func testOnDropDelegate() throws { - let sut = EmptyView().onDrop(of: [], delegate: DummyDropDelegate()) + let sut = EmptyView().onDrop(of: [String](), delegate: DummyDropDelegate()) XCTAssertNoThrow(try sut.inspect().emptyView()) } func testOnDropCallback() throws { let binding = Binding(wrappedValue: true) - let sut = EmptyView().onDrop(of: [], isTargeted: binding, perform: { _ in false }) + let sut = EmptyView().onDrop(of: [String](), isTargeted: binding, perform: { _ in false }) XCTAssertNoThrow(try sut.inspect().emptyView()) } #endif diff --git a/Tests/ViewInspectorTests/ViewModifiers/TextInputModifiersTests.swift b/Tests/ViewInspectorTests/ViewModifiers/TextInputModifiersTests.swift index 93763377..c343fc35 100644 --- a/Tests/ViewInspectorTests/ViewModifiers/TextInputModifiersTests.swift +++ b/Tests/ViewInspectorTests/ViewModifiers/TextInputModifiersTests.swift @@ -14,7 +14,7 @@ final class TextInputModifiersTests: XCTestCase { } #endif - #if os(iOS) || os(tvOS) + #if (os(iOS) || os(tvOS)) && !targetEnvironment(macCatalyst) func testTextContentTypeInspection() throws { let sut = AnyView(EmptyView()).textContentType(.emailAddress) XCTAssertEqual(try sut.inspect().anyView().textContentType(), .emailAddress) @@ -22,7 +22,7 @@ final class TextInputModifiersTests: XCTestCase { } #endif - #if os(iOS) || os(tvOS) + #if (os(iOS) || os(tvOS)) && !targetEnvironment(macCatalyst) func testKeyboardType() throws { let sut = EmptyView().keyboardType(.namePhonePad) XCTAssertNoThrow(try sut.inspect().emptyView()) From a27f2a92facdc3197f6764682d9e45fe94e7c79b Mon Sep 17 00:00:00 2001 From: Alexey Naumov Date: Sat, 18 Sep 2021 23:53:02 +0300 Subject: [PATCH 79/99] Update readiness --- readiness.md | 30 +++++++++--------------------- 1 file changed, 9 insertions(+), 21 deletions(-) diff --git a/readiness.md b/readiness.md index 883d3ea4..835423b9 100644 --- a/readiness.md +++ b/readiness.md @@ -25,6 +25,7 @@ Visit [this discussion](https://github.com/nalexn/ViewInspector/discussions/60) |:white_check_mark:| Color | `value: Color`, `rgba: (Float, Float, Float, Float)`, `name: String` | |:white_check_mark:| ColorPicker | `label view`, `select(color: Color)` | |:white_check_mark:| ConditionalContent | `contained view` | +|:white_check_mark:| ConfirmationDialog | `title view`, `message view`, `actions view`, `titleVisibility: Visibility`, `dismiss()` | |:white_check_mark:| Custom View | `actualView: CustomView`, `viewBuilder container` | |:white_check_mark:| Custom ViewModifier | | |:white_check_mark:| Custom ViewModifier.Content | | @@ -75,6 +76,7 @@ Visit [this discussion](https://github.com/nalexn/ViewInspector/discussions/60) |:white_check_mark:| ProgressViewStyleConfiguration.CurrentValueLabel | | |:white_check_mark:| ProgressViewStyleConfiguration.Label | | |:white_check_mark:| RadialGradient | `gradient: Gradient`, `center: UnitPoint`, `startRadius: CGFloat`, `endRadius: CGFloat` | +|:white_check_mark:| SafeAreaInset | `regions: SafeAreaRegions`, `spacing: CGFloat?`, `edge: Edge` | |:technologist:| SceneView | | |:white_check_mark:| ScrollView | `contained view`, `contentInsets: EdgeInsets` | |:white_check_mark:| ScrollViewReader | `contained view` | @@ -349,35 +351,21 @@ Visit [this discussion](https://github.com/nalexn/ViewInspector/discussions/60) |:white_check_mark:| `func allowsHitTesting(Bool) -> some View` | |:white_check_mark:| `func contentShape(S, eoFill: Bool) -> some View` | -### Presenting Action Sheets +### Presenting system popup views | Status | Modifier | |:---:|---| |:white_check_mark:| `func actionSheet(isPresented: Binding, content: () -> ActionSheet) -> some View` | |:white_check_mark:| `func actionSheet(item: Binding, content: (T) -> ActionSheet) -> some View` | - -### Presenting Sheets - -| Status | Modifier | -|:---:|---| |:white_check_mark:| `func sheet(isPresented: Binding, onDismiss: (() -> Void)?, content: () -> Content) -> some View` | |:white_check_mark:| `func sheet(item: Binding, onDismiss: (() -> Void)?, content: (Item) -> Content) -> some View` | -|:technologist:| `func fullScreenCover(isPresented: Binding, onDismiss: (() -> Void)?, content: () -> Content) -> some View` | -|:technologist:| `func fullScreenCover(item: Binding, onDismiss: (() -> Void)?, content: (Item) -> Content) -> some View` | - -### Presenting Alerts - -| Status | Modifier | -|:---:|---| +|: white_check_mark:| `func fullScreenCover(isPresented: Binding, onDismiss: (() -> Void)?, content: () -> Content) -> some View` | +|: white_check_mark:| `func fullScreenCover(item: Binding, onDismiss: (() -> Void)?, content: (Item) -> Content) -> some View` | |:white_check_mark:| `func alert(isPresented: Binding, content: () -> Alert) -> some View` | |:white_check_mark:| `func alert(item: Binding, content: (Item) -> Alert) -> some View` | - -### Presenting Popovers - -| Status | Modifier | -|:---:|---| |:white_check_mark:| `func popover(isPresented: Binding, attachmentAnchor: PopoverAttachmentAnchor, arrowEdge: Edge, content: () -> Content) -> some View` | |:white_check_mark:| `func popover(item: Binding, attachmentAnchor: PopoverAttachmentAnchor, arrowEdge: Edge, content: (Item) -> Content) -> some View` | +|:white_check_mark:| `func confirmationDialog(_ title: S, isPresented: Binding, titleVisibility: Visibility, @ViewBuilder actions: () -> A, @ViewBuilder message: () -> M) -> some View` | ### APIs from other Frameworks @@ -558,9 +546,9 @@ Visit [this discussion](https://github.com/nalexn/ViewInspector/discussions/60) | Status | Modifier | |:---:|---| -|:technologist:| `func toolbar(content: () -> Content) -> some View` | -|:technologist:| `func toolbar(content: () -> Content) -> some View` | -|:technologist:| `func toolbar(id: String, content: () -> Content) -> some View` | +|: white_check_mark:| `func toolbar(content: () -> Content) -> some View` | +|: white_check_mark:| `func toolbar(content: () -> Content) -> some View` | +|: white_check_mark:| `func toolbar(id: String, content: () -> Content) -> some View` | ### Configuring Context Menu Views From 6802c15adefb69ae8c81725f8aa559984950779b Mon Sep 17 00:00:00 2001 From: Alexey Naumov Date: Sat, 18 Sep 2021 23:53:50 +0300 Subject: [PATCH 80/99] Export popups inspection guide to a separate file --- guide.md | 301 +---------------------------------------------- guide_popups.md | 305 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 307 insertions(+), 299 deletions(-) create mode 100644 guide_popups.md diff --git a/guide.md b/guide.md index 3108c639..5df722cf 100644 --- a/guide.md +++ b/guide.md @@ -7,9 +7,9 @@ - [Views using **@ObservedObject**](#views-using-observedobject) - [Views using **@State**, **@Environment** or **@EnvironmentObject**](#views-using-state-environment-or-environmentobject) - [Custom **ViewModifier**](#custom-viewmodifier) -- [Alert, Sheet and ActionSheet](#alert-sheet-and-actionsheet) - [Styles](guide_styles.md) - [Gestures](guide_gestures.md) +- [Alert, Sheet, ActionSheet, FullScreenCover and Popover](guide_popups.md) ## The Basics @@ -577,305 +577,8 @@ let view = EmptyView().modifier(sut).environmentObject(envObject) ViewHosting.host(view: view) ``` -## Alert, Sheet, ActionSheet, and FullScreenCover - -These four types of views have many in common, so is their inspection mechanism. Due to limited capabilities of what can be achieved in reflection, the native SwiftUI modifiers for presenting these views (`.alert`, `.sheet`, `.actionSheet`, `.fullScreenCover`) cannot be inspected as-is by the ViewInspector. - -This section discusses how you still can gain the full access to the internals of these views by adding a couple of code snippets to your source code while not making ViewInspector a dependency for the main target. - -### Making `Alert` inspectable - -Add the following snippet to your main target: - -```swift -extension View { - func alert2(isPresented: Binding, content: @escaping () -> Alert) -> some View { - return self.modifier(InspectableAlert(isPresented: isPresented, alertBuilder: content)) - } -} - -struct InspectableAlert: ViewModifier { - - let isPresented: Binding - let alertBuilder: () -> Alert - - func body(content: Self.Content) -> some View { - content.alert(isPresented: isPresented, content: alertBuilder) - } -} -``` - -And tweak the code of your view to use `alert2` instead of `alert`. Feel free to use another name instead of `alert2`. - -Then, add this line in your test target scope: - -```swift -extension InspectableAlert: AlertProvider { } -``` - -After that you'll be able to inspect the `Alert` in the tests: read the `title`, `message`, and access the buttons: - -```swift -func testAlertExample() throws { - let binding = Binding(wrappedValue: true) - let sut = EmptyView().alert2(isPresented: binding) { - Alert(title: Text("Title"), message: Text("Message"), - primaryButton: .destructive(Text("Delete")), - secondaryButton: .cancel(Text("Cancel"))) - } - let alert = try sut.inspect().emptyView().alert() - XCTAssertEqual(try alert.title().string(), "Title") - XCTAssertEqual(try alert.message().string(), "Message") - XCTAssertEqual(try alert.primaryButton().style(), .destructive) - try sut.inspect().find(ViewType.AlertButton.self, containing: "Cancel").tap() -} -``` - -SwiftUI has a second variant of the `Alert` presentation API, which takes a generic `Item` parameter. - -Here is the corresponding snippet for the main target: - -```swift -extension View { - func alert2(item: Binding, content: @escaping (Item) -> Alert) -> some View where Item: Identifiable { - return self.modifier(InspectableAlertWithItem(item: item, alertBuilder: content)) - } -} - -struct InspectableAlertWithItem: ViewModifier { - - let item: Binding - let alertBuilder: (Item) -> Alert - - func body(content: Self.Content) -> some View { - content.alert(item: item, content: alertBuilder) - } -} -``` - -And for the test scope: - -```swift -extension InspectableAlertWithItem: AlertItemProvider { } -``` - -Feel free to add both sets to the project as needed. - -### Making `ActionSheet` inspectable - -Just like with `Alert`, there are two APIs for showing `ActionSheet` in SwiftUI - a simple one taking a `isPresented: Binding` parameter, and a generic version taking `item: Binding` parameter. - -Variant with `isPresented: Binding` - main target snippet: - -```swift -extension View { - func actionSheet2(isPresented: Binding, content: @escaping () -> ActionSheet) -> some View { - return self.modifier(InspectableActionSheet(isPresented: isPresented, sheetBuilder: content)) - } -} - -struct InspectableActionSheet: ViewModifier { - - let isPresented: Binding - let sheetBuilder: () -> ActionSheet - - func body(content: Self.Content) -> some View { - content.actionSheet(isPresented: isPresented, content: sheetBuilder) - } -} -``` - -Test target: - -```swift -extension InspectableActionSheet: ActionSheetProvider { } -``` - -Variant with `item: Binding` - main target snippet: - -```swift -extension View { - func actionSheet2(item: Binding, content: @escaping (Item) -> ActionSheet) -> some View where Item: Identifiable { - return self.modifier(InspectableActionSheetWithItem(item: item, sheetBuilder: content)) - } -} - -struct InspectableActionSheetWithItem: ViewModifier { - - let item: Binding - let sheetBuilder: (Item) -> ActionSheet - - func body(content: Self.Content) -> some View { - content.actionSheet(item: item, content: sheetBuilder) - } -} -``` - -Test target: - -```swift -extension InspectableActionSheetWithItem: ActionSheetItemProvider { } -``` - -Make sure to use `actionSheet2` in your view's body (or a different name of your choice). - -### Making `Sheet` inspectable - -Similarly to the `Alert` and `ActionSheet`, there are two APIs for presenting the `Sheet` thus two sets of snippets to add to the project, depending on your needs. - -Variant with `isPresented: Binding` - main target snippet: - -```swift -extension View { - func sheet2(isPresented: Binding, onDismiss: (() -> Void)? = nil, @ViewBuilder content: @escaping () -> Sheet - ) -> some View where Sheet: View { - return self.modifier(InspectableSheet(isPresented: isPresented, onDismiss: onDismiss, content: content)) - } -} - -struct InspectableSheet: ViewModifier where Sheet: View { - - let isPresented: Binding - let onDismiss: (() -> Void)? - let content: () -> Sheet - let sheetBuilder: () -> Any - - init(isPresented: Binding, onDismiss: (() -> Void)?, content: @escaping () -> Sheet) { - self.isPresented = isPresented - self.onDismiss = onDismiss - self.content = content - self.sheetBuilder = { content() as Any } - } - - func body(content: Self.Content) -> some View { - content.sheet(isPresented: isPresented, content: self.content) - } -} -``` - -Test target: - -```swift -extension InspectableSheet: SheetProvider { } -``` - -Variant with `item: Binding` - main target snippet: - -```swift -extension View { - func sheet2(item: Binding, onDismiss: (() -> Void)? = nil, content: @escaping (Item) -> Sheet - ) -> some View where Item: Identifiable, Sheet: View { - return self.modifier(InspectableSheetWithItem(item: item, onDismiss: onDismiss, content: content)) - } -} - -struct InspectableSheetWithItem: ViewModifier where Item: Identifiable, Sheet: View { - - let item: Binding - let onDismiss: (() -> Void)? - let content: (Item) -> Sheet - let sheetBuilder: (Item) -> Any - - init(item: Binding, onDismiss: (() -> Void)?, content: @escaping (Item) -> Sheet) { - self.item = item - self.onDismiss = onDismiss - self.content = content - self.sheetBuilder = { content($0) as Any } - } - - func body(content: Self.Content) -> some View { - content.sheet(item: item, onDismiss: onDismiss, content: self.content) - } -} -``` - -Test target: - -```swift -extension InspectableSheetWithItem: SheetItemProvider { } -``` - -Don't forget that you'll need to use `sheet2` in place of `sheet` in your views. - -### Making `FullScreenCover` inspectable - -Similarly to the `Alert` and `Sheet`, there are two APIs for presenting the `FullScreenCover` thus two sets of snippets to add to the project, depending on your needs. - -Variant with `isPresented: Binding` - main target snippet: - -```swift -extension View { - func fullScreenCover2(isPresented: Binding, onDismiss: (() -> Void)? = nil, @ViewBuilder content: @escaping () -> FullScreenCover - ) -> some View where FullScreenCover: View { - return self.modifier(InspectableFullScreenCover(isPresented: isPresented, onDismiss: onDismiss, content: content)) - } -} - -struct InspectableFullScreenCover: ViewModifier where FullScreenCover: View { - - let isPresented: Binding - let onDismiss: (() -> Void)? - let content: () -> FullScreenCover - let fullScreenCoverBuilder: () -> Any - - init(isPresented: Binding, onDismiss: (() -> Void)?, content: @escaping () -> FullScreenCover) { - self.isPresented = isPresented - self.onDismiss = onDismiss - self.content = content - self.fullScreenCoverBuilder = { content() as Any } - } - - func body(content: Self.Content) -> some View { - content.fullScreenCover(isPresented: isPresented, content: self.content) - } -} -``` - -Test target: - -```swift -extension InspectableFullScreenCover: FullScreenCoverProvider { } -``` - -Variant with `item: Binding` - main target snippet: - -```swift -extension View { - func fullScreenCover2(item: Binding, onDismiss: (() -> Void)? = nil, content: @escaping (Item) -> FullScreenCover - ) -> some View where Item: Identifiable, FullScreenCover: View { - return self.modifier(InspectableFullScreenCoverWithItem(item: item, onDismiss: onDismiss, content: content)) - } -} - -struct InspectableFullScreenCoverWithItem: ViewModifier where Item: Identifiable, FullScreenCover: View { - - let item: Binding - let onDismiss: (() -> Void)? - let content: (Item) -> FullScreenCover - let fullScreenCoverBuilder: (Item) -> Any - - init(item: Binding, onDismiss: (() -> Void)?, content: @escaping (Item) -> FullScreenCover) { - self.item = item - self.onDismiss = onDismiss - self.content = content - self.fullScreenCoverBuilder = { content($0) as Any } - } - - func body(content: Self.Content) -> some View { - content.fullScreenCover(item: item, onDismiss: onDismiss, content: self.content) - } -} -``` - -Test target: - -```swift -extension InspectableFullScreenCoverWithItem: FullScreenCoverItemProvider { } -``` - -Don't forget that you'll need to use `fullScreenCover2` in place of `fullScreenCover` in your views. - ## Advanced topics - [Styles](guide_styles.md) - [Gestures](guide_gestures.md) +- [Alert, Sheet, ActionSheet, FullScreenCover and Popover](guide_popups.md) \ No newline at end of file diff --git a/guide_popups.md b/guide_popups.md new file mode 100644 index 00000000..67a0db6d --- /dev/null +++ b/guide_popups.md @@ -0,0 +1,305 @@ +# System popup views + +- [Alert](#alert) +- [ActionSheet](#actionsheet) +- [Sheet](#sheet) +- [FullScreenCover](#fullscreencover) +- [Popover](#popover) + +These five types of views have many in common, so is their inspection mechanism. Due to limited capabilities of what can be achieved in reflection, the native SwiftUI modifiers for presenting these views (`.alert`, `.actionSheet`, `.sheet`, `.fullScreenCover`, `.popover`) cannot be inspected as-is by the ViewInspector. + +This section discusses how you still can gain the full access to the internals of these views by adding a couple of code snippets to your source code while not making ViewInspector a dependency for the main target. + +## `Alert` + +Add the following snippet to your main target: + +```swift +extension View { + func alert2(isPresented: Binding, content: @escaping () -> Alert) -> some View { + return self.modifier(InspectableAlert(isPresented: isPresented, alertBuilder: content)) + } +} + +struct InspectableAlert: ViewModifier { + + let isPresented: Binding + let alertBuilder: () -> Alert + + func body(content: Self.Content) -> some View { + content.alert(isPresented: isPresented, content: alertBuilder) + } +} +``` + +And tweak the code of your view to use `alert2` instead of `alert`. Feel free to use another name instead of `alert2`. + +Then, add this line in your test target scope: + +```swift +extension InspectableAlert: AlertProvider { } +``` + +After that you'll be able to inspect the `Alert` in the tests: read the `title`, `message`, and access the buttons: + +```swift +func testAlertExample() throws { + let binding = Binding(wrappedValue: true) + let sut = EmptyView().alert2(isPresented: binding) { + Alert(title: Text("Title"), message: Text("Message"), + primaryButton: .destructive(Text("Delete")), + secondaryButton: .cancel(Text("Cancel"))) + } + let alert = try sut.inspect().emptyView().alert() + XCTAssertEqual(try alert.title().string(), "Title") + XCTAssertEqual(try alert.message().string(), "Message") + XCTAssertEqual(try alert.primaryButton().style(), .destructive) + try sut.inspect().find(ViewType.AlertButton.self, containing: "Cancel").tap() +} +``` + +SwiftUI has a second variant of the `Alert` presentation API, which takes a generic `Item` parameter. + +Here is the corresponding snippet for the main target: + +```swift +extension View { + func alert2(item: Binding, content: @escaping (Item) -> Alert) -> some View where Item: Identifiable { + return self.modifier(InspectableAlertWithItem(item: item, alertBuilder: content)) + } +} + +struct InspectableAlertWithItem: ViewModifier { + + let item: Binding + let alertBuilder: (Item) -> Alert + + func body(content: Self.Content) -> some View { + content.alert(item: item, content: alertBuilder) + } +} +``` + +And for the test scope: + +```swift +extension InspectableAlertWithItem: AlertItemProvider { } +``` + +Feel free to add both sets to the project as needed. + +## `ActionSheet` + +Just like with `Alert`, there are two APIs for showing `ActionSheet` in SwiftUI - a simple one taking a `isPresented: Binding` parameter, and a generic version taking `item: Binding` parameter. + +Variant with `isPresented: Binding` - main target snippet: + +```swift +extension View { + func actionSheet2(isPresented: Binding, content: @escaping () -> ActionSheet) -> some View { + return self.modifier(InspectableActionSheet(isPresented: isPresented, sheetBuilder: content)) + } +} + +struct InspectableActionSheet: ViewModifier { + + let isPresented: Binding + let sheetBuilder: () -> ActionSheet + + func body(content: Self.Content) -> some View { + content.actionSheet(isPresented: isPresented, content: sheetBuilder) + } +} +``` + +Test target: + +```swift +extension InspectableActionSheet: ActionSheetProvider { } +``` + +Variant with `item: Binding` - main target snippet: + +```swift +extension View { + func actionSheet2(item: Binding, content: @escaping (Item) -> ActionSheet) -> some View where Item: Identifiable { + return self.modifier(InspectableActionSheetWithItem(item: item, sheetBuilder: content)) + } +} + +struct InspectableActionSheetWithItem: ViewModifier { + + let item: Binding + let sheetBuilder: (Item) -> ActionSheet + + func body(content: Self.Content) -> some View { + content.actionSheet(item: item, content: sheetBuilder) + } +} +``` + +Test target: + +```swift +extension InspectableActionSheetWithItem: ActionSheetItemProvider { } +``` + +Make sure to use `actionSheet2` in your view's body (or a different name of your choice). + +## `Sheet` + +Similarly to the `Alert` and `ActionSheet`, there are two APIs for presenting the `Sheet` thus two sets of snippets to add to the project, depending on your needs. + +Variant with `isPresented: Binding` - main target snippet: + +```swift +extension View { + func sheet2(isPresented: Binding, onDismiss: (() -> Void)? = nil, @ViewBuilder content: @escaping () -> Sheet + ) -> some View where Sheet: View { + return self.modifier(InspectableSheet(isPresented: isPresented, onDismiss: onDismiss, content: content)) + } +} + +struct InspectableSheet: ViewModifier where Sheet: View { + + let isPresented: Binding + let onDismiss: (() -> Void)? + let content: () -> Sheet + let sheetBuilder: () -> Any + + init(isPresented: Binding, onDismiss: (() -> Void)?, content: @escaping () -> Sheet) { + self.isPresented = isPresented + self.onDismiss = onDismiss + self.content = content + self.sheetBuilder = { content() as Any } + } + + func body(content: Self.Content) -> some View { + content.sheet(isPresented: isPresented, content: self.content) + } +} +``` + +Test target: + +```swift +extension InspectableSheet: SheetProvider { } +``` + +Variant with `item: Binding` - main target snippet: + +```swift +extension View { + func sheet2(item: Binding, onDismiss: (() -> Void)? = nil, content: @escaping (Item) -> Sheet + ) -> some View where Item: Identifiable, Sheet: View { + return self.modifier(InspectableSheetWithItem(item: item, onDismiss: onDismiss, content: content)) + } +} + +struct InspectableSheetWithItem: ViewModifier where Item: Identifiable, Sheet: View { + + let item: Binding + let onDismiss: (() -> Void)? + let content: (Item) -> Sheet + let sheetBuilder: (Item) -> Any + + init(item: Binding, onDismiss: (() -> Void)?, content: @escaping (Item) -> Sheet) { + self.item = item + self.onDismiss = onDismiss + self.content = content + self.sheetBuilder = { content($0) as Any } + } + + func body(content: Self.Content) -> some View { + content.sheet(item: item, onDismiss: onDismiss, content: self.content) + } +} +``` + +Test target: + +```swift +extension InspectableSheetWithItem: SheetItemProvider { } +``` + +Don't forget that you'll need to use `sheet2` in place of `sheet` in your views. + +## `FullScreenCover` + +Similarly to the `Alert` and `Sheet`, there are two APIs for presenting the `FullScreenCover` thus two sets of snippets to add to the project, depending on your needs. + +Variant with `isPresented: Binding` - main target snippet: + +```swift +extension View { + func fullScreenCover2(isPresented: Binding, onDismiss: (() -> Void)? = nil, @ViewBuilder content: @escaping () -> FullScreenCover + ) -> some View where FullScreenCover: View { + return self.modifier(InspectableFullScreenCover(isPresented: isPresented, onDismiss: onDismiss, content: content)) + } +} + +struct InspectableFullScreenCover: ViewModifier where FullScreenCover: View { + + let isPresented: Binding + let onDismiss: (() -> Void)? + let content: () -> FullScreenCover + let fullScreenCoverBuilder: () -> Any + + init(isPresented: Binding, onDismiss: (() -> Void)?, content: @escaping () -> FullScreenCover) { + self.isPresented = isPresented + self.onDismiss = onDismiss + self.content = content + self.fullScreenCoverBuilder = { content() as Any } + } + + func body(content: Self.Content) -> some View { + content.fullScreenCover(isPresented: isPresented, content: self.content) + } +} +``` + +Test target: + +```swift +extension InspectableFullScreenCover: FullScreenCoverProvider { } +``` + +Variant with `item: Binding` - main target snippet: + +```swift +extension View { + func fullScreenCover2(item: Binding, onDismiss: (() -> Void)? = nil, content: @escaping (Item) -> FullScreenCover + ) -> some View where Item: Identifiable, FullScreenCover: View { + return self.modifier(InspectableFullScreenCoverWithItem(item: item, onDismiss: onDismiss, content: content)) + } +} + +struct InspectableFullScreenCoverWithItem: ViewModifier where Item: Identifiable, FullScreenCover: View { + + let item: Binding + let onDismiss: (() -> Void)? + let content: (Item) -> FullScreenCover + let fullScreenCoverBuilder: (Item) -> Any + + init(item: Binding, onDismiss: (() -> Void)?, content: @escaping (Item) -> FullScreenCover) { + self.item = item + self.onDismiss = onDismiss + self.content = content + self.fullScreenCoverBuilder = { content($0) as Any } + } + + func body(content: Self.Content) -> some View { + content.fullScreenCover(item: item, onDismiss: onDismiss, content: self.content) + } +} +``` + +Test target: + +```swift +extension InspectableFullScreenCoverWithItem: FullScreenCoverItemProvider { } +``` + +Don't forget that you'll need to use `fullScreenCover2` in place of `fullScreenCover` in your views. + +## `Popover` \ No newline at end of file From e489e15f3fff4cd7945c2db016c8abefffdcb0dc Mon Sep 17 00:00:00 2001 From: Alexey Naumov Date: Sun, 19 Sep 2021 00:53:04 +0300 Subject: [PATCH 81/99] Brush up the guide --- guide.md | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/guide.md b/guide.md index 5df722cf..044d574c 100644 --- a/guide.md +++ b/guide.md @@ -2,14 +2,12 @@ - [The Basics](#the-basics) - [Dynamic query with **find**](#dynamic-query-with-find) -- [Navigation Links](#navigation-links) +- [Inspectable attributes](#inspectable-attributes) - [Views using **@Binding**](#views-using-binding) - [Views using **@ObservedObject**](#views-using-observedobject) - [Views using **@State**, **@Environment** or **@EnvironmentObject**](#views-using-state-environment-or-environmentobject) - [Custom **ViewModifier**](#custom-viewmodifier) -- [Styles](guide_styles.md) -- [Gestures](guide_gestures.md) -- [Alert, Sheet, ActionSheet, FullScreenCover and Popover](guide_popups.md) +- [Advanced topics](#advanced-topics) ## The Basics @@ -229,19 +227,28 @@ One of such cases is a custom view that does not conform to `Inspectable`. Addin In addition to that, there are a few SwiftUI modifiers which currently block the search: * `navigationBarItems` -* `popover` * `overlayPreferenceValue` * `backgroundPreferenceValue` While the first two can be unwrapped manually, the last two are notorious for blocking the inspection completely. The workaround is under investigation. -## Navigation Links +## Inspectable attributes + +**ViewInspector** provides access to various parameters held inside Views. + +For a particular view type, there might be available values of `alignment` or `spacing`. For another, there could be `labelView` – a non-standard child view. + +[ViewInspector's API coverage](readiness.md) is the place where you can see all the attributes available for each view type. -A `NavigationLink` contains two views: one for the destination, another for the label. You can examine the label with `labelView()`. +Let's consider `NavigationLink` as an example: it offers `contained view`, `label view`, `isActive: Bool`, `activate()` and `deactivate()`. -The destination is a "contained view" as shown in [ViewInspector's API coverage](readiness.md). Access an inspectable version of the contained view with `view()`, specifying the actual type. From there, you can get the actual view with `actualView()`. +While the last three are self-explanatory, you can see it contains two views: one for the destination, another for the label. -For example, let's say we have a view with a `NavigationLink` inside a `VStack`. The view body looks likes this: +The destination view is the "default" child, which gets returned as you continue chaining the view inspection calls (such as `hStack()` or `view(MyCustomView.self)`) after the `navigationLink()`. Such a direct descendant view is referred to as "contained view". + +Label view, on the other hand, is an additional child view available for inspection on `NavigationLink`. In order to direct ViewInspector to that view, use `labelView()` call after the `navigationLink()`. + +Let's say we have a view with a `NavigationLink` inside a `VStack`. The view body looks likes this: ```swift var body: some View { @@ -269,6 +276,12 @@ let nextView = try link.view(MyView.self).actualView() XCTAssertEqual(nextView.parameter, "Screen 1") ``` +or unwrap the label view and read its contents: + +```swift +let label = try link.labelView().text() +XCTAssertEqual(try label.string(), "Continue") +``` ## Views using `@Binding` @@ -581,4 +594,5 @@ ViewHosting.host(view: view) - [Styles](guide_styles.md) - [Gestures](guide_gestures.md) +- [View Hosting on watchOS](guide_watchOS.md) - [Alert, Sheet, ActionSheet, FullScreenCover and Popover](guide_popups.md) \ No newline at end of file From 386212ff6c6376a89d361f86e4cf66694f1c9bcb Mon Sep 17 00:00:00 2001 From: Alexey Naumov Date: Sun, 19 Sep 2021 10:38:55 +0300 Subject: [PATCH 82/99] Add system popup views to the readiness --- readiness.md | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/readiness.md b/readiness.md index 835423b9..c3e086ce 100644 --- a/readiness.md +++ b/readiness.md @@ -17,6 +17,8 @@ Visit [this discussion](https://github.com/nalexn/ViewInspector/discussions/60) | Status | View | Inspectable Attributes | |:---:|---|---| +|:white_check_mark:| ActionSheet | `title view`, `message view`, `button(_ index: Int)`, `dismiss()` | +|:white_check_mark:| Alert | `title view`, `message view`, `primaryButton`, `secondaryButton`, `dismiss()` | |:white_check_mark:| AngularGradient | `gradient: Gradient`, `center: UnitPoint`, `startAngle: Angle`, `endAngle: Angle` | |:white_check_mark:| AnyView | `contained view` | |:white_check_mark:| Button | `label view`, `tap()` | @@ -32,7 +34,7 @@ Visit [this discussion](https://github.com/nalexn/ViewInspector/discussions/60) |:white_check_mark:| UIViewRepresentable | `uiView: UIView` | |:white_check_mark:| UIViewControllerRepresentable | `viewController: UIViewController` | |:white_check_mark:| DatePicker | `label view`, `select(date: Date)` | -|:white_check_mark:| DisclosureGroup | `label view`, `content view`, `isExpanded: Bool`, `expand()`, `collapse()` | +|:white_check_mark:| DisclosureGroup | `contained view`, `label view`, `isExpanded: Bool`, `expand()`, `collapse()` | |:white_check_mark:| Divider | | |:white_check_mark:| EditButton | `editMode: Binding?` | |:white_check_mark:| EmptyView | | @@ -40,6 +42,7 @@ Visit [this discussion](https://github.com/nalexn/ViewInspector/discussions/60) |:white_check_mark:| Font (*) | `size: CGFloat`, `isFixedSize: Bool`, `name: String`, `weight: Font.Weight`, `design: Font.Design`, `style: Font.TextStyle` | |:white_check_mark:| ForEach | `contained view`, `callOnDelete`, `callOnMove`, `callOnInsert` | |:white_check_mark:| Form | `contained view` | +|:white_check_mark:| FullScreenCover | `dismiss()` | |:white_check_mark:| GeometryReader | `contained view` | |:white_check_mark:| Group | `contained view` | |:white_check_mark:| GroupBox | `contained view`, `label view` | @@ -70,7 +73,7 @@ Visit [this discussion](https://github.com/nalexn/ViewInspector/discussions/60) |:white_check_mark:| OutlineGroup | `leaf view`, `source data` | |:white_check_mark:| PasteButton | `supportedTypes: [String]`| |:white_check_mark:| Picker | `contained view`, `label view`, `select(value: Hashable)` | -|:white_check_mark:| Popover | `content view`, `attachmentAnchor: PopoverAttachmentAnchor`, `arrowEdge: Edge`, `isPresented: Bool`, `dismiss()` | +|:white_check_mark:| Popover | `contained view`, `attachmentAnchor: PopoverAttachmentAnchor`, `arrowEdge: Edge`, `dismiss()` | |:white_check_mark:| PrimitiveButtonStyleConfiguration.Label | | |:white_check_mark:| ProgressView | `label view`, `currentValueLabel view`, `fractionCompleted: Double?`, `progress: Progress` | |:white_check_mark:| ProgressViewStyleConfiguration.CurrentValueLabel | | @@ -83,6 +86,7 @@ Visit [this discussion](https://github.com/nalexn/ViewInspector/discussions/60) |:white_check_mark:| Section | `contained view`, `header view`, `footer view` | |:white_check_mark:| SecureField | `label view`, `callOnCommit()`, `input: String`, `setInput(_: String)` | |:white_check_mark:| Shape | `func path(in rect: CGRect) -> Path`, `inset: CGFloat`, `offset: CGSize`, `scale: (x: CGFloat, y: CGFloat, anchor: UnitPoint)`, `rotation: (angle: Angle, anchor: UnitPoint)`, `transform: CGAffineTransform`, `size: CGSize`, `strokeStyle: StrokeStyle`, `trim: (from: CGFloat, to: CGFloat)`, `fillShapeStyle() -> ShapeStyle`, `fillStyle: FillStyle` | +|:white_check_mark:| Sheet | `dismiss()` | |:technologist:| SignInWithAppleButton | | |:white_check_mark:| Slider | `label view`, `callOnEditingChanged()`, `value: Double`, `setValue(_: Double)` | |:white_check_mark:| Spacer | `minLength: CGFloat?` | @@ -125,18 +129,19 @@ Visit [this discussion](https://github.com/nalexn/ViewInspector/discussions/60) |:technologist:| `@UIApplicationDelegateAdaptor` | ## Gestures - | Status | Modifier | - |:---:|---| - |:white_check_mark:|`AnyGesture`| - |:white_check_mark:|`DragGesture`| - |:white_check_mark:|`ExclusiveGesture`| - |:white_check_mark:|`GestureStateGesture`| - |:white_check_mark:|`LongPressGesture`| - |:white_check_mark:|`MagnificationGesture`| - |:white_check_mark:|`RotationGesture`| - |:white_check_mark:|`SequenceGesture`| - |:white_check_mark:|`SimultaneousGesture`| - |:white_check_mark:|`TapGesture`| + +| Status | Modifier | +|:---:|---| +|:white_check_mark:| `AnyGesture` | +|:white_check_mark:| `DragGesture` | +|:white_check_mark:| `ExclusiveGesture` | +|:white_check_mark:| `GestureStateGesture` | +|:white_check_mark:| `LongPressGesture` | +|:white_check_mark:| `MagnificationGesture` | +|:white_check_mark:| `RotationGesture` | +|:white_check_mark:| `SequenceGesture` | +|:white_check_mark:| `SimultaneousGesture` | +|:white_check_mark:| `TapGesture` | ## View Modifiers From 96b88324c4710856d99440add66c02abc02c0053 Mon Sep 17 00:00:00 2001 From: Alexey Naumov Date: Sun, 19 Sep 2021 13:08:56 +0300 Subject: [PATCH 83/99] Support new alert API in iOS 15 --- Sources/ViewInspector/Inspector.swift | 39 +++--- Sources/ViewInspector/SwiftUI/Alert.swift | 129 ++++++++++++++---- .../SwiftUI/AlertTests.swift | 40 +++++- readiness.md | 2 +- 4 files changed, 166 insertions(+), 44 deletions(-) diff --git a/Sources/ViewInspector/Inspector.swift b/Sources/ViewInspector/Inspector.swift index 5a9a2563..c673bb3a 100644 --- a/Sources/ViewInspector/Inspector.swift +++ b/Sources/ViewInspector/Inspector.swift @@ -213,25 +213,30 @@ internal extension Inspector { } static func guardType(value: Any, namespacedPrefixes: [String], inspectionCall: String) throws { - guard let firstPrefix = namespacedPrefixes.first - else { return } - let typeWithParams = typeName(type: type(of: value)) - let withGenericParams = firstPrefix.contains("<") - let typePrefix = typeName(type: type(of: value), namespaced: true, prefixOnly: !withGenericParams) - if typePrefix == "SwiftUI.EnvironmentReaderView" { - if typeWithParams.contains("NavigationBarItemsKey") { - throw InspectionError.notSupported( - """ - Please insert '.navigationBarItems()' before \(inspectionCall) \ - for unwrapping the underlying view hierarchy. - """) - } else if typeWithParams.contains("_AnchorWritingModifier") { - throw InspectionError.notSupported( - "Unwrapping the view under popover is not supported on iOS 14.0 and 14.1") + + for prefix in namespacedPrefixes { + let withGenericParams = prefix.contains("<") + let typePrefix = typeName(type: type(of: value), namespaced: true, prefixOnly: !withGenericParams) + if typePrefix == "SwiftUI.EnvironmentReaderView" { + let typeWithParams = typeName(type: type(of: value)) + if typeWithParams.contains("NavigationBarItemsKey") { + throw InspectionError.notSupported( + """ + Please insert '.navigationBarItems()' before \(inspectionCall) \ + for unwrapping the underlying view hierarchy. + """) + } else if typeWithParams.contains("_AnchorWritingModifier") { + throw InspectionError.notSupported( + "Unwrapping the view under popover is not supported on iOS 14.0 and 14.1") + } + } + if namespacedPrefixes.contains(typePrefix) { + return } } - guard namespacedPrefixes.contains(typePrefix) else { - throw InspectionError.typeMismatch(factual: typePrefix, expected: firstPrefix) + if let prefix = namespacedPrefixes.first { + let typePrefix = typeName(type: type(of: value), namespaced: true) + throw InspectionError.typeMismatch(factual: typePrefix, expected: prefix) } } } diff --git a/Sources/ViewInspector/SwiftUI/Alert.swift b/Sources/ViewInspector/SwiftUI/Alert.swift index b2c36bff..61141225 100644 --- a/Sources/ViewInspector/SwiftUI/Alert.swift +++ b/Sources/ViewInspector/SwiftUI/Alert.swift @@ -7,7 +7,10 @@ public extension ViewType { struct Alert: KnownViewType { public static var typePrefix: String = ViewType.PopupContainer.typePrefix - public static var namespacedPrefixes: [String] { [typePrefix] } + static var typePrefixIOS15: String = "AlertModifier" + public static var namespacedPrefixes: [String] { + [typePrefix, "SwiftUI." + typePrefixIOS15] + } public static func inspectionCall(typeName: String) -> String { return "alert(\(ViewType.indexPlaceholder))" } @@ -28,12 +31,21 @@ public extension InspectableView { internal extension Content { func alert(parent: UnwrappedView, index: Int?) throws -> InspectableView { - return try popup(parent: parent, index: index, - modifierPredicate: isAlertPresenter(modifier:), - standardPredicate: standardAlertModifier) + do { + return try popup(parent: parent, index: index, + modifierPredicate: isDeprecatedAlertPresenter(modifier:), + standardPredicate: deprecatedStandardAlertModifier) + } catch { + if #available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *), + let alert = try? alertIOS15(parent: parent, index: index) { + return alert + } else { + throw error + } + } } - func standardAlertModifier(_ name: String = "Alert") throws -> Any { + private func deprecatedStandardAlertModifier(_ name: String = "Alert") throws -> Any { return try self.modifier({ $0.modifierType == "IdentifiedPreferenceTransformModifier" || $0.modifierType.contains("AlertTransformModifier") @@ -42,7 +54,10 @@ internal extension Content { func alertsForSearch() -> [ViewSearch.ModifierIdentity] { let count = medium.viewModifiers - .filter(isAlertPresenter(modifier:)) + .filter { modifier in + isDeprecatedAlertPresenter(modifier: modifier) + || isAlertIOS15(modifier: modifier) + } .count return Array(0.. Bool { + private func isDeprecatedAlertPresenter(modifier: Any) -> Bool { let modifier = try? Inspector.attribute( label: "modifier", value: modifier, type: BasePopupPresenter.self) return modifier?.isAlertPresenter == true } + + // MARK: - iOS 15 + + var isIOS15Modifier: Bool { + let type = ViewType.PopupContainer.self + return (try? Inspector.cast(value: view, type: type)) == nil + } + + @available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) + func alertIOS15(parent: UnwrappedView, index: Int?) throws -> InspectableView { + let modifier = try self.modifierAttribute( + modifierLookup: isAlertIOS15(modifier:), path: "modifier", + type: Any.self, call: "alert", index: index ?? 0) + let medium = self.medium.resettingViewModifiers() + let content = Content(modifier, medium: medium) + let call = ViewType.inspectionCall( + base: ViewType.Alert.inspectionCall(typeName: ""), index: index) + let view = try InspectableView( + content, parent: parent, call: call, index: index) + guard try view.isPresentedBinding().wrappedValue else { + throw InspectionError.viewNotFound(parent: "Alert") + } + return view + } + + private func isAlertIOS15(modifier: Any) -> Bool { + guard let modifier = modifier as? ModifierNameProvider + else { return false } + return modifier.modifierType.contains(ViewType.Alert.typePrefixIOS15) + } } // MARK: - Custom Attributes @@ -68,9 +113,9 @@ public extension InspectableView where View == ViewType.Alert { .asInspectableView(ofType: ViewType.Text.self) } - func message() throws -> InspectableView { + func message() throws -> InspectableView { return try View.supplementaryChildren(self).element(at: 1) - .asInspectableView(ofType: ViewType.Text.self) + .asInspectableView(ofType: ViewType.ClassifiedView.self) } func primaryButton() throws -> InspectableView { @@ -84,9 +129,27 @@ public extension InspectableView where View == ViewType.Alert { } func dismiss() throws { - let container = try Inspector.cast( - value: content.view, type: ViewType.PopupContainer.self) - container.presenter.dismissPopup() + do { + let container = try Inspector.cast( + value: content.view, type: ViewType.PopupContainer.self) + container.presenter.dismissPopup() + } catch { + if #available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *), + let binding = try? isPresentedBinding() { + binding.wrappedValue = false + } else { + throw error + } + } + } +} + +@available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) +public extension InspectableView where View == ViewType.Alert { + + func actions() throws -> InspectableView { + return try View.supplementaryChildren(self).element(at: 2) + .asInspectableView(ofType: ViewType.ClassifiedView.self) } } @@ -95,24 +158,36 @@ public extension InspectableView where View == ViewType.Alert { @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) extension ViewType.Alert: SupplementaryChildren { static func supplementaryChildren(_ parent: UnwrappedView) throws -> LazyGroup { - return .init(count: 4) { index in + let iOS15Modifier = parent.content.isIOS15Modifier + return .init(count: iOS15Modifier ? 3 : 4) { index in let medium = parent.content.medium.resettingViewModifiers() switch index { case 0: - let view = try Inspector.attribute(path: "popup|title", value: parent.content.view) + let path = iOS15Modifier ? "title" : "popup|title" + let view = try Inspector.attribute(path: path, value: parent.content.view) let content = try Inspector.unwrap(content: Content(view, medium: medium)) - return try InspectableView( - content, parent: parent, call: "title()") + return try InspectableView(content, parent: parent, call: "title()") case 1: - let maybeView = try Inspector.attribute( - path: "popup|message", value: parent.content.view, type: Text?.self) - guard let view = maybeView else { - throw InspectionError.viewNotFound(parent: "message") + let path = iOS15Modifier ? "message" : "popup|message" + do { + let view = try Inspector.attribute(path: path, value: parent.content.view) + let content = try Inspector.unwrap(content: Content(view, medium: medium)) + return try InspectableView( + content, parent: parent, call: "message()") + } catch { + if let inspError = error as? InspectionError, + case .viewNotFound = inspError { + throw InspectionError.viewNotFound(parent: "message") + } + throw error } - let content = try Inspector.unwrap(content: Content(view, medium: medium)) - return try InspectableView( - content, parent: parent, call: "message()") case 2: + if iOS15Modifier { + let view = try Inspector.attribute(path: "actions", value: parent.content.view) + let content = try Inspector.unwrap(content: Content(view, medium: medium)) + return try InspectableView( + content, parent: parent, call: "actions()") + } let view = try Inspector.attribute(path: "popup|primaryButton", value: parent.content.view) let content = try Inspector.unwrap(content: Content(view, medium: medium)) return try InspectableView( @@ -199,3 +274,11 @@ public extension InspectableView where View == ViewType.AlertButton { callback() } } + +@available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) +private extension InspectableView where View == ViewType.Alert { + func isPresentedBinding() throws -> Binding { + return try Inspector.attribute( + label: "isPresented", value: content.view, type: Binding.self) + } +} diff --git a/Tests/ViewInspectorTests/SwiftUI/AlertTests.swift b/Tests/ViewInspectorTests/SwiftUI/AlertTests.swift index aef2ff5a..152c72ee 100644 --- a/Tests/ViewInspectorTests/SwiftUI/AlertTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/AlertTests.swift @@ -3,7 +3,7 @@ import SwiftUI @testable import ViewInspector @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) -final class AlertTests: XCTestCase { +final class DeprecatedAlertTests: XCTestCase { func testInspectionNotBlocked() throws { let binding = Binding(wrappedValue: true) @@ -58,7 +58,7 @@ final class AlertTests: XCTestCase { Alert(title: Text("abc"), message: Text("123"), dismissButton: nil) } let message = try sut.inspect().emptyView().alert().message() - XCTAssertEqual(try message.string(), "123") + XCTAssertEqual(try message.text().string(), "123") XCTAssertEqual(message.pathToRoot, "emptyView().alert().message()") } @@ -228,7 +228,7 @@ final class AlertTests: XCTestCase { XCTAssertEqual(try sut.inspect().find(text: "title_1").pathToRoot, "view(AlertFindTestView.self).hStack().emptyView(0).alert().title()") XCTAssertEqual(try sut.inspect().find(text: "message_1").pathToRoot, - "view(AlertFindTestView.self).hStack().emptyView(0).alert().message()") + "view(AlertFindTestView.self).hStack().emptyView(0).alert().message().text()") XCTAssertEqual(try sut.inspect().find(text: "primary_1").pathToRoot, "view(AlertFindTestView.self).hStack().emptyView(0).alert().primaryButton().labelView()") XCTAssertEqual(try sut.inspect().find(text: "secondary_1").pathToRoot, @@ -246,6 +246,40 @@ final class AlertTests: XCTestCase { "view(AlertFindTestView.self).hStack().emptyView(0).alert(1).primaryButton().labelView()") } } + +@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) +final class AlertIOS15Tests: XCTestCase { + + @available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) + private func sutIOS15(binding: Binding) -> some View { + let param: String? = "abc" + return EmptyView().alert("Title", isPresented: binding, presenting: param, + actions: { param in + Button(role: .destructive) { } label: { Text(param) } + Button("Second") { } + }, message: { param in + HStack { Text("Message: \(param)") } + }) + } + + func testAlertInspectioniOS15() throws { + guard #available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) else { return } + let binding = Binding(wrappedValue: true) + let sut = sutIOS15(binding: binding) + let alert = try sut.inspect().alert() + XCTAssertEqual(try alert.title().string(), "Title") + let message = try alert.message().hStack().text(0) + XCTAssertEqual(try message.string(), "Message: abc") + XCTAssertEqual(message.pathToRoot, + "alert().message().hStack().text(0)") + let secondButtonLabel = try alert.actions().button(1).labelView().text() + XCTAssertEqual(try secondButtonLabel.string(), "Second") + XCTAssertEqual(secondButtonLabel.pathToRoot, + "alert().actions().button(1).labelView().text()") + let searchLabel = try sut.inspect().find(button: "Second") + XCTAssertEqual(searchLabel.pathToRoot, secondButtonLabel.pathToRoot) + } +} extension Int: Identifiable { public var id: Int { self } diff --git a/readiness.md b/readiness.md index c3e086ce..9bad9341 100644 --- a/readiness.md +++ b/readiness.md @@ -18,7 +18,7 @@ Visit [this discussion](https://github.com/nalexn/ViewInspector/discussions/60) | Status | View | Inspectable Attributes | |:---:|---|---| |:white_check_mark:| ActionSheet | `title view`, `message view`, `button(_ index: Int)`, `dismiss()` | -|:white_check_mark:| Alert | `title view`, `message view`, `primaryButton`, `secondaryButton`, `dismiss()` | +|:white_check_mark:| Alert | `title view`, `message view`, `actions view`, `primaryButton`, `secondaryButton`, `dismiss()` | |:white_check_mark:| AngularGradient | `gradient: Gradient`, `center: UnitPoint`, `startAngle: Angle`, `endAngle: Angle` | |:white_check_mark:| AnyView | `contained view` | |:white_check_mark:| Button | `label view`, `tap()` | From 890d394ffb7aa1854240144d471868193b60141e Mon Sep 17 00:00:00 2001 From: Alexey Naumov Date: Sun, 19 Sep 2021 13:31:40 +0300 Subject: [PATCH 84/99] Support button role inspection --- Sources/ViewInspector/SwiftUI/Button.swift | 6 ++++++ Tests/ViewInspectorTests/SwiftUI/ButtonTests.swift | 10 ++++++++++ readiness.md | 2 +- 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/Sources/ViewInspector/SwiftUI/Button.swift b/Sources/ViewInspector/SwiftUI/Button.swift index 0e0bfebb..7dfad8df 100644 --- a/Sources/ViewInspector/SwiftUI/Button.swift +++ b/Sources/ViewInspector/SwiftUI/Button.swift @@ -58,6 +58,12 @@ public extension InspectableView where View == ViewType.Button { .attribute(label: "action", value: content.view, type: Callback.self) callback() } + + @available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) + func role() throws -> ButtonRole? { + return try Inspector.attribute( + label: "role", value: content.view, type: ButtonRole?.self) + } } // MARK: - Global View Modifiers diff --git a/Tests/ViewInspectorTests/SwiftUI/ButtonTests.swift b/Tests/ViewInspectorTests/SwiftUI/ButtonTests.swift index abba27ea..3449b8d5 100644 --- a/Tests/ViewInspectorTests/SwiftUI/ButtonTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/ButtonTests.swift @@ -71,6 +71,16 @@ final class ButtonTests: XCTestCase { "Button is unresponsive: it is disabled") wait(for: [exp], timeout: 0.5) } + + func testButtonRole() throws { + guard #available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) else { return } + let sut1 = Button(role: .cancel, action: { }, label: { Text("") }) + let sut2 = Button(role: .destructive, action: { }, label: { Text("") }) + let sut3 = Button(action: { }, label: { Text("") }) + XCTAssertEqual(try sut1.inspect().button().role(), .cancel) + XCTAssertEqual(try sut2.inspect().button().role(), .destructive) + XCTAssertNil(try sut3.inspect().button().role()) + } } // MARK: - View Modifiers diff --git a/readiness.md b/readiness.md index 9bad9341..2a7c7009 100644 --- a/readiness.md +++ b/readiness.md @@ -21,7 +21,7 @@ Visit [this discussion](https://github.com/nalexn/ViewInspector/discussions/60) |:white_check_mark:| Alert | `title view`, `message view`, `actions view`, `primaryButton`, `secondaryButton`, `dismiss()` | |:white_check_mark:| AngularGradient | `gradient: Gradient`, `center: UnitPoint`, `startAngle: Angle`, `endAngle: Angle` | |:white_check_mark:| AnyView | `contained view` | -|:white_check_mark:| Button | `label view`, `tap()` | +|:white_check_mark:| Button | `label view`, `role: ButtonRole?`, `tap()` | |:white_check_mark:| ButtonStyleConfiguration.Label | | |:technologist:| CameraView | | |:white_check_mark:| Color | `value: Color`, `rgba: (Float, Float, Float, Float)`, `name: String` | From 7090c9345f8b64ac5db08eac20fae7711e67bf24 Mon Sep 17 00:00:00 2001 From: Alexey Naumov Date: Sun, 19 Sep 2021 14:58:45 +0300 Subject: [PATCH 85/99] Fix searching for new alert API --- Sources/ViewInspector/ViewSearchIndex.swift | 19 +++++++++++++------ .../SwiftUI/AlertTests.swift | 3 ++- .../SwiftUI/ConfirmationDialogTests.swift | 9 +++++---- 3 files changed, 20 insertions(+), 11 deletions(-) diff --git a/Sources/ViewInspector/ViewSearchIndex.swift b/Sources/ViewInspector/ViewSearchIndex.swift index 9c2c0c43..81b6736a 100644 --- a/Sources/ViewInspector/ViewSearchIndex.swift +++ b/Sources/ViewInspector/ViewSearchIndex.swift @@ -7,7 +7,8 @@ internal extension ViewSearch { private static var index: [String: [ViewIdentity]] = { let identities: [ViewIdentity] = [ - .init(ViewType.ActionSheet.self), .init(ViewType.Alert.self), .init(ViewType.AlertButton.self), + .init(ViewType.ActionSheet.self), + .init(ViewType.Alert.self), .init(ViewType.AlertButton.self), .init(ViewType.AngularGradient.self), .init(ViewType.AnyView.self), .init(ViewType.Button.self), .init(ViewType.Color.self), .init(ViewType.ColorPicker.self), @@ -52,10 +53,15 @@ internal extension ViewSearch { ] var index = [String: [ViewIdentity]](minimumCapacity: 26) // alphabet identities.forEach { identity in - let letter = String(identity.viewType.typePrefix.prefix(1)) - var array = index[letter] ?? [] - array.append(identity) - index[letter] = array + let names = identity.viewType.namespacedPrefixes + .compactMap { $0.components(separatedBy: ".").last } + + [identity.viewType.typePrefix] + let letters = Set(names).map { String($0.prefix(1)) } + letters.forEach { letter in + var array = index[letter] ?? [] + array.append(identity) + index[letter] = array + } } return index }() @@ -158,7 +164,8 @@ internal extension ViewSearch { let descendants = try supplementary(parent) return .init(count: descendants.count) { index -> UnwrappedView in var view = try descendants.element(at: index) - if !(view is InspectableView) { + if Inspector.isTupleView(view.content.view) || + !(view is InspectableView) { view.isUnwrappedSupplementaryChild = true return view } diff --git a/Tests/ViewInspectorTests/SwiftUI/AlertTests.swift b/Tests/ViewInspectorTests/SwiftUI/AlertTests.swift index 152c72ee..a4e342f3 100644 --- a/Tests/ViewInspectorTests/SwiftUI/AlertTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/AlertTests.swift @@ -277,7 +277,8 @@ final class AlertIOS15Tests: XCTestCase { XCTAssertEqual(secondButtonLabel.pathToRoot, "alert().actions().button(1).labelView().text()") let searchLabel = try sut.inspect().find(button: "Second") - XCTAssertEqual(searchLabel.pathToRoot, secondButtonLabel.pathToRoot) + XCTAssertEqual(searchLabel.pathToRoot, + "emptyView().alert().actions().button(1)") } } diff --git a/Tests/ViewInspectorTests/SwiftUI/ConfirmationDialogTests.swift b/Tests/ViewInspectorTests/SwiftUI/ConfirmationDialogTests.swift index e67d9b2a..ce47dd2a 100644 --- a/Tests/ViewInspectorTests/SwiftUI/ConfirmationDialogTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/ConfirmationDialogTests.swift @@ -105,19 +105,20 @@ final class ConfirmationDialogTests: XCTestCase { EmptyView() Text("") .confirmationDialog(Text("1"), isPresented: binding, - actions: { EmptyView() }, message: { Text("2") }) + actions: { EmptyView() }, + message: { EmptyView(); Text("2") }) .padding() .confirmationDialog(Text("3"), isPresented: binding, - actions: { Text("4") }) + actions: { EmptyView(); Text("4") }) } XCTAssertEqual(try sut.inspect().find(text: "1").pathToRoot, "group().text(1).confirmationDialog().title()") XCTAssertEqual(try sut.inspect().find(text: "2").pathToRoot, - "group().text(1).confirmationDialog().message().text()") + "group().text(1).confirmationDialog().message().text(1)") XCTAssertEqual(try sut.inspect().find(text: "3").pathToRoot, "group().text(1).confirmationDialog(1).title()") XCTAssertEqual(try sut.inspect().find(text: "4").pathToRoot, - "group().text(1).confirmationDialog(1).actions().text()") + "group().text(1).confirmationDialog(1).actions().text(1)") } } #endif From 820917db95bd6526e1e297055efc284cb9ba3e84 Mon Sep 17 00:00:00 2001 From: Alexey Naumov Date: Sun, 19 Sep 2021 15:02:56 +0300 Subject: [PATCH 86/99] Disable functions not available for macOS prior 12 --- Sources/ViewInspector/SwiftUI/Button.swift | 2 ++ Tests/ViewInspectorTests/SwiftUI/AlertTests.swift | 2 ++ Tests/ViewInspectorTests/SwiftUI/ButtonTests.swift | 2 ++ 3 files changed, 6 insertions(+) diff --git a/Sources/ViewInspector/SwiftUI/Button.swift b/Sources/ViewInspector/SwiftUI/Button.swift index 7dfad8df..f1e0714f 100644 --- a/Sources/ViewInspector/SwiftUI/Button.swift +++ b/Sources/ViewInspector/SwiftUI/Button.swift @@ -59,11 +59,13 @@ public extension InspectableView where View == ViewType.Button { callback() } + #if !os(macOS) && !targetEnvironment(macCatalyst) // requires macOS SDK 12.0 @available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) func role() throws -> ButtonRole? { return try Inspector.attribute( label: "role", value: content.view, type: ButtonRole?.self) } + #endif } // MARK: - Global View Modifiers diff --git a/Tests/ViewInspectorTests/SwiftUI/AlertTests.swift b/Tests/ViewInspectorTests/SwiftUI/AlertTests.swift index a4e342f3..12e17671 100644 --- a/Tests/ViewInspectorTests/SwiftUI/AlertTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/AlertTests.swift @@ -247,6 +247,7 @@ final class DeprecatedAlertTests: XCTestCase { } } +#if !os(macOS) && !targetEnvironment(macCatalyst) // requires macOS SDK 12.0 @available(iOS 13.0, macOS 10.15, tvOS 13.0, *) final class AlertIOS15Tests: XCTestCase { @@ -281,6 +282,7 @@ final class AlertIOS15Tests: XCTestCase { "emptyView().alert().actions().button(1)") } } +#endif extension Int: Identifiable { public var id: Int { self } diff --git a/Tests/ViewInspectorTests/SwiftUI/ButtonTests.swift b/Tests/ViewInspectorTests/SwiftUI/ButtonTests.swift index 3449b8d5..2bfe3097 100644 --- a/Tests/ViewInspectorTests/SwiftUI/ButtonTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/ButtonTests.swift @@ -72,6 +72,7 @@ final class ButtonTests: XCTestCase { wait(for: [exp], timeout: 0.5) } + #if !os(macOS) && !targetEnvironment(macCatalyst) // requires macOS SDK 12.0 func testButtonRole() throws { guard #available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) else { return } let sut1 = Button(role: .cancel, action: { }, label: { Text("") }) @@ -81,6 +82,7 @@ final class ButtonTests: XCTestCase { XCTAssertEqual(try sut2.inspect().button().role(), .destructive) XCTAssertNil(try sut3.inspect().button().role()) } + #endif } // MARK: - View Modifiers From c0b6ef489b2be8ca46153bba35a1a7d3a128378b Mon Sep 17 00:00:00 2001 From: Alexey Naumov Date: Sun, 19 Sep 2021 16:35:42 +0300 Subject: [PATCH 87/99] Remove explicit initializers for FullScreenCover, Sheet and Popover --- .../SwiftUI/FullScreenCoverTests.swift | 17 +++---------- .../SwiftUI/PopoverTests.swift | 24 ++----------------- .../SwiftUI/SheetTests.swift | 16 ++----------- 3 files changed, 7 insertions(+), 50 deletions(-) diff --git a/Tests/ViewInspectorTests/SwiftUI/FullScreenCoverTests.swift b/Tests/ViewInspectorTests/SwiftUI/FullScreenCoverTests.swift index ac331d16..f371db34 100644 --- a/Tests/ViewInspectorTests/SwiftUI/FullScreenCoverTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/FullScreenCoverTests.swift @@ -160,14 +160,15 @@ private extension View { @ViewBuilder content: @escaping () -> FullScreenCover ) -> some View where FullScreenCover: View { return self.modifier(InspectableFullScreenCover( - isPresented: isPresented, onDismiss: onDismiss, content: content)) + isPresented: isPresented, onDismiss: onDismiss, popupBuilder: content)) } func fullScreenCover2(item: Binding, onDismiss: (() -> Void)? = nil, content: @escaping (Item) -> FullScreenCover ) -> some View where Item: Identifiable, FullScreenCover: View { - return self.modifier(InspectableFullScreenCoverWithItem(item: item, onDismiss: onDismiss, content: content)) + return self.modifier(InspectableFullScreenCoverWithItem( + item: item, onDismiss: onDismiss, popupBuilder: content)) } } @@ -180,12 +181,6 @@ where FullScreenCover: View { let onDismiss: (() -> Void)? let popupBuilder: () -> FullScreenCover - init(isPresented: Binding, onDismiss: (() -> Void)?, content: @escaping () -> FullScreenCover) { - self.isPresented = isPresented - self.onDismiss = onDismiss - self.popupBuilder = content - } - func body(content: Self.Content) -> some View { content.fullScreenCover(isPresented: isPresented, onDismiss: onDismiss, content: popupBuilder) } @@ -200,12 +195,6 @@ where Item: Identifiable, FullScreenCover: View { let onDismiss: (() -> Void)? let popupBuilder: (Item) -> FullScreenCover - init(item: Binding, onDismiss: (() -> Void)?, content: @escaping (Item) -> FullScreenCover) { - self.item = item - self.onDismiss = onDismiss - self.popupBuilder = content - } - func body(content: Self.Content) -> some View { content.fullScreenCover(item: item, onDismiss: onDismiss, content: popupBuilder) } diff --git a/Tests/ViewInspectorTests/SwiftUI/PopoverTests.swift b/Tests/ViewInspectorTests/SwiftUI/PopoverTests.swift index 2fb8ee2e..08f5715e 100644 --- a/Tests/ViewInspectorTests/SwiftUI/PopoverTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/PopoverTests.swift @@ -217,7 +217,7 @@ private extension View { isPresented: isPresented, attachmentAnchor: attachmentAnchor, arrowEdge: arrowEdge, - content: content)) + popupBuilder: content)) } func popover2(item: Binding, @@ -229,7 +229,7 @@ private extension View { item: item, attachmentAnchor: attachmentAnchor, arrowEdge: arrowEdge, - content: content)) + popupBuilder: content)) } } @@ -242,16 +242,6 @@ private struct InspectablePopover: ViewModifier, PopupPresenter where P let popupBuilder: () -> Popover let onDismiss: (() -> Void)? = nil - init(isPresented: Binding, - attachmentAnchor: PopoverAttachmentAnchor, - arrowEdge: Edge, - content: @escaping () -> Popover) { - self.isPresented = isPresented - self.attachmentAnchor = attachmentAnchor - self.arrowEdge = arrowEdge - self.popupBuilder = content - } - func body(content: Self.Content) -> some View { content.popover(isPresented: isPresented, attachmentAnchor: attachmentAnchor, arrowEdge: arrowEdge, content: popupBuilder) @@ -268,16 +258,6 @@ where Item: Identifiable, Popover: View { let popupBuilder: (Item) -> Popover let onDismiss: (() -> Void)? = nil - init(item: Binding, - attachmentAnchor: PopoverAttachmentAnchor, - arrowEdge: Edge, - content: @escaping (Item) -> Popover) { - self.item = item - self.attachmentAnchor = attachmentAnchor - self.arrowEdge = arrowEdge - self.popupBuilder = content - } - func body(content: Self.Content) -> some View { content.popover(item: item, attachmentAnchor: attachmentAnchor, arrowEdge: arrowEdge, content: popupBuilder) diff --git a/Tests/ViewInspectorTests/SwiftUI/SheetTests.swift b/Tests/ViewInspectorTests/SwiftUI/SheetTests.swift index fec5fee7..cefb6e13 100644 --- a/Tests/ViewInspectorTests/SwiftUI/SheetTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/SheetTests.swift @@ -139,14 +139,14 @@ private extension View { onDismiss: (() -> Void)? = nil, @ViewBuilder content: @escaping () -> Sheet ) -> some View where Sheet: View { - return self.modifier(InspectableSheet(isPresented: isPresented, onDismiss: onDismiss, content: content)) + return self.modifier(InspectableSheet(isPresented: isPresented, onDismiss: onDismiss, popupBuilder: content)) } func sheet2(item: Binding, onDismiss: (() -> Void)? = nil, content: @escaping (Item) -> Sheet ) -> some View where Item: Identifiable, Sheet: View { - return self.modifier(InspectableSheetWithItem(item: item, onDismiss: onDismiss, content: content)) + return self.modifier(InspectableSheetWithItem(item: item, onDismiss: onDismiss, popupBuilder: content)) } } @@ -157,12 +157,6 @@ private struct InspectableSheet: ViewModifier, PopupPresenter where Sheet let onDismiss: (() -> Void)? let popupBuilder: () -> Sheet - init(isPresented: Binding, onDismiss: (() -> Void)?, content: @escaping () -> Sheet) { - self.isPresented = isPresented - self.onDismiss = onDismiss - self.popupBuilder = content - } - func body(content: Self.Content) -> some View { content.sheet(isPresented: isPresented, onDismiss: onDismiss, content: popupBuilder) } @@ -176,12 +170,6 @@ where Item: Identifiable, Sheet: View { let onDismiss: (() -> Void)? let popupBuilder: (Item) -> Sheet - init(item: Binding, onDismiss: (() -> Void)?, content: @escaping (Item) -> Sheet) { - self.item = item - self.onDismiss = onDismiss - self.popupBuilder = content - } - func body(content: Self.Content) -> some View { content.sheet(item: item, onDismiss: onDismiss, content: popupBuilder) } From 5ddcdde3ec995ca8b885c8bfa57715b9223fdccb Mon Sep 17 00:00:00 2001 From: Alexey Naumov Date: Sun, 19 Sep 2021 17:04:55 +0300 Subject: [PATCH 88/99] Make popover inspectable for iOS 13, fix tests --- Sources/ViewInspector/SwiftUI/Popover.swift | 19 ++++++++++++++++--- Sources/ViewInspector/ViewSearch.swift | 2 +- Sources/ViewInspector/ViewSearchIndex.swift | 2 +- .../SwiftUI/PopoverTests.swift | 12 ------------ 4 files changed, 18 insertions(+), 17 deletions(-) diff --git a/Sources/ViewInspector/SwiftUI/Popover.swift b/Sources/ViewInspector/SwiftUI/Popover.swift index d86a932b..57354b6a 100644 --- a/Sources/ViewInspector/SwiftUI/Popover.swift +++ b/Sources/ViewInspector/SwiftUI/Popover.swift @@ -9,6 +9,13 @@ public extension ViewType { public static func inspectionCall(typeName: String) -> String { return "popover(\(ViewType.indexPlaceholder))" } + internal static var standardModifierName: String { + if #available(iOS 14.2, macOS 11.0, *) { + return "PopoverPresentationModifier" + } else { + return "_AnchorWritingModifier, Key>" + } + } } } @@ -36,7 +43,7 @@ extension ViewType.Popover: MultipleViewContent { // MARK: - Extraction -@available(iOS 14.2, macOS 11.0, *) +@available(iOS 13.0, macOS 10.15, *) @available(tvOS, unavailable) @available(watchOS, unavailable) public extension InspectableView { @@ -57,7 +64,7 @@ internal extension Content { func standardPopoverModifier(_ name: String = "Popover") throws -> Any { return try modifierAttribute( - modifierName: "PopoverPresentationModifier", path: "modifier", + modifierName: ViewType.Popover.standardModifierName, path: "modifier", type: Any.self, call: name.firstLetterLowercased) } @@ -81,7 +88,7 @@ internal extension Content { // MARK: - Custom Attributes -@available(iOS 13.0, macOS 10.15, *) +@available(iOS 14.2, macOS 11.0, *) @available(tvOS, unavailable) @available(watchOS, unavailable) public extension InspectableView where View == ViewType.Popover { @@ -99,6 +106,12 @@ public extension InspectableView where View == ViewType.Popover { return try Inspector.attribute( label: "attachmentAnchor", value: modifier, type: PopoverAttachmentAnchor.self) } +} + +@available(iOS 13.0, macOS 10.15, *) +@available(tvOS, unavailable) +@available(watchOS, unavailable) +public extension InspectableView where View == ViewType.Popover { func dismiss() throws { let container = try Inspector.cast(value: content.view, type: ViewType.PopupContainer.self) diff --git a/Sources/ViewInspector/ViewSearch.swift b/Sources/ViewInspector/ViewSearch.swift index 3f4bf0e3..0f1b88b4 100644 --- a/Sources/ViewInspector/ViewSearch.swift +++ b/Sources/ViewInspector/ViewSearch.swift @@ -347,7 +347,7 @@ private extension UnwrappedView { if name.hasPrefix("EnvironmentReaderView") { return "navigationBarItems" } - if name.hasPrefix("PopoverPresentationModifier") { + if name.hasPrefix(ViewType.Popover.standardModifierName) { return "popover" } if let inspectable = view as? Inspectable { diff --git a/Sources/ViewInspector/ViewSearchIndex.swift b/Sources/ViewInspector/ViewSearchIndex.swift index 81b6736a..c9a4d724 100644 --- a/Sources/ViewInspector/ViewSearchIndex.swift +++ b/Sources/ViewInspector/ViewSearchIndex.swift @@ -265,7 +265,7 @@ internal extension ViewSearch { .init(name: ViewType.SafeAreaInset.typePrefix, builder: { parent, index in try parent.content.safeAreaInset(parent: parent, index: index) }), - .init(name: "PopoverPresentationModifier", builder: { parent, index in + .init(name: ViewType.Popover.standardModifierName, builder: { parent, index in try parent.content.popover(parent: parent, index: index) }), .init(name: "_MaskEffect", builder: { parent, index in diff --git a/Tests/ViewInspectorTests/SwiftUI/PopoverTests.swift b/Tests/ViewInspectorTests/SwiftUI/PopoverTests.swift index 08f5715e..33b4234a 100644 --- a/Tests/ViewInspectorTests/SwiftUI/PopoverTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/PopoverTests.swift @@ -16,14 +16,12 @@ final class PopoverTests: XCTestCase { } func testInspectionErrorNoModifier() throws { - guard #available(iOS 14.2, macOS 11.0, *) else { return } let sut = EmptyView().offset() XCTAssertThrows(try sut.inspect().emptyView().popover(), "EmptyView does not have 'popover' modifier") } func testInspectionErrorCustomModifierRequired() throws { - guard #available(iOS 14.2, macOS 11.0, *) else { return } let binding = Binding(wrappedValue: true) let sut = EmptyView().popover(isPresented: binding) { Text("") } print("\(Inspector.print(sut) as AnyObject)") @@ -35,7 +33,6 @@ final class PopoverTests: XCTestCase { } func testInspectionErrorPopoverNotPresented() throws { - guard #available(iOS 14.2, macOS 11.0, *) else { return } let binding = Binding(wrappedValue: false) let sut = EmptyView().popover2(isPresented: binding) { Text("") } XCTAssertThrows(try sut.inspect().emptyView().popover(), @@ -43,7 +40,6 @@ final class PopoverTests: XCTestCase { } func testInspectionErrorPopoverWithItemNotPresented() throws { - guard #available(iOS 14.2, macOS 11.0, *) else { return } let binding = Binding(wrappedValue: nil) let sut = EmptyView().popover2(item: binding) { Text("\($0)") } XCTAssertThrows(try sut.inspect().emptyView().popover(), @@ -51,7 +47,6 @@ final class PopoverTests: XCTestCase { } func testContentInspection() throws { - guard #available(iOS 14.2, macOS 11.0, *) else { return } let binding = Binding(wrappedValue: true) let sut = EmptyView().popover2(isPresented: binding) { Text("abc") @@ -62,7 +57,6 @@ final class PopoverTests: XCTestCase { } func testContentInteraction() throws { - guard #available(iOS 14.2, macOS 11.0, *) else { return } let binding = Binding(wrappedValue: true) let sut = EmptyView().popover2(isPresented: binding) { Text("abc") @@ -75,7 +69,6 @@ final class PopoverTests: XCTestCase { } func testDismiss() throws { - guard #available(iOS 14.2, macOS 11.0, *) else { return } let binding = Binding(wrappedValue: true) let sut = EmptyView().popover2(isPresented: binding, content: { Text("") }) XCTAssertTrue(binding.wrappedValue) @@ -85,7 +78,6 @@ final class PopoverTests: XCTestCase { } func testDismissForItemVersion() throws { - guard #available(iOS 14.2, macOS 11.0, *) else { return } let binding = Binding(wrappedValue: 6) let sut = EmptyView().popover2(item: binding) { Text("\($0)") } let popover = try sut.inspect().emptyView().popover() @@ -97,7 +89,6 @@ final class PopoverTests: XCTestCase { } func testMultiplePopoversInspection() throws { - guard #available(iOS 14.2, macOS 11.0, *) else { return } let binding1 = Binding(wrappedValue: true) let binding2 = Binding(wrappedValue: true) let binding3 = Binding(wrappedValue: true) @@ -120,7 +111,6 @@ final class PopoverTests: XCTestCase { } func testFindAndPathToRoots() throws { - guard #available(iOS 14.2, macOS 11.0, *) else { return } let binding = Binding(wrappedValue: true) let sut = PopoverFindTestView(popover1: binding, popover2: binding, popover3: binding) @@ -186,7 +176,6 @@ final class PopoverDeprecatedTests: XCTestCase { @available(*, deprecated) func testContentView() throws { - guard #available(iOS 14.2, macOS 11.0, *) else { return } let binding = Binding(wrappedValue: true) let sut = EmptyView().popover2(isPresented: binding) { Text("") } let popover = try sut.inspect().emptyView().popover() @@ -196,7 +185,6 @@ final class PopoverDeprecatedTests: XCTestCase { @available(*, deprecated) func testIsPresentedAndDismiss() throws { - guard #available(iOS 14.2, macOS 11.0, *) else { return } let binding = Binding(wrappedValue: true) let sut = EmptyView().popover2(isPresented: binding) { Text("") } XCTAssertTrue(try sut.inspect().emptyView().popover().isPresented()) From 9684557ea3ee48cb79567ea910669c7a5930472a Mon Sep 17 00:00:00 2001 From: Alexey Naumov Date: Sun, 19 Sep 2021 17:06:34 +0300 Subject: [PATCH 89/99] Refresh the guide for system popup views --- guide_popups.md | 200 ++++++++++++++++++++++++++++++------------------ 1 file changed, 127 insertions(+), 73 deletions(-) diff --git a/guide_popups.md b/guide_popups.md index 67a0db6d..37ddfcba 100644 --- a/guide_popups.md +++ b/guide_popups.md @@ -10,24 +10,29 @@ These five types of views have many in common, so is their inspection mechanism. This section discusses how you still can gain the full access to the internals of these views by adding a couple of code snippets to your source code while not making ViewInspector a dependency for the main target. +*Note*: ViewInspector fully supports `confirmationDialog` inspection without any code tweaking. + ## `Alert` -Add the following snippet to your main target: +If you're using `alert` functions added in iOS 15 (those not marked as deprecated) - you're good to go. + +Otherwise, you'll need to add the following snippet to your main target: ```swift extension View { func alert2(isPresented: Binding, content: @escaping () -> Alert) -> some View { - return self.modifier(InspectableAlert(isPresented: isPresented, alertBuilder: content)) + return self.modifier(InspectableAlert(isPresented: isPresented, popupBuilder: content)) } } struct InspectableAlert: ViewModifier { let isPresented: Binding - let alertBuilder: () -> Alert + let popupBuilder: () -> Alert + let onDismiss: (() -> Void)? = nil func body(content: Self.Content) -> some View { - content.alert(isPresented: isPresented, content: alertBuilder) + content.alert(isPresented: isPresented, content: popupBuilder) } } ``` @@ -37,7 +42,7 @@ And tweak the code of your view to use `alert2` instead of `alert`. Feel free to Then, add this line in your test target scope: ```swift -extension InspectableAlert: AlertProvider { } +extension InspectableAlert: PopupPresenter { } ``` After that you'll be able to inspect the `Alert` in the tests: read the `title`, `message`, and access the buttons: @@ -65,17 +70,18 @@ Here is the corresponding snippet for the main target: ```swift extension View { func alert2(item: Binding, content: @escaping (Item) -> Alert) -> some View where Item: Identifiable { - return self.modifier(InspectableAlertWithItem(item: item, alertBuilder: content)) + return self.modifier(InspectableAlertWithItem(item: item, popupBuilder: content)) } } struct InspectableAlertWithItem: ViewModifier { let item: Binding - let alertBuilder: (Item) -> Alert + let popupBuilder: (Item) -> Alert + let onDismiss: (() -> Void)? = nil func body(content: Self.Content) -> some View { - content.alert(item: item, content: alertBuilder) + content.alert(item: item, content: popupBuilder) } } ``` @@ -83,7 +89,7 @@ struct InspectableAlertWithItem: ViewModifier { And for the test scope: ```swift -extension InspectableAlertWithItem: AlertItemProvider { } +extension InspectableAlertWithItem: ItemPopupPresenter { } ``` Feel free to add both sets to the project as needed. @@ -92,22 +98,23 @@ Feel free to add both sets to the project as needed. Just like with `Alert`, there are two APIs for showing `ActionSheet` in SwiftUI - a simple one taking a `isPresented: Binding` parameter, and a generic version taking `item: Binding` parameter. -Variant with `isPresented: Binding` - main target snippet: +#### Variant with `isPresented: Binding` - main target snippet: ```swift extension View { func actionSheet2(isPresented: Binding, content: @escaping () -> ActionSheet) -> some View { - return self.modifier(InspectableActionSheet(isPresented: isPresented, sheetBuilder: content)) + return self.modifier(InspectableActionSheet(isPresented: isPresented, popupBuilder: content)) } } struct InspectableActionSheet: ViewModifier { let isPresented: Binding - let sheetBuilder: () -> ActionSheet + let popupBuilder: () -> ActionSheet + let onDismiss: (() -> Void)? = nil func body(content: Self.Content) -> some View { - content.actionSheet(isPresented: isPresented, content: sheetBuilder) + content.actionSheet(isPresented: isPresented, content: popupBuilder) } } ``` @@ -115,25 +122,26 @@ struct InspectableActionSheet: ViewModifier { Test target: ```swift -extension InspectableActionSheet: ActionSheetProvider { } +extension InspectableActionSheet: PopupPresenter { } ``` -Variant with `item: Binding` - main target snippet: +#### Variant with `item: Binding` - main target snippet: ```swift extension View { func actionSheet2(item: Binding, content: @escaping (Item) -> ActionSheet) -> some View where Item: Identifiable { - return self.modifier(InspectableActionSheetWithItem(item: item, sheetBuilder: content)) + return self.modifier(InspectableActionSheetWithItem(item: item, popupBuilder: content)) } } struct InspectableActionSheetWithItem: ViewModifier { let item: Binding - let sheetBuilder: (Item) -> ActionSheet + let popupBuilder: (Item) -> ActionSheet + let onDismiss: (() -> Void)? = nil func body(content: Self.Content) -> some View { - content.actionSheet(item: item, content: sheetBuilder) + content.actionSheet(item: item, content: popupBuilder) } } ``` @@ -141,7 +149,7 @@ struct InspectableActionSheetWithItem: ViewModifier { Test target: ```swift -extension InspectableActionSheetWithItem: ActionSheetItemProvider { } +extension InspectableActionSheetWithItem: ItemPopupPresenter { } ``` Make sure to use `actionSheet2` in your view's body (or a different name of your choice). @@ -150,13 +158,13 @@ Make sure to use `actionSheet2` in your view's body (or a different name of your Similarly to the `Alert` and `ActionSheet`, there are two APIs for presenting the `Sheet` thus two sets of snippets to add to the project, depending on your needs. -Variant with `isPresented: Binding` - main target snippet: +#### Variant with `isPresented: Binding` - main target snippet: ```swift extension View { func sheet2(isPresented: Binding, onDismiss: (() -> Void)? = nil, @ViewBuilder content: @escaping () -> Sheet ) -> some View where Sheet: View { - return self.modifier(InspectableSheet(isPresented: isPresented, onDismiss: onDismiss, content: content)) + return self.modifier(InspectableSheet(isPresented: isPresented, onDismiss: onDismiss, popupBuilder: content)) } } @@ -164,18 +172,10 @@ struct InspectableSheet: ViewModifier where Sheet: View { let isPresented: Binding let onDismiss: (() -> Void)? - let content: () -> Sheet - let sheetBuilder: () -> Any - - init(isPresented: Binding, onDismiss: (() -> Void)?, content: @escaping () -> Sheet) { - self.isPresented = isPresented - self.onDismiss = onDismiss - self.content = content - self.sheetBuilder = { content() as Any } - } + let popupBuilder: () -> Sheet func body(content: Self.Content) -> some View { - content.sheet(isPresented: isPresented, content: self.content) + content.sheet(isPresented: isPresented, onDismiss: onDismiss, content: popupBuilder) } } ``` @@ -183,16 +183,16 @@ struct InspectableSheet: ViewModifier where Sheet: View { Test target: ```swift -extension InspectableSheet: SheetProvider { } +extension InspectableSheet: PopupPresenter { } ``` -Variant with `item: Binding` - main target snippet: +#### Variant with `item: Binding` - main target snippet: ```swift extension View { func sheet2(item: Binding, onDismiss: (() -> Void)? = nil, content: @escaping (Item) -> Sheet ) -> some View where Item: Identifiable, Sheet: View { - return self.modifier(InspectableSheetWithItem(item: item, onDismiss: onDismiss, content: content)) + return self.modifier(InspectableSheetWithItem(item: item, onDismiss: onDismiss, popupBuilder: content)) } } @@ -200,18 +200,10 @@ struct InspectableSheetWithItem: ViewModifier where Item: Identifia let item: Binding let onDismiss: (() -> Void)? - let content: (Item) -> Sheet - let sheetBuilder: (Item) -> Any - - init(item: Binding, onDismiss: (() -> Void)?, content: @escaping (Item) -> Sheet) { - self.item = item - self.onDismiss = onDismiss - self.content = content - self.sheetBuilder = { content($0) as Any } - } + let popupBuilder: (Item) -> Sheet func body(content: Self.Content) -> some View { - content.sheet(item: item, onDismiss: onDismiss, content: self.content) + content.sheet(item: item, onDismiss: onDismiss, content: popupBuilder) } } ``` @@ -219,7 +211,7 @@ struct InspectableSheetWithItem: ViewModifier where Item: Identifia Test target: ```swift -extension InspectableSheetWithItem: SheetItemProvider { } +extension InspectableSheetWithItem: ItemPopupPresenter { } ``` Don't forget that you'll need to use `sheet2` in place of `sheet` in your views. @@ -228,13 +220,13 @@ Don't forget that you'll need to use `sheet2` in place of `sheet` in your views. Similarly to the `Alert` and `Sheet`, there are two APIs for presenting the `FullScreenCover` thus two sets of snippets to add to the project, depending on your needs. -Variant with `isPresented: Binding` - main target snippet: +#### Variant with `isPresented: Binding` - main target snippet: ```swift extension View { func fullScreenCover2(isPresented: Binding, onDismiss: (() -> Void)? = nil, @ViewBuilder content: @escaping () -> FullScreenCover ) -> some View where FullScreenCover: View { - return self.modifier(InspectableFullScreenCover(isPresented: isPresented, onDismiss: onDismiss, content: content)) + return self.modifier(InspectableFullScreenCover(isPresented: isPresented, onDismiss: onDismiss, popupBuilder: content)) } } @@ -242,18 +234,10 @@ struct InspectableFullScreenCover: ViewModifier where FullScree let isPresented: Binding let onDismiss: (() -> Void)? - let content: () -> FullScreenCover - let fullScreenCoverBuilder: () -> Any - - init(isPresented: Binding, onDismiss: (() -> Void)?, content: @escaping () -> FullScreenCover) { - self.isPresented = isPresented - self.onDismiss = onDismiss - self.content = content - self.fullScreenCoverBuilder = { content() as Any } - } - + let popupBuilder: () -> FullScreenCover + func body(content: Self.Content) -> some View { - content.fullScreenCover(isPresented: isPresented, content: self.content) + content.fullScreenCover(isPresented: isPresented, onDismiss: onDismiss, content: popupBuilder) } } ``` @@ -261,16 +245,16 @@ struct InspectableFullScreenCover: ViewModifier where FullScree Test target: ```swift -extension InspectableFullScreenCover: FullScreenCoverProvider { } +extension InspectableFullScreenCover: PopupPresenter { } ``` -Variant with `item: Binding` - main target snippet: +#### Variant with `item: Binding` - main target snippet: ```swift extension View { func fullScreenCover2(item: Binding, onDismiss: (() -> Void)? = nil, content: @escaping (Item) -> FullScreenCover ) -> some View where Item: Identifiable, FullScreenCover: View { - return self.modifier(InspectableFullScreenCoverWithItem(item: item, onDismiss: onDismiss, content: content)) + return self.modifier(InspectableFullScreenCoverWithItem(item: item, onDismiss: onDismiss, popupBuilder: content)) } } @@ -278,18 +262,52 @@ struct InspectableFullScreenCoverWithItem: ViewModifier w let item: Binding let onDismiss: (() -> Void)? - let content: (Item) -> FullScreenCover - let fullScreenCoverBuilder: (Item) -> Any - - init(item: Binding, onDismiss: (() -> Void)?, content: @escaping (Item) -> FullScreenCover) { - self.item = item - self.onDismiss = onDismiss - self.content = content - self.fullScreenCoverBuilder = { content($0) as Any } + let popupBuilder: (Item) -> FullScreenCover + + func body(content: Self.Content) -> some View { + content.fullScreenCover(item: item, onDismiss: onDismiss, content: popupBuilder) } +} +``` + +Test target: + +```swift +extension InspectableFullScreenCoverWithItem: ItemPopupPresenter { } +``` + +Don't forget that you'll need to use `fullScreenCover2` in place of `fullScreenCover` in your views. + +## `Popover` + +#### Variant with `isPresented: Binding` - main target snippet: + +```swift +extension View { + func popover2(isPresented: Binding, + attachmentAnchor: PopoverAttachmentAnchor = .rect(.bounds), + arrowEdge: Edge = .top, + @ViewBuilder content: @escaping () -> Popover + ) -> some View where Popover: View { + return self.modifier(InspectablePopover( + isPresented: isPresented, + attachmentAnchor: attachmentAnchor, + arrowEdge: arrowEdge, + popupBuilder: content)) + } +} + +struct InspectablePopover: ViewModifier where Popover: View { + + let isPresented: Binding + let attachmentAnchor: PopoverAttachmentAnchor + let arrowEdge: Edge + let popupBuilder: () -> Popover + let onDismiss: (() -> Void)? = nil func body(content: Self.Content) -> some View { - content.fullScreenCover(item: item, onDismiss: onDismiss, content: self.content) + content.popover(isPresented: isPresented, attachmentAnchor: attachmentAnchor, + arrowEdge: arrowEdge, content: popupBuilder) } } ``` @@ -297,9 +315,45 @@ struct InspectableFullScreenCoverWithItem: ViewModifier w Test target: ```swift -extension InspectableFullScreenCoverWithItem: FullScreenCoverItemProvider { } +extension InspectablePopover: PopupPresenter { } ``` -Don't forget that you'll need to use `fullScreenCover2` in place of `fullScreenCover` in your views. +#### Variant with `item: Binding` - main target snippet: + +```swift +extension View { + func popover2(item: Binding, + attachmentAnchor: PopoverAttachmentAnchor = .rect(.bounds), + arrowEdge: Edge = .top, + content: @escaping (Item) -> Popover + ) -> some View where Item: Identifiable, Popover: View { + return self.modifier(InspectablePopoverWithItem( + item: item, + attachmentAnchor: attachmentAnchor, + arrowEdge: arrowEdge, + popupBuilder: content)) + } +} + +struct InspectablePopoverWithItem: ViewModifier where Item: Identifiable, Popover: View { + + let item: Binding + let attachmentAnchor: PopoverAttachmentAnchor + let arrowEdge: Edge + let popupBuilder: (Item) -> Popover + let onDismiss: (() -> Void)? = nil + + func body(content: Self.Content) -> some View { + content.popover(item: item, attachmentAnchor: attachmentAnchor, + arrowEdge: arrowEdge, content: popupBuilder) + } +} +``` + +Test target: + +```swift +extension InspectablePopoverWithItem: ItemPopupPresenter { } +``` -## `Popover` \ No newline at end of file +Don't forget that you'll need to use `popover2` in place of `popover` in your views. \ No newline at end of file From febfd5003e15dc97f0d4e257c58e3a5a41e250b9 Mon Sep 17 00:00:00 2001 From: Alexey Naumov Date: Sun, 19 Sep 2021 17:35:48 +0300 Subject: [PATCH 90/99] Update tests for iOS 13 --- .../SwiftUI/ActionSheetTests.swift | 12 ++++++++---- Tests/ViewInspectorTests/SwiftUI/AlertTests.swift | 12 ++++++++---- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/Tests/ViewInspectorTests/SwiftUI/ActionSheetTests.swift b/Tests/ViewInspectorTests/SwiftUI/ActionSheetTests.swift index 02b10dc4..f264e211 100644 --- a/Tests/ViewInspectorTests/SwiftUI/ActionSheetTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/ActionSheetTests.swift @@ -193,15 +193,19 @@ final class ActionSheetTests: XCTestCase { XCTAssertEqual(try sut.inspect().find(text: "button_1_1").pathToRoot, "view(ActionSheetFindTestView.self).hStack().emptyView(0).actionSheet().button(1).labelView()") // 2 - XCTAssertThrows(try sut.inspect().find(text: "title_2").pathToRoot, - "Search did not find a match") + let noMatchMessage: String + if #available(iOS 13.2, tvOS 13.2, macOS 10.17, *) { + noMatchMessage = "Search did not find a match" + } else { + noMatchMessage = "Search did not find a match. Possible blockers: ActionSheet, ActionSheet" + } + XCTAssertThrows(try sut.inspect().find(text: "title_2").pathToRoot, noMatchMessage) // 3 XCTAssertEqual(try sut.inspect().find(text: "title_3").pathToRoot, "view(ActionSheetFindTestView.self).hStack().emptyView(0).actionSheet(1).title()") - XCTAssertThrows(try sut.inspect().find(text: "message_3").pathToRoot, - "Search did not find a match") + XCTAssertThrows(try sut.inspect().find(text: "message_3").pathToRoot, noMatchMessage) XCTAssertEqual(try sut.inspect().find(text: "button_3_0").pathToRoot, "view(ActionSheetFindTestView.self).hStack().emptyView(0).actionSheet(1).button(0).labelView()") } diff --git a/Tests/ViewInspectorTests/SwiftUI/AlertTests.swift b/Tests/ViewInspectorTests/SwiftUI/AlertTests.swift index 12e17671..c35702dd 100644 --- a/Tests/ViewInspectorTests/SwiftUI/AlertTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/AlertTests.swift @@ -234,14 +234,18 @@ final class DeprecatedAlertTests: XCTestCase { XCTAssertEqual(try sut.inspect().find(text: "secondary_1").pathToRoot, "view(AlertFindTestView.self).hStack().emptyView(0).alert().secondaryButton().labelView()") // 2 - XCTAssertThrows(try sut.inspect().find(text: "title_2").pathToRoot, - "Search did not find a match") + let noMatchMessage: String + if #available(iOS 13.2, tvOS 13.2, macOS 10.17, *) { + noMatchMessage = "Search did not find a match" + } else { + noMatchMessage = "Search did not find a match. Possible blockers: Alert, Alert" + } + XCTAssertThrows(try sut.inspect().find(text: "title_2").pathToRoot, noMatchMessage) // 3 XCTAssertEqual(try sut.inspect().find(text: "title_3").pathToRoot, "view(AlertFindTestView.self).hStack().emptyView(0).alert(1).title()") - XCTAssertThrows(try sut.inspect().find(text: "message_3").pathToRoot, - "Search did not find a match") + XCTAssertThrows(try sut.inspect().find(text: "message_3").pathToRoot, noMatchMessage) XCTAssertEqual(try sut.inspect().find(text: "primary_3").pathToRoot, "view(AlertFindTestView.self).hStack().emptyView(0).alert(1).primaryButton().labelView()") } From 1ee271a2bb5883de6533f2a51627f0037c6da83b Mon Sep 17 00:00:00 2001 From: Alexey Naumov Date: Sun, 19 Sep 2021 17:40:28 +0300 Subject: [PATCH 91/99] Update link to the popups guide --- Sources/ViewInspector/PopupPresenter.swift | 2 +- Tests/ViewInspectorTests/SwiftUI/ActionSheetTests.swift | 2 +- Tests/ViewInspectorTests/SwiftUI/AlertTests.swift | 2 +- Tests/ViewInspectorTests/SwiftUI/FullScreenCoverTests.swift | 2 +- Tests/ViewInspectorTests/SwiftUI/PopoverTests.swift | 2 +- Tests/ViewInspectorTests/SwiftUI/SheetTests.swift | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Sources/ViewInspector/PopupPresenter.swift b/Sources/ViewInspector/PopupPresenter.swift index 7f79e741..c702457e 100644 --- a/Sources/ViewInspector/PopupPresenter.swift +++ b/Sources/ViewInspector/PopupPresenter.swift @@ -169,7 +169,7 @@ internal extension Content { throw InspectionError.notSupported( """ Please refer to the Guide for inspecting the \(name): \ - https://github.com/nalexn/ViewInspector/blob/master/guide.md#alert-sheet-actionsheet-and-fullscreencover + https://github.com/nalexn/ViewInspector/blob/master/guide_popups.md#\(name.lowercased()) """) } let popup: Any = try { diff --git a/Tests/ViewInspectorTests/SwiftUI/ActionSheetTests.swift b/Tests/ViewInspectorTests/SwiftUI/ActionSheetTests.swift index f264e211..3b411cee 100644 --- a/Tests/ViewInspectorTests/SwiftUI/ActionSheetTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/ActionSheetTests.swift @@ -24,7 +24,7 @@ final class ActionSheetTests: XCTestCase { XCTAssertThrows(try sut.inspect().emptyView().actionSheet(), """ Please refer to the Guide for inspecting the ActionSheet: \ - https://github.com/nalexn/ViewInspector/blob/master/guide.md#alert-sheet-actionsheet-and-fullscreencover + https://github.com/nalexn/ViewInspector/blob/master/guide_popups.md#actionsheet """) } diff --git a/Tests/ViewInspectorTests/SwiftUI/AlertTests.swift b/Tests/ViewInspectorTests/SwiftUI/AlertTests.swift index c35702dd..c0fad9fa 100644 --- a/Tests/ViewInspectorTests/SwiftUI/AlertTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/AlertTests.swift @@ -23,7 +23,7 @@ final class DeprecatedAlertTests: XCTestCase { XCTAssertThrows(try sut.inspect().emptyView().alert(), """ Please refer to the Guide for inspecting the Alert: \ - https://github.com/nalexn/ViewInspector/blob/master/guide.md#alert-sheet-actionsheet-and-fullscreencover + https://github.com/nalexn/ViewInspector/blob/master/guide_popups.md#alert """) } diff --git a/Tests/ViewInspectorTests/SwiftUI/FullScreenCoverTests.swift b/Tests/ViewInspectorTests/SwiftUI/FullScreenCoverTests.swift index f371db34..596d75a7 100644 --- a/Tests/ViewInspectorTests/SwiftUI/FullScreenCoverTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/FullScreenCoverTests.swift @@ -26,7 +26,7 @@ final class FullScreenCoverTests: XCTestCase { XCTAssertThrows(try sut.inspect().emptyView().fullScreenCover(), """ Please refer to the Guide for inspecting the FullScreenCover: \ - https://github.com/nalexn/ViewInspector/blob/master/guide.md#alert-sheet-actionsheet-and-fullscreencover + https://github.com/nalexn/ViewInspector/blob/master/guide_popups.md#fullscreencover """) } diff --git a/Tests/ViewInspectorTests/SwiftUI/PopoverTests.swift b/Tests/ViewInspectorTests/SwiftUI/PopoverTests.swift index 33b4234a..d886d0d0 100644 --- a/Tests/ViewInspectorTests/SwiftUI/PopoverTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/PopoverTests.swift @@ -28,7 +28,7 @@ final class PopoverTests: XCTestCase { XCTAssertThrows(try sut.inspect().emptyView().popover(), """ Please refer to the Guide for inspecting the Popover: \ - https://github.com/nalexn/ViewInspector/blob/master/guide.md#alert-sheet-actionsheet-and-fullscreencover + https://github.com/nalexn/ViewInspector/blob/master/guide_popups.md#popover """) } diff --git a/Tests/ViewInspectorTests/SwiftUI/SheetTests.swift b/Tests/ViewInspectorTests/SwiftUI/SheetTests.swift index cefb6e13..d850453d 100644 --- a/Tests/ViewInspectorTests/SwiftUI/SheetTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/SheetTests.swift @@ -23,7 +23,7 @@ final class SheetTests: XCTestCase { XCTAssertThrows(try sut.inspect().emptyView().sheet(), """ Please refer to the Guide for inspecting the Sheet: \ - https://github.com/nalexn/ViewInspector/blob/master/guide.md#alert-sheet-actionsheet-and-fullscreencover + https://github.com/nalexn/ViewInspector/blob/master/guide_popups.md#sheet """) } From ad769299fb291508842e73cdda6452403e13d5e4 Mon Sep 17 00:00:00 2001 From: Alexey Naumov Date: Sun, 19 Sep 2021 18:16:09 +0300 Subject: [PATCH 92/99] Fix tests crashing on tvOS 13 --- .../GestureModifierTests.swift | 12 +-- .../HighPriorityGestureModifierTests.swift | 12 +-- .../SimultaneousGestureModifierTests.swift | 12 +-- .../Gestures/LongPressGestureTests.swift | 91 ++++++++++++------- .../TransitiveModifiersTests.swift | 2 +- 5 files changed, 79 insertions(+), 50 deletions(-) diff --git a/Tests/ViewInspectorTests/Gestures/GestureModifiers/GestureModifierTests.swift b/Tests/ViewInspectorTests/Gestures/GestureModifiers/GestureModifierTests.swift index d51f172a..1427866b 100644 --- a/Tests/ViewInspectorTests/Gestures/GestureModifiers/GestureModifierTests.swift +++ b/Tests/ViewInspectorTests/Gestures/GestureModifiers/GestureModifierTests.swift @@ -33,8 +33,8 @@ final class GestureModifierTests: XCTestCase { "EmptyView does not have 'gesture(DragGesture.self)' modifier") } - @available(tvOS 14.0, *) func testGestureInspectionFailureDueToTypeMismatch() throws { + guard #available(tvOS 14.0, *) else { return } let sut = EmptyView() .gesture(LongPressGesture()) XCTAssertThrows( @@ -42,8 +42,8 @@ final class GestureModifierTests: XCTestCase { "Type mismatch: LongPressGesture is not DragGesture") } - @available(tvOS 14.0, *) func testGestureInspectionWithIndex1() throws { + guard #available(tvOS 14.0, *) else { return } let sut = EmptyView() .gesture(DragGesture()) .gesture(LongPressGesture()) @@ -51,8 +51,8 @@ final class GestureModifierTests: XCTestCase { XCTAssertNoThrow(try sut.inspect().emptyView().gesture(LongPressGesture.self, 1)) } - @available(tvOS 14.0, *) func testGestureInspectionWithIndex2() throws { + guard #available(tvOS 14.0, *) else { return } let sut = EmptyView() .gesture(DragGesture()) .highPriorityGesture(TapGesture()) @@ -61,8 +61,8 @@ final class GestureModifierTests: XCTestCase { XCTAssertNoThrow(try sut.inspect().emptyView().gesture(LongPressGesture.self, 1)) } - @available(tvOS 14.0, *) func testGestureInspectionWithIndexFailureDueToNoModifier() throws { + guard #available(tvOS 14.0, *) else { return } let sut = EmptyView() .gesture(DragGesture()) .gesture(LongPressGesture()) @@ -71,8 +71,8 @@ final class GestureModifierTests: XCTestCase { "EmptyView does not have 'gesture(DragGesture.self)' modifier at index 2") } - @available(tvOS 14.0, *) func testGestureInspectionWithIndexFailureDueToTypeMismatch() throws { + guard #available(tvOS 14.0, *) else { return } let sut = EmptyView() .gesture(DragGesture()) .gesture(LongPressGesture()) @@ -90,8 +90,8 @@ final class GestureModifierTests: XCTestCase { XCTAssertEqual(path, "emptyView().gesture(DragGesture.self)") } - @available(tvOS 14.0, *) func testGestureInspectionWithIndexPathToRoot() throws { + guard #available(tvOS 14.0, *) else { return } let sut = EmptyView() .padding(100) .gesture(DragGesture()) diff --git a/Tests/ViewInspectorTests/Gestures/GestureModifiers/HighPriorityGestureModifierTests.swift b/Tests/ViewInspectorTests/Gestures/GestureModifiers/HighPriorityGestureModifierTests.swift index 0f1385d7..267eae9b 100644 --- a/Tests/ViewInspectorTests/Gestures/GestureModifiers/HighPriorityGestureModifierTests.swift +++ b/Tests/ViewInspectorTests/Gestures/GestureModifiers/HighPriorityGestureModifierTests.swift @@ -36,8 +36,8 @@ final class HighPriorityGestureModifierTests: XCTestCase { "EmptyView does not have 'highPriorityGesture(DragGesture.self)' modifier") } - @available(tvOS 14.0, *) func testHighPriorityGestureInspectionFailureDueToTypeMismatch() throws { + guard #available(tvOS 14.0, *) else { return } let sut = EmptyView() .highPriorityGesture(LongPressGesture()) XCTAssertThrows( @@ -45,8 +45,8 @@ final class HighPriorityGestureModifierTests: XCTestCase { "Type mismatch: LongPressGesture is not DragGesture") } - @available(tvOS 14.0, *) func testHighPriorityGestureInspectionWithIndex1() throws { + guard #available(tvOS 14.0, *) else { return } let sut = EmptyView() .highPriorityGesture(DragGesture()) .highPriorityGesture(LongPressGesture()) @@ -54,8 +54,8 @@ final class HighPriorityGestureModifierTests: XCTestCase { XCTAssertNoThrow(try sut.inspect().emptyView().highPriorityGesture(LongPressGesture.self, 1)) } - @available(tvOS 14.0, *) func testHighPriorityGestureInspectionWithIndex2() throws { + guard #available(tvOS 14.0, *) else { return } let sut = EmptyView() .highPriorityGesture(DragGesture()) .gesture(TapGesture()) @@ -64,8 +64,8 @@ final class HighPriorityGestureModifierTests: XCTestCase { XCTAssertNoThrow(try sut.inspect().emptyView().highPriorityGesture(LongPressGesture.self, 1)) } - @available(tvOS 14.0, *) func testHighPriorityGestureInspectionWithIndexFailureDueToNoModifier() throws { + guard #available(tvOS 14.0, *) else { return } let sut = EmptyView() .highPriorityGesture(DragGesture()) .highPriorityGesture(LongPressGesture()) @@ -74,8 +74,8 @@ final class HighPriorityGestureModifierTests: XCTestCase { "EmptyView does not have 'highPriorityGesture(DragGesture.self)' modifier at index 2") } - @available(tvOS 14.0, *) func testHighPriorityGestureInspectionWithIndexFailureDueToTypeMismatch() throws { + guard #available(tvOS 14.0, *) else { return } let sut = EmptyView() .highPriorityGesture(DragGesture()) .highPriorityGesture(LongPressGesture()) @@ -92,8 +92,8 @@ final class HighPriorityGestureModifierTests: XCTestCase { XCTAssertEqual(path, "emptyView().highPriorityGesture(DragGesture.self)") } - @available(tvOS 14.0, *) func testHighPriorityGestureInspectionWithIndexPathToRoot() throws { + guard #available(tvOS 14.0, *) else { return } let sut = EmptyView() .padding(100) .highPriorityGesture(DragGesture()) diff --git a/Tests/ViewInspectorTests/Gestures/GestureModifiers/SimultaneousGestureModifierTests.swift b/Tests/ViewInspectorTests/Gestures/GestureModifiers/SimultaneousGestureModifierTests.swift index 9dc0eec3..c22834aa 100644 --- a/Tests/ViewInspectorTests/Gestures/GestureModifiers/SimultaneousGestureModifierTests.swift +++ b/Tests/ViewInspectorTests/Gestures/GestureModifiers/SimultaneousGestureModifierTests.swift @@ -36,8 +36,8 @@ final class SimultaneousGestureModifierTests: XCTestCase { "EmptyView does not have 'simultaneousGesture(DragGesture.self)' modifier") } - @available(tvOS 14.0, *) func testSimultaneousGestureInspectionFailureDueToTypeMismatch() throws { + guard #available(tvOS 14.0, *) else { return } let sut = EmptyView() .simultaneousGesture(LongPressGesture()) XCTAssertThrows( @@ -45,8 +45,8 @@ final class SimultaneousGestureModifierTests: XCTestCase { "Type mismatch: LongPressGesture is not DragGesture") } - @available(tvOS 14.0, *) func testSimultaneousGestureInspectionWithIndex1() throws { + guard #available(tvOS 14.0, *) else { return } let sut = EmptyView() .simultaneousGesture(DragGesture()) .simultaneousGesture(LongPressGesture()) @@ -54,8 +54,8 @@ final class SimultaneousGestureModifierTests: XCTestCase { XCTAssertNoThrow(try sut.inspect().emptyView().simultaneousGesture(LongPressGesture.self, 1)) } - @available(tvOS 14.0, *) func testSimultaneousGestureInspectionWithIndex2() throws { + guard #available(tvOS 14.0, *) else { return } let sut = EmptyView() .simultaneousGesture(DragGesture()) .gesture(TapGesture()) @@ -64,8 +64,8 @@ final class SimultaneousGestureModifierTests: XCTestCase { XCTAssertNoThrow(try sut.inspect().emptyView().simultaneousGesture(LongPressGesture.self, 1)) } - @available(tvOS 14.0, *) func testSimultaneousGestureInspectionWithIndexFailureDueToNoModifier() throws { + guard #available(tvOS 14.0, *) else { return } let sut = EmptyView() .simultaneousGesture(DragGesture()) .simultaneousGesture(LongPressGesture()) @@ -74,8 +74,8 @@ final class SimultaneousGestureModifierTests: XCTestCase { "EmptyView does not have 'simultaneousGesture(DragGesture.self)' modifier at index 2") } - @available(tvOS 14.0, *) func testSimultaneousGestureInspectionWithIndexFailureDueToTypeMismatch() throws { + guard #available(tvOS 14.0, *) else { return } let sut = EmptyView() .simultaneousGesture(DragGesture()) .simultaneousGesture(LongPressGesture()) @@ -92,8 +92,8 @@ final class SimultaneousGestureModifierTests: XCTestCase { XCTAssertEqual(path, "emptyView().simultaneousGesture(DragGesture.self)") } - @available(tvOS 14.0, *) func testSimultaneousGestureInspectionWithIndexPathToRoot() throws { + guard #available(tvOS 14.0, *) else { return } let sut = EmptyView() .padding(100) .simultaneousGesture(DragGesture()) diff --git a/Tests/ViewInspectorTests/Gestures/LongPressGestureTests.swift b/Tests/ViewInspectorTests/Gestures/LongPressGestureTests.swift index 1791a1d0..93bbccf2 100644 --- a/Tests/ViewInspectorTests/Gestures/LongPressGestureTests.swift +++ b/Tests/ViewInspectorTests/Gestures/LongPressGestureTests.swift @@ -5,38 +5,50 @@ import Combine // MARK: - Long Press Gesture Tests -@available(iOS 13.0, macOS 10.15, tvOS 14.0, *) +@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) final class LongPressGestureTests: XCTestCase { var longPressFinished: Bool? - var longPressValue: LongPressGesture.Value? - var gestureTests: CommonGestureTests? + private var _longPressValue: Any? + @available(tvOS 14.0, *) + private func longPressValue() throws -> LongPressGesture.Value { + return try Inspector.cast(value: _longPressValue!, type: LongPressGesture.Value.self) + } + + private var _gestureTests: Any? + @available(tvOS 14.0, *) + private func gestureTests() throws -> CommonGestureTests { + return try Inspector.cast(value: _gestureTests!, type: CommonGestureTests.self) + } override func setUpWithError() throws { + guard #available(tvOS 14.0, *) else { return } longPressFinished = false - longPressValue = LongPressGesture.Value(finished: longPressFinished!) + _longPressValue = LongPressGesture.Value(finished: longPressFinished!) - gestureTests = CommonGestureTests(testCase: self, + _gestureTests = CommonGestureTests(testCase: self, gesture: LongPressGesture(), - value: longPressValue!, + value: try longPressValue(), assert: assertLongPressValue) } override func tearDownWithError() throws { longPressFinished = nil - longPressValue = nil - gestureTests = nil + _longPressValue = nil + _gestureTests = nil } func testCreateLongPressGestureValue() throws { + guard #available(tvOS 14.0, *) else { return } XCTAssertNotNil(longPressFinished) - let value = try XCTUnwrap(longPressValue) + let value = try longPressValue() assertLongPressValue(value) } func testLongPressGestureMask() throws { - try gestureTests!.maskTest() + guard #available(tvOS 14.0, *) else { return } + try gestureTests().maskTest() } #if !os(tvOS) @@ -50,93 +62,110 @@ final class LongPressGestureTests: XCTestCase { #endif func testLongPressGestureWithUpdatingModifier() throws { - try gestureTests!.propertiesWithUpdatingModifierTest() + guard #available(tvOS 14.0, *) else { return } + try gestureTests().propertiesWithUpdatingModifierTest() } func testLongPressGestureWithOnChangedModifier() throws { - try gestureTests!.propertiesWithOnChangedModifierTest() + guard #available(tvOS 14.0, *) else { return } + try gestureTests().propertiesWithOnChangedModifierTest() } func testLongPressGestureWithOnEndedModifier() throws { - try gestureTests!.propertiesWithOnEndedModifierTest() + guard #available(tvOS 14.0, *) else { return } + try gestureTests().propertiesWithOnEndedModifierTest() } #if os(macOS) func testLongPressGestureWithModifiers() throws { - try gestureTests!.propertiesWithModifiersTest() + try gestureTests().propertiesWithModifiersTest() } #endif func testLongPressGestureFailure() throws { - try gestureTests!.propertiesFailureTest("LongPressGesture") + guard #available(tvOS 14.0, *) else { return } + try gestureTests().propertiesFailureTest("LongPressGesture") } func testLongPressGestureCallUpdating() throws { - try gestureTests!.callUpdatingTest() + guard #available(tvOS 14.0, *) else { return } + try gestureTests().callUpdatingTest() } func testLongPressGestureCallUpdatingNotFirst() throws { - try gestureTests!.callUpdatingNotFirstTest() + guard #available(tvOS 14.0, *) else { return } + try gestureTests().callUpdatingNotFirstTest() } func testLongPressGestureCallUpdatingMultiple() throws { - try gestureTests!.callUpdatingMultipleTest() + guard #available(tvOS 14.0, *) else { return } + try gestureTests().callUpdatingMultipleTest() } func testLongPressGestureCallUpdatingFailure() throws { - try gestureTests!.callUpdatingFailureTest() + guard #available(tvOS 14.0, *) else { return } + try gestureTests().callUpdatingFailureTest() } func testLongPressGestureCallOnChanged() throws { - try gestureTests!.callOnChangedTest() + guard #available(tvOS 14.0, *) else { return } + try gestureTests().callOnChangedTest() } func testLongPressGestureCallOnChangedNotFirst() throws { - try gestureTests!.callOnChangedNotFirstTest() + guard #available(tvOS 14.0, *) else { return } + try gestureTests().callOnChangedNotFirstTest() } func testLongPressGestureCallOnChangedMultiple() throws { - try gestureTests!.callOnChangedMultipleTest() + guard #available(tvOS 14.0, *) else { return } + try gestureTests().callOnChangedMultipleTest() } func testLongPressGestureCallOnChangedFailure() throws { - try gestureTests!.callOnChangedFailureTest() + guard #available(tvOS 14.0, *) else { return } + try gestureTests().callOnChangedFailureTest() } func testLongPressGestureCallOnEnded() throws { - try gestureTests!.callOnEndedTest() + guard #available(tvOS 14.0, *) else { return } + try gestureTests().callOnEndedTest() } func testLongPressGestureCallOnEndedNotFirst() throws { - try gestureTests!.callOnEndedNotFirstTest() + guard #available(tvOS 14.0, *) else { return } + try gestureTests().callOnEndedNotFirstTest() } func testLongPressGestureCallOnEndedMultiple() throws { - try gestureTests!.callOnEndedMultipleTest() + guard #available(tvOS 14.0, *) else { return } + try gestureTests().callOnEndedMultipleTest() } func testLongPressGestureCallOnEndedFailure() throws { - try gestureTests!.callOnEndedFailureTest() + guard #available(tvOS 14.0, *) else { return } + try gestureTests().callOnEndedFailureTest() } #if os(macOS) func testLongPressGestureModifiers() throws { - try gestureTests!.modifiersTest() + try gestureTests().modifiersTest() } func testLongPressGestureModifiersNotFirst() throws { - try gestureTests!.modifiersNotFirstTest() + try gestureTests().modifiersNotFirstTest() } func testLongPressGestureModifiersMultiple() throws { - try gestureTests!.modifiersMultipleTest() + try gestureTests().modifiersMultipleTest() } func testLongPressGestureModifiersNone() throws { - try gestureTests!.modifiersNoneTest() + try gestureTests().modifiersNoneTest() } #endif + @available(tvOS 14.0, *) func assertLongPressValue( _ value: LongPressGesture.Value, file: StaticString = #filePath, diff --git a/Tests/ViewInspectorTests/ViewModifiers/TransitiveModifiersTests.swift b/Tests/ViewInspectorTests/ViewModifiers/TransitiveModifiersTests.swift index 3fd0b017..ab579602 100644 --- a/Tests/ViewInspectorTests/ViewModifiers/TransitiveModifiersTests.swift +++ b/Tests/ViewInspectorTests/ViewModifiers/TransitiveModifiersTests.swift @@ -26,7 +26,7 @@ final class TransitiveModifiersTests: XCTestCase { @available(watchOS, unavailable) func testFlipsRightToLeftInheritance() throws { let sut = try FlipsRightToLeftTestView().inspect() - if #available(iOS 14.0, *) { + if #available(iOS 14.0, tvOS 14.0, *) { XCTAssertFalse(try sut.find(text: "1").flipsForRightToLeftLayoutDirection()) } else { // Prior to iOS 14 flipsForRightToLeftLayoutDirection is ignoring the Bool parameter From 80e78443071a0b20b6a61f346a77c9ea223c8317 Mon Sep 17 00:00:00 2001 From: Alexey Naumov Date: Sun, 19 Sep 2021 22:13:49 +0300 Subject: [PATCH 93/99] Update podspec --- ViewInspector.podspec | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ViewInspector.podspec b/ViewInspector.podspec index 464ef92b..5292d412 100644 --- a/ViewInspector.podspec +++ b/ViewInspector.podspec @@ -2,7 +2,7 @@ Pod::Spec.new do |s| s.name = "ViewInspector" - s.version = "0.8.1" + s.version = "0.9.0" s.summary = "ViewInspector is a library for unit testing SwiftUI views." s.homepage = "https://github.com/nalexn/ViewInspector" s.license = { :type => "MIT", :file => "LICENSE" } @@ -10,8 +10,8 @@ Pod::Spec.new do |s| s.ios.deployment_target = '13.0' s.osx.deployment_target = '10.15' - #s.tvos.deployment_target = '13.0' - #s.watchos.deployment_target = '6.0' + s.tvos.deployment_target = '13.0' + #s.watchos.deployment_target = '7.0' s.swift_version = '5.0' s.framework = 'XCTest' s.source = { :git => "https://github.com/nalexn/ViewInspector.git", :tag => "#{s.version}" } From bf56fb118414e04ed7001311f8241e567d8f15f9 Mon Sep 17 00:00:00 2001 From: Alexey Naumov Date: Sun, 19 Sep 2021 22:34:24 +0300 Subject: [PATCH 94/99] Fix tests for tvOS --- Sources/ViewInspector/SwiftUI/GroupBox.swift | 2 ++ Sources/ViewInspector/SwiftUI/Menu.swift | 2 ++ Sources/ViewInspector/SwiftUI/OutlineGroup.swift | 2 ++ Tests/ViewInspectorTests/SwiftUI/ColorPickerTests.swift | 2 ++ Tests/ViewInspectorTests/SwiftUI/DisclosureGroupTests.swift | 2 ++ Tests/ViewInspectorTests/SwiftUI/GroupBoxTests.swift | 4 +++- Tests/ViewInspectorTests/SwiftUI/OutlineGroupTests.swift | 2 ++ Tests/ViewInspectorTests/SwiftUI/TextEditorTests.swift | 2 ++ 8 files changed, 17 insertions(+), 1 deletion(-) diff --git a/Sources/ViewInspector/SwiftUI/GroupBox.swift b/Sources/ViewInspector/SwiftUI/GroupBox.swift index 89f96dae..057542a2 100644 --- a/Sources/ViewInspector/SwiftUI/GroupBox.swift +++ b/Sources/ViewInspector/SwiftUI/GroupBox.swift @@ -74,6 +74,7 @@ public extension InspectableView { // MARK: - GroupBoxStyle inspection +#if os(iOS) || os(macOS) @available(iOS 14.0, macOS 11.0, *) @available(tvOS, unavailable) @available(watchOS, unavailable) @@ -96,3 +97,4 @@ private extension GroupBoxStyleConfiguration { self = unsafeBitCast(Allocator(), to: Self.self) } } +#endif diff --git a/Sources/ViewInspector/SwiftUI/Menu.swift b/Sources/ViewInspector/SwiftUI/Menu.swift index c4bb2a71..72a98ff1 100644 --- a/Sources/ViewInspector/SwiftUI/Menu.swift +++ b/Sources/ViewInspector/SwiftUI/Menu.swift @@ -74,6 +74,7 @@ public extension InspectableView { // MARK: - MenuStyle inspection +#if os(iOS) || os(macOS) @available(iOS 14.0, macOS 11.0, *) @available(tvOS, unavailable) @available(watchOS, unavailable) @@ -106,3 +107,4 @@ private extension MenuStyleConfiguration { } } } +#endif diff --git a/Sources/ViewInspector/SwiftUI/OutlineGroup.swift b/Sources/ViewInspector/SwiftUI/OutlineGroup.swift index 173a60b1..6d2c4e03 100644 --- a/Sources/ViewInspector/SwiftUI/OutlineGroup.swift +++ b/Sources/ViewInspector/SwiftUI/OutlineGroup.swift @@ -58,6 +58,7 @@ private protocol LeafContentProvider { func view(_ element: Any) throws -> Any } +#if os(iOS) || os(macOS) @available(iOS 14.0, macOS 11.0, *) @available(tvOS, unavailable) @available(watchOS, unavailable) @@ -72,3 +73,4 @@ extension OutlineGroup: LeafContentProvider { return builder(data) } } +#endif diff --git a/Tests/ViewInspectorTests/SwiftUI/ColorPickerTests.swift b/Tests/ViewInspectorTests/SwiftUI/ColorPickerTests.swift index 7299d2b3..2b8a5088 100644 --- a/Tests/ViewInspectorTests/SwiftUI/ColorPickerTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/ColorPickerTests.swift @@ -2,6 +2,7 @@ import XCTest import SwiftUI @testable import ViewInspector +#if os(iOS) || os(macOS) @available(iOS 13.0, macOS 10.15, *) @available(tvOS, unavailable) @available(watchOS, unavailable) @@ -145,3 +146,4 @@ private extension Color { return .init(color: self) } } +#endif diff --git a/Tests/ViewInspectorTests/SwiftUI/DisclosureGroupTests.swift b/Tests/ViewInspectorTests/SwiftUI/DisclosureGroupTests.swift index 332fd637..7f674b9c 100644 --- a/Tests/ViewInspectorTests/SwiftUI/DisclosureGroupTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/DisclosureGroupTests.swift @@ -2,6 +2,7 @@ import XCTest import SwiftUI @testable import ViewInspector +#if os(iOS) || os(macOS) @available(iOS 13.0, macOS 10.15, *) @available(tvOS, unavailable) @available(watchOS, unavailable) @@ -134,3 +135,4 @@ private struct TestViewBinding: View, Inspectable { }, label: { EmptyView() }) } } +#endif diff --git a/Tests/ViewInspectorTests/SwiftUI/GroupBoxTests.swift b/Tests/ViewInspectorTests/SwiftUI/GroupBoxTests.swift index 00bd4916..ce032511 100644 --- a/Tests/ViewInspectorTests/SwiftUI/GroupBoxTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/GroupBoxTests.swift @@ -89,7 +89,7 @@ final class GroupBoxTests: XCTestCase { XCTAssertEqual(sut, "abc") } - #if os(iOS) + #if os(iOS) || os(macOS) func testGroupBoxStyleInspection() throws { guard #available(iOS 14, *) else { return } let sut = EmptyView().groupBoxStyle(DefaultGroupBoxStyle()) @@ -110,6 +110,7 @@ final class GroupBoxTests: XCTestCase { #endif } +#if os(iOS) || os(macOS) @available(iOS 14.0, macOS 11.0, *) @available(tvOS, unavailable) @available(watchOS, unavailable) @@ -123,3 +124,4 @@ private struct TestGroupBoxStyle: GroupBoxStyle { } } } +#endif diff --git a/Tests/ViewInspectorTests/SwiftUI/OutlineGroupTests.swift b/Tests/ViewInspectorTests/SwiftUI/OutlineGroupTests.swift index ae413d14..61408ac6 100644 --- a/Tests/ViewInspectorTests/SwiftUI/OutlineGroupTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/OutlineGroupTests.swift @@ -2,6 +2,7 @@ import XCTest import SwiftUI @testable import ViewInspector +#if os(iOS) || os(macOS) @available(iOS 13.0, macOS 10.15, *) @available(tvOS, unavailable) final class OutlineGroupTests: XCTestCase { @@ -80,3 +81,4 @@ final class OutlineGroupTests: XCTestCase { XCTAssertEqual(sut, "l2") } } +#endif diff --git a/Tests/ViewInspectorTests/SwiftUI/TextEditorTests.swift b/Tests/ViewInspectorTests/SwiftUI/TextEditorTests.swift index f18a35e6..60644472 100644 --- a/Tests/ViewInspectorTests/SwiftUI/TextEditorTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/TextEditorTests.swift @@ -2,6 +2,7 @@ import XCTest import SwiftUI @testable import ViewInspector +#if os(iOS) || os(macOS) @available(iOS 13.0, macOS 10.15, *) @available(tvOS, unavailable) @available(watchOS, unavailable) @@ -52,3 +53,4 @@ final class TextEditorTests: XCTestCase { XCTAssertEqual(try sut.input(), "123") } } +#endif From 5028ff42ab6b47dc3dfbc67fd02597a3ea44eb9e Mon Sep 17 00:00:00 2001 From: Alexey Naumov Date: Sun, 19 Sep 2021 22:41:09 +0300 Subject: [PATCH 95/99] Fix tests for macOS --- .../SwiftUI/GroupBoxTests.swift | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/Tests/ViewInspectorTests/SwiftUI/GroupBoxTests.swift b/Tests/ViewInspectorTests/SwiftUI/GroupBoxTests.swift index ce032511..34e1c4c0 100644 --- a/Tests/ViewInspectorTests/SwiftUI/GroupBoxTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/GroupBoxTests.swift @@ -8,7 +8,7 @@ import SwiftUI final class GroupBoxTests: XCTestCase { func testSingleEnclosedView() throws { - guard #available(iOS 14, *) else { return } + guard #available(iOS 14, macOS 11.0, *) else { return } let sampleView = Text("Test") let view = GroupBox { sampleView } let sut = try view.inspect().groupBox().text(0).content.view as? Text @@ -16,7 +16,7 @@ final class GroupBoxTests: XCTestCase { } func testSingleEnclosedViewIndexOutOfBounds() throws { - guard #available(iOS 14, *) else { return } + guard #available(iOS 14, macOS 11.0, *) else { return } let sampleView = Text("Test") let view = GroupBox { sampleView } XCTAssertThrows( @@ -25,7 +25,7 @@ final class GroupBoxTests: XCTestCase { } func testMultipleEnclosedViews() throws { - guard #available(iOS 14, *) else { return } + guard #available(iOS 14, macOS 11.0, *) else { return } let sampleView1 = Text("Test") let sampleView2 = Text("Abc") let sampleView3 = Text("XYZ") @@ -39,7 +39,7 @@ final class GroupBoxTests: XCTestCase { } func testMultipleEnclosedViewsIndexOutOfBounds() throws { - guard #available(iOS 14, *) else { return } + guard #available(iOS 14, macOS 11.0, *) else { return } let sampleView1 = Text("Test") let sampleView2 = Text("Abc") let view = GroupBox { sampleView1; sampleView2 } @@ -49,20 +49,20 @@ final class GroupBoxTests: XCTestCase { } func testResetsModifiers() throws { - guard #available(iOS 14, *) else { return } + guard #available(iOS 14, macOS 11.0, *) else { return } let view = GroupBox { Text("Test") }.padding() let sut = try view.inspect().groupBox().text(0) XCTAssertEqual(sut.content.medium.viewModifiers.count, 0) } func testExtractionFromSingleViewContainer() throws { - guard #available(iOS 14, *) else { return } + guard #available(iOS 14, macOS 11.0, *) else { return } let view = AnyView(GroupBox { Text("Test") }) XCTAssertNoThrow(try view.inspect().anyView().groupBox()) } func testExtractionFromMultipleViewContainer() throws { - guard #available(iOS 14, *) else { return } + guard #available(iOS 14, macOS 11.0, *) else { return } let view = GroupBox { GroupBox { Text("Test") } GroupBox { Text("Test") } @@ -72,7 +72,7 @@ final class GroupBoxTests: XCTestCase { } func testSearch() throws { - guard #available(iOS 14, *) else { return } + guard #available(iOS 14, macOS 11.0, *) else { return } let view = AnyView(GroupBox { Text("Test") }) XCTAssertEqual(try view.inspect().find(ViewType.GroupBox.self).pathToRoot, "anyView().groupBox()") @@ -81,7 +81,7 @@ final class GroupBoxTests: XCTestCase { } func testLabelInspection() throws { - guard #available(iOS 14, *) else { return } + guard #available(iOS 14, macOS 11.0, *) else { return } let view = GroupBox( label: HStack { Text("abc") }, content: { Text("test") }) @@ -91,13 +91,13 @@ final class GroupBoxTests: XCTestCase { #if os(iOS) || os(macOS) func testGroupBoxStyleInspection() throws { - guard #available(iOS 14, *) else { return } + guard #available(iOS 14, macOS 11.0, *) else { return } let sut = EmptyView().groupBoxStyle(DefaultGroupBoxStyle()) XCTAssertTrue(try sut.inspect().groupBoxStyle() is DefaultGroupBoxStyle) } func testCustomGroupBoxStyleInspection() throws { - guard #available(iOS 14, *) else { return } + guard #available(iOS 14, macOS 11.0, *) else { return } let sut = TestGroupBoxStyle() XCTAssertEqual(try sut.inspect().vStack().styleConfigurationContent(0).blur().radius, 5) XCTAssertEqual(try sut.inspect().vStack().styleConfigurationLabel(1).brightness(), 3) From 71121e620eb7840936391d13d668e23c0af41050 Mon Sep 17 00:00:00 2001 From: Alexey Naumov Date: Sun, 19 Sep 2021 23:20:49 +0300 Subject: [PATCH 96/99] Revert "Remove UnaryViewAdaptor" This reverts commit 9aeaa2ccbce383662b5b5cff8c62b2d3e41c72e1. --- Sources/ViewInspector/Inspector.swift | 4 ++++ .../SwiftUI/UnaryViewAdaptor.swift | 17 +++++++++++++++++ ViewInspector.xcodeproj/project.pbxproj | 4 ++++ 3 files changed, 25 insertions(+) create mode 100644 Sources/ViewInspector/SwiftUI/UnaryViewAdaptor.swift diff --git a/Sources/ViewInspector/Inspector.swift b/Sources/ViewInspector/Inspector.swift index c673bb3a..424197ba 100644 --- a/Sources/ViewInspector/Inspector.swift +++ b/Sources/ViewInspector/Inspector.swift @@ -187,6 +187,7 @@ internal extension Inspector { return try unwrap(content: Content(view, medium: medium)) } + // swiftlint:disable cyclomatic_complexity static func unwrap(content: Content) throws -> Content { switch Inspector.typeName(value: content.view, prefixOnly: true) { case "Tree": @@ -201,6 +202,8 @@ internal extension Inspector { return try ViewType.ViewModifier.child(content) case "SubscriptionView": return try ViewType.SubscriptionView.child(content) + case "_UnaryViewAdaptor": + return try ViewType.UnaryViewAdaptor.child(content) case "_ConditionalContent": return try ViewType.ConditionalContent.child(content) case "EnvironmentReaderView": @@ -211,6 +214,7 @@ internal extension Inspector { return content } } + // swiftlint:enable cyclomatic_complexity static func guardType(value: Any, namespacedPrefixes: [String], inspectionCall: String) throws { diff --git a/Sources/ViewInspector/SwiftUI/UnaryViewAdaptor.swift b/Sources/ViewInspector/SwiftUI/UnaryViewAdaptor.swift new file mode 100644 index 00000000..6d4c6688 --- /dev/null +++ b/Sources/ViewInspector/SwiftUI/UnaryViewAdaptor.swift @@ -0,0 +1,17 @@ +import SwiftUI + +@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) +internal extension ViewType { + struct UnaryViewAdaptor { } +} + +// MARK: - Content Extraction + +@available(iOS 13.0, macOS 10.15, tvOS 13.0, *) +extension ViewType.UnaryViewAdaptor: SingleViewContent { + + static func child(_ content: Content) throws -> Content { + let view = try Inspector.attribute(label: "content", value: content.view) + return try Inspector.unwrap(view: view, medium: content.medium) + } +} diff --git a/ViewInspector.xcodeproj/project.pbxproj b/ViewInspector.xcodeproj/project.pbxproj index 090a7aed..d94d651f 100644 --- a/ViewInspector.xcodeproj/project.pbxproj +++ b/ViewInspector.xcodeproj/project.pbxproj @@ -30,6 +30,7 @@ 5214803A25F803DC002D974D /* CustomStyleModifiersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5214803025F803D5002D974D /* CustomStyleModifiersTests.swift */; }; 5223540026D62CB2008DA52F /* ToolbarTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 522353FF26D62CB2008DA52F /* ToolbarTests.swift */; }; 5223540226D63B7A008DA52F /* Toolbar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5223540126D63B79008DA52F /* Toolbar.swift */; }; + 5236C34326CDC2F4007432E1 /* UnaryViewAdaptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5236C34226CDC2F4007432E1 /* UnaryViewAdaptor.swift */; }; 52507626264FC0F400ADE4E7 /* Alert.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52507625264FC0F400ADE4E7 /* Alert.swift */; }; 525076282650000600ADE4E7 /* AlertTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 525076272650000600ADE4E7 /* AlertTests.swift */; }; 52507647265155C000ADE4E7 /* TransitiveModifiersTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52507646265155C000ADE4E7 /* TransitiveModifiersTests.swift */; }; @@ -282,6 +283,7 @@ 5214803025F803D5002D974D /* CustomStyleModifiersTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomStyleModifiersTests.swift; sourceTree = ""; }; 522353FF26D62CB2008DA52F /* ToolbarTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ToolbarTests.swift; sourceTree = ""; }; 5223540126D63B79008DA52F /* Toolbar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Toolbar.swift; sourceTree = ""; }; + 5236C34226CDC2F4007432E1 /* UnaryViewAdaptor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnaryViewAdaptor.swift; sourceTree = ""; }; 52507625264FC0F400ADE4E7 /* Alert.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Alert.swift; sourceTree = ""; }; 525076272650000600ADE4E7 /* AlertTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertTests.swift; sourceTree = ""; }; 52507646265155C000ADE4E7 /* TransitiveModifiersTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransitiveModifiersTests.swift; sourceTree = ""; }; @@ -676,6 +678,7 @@ F639DBC223A7DDA2003A6FED /* TouchBar.swift */, F64A2C6723A3FD3A00A4853A /* TreeView.swift */, F653BDE2255698A6001FA688 /* TupleView.swift */, + 5236C34226CDC2F4007432E1 /* UnaryViewAdaptor.swift */, F6D933B22385ED1400358E0E /* VSplitView.swift */, F60EEBC92382EED0007DB53A /* VStack.swift */, F60EEBC12382EED0007DB53A /* ZStack.swift */, @@ -1024,6 +1027,7 @@ F6C15ADD254F26B9000240F1 /* StyleConfiguration.swift in Sources */, F639DBC323A7DDA2003A6FED /* TouchBar.swift in Sources */, 52507626264FC0F400ADE4E7 /* Alert.swift in Sources */, + 5236C34326CDC2F4007432E1 /* UnaryViewAdaptor.swift in Sources */, 5223540226D63B7A008DA52F /* Toolbar.swift in Sources */, F60EEBD32382EED0007DB53A /* ZStack.swift in Sources */, 5214802B25F803B7002D974D /* CustomStyleModifiers.swift in Sources */, From 2bf11d907bec90f9458b514a8bf6c5ea02561462 Mon Sep 17 00:00:00 2001 From: Alexey Naumov Date: Sun, 19 Sep 2021 23:27:22 +0300 Subject: [PATCH 97/99] Add a test for UnaryViewAdaptor --- .../SwiftUI/EnvironmentReaderViewTests.swift | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Tests/ViewInspectorTests/SwiftUI/EnvironmentReaderViewTests.swift b/Tests/ViewInspectorTests/SwiftUI/EnvironmentReaderViewTests.swift index 962f9eac..9687491b 100644 --- a/Tests/ViewInspectorTests/SwiftUI/EnvironmentReaderViewTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/EnvironmentReaderViewTests.swift @@ -6,6 +6,12 @@ import SwiftUI @available(iOS 13.0, tvOS 13.0, *) final class EnvironmentReaderViewTests: XCTestCase { + func testUnaryViewAdaptor() throws { + let sut = EmptyView() + .navigationBarItems(trailing: Text("abc")) + XCTAssertNoThrow(try sut.inspect().emptyView()) + } + func skipForiOS15(file: StaticString = #file, line: UInt = #line) throws { if #available(iOS 15.0, tvOS 15.0, *) { throw XCTSkip("Not relevant for iOS 15", file: file, line: line) From 21a2cc2ea5a1205ea5820a32f1356f4e47212880 Mon Sep 17 00:00:00 2001 From: Alexey Naumov Date: Sun, 19 Sep 2021 23:27:37 +0300 Subject: [PATCH 98/99] Remove outdated code for popover --- Sources/ViewInspector/Inspector.swift | 3 --- 1 file changed, 3 deletions(-) diff --git a/Sources/ViewInspector/Inspector.swift b/Sources/ViewInspector/Inspector.swift index 424197ba..4da98e60 100644 --- a/Sources/ViewInspector/Inspector.swift +++ b/Sources/ViewInspector/Inspector.swift @@ -229,9 +229,6 @@ internal extension Inspector { Please insert '.navigationBarItems()' before \(inspectionCall) \ for unwrapping the underlying view hierarchy. """) - } else if typeWithParams.contains("_AnchorWritingModifier") { - throw InspectionError.notSupported( - "Unwrapping the view under popover is not supported on iOS 14.0 and 14.1") } } if namespacedPrefixes.contains(typePrefix) { From b2b591ead8c9f2072068ac8370a56923a492983e Mon Sep 17 00:00:00 2001 From: Alexey Naumov Date: Mon, 20 Sep 2021 00:26:26 +0300 Subject: [PATCH 99/99] Disable UnaryViewAdaptor test prior to iOS 15 --- .../SwiftUI/EnvironmentReaderViewTests.swift | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/Tests/ViewInspectorTests/SwiftUI/EnvironmentReaderViewTests.swift b/Tests/ViewInspectorTests/SwiftUI/EnvironmentReaderViewTests.swift index 9687491b..b35cef07 100644 --- a/Tests/ViewInspectorTests/SwiftUI/EnvironmentReaderViewTests.swift +++ b/Tests/ViewInspectorTests/SwiftUI/EnvironmentReaderViewTests.swift @@ -6,18 +6,19 @@ import SwiftUI @available(iOS 13.0, tvOS 13.0, *) final class EnvironmentReaderViewTests: XCTestCase { - func testUnaryViewAdaptor() throws { - let sut = EmptyView() - .navigationBarItems(trailing: Text("abc")) - XCTAssertNoThrow(try sut.inspect().emptyView()) - } - func skipForiOS15(file: StaticString = #file, line: UInt = #line) throws { if #available(iOS 15.0, tvOS 15.0, *) { throw XCTSkip("Not relevant for iOS 15", file: file, line: line) } } + func testUnaryViewAdaptor() throws { + guard #available(iOS 15.0, tvOS 15.0, *) else { return } + let sut = EmptyView() + .navigationBarItems(trailing: Text("abc")) + XCTAssertNoThrow(try sut.inspect().emptyView()) + } + func testIncorrectUnwrap() throws { try skipForiOS15() let view = NavigationView {