From 4944747e7aaeec58dc62082a2f9ff399613b5539 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kry=C5=A1tof=20Mat=C4=9Bj?= Date: Mon, 11 Sep 2023 15:08:54 +0200 Subject: [PATCH] Integrate dummy generator --- .../Rubicon/Generator/ArgumentGenerator.swift | 19 + .../Generator/CreateDummyInteractor.swift | 175 ------ .../Rubicon/Generator/DummyGenerator.swift | 69 ++ .../Rubicon/Generator/FunctionGenerator.swift | 47 ++ .../Rubicon/Generator/TypeGenerator.swift | 5 + .../Rubicon/Generator/VariableGenerator.swift | 20 +- .../Sources/Rubicon/Integration/Rubicon.swift | 60 ++ .../Parser/TypeDeclarationParser.swift | 2 +- .../Generator/ArgumentGeneratorTests.swift | 32 + .../CreateDummyInteractorTests.swift | 589 ------------------ .../Generator/DummyGeneratorTests.swift | 173 +++++ .../Generator/FunctionGeneratorTests.swift | 129 ++++ .../Generator/ProtocolGeneratorTests.swift | 2 +- .../Generator/TypeGeneratorTests.swift | 29 +- .../Generator/VariableGeneratorTests.swift | 37 +- .../Tests/RubiconTests/IntegrationTests.swift | 63 ++ .../TypeDeclarationParserTests.swift | 2 +- 17 files changed, 659 insertions(+), 794 deletions(-) create mode 100644 Rubicon/Sources/Rubicon/Generator/ArgumentGenerator.swift delete mode 100644 Rubicon/Sources/Rubicon/Generator/CreateDummyInteractor.swift create mode 100644 Rubicon/Sources/Rubicon/Generator/DummyGenerator.swift create mode 100644 Rubicon/Sources/Rubicon/Generator/FunctionGenerator.swift create mode 100644 Rubicon/Sources/Rubicon/Integration/Rubicon.swift create mode 100644 Rubicon/Tests/RubiconTests/Generator/ArgumentGeneratorTests.swift delete mode 100644 Rubicon/Tests/RubiconTests/Generator/CreateDummyInteractorTests.swift create mode 100644 Rubicon/Tests/RubiconTests/Generator/DummyGeneratorTests.swift create mode 100644 Rubicon/Tests/RubiconTests/Generator/FunctionGeneratorTests.swift create mode 100644 Rubicon/Tests/RubiconTests/IntegrationTests.swift diff --git a/Rubicon/Sources/Rubicon/Generator/ArgumentGenerator.swift b/Rubicon/Sources/Rubicon/Generator/ArgumentGenerator.swift new file mode 100644 index 0000000..34b949d --- /dev/null +++ b/Rubicon/Sources/Rubicon/Generator/ArgumentGenerator.swift @@ -0,0 +1,19 @@ +protocol ArgumentGenerator { + func makeCode(from declaration: ArgumentDeclaration) -> String +} + +final class ArgumentGeneratorImpl: ArgumentGenerator { + private let typeGenerator: TypeGenerator + + init(typeGenerator: TypeGenerator) { + self.typeGenerator = typeGenerator + } + + func makeCode(from declaration: ArgumentDeclaration) -> String { + if let label = declaration.label { + return "\(label) \(declaration.name): \(typeGenerator.makeArgumentCode(from: declaration.type))" + } else { + return "\(declaration.name): \(typeGenerator.makeArgumentCode(from: declaration.type))" + } + } +} diff --git a/Rubicon/Sources/Rubicon/Generator/CreateDummyInteractor.swift b/Rubicon/Sources/Rubicon/Generator/CreateDummyInteractor.swift deleted file mode 100644 index 0659c57..0000000 --- a/Rubicon/Sources/Rubicon/Generator/CreateDummyInteractor.swift +++ /dev/null @@ -1,175 +0,0 @@ -final class CreateDummyInteractor { - private let protocolGenerator: ProtocolGenerator - private var accessLevel: AccessLevel = .internal - private var protocolType: ProtocolDeclaration? - private var variableGenerator: VariableGenerator - - init( - protocolGenerator: ProtocolGenerator, - variableGenerator: VariableGenerator - ) { - self.protocolGenerator = protocolGenerator - self.variableGenerator = variableGenerator - } - - func generate(from protocolType: ProtocolDeclaration) -> String { - let content = generateBody(from: protocolType) - return protocolGenerator.makeProtocol( - from: protocolType, - stub: "Dummy", - content: content.joined(separator: "\n") - ) - } - - private func generateBody(from protocolType: ProtocolDeclaration) -> [String] { - var content = [String]() - - if !protocolType.variables.isEmpty { - content += protocolType.variables.map{ - variableGenerator.makeStubCode( - from: $0, - getContent: "fatalError()", - setContent: "fatalError()" - ) - } - } - - let initRows = generateInit(for: protocolType) - - if !initRows.isEmpty { - content.append("") - content += initRows - } - - let body = generateFunctionsBody(for: protocolType) - if !body.isEmpty { - content.append("") - content += body - } - - return content - } - - private func generateInit(for type: ProtocolDeclaration) -> [String] { - guard accessLevel == .public else { - return [] - } - - var result = [String]() - result.append("\t\(accessLevel.makeContentString())init() {") - result.append("\t}") - return result - } - - private func generateFunctionsBody(for protocolType: ProtocolDeclaration) -> [String] { - var rows = [[String]]() - - for function in protocolType.functions { - rows.append(generateDummy(of: function)) - } - - return rows.joined(separator: [""]).compactMap({ $0 }) - } - - private func makeArgument(from variable: VarDeclaration) -> String? { - if variable.type.isOptional { - return nil - } else { - let typeString = TypeStringFactory.makeInitString(variable.type) - return "\(variable.identifier): \(typeString)" - } - } - - private func makeAssigment(of variable: VarDeclaration) -> String? { - if variable.type.isOptional { - return nil - } else { - return "\t\tself.\(variable.identifier) = \(variable.identifier)" - } - } - - private func makeReturnArgument(of function: FunctionDeclaration) -> String? { - guard let returnType = function.returnType, !returnType.isOptional else { - return nil - } - let functionName = getName(from: function) - let typeString = TypeStringFactory.makeInitString(returnType) - return "\(functionName)Return: \(typeString)" - } - - private func makeReturnAssigment(of function: FunctionDeclaration) -> String? { - guard let returnType = function.returnType, !returnType.isOptional else { - return nil - } - let functionName = getName(from: function) - - return "\t\tself.\(functionName)Return = \(functionName)Return" - } - - private func getName(from function: FunctionDeclaration) -> String { - let argumentsTitles = function.arguments.map(getArgumentName(from:)).joined() - let arguments = isFunctionNameUnique(function) ? argumentsTitles : "" - - return "\(function.name)\(arguments)" - } - - private func getArgumentName(from type: ArgumentDeclaration) -> String { - if let label = type.label, label != "_" { - return label.capitalizingFirstLetter() - } else { - return type.name.capitalizingFirstLetter() - } - } - - private func isFunctionNameUnique(_ function: FunctionDeclaration) -> Bool { - guard let protocolType = protocolType else { - return false - } - - var matchCount = 0 - - for fc in protocolType.functions { - if fc.name == function.name { - matchCount += 1 - } - } - - return matchCount > 1 - } - - private func generateArgument(_ argument: ArgumentDeclaration) -> String { - let labelString: String - - if let label = argument.label { - labelString = "\(label) " - } else { - labelString = "" - } - let typeString = TypeStringFactory.makeFunctionArgumentString(argument.type) - return "\(labelString)\(argument.name): \(typeString)" - } - - private func generateDummy(of function: FunctionDeclaration) -> [String] { - var result = [String]() - let argumentsString = function.arguments.map(generateArgument).joined(separator: ", ") - var returnString = "" - - if function.isAsync { - returnString += "async " - } - - if function.isThrowing { - returnString += "throws " - } - - if let returnType = function.returnType { - let returnTypeString = TypeStringFactory.makeSimpleString(returnType) - returnString += "-> \(returnTypeString) " - } - - result.append("\t\(accessLevel.makeContentString())func \(function.name)(\(argumentsString)) \(returnString){") - result.append("\t\tfatalError()") - result.append("\t}") - return result - } -} diff --git a/Rubicon/Sources/Rubicon/Generator/DummyGenerator.swift b/Rubicon/Sources/Rubicon/Generator/DummyGenerator.swift new file mode 100644 index 0000000..d56f926 --- /dev/null +++ b/Rubicon/Sources/Rubicon/Generator/DummyGenerator.swift @@ -0,0 +1,69 @@ +final class DummyGenerator { + private let protocolGenerator: ProtocolGenerator + private let variableGenerator: VariableGenerator + private let functionGenerator: FunctionGenerator + private let accessLevel: AccessLevel + private let accessLevelGenerator: AccessLevelGenerator + + init( + protocolGenerator: ProtocolGenerator, + variableGenerator: VariableGenerator, + functionGenerator: FunctionGenerator, + accessLevel: AccessLevel, + accessLevelGenerator: AccessLevelGenerator + ) { + self.protocolGenerator = protocolGenerator + self.variableGenerator = variableGenerator + self.functionGenerator = functionGenerator + self.accessLevel = accessLevel + self.accessLevelGenerator = accessLevelGenerator + } + + func generate(from protocolType: ProtocolDeclaration) -> String { + let content = generateBody(from: protocolType) + return protocolGenerator.makeProtocol( + from: protocolType, + stub: "Dummy", + content: content.joined(separator: "\n") + ) + } + + private func generateBody(from protocolType: ProtocolDeclaration) -> [String] { + var content = [String]() + + if !protocolType.variables.isEmpty { + content += protocolType.variables.map{ + variableGenerator.makeStubCode( + from: $0, + getContent: "\t\t\tfatalError()", + setContent: "\t\t\tfatalError()" + ) + } + content.append("") + } + + let initRows = generateInit(for: protocolType) + + if !initRows.isEmpty { + content.append(initRows) + } + + content += protocolType.functions.map { + functionGenerator.makeCode(from: $0, content: "\t\tfatalError()") + "\n" + } + + return content + } + + private func generateInit(for type: ProtocolDeclaration) -> String { + guard accessLevel == .public else { + return "" + } + + return """ + \t\(accessLevelGenerator.makeContentAccessLevel())init() { + \t} + + """ + } +} diff --git a/Rubicon/Sources/Rubicon/Generator/FunctionGenerator.swift b/Rubicon/Sources/Rubicon/Generator/FunctionGenerator.swift new file mode 100644 index 0000000..3fa61ca --- /dev/null +++ b/Rubicon/Sources/Rubicon/Generator/FunctionGenerator.swift @@ -0,0 +1,47 @@ +protocol FunctionGenerator { + func makeCode(from declaration: FunctionDeclaration, content: String) -> String +} + +final class FunctionGeneratorImpl: FunctionGenerator { + private let accessLevelGenerator: AccessLevelGenerator + private let typeGenerator: TypeGenerator + private let argumentGenerator: ArgumentGenerator + + init( + accessLevelGenerator: AccessLevelGenerator, + typeGenerator: TypeGenerator, + argumentGenerator: ArgumentGenerator + ) { + self.accessLevelGenerator = accessLevelGenerator + self.typeGenerator = typeGenerator + self.argumentGenerator = argumentGenerator + } + + func makeCode(from declaration: FunctionDeclaration, content: String) -> String { + let returnString = makeReturn(from: declaration) + let arguments = declaration.arguments.map(argumentGenerator.makeCode(from:)).joined(separator: ", ") + return """ + \t\(accessLevelGenerator.makeContentAccessLevel())func \(declaration.name)(\(arguments)) \(returnString){ + \(content) + \t} + """ + } + + private func makeReturn(from declaration: FunctionDeclaration) -> String { + var result = "" + + if declaration.isAsync { + result += "async " + } + + if declaration.isThrowing { + result += "throws " + } + + if let returnType = declaration.returnType { + result += "-> \(typeGenerator.makeVariableCode(from: returnType)) " + } + + return result + } +} diff --git a/Rubicon/Sources/Rubicon/Generator/TypeGenerator.swift b/Rubicon/Sources/Rubicon/Generator/TypeGenerator.swift index ce9a723..b8ed219 100644 --- a/Rubicon/Sources/Rubicon/Generator/TypeGenerator.swift +++ b/Rubicon/Sources/Rubicon/Generator/TypeGenerator.swift @@ -1,9 +1,14 @@ protocol TypeGenerator { func makeVariableCode(from declaration: TypeDeclaration) -> String + func makeArgumentCode(from declaration: TypeDeclaration) -> String } final class TypeGeneratorImpl: TypeGenerator { func makeVariableCode(from declaration: TypeDeclaration) -> String { return declaration.name } + + func makeArgumentCode(from declaration: TypeDeclaration) -> String { + return (declaration.prefix.map(\.rawValue) + [declaration.name]).joined(separator: " ") + } } diff --git a/Rubicon/Sources/Rubicon/Generator/VariableGenerator.swift b/Rubicon/Sources/Rubicon/Generator/VariableGenerator.swift index b4c1ba8..8376a47 100644 --- a/Rubicon/Sources/Rubicon/Generator/VariableGenerator.swift +++ b/Rubicon/Sources/Rubicon/Generator/VariableGenerator.swift @@ -18,23 +18,21 @@ final class VariableGeneratorImpl: VariableGenerator { if declaration.isConstant { return """ \t\(accessLevelGenerator.makeContentAccessLevel())var \(declaration.identifier): \(typeGenerator.makeVariableCode(from: declaration.type)) { - \tget { - \t\tgetContent + \t\tget { + \(getContent) + \t\t} \t} - } - """ } else { return """ \t\(accessLevelGenerator.makeContentAccessLevel())var \(declaration.identifier): \(typeGenerator.makeVariableCode(from: declaration.type)) { - \tget { - \t\tgetContent - \t} - \tset { - \t\tsetContent + \t\tget { + \(getContent) + \t\t} + \t\tset { + \(setContent) + \t\t} \t} - } - """ } } diff --git a/Rubicon/Sources/Rubicon/Integration/Rubicon.swift b/Rubicon/Sources/Rubicon/Integration/Rubicon.swift new file mode 100644 index 0000000..c433c1e --- /dev/null +++ b/Rubicon/Sources/Rubicon/Integration/Rubicon.swift @@ -0,0 +1,60 @@ +public final class Rubicon { + public init() {} + + public func makeDummy(code: String, accessLevel: AccessLevel) -> [String] { + let parser = makeParser() + let dummyGenerator = makeDummyGenerator(accessLevel: accessLevel) + do { + let protocols = try parser.parse(text: code) + return protocols.map(dummyGenerator.generate(from:)) + } catch { + return [] + } + } + + private func makeDummyGenerator(accessLevel: AccessLevel) -> DummyGenerator { + let accessLevelGenerator = AccessLevelGeneratorImpl( + accessLevel: accessLevel + ) + let protocolGenerator = ProtocolGeneratorImpl( + accessLevelGenerator: accessLevelGenerator + ) + let typeGenerator = TypeGeneratorImpl() + let variableGenerator = VariableGeneratorImpl( + typeGenerator: typeGenerator, + accessLevelGenerator: accessLevelGenerator + ) + let argumentGenerator = ArgumentGeneratorImpl(typeGenerator: typeGenerator) + let functionGenerator = FunctionGeneratorImpl( + accessLevelGenerator: accessLevelGenerator, + typeGenerator: typeGenerator, + argumentGenerator: argumentGenerator + ) + return DummyGenerator( + protocolGenerator: protocolGenerator, + variableGenerator: variableGenerator, + functionGenerator: functionGenerator, + accessLevel: accessLevel, + accessLevelGenerator: accessLevelGenerator + ) + } + + private func makeParser() -> ProtocolParser { + let typeDeclarationParser = TypeDeclarationParserImpl() + let argumentDeclarationParser = ArgumentDeclarationParserImpl( + typeDeclarationParser: typeDeclarationParser + ) + let functionParser = FunctionDeclarationParserImpl( + typeDeclarationParser: typeDeclarationParser, + argumentDeclarationParser: argumentDeclarationParser + ) + let varParser = VarDeclarationParserImpl( + typeDeclarationParser: typeDeclarationParser + ) + return ProtocolParserImpl( + functionParser: functionParser, + varParser: varParser + ) + } + +} diff --git a/Rubicon/Sources/Rubicon/Syntactic analysis/Parser/TypeDeclarationParser.swift b/Rubicon/Sources/Rubicon/Syntactic analysis/Parser/TypeDeclarationParser.swift index ee456a9..482d7f3 100644 --- a/Rubicon/Sources/Rubicon/Syntactic analysis/Parser/TypeDeclarationParser.swift +++ b/Rubicon/Sources/Rubicon/Syntactic analysis/Parser/TypeDeclarationParser.swift @@ -19,7 +19,7 @@ final class TypeDeclarationParserImpl: TypeDeclarationParser { ) } else { return TypeDeclaration( - name: node.description, + name: node.description.trimmingCharacters(in: .whitespacesAndNewlines), isOptional: isOptional(node: node), prefix: [] ) diff --git a/Rubicon/Tests/RubiconTests/Generator/ArgumentGeneratorTests.swift b/Rubicon/Tests/RubiconTests/Generator/ArgumentGeneratorTests.swift new file mode 100644 index 0000000..02472d6 --- /dev/null +++ b/Rubicon/Tests/RubiconTests/Generator/ArgumentGeneratorTests.swift @@ -0,0 +1,32 @@ +@testable import Rubicon +import XCTest + +final class ArgumentGeneratorTests: XCTestCase { + private var typeGeneratorSpy: TypeGeneratorSpy! + private var sut: ArgumentGeneratorImpl! + + override func setUp() { + super.setUp() + typeGeneratorSpy = TypeGeneratorSpy(makeVariableCodeReturn: "", makeArgumentCodeReturn: "Type") + sut = ArgumentGeneratorImpl( + typeGenerator: typeGeneratorSpy + ) + } + + func test_givenTypeWithoutLabel_whenMakeCode_thenReturnCode() { + let declaration = ArgumentDeclaration.makeStub(label: nil) + + let code = sut.makeCode(from: declaration) + + XCTAssertEqual(code, "name: Type") + + } + + func test_givenTypeWithLabel_whenMakeCode_thenReturnCode() { + let declaration = ArgumentDeclaration.makeStub() + + let code = sut.makeCode(from: declaration) + + XCTAssertEqual(code, "label name: Type") + } +} diff --git a/Rubicon/Tests/RubiconTests/Generator/CreateDummyInteractorTests.swift b/Rubicon/Tests/RubiconTests/Generator/CreateDummyInteractorTests.swift deleted file mode 100644 index 86fd187..0000000 --- a/Rubicon/Tests/RubiconTests/Generator/CreateDummyInteractorTests.swift +++ /dev/null @@ -1,589 +0,0 @@ -@testable import Rubicon -import XCTest - -final class CreateDummyInteractorTests: XCTestCase { - private var protocolGeneratorSpy: ProtocolGeneratorSpy! - private var variableGeneratorSpy: VariableGeneratorSpy! - private var sut: CreateDummyInteractor! - private let type = TypeDeclaration.makeStub(name: "Color", isOptional: false) - - override func setUp() { - super.setUp() - protocolGeneratorSpy = ProtocolGeneratorSpy(makeProtocolReturn: "result") - variableGeneratorSpy = VariableGeneratorSpy(makeStubCodeReturn: "variable") - sut = CreateDummyInteractor(protocolGenerator: protocolGeneratorSpy,variableGenerator: variableGeneratorSpy) - } - - func test_givenEmptyProtocol_whenGenerate_thenGenerateEmptyDummy() { - let result = sut.generate(from: .makeStub()) - - XCTAssertEqual(protocolGeneratorSpy.makeProtocol.count, 1) - XCTAssertEqual(protocolGeneratorSpy.makeProtocol.first?.declaration, .makeStub()) - XCTAssertEqual(protocolGeneratorSpy.makeProtocol.first?.stub, "Dummy") - XCTAssertEqual(protocolGeneratorSpy.makeProtocol.first?.content, "") - XCTAssertEqual(result, "result") - } - - func test_givenProtocolWithVariables_whenGenerate_thenGenerateDummy() { - let protocolDeclaration = ProtocolDeclaration.makeStub(variables: [.makeStub()]) - - let result = sut.generate(from: protocolDeclaration) - - XCTAssertEqual(protocolGeneratorSpy.makeProtocol.first?.content, "variable") - XCTAssertEqual(variableGeneratorSpy.makeStubCode.count, 1) - XCTAssertEqual(variableGeneratorSpy.makeStubCode.first?.declaration, .makeStub()) - XCTAssertEqual(variableGeneratorSpy.makeStubCode.first?.getContent, "fatalError()") - XCTAssertEqual(variableGeneratorSpy.makeStubCode.first?.setContent, "fatalError()") - } - -// func test_givenProtocolWithVariable_whenGenerate_thenGenerateDummy() { -// let protocolType = ProtocolDeclaration.makeStub(variables: [.makeStub()]) -// -// equal(protocolType: protocolType, rows: [ -// "final class NameDummy: Name {", -// "", -// "\tvar identifier: Int {", -// "\t\tget {", -// "\t\t\tfatalError()", -// "\t\t}", -// "\t\tset {", -// "\t\t\tfatalError()", -// "\t\t}", -// "\t}", -// "}", -// "", -// ]) -// } -// -// func test_givenProtocolWithEscapingClosureVariable_whenGenerate_thenGenerateDummy() { -// let type = TypeDeclaration.makeStub(name: "(() -> Void)", isOptional: false) -// let variable = VarDeclaration(isConstant: false, identifier: "closeBlock", type: type) -// let protocolType = ProtocolDeclaration.makeStub(variables: [variable]) -// -// equal(protocolType: protocolType, rows: [ -// "final class NameDummy: Name {", -// "", -// "\tvar closeBlock: (() -> Void) {", -// "\t\tget {", -// "\t\t\tfatalError()", -// "\t\t}", -// "\t\tset {", -// "\t\t\tfatalError()", -// "\t\t}", -// "\t}", -// "}", -// "", -// ]) -// } -// -// func test_givenProtocolWithConstant_whenGenerate_thenGenerateDummy() { -// let type = TypeDeclaration.makeStub(name: "Color", isOptional: false) -// let variable = VarDeclaration(isConstant: true, identifier: "color", type: type) -// let protocolType = ProtocolDeclaration.makeStub(variables: [variable]) -// equal(protocolType: protocolType, rows: [ -// "final class NameDummy: Name {", -// "", -// "\tvar color: Color {", -// "\t\tfatalError()", -// "\t}", -// "}", -// "", -// ]) -// } -// -// func test_givenProtocolWithOptional_whenGenerate_thenGenerateDummy() { -// let type = TypeDeclaration.makeStub(name: "Color", isOptional: true) -// let variable = VarDeclaration(isConstant: true, identifier: "color", type: type) -// let protocolType = ProtocolDeclaration.makeStub(variables: [variable]) -// equal(protocolType: protocolType, rows: [ -// "final class NameDummy: Name {", -// "", -// "\tvar color: Color? {", -// "\t\tfatalError()", -// "\t}", -// "}", -// "", -// ]) -// } -// -// func test_givenProtocolWithTwoVariables_whenGenerate_thenGenerateDummy() { -// let variable1 = VarDeclaration(isConstant: false, identifier: "color1", type: type) -// let variable2 = VarDeclaration(isConstant: false, identifier: "color2", type: type) -// let protocolType = ProtocolDeclaration.makeStub(variables: [variable1, variable2]) -// -// equal(protocolType: protocolType, rows: [ -// "final class NameDummy: Name {", -// "", -// "\tvar color1: Color {", -// "\t\tget {", -// "\t\t\tfatalError()", -// "\t\t}", -// "\t\tset {", -// "\t\t\tfatalError()", -// "\t\t}", -// "\t}", -// "\tvar color2: Color {", -// "\t\tget {", -// "\t\t\tfatalError()", -// "\t\t}", -// "\t\tset {", -// "\t\t\tfatalError()", -// "\t\t}", -// "\t}", -// "}", -// "", -// ]) -// } -// -// func test_givenProtocolWithSimpleFunction_whenGenerate_thenGenerateDummy() { -// let function = FunctionDeclaration.makeStub() -// let protocolType = ProtocolDeclaration.makeStub(functions: [function]) -// -// equal(protocolType: protocolType, rows: [ -// "final class NameDummy: Name {", -// "", -// "\tfunc name() {", -// "\t\tfatalError()", -// "\t}", -// "}", -// "", -// ]) -// } -// - //// -// func test_givenProtocolWithFunctionWithReturn_whenGenerate_thenGenerateDummy() { -// let function = FunctionDeclaration.makeStub(returnType: .makeStub(name: "Int", isOptional: false)) -// let protocolType = ProtocolDeclaration.makeStub(functions: [function]) -// -// equal(protocolType: protocolType, rows: [ -// "final class NameDummy: Name {", -// "", -// "\tfunc name() -> Int {", -// "\t\tfatalError()", -// "\t}", -// "}", -// "", -// ]) -// } -// -// func test_givenProtocolWithAsyncFunction_whenGenerate_thenGenerateDummy() { -// let function = FunctionDeclaration.makeStub(isAsync: true) -// let protocolType = ProtocolDeclaration.makeStub(functions: [function]) -// -// equal(protocolType: protocolType, rows: [ -// "final class NameDummy: Name {", -// "", -// "\tfunc name() async {", -// "\t\tfatalError()", -// "\t}", -// "}", -// "", -// ]) -// } -// -// func test_givenProtocolWithThrowingFunction_whenGenerate_thenGenerateDummy() { -// let function = FunctionDeclaration.makeStub(isThrowing: true) -// let protocolType = ProtocolDeclaration.makeStub(functions: [function]) -// -// equal(protocolType: protocolType, rows: [ -// "final class NameDummy: Name {", -// "", -// "\tfunc name() throws {", -// "\t\tfatalError()", -// "\t}", -// "}", -// "", -// ]) -// } -// -// func test_givenProtocolWithThrowingAndAsyncFunction_whenGenerate_thenGenerateDummy() { -// let function = FunctionDeclaration.makeStub(isThrowing: true, isAsync: true, returnType: .makeStub(name: "Int", isOptional: false)) -// let protocolType = ProtocolDeclaration.makeStub(functions: [function]) -// -// equal(protocolType: protocolType, rows: [ -// "final class NameDummy: Name {", -// "", -// "\tfunc name() async throws -> Int {", -// "\t\tfatalError()", -// "\t}", -// "}", -// "", -// ]) -// } -// -// func test_givenProtocolWithThrowingFunctionWithArguments_whenGenerate_thenGenerateDummy() { -// let argument = ArgumentDeclaration(label: "with", name: "label", type: type) -// let function = FunctionDeclaration.makeStub(arguments: [argument], isThrowing: true, returnType: .makeStub(name: "Int", isOptional: false)) -// let protocolType = ProtocolDeclaration.makeStub(functions: [function]) -// -// equal(protocolType: protocolType, rows: [ -// "final class NameDummy: Name {", -// "", -// "\tfunc name(with label: Color) throws -> Int {", -// "\t\tfatalError()", -// "\t}", -// "}", -// "", -// ]) -// } -// -// func test_givenProtocolWithMultipleReturnFunctions_whenGenerate_thenGenerateDummy() { -// let function = FunctionDeclaration.makeStub(name: "start", returnType: .makeStub(name: "Int", isOptional: false)) -// let function2 = FunctionDeclaration.makeStub(name: "stop", returnType: .makeStub(name: "Int", isOptional: false)) -// let protocolType = ProtocolDeclaration.makeStub(functions: [function, function2]) -// -// equal(protocolType: protocolType, rows: [ -// "final class NameDummy: Name {", -// "", -// "\tfunc start() -> Int {", -// "\t\tfatalError()", -// "\t}", -// "", -// "\tfunc stop() -> Int {", -// "\t\tfatalError()", -// "\t}", -// "}", -// "", -// ]) -// } -// -// func test_givenProtocolWithFunctionWithEscapingType_whenGenerate_thenGenerateDummy() { -// let argumentType = TypeDeclaration.makeStub(name: "ActionBlock", isOptional: false, prefix: [.escaping]) -// let argument = ArgumentDeclaration(label: "with", name: "action", type: argumentType) -// let function = FunctionDeclaration.makeStub(name: "start", arguments: [argument], returnType: nil) -// let protocolType = ProtocolDeclaration.makeStub(functions: [function]) -// -// equal(protocolType: protocolType, rows: [ -// "final class NameDummy: Name {", -// "", -// "\tfunc start(with action: @escaping ActionBlock) {", -// "\t\tfatalError()", -// "\t}", -// "}", -// "", -// ]) -// } -// -// func test_givenProtocolWithFunctionWithClosureParameterAndReturnClosure_whenGenerate_thenGenerateDummy() { -// let argumentType = TypeDeclaration.makeStub(name: "(String) -> Int", isOptional: false, prefix: [.escaping]) -// let argument = ArgumentDeclaration(label: "with", name: "mapping", type: argumentType) -// let returnType = TypeDeclaration.makeStub(name: "(Data) -> Void", isOptional: false) -// let function = FunctionDeclaration.makeStub(name: "start", arguments: [argument], returnType: returnType) -// let protocolType = ProtocolDeclaration.makeStub(functions: [function]) -// -// equal(protocolType: protocolType, rows: [ -// "final class NameDummy: Name {", -// "", -// "\tfunc start(with mapping: @escaping (String) -> Int) -> (Data) -> Void {", -// "\t\tfatalError()", -// "\t}", -// "}", -// "", -// ]) -// } -// -// func test_givenProtocolWithFunctionWithThrowingAutoclosureArgument_whenGenerate_thenGenerateDummy() { -// let type = TypeDeclaration.makeStub(name: "(Window) throws -> Air", isOptional: false) -// let function = FunctionDeclaration.makeStub(name: "rollDown", arguments: [], returnType: type) -// let protocolType = ProtocolDeclaration.makeStub(functions: [function]) -// -// equal(protocolType: protocolType, rows: [ -// "final class NameDummy: Name {", -// "", -// "\tfunc rollDown() -> (Window) throws -> Air {", -// "\t\tfatalError()", -// "\t}", -// "}", -// "", -// ]) -// } -// -// func test_givenProtocolWithFunctionWithClosureAndIntParameterAndOptionalReturnClosure_whenGenerate_thenGenerateDummy() { -// let closureArgumentType = TypeDeclaration.makeStub(name: "(String) -> Int", isOptional: false, prefix: [.escaping]) -// let closureArgument = ArgumentDeclaration(label: "with", name: "mapping", type: closureArgumentType) -// let intType = TypeDeclaration.makeStub(name: "Int", isOptional: false) -// let intArgument = ArgumentDeclaration(label: nil, name: "count", type: intType) -// let returnType = TypeDeclaration.makeStub(name: "((Data) -> Void)", isOptional: true) -// let function = FunctionDeclaration.makeStub(name: "start", arguments: [closureArgument, intArgument], returnType: returnType) -// let protocolType = ProtocolDeclaration.makeStub(functions: [function]) -// -// equal(protocolType: protocolType, rows: [ -// "final class NameDummy: Name {", -// "", -// "\tfunc start(with mapping: @escaping (String) -> Int, count: Int) -> ((Data) -> Void)? {", -// "\t\tfatalError()", -// "\t}", -// "}", -// "", -// ]) -// } -// -// func test_givenProtocolWithFunctionWithArgument_whenGenerate_thenGenerateDummy() { -// let argument = ArgumentDeclaration(label: "a", name: "b", type: type) -// let function = FunctionDeclaration.makeStub(name: "start", arguments: [argument]) -// let protocolType = ProtocolDeclaration.makeStub(functions: [function]) -// -// equal(protocolType: protocolType, rows: [ -// "final class NameDummy: Name {", -// "", -// "\tfunc start(a b: Color) {", -// "\t\tfatalError()", -// "\t}", -// "}", -// "", -// ]) -// } -// -// func test_givenProtocolWithFunctionWithNoLabelAndArgument_whenGenerate_thenGenerateDummy() { -// let argument = ArgumentDeclaration(label: "_", name: "b", type: type) -// let function = FunctionDeclaration.makeStub(name: "start", arguments: [argument]) -// let protocolType = ProtocolDeclaration.makeStub(functions: [function]) -// -// equal(protocolType: protocolType, rows: [ -// "final class NameDummy: Name {", -// "", -// "\tfunc start(_ b: Color) {", -// "\t\tfatalError()", -// "\t}", -// "}", -// "", -// ]) -// } -// -// func test_givenProtocolWithFunctionWithTwoArguments_whenGenerate_thenGenerateDummy() { -// let argument = ArgumentDeclaration(label: "a", name: "b", type: type) -// let type2 = TypeDeclaration.makeStub(name: "Color", isOptional: true) -// let argument2 = ArgumentDeclaration(label: nil, name: "d", type: type2) -// let function = FunctionDeclaration.makeStub(name: "start", arguments: [argument, argument2]) -// let protocolType = ProtocolDeclaration.makeStub(functions: [function]) -// -// equal(protocolType: protocolType, rows: [ -// "final class NameDummy: Name {", -// "", -// "\tfunc start(a b: Color, d: Color?) {", -// "\t\tfatalError()", -// "\t}", -// "}", -// "", -// ]) -// } -// -// func test_givenProtocolWithTwoFunctionWithArgument_whenGenerate_thenGenerateDummy() { -// let argument = ArgumentDeclaration(label: "a", name: "b", type: type) -// let function = FunctionDeclaration.makeStub(name: "start", arguments: [argument]) -// let function2 = FunctionDeclaration.makeStub(name: "stop", arguments: [argument]) -// let protocolType = ProtocolDeclaration.makeStub(functions: [function, function2]) -// -// equal(protocolType: protocolType, rows: [ -// "final class NameDummy: Name {", -// "", -// "\tfunc start(a b: Color) {", -// "\t\tfatalError()", -// "\t}", -// "", -// "\tfunc stop(a b: Color) {", -// "\t\tfatalError()", -// "\t}", -// "}", -// "", -// ]) -// } -// -// func test_givenProtocolWithFunctionAndVarible_whenGenerate_thenGenerateDummy() { -// let variable = VarDeclaration(isConstant: false, identifier: "color", type: type) -// let argument = ArgumentDeclaration(label: "a", name: "b", type: type) -// let function = FunctionDeclaration.makeStub(name: "start", arguments: [argument]) -// let protocolType = ProtocolDeclaration.makeStub(variables: [variable], functions: [function]) -// -// equal(protocolType: protocolType, rows: [ -// "final class NameDummy: Name {", -// "", -// "\tvar color: Color {", -// "\t\tget {", -// "\t\t\tfatalError()", -// "\t\t}", -// "\t\tset {", -// "\t\t\tfatalError()", -// "\t\t}", -// "\t}", -// "", -// "\tfunc start(a b: Color) {", -// "\t\tfatalError()", -// "\t}", -// "}", -// "", -// ]) -// } -// -// func test_givenProtocolWithLongNames_whenGenerate_thenDummyIsGenerated() { -// let argument = ArgumentDeclaration(label: nil, name: "productId", type: type) -// let function = FunctionDeclaration.makeStub(name: "startGenerating", arguments: [argument]) -// let protocolType = ProtocolDeclaration.makeStub(functions: [function]) -// -// equal(protocolType: protocolType, rows: [ -// "final class NameDummy: Name {", -// "", -// "\tfunc startGenerating(productId: Color) {", -// "\t\tfatalError()", -// "\t}", -// "}", -// "", -// ]) -// } -// -// func test_givenProtocolWithSameFunctionNames_whenGenerate_thenGenerateDummy() { -// let argument = ArgumentDeclaration(label: "a", name: "b", type: type) -// let argument2 = ArgumentDeclaration(label: "c", name: "d", type: type) -// let function = FunctionDeclaration.makeStub(name: "start", arguments: [argument]) -// let function2 = FunctionDeclaration.makeStub(name: "start", arguments: [argument2]) -// let protocolType = ProtocolDeclaration.makeStub(functions: [function, function2]) -// -// equal(protocolType: protocolType, rows: [ -// "final class NameDummy: Name {", -// "", -// "\tfunc start(a b: Color) {", -// "\t\tfatalError()", -// "\t}", -// "", -// "\tfunc start(c d: Color) {", -// "\t\tfatalError()", -// "\t}", -// "}", -// "", -// ]) -// } -// -// func test_givenProtocolWithNoArgumentLabelAndReturnValue_whenGenerate_thenGenerateDummy() { -// let argumentType = TypeDeclaration.makeStub(name: "Int", isOptional: true) -// let argument = ArgumentDeclaration(label: "_", name: "value", type: argumentType) -// let returnType = TypeDeclaration.makeStub(name: "String", isOptional: true) -// let function = FunctionDeclaration.makeStub(name: "formattedString", arguments: [argument], returnType: returnType) -// let protocolType = ProtocolDeclaration(name: "Formatter", parents: [], variables: [], functions: [function]) -// -// equal(protocolType: protocolType, rows: [ -// "final class FormatterDummy: Formatter {", -// "", -// "\tfunc formattedString(_ value: Int?) -> String? {", -// "\t\tfatalError()", -// "\t}", -// "}", -// "", -// ]) -// } -// -// func test_givenEmptyProtocolAndPrivate_whenGenerate_thenGenerateDummy() { -// let protocolType = ProtocolDeclaration(name: "TestTestTestTestTest", parents: [], variables: [], functions: []) -// -// equal(protocolType: protocolType, accessLevel: .private, rows: [ -// "private final class TestTestTestTestTestDummy: TestTestTestTestTest {", -// "}", -// "", -// ]) -// } -// -// func test_givenProtocolWithArgumentAndThrowingFunctionWithReturnValue_whenGeneratePublic_thenGenerateDummy() { -// let variable = VarDeclaration(isConstant: false, identifier: "color", type: type) -// let variable2 = VarDeclaration(isConstant: true, identifier: "color", type: type) -// let argumentType = TypeDeclaration.makeStub(name: "Int", isOptional: true) -// let argument = ArgumentDeclaration(label: "_", name: "value", type: argumentType) -// let returnType = TypeDeclaration.makeStub(name: "String", isOptional: true) -// let function = FunctionDeclaration.makeStub(name: "formattedString", arguments: [argument], isThrowing: true, returnType: returnType) -// let protocolType = ProtocolDeclaration(name: "Formatter", parents: [], variables: [variable, variable2], functions: [function]) -// -// equal(protocolType: protocolType, accessLevel: .public, rows: [ -// "public final class FormatterDummy: Formatter {", -// "", -// "\tpublic var color: Color {", -// "\t\tget {", -// "\t\t\tfatalError()", -// "\t\t}", -// "\t\tset {", -// "\t\t\tfatalError()", -// "\t\t}", -// "\t}", -// "\tpublic var color: Color {", -// "\t\tfatalError()", -// "\t}", -// "", -// "\tpublic init() {", -// "\t}", -// "", -// "\tpublic func formattedString(_ value: Int?) throws -> String? {", -// "\t\tfatalError()", -// "\t}", -// "}", -// "", -// ]) -// } -} - -extension TypeDeclaration { - static func makeStub( - name: String = "Int", - isOptional: Bool = false, - prefix: [Prefix] = [] - ) -> TypeDeclaration { - return TypeDeclaration( - name: name, - isOptional: isOptional, - prefix: prefix - ) - } -} - -extension ProtocolDeclaration { - static func makeStub( - variables: [VarDeclaration] = [], - functions: [FunctionDeclaration] = [] - ) -> ProtocolDeclaration { - return ProtocolDeclaration( - name: "Name", - parents: [], - variables: variables, - functions: functions - ) - } -} - -final class ProtocolGeneratorSpy: ProtocolGenerator { - struct MakeProtocol { - let declaration: ProtocolDeclaration - let stub: String - let content: String - } - - var makeProtocol = [MakeProtocol]() - var makeProtocolReturn: String - - init(makeProtocolReturn: String) { - self.makeProtocolReturn = makeProtocolReturn - } - - func makeProtocol(from declaration: ProtocolDeclaration, stub: String, content: String) -> String { - let item = MakeProtocol(declaration: declaration, stub: stub, content: content) - makeProtocol.append(item) - return makeProtocolReturn - } -} - -final class VariableGeneratorSpy: VariableGenerator { - - struct MakeStubCode { - let declaration: VarDeclaration - let getContent: String - let setContent: String - } - - var makeStubCode = [MakeStubCode]() - var makeStubCodeReturn: String - - init(makeStubCodeReturn: String) { - self.makeStubCodeReturn = makeStubCodeReturn - } - - func makeStubCode(from declaration: VarDeclaration, getContent: String, setContent: String) -> String { - let item = MakeStubCode(declaration: declaration, getContent: getContent, setContent: setContent) - makeStubCode.append(item) - return makeStubCodeReturn - } -} diff --git a/Rubicon/Tests/RubiconTests/Generator/DummyGeneratorTests.swift b/Rubicon/Tests/RubiconTests/Generator/DummyGeneratorTests.swift new file mode 100644 index 0000000..c500e28 --- /dev/null +++ b/Rubicon/Tests/RubiconTests/Generator/DummyGeneratorTests.swift @@ -0,0 +1,173 @@ +@testable import Rubicon +import XCTest + +final class DummyGeneratorTests: XCTestCase { + private var protocolGeneratorSpy: ProtocolGeneratorSpy! + private var variableGeneratorSpy: VariableGeneratorSpy! + private var functionGeneratorSpy: FunctionGeneratorSpy! + private var accessLevelGeneratorSpy: AccessLevelGeneratorSpy! + private var sut: DummyGenerator! + private let type = TypeDeclaration.makeStub(name: "Color", isOptional: false) + + override func setUp() { + super.setUp() + protocolGeneratorSpy = ProtocolGeneratorSpy(makeProtocolReturn: "result") + variableGeneratorSpy = VariableGeneratorSpy(makeStubCodeReturn: "variable") + functionGeneratorSpy = FunctionGeneratorSpy(makeCodeReturn: "function") + accessLevelGeneratorSpy = AccessLevelGeneratorSpy(makeClassAccessLevelReturn: "", makeContentAccessLevelReturn: "accessLevel ") + sut = DummyGenerator( + protocolGenerator: protocolGeneratorSpy, + variableGenerator: variableGeneratorSpy, + functionGenerator: functionGeneratorSpy, + accessLevel: .internal, + accessLevelGenerator: accessLevelGeneratorSpy + ) + } + + func test_givenEmptyProtocol_whenGenerate_thenGenerateCode() { + let result = sut.generate(from: .makeStub()) + + XCTAssertEqual(protocolGeneratorSpy.makeProtocol.count, 1) + XCTAssertEqual(protocolGeneratorSpy.makeProtocol.first?.declaration, .makeStub()) + XCTAssertEqual(protocolGeneratorSpy.makeProtocol.first?.stub, "Dummy") + XCTAssertEqual(protocolGeneratorSpy.makeProtocol.first?.content, "") + XCTAssertEqual(result, "result") + } + + func test_givenProtocolWithVariable_whenGenerate_thenGenerateDummy() { + let protocolDeclaration = ProtocolDeclaration.makeStub(variables: [.makeStub()]) + + _ = sut.generate(from: protocolDeclaration) + + XCTAssertEqual(protocolGeneratorSpy.makeProtocol.first?.content, "variable\n") + XCTAssertEqual(variableGeneratorSpy.makeStubCode.count, 1) + XCTAssertEqual(variableGeneratorSpy.makeStubCode.first?.declaration, .makeStub()) + XCTAssertEqual(variableGeneratorSpy.makeStubCode.first?.getContent, "\t\t\tfatalError()") + XCTAssertEqual(variableGeneratorSpy.makeStubCode.first?.setContent, "\t\t\tfatalError()") + } + + func test_givenProtocolWithVariables_whenGenerate_thenGenerateDummy() { + let protocolDeclaration = ProtocolDeclaration.makeStub(variables: [.makeStub(), .makeStub()]) + + _ = sut.generate(from: protocolDeclaration) + + XCTAssertEqual(protocolGeneratorSpy.makeProtocol.first?.content, "variable\nvariable\n") + XCTAssertEqual(variableGeneratorSpy.makeStubCode.count, 2) + } + + func test_givenProtocolWithFunction_whenGenerate_thenGenerateDummy() { + let protocolDeclaration = ProtocolDeclaration.makeStub(functions: [.makeStub()]) + + _ = sut.generate(from: protocolDeclaration) + + XCTAssertEqual(protocolGeneratorSpy.makeProtocol.first?.content, "function\n") + XCTAssertEqual(functionGeneratorSpy.makeCode.count, 1) + XCTAssertEqual(functionGeneratorSpy.makeCode.first?.declaration, .makeStub()) + XCTAssertEqual(functionGeneratorSpy.makeCode.first?.content, "\t\tfatalError()") + } + + func test_givenPublicAccessLevel_whenGenerate_thenGenerateCode() { + sut = DummyGenerator( + protocolGenerator: protocolGeneratorSpy, + variableGenerator: variableGeneratorSpy, + functionGenerator: functionGeneratorSpy, + accessLevel: .public, + accessLevelGenerator: accessLevelGeneratorSpy + ) + + let result = sut.generate(from: .makeStub()) + + XCTAssertEqual(protocolGeneratorSpy.makeProtocol.first?.content, "\taccessLevel init() {\n\t}\n") + XCTAssertEqual(result, "result") + } +} + +extension TypeDeclaration { + static func makeStub( + name: String = "Int", + isOptional: Bool = false, + prefix: [Prefix] = [] + ) -> TypeDeclaration { + return TypeDeclaration( + name: name, + isOptional: isOptional, + prefix: prefix + ) + } +} + +extension ProtocolDeclaration { + static func makeStub( + variables: [VarDeclaration] = [], + functions: [FunctionDeclaration] = [] + ) -> ProtocolDeclaration { + return ProtocolDeclaration( + name: "Name", + parents: [], + variables: variables, + functions: functions + ) + } +} + +final class ProtocolGeneratorSpy: ProtocolGenerator { + struct MakeProtocol { + let declaration: ProtocolDeclaration + let stub: String + let content: String + } + + var makeProtocol = [MakeProtocol]() + var makeProtocolReturn: String + + init(makeProtocolReturn: String) { + self.makeProtocolReturn = makeProtocolReturn + } + + func makeProtocol(from declaration: ProtocolDeclaration, stub: String, content: String) -> String { + let item = MakeProtocol(declaration: declaration, stub: stub, content: content) + makeProtocol.append(item) + return makeProtocolReturn + } +} + +final class VariableGeneratorSpy: VariableGenerator { + struct MakeStubCode { + let declaration: VarDeclaration + let getContent: String + let setContent: String + } + + var makeStubCode = [MakeStubCode]() + var makeStubCodeReturn: String + + init(makeStubCodeReturn: String) { + self.makeStubCodeReturn = makeStubCodeReturn + } + + func makeStubCode(from declaration: VarDeclaration, getContent: String, setContent: String) -> String { + let item = MakeStubCode(declaration: declaration, getContent: getContent, setContent: setContent) + makeStubCode.append(item) + return makeStubCodeReturn + } +} + +final class FunctionGeneratorSpy: FunctionGenerator { + struct MakeCode { + let declaration: FunctionDeclaration + let content: String + } + + var makeCode = [MakeCode]() + var makeCodeReturn: String + + init(makeCodeReturn: String) { + self.makeCodeReturn = makeCodeReturn + } + + func makeCode(from declaration: FunctionDeclaration, content: String) -> String { + let item = MakeCode(declaration: declaration, content: content) + makeCode.append(item) + return makeCodeReturn + } +} diff --git a/Rubicon/Tests/RubiconTests/Generator/FunctionGeneratorTests.swift b/Rubicon/Tests/RubiconTests/Generator/FunctionGeneratorTests.swift new file mode 100644 index 0000000..dc9cc3a --- /dev/null +++ b/Rubicon/Tests/RubiconTests/Generator/FunctionGeneratorTests.swift @@ -0,0 +1,129 @@ +@testable import Rubicon +import XCTest + +final class FunctionGeneratorTests: XCTestCase { + private var accessLevelGeneratorSpy: AccessLevelGeneratorSpy! + private var typeGeneratorSpy: TypeGeneratorSpy! + private var argumentGeneratorSpy: ArgumentGeneratorSpy! + private var sut: FunctionGeneratorImpl! + + override func setUp() { + super.setUp() + accessLevelGeneratorSpy = AccessLevelGeneratorSpy(makeClassAccessLevelReturn: "", makeContentAccessLevelReturn: "accessLevel ") + typeGeneratorSpy = TypeGeneratorSpy(makeVariableCodeReturn: "Type", makeArgumentCodeReturn: "") + argumentGeneratorSpy = ArgumentGeneratorSpy(makeCodeReturn: "argument") + sut = FunctionGeneratorImpl( + accessLevelGenerator: accessLevelGeneratorSpy, + typeGenerator: typeGeneratorSpy, + argumentGenerator: argumentGeneratorSpy + ) + } + + func test_whenGenerate_thenGenerateCode() { + let declaration = FunctionDeclaration.makeStub() + + let code = sut.makeCode(from: declaration, content: "content") + + equal(string: code, rows: [ + "\taccessLevel func name() {", + "content", + "\t}", + ]) + XCTAssertEqual(accessLevelGeneratorSpy.makeContentAccessLevelCount, 1) + } + + func test_givenThrow_whenGenerate_thenGenerateCode() { + let declaration = FunctionDeclaration.makeStub(isThrowing: true) + + let code = sut.makeCode(from: declaration, content: "content") + + equal(string: code, rows: [ + "\taccessLevel func name() throws {", + "content", + "\t}", + ]) + } + + func test_givenAsync_whenGenerate_thenGenerateCode() { + let declaration = FunctionDeclaration.makeStub(isAsync: true) + + let code = sut.makeCode(from: declaration, content: "content") + + equal(string: code, rows: [ + "\taccessLevel func name() async {", + "content", + "\t}", + ]) + } + + func test_givenThrowAndAsync_whenGenerate_thenGenerateCode() { + let declaration = FunctionDeclaration.makeStub(isThrowing: true, isAsync: true) + + let code = sut.makeCode(from: declaration, content: "content") + + equal(string: code, rows: [ + "\taccessLevel func name() async throws {", + "content", + "\t}", + ]) + } + + func test_givenThrowAndAsyncAndResult_whenGenerate_thenGenerateCode() { + let declaration = FunctionDeclaration.makeStub(isThrowing: true, isAsync: true, returnType: .makeStub()) + + let code = sut.makeCode(from: declaration, content: "content") + + equal(string: code, rows: [ + "\taccessLevel func name() async throws -> Type {", + "content", + "\t}", + ]) + } + + func test_givenArgument_whenGenerate_thenGenerateCode() { + let declaration = FunctionDeclaration.makeStub(arguments: [.makeStub()]) + + let code = sut.makeCode(from: declaration, content: "content") + + equal(string: code, rows: [ + "\taccessLevel func name(argument) {", + "content", + "\t}", + ]) + XCTAssertEqual(argumentGeneratorSpy.makeCode.count, 1) + XCTAssertEqual(argumentGeneratorSpy.makeCode.first?.declaration, .makeStub()) + } + + func test_givenArguments_whenGenerate_thenGenerateCode() { + let declaration = FunctionDeclaration.makeStub(arguments: [.makeStub(), .makeStub(label: "a", name: "b", type: .makeStub())]) + + let code = sut.makeCode(from: declaration, content: "content") + + equal(string: code, rows: [ + "\taccessLevel func name(argument, argument) {", + "content", + "\t}", + ]) + XCTAssertEqual(argumentGeneratorSpy.makeCode.count, 2) + } +} + +final class ArgumentGeneratorSpy: ArgumentGenerator { + + struct MakeCode { + let declaration: ArgumentDeclaration + } + + var makeCode = [MakeCode]() + var makeCodeReturn: String + + init(makeCodeReturn: String) { + self.makeCodeReturn = makeCodeReturn + } + + func makeCode(from declaration: ArgumentDeclaration) -> String { + let item = MakeCode(declaration: declaration) + makeCode.append(item) + return makeCodeReturn + } +} diff --git a/Rubicon/Tests/RubiconTests/Generator/ProtocolGeneratorTests.swift b/Rubicon/Tests/RubiconTests/Generator/ProtocolGeneratorTests.swift index 1f8cdee..a37431c 100644 --- a/Rubicon/Tests/RubiconTests/Generator/ProtocolGeneratorTests.swift +++ b/Rubicon/Tests/RubiconTests/Generator/ProtocolGeneratorTests.swift @@ -11,7 +11,7 @@ final class ProtocolGeneratorTests: XCTestCase { sut = ProtocolGeneratorImpl(accessLevelGenerator: accessLevelGeneratorSpy) } - func test_whenGenerate_thenGenerateEmptyStub() { + func test_whenGenerate_thenGenerateCode() { let code = sut.makeProtocol(from: .makeStub(), stub: "Dummy", content: "content") equal(string: code, rows: [ diff --git a/Rubicon/Tests/RubiconTests/Generator/TypeGeneratorTests.swift b/Rubicon/Tests/RubiconTests/Generator/TypeGeneratorTests.swift index 2b49112..0576a87 100644 --- a/Rubicon/Tests/RubiconTests/Generator/TypeGeneratorTests.swift +++ b/Rubicon/Tests/RubiconTests/Generator/TypeGeneratorTests.swift @@ -9,7 +9,7 @@ final class TypGeneratorTests: XCTestCase { sut = TypeGeneratorImpl() } - func test_whenGenerate_thenGenerateCode() { + func test_whenMakeVariable_thenGenerateCode() { let typeDeclaration = TypeDeclaration.makeStub() let code = sut.makeVariableCode(from: typeDeclaration) @@ -17,7 +17,7 @@ final class TypGeneratorTests: XCTestCase { XCTAssertEqual(code, "Int") } - func test_givenClosure_whenGenerate_thenGenerateCode() { + func test_givenClosure_whenMakeVariable_thenGenerateCode() { let typeDeclaration = TypeDeclaration.makeStub(name: "() -> Void", prefix: [.escaping]) let code = sut.makeVariableCode(from: typeDeclaration) @@ -25,7 +25,7 @@ final class TypGeneratorTests: XCTestCase { XCTAssertEqual(code, "() -> Void") } - func test_givenOptional_whenGenerate_thenGenerateCode() { + func test_givenOptional_whenMakeVariable_thenGenerateCode() { let typeDeclaration = TypeDeclaration.makeStub(name: "() -> Void?", isOptional: true) let code = sut.makeVariableCode(from: typeDeclaration) @@ -33,4 +33,27 @@ final class TypGeneratorTests: XCTestCase { XCTAssertEqual(code, "() -> Void?") } + func test_whenMakeArgument_thenGenerateCode() { + let typeDeclaration = TypeDeclaration.makeStub() + + let code = sut.makeArgumentCode(from: typeDeclaration) + + XCTAssertEqual(code, "Int") + } + + func test_givenClosure_whenMakeArgument_thenGenerateCode() { + let typeDeclaration = TypeDeclaration.makeStub(name: "() -> Void", prefix: [.escaping]) + + let code = sut.makeArgumentCode(from: typeDeclaration) + + XCTAssertEqual(code, "@escaping () -> Void") + } + + func test_givenOptional_whenMakeArgument_thenGenerateCode() { + let typeDeclaration = TypeDeclaration.makeStub(name: "() -> Void?", isOptional: true) + + let code = sut.makeArgumentCode(from: typeDeclaration) + + XCTAssertEqual(code, "() -> Void?") + } } diff --git a/Rubicon/Tests/RubiconTests/Generator/VariableGeneratorTests.swift b/Rubicon/Tests/RubiconTests/Generator/VariableGeneratorTests.swift index a147f2c..6a75b07 100644 --- a/Rubicon/Tests/RubiconTests/Generator/VariableGeneratorTests.swift +++ b/Rubicon/Tests/RubiconTests/Generator/VariableGeneratorTests.swift @@ -8,7 +8,7 @@ final class VariableGeneratorTests: XCTestCase { override func setUp() { super.setUp() - typeGeneratorSpy = TypeGeneratorSpy(makeVariableCodeReturn: "Type") + typeGeneratorSpy = TypeGeneratorSpy(makeVariableCodeReturn: "Type", makeArgumentCodeReturn: "") accessLevelGeneratorSpy = AccessLevelGeneratorSpy( makeClassAccessLevelReturn: "", makeContentAccessLevelReturn: "accessLevel " @@ -26,14 +26,13 @@ final class VariableGeneratorTests: XCTestCase { equal(string: code, rows: [ "\taccessLevel var identifier: Type {", - "\tget {", - "\t\tgetContent", + "\t\tget {", + "getContent", + "\t\t}", + "\t\tset {", + "setContent", + "\t\t}", "\t}", - "\tset {", - "\t\tsetContent", - "\t}", - "}", - "" ]) } @@ -44,11 +43,10 @@ final class VariableGeneratorTests: XCTestCase { equal(string: code, rows: [ "\taccessLevel var identifier: Type {", - "\tget {", - "\t\tgetContent", + "\t\tget {", + "getContent", + "\t\t}", "\t}", - "}", - "" ]) } } @@ -58,11 +56,18 @@ final class TypeGeneratorSpy: TypeGenerator { let declaration: TypeDeclaration } + struct MakeArgumentCode { + let declaration: TypeDeclaration + } + var makeVariableCode = [MakeVariableCode]() var makeVariableCodeReturn: String + var makeArgumentCode = [MakeArgumentCode]() + var makeArgumentCodeReturn: String - init(makeVariableCodeReturn: String) { + init(makeVariableCodeReturn: String, makeArgumentCodeReturn: String) { self.makeVariableCodeReturn = makeVariableCodeReturn + self.makeArgumentCodeReturn = makeArgumentCodeReturn } func makeVariableCode(from declaration: TypeDeclaration) -> String { @@ -70,4 +75,10 @@ final class TypeGeneratorSpy: TypeGenerator { makeVariableCode.append(item) return makeVariableCodeReturn } + + func makeArgumentCode(from declaration: TypeDeclaration) -> String { + let item = MakeArgumentCode(declaration: declaration) + makeArgumentCode.append(item) + return makeArgumentCodeReturn + } } diff --git a/Rubicon/Tests/RubiconTests/IntegrationTests.swift b/Rubicon/Tests/RubiconTests/IntegrationTests.swift new file mode 100644 index 0000000..231782c --- /dev/null +++ b/Rubicon/Tests/RubiconTests/IntegrationTests.swift @@ -0,0 +1,63 @@ +import Rubicon +import XCTest + +final class IntegrationTests: XCTestCase { + func test_givenProtocol_whenMakeDummy_thenReturnDummy() { + let code = """ + protocol Car { + var name: String? { get } + var color: Int { get set } + + func go() + func load(with stuff: Int, label: String) throws -> Int + func isFull(validate: @escaping () -> Void) -> Bool + func download() async throws -> [String] + } + """ + let sut = Rubicon() + + let result = sut.makeDummy(code: code, accessLevel: .public) + + equal(string: result.first ?? "", rows: [ + "public final class CarDummy: Car {", + "\tpublic var name: String? {", + "\t\tget {", + "\t\t\tfatalError()", + "\t\t}", + "\t\tset {", + "\t\t\tfatalError()", + "\t\t}", + "\t}", + "\tpublic var color: Int {", + "\t\tget {", + "\t\t\tfatalError()", + "\t\t}", + "\t\tset {", + "\t\t\tfatalError()", + "\t\t}", + "\t}", + "", + "\tpublic init() {", + "\t}", + "", + "\tpublic func go() {", + "\t\tfatalError()", + "\t}", + "", + "\tpublic func load(with stuff: Int, label: String) throws -> Int {", + "\t\tfatalError()", + "\t}", + "", + "\tpublic func isFull(validate: @escaping () -> Void) -> Bool {", + "\t\tfatalError()", + "\t}", + "", + "\tpublic func download() async throws -> [String] {", + "\t\tfatalError()", + "\t}", + "", + "}", + "", + ]) + } +} diff --git a/Rubicon/Tests/RubiconTests/Syntactic analysis/TypeDeclarationParserTests.swift b/Rubicon/Tests/RubiconTests/Syntactic analysis/TypeDeclarationParserTests.swift index b813804..6ea9cc3 100644 --- a/Rubicon/Tests/RubiconTests/Syntactic analysis/TypeDeclarationParserTests.swift +++ b/Rubicon/Tests/RubiconTests/Syntactic analysis/TypeDeclarationParserTests.swift @@ -17,7 +17,7 @@ final class TypeDeclarationParserTests: XCTestCase { } func test_givenSimpleType_whenParse_thenReturnDeclaration() throws { - let node = try parse(string: "T") + let node = try parse(string: "T ") let declaration = sut.parse(node: node)