diff --git a/Sources/SafeDICore/Generators/DependencyTreeGenerator.swift b/Sources/SafeDICore/Generators/DependencyTreeGenerator.swift index d9a2c6af..1e2c7f0f 100644 --- a/Sources/SafeDICore/Generators/DependencyTreeGenerator.swift +++ b/Sources/SafeDICore/Generators/DependencyTreeGenerator.swift @@ -100,7 +100,7 @@ public actor DependencyTreeGenerator { // Create mock-root ScopeGenerators using the production Scope tree. var seen = Set() return try await withThrowingTaskGroup( - of: GeneratedRoot?.self, + of: GeneratedRoot.self, returning: [GeneratedRoot].self, ) { taskGroup in for instantiable in typeDescriptionToFulfillingInstantiableMap.values @@ -134,7 +134,6 @@ public actor DependencyTreeGenerator { mockConditionalCompilation: mockConditionalCompilation, )), ) - guard !code.isEmpty else { return nil } return GeneratedRoot( typeDescription: instantiable.concreteInstantiable, sourceFilePath: instantiable.sourceFilePath, @@ -144,9 +143,7 @@ public actor DependencyTreeGenerator { } var generatedRoots = [GeneratedRoot]() for try await generatedRoot in taskGroup { - if let generatedRoot { - generatedRoots.append(generatedRoot) - } + generatedRoots.append(generatedRoot) } return generatedRoots } diff --git a/Sources/SafeDICore/Models/Property.swift b/Sources/SafeDICore/Models/Property.swift index 2267de75..e5569e26 100644 --- a/Sources/SafeDICore/Models/Property.swift +++ b/Sources/SafeDICore/Models/Property.swift @@ -89,13 +89,11 @@ public struct Property: Codable, Hashable, Comparable, Sendable { name: "escaping", trailingTrivia: .space, )) - if let attributes { - for attribute in attributes { - AttributeSyntax( - attributeName: IdentifierTypeSyntax(name: .identifier(attribute)), - trailingTrivia: .space, - ) - } + for attribute in attributes { + AttributeSyntax( + attributeName: IdentifierTypeSyntax(name: .identifier(attribute)), + trailingTrivia: .space, + ) } }, baseType: IdentifierTypeSyntax(name: .identifier(typeDescription.asSource)), diff --git a/Sources/SafeDICore/Models/TypeDescription.swift b/Sources/SafeDICore/Models/TypeDescription.swift index 3e37ba57..ef29ade2 100644 --- a/Sources/SafeDICore/Models/TypeDescription.swift +++ b/Sources/SafeDICore/Models/TypeDescription.swift @@ -41,7 +41,7 @@ public enum TypeDescription: Codable, Hashable, Comparable, Sendable { /// A meta type. e.g. `Int.Type` or `Equatable.Protocol` indirect case metatype(TypeDescription, isType: Bool) /// A type identifier with a specifier or attributes. e.g. `inout Int` or `@autoclosure () -> Void` - indirect case attributed(TypeDescription, specifiers: [String]?, attributes: [String]?) + indirect case attributed(TypeDescription, specifiers: [String], attributes: [String]) /// An array. e.g. [Int] indirect case array(element: TypeDescription) /// A dictionary. e.g. [Int: String] @@ -128,28 +128,13 @@ public enum TypeDescription: Codable, Hashable, Comparable, Sendable { case let .any(type): return "any \(type.wrappedIfAmbiguous.asSource)" case let .attributed(type, specifiers, attributes): - func attributesFromList(_ attributes: [String]) -> String { - attributes - .map { "@\($0)" } - .joined(separator: " ") - } - return switch (specifiers, attributes) { - case let (.some(specifiers), .none): - "\(specifiers.joined(separator: " ")) \(type.asSource)" - case let (.none, .some(attributes)): - "\(attributesFromList(attributes)) \(type.asSource)" - case let (.some(specifiers), .some(attributes)): - // This case likely represents an error. - // We are unaware of type reference that compiles with both a specifier and attributes. - // The Swift reference manual specifies that attributes come before the specifier, - // however code that puts an attribute first does not parse as AttributedTypeSyntax. - // Only code where the specifier comes before the attribute parses as an AttributedTypeSyntax. - // As a result, we construct this source with the specifier first. - // Reference manual: https://docs.swift.org/swift-book/ReferenceManual/Types.html#grammar_type - "\(specifiers.joined(separator: " ")) \(attributesFromList(attributes)) \(type.asSource)" - case (.none, .none): - type.asSource // This case represents an error. - } + // Specifiers come before attributes per the Swift reference manual: + // https://docs.swift.org/swift-book/ReferenceManual/Types.html#grammar_type + let prefix = [ + specifiers.isEmpty ? nil : specifiers.joined(separator: " "), + attributes.isEmpty ? nil : attributes.map { "@\($0)" }.joined(separator: " "), + ].compactMap(\.self).joined(separator: " ") + return "\(prefix) \(type.asSource)" case let .array(element): return "[\(element.asSource)]" case let .dictionary(key, value): @@ -251,16 +236,12 @@ public enum TypeDescription: Codable, Hashable, Comparable, Sendable { .void: self case .closure: - .attributed(self, specifiers: nil, attributes: ["escaping"]) - case let .attributed(type, specifiers: specifiers, attributes: attributes): - if let attributes { - if attributes.contains(where: { $0 == "escaping" }) { - .attributed(type, specifiers: specifiers, attributes: attributes) - } else { - .attributed(type, specifiers: specifiers, attributes: ["escaping"] + attributes) - } + .attributed(self, specifiers: [], attributes: ["escaping"]) + case let .attributed(type, specifiers, attributes): + if attributes.contains(where: { $0 == "escaping" }) { + .attributed(type, specifiers: specifiers, attributes: attributes) } else { - .attributed(type, specifiers: specifiers, attributes: ["escaping"]) + .attributed(type, specifiers: specifiers, attributes: ["escaping"] + attributes) } } } @@ -351,12 +332,9 @@ public enum TypeDescription: Codable, Hashable, Comparable, Sendable { case let .metatype(type, isType): return "\(type.asIdentifier)_\(isType ? "Type" : "Protocol")" case let .attributed(type, specifiers, attributes): - // .attributed always has at least one non-nil specifier or attribute - // (the parser sets nil-if-empty, and all programmatic constructors - // ensure at least one is present). let prefix = [ - specifiers?.joined(separator: "_"), - attributes?.joined(separator: "_"), + specifiers.isEmpty ? nil : specifiers.joined(separator: "_"), + attributes.isEmpty ? nil : attributes.joined(separator: "_"), ].compactMap(\.self).joined(separator: "_") return "\(prefix)_\(type.asIdentifier)" case let .array(element): @@ -380,11 +358,11 @@ public enum TypeDescription: Codable, Hashable, Comparable, Sendable { public var strippingEscaping: TypeDescription { switch self { case let .attributed(type, specifiers, attributes): - let filtered = attributes?.filter { $0 != "escaping" } - if let filtered, !filtered.isEmpty { + let filtered = attributes.filter { $0 != "escaping" } + if !filtered.isEmpty { return .attributed(type, specifiers: specifiers, attributes: filtered) - } else if let specifiers, !specifiers.isEmpty { - return .attributed(type, specifiers: specifiers, attributes: nil) + } else if !specifiers.isEmpty { + return .attributed(type, specifiers: specifiers, attributes: []) } else { return type } @@ -581,8 +559,8 @@ extension TypeSyntax { } return .attributed( typeIdentifier.baseType.typeDescription, - specifiers: typeIdentifier.specifiers.textRepresentation, - attributes: attributes.isEmpty ? nil : attributes, + specifiers: typeIdentifier.specifiers.textRepresentation ?? [], + attributes: attributes, ) } else if let typeIdentifier = ArrayTypeSyntax(self) { @@ -662,19 +640,19 @@ extension ExprSyntax { } else if let genericExpr = GenericSpecializationExprSyntax(self) { let genericTypeVisitor = GenericArgumentVisitor(viewMode: .sourceAccurate) genericTypeVisitor.walk(genericExpr.genericArgumentClause) - return switch genericExpr.expression.typeDescription { - case let .simple(name, _): - .simple( - name: name, + if let declReferenceExpr = DeclReferenceExprSyntax(genericExpr.expression) { + return .simple( + name: declReferenceExpr.baseName.text, generics: genericTypeVisitor.genericArguments, ) - case let .nested(name, parentType, _): - .nested( - name: name, - parentType: parentType, generics: genericTypeVisitor.genericArguments, + } else if let memberAccessExpr = MemberAccessExprSyntax(genericExpr.expression), + let base = memberAccessExpr.base + { + return .nested( + name: memberAccessExpr.declName.baseName.text, + parentType: base.typeDescription, + generics: genericTypeVisitor.genericArguments, ) - case .any, .array, .attributed, .closure, .composition, .dictionary, .implicitlyUnwrappedOptional, .metatype, .optional, .some, .tuple, .unknown, .void: - .unknown(text: trimmedDescription) } } else if let tupleExpr = TupleExprSyntax(self) { let tupleElements = tupleExpr.elements diff --git a/Sources/SafeDIMacros/Macros/InstantiableMacro.swift b/Sources/SafeDIMacros/Macros/InstantiableMacro.swift index e7eb3141..abf16923 100644 --- a/Sources/SafeDIMacros/Macros/InstantiableMacro.swift +++ b/Sources/SafeDIMacros/Macros/InstantiableMacro.swift @@ -1317,14 +1317,14 @@ extension TypeDescription { ) || self == .attributed( .simple(name: "Instantiable"), - specifiers: nil, + specifiers: [], attributes: ["retroactive"], ) || self == .nested( name: "Instantiable", parentType: .attributed( .simple(name: "SafeDI"), - specifiers: nil, + specifiers: [], attributes: ["retroactive"], ), ) diff --git a/Sources/SafeDITool/SafeDITool.swift b/Sources/SafeDITool/SafeDITool.swift index 79fde77f..4a804b0d 100644 --- a/Sources/SafeDITool/SafeDITool.swift +++ b/Sources/SafeDITool/SafeDITool.swift @@ -24,6 +24,7 @@ import SafeDICore import SwiftParser @main +@available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) struct SafeDITool: AsyncParsableCommand { // MARK: Arguments @@ -507,24 +508,24 @@ struct SafeDITool: AsyncParsableCommand { } extension Data { + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) fileprivate func write(toPath filePath: String) throws { try write(to: filePath.asFileURL) } } extension String { + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) fileprivate func write(toPath filePath: String) throws { try Data(utf8).write(toPath: filePath) } + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) fileprivate var asFileURL: URL { #if os(Linux) - return URL(fileURLWithPath: self) + URL(fileURLWithPath: self) #else - guard #available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) else { - return URL(fileURLWithPath: self) - } - return URL(filePath: self) + URL(filePath: self) #endif } } diff --git a/Tests/SafeDICoreTests/TypeDescriptionTests.swift b/Tests/SafeDICoreTests/TypeDescriptionTests.swift index 4e4fd275..cd308998 100644 --- a/Tests/SafeDICoreTests/TypeDescriptionTests.swift +++ b/Tests/SafeDICoreTests/TypeDescriptionTests.swift @@ -472,6 +472,19 @@ struct TypeDescriptionTests { #expect(typeDescription.asSource == "(Int, Double) throws -> String") } + @Test + func typeDescription_whenCalledOnATypeSyntaxNodeRepresentingASuppressedTypeSyntax_returnsUnknown() throws { + let content = """ + var test: ~Copyable + """ + + let visitor = SuppressedTypeSyntaxVisitor(viewMode: .sourceAccurate) + visitor.walk(Parser.parse(source: content)) + let typeDescription = try #require(visitor.suppressedTypeIdentifier) + #expect(typeDescription.isUnknown) + #expect(typeDescription.asSource == "~Copyable") + } + @Test func typeDescription_whenCalledOnAExprSyntaxNodeRepresentingAVoidType_findsTheType() throws { let content = """ @@ -655,6 +668,18 @@ struct TypeDescriptionTests { #expect(typeDescription.asSource == "() -> ()") } + @Test + func typeDescription_whenCalledOnAExprSyntaxNodeRepresentingAClosureTypeWithArguments_findsTheType() throws { + let content = """ + let test: Any.Type = ((Int, String) -> Bool).self + """ + let visitor = MemberAccessExprSyntaxVisitor(viewMode: .sourceAccurate) + visitor.walk(Parser.parse(source: content)) + let typeDescription = try #require(visitor.typeDescription) + #expect(!typeDescription.isUnknown, "Type description is not of known type!") + #expect(typeDescription.asSource == "(Int, String) -> Bool") + } + @Test func typeDescription_whenCalledOnAExprSyntaxNodeRepresentingAThrowingClosureType_findsTheType() throws { let content = """ @@ -738,7 +763,7 @@ struct TypeDescriptionTests { doesThrow: false, returnType: .void(.identifier), ), - specifiers: nil, + specifiers: [], attributes: ["autoclosure", "escaping"], ).asFunctionParameter == TypeDescription.attributed( .closure( @@ -747,7 +772,7 @@ struct TypeDescriptionTests { doesThrow: false, returnType: .void(.identifier), ), - specifiers: nil, + specifiers: [], attributes: ["autoclosure", "escaping"], )) } @@ -761,7 +786,7 @@ struct TypeDescriptionTests { doesThrow: false, returnType: .void(.identifier), ), - specifiers: nil, + specifiers: [], attributes: ["escaping", "autoclosure"], ).asFunctionParameter == TypeDescription.attributed( .closure( @@ -770,7 +795,7 @@ struct TypeDescriptionTests { doesThrow: false, returnType: .void(.identifier), ), - specifiers: nil, + specifiers: [], attributes: ["escaping", "autoclosure"], )) } @@ -796,7 +821,7 @@ struct TypeDescriptionTests { returnType: .void(.tuple), ), specifiers: ["borrowing"], - attributes: nil, + attributes: [], )) } @@ -809,8 +834,8 @@ struct TypeDescriptionTests { doesThrow: false, returnType: .void(.identifier), ), - specifiers: nil, - attributes: nil, + specifiers: [], + attributes: [], ).asFunctionParameter == TypeDescription.attributed( .closure( arguments: [.void(.tuple)], @@ -818,7 +843,7 @@ struct TypeDescriptionTests { doesThrow: false, returnType: .void(.identifier), ), - specifiers: nil, + specifiers: [], attributes: ["escaping"], )) } @@ -857,13 +882,13 @@ struct TypeDescriptionTests { @Test func simplified_stripsAttributes() { - let type = TypeDescription.attributed(.simple(name: "Int"), specifiers: ["inout"], attributes: nil) + let type = TypeDescription.attributed(.simple(name: "Int"), specifiers: ["inout"], attributes: []) #expect(type.simplified == .simple(name: "Int")) } @Test func simplified_stripsNestedWrappers() { - let type = TypeDescription.optional(.attributed(.some(.simple(name: "Service")), specifiers: nil, attributes: ["Sendable"])) + let type = TypeDescription.optional(.attributed(.some(.simple(name: "Service")), specifiers: [], attributes: ["Sendable"])) #expect(type.simplified == .simple(name: "Service")) } @@ -1522,6 +1547,14 @@ struct TypeDescriptionTests { } } + private final class SuppressedTypeSyntaxVisitor: SyntaxVisitor { + var suppressedTypeIdentifier: TypeDescription? + override func visit(_ node: SuppressedTypeSyntax) -> SyntaxVisitorContinueKind { + suppressedTypeIdentifier = TypeSyntax(node).typeDescription + return .skipChildren + } + } + private final class MemberAccessExprSyntaxVisitor: SyntaxVisitor { var typeDescription: TypeDescription? override func visit(_ node: MemberAccessExprSyntax) -> SyntaxVisitorContinueKind { diff --git a/Tests/SafeDIToolTests/Helpers/SafeDIToolTestExecution.swift b/Tests/SafeDIToolTests/Helpers/SafeDIToolTestExecution.swift index fab3ae92..757d838b 100644 --- a/Tests/SafeDIToolTests/Helpers/SafeDIToolTestExecution.swift +++ b/Tests/SafeDIToolTests/Helpers/SafeDIToolTestExecution.swift @@ -24,6 +24,7 @@ import SafeDIRootScannerCore import Testing @testable import SafeDITool +@available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) func executeSafeDIToolTest( swiftFileContent: [String], additionalDirectorySwiftFileContent: [String] = [], @@ -185,6 +186,7 @@ func executeSafeDIToolTest( } } +@available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) struct TestOutput { let moduleInfo: SafeDITool.ModuleInfo let moduleInfoOutputPath: String diff --git a/Tests/SafeDIToolTests/SafeDIToolCodeGenerationErrorTests.swift b/Tests/SafeDIToolTests/SafeDIToolCodeGenerationErrorTests.swift index 6d753393..326193a0 100644 --- a/Tests/SafeDIToolTests/SafeDIToolCodeGenerationErrorTests.swift +++ b/Tests/SafeDIToolTests/SafeDIToolCodeGenerationErrorTests.swift @@ -39,6 +39,7 @@ struct SafeDIToolCodeGenerationErrorTests: ~Copyable { // MARK: Error Tests @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_onCodeWithPropertyWithUnknownFulfilledType_throwsError() async { await assertThrowsError( """ @@ -64,6 +65,7 @@ struct SafeDIToolCodeGenerationErrorTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_onCodeWithPropertyWithUnknownTypeWithDotSuffixOfFulfillableType_throwsError() async { await assertThrowsError( """ @@ -110,6 +112,7 @@ struct SafeDIToolCodeGenerationErrorTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_onCodeWithPropertyWithUnknownTypeWithDotPrefixOfFulfillableType_throwsError() async { await assertThrowsError( """ @@ -156,6 +159,7 @@ struct SafeDIToolCodeGenerationErrorTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_onCodeWithMultipleInstantiateMethodsForTheSameTypeWithSameParameters_throwsError() async { await assertThrowsError( """ @@ -191,6 +195,7 @@ struct SafeDIToolCodeGenerationErrorTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_onCodeWithMultipleInstantiateMethodsForTheSameTypeWithDifferentParameters_throwsError() async { await assertThrowsError( """ @@ -226,6 +231,7 @@ struct SafeDIToolCodeGenerationErrorTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_onCodeWithUnfulfillableInstantiatedProperty_throwsError() async { await assertThrowsError( """ @@ -260,6 +266,7 @@ struct SafeDIToolCodeGenerationErrorTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_onCodeWithUnfulfillableReceivedProperty_throwsError() async { await assertThrowsError( """ @@ -295,6 +302,7 @@ struct SafeDIToolCodeGenerationErrorTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_onCodeWithUnfulfillableInstantiatedPropertyDueToUnexpectedAny_throwsError() async { await assertThrowsError( """ @@ -340,6 +348,7 @@ struct SafeDIToolCodeGenerationErrorTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_onCodeWithUnfulfillableInstantiatedPropertyDueToDroppedAny_throwsError() async { await assertThrowsError( """ @@ -385,6 +394,7 @@ struct SafeDIToolCodeGenerationErrorTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_onCodeWithUnfulfillableInstantiatedPropertyDueToUnexpectedForceUnwrap_throwsError() async { await assertThrowsError( """ @@ -428,6 +438,7 @@ struct SafeDIToolCodeGenerationErrorTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_onCodeWithUnfulfillableInstantiatedPropertyDueToDroppedForceUnwrap_throwsError() async { await assertThrowsError( """ @@ -471,6 +482,7 @@ struct SafeDIToolCodeGenerationErrorTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_onCodeWithUnfulfillableInstantiatedPropertyDueToUnexpectedOptional_throwsError() async { await assertThrowsError( """ @@ -513,6 +525,7 @@ struct SafeDIToolCodeGenerationErrorTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_onCodeWithUnfulfillableInstantiatedPropertyDueToDroppedOptional_throwsError() async { await assertThrowsError( """ @@ -556,6 +569,7 @@ struct SafeDIToolCodeGenerationErrorTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_onCodeWithUnfulfillableInstantiatedPropertyDueToIncorrectType_throwsError() async { await assertThrowsError( """ @@ -602,6 +616,7 @@ struct SafeDIToolCodeGenerationErrorTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_onCodeWithUnfulfillableInstantiatedPropertyDueToIncorrectTypeOrLabel_throwsError() async { await assertThrowsError( """ @@ -650,6 +665,7 @@ struct SafeDIToolCodeGenerationErrorTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_onCodeWithInstantiatedPropertyWithForwardedArgument_throwsError() async { await assertThrowsError( """ @@ -684,6 +700,7 @@ struct SafeDIToolCodeGenerationErrorTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_onCodeWithDiamondDependencyWhereAReceivedPropertyIsUnfulfillableOnOneBranch_throwsError() async { await assertThrowsError( """ @@ -731,6 +748,7 @@ struct SafeDIToolCodeGenerationErrorTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_onCodeWithDiamondDependencyWhereMultipleReceivedPropertiesAreUnfulfillableOnOneBranch_throwsError() async { await assertThrowsError( """ @@ -788,6 +806,7 @@ struct SafeDIToolCodeGenerationErrorTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_onCodeWithInstantiatedPropertyThatRefersToCurrentInstantiable_throwsError() async { await assertThrowsError( """ @@ -846,6 +865,7 @@ struct SafeDIToolCodeGenerationErrorTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_onCodeWithReceivedPropertyThatRefersToCurrentInstantiable_throwsError() async { await assertThrowsError( """ @@ -904,6 +924,7 @@ struct SafeDIToolCodeGenerationErrorTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_onCodeWithUnfulfillableAliasedReceivedPropertyName_throwsError() async { await assertThrowsError( """ @@ -958,6 +979,7 @@ struct SafeDIToolCodeGenerationErrorTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_onCodeWithUnfulfillableAliasedReceivedPropertyType_throwsError() async { await assertThrowsError( """ @@ -1012,6 +1034,7 @@ struct SafeDIToolCodeGenerationErrorTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_onCodeWhereAliasedReceivedPropertyRefersToCurrentInstantiable_throwsError() async { await assertThrowsError( """ @@ -1070,6 +1093,7 @@ struct SafeDIToolCodeGenerationErrorTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_onCodeWithUnfulfillableReceivedPropertyOnExtendedInstantiatedType_throwsError() async { await assertThrowsError( """ @@ -1105,6 +1129,7 @@ struct SafeDIToolCodeGenerationErrorTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_onCodeWithDuplicateInstantiableNames_throwsError() async { await assertThrowsError( """ @@ -1133,6 +1158,7 @@ struct SafeDIToolCodeGenerationErrorTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_onCodeWithDuplicateInstantiableNamesWhereOneIsRoot_throwsError() async { await assertThrowsError( """ @@ -1161,6 +1187,7 @@ struct SafeDIToolCodeGenerationErrorTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_onCodeWithDuplicateInstantiableNamesViaDeclarationAndExtension_throwsError() async { await assertThrowsError( """ @@ -1193,6 +1220,7 @@ struct SafeDIToolCodeGenerationErrorTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_onCodeWithDuplicateInstantiableNamesViaDeclarationAndExtensionWhereDeclarationIsRoot_throwsError() async { await assertThrowsError( """ @@ -1225,6 +1253,7 @@ struct SafeDIToolCodeGenerationErrorTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_onCodeWithDuplicateInstantiableNamesViaDeclarationAndExtensionWhereExtensionIsRoot_throwsError() async { await assertThrowsError( """ @@ -1257,6 +1286,7 @@ struct SafeDIToolCodeGenerationErrorTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_onCodeWithDuplicateInstantiableNamesViaExtension_throwsError() async { await assertThrowsError( """ @@ -1293,6 +1323,7 @@ struct SafeDIToolCodeGenerationErrorTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_onCodeWithDuplicateInstantiableFulfillment_throwsError() async { await assertThrowsError( """ @@ -1321,6 +1352,7 @@ struct SafeDIToolCodeGenerationErrorTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_onCodeWithCircularPropertyDependenciesImmediatelyInitialized_throwsError() async { await assertThrowsError( """ @@ -1362,6 +1394,7 @@ struct SafeDIToolCodeGenerationErrorTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_onCodeWithCircularPropertyDependenciesImmediatelyInitializedWithMixOfReceivedAndInstantiated_throwsError() async { await assertThrowsError( """ @@ -1401,6 +1434,7 @@ struct SafeDIToolCodeGenerationErrorTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_onCodeWithCircularPropertyDependenciesImmediatelyInitializedAndReceived_throwsError() async { await assertThrowsError( """ @@ -1442,6 +1476,7 @@ struct SafeDIToolCodeGenerationErrorTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_onCodeWithCircularPropertyDependenciesLazyInitializedAndReceived_throwsError() async { await assertThrowsError( """ @@ -1483,6 +1518,7 @@ struct SafeDIToolCodeGenerationErrorTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_onCodeWithCircularPropertyDependenciesLazyInitializedAndOnlyIfAvailableReceived_throwsError() async { await assertThrowsError( """ @@ -1524,6 +1560,7 @@ struct SafeDIToolCodeGenerationErrorTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_onCodeWithCircularPropertyDependenciesImmediatelyInitializedWithVaryingNames_throwsError() async { await assertThrowsError( """ @@ -1565,6 +1602,7 @@ struct SafeDIToolCodeGenerationErrorTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_onCodeWithCircularReceivedDependencies_throwsError() async { await assertThrowsError( """ @@ -1608,6 +1646,7 @@ struct SafeDIToolCodeGenerationErrorTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_onCodeWithCircularReceivedRenamedDependencies_throwsError() async { await assertThrowsError( """ @@ -1652,6 +1691,7 @@ struct SafeDIToolCodeGenerationErrorTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_onCodeWithMultipleCircularReceivedRenamedDependencies_throwsError() async { await assertThrowsError( """ @@ -1695,6 +1735,7 @@ struct SafeDIToolCodeGenerationErrorTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_OnCodeWithOptionalPropertyAliasAndMarkedOnlyIfAvailableAndItIsOnlyAvialableViaCircularDependency_throws_error() async { await assertThrowsError( """ @@ -1752,6 +1793,7 @@ struct SafeDIToolCodeGenerationErrorTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_onCodeWithIncorrectErasedInstantiatorFirstGeneric_whenInstantiableHasSingleForwardedProperty_throwsError() async { await assertThrowsError( """ @@ -1833,6 +1875,7 @@ struct SafeDIToolCodeGenerationErrorTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_onCodeWithIncorrectErasedInstantiatorFirstGeneric_whenInstantiableHasMultipleForwardedProperty_throwsError() async { await assertThrowsError( """ @@ -1918,6 +1961,7 @@ struct SafeDIToolCodeGenerationErrorTests: ~Copyable { // MARK: Argument handling error tests @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) func include_throwsErrorWhenCanNotCreateEnumerator() async { final class FailingFileFinder: FileFinder { func enumerator( @@ -1946,6 +1990,7 @@ struct SafeDIToolCodeGenerationErrorTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) func include_throwsErrorWhenNoSwiftSourcesFilePathAndNoInclude() async { var tool = SafeDITool() tool.swiftSourcesFilePath = nil @@ -1964,6 +2009,7 @@ struct SafeDIToolCodeGenerationErrorTests: ~Copyable { // MARK: Manifest Validation Tests @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_throwsError_whenManifestListsFileThatDoesNotContainRoot() async throws { let swiftFile = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(UUID().uuidString + ".swift") try """ @@ -1999,6 +2045,7 @@ struct SafeDIToolCodeGenerationErrorTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_throwsError_whenRootExistsButNotInManifest() async throws { let swiftFile = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(UUID().uuidString + ".swift") try """ @@ -2038,6 +2085,7 @@ struct SafeDIToolCodeGenerationErrorTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_onCodeWithMultipleSafeDIConfigurations_throwsError() async { do { _ = try await executeSafeDIToolTest( diff --git a/Tests/SafeDIToolTests/SafeDIToolCodeGenerationTests.swift b/Tests/SafeDIToolTests/SafeDIToolCodeGenerationTests.swift index d7256a2f..9944dd5e 100644 --- a/Tests/SafeDIToolTests/SafeDIToolCodeGenerationTests.swift +++ b/Tests/SafeDIToolTests/SafeDIToolCodeGenerationTests.swift @@ -39,6 +39,7 @@ struct SafeDIToolCodeGenerationTests: ~Copyable { // MARK: Code Generation Tests @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_successfullyGeneratesOutputFileWhenNoCodeInput() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [], @@ -50,6 +51,7 @@ struct SafeDIToolCodeGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_doesNotWriteExtensionIfRootAlreadyHasEmptyInitializer() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -74,6 +76,7 @@ struct SafeDIToolCodeGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesConvenienceExtensionOnRootOfTree_whenRootIsClass() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -123,6 +126,7 @@ struct SafeDIToolCodeGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesConvenienceExtensionOnRootOfTree_whenRootIsActor() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -172,6 +176,7 @@ struct SafeDIToolCodeGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesConvenienceExtensionOnRootOfTree_whenRootIsStruct() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -221,6 +226,7 @@ struct SafeDIToolCodeGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesConvenienceExtensionOnRootOfTree_whenMultipleRootsExist() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -297,6 +303,7 @@ struct SafeDIToolCodeGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesConvenienceExtensionOnRootOfTree_whenRootHasAnAnyProperty() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -348,6 +355,7 @@ struct SafeDIToolCodeGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesConvenienceExtensionOnRootOfTree_whenRootHasAnAnyPropertyFulfilledByAnyAdditionalType() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -397,6 +405,7 @@ struct SafeDIToolCodeGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesConvenienceExtensionOnRootOfTree_whenRootHasAnOptionalProperty() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -448,6 +457,7 @@ struct SafeDIToolCodeGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesConvenienceExtensionOnRootOfTree_whenRootHasMultipleLayers() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -555,6 +565,7 @@ struct SafeDIToolCodeGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesConvenienceExtensionOnRootOfTree_whenRootInstantiatesPropertiesThatUtilizesSingleForwardedPropertyInSubBuilders() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -674,6 +685,7 @@ struct SafeDIToolCodeGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesConvenienceExtensionOnRootOfTree_whenRootInstantiatesPropertiesThatUtilizesSingleEscapingForwardedProperty() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -729,6 +741,7 @@ struct SafeDIToolCodeGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesConvenienceExtensionOnRootOfTree_whenRootInstantiatesPropertiesThatUtilizeMultipleForwardedPropertiesInSubBuilders() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -856,6 +869,7 @@ struct SafeDIToolCodeGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesConvenienceExtensionOnRootOfTree_whenRootInstantiatesPropertiesThatUtilizeMultipleForwardedPropertiesAndDependencyInversionInSubBuilders() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -983,6 +997,7 @@ struct SafeDIToolCodeGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesConvenienceExtensionOnRootOfTree_whenRootInstantiatesPropertiesThatUtilizesDependencyInversionOfExistentialTypeInSubBuilder() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -1034,6 +1049,7 @@ struct SafeDIToolCodeGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesConvenienceExtensionOnRootOfTree_whenRootInstantiatesPropertiesThatUtilizesLazyDependencyInversionOfExistentialTypeInSubBuilder() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -1090,6 +1106,7 @@ struct SafeDIToolCodeGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesConvenienceExtensionOnRootOfTree_whenRootInstantiatesPropertiesThatUtilizePropertiesNotDirectlyProvidedByParent() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -1210,6 +1227,7 @@ struct SafeDIToolCodeGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesConvenienceExtensionOnRootOfTree_whenRootInstantiatesPropertiesWithMultipleLayersOfInstantiators() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -1332,6 +1350,7 @@ struct SafeDIToolCodeGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesConvenienceExtensionOnRootOfTree_whenRootInstantiatesPropertyWithMissingInstantiableInitializer() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -1385,6 +1404,7 @@ struct SafeDIToolCodeGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesConvenienceExtensionOnRootOfTree_whenRootInstantiatesPropertyWithInitializerWithDefaultArgumentForNonInjectedProperty() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -1441,6 +1461,7 @@ struct SafeDIToolCodeGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesConvenienceExtensionOnRootOfTree_whenRootInstantiatesPropertyWithNotPublicInstantiableInitializer() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -1494,6 +1515,7 @@ struct SafeDIToolCodeGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesConvenienceExtensionOnRootOfTree_whenRootInstantiatesNonPublicProperty() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -1547,6 +1569,7 @@ struct SafeDIToolCodeGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesConvenienceExtensionOnRootOfTree_whenRootInstantiatesPropertiesWithMultipleTreesThatReceiveTheSameProperty() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -1663,6 +1686,7 @@ struct SafeDIToolCodeGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesConvenienceExtensionOnRootOfTree_whenRootInstantiatesPropertiesWithMultipleTreesThatInstantiateTheSamePropertyInMiddleLevel() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -1781,6 +1805,7 @@ struct SafeDIToolCodeGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesConvenienceExtensionOnRootOfTree_whenRootInstantiatesPropertiesWithSingleTreeThatInstantiatesTheSamePropertyAtMultipleLevels() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -1863,6 +1888,7 @@ struct SafeDIToolCodeGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesConvenienceExtensionOnRootOfTree_whenRootInstantiatesPropertiesWithSingleTreeThatInstantiatesAReceivedPropertyBelowWhereItIsReceived() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -1947,6 +1973,7 @@ struct SafeDIToolCodeGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesConvenienceExtensionOnRootOfTree_whenRootInstantiatesPropertiesWithSingleTreeThatInstantiatesAReceivedPropertyMultipleLevelsBelowWhereItIsFirstReceived() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -2045,6 +2072,7 @@ struct SafeDIToolCodeGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesConvenienceExtensionOnRootOfTree_whenRootInstantiatesPropertiesWithSingleTreeThatInstantiatesAPropertyReceivedInOneChildBranchMultipleLevelsBelowWhereItIsFirstReceived() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -2163,6 +2191,7 @@ struct SafeDIToolCodeGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesConvenienceExtensionOnRootOfTree_whenRootInstantiatesAPropertyForwardedByAChild_doesNotRequirePuttingInstantiatedPropertyBeforeErasedInstantiator() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -2292,6 +2321,7 @@ struct SafeDIToolCodeGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesConvenienceExtensionOnRootOfTree_whenRootInstantiatesPropertiesWithMultipleTreesThatInstantiateTheSamePropertyMultipleLayersDeep() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -2422,6 +2452,7 @@ struct SafeDIToolCodeGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesConvenienceExtensionOnRootOfTree_whenRootInstantiatesInstantiablePropertyWithNoArguments() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -2493,6 +2524,7 @@ struct SafeDIToolCodeGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesConvenienceExtensionOnRootOfTree_whenRootInstantiatesInstantiablePropertyWithArguments() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -2623,6 +2655,7 @@ struct SafeDIToolCodeGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesConvenienceExtensionOnRootOfTree_whenRootInstantiatesPropertiesWithMultipleTreesThatInstantiateTheSamePropertyAcrossMultipleModules() async throws { let greatGrandchildModuleOutput = try await executeSafeDIToolTest( swiftFileContent: [ @@ -2816,6 +2849,7 @@ struct SafeDIToolCodeGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesConvenienceExtensionOnRootOfTree_whenRootHasReceivedAliasOfInstantiable() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -2870,6 +2904,7 @@ struct SafeDIToolCodeGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_successfullyGeneratesOutputFileWhenNoRootFound() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -2890,6 +2925,7 @@ struct SafeDIToolCodeGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_successfullyGeneratesOutputFileWhenNoRootFoundAndAdditionalImportedModulesSet() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -2912,6 +2948,7 @@ struct SafeDIToolCodeGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_successfullyGeneratesOutputFileWhenIsRootIsFalse() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -2932,6 +2969,7 @@ struct SafeDIToolCodeGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesConvenienceExtensionOnRootOfTree_whenReceivedPropertyIsAliased() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -3088,6 +3126,7 @@ struct SafeDIToolCodeGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesConvenienceExtensionOnRootOfTree_whenReceivedPropertyIsAliasedAndExistential() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -3152,6 +3191,7 @@ struct SafeDIToolCodeGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesConvenienceExtensionOnRootOfTree_whenReceivedPropertyIsAliasedALevelAboveWhereItIsReceived() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -3312,6 +3352,7 @@ struct SafeDIToolCodeGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesConvenienceExtensionOnRootOfTree_whenReceivedPropertyIsAliasedWhenInstantiated() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -3388,6 +3429,7 @@ struct SafeDIToolCodeGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesConvenienceExtensionOnRootOfTree_whenReceivedPropertyIsAliasedTwice() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -3469,6 +3511,7 @@ struct SafeDIToolCodeGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesConvenienceExtensionOnRootOfTree_whenReceivedPropertyIsAliasedWhenForwarded() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -3625,6 +3668,7 @@ struct SafeDIToolCodeGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesConvenienceExtensionOnRootOfTree_whenReceivedPropertyIsAliasedWasALevelBelowWhereItWasForwarded() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -3779,6 +3823,7 @@ struct SafeDIToolCodeGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesConvenienceExtensionOnRootOfTree_whenFirstPropertyDependsOnLastPropertyAndMiddlePropertyHasNoDependencyEntanglementsWithEither() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -3852,6 +3897,7 @@ struct SafeDIToolCodeGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesConvenienceExtensionOnRootOfTree_whenRootHasLotsOfDependenciesThatDependOnOneAnother() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -4235,6 +4281,7 @@ struct SafeDIToolCodeGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesConvenienceExtensionOnRootOfTree_whenRootPropertyWithOptionalInstantiator() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -4277,6 +4324,7 @@ struct SafeDIToolCodeGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesConvenienceExtensionOnRootOfTree_whenLazyInstantiationCycleExists() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -4352,6 +4400,7 @@ struct SafeDIToolCodeGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesConvenienceExtensionOnRootOfTree_whenPartiallyLazyInstantiationCycleExists() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -4427,6 +4476,7 @@ struct SafeDIToolCodeGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesConvenienceExtensionOnRootOfTree_whenLazySelfInstantiationCycleExists() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -4478,6 +4528,7 @@ struct SafeDIToolCodeGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesConvenienceExtensionOnRootOfTree_whenLazySelfForwardingInstantiationCycleExists() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -4530,6 +4581,7 @@ struct SafeDIToolCodeGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesConvenienceExtensionOnRootOfTree_whenAGenericTypeIsAnExtendedInstantiableWithMultipleGenericReturnTypes() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -4589,6 +4641,7 @@ struct SafeDIToolCodeGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesConvenienceExtensionOnRootOfTree_whenAGenericTypeIsAnExtendedInstantiableWithMultipleGenericFullyQualifiedReturnTypes() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -4648,6 +4701,7 @@ struct SafeDIToolCodeGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesConvenienceExtensionOnRootOfTree_whenTreeContainsNestedType() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -4706,6 +4760,7 @@ struct SafeDIToolCodeGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesConvenienceExtensionOnRootOfTree_whenTreeContainsNestedTypesWithNoQualification() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -4797,6 +4852,7 @@ struct SafeDIToolCodeGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesConvenienceExtensionOnRootOfTree_whenTreeContainsNestedTypesWithMixedQualification() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -4888,6 +4944,7 @@ struct SafeDIToolCodeGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesConvenienceExtensionOnRootOfTree_whenTreeContainsNestedTypesWithSameObjectReferencedWithDifferingQualification() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -4976,6 +5033,7 @@ struct SafeDIToolCodeGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesConvenienceExtensionOnRootOfTree_whenTreeContainsNestedTypeFulfillingAdditionalNestedTypes() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -5036,6 +5094,7 @@ struct SafeDIToolCodeGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesConvenienceExtensionOnRootOfTree_whenTreeContainsNestedTypeFulfillingAdditionalFullyQualifiedNestedTypes() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -5096,6 +5155,7 @@ struct SafeDIToolCodeGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesConvenienceExtensionOnRootOfTree_whenTypeIsFulfilledByNestedType() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -5139,6 +5199,7 @@ struct SafeDIToolCodeGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesConvenienceExtensionOnRootOfTree_whenTypeIsFulfilledByNestedTypeAndExtensionIsDefinedFirst() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -5190,6 +5251,7 @@ struct SafeDIToolCodeGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesConvenienceExtensionOnRootOfTree_whenPropertyIsOptionalAndMarkedOnlyIfAvailableAndItIsAvailable() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -5243,6 +5305,7 @@ struct SafeDIToolCodeGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesConvenienceExtensionOnRootOfTree_whenBothParentAndChildPropertyIsOptionalAndMarkedOnlyIfAvailableAndItIsAvailable() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -5296,6 +5359,7 @@ struct SafeDIToolCodeGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesConvenienceExtensionOnRootOfTree_whenPropertyIsOptionalAndMarkedOnlyIfAvailableAndItIsNotAvailable() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -5347,6 +5411,7 @@ struct SafeDIToolCodeGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesConvenienceExtensionOnRootOfTree_whenPropertyIsOptionalAndMarkedOnlyIfAvailableAndItIsAvailableBecauseAnotherDependencyBuildsIt() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -5414,6 +5479,7 @@ struct SafeDIToolCodeGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesConvenienceExtensionOnRootOfTree_whenPropertyIsOptionalAndMarkedOnlyIfAvailableAndItIsAvailableInOneBranch() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -5500,6 +5566,7 @@ struct SafeDIToolCodeGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesConvenienceExtensionOnRootOfTree_whenPropertyIsOptionalAndMarkedOnlyIfAvailableAndItIsOnlyAvialableViaCircularDependency() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -5571,6 +5638,7 @@ struct SafeDIToolCodeGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesConvenienceExtensionOnRootOfTree_whenPropertyAliasIsOptionalAndMarkedOnlyIfAvailableAndItIsNotAvailable() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -5626,6 +5694,7 @@ struct SafeDIToolCodeGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesConvenienceExtensionOnRootOfTree_whenPropertyAliasIsOptionalAndMarkedOnlyIfAvailableAndItIsAvailableBecauseAnotherDependencyBuildsIt() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -5697,6 +5766,7 @@ struct SafeDIToolCodeGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesConvenienceExtensionOnRootOfTree_whenPropertyAliasIsOptionalAndMarkedOnlyIfAvailableAndItIsAvailableInOneBranch() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -5788,6 +5858,7 @@ struct SafeDIToolCodeGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_doesNotWriteConvenienceExtensionOnRootOfTree_whenUnexpectedSwiftNodesAreEncountered() async throws { // If this test begins to fail after updating Swift, put the below code into an AST parser and see if unexpected nodes are still encountered. // The broken syntax must produce UnexpectedNodesSyntax at a level FileVisitor visits (class body, not inside function/variable bodies). @@ -5826,6 +5897,7 @@ struct SafeDIToolCodeGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesErrorToOutputFile_whenUnexpectedSwiftNodesAreEncounteredAndRootExists() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -5857,6 +5929,7 @@ struct SafeDIToolCodeGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesConvenienceExtensionOnRootOfTree_whenMultipleRootsExistInSameFile() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -5913,6 +5986,7 @@ struct SafeDIToolCodeGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesEmptyRootContent_whenRootHasNoDependencies() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -5939,6 +6013,7 @@ struct SafeDIToolCodeGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesDistinctManifestOutputs_whenRootFilesShareTheSameBasename() async throws { let rootDirectory = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(UUID().uuidString) let featureADirectory = rootDirectory.appendingPathComponent("FeatureA") @@ -6044,6 +6119,7 @@ struct SafeDIToolCodeGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_doesNotRewriteOutputFile_whenContentIsUnchanged() async throws { let swiftFile = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(UUID().uuidString + ".swift") try """ @@ -6108,6 +6184,7 @@ struct SafeDIToolCodeGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_generatesManifestOutputAndDOTFileSimultaneously() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -6143,6 +6220,7 @@ struct SafeDIToolCodeGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesConvenienceExtensionOnRootOfTree_whenInstantiatorClosureTransitivelyCapturesVariableDeclaredLaterAlphabetically() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -6213,6 +6291,7 @@ struct SafeDIToolCodeGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_successfullyGeneratesOutputFileWhenNoRootFoundAndAdditionalImportedModulesSetViaSourceConfiguration() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -6241,6 +6320,7 @@ struct SafeDIToolCodeGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_parsesAdditionalDirectoriesToIncludeFromSourceConfiguration() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -6265,6 +6345,7 @@ struct SafeDIToolCodeGenerationTests: ~Copyable { // MARK: Additional Directories + Manifest Tests @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_generatesOutputForRootInAdditionalDirectory() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -6314,6 +6395,7 @@ struct SafeDIToolCodeGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_generatesOutputForMultipleRootsInAdditionalDirectory() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -6374,6 +6456,7 @@ struct SafeDIToolCodeGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_generatesOutput_whenOnlyAdditionalDirectoryHasRoots() async throws { // No roots in the target, only in the additional directory. // The pre-scan discovers additional directories via @SafeDIConfiguration @@ -6414,6 +6497,7 @@ struct SafeDIToolCodeGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_generatesCorrectOutput_whenAdditionalDirectoryRootDependsOnTargetRootDependency() async throws { // The additional directory root has a dependency chain that shares // dependencies with the target root. Verifies the full dependency diff --git a/Tests/SafeDIToolTests/SafeDIToolDOTGenerationTests.swift b/Tests/SafeDIToolTests/SafeDIToolDOTGenerationTests.swift index 580cdbda..e5b0cddb 100644 --- a/Tests/SafeDIToolTests/SafeDIToolDOTGenerationTests.swift +++ b/Tests/SafeDIToolTests/SafeDIToolDOTGenerationTests.swift @@ -39,6 +39,7 @@ struct SafeDIToolDOTGenerationTests: ~Copyable { // MARK: DOT Generation Tests @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_successfullyGeneratesOutputFileWhenNoCodeInput() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [], @@ -55,6 +56,7 @@ struct SafeDIToolDOTGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesDOTTree_whenSingleRoot() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -88,6 +90,7 @@ struct SafeDIToolDOTGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesDOTTree_whenMultipleRootsExist() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -129,6 +132,7 @@ struct SafeDIToolDOTGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesDOTTree_whenRootHasMultipleLayers() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -212,6 +216,7 @@ struct SafeDIToolDOTGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesDOTTree_whenRootInstantiatesPropertiesThatUtilizesSingleForwardedPropertyInSubBuilders() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -304,6 +309,7 @@ struct SafeDIToolDOTGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesDOTTree_whenRootInstantiatesPropertiesThatUtilizeMultipleForwardedPropertiesInSubBuilders() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -404,6 +410,7 @@ struct SafeDIToolDOTGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesDOTTree_whenRootInstantiatesPropertiesThatUtilizeMultipleForwardedPropertiesAndDependencyInversionInSubBuilders() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -504,6 +511,7 @@ struct SafeDIToolDOTGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesDOTTree_whenRootInstantiatesPropertiesThatUtilizePropertiesNotDirectlyProvidedByParent() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -597,6 +605,7 @@ struct SafeDIToolDOTGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesDOTTree_whenRootInstantiatesPropertiesWithMultipleLayersOfInstantiators() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -690,6 +699,7 @@ struct SafeDIToolDOTGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesDOTTree_whenRootInstantiatesPropertiesWithMultipleTreesThatReceiveTheSameProperty() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -764,6 +774,7 @@ struct SafeDIToolDOTGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesDOTTree_whenRootInstantiatesPropertiesWithMultipleTreesThatInstantiateTheSamePropertyInMiddleLevel() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -840,6 +851,7 @@ struct SafeDIToolDOTGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesDOTTree_whenRootInstantiatesPropertiesWithSingleTreeThatInstantiatesTheSamePropertyAtMultipleLevels() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -892,6 +904,7 @@ struct SafeDIToolDOTGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesDOTTree_whenRootInstantiatesPropertiesWithMultipleTreesThatInstantiateTheSamePropertyMultipleLayersDeep() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -968,6 +981,7 @@ struct SafeDIToolDOTGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesDOTTree_whenRootInstantiatesPropertiesWithMultipleTreesThatInstantiateTheSamePropertyAcrossMultipleModules() async throws { let greatGrandchildModuleOutput = try await executeSafeDIToolTest( swiftFileContent: [ @@ -1091,6 +1105,7 @@ struct SafeDIToolDOTGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesDOTTree_whenRootHasReceivedAliasOfInstantiable() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -1131,6 +1146,7 @@ struct SafeDIToolDOTGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesDOTTree_whenReceivedPropertyIsAliasedTwice() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -1198,6 +1214,7 @@ struct SafeDIToolDOTGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesDOTTree_whenFirstPropertyDependsOnLastPropertyAndMiddlePropertyHasNoDependencyEntanglementsWithEither() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -1245,6 +1262,7 @@ struct SafeDIToolDOTGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesDOTTree_whenRootHasLotsOfDependenciesThatDependOnOneAnother() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -1518,6 +1536,7 @@ struct SafeDIToolDOTGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesDOTTree_whenLazyInstantiationCycleExists() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -1562,6 +1581,7 @@ struct SafeDIToolDOTGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesDOTTree_whenPartiallyLazyInstantiationCycleExists() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -1606,6 +1626,7 @@ struct SafeDIToolDOTGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesDOTTree_whenLazySelfInstantiationCycleExists() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -1637,6 +1658,7 @@ struct SafeDIToolDOTGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesDOTTree_whenLazySelfForwardingInstantiationCycleExists() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -1670,6 +1692,7 @@ struct SafeDIToolDOTGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesDOTTree_whenAGenericTypeIsAnExtendedInstantiableWithMultipleGenericReturnTypes() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -1719,6 +1742,7 @@ struct SafeDIToolDOTGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func run_writesDOTTree_whenAGenericTypeIsAnExtendedInstantiableWithMultipleGenericFullyQualifiedReturnTypes() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ diff --git a/Tests/SafeDIToolTests/SafeDIToolMockGenerationTests.swift b/Tests/SafeDIToolTests/SafeDIToolMockGenerationTests.swift index 0a621f24..bc2e92b5 100644 --- a/Tests/SafeDIToolTests/SafeDIToolMockGenerationTests.swift +++ b/Tests/SafeDIToolTests/SafeDIToolMockGenerationTests.swift @@ -39,6 +39,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { // MARK: Tests – Simple types @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_generatedForTypeWithNoDependencies() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -70,6 +71,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_generatedForExtensionBasedInstantiable() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -107,6 +109,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { // MARK: Tests – Types with dependencies @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_generatedForTypeWithInstantiatedDependency() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -164,6 +167,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_generatedForTypeWithReceivedDependency() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -251,6 +255,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_generatedForFullTree() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -375,6 +380,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { // MARK: Tests – Configuration @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_respectsMockConditionalCompilationNil() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -412,6 +418,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_respectsCustomMockConditionalCompilation() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -451,6 +458,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_typeWithDependenciesAndNilConditionalCompilation() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -512,6 +520,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_respectsMockAttributes() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -543,6 +552,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_parameterRequiredForTypeNotInTypeMap() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -582,6 +592,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_extensionBasedWithNilConditionalCompilation() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -623,6 +634,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_receivedErasedTypeAutoWraps() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -717,6 +729,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_generatedForErasedToConcreteExistential() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -782,6 +795,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { // MARK: Tests – Complex configurations @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_generatedForRootWithMultipleBranchesReceivingSameProperty() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -964,6 +978,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_generatedForRootWithProtocolFulfilledByAdditionalType() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -1023,6 +1038,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_generatedForMultipleRootsEachGetsOwnMockFile() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -1105,6 +1121,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_constructionOrderRespectsReceivedDependencies() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -1217,6 +1234,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_generatedForFourLevelDeepTreeWithSharedLeaf() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -1379,6 +1397,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_defaultValuedParameterBubblesUpToRootMock() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -1473,6 +1492,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_generatedForTypeWithInstantiatorDependency() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -1568,6 +1588,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_generatedForTypeWithInstantiatorNoForwardedProperties() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -1628,6 +1649,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_generatedForInstantiatorWithMultipleForwardedProperties() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -1698,6 +1720,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_generatedForTypeWithPublishedReceivedDependency() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -1769,6 +1792,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { // MARK: Tests – Coverage for edge cases @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_generatedForExtensionBasedTypeWithReceivedDependencies() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -1858,6 +1882,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_generatedForExtensionBasedTypeInInlineConstruction() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -1949,6 +1974,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_generatedForInstantiatorWithDefaultValuedBuiltTypeArg() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -2046,6 +2072,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_generatedForInstantiatorWithExtensionBasedBuiltType() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -2138,6 +2165,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_generatedForLazySelfInstantiationCycle() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -2185,6 +2213,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { // MARK: Tests – onlyIfAvailable and aliased properties @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_generatedForTypeWithOnlyIfAvailableReceivedProperty() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -2272,6 +2301,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_generatedForTypeWithAliasedReceivedProperty() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -2368,6 +2398,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { // MARK: Tests – Additional patterns @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_generatedForOnlyIfAvailableWherePropertyIsAvailable() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -2457,6 +2488,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_generatedForTypeWithAnyProtocolProperty() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -2525,6 +2557,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_generatedForErasedInstantiatorType() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -2689,6 +2722,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_generatedForSendableInstantiatorType() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -2756,6 +2790,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_generatedForMultipleLayersOfInstantiators() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -2864,6 +2899,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_generatedForLotsOfInterdependentDependencies() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -3119,6 +3155,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_generatedForAliasedPropertyThatIsAlsoExistential() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -3229,6 +3266,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_generatedForSendableErasedInstantiatorType() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -3351,6 +3389,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_generatedForAliasedReceivedPropertyWithErasedToConcreteExistentialFalse() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -3454,6 +3493,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { // MARK: Tests – Disambiguation @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_disambiguatesParameters_whenInstantiatorLabelCollidesWithTypeName() async throws { // Root has @Instantiated let childB: ChildB (constant). // Root has @Instantiated let childA: ChildA, which has @Instantiated let childB: Instantiator. @@ -3578,6 +3618,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { // MARK: Tests – Existing mock method detection @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_generatedWithCustomMockCallThrough_whenTypeHasExistingMockMethodAndCustomMockName() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -3612,6 +3653,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_generatedWhenTypeHasExistingMockMethodWithCustomMockNameAndGenerateMock() async throws { // Type has generateMock: true AND a hand-written customMock with a dependency parameter. // The generated mock calls through to the hand-written .customMock(dependency:). @@ -3675,6 +3717,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_generatedWhenTypeHasNonStaticMockMethod() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -3710,6 +3753,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_misconfiguredMockMethodEmitsComment() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -3782,6 +3826,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_extensionBasedTypeUsesInstantiateInReturnStatement() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -3846,6 +3891,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_nestsBuilderInsideClosureWhenForwardedTypeIsMockable() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -3921,6 +3967,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_extensionBasedTypeRespectsMockAttributes() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -3956,6 +4003,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_inlineConstructionRecursivelyBuildsInstantiatedDependencies() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -4026,6 +4074,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_nestsConstantEntryInsideBuilderWhenItDependsOnForwardedType() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -4095,6 +4144,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_resolvesDependencyViaFulfillingTypeInScope() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -4153,6 +4203,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_inlineConstructionWrapsInstantiatorDependenciesWithForwardedProperties() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -4236,6 +4287,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { // MARK: Tests – Edge cases @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_sendableInstantiatorWithNoForwardedPropertiesIncludesIn() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -4283,6 +4335,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_multiLevelNestingInsideBuilderClosure() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -4369,6 +4422,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_aliasedReceivedDependencyResolvesToForwardedAncestor() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -4434,6 +4488,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_disambiguatesParameterLabelsWhenSameInitLabelAppearsTwice() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -4516,6 +4571,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_passesNilForOnlyIfAvailableProtocolDependency() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -4573,6 +4629,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_threadsTransitiveDependenciesNotInParentScope() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -4630,6 +4687,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_receivedNonInstantiableDependencyBecomesRequiredParameter() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -4672,6 +4730,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_receivedNonInstantiableTransitiveDependencyBecomesRequiredParameter() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -4724,6 +4783,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_onlyIfAvailableTransitiveDependencyBecomesOptionalParameter() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -4782,6 +4842,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_onlyIfAvailableDependencyUsesVariableInReturnStatement() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -4833,6 +4894,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_sendableInstantiatorDependencyClosuresAreMarkedSendable() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -4891,6 +4953,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_nonSendableInstantiatorDependencyClosuresAreNotMarkedSendable() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -4952,6 +5015,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_instantiatedDependencyFromAnotherModuleGetsDefaultFromModuleInfo() async throws { // First module: ExternalEngine is @Instantiable via extension in another module. let externalModuleOutput = try await executeSafeDIToolTest( @@ -5031,6 +5095,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_receivedDependencyFromAnotherModuleGetsDefaultFromModuleInfo() async throws { // First module: ExternalEngine is @Instantiable via extension in another module. let externalModuleOutput = try await executeSafeDIToolTest( @@ -5105,6 +5170,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_rootUncoveredDependencyNotSuppressedByNestedDeclarationWithSameLabel() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -5172,6 +5238,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_sameTypeDifferentLabelsEachGetOwnParameter() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -5223,6 +5290,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_receivedConcreteExistentialWrapperConstructsUnderlyingType() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -5297,6 +5365,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_sharedTransitiveReceivedDependencyPromotedAtRootScope() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -5367,6 +5436,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_transitiveProtocolDependencyFulfilledByExtensionIsOptional() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -5434,6 +5504,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_erasedToConcreteExistentialWithChildrenWrapsInMockBinding() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -5504,6 +5575,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_noRedeclarationWhenOnlyIfAvailableDependencyAppearsInMultipleChildren() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -5559,6 +5631,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_noUseBeforeDeclarationWhenReceivedDependencyPromotedFromDeepTree() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -5630,6 +5703,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_noRedeclarationWhenSameDependencyIsReceivedAndOnlyIfAvailable() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -5689,6 +5763,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_noDuplicateBindingWhenRequiredAndOnlyIfAvailableForNonInstantiableType() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -5755,6 +5830,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_instantiatedDependencyNotInScopeMapBecomesRequiredParameter() async throws { // Simulates an @Instantiated dependency whose type is @Instantiable in another module // but not visible to this module's scope map. The type appears in the root's @@ -5804,6 +5880,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_instantiatedInstantiatorNotInScopeMapBecomesRequiredParameter() async throws { // An Instantiator where ExternalType is @Instantiable in another module // but not visible here. The Instantiator property has no scope and must become a @@ -5848,6 +5925,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_instantiatedAndForwardedWithUncoveredDependency() async throws { // A type with both @Forwarded properties and an @Instantiated dependency // whose type is not in the scope map. Tests the interaction of forwarded @@ -5906,6 +5984,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_aliasedOnlyIfAvailableDependencyTracksOnlyIfAvailable() async throws { // An aliased dependency with onlyIfAvailable: true should produce an optional // mock parameter, not a required one. This exercises the aliased+onlyIfAvailable @@ -5971,6 +6050,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_onlyIfAvailableTransitiveDependenciesNotPromoted() async throws { // When an onlyIfAvailable dependency (e.g., ApplicationStateService?) has its own // transitive dependencies (e.g., NotificationCenter), those transitive deps should @@ -6041,6 +6121,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_closureDependencyProducesValidIdentifier() async throws { // A type with a closure dependency returning Void should produce a valid // identifier suffix (not `-Void` or other invalid characters). @@ -6094,6 +6175,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_sendableClosureDependencyProducesValidIdentifier() async throws { // Verify that @Sendable closure types produce valid identifier suffixes // (@ symbols must not appear in generated parameter names). @@ -6134,6 +6216,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_forwardedClosureParameterHasEscapingAnnotation() async throws { // A forwarded closure parameter must be @escaping in the mock function // signature, since it's passed to an init that stores it. @@ -6181,6 +6264,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_usesExistingMockMethodInChildConstruction() async throws { // When a child type has a user-defined mock() with parameters matching its // dependencies, the parent's generated mock calls Child.mock(...) instead @@ -6260,6 +6344,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_existingMockMethodCoexistsWithNonMockChildren() async throws { // Some children have user-defined mocks, others don't. The generated // mock uses .mock() for the former and regular init for the latter. @@ -6320,6 +6405,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_existingMockMethodInDeepTree() async throws { // Grandchild has a user-defined mock with parameters. Parent → Child → Grandchild. // The construction chain should call Grandchild.mock() at the deepest level. @@ -6394,6 +6480,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_existingMockMethodOnExtensionBasedType() async throws { // An extension-based @Instantiable type with a user-defined mock method. // Parent should call Child.mock() instead of Child.instantiate(). @@ -6458,6 +6545,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_existingMockMethodOnExtensionBasedTypeWithReversedSourceOrder() async throws { // Same as mock_existingMockMethodOnExtensionBasedType but with mock() declared // before instantiate() in source order. Verifies visit order doesn't matter. @@ -6522,6 +6610,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_existingMockMethodWithMultipleDependencies() async throws { // Child has a user-defined mock with multiple dependency parameters. // All parameters are correctly threaded through the parent's mock. @@ -6592,6 +6681,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_existingMockMethodWithReversedParameterOrder() async throws { // Child's customMock has parameters in reversed order from init. // The generated mock's call-through must match the custom mock's parameter order. @@ -6652,6 +6742,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_existingMockMethodSkipsGenerationForTypeButGeneratesForParent() async throws { // A type with a user-defined mock() gets no generated mock file, but its parent // still gets a generated mock with parameters and inline construction. @@ -6724,6 +6815,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_defaultValuedParameterUsesOriginalDefaultExpression() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -6786,6 +6878,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_defaultValuedParameterDoesNotBubbleThroughInstantiator() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -6850,6 +6943,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_defaultValuedParameterBubblesFromGrandchildToRoot() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -6946,6 +7040,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_defaultValuedParameterOnRootType() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -6990,6 +7085,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_defaultValuedParameterDoesNotBubbleThroughSendableInstantiator() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -7036,6 +7132,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_multipleDefaultValuedParametersFromDifferentChildren() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -7098,6 +7195,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_defaultValuedParameterWithNilDefault() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -7160,6 +7258,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_defaultValuedParameterDisambiguatedWhenLabelCollides() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -7223,6 +7322,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_defaultValuedParameterDoesNotBubbleThroughErasedInstantiator() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -7274,6 +7374,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_defaultValuedParameterDoesNotBubbleThroughSendableErasedInstantiator() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -7325,6 +7426,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_defaultValuedParameterWithComplexDefault() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -7371,6 +7473,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_defaultValuedParameterOnTypeWithExistingMock() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -7434,6 +7537,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_childDefaultParamDoesNotReEvaluateRootBoundLabel() async throws { // Parent @Receives clientId (uncovered, no scope for String). // Child has clientId as a non-dependency default-valued init param. @@ -7484,6 +7588,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_receivedDependencyNotSuppressedByTreeChildWithSameLabelDifferentType() async throws { // ChildA @Instantiates `service: LocalService` (tree child). // ChildB @Receives `service: ExternalService` (different type, same label). @@ -7564,6 +7669,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_optionalReceivedNotSuppressedByNonOptionalWithSameLabelDifferentType() async throws { // ChildA @Receives `service: ExternalService` (non-optional). // ChildB @Receives(onlyIfAvailable: true) `service: LocalService?` (optional, different type). @@ -7637,6 +7743,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_disambiguationUsesSimplifiedSuffixWhenUnique() async throws { // Two children have `service` with different types. One is optional. // Simplified suffixes (stripping ?) are unique → use simplified. @@ -7705,6 +7812,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_disambiguationFallsBackToFullSuffixWhenSimplifiedCollides() async throws { // Two children have `service` — one is `Service` (non-optional), // one is `Service?` (optional). Simplified types are both `Service` → collision. @@ -7775,6 +7883,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_disambiguatedDefaultParamsFromDifferentChildrenDoNotCollideAtRoot() async throws { // ChildA has `viewModel: ViewModelA = ViewModelA()` and ChildB has `viewModel: ViewModelB = ViewModelB()`. // Both bubble to root as disambiguated autoclosure params. They must NOT both produce @@ -7848,6 +7957,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_uncoveredDependencyEvaluatedBeforePassingToUserMock() async throws { // Root @Instantiates ChildService which has a user-defined mock(engine:). // engine comes from a parallel module (uncovered dep). @@ -7914,6 +8024,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_deepNestedChildNotExposedAsRootParameter() async throws { // Root → Parent (subtree) → Child (subtree) → Leaf. // Only Parent is a root parameter. Child and Leaf are constructed inline @@ -7981,6 +8092,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_siblingResolvesOptionalBeforeNestedChild() async throws { // Root has widgetService (promoted) and parent. Parent receives widgetService. // widgetService is resolved via ?? at root scope. Inside __safeDI_parent(), @@ -8051,6 +8163,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_siblingResolvesOptionalBeforeDeepNestedGrandchild() async throws { // Root → widgetService (promoted, subtree) + parent (subtree). // Parent → grandchild (subtree). Grandchild receives widgetService. @@ -8136,6 +8249,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_siblingInstantiatedAtGrandchildLevelUsesResolvedValue() async throws { // Root → widgetService (promoted subtree) + parent (subtree). // Parent → grandchild. Grandchild @Instantiates widgetService (same type). @@ -8229,6 +8343,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_instantiatorResolvedBySiblingNotRedeclaredInNestedScope() async throws { // Root has childBuilder (Instantiator) and parent. Parent also uses childBuilder. // childBuilder is resolved at root via ??. Inside __safeDI_parent(), @@ -8296,6 +8411,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_disambiguatedParamUsedInInstantiatorBuilderFunction() async throws { // ChildA is built via Instantiator and @Receives presenter: PresenterA. // ChildB @Receives presenter: PresenterB (same label, different type). @@ -8375,6 +8491,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_disambiguatedInstantiatorBindingUsesDisambiguatedLocalName() async throws { // Two Instantiator children share label "childBuilder" but different types. // After disambiguation, the ?? binding local must use the disambiguated name. @@ -8455,6 +8572,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_disambiguatedInstantiatorResolvedBySiblingInNestedBuilder() async throws { // ChildC and ChildD both have a dep named "childBuilder" but with different generic types. // At root, both are promoted → disambiguated. ChildC's builder must reference @@ -8544,6 +8662,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_disambiguatedInstantiatorResolvedThroughIntermediateInstantiatorBuilder() async throws { // Root → parentBuilder (Instantiator) + childBuilder (Instantiator). // Parent uses childBuilder (Instantiator) + also has otherBuilder (Instantiator) @@ -8629,6 +8748,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_disambiguatedInstantiatorInDeepNestedBuilderUsesResolvedName() async throws { // Root has two children that each receive a different-typed builder with same label. // ChildA → receives builder: Instantiator @@ -8735,6 +8855,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_defaultValuedParametersFromMultipleLevelsAllAppearAtRoot() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -8797,6 +8918,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_defaultValuedParameterFromGrandchildStopsAtInstantiatorBoundary() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -8860,6 +8982,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_defaultValuedClosureParameterStripsEscaping() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -8902,6 +9025,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_defaultValuedMainActorClosurePreservesMainActor() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -8946,6 +9070,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_defaultValuedSendableClosurePreservesSendable() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -8988,6 +9113,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_typeWithUserMockAndOnlyDefaultValuedParamsGeneratesCallThrough_whenCustomMockNameIsSet() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -9054,6 +9180,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_mockMethodMissingDependencyEmitsComment() async throws { // Parent has a child whose mock() takes only some of its dependencies. // The .mock() call emits the "incorrectly configured" comment, triggering @@ -9127,6 +9254,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_defaultValuedParamDoesNotSuppressReceivedPropertyBinding() async throws { // A child has a default-valued init param with the same label as a received // dependency on another child. The default-valued declaration must NOT suppress @@ -9196,6 +9324,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_crossModuleDependencyWithModuleInfoIsOptionalParameter() async throws { // CrossModuleService is provided via .safedi — constructible, optional parameter. let crossModuleOutput = try await executeSafeDIToolTest( @@ -9268,6 +9397,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_uncoveredTransitiveDependencyFromParallelModuleSurfacesAsRequired() async throws { // Simulates a dependency whose transitive dep is @Instantiable in a parallel // module not available to this module. The transitive dep has no scope in the @@ -9333,6 +9463,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_userMockDependencyIsOptionalParameterWhenFulfillableFromTree() async throws { // Child has a user-defined mock() with a dep that IS constructible. // The dep should be an optional parameter with tree construction as default. @@ -9390,6 +9521,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_userMockDependencyBecomesRequiredParameterWhenNotFulfillable() async throws { // Child has a user-defined mock() with a dep from a dependent module. // The dep is constructible (via .safedi) but from another module. @@ -9455,6 +9587,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_userMockOnlyIfAvailableDependencyUsesNilDefaultWhenNotFulfillable() async throws { // Child has @Received(onlyIfAvailable: true) dep. The mock() has it as optional. // At the root, it should be an optional parameter with nil default. @@ -9511,6 +9644,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { // MARK: - Bug fix regression tests @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_uncoveredDependencyNotSuppressedByGrandchildWithSameLabel() async throws { // Child has @Instantiated service: ExternalService (NOT in scope map — // @Instantiable is in a parallel module). Grandchild has a tree child @@ -9589,6 +9723,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_userMockReturningAdditionalTypeUsedForProtocolProperty() async throws { // ChildService fulfills ChildServiceProtocol. Its mock returns the protocol type // and accepts a received dependency. Root's property is typed as the protocol. @@ -9648,6 +9783,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_userMockReturningAdditionalTypeNotUsedForConcreteProperty() async throws { // ChildService fulfills ChildServiceProtocol. Its mock returns the protocol type // and accepts a received dependency. Root's property is typed as the concrete type. @@ -9708,6 +9844,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_extensionUserMockReturningAdditionalTypeUsedForProtocolProperty() async throws { // Extension-based ChildService fulfills ChildServiceProtocol. Its mock returns the protocol // type and accepts a received dependency. Root's property is typed as the protocol. @@ -9766,6 +9903,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_extensionUserMockReturningAdditionalTypeNotUsedForConcreteProperty() async throws { // Extension-based ChildService fulfills ChildServiceProtocol. Its mock returns the protocol // type and accepts a received dependency. Root's property is typed as the concrete type. @@ -9825,6 +9963,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_generatedMockCallsThroughToHandWrittenMock() async throws { // Type has generateMock: true AND a hand-written mock with a dependency parameter. // The generated mock should call through to the hand-written .mock(dependency:). @@ -9877,6 +10016,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_generatedMockDoesNotExposeInitDefaultsNotOnHandWrittenMock() async throws { // Service has a default-valued init parameter (showDebugInfo) that the hand-written // mock does NOT expose. The generated mock should NOT bubble it up — the hand-written @@ -9958,6 +10098,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_generatedMockExposesHandWrittenMockExtraParams() async throws { // Service's hand-written mock has an extra non-dependency parameter (showDebugInfo) // with a default. The generated mock SHOULD expose it since the hand-written mock @@ -10016,6 +10157,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_generatedMockCallsThroughToHandWrittenMockForExtension() async throws { // Extension-based type has generateMock: true AND a hand-written mock with a dependency. // The generated mock should call through to .mock(dependency:). @@ -10073,6 +10215,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_parseErrorWritesErrorStubToMockOutputs() async throws { // When source has parse errors, mock outputs should get the error stub too // (not be left stale or missing). @@ -10100,6 +10243,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_forwardedParamDoesNotCollideWithBubbledDefault() async throws { // Root @Forwards `name: String`. Child has default-valued `name: String = "default"`. // Both produce mock params with label "name". Disambiguation must handle forwarded too. @@ -10153,6 +10297,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_instantiatorSiblingResolvedForDescendant() async throws { // Root has both an Instantiator and an @Instantiated SharedThing. // Parent @Receives shared: SharedThing. Inside parentBuilder's function, @@ -10218,6 +10363,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_disambiguatedAutoclosureEvaluatedInInstantiatorBuilder() async throws { // Root has parentBuilder (Instantiator) and childB: ChildB. // Parent @Receives config: ConfigA. ChildB @Receives config: ConfigB. @@ -10295,6 +10441,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_disambiguatedUncoveredDependencyInNestedInstantiator() async throws { // Root @Instantiates parent: Parent and child: Child. // Parent @Receives engine: EngineA. Child @Receives engine: EngineB. @@ -10363,6 +10510,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_onlyIfAvailableDisambiguatedSimplifiedUnique() async throws { // ChildA @Receives service: ExternalService. ChildB @Receives(onlyIfAvailable: true) service: LocalService?. // Both share label "service" — disambiguated by type. Optional suffix stripped from @@ -10430,6 +10578,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_closureTypedDefaultDisambiguated() async throws { // ChildA has default-valued `onAction: @escaping () -> Void = {}`. // ChildB has default-valued `onAction: @escaping (String) -> Void = { _ in }`. @@ -10488,6 +10637,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_extensionBasedChildReceivesInstantiatorFromParentScope() async throws { // Root @Instantiates childBuilder: Instantiator (generated first). // Root @Instantiates wrapper: ThirdPartyWrapper (extension-based, generated second). @@ -10555,6 +10705,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_disambiguatesAllParameters_whenThreeChildrenShareSameLabel() async throws { // Three children each receive "service" with a different type. // All three get disambiguated: service_ServiceA, service_ServiceB, service_ServiceC. @@ -10637,6 +10788,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_disambiguatedInstantiatorResolvedFromRootInNestedScope() async throws { // Root @Instantiates childBuilder: Instantiator (disambiguated). // Root also @Instantiates parentBuilder: Instantiator. @@ -10750,6 +10902,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { // MARK: - Scope and ordering tests @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_receivedDependencyGetsRootBindingWhenCreatedBySiblingInstantiator() async throws { // ChildA @Instantiates shared in its subtree. ChildB @Receives it. // shared is promoted to root. Root binding must exist so ChildB's @@ -10838,6 +10991,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_ordering_constantDependencyBeforeInstantiatorGrandchild() async throws { // Root has @Instantiated shared + child with Instantiator grandchild that receives shared. // shared must be defined before the grandchild's Instantiator function. @@ -10893,6 +11047,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_ordering_promotedDependencyBeforeSiblingInstantiator() async throws { // Two Instantiator siblings. ChildA @Instantiates shared, ChildB @Receives it. // shared is promoted to root. Must be ordered before builderB's function. @@ -10977,6 +11132,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_ordering_promotedDependencyBeforeGrandchildInSiblingBranch() async throws { // ChildA creates shared in its subtree. ChildB's grandchild receives it. // shared promoted to root. Must be ordered before childB. @@ -11068,6 +11224,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_ordering_chainedPromotedDependenciesBeforeGrandchild() async throws { // Grandchild receives serviceA and serviceB. ServiceA depends on serviceB. // Both promoted. serviceB must be ordered before serviceA, both before grandchild. @@ -11157,6 +11314,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_ordering_deepNesting_greatGrandchildReceivesFromSiblingBranch() async throws { // ChildB @Instantiates shared. ChildA's great-grandchild (via Instantiator) receives it. // shared must be at root before childA. @@ -11256,6 +11414,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_requiredReceivedDependencyIsNotTreatedAsOnlyIfAvailableWhenSiblingHasOnlyIfAvailableWithSameLabel() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -11325,6 +11484,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_postDisambiguationLabelDoesNotCollideWithExistingPropertyLabel() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -11423,6 +11583,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_aliasedBindingUsesDisambiguatedFulfillingPropertyLabel() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -11496,6 +11657,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_disambiguationFallsBackToFullSuffixWhenSimplifiedSuffixesCollide() async throws { // Root instantiates three children. Each child has a default-valued init // parameter named "value" with a different type. ServiceA and ServiceA? @@ -11595,6 +11757,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { // MARK: Tests – Per-type generateMock @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_generatedForType_whenGenerateMockIsTrue() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -11626,6 +11789,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_generatedForType_whenEnableMockGenerationIsTrue() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -11658,6 +11822,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_notGeneratedForType_whenGenerateMockIsDefault() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -11676,6 +11841,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_notGeneratedForType_whenGenerateMockIsFalse() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -11694,6 +11860,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_generatedOnlyForOptedInTypes_whenMixOfGenerateMockValues() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -11737,6 +11904,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_usesOuterLabel_whenDefaultValuedParameterHasUnderscoreInnerLabel() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -11799,6 +11967,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_doesNotBubbleDefaultValuedParameter_whenOuterLabelIsUnderscore() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -11853,6 +12022,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_doesNotBubbleDefaultValuedParameter_whenOnlyLabelIsUnderscore() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -11909,6 +12079,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { // MARK: Custom Mock Dependency Default Bubbling Tests @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_bubblesCustomMockDependencyDefault_whenForwardedPropertyReceivedByChild() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -11978,6 +12149,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_nearestReceiverDefaultWins_whenMultipleChildrenAtSameDepth() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -12042,6 +12214,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_forwardedPropertyDefaultBubblesAcrossThreeLevels_eachWithCustomMock() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -12125,6 +12298,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_doesNotBubbleDefault_whenNoChildHasCustomMock() async throws { let output = try await executeSafeDIToolTest( swiftFileContent: [ @@ -12172,6 +12346,7 @@ struct SafeDIToolMockGenerationTests: ~Copyable { } @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) mutating func mock_doesNotApplyDefaultFromWrongType_whenSameLabelDifferentTypes() async throws { // ChildA has `value: String` with a custom mock default. // ChildB has `value: Int` with no custom mock. @@ -12257,6 +12432,64 @@ struct SafeDIToolMockGenerationTests: ~Copyable { """, "Unexpected output \(output.mockFiles["Root+SafeDIMock.swift"] ?? "")") } + @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) + mutating func mock_crossModuleTypeWithGenerateMockIsSkipped() async throws { + // CrossModuleService has generateMock: true, but its source file belongs + // to the dependent module. The consuming module must NOT generate a mock + // for it — that's the dependent module's responsibility. + let crossModuleOutput = try await executeSafeDIToolTest( + swiftFileContent: [ + """ + @Instantiable(generateMock: true) + public struct CrossModuleService: Instantiable { + public init() {} + } + """, + ], + filesToDelete: &filesToDelete, + ) + + let output = try await executeSafeDIToolTest( + swiftFileContent: [ + """ + @Instantiable(isRoot: true, generateMock: true) + public struct Root: Instantiable { + public init(crossModuleService: CrossModuleService) { + self.crossModuleService = crossModuleService + } + @Instantiated let crossModuleService: CrossModuleService + } + """, + ], + dependentModuleInfoPaths: [crossModuleOutput.moduleInfoOutputPath], + buildSwiftOutputDirectory: true, + filesToDelete: &filesToDelete, + ) + + // Root mock should exist. + #expect(output.mockFiles["Root+SafeDIMock.swift"] == """ + // This file was generated by the SafeDIGenerateDependencyTree build tool plugin. + // Any modifications made to this file will be overwritten on subsequent builds. + // Please refrain from editing this file directly. + + #if DEBUG + extension Root { + public static func mock( + crossModuleService: @autoclosure @escaping () -> CrossModuleService = CrossModuleService() + ) -> Root { + let crossModuleService = crossModuleService() + return Root(crossModuleService: crossModuleService) + } + } + #endif + """, "Unexpected output \(output.mockFiles["Root+SafeDIMock.swift"] ?? "")") + + // CrossModuleService mock must NOT be generated by this module. + #expect(output.mockFiles["CrossModuleService+SafeDIMock.swift"] == nil, + "Cross-module type should not have a mock generated in consuming module") + } + // MARK: Private private var filesToDelete: [URL] diff --git a/Tests/SafeDIToolTests/SafeDIToolVersionTests.swift b/Tests/SafeDIToolTests/SafeDIToolVersionTests.swift index 936ef1df..a54064c2 100644 --- a/Tests/SafeDIToolTests/SafeDIToolVersionTests.swift +++ b/Tests/SafeDIToolTests/SafeDIToolVersionTests.swift @@ -32,6 +32,7 @@ import Testing @MainActor // serialized due to changes to stdout struct SafeDIToolVersionTests { @Test + @available(macOS 13.0, iOS 16.0, tvOS 16.0, watchOS 9.0, *) func run_withVersionFlag_printsCurrentVersion() async throws { var tool = SafeDITool() tool.swiftSourcesFilePath = nil