From f4507dbe45dc4d0ac52c05ce7cd86c9f5429ec8b Mon Sep 17 00:00:00 2001 From: Michael O'Brien <98201889+mobrien-ghost@users.noreply.github.com> Date: Mon, 11 Mar 2024 00:24:45 +1000 Subject: [PATCH] Adding Function Signature Node, Subscript hasSetter, bumping swift-syntax version (#34) * Exposing Function Signature Node, Subscript hasSetter, Bumping swift-syntax version * Adding convenience method for parameter collections * Assigning manual Xcode version in GitHub actions workflow --- .github/workflows/unit-tests.yml | 3 + .swift-version | 1 + .swiftpm/SyntaxSparrow.xctestplan | 32 ----- ...88143FD8-9C60-4842-BE21-570110166AD5.plist | 68 ---------- .../SyntaxSparrowTests.xcbaseline/Info.plist | 33 ----- .../xcschemes/SyntaxSparrow.xcscheme | 97 -------------- Package.resolved | 4 +- Package.swift | 7 +- Package@swift-5.7.swift | 7 +- Package@swift-5.8.swift | 7 +- .../Collectors/RootDeclarationCollector.swift | 5 +- .../FunctionSemanticsResolver.swift | 1 + .../SubscriptSemanticsResolver.swift | 6 +- .../VariableSemanticsResolver.swift | 2 +- .../Extensions/Collection+Parameters.swift | 35 +++++ .../Semantics/Declarations/Function.swift | 6 +- .../Semantics/Declarations/Subscript.swift | 3 + .../SparrowSourceLocationConverter.swift | 15 ++- .../Declarations/FunctionTests.swift | 6 +- .../Declarations/SubscriptTests.swift | 22 +++ .../Collection+ParametersTests.swift | 125 ++++++++++++++++++ 21 files changed, 238 insertions(+), 247 deletions(-) create mode 100644 .swift-version delete mode 100644 .swiftpm/SyntaxSparrow.xctestplan delete mode 100644 .swiftpm/xcode/xcshareddata/xcbaselines/SyntaxSparrowTests.xcbaseline/88143FD8-9C60-4842-BE21-570110166AD5.plist delete mode 100644 .swiftpm/xcode/xcshareddata/xcbaselines/SyntaxSparrowTests.xcbaseline/Info.plist delete mode 100644 .swiftpm/xcode/xcshareddata/xcschemes/SyntaxSparrow.xcscheme create mode 100644 Sources/SyntaxSparrow/Public/Extensions/Collection+Parameters.swift create mode 100644 Tests/SyntaxSparrowTests/Extensions/Collection+ParametersTests.swift diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index a3b78968..96665af6 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -34,6 +34,9 @@ jobs: - uses: swift-actions/setup-swift@v1 with: swift-version: ${{ matrix.swift }} + - uses: maxim-lobanov/setup-xcode@v1 + with: + xcode-version: "14.3.1" - uses: actions/checkout@v3 - uses: actions/cache@v3 with: diff --git a/.swift-version b/.swift-version new file mode 100644 index 00000000..bec3a35e --- /dev/null +++ b/.swift-version @@ -0,0 +1 @@ +system diff --git a/.swiftpm/SyntaxSparrow.xctestplan b/.swiftpm/SyntaxSparrow.xctestplan deleted file mode 100644 index ff00f5cc..00000000 --- a/.swiftpm/SyntaxSparrow.xctestplan +++ /dev/null @@ -1,32 +0,0 @@ -{ - "configurations" : [ - { - "id" : "FDC14052-B4F5-4EFE-A33B-8B0FD42FC77F", - "name" : "Configuration 1", - "options" : { - - } - } - ], - "defaultOptions" : { - "codeCoverage" : { - "targets" : [ - { - "containerPath" : "container:", - "identifier" : "SyntaxSparrow", - "name" : "SyntaxSparrow" - } - ] - } - }, - "testTargets" : [ - { - "target" : { - "containerPath" : "container:", - "identifier" : "SyntaxSparrowTests", - "name" : "SyntaxSparrowTests" - } - } - ], - "version" : 1 -} diff --git a/.swiftpm/xcode/xcshareddata/xcbaselines/SyntaxSparrowTests.xcbaseline/88143FD8-9C60-4842-BE21-570110166AD5.plist b/.swiftpm/xcode/xcshareddata/xcbaselines/SyntaxSparrowTests.xcbaseline/88143FD8-9C60-4842-BE21-570110166AD5.plist deleted file mode 100644 index 30c28ebe..00000000 --- a/.swiftpm/xcode/xcshareddata/xcbaselines/SyntaxSparrowTests.xcbaseline/88143FD8-9C60-4842-BE21-570110166AD5.plist +++ /dev/null @@ -1,68 +0,0 @@ - - - - - classNames - - ClassTests - - testPerformanceExample() - - com.apple.XCTPerformanceMetric_WallClockTime - - baselineAverage - 0.006317 - baselineIntegrationDisplayName - Local Baseline - - - - StructureTests - - testPerformanceExample() - - com.apple.XCTPerformanceMetric_WallClockTime - - baselineAverage - 0.014173 - baselineIntegrationDisplayName - Local Baseline - - - - SyntaxSparrowTests - - test_initialCollectionPerformance() - - com.apple.XCTPerformanceMetric_WallClockTime - - baselineAverage - 0.030244 - baselineIntegrationDisplayName - Local Baseline - - - test_sourceResolving_topLevelOnly_Performance() - - com.apple.XCTPerformanceMetric_WallClockTime - - baselineAverage - 0.062897 - baselineIntegrationDisplayName - Local Baseline - - - test_sourceResolving_traversed_Performance() - - com.apple.XCTPerformanceMetric_WallClockTime - - baselineAverage - 0.106073 - baselineIntegrationDisplayName - Local Baseline - - - - - - diff --git a/.swiftpm/xcode/xcshareddata/xcbaselines/SyntaxSparrowTests.xcbaseline/Info.plist b/.swiftpm/xcode/xcshareddata/xcbaselines/SyntaxSparrowTests.xcbaseline/Info.plist deleted file mode 100644 index c234d6e6..00000000 --- a/.swiftpm/xcode/xcshareddata/xcbaselines/SyntaxSparrowTests.xcbaseline/Info.plist +++ /dev/null @@ -1,33 +0,0 @@ - - - - - runDestinationsByUUID - - 88143FD8-9C60-4842-BE21-570110166AD5 - - localComputer - - busSpeedInMHz - 0 - cpuCount - 1 - cpuKind - Apple M2 - cpuSpeedInMHz - 0 - logicalCPUCoresPerPackage - 8 - modelCode - Mac14,2 - physicalCPUCoresPerPackage - 8 - platformIdentifier - com.apple.platform.macosx - - targetArchitecture - arm64 - - - - diff --git a/.swiftpm/xcode/xcshareddata/xcschemes/SyntaxSparrow.xcscheme b/.swiftpm/xcode/xcshareddata/xcschemes/SyntaxSparrow.xcscheme deleted file mode 100644 index 20df89ca..00000000 --- a/.swiftpm/xcode/xcshareddata/xcschemes/SyntaxSparrow.xcscheme +++ /dev/null @@ -1,97 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Package.resolved b/Package.resolved index 7f804c46..0d514e0f 100644 --- a/Package.resolved +++ b/Package.resolved @@ -14,8 +14,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-syntax.git", "state" : { - "revision" : "6ad4ea24b01559dde0773e3d091f1b9e36175036", - "version" : "509.0.2" + "revision" : "fa8f95c2d536d6620cc2f504ebe8a6167c9fc2dd", + "version" : "510.0.1" } }, { diff --git a/Package.swift b/Package.swift index 79fbce21..21b7edd0 100644 --- a/Package.swift +++ b/Package.swift @@ -7,7 +7,10 @@ let package = Package( name: "SyntaxSparrow", platforms: [ .macOS(.v10_15), - .iOS(.v13) + .iOS(.v13), + .tvOS(.v13), + .watchOS(.v6), + .macCatalyst(.v13) ], products: [ // Products define the executables and libraries a package produces, and make them visible to other packages. @@ -17,7 +20,7 @@ let package = Package( ), ], dependencies: [ - .package(url: "https://github.com/apple/swift-syntax.git", from: "509.0.0"), + .package(url: "https://github.com/apple/swift-syntax.git", from: "510.0.1"), ], targets: [ .target( diff --git a/Package@swift-5.7.swift b/Package@swift-5.7.swift index 83488f5b..2c69e329 100644 --- a/Package@swift-5.7.swift +++ b/Package@swift-5.7.swift @@ -7,7 +7,10 @@ let package = Package( name: "SyntaxSparrow", platforms: [ .macOS(.v10_15), - .iOS(.v13) + .iOS(.v13), + .tvOS(.v13), + .watchOS(.v6), + .macCatalyst(.v13) ], products: [ // Products define the executables and libraries a package produces, and make them visible to other packages. @@ -17,7 +20,7 @@ let package = Package( ), ], dependencies: [ - .package(url: "https://github.com/apple/swift-syntax.git", from: "509.0.0"), + .package(url: "https://github.com/apple/swift-syntax.git", from: "510.0.1"), ], targets: [ .target( diff --git a/Package@swift-5.8.swift b/Package@swift-5.8.swift index f6e287c8..670f9705 100644 --- a/Package@swift-5.8.swift +++ b/Package@swift-5.8.swift @@ -7,7 +7,10 @@ let package = Package( name: "SyntaxSparrow", platforms: [ .macOS(.v10_15), - .iOS(.v13) + .iOS(.v13), + .tvOS(.v13), + .watchOS(.v6), + .macCatalyst(.v13) ], products: [ // Products define the executables and libraries a package produces, and make them visible to other packages. @@ -17,7 +20,7 @@ let package = Package( ), ], dependencies: [ - .package(url: "https://github.com/apple/swift-syntax.git", from: "509.0.0"), + .package(url: "https://github.com/apple/swift-syntax.git", from: "510.0.1"), ], targets: [ .target( diff --git a/Sources/SyntaxSparrow/Internal/Collectors/RootDeclarationCollector.swift b/Sources/SyntaxSparrow/Internal/Collectors/RootDeclarationCollector.swift index 086377dd..45cc3846 100644 --- a/Sources/SyntaxSparrow/Internal/Collectors/RootDeclarationCollector.swift +++ b/Sources/SyntaxSparrow/Internal/Collectors/RootDeclarationCollector.swift @@ -19,6 +19,9 @@ class RootDeclarationCollector: SyntaxVisitor { /// `DeclarationCollection` instance to collect results into. private(set) var declarationCollection: DeclarationCollection = .init() + /// Transient entry node used when walking over a node. The entry node will be ignored and it's children visited. + private(set) var tree: SourceFileSyntax = SourceFileSyntax(statements: .init([])) + /// Transient entry node used when walking over a node. The entry node will be ignored and it's children visited. private(set) var entryNode: SyntaxProtocol? @@ -30,7 +33,7 @@ class RootDeclarationCollector: SyntaxVisitor { /// - Parameter source: The source code being analyzed by this instance. @discardableResult func collect(fromSource source: String) -> DeclarationCollection { declarationCollection.reset() - let tree = Parser.parse(source: source) + tree = Parser.parse(source: source) walk(tree) return declarationCollection } diff --git a/Sources/SyntaxSparrow/Internal/Resolvers/Declaration/FunctionSemanticsResolver.swift b/Sources/SyntaxSparrow/Internal/Resolvers/Declaration/FunctionSemanticsResolver.swift index 6eebb4c7..96e63624 100644 --- a/Sources/SyntaxSparrow/Internal/Resolvers/Declaration/FunctionSemanticsResolver.swift +++ b/Sources/SyntaxSparrow/Internal/Resolvers/Declaration/FunctionSemanticsResolver.swift @@ -69,6 +69,7 @@ struct FunctionSemanticsResolver: SemanticsResolving { effectSpecifiers = EffectSpecifiers(node: specifiers) } return Function.Signature( + node: node.signature, input: inputParameters, output: outputType, outputIsOptional: isOutputOptional, diff --git a/Sources/SyntaxSparrow/Internal/Resolvers/Declaration/SubscriptSemanticsResolver.swift b/Sources/SyntaxSparrow/Internal/Resolvers/Declaration/SubscriptSemanticsResolver.swift index 81d4f13a..142ed6eb 100644 --- a/Sources/SyntaxSparrow/Internal/Resolvers/Declaration/SubscriptSemanticsResolver.swift +++ b/Sources/SyntaxSparrow/Internal/Resolvers/Declaration/SubscriptSemanticsResolver.swift @@ -59,8 +59,12 @@ struct SubscriptSemanticsResolver: SemanticsResolving { node.returnClause.type.resolveIsTypeOptional() } + func resolveHasSetter() -> Bool { + return resolveAccessors().contains(where: { $0.kind == .set }) + } + func resolveAccessors() -> [Accessor] { - guard let accessor = node.accessorBlock?.as(AccessorBlockSyntax.self) else { return [] } + guard let accessor = node.accessorBlock else { return [] } switch accessor.accessors { case .accessors(let accessorList): return accessorList.map(Accessor.init) diff --git a/Sources/SyntaxSparrow/Internal/Resolvers/Declaration/VariableSemanticsResolver.swift b/Sources/SyntaxSparrow/Internal/Resolvers/Declaration/VariableSemanticsResolver.swift index a3e58197..44a01f07 100644 --- a/Sources/SyntaxSparrow/Internal/Resolvers/Declaration/VariableSemanticsResolver.swift +++ b/Sources/SyntaxSparrow/Internal/Resolvers/Declaration/VariableSemanticsResolver.swift @@ -28,7 +28,7 @@ struct VariableSemanticsResolver: SemanticsResolving { // MARK: - Resolvers func resolveAccessors() -> [Accessor] { - guard let accessor = node.accessorBlock?.as(AccessorBlockSyntax.self) else { return [] } + guard let accessor = node.accessorBlock else { return [] } switch accessor.accessors { case .accessors(let accessorList): return accessorList.map(Accessor.init) diff --git a/Sources/SyntaxSparrow/Public/Extensions/Collection+Parameters.swift b/Sources/SyntaxSparrow/Public/Extensions/Collection+Parameters.swift new file mode 100644 index 00000000..cc19a840 --- /dev/null +++ b/Sources/SyntaxSparrow/Public/Extensions/Collection+Parameters.swift @@ -0,0 +1,35 @@ +// +// Collection+Parameters.swift +// +// +// Created by Michael O'Brien on 9/3/2024. +// + +import Foundation + +public extension Collection where Element == Parameter { + + /// Will return the parameters as they would appear within signature input parenthesis. + /// + /// Note: Sending true to the `includeParenthesis` flag (default) will wrap the result in parenthesis. + /// i.e: + /// - `true`: `"(_ name: String, age: Int = 0, withOtherThing otherThing: String? = nil)"` + /// - `false`:`"_ name: String, age: Int = 0, withOtherThing otherThing: String? = nil"` + /// + /// - Parameter includeParenthesis: Bool whether to wrap the result in parenthesis. Defaults to `true`. + /// - Returns: `String` + func signatureInputString(includeParenthesis: Bool = true) -> String { + let components: [String] = map { param in + var base = param.description + base = base.replacingOccurrences(of: ",", with: "") + base = base.replacingOccurrences(of: " :", with: ":") + base = base.trimmingCharacters(in: .whitespacesAndNewlines) + return base + } + let joined = components.joined(separator: ", ") + if includeParenthesis { + return "(\(joined))" + } + return joined + } +} diff --git a/Sources/SyntaxSparrow/Public/Semantics/Declarations/Function.swift b/Sources/SyntaxSparrow/Public/Semantics/Declarations/Function.swift index 40ba9f69..2895de87 100644 --- a/Sources/SyntaxSparrow/Public/Semantics/Declarations/Function.swift +++ b/Sources/SyntaxSparrow/Public/Semantics/Declarations/Function.swift @@ -24,8 +24,12 @@ public struct Function: Declaration, SyntaxChildCollecting { /// /// The signature describes the function's parameter types and return type. /// This information is parsed from an underlying `FunctionSignatureSyntax` token. - public struct Signature: Hashable { + public struct Signature: Hashable, Equatable { + // MARK: - Properties + + /// The raw syntax node being represented by the instance. + public let node: FunctionSignatureSyntax /// Array of input parameters for the function. /// Each parameter is represented by a `Parameter` struct. diff --git a/Sources/SyntaxSparrow/Public/Semantics/Declarations/Subscript.swift b/Sources/SyntaxSparrow/Public/Semantics/Declarations/Subscript.swift index 6c19c29c..ed6f61ff 100644 --- a/Sources/SyntaxSparrow/Public/Semantics/Declarations/Subscript.swift +++ b/Sources/SyntaxSparrow/Public/Semantics/Declarations/Subscript.swift @@ -81,6 +81,9 @@ public struct Subscript: Declaration { /// The subscript getter and/or setter. public var accessors: [Accessor] { resolver.resolveAccessors() } + /// Will return `true` when the `.set` accessor kind is present + public var hasSetter: Bool { resolver.resolveHasSetter() } + // MARK: - Properties: DeclarationCollecting private(set) var resolver: SubscriptSemanticsResolver diff --git a/Sources/SyntaxSparrow/Public/Utilities/SparrowSourceLocationConverter.swift b/Sources/SyntaxSparrow/Public/Utilities/SparrowSourceLocationConverter.swift index 2002191d..385a8051 100644 --- a/Sources/SyntaxSparrow/Public/Utilities/SparrowSourceLocationConverter.swift +++ b/Sources/SyntaxSparrow/Public/Utilities/SparrowSourceLocationConverter.swift @@ -24,13 +24,19 @@ public class SparrowSourceLocationConverter { // MARK: - Lifecycle static var empty: SparrowSourceLocationConverter { - SparrowSourceLocationConverter(file: "", source: "") + let syntax = SourceFileSyntax(statements: .init([])) + return SparrowSourceLocationConverter(file: "", tree: syntax) } public init(file: String, tree: SyntaxProtocol) { converter = SourceLocationConverter(fileName: file, tree: tree) } + @available( + *, + deprecated, + message: "`init(file:source:)' is deprecated: Use `init(fileName:tree:)` instead" + ) public init(file: String, source: String) { converter = SourceLocationConverter(file: file, source: source) } @@ -47,7 +53,12 @@ public class SparrowSourceLocationConverter { } } - public func udpateForSource(_ source: String, file: String = "") { + @available( + *, + deprecated, + message: "`updateForSource(_:file:)' is deprecated: Use `updateForTree(_:file:)` instead" + ) + public func updateForSource(_ source: String, file: String = "") { queue.async(flags: .barrier) { [self] in converter = SourceLocationConverter(file: file, source: source) } diff --git a/Tests/SyntaxSparrowTests/Declarations/FunctionTests.swift b/Tests/SyntaxSparrowTests/Declarations/FunctionTests.swift index 2f3b566d..62266d58 100644 --- a/Tests/SyntaxSparrowTests/Declarations/FunctionTests.swift +++ b/Tests/SyntaxSparrowTests/Declarations/FunctionTests.swift @@ -285,16 +285,16 @@ final class FunctionTests: XCTestCase { XCTAssertEqual(function.genericRequirements[1].rightTypeIdentifier, "C2.Element") } - func test_thing() { + func test_signatureNode_isParentNode() { let source = #""" - func variadicOptional(_ names: String?...) {} + func noParameters() throws {} """# instanceUnderTest.updateToSource(source) XCTAssertTrue(instanceUnderTest.isStale) instanceUnderTest.collectChildren() XCTAssertFalse(instanceUnderTest.isStale) XCTAssertEqual(instanceUnderTest.functions.count, 1) - XCTAssertTrue(instanceUnderTest.functions[0].signature.input[0].isOptional) + XCTAssertEqual(instanceUnderTest.functions[0].signature.node, instanceUnderTest.functions[0].node.signature) } func test_function_parameters_willResolveExpectedTypes() throws { diff --git a/Tests/SyntaxSparrowTests/Declarations/SubscriptTests.swift b/Tests/SyntaxSparrowTests/Declarations/SubscriptTests.swift index 3ae4a433..d95471b6 100644 --- a/Tests/SyntaxSparrowTests/Declarations/SubscriptTests.swift +++ b/Tests/SyntaxSparrowTests/Declarations/SubscriptTests.swift @@ -158,6 +158,28 @@ final class SubscriptTests: XCTestCase { XCTAssertEqual(instanceUnderTest.subscripts[2].accessors.map(\.kind?.rawValue), ["get", "set"]) } + func test_subscript_hasSetter_willResolveExpectedValues() { + let source = #""" + subscript(index: Int) -> Int { 0 } + subscript(index: Int) -> Int { + get { 0 } + } + subscript(index: Int) -> Int { + get { 0 } + set { 0 } + } + """# + instanceUnderTest.updateToSource(source) + XCTAssertTrue(instanceUnderTest.isStale) + instanceUnderTest.collectChildren() + XCTAssertFalse(instanceUnderTest.isStale) + XCTAssertEqual(instanceUnderTest.subscripts.count, 3) + // Main + XCTAssertFalse(instanceUnderTest.subscripts[0].hasSetter) // Technically getter but going w code accuracy + XCTAssertFalse(instanceUnderTest.subscripts[1].hasSetter) + XCTAssertTrue(instanceUnderTest.subscripts[2].hasSetter) + } + func test_subscript_returnTypeIsOptional_willResolveExpectedValues() { let source = #""" subscript(index: Int) -> Int { 0 } diff --git a/Tests/SyntaxSparrowTests/Extensions/Collection+ParametersTests.swift b/Tests/SyntaxSparrowTests/Extensions/Collection+ParametersTests.swift new file mode 100644 index 00000000..f0e96d62 --- /dev/null +++ b/Tests/SyntaxSparrowTests/Extensions/Collection+ParametersTests.swift @@ -0,0 +1,125 @@ +// +// Collection+ParametersTests.swift +// +// +// Created by Michael O'Brien on 9/3/2024. +// + +import Foundation +@testable import SyntaxSparrow +import XCTest + +final class CollectionParametersTests: XCTestCase { + + // MARK: - Properties + + var instanceUnderTest: SyntaxTree! + + // MARK: - Lifecycle + + override func setUpWithError() throws { + instanceUnderTest = SyntaxTree(viewMode: .sourceAccurate, sourceBuffer: "") + } + + override func tearDownWithError() throws { + // Put teardown code here. This method is called after the invocation of each test method in the class. + } + + // MARK: - Tests + + func test_emptyCollection_willReturnExpectedResults() { + let parameters: [Parameter] = [] + XCTAssertEqual(parameters.signatureInputString(includeParenthesis: false), "") + XCTAssertEqual(parameters.signatureInputString(includeParenthesis: true), "()") + } + + func test_singleParameter_singleName_defaultValue_willReturnExpectedResults() { + let source = #""" + func example(name: String = "test") throws {} + """# + instanceUnderTest.updateToSource(source) + instanceUnderTest.collectChildren() + + let expectedString = "name: String = \"test\"" + let expectedParenthesisString = "(\(expectedString))" + + let function = instanceUnderTest.functions[0] + XCTAssertEqual(function.signature.input.signatureInputString(includeParenthesis: false), expectedString) + XCTAssertEqual(function.signature.input.signatureInputString(includeParenthesis: true), expectedParenthesisString) + } + + func test_singleParameter_labelOmitted_willReturnExpectedResults() { + let source = #""" + func example(_ name: String) throws {} + """# + instanceUnderTest.updateToSource(source) + instanceUnderTest.collectChildren() + + let expectedString = "_ name: String" + let expectedParenthesisString = "(\(expectedString))" + + let function = instanceUnderTest.functions[0] + XCTAssertEqual(function.signature.input.signatureInputString(includeParenthesis: false), expectedString) + XCTAssertEqual(function.signature.input.signatureInputString(includeParenthesis: true), expectedParenthesisString) + } + + func test_singleParameter_labelOmitted_defaultValue_willReturnExpectedResults() { + let source = #""" + func example(_ name: String? = nil) throws {} + """# + instanceUnderTest.updateToSource(source) + instanceUnderTest.collectChildren() + + let expectedString = "_ name: String? = nil" + let expectedParenthesisString = "(\(expectedString))" + + let function = instanceUnderTest.functions[0] + XCTAssertEqual(function.signature.input.signatureInputString(includeParenthesis: false), expectedString) + XCTAssertEqual(function.signature.input.signatureInputString(includeParenthesis: true), expectedParenthesisString) + } + + func test_singleParameter_twoNames_defaultValue_willReturnExpectedResults() { + let source = #""" + func example(withName name: String = "Name") throws {} + """# + instanceUnderTest.updateToSource(source) + instanceUnderTest.collectChildren() + + let expectedString = "withName name: String = \"Name\"" + let expectedParenthesisString = "(\(expectedString))" + + let function = instanceUnderTest.functions[0] + XCTAssertEqual(function.signature.input.signatureInputString(includeParenthesis: false), expectedString) + XCTAssertEqual(function.signature.input.signatureInputString(includeParenthesis: true), expectedParenthesisString) + } + + func test_multipleParams_willReturnExpectedResults() { + let source = #""" + func exampleWithName(_ name: String, age: Int = 0, otherThings things: String...) throws {} + """# + instanceUnderTest.updateToSource(source) + instanceUnderTest.collectChildren() + + let expectedString = "_ name: String, age: Int = 0, otherThings things: String..." + let expectedParenthesisString = "(\(expectedString))" + + let function = instanceUnderTest.functions[0] + XCTAssertEqual(function.signature.input.signatureInputString(includeParenthesis: false), expectedString) + XCTAssertEqual(function.signature.input.signatureInputString(includeParenthesis: true), expectedParenthesisString) + } + + func test_multipleParams_attributed_willReturnExpectedResults() { + let source = #""" + func exampleWithName(_ name: String, inout age: Int = 0, handler: @escaping (String) -> Void = {}) throws {} + """# + instanceUnderTest.updateToSource(source) + instanceUnderTest.collectChildren() + + let expectedString = "_ name: String, inout age: Int = 0, handler: @escaping (String) -> Void = {}" + let expectedParenthesisString = "(\(expectedString))" + + let function = instanceUnderTest.functions[0] + XCTAssertEqual(function.signature.input.signatureInputString(includeParenthesis: false), expectedString) + XCTAssertEqual(function.signature.input.signatureInputString(includeParenthesis: true), expectedParenthesisString) + } +}