Skip to content

Commit

Permalink
Merge pull request #68 from raptorxcz/feature/struct-stub
Browse files Browse the repository at this point in the history
Add default values to array, dictionary and set
  • Loading branch information
raptorxcz authored May 16, 2024
2 parents 19eebc2 + 6131216 commit 511d162
Show file tree
Hide file tree
Showing 15 changed files with 165 additions and 50 deletions.
10 changes: 9 additions & 1 deletion Sources/Rubicon/Domain/TypeDeclaration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,15 @@ struct TypeDeclaration: Equatable {
case autoclosure = "@autoclosure"
}

enum ComposedType {
case plain
case array
case dictionary
case optional
case set
}

var name: String
var isOptional: Bool
let prefix: [Prefix]
let composedType: ComposedType
}
13 changes: 12 additions & 1 deletion Sources/Rubicon/Generator/DefaultValueGenerator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,21 @@ final class DefaultValueGeneratorImpl: DefaultValueGenerator {
return customValue
}

guard !varDeclaration.type.isOptional else {
switch varDeclaration.type.composedType {
case .plain:
return makeDefaultValueByType(varDeclaration: varDeclaration)
case .array:
return "[]"
case .dictionary:
return "[:]"
case .optional:
return "nil"
case .set:
return "[]"
}
}

private func makeDefaultValueByType(varDeclaration: VarDeclaration) -> String {
switch varDeclaration.type.name {
case "String":
return "\"\(varDeclaration.identifier)\""
Expand Down
10 changes: 7 additions & 3 deletions Sources/Rubicon/Generator/InitGenerator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,13 @@ final class InitGeneratorImpl: InitGenerator {
}

private func makeInitArgument(from variable: VarDeclaration, isAddingDefaultValueToOptionalsEnabled: Bool) -> String {
let defaultValue = isAddingDefaultValueToOptionalsEnabled && variable.type.isOptional ? "nil" : nil
let prefix = variable.type.isOptional ? [] : variable.type.prefix
let type = TypeDeclaration(name: variable.type.name, isOptional: variable.type.isOptional, prefix: prefix)
let defaultValue = isAddingDefaultValueToOptionalsEnabled && variable.type.composedType == .optional ? "nil" : nil
let prefix = variable.type.composedType == .optional ? [] : variable.type.prefix
let type = TypeDeclaration(
name: variable.type.name,
prefix: prefix,
composedType: variable.type.composedType
)
let declaration = ArgumentDeclaration(name: variable.identifier, type: type, defaultValue: defaultValue)
return argumentGenerator.makeCode(from: declaration)
}
Expand Down
8 changes: 6 additions & 2 deletions Sources/Rubicon/Generator/SpyGenerator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ final class SpyGenerator {
content.append(makeVariables(from: protocolType).map(variableGenerator.makeCode))
content.append(makeSpyVariables(from: protocolType))
let initVariables = makeVariables(from: protocolType) + makeReturnVariables(from: protocolType)
let nonOptionalInitVariables = initVariables.filter { !$0.type.isOptional }
let nonOptionalInitVariables = initVariables.filter { $0.type.composedType != .optional }
content.append(initGenerator.makeCode(
with: isInitWithOptionalsEnabled ? initVariables : nonOptionalInitVariables,
isAddingDefaultValueToOptionalsEnabled: isInitWithOptionalsEnabled
Expand Down Expand Up @@ -81,7 +81,11 @@ final class SpyGenerator {
var variables = [VarDeclaration]()

if declaration.isThrowing {
let throwBlockType = TypeDeclaration(name: "(() throws -> Void)?", isOptional: true, prefix: [.escaping])
let throwBlockType = TypeDeclaration(
name: "(() throws -> Void)?",
prefix: [.escaping],
composedType: .optional
)
variables.append(VarDeclaration(isConstant: false, identifier: name + "ThrowBlock", type: throwBlockType))
}

Expand Down
2 changes: 1 addition & 1 deletion Sources/Rubicon/Generator/StructStubGenerator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ final class StructStubGeneratorImpl: StructStubGenerator {
isThrowing: false,
isAsync: false,
isStatic: true,
returnType: TypeDeclaration(name: structType.name, isOptional: false, prefix: [])
returnType: TypeDeclaration(name: structType.name, prefix: [], composedType: .plain)
)
return functionGenerator.makeCode(
from: functionDeclaration,
Expand Down
8 changes: 6 additions & 2 deletions Sources/Rubicon/Generator/StubGenerator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ final class StubGenerator {

content.append(makeVariables(from: protocolType).map(variableGenerator.makeCode))
let initVariables = makeVariables(from: protocolType)
let nonOptionalInitVariables = initVariables.filter { !$0.type.isOptional }
let nonOptionalInitVariables = initVariables.filter { $0.type.composedType != .optional }
content.append(initGenerator.makeCode(
with: isInitWithOptionalsEnabled ? initVariables : nonOptionalInitVariables,
isAddingDefaultValueToOptionalsEnabled: isInitWithOptionalsEnabled
Expand Down Expand Up @@ -66,7 +66,11 @@ final class StubGenerator {
var variables = [VarDeclaration]()

if declaration.isThrowing {
let throwBlockType = TypeDeclaration(name: "(() throws -> Void)?", isOptional: true, prefix: [.escaping])
let throwBlockType = TypeDeclaration(
name: "(() throws -> Void)?",
prefix: [.escaping],
composedType: .optional
)
variables.append(VarDeclaration(isConstant: false, identifier: name + "ThrowBlock", type: throwBlockType))
}

Expand Down
44 changes: 40 additions & 4 deletions Sources/Rubicon/Syntactic analysis/TypeDeclarationParser.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,25 +14,61 @@ final class TypeDeclarationParserImpl: TypeDeclarationParser {
if let attributedType = node.as(AttributedTypeSyntax.self) {
return TypeDeclaration(
name: attributedType.baseType.description.trimmingCharacters(in: .whitespacesAndNewlines),
isOptional: isOptional(node: node),
prefix: attributedType.attributes.compactMap(makePrefix(from:))
prefix: attributedType.attributes.compactMap(makePrefix(from:)),
composedType: parseComposedType(from: node)
)
} else {
return TypeDeclaration(
name: node.description.trimmingCharacters(in: .whitespacesAndNewlines),
isOptional: isOptional(node: node),
prefix: []
prefix: [],
composedType: parseComposedType(from: node)
)
}

}

private func parseComposedType(from node: TypeSyntax) -> TypeDeclaration.ComposedType {
if isOptional(node: node) {
return .optional
}

if node.is(DictionaryTypeSyntax.self) {
return .dictionary
}

if isArray(node: node) {
return .array
}

if isSet(node: node) {
return .set
}

return .plain
}

private func isOptional(node: TypeSyntax) -> Bool {
let isSimpleOptional = node.as(OptionalTypeSyntax.self) != nil
let isClosureOptional = node.as(FunctionTypeSyntax.self)?.returnClause.type.as(OptionalTypeSyntax.self) != nil
return isSimpleOptional || isClosureOptional
}

private func isArray(node: TypeSyntax) -> Bool {
if let identifierTypeSyntax = node.as(IdentifierTypeSyntax.self) {
return identifierTypeSyntax.name.text == "Array"
} else {
return node.is(ArrayTypeSyntax.self)
}
}

private func isSet(node: TypeSyntax) -> Bool {
if let identifierTypeSyntax = node.as(IdentifierTypeSyntax.self) {
return identifierTypeSyntax.name.text == "Set"
} else {
return false
}
}

private func makePrefix(from node: AttributeListSyntax.Element) -> TypeDeclaration.Prefix? {
switch node {
case .attribute(let attributeSyntax):
Expand Down
20 changes: 19 additions & 1 deletion Tests/RubiconTests/Generator/DefaultValueGeneratorTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,29 @@ final class DefaultValueGeneratorTests: XCTestCase {
}

func test_givenOptionalType_whenMakeDefaultValue_thenReturnNil() {
let value = sut.makeDefaultValue(for: .makeStub(type: .makeStub(isOptional: true)))
let value = sut.makeDefaultValue(for: .makeStub(type: .makeStub(composedType: .optional)))

XCTAssertEqual(value, "nil")
}

func test_givenArrayType_whenMakeDefaultValue_thenReturnNil() {
let value = sut.makeDefaultValue(for: .makeStub(type: .makeStub(composedType: .array)))

XCTAssertEqual(value, "[]")
}

func test_givenDictionaryType_whenMakeDefaultValue_thenReturnNil() {
let value = sut.makeDefaultValue(for: .makeStub(type: .makeStub(composedType: .dictionary)))

XCTAssertEqual(value, "[:]")
}

func test_givenSetType_whenMakeDefaultValue_thenReturnNil() {
let value = sut.makeDefaultValue(for: .makeStub(type: .makeStub(composedType: .set)))

XCTAssertEqual(value, "[]")
}

func test_givenIntType_whenMakeDefaultValue_thenReturnZero() {
let value = sut.makeDefaultValue(for: .makeStub(identifier: "name", type: .makeStub(name: "Int")))

Expand Down
10 changes: 5 additions & 5 deletions Tests/RubiconTests/Generator/DummyGeneratorTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ final class DummyGeneratorTests: XCTestCase {
private var functionGeneratorSpy: FunctionGeneratorSpy!
private var initGeneratorSpy: InitGeneratorSpy!
private var sut: DummyGenerator!
private let type = TypeDeclaration.makeStub(name: "Color", isOptional: false)
private let type = TypeDeclaration.makeStub(name: "Color")

override func setUp() {
super.setUp()
Expand Down Expand Up @@ -84,13 +84,13 @@ final class DummyGeneratorTests: XCTestCase {
extension TypeDeclaration {
static func makeStub(
name: String = "Int",
isOptional: Bool = false,
prefix: [Prefix] = []
prefix: [Prefix] = [],
composedType: ComposedType = .plain
) -> TypeDeclaration {
return TypeDeclaration(
name: name,
isOptional: isOptional,
prefix: prefix
prefix: prefix,
composedType: composedType
)
}
}
Expand Down
8 changes: 4 additions & 4 deletions Tests/RubiconTests/Generator/InitGeneratorTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ final class InitGeneratorTests: XCTestCase {
private var accessLevelGeneratorSpy: AccessLevelGeneratorSpy!
private var indentationGeneratorStub: IndentationGeneratorStub!
private var sut: InitGenerator!
private let type = TypeDeclaration.makeStub(name: "Color", isOptional: false)
private let type = TypeDeclaration.makeStub(name: "Color")

override func setUp() {
super.setUp()
Expand Down Expand Up @@ -64,7 +64,7 @@ final class InitGeneratorTests: XCTestCase {
let result = sut.makeCode(
with: [
.makeStub(type: .makeStub(prefix: [.escaping])),
.makeStub(type: .makeStub(isOptional: true, prefix: [.escaping]))
.makeStub(type: .makeStub(prefix: [.escaping], composedType: .optional))
],
isAddingDefaultValueToOptionalsEnabled: false
)
Expand All @@ -77,14 +77,14 @@ final class InitGeneratorTests: XCTestCase {
])
XCTAssertEqual(argumentGeneratorSpy.makeCode.count, 2)
XCTAssertEqual(argumentGeneratorSpy.makeCode.first?.declaration, .makeStub(label: nil, name: "identifier", type: .makeStub(prefix: [.escaping])))
XCTAssertEqual(argumentGeneratorSpy.makeCode.last?.declaration, .makeStub(label: nil, name: "identifier", type: .makeStub(isOptional: true, prefix: [])))
XCTAssertEqual(argumentGeneratorSpy.makeCode.last?.declaration, .makeStub(label: nil, name: "identifier", type: .makeStub(prefix: [], composedType: .optional)))
}

func test_givenOptionalVariableAndIsAddingDefaultValueToOptionalsEnabled_whenMakeCode_thenMakeInit() {
initialize(accessLevel: .public)

let result = sut.makeCode(
with: [.makeStub(), .makeStub(type: .makeStub(isOptional: true))],
with: [.makeStub(), .makeStub(type: .makeStub(composedType: .optional))],
isAddingDefaultValueToOptionalsEnabled: true
)

Expand Down
10 changes: 5 additions & 5 deletions Tests/RubiconTests/Generator/SpyGeneratorTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ final class SpyGeneratorTests: XCTestCase {
private var structGeneratorSpy: StructGeneratorSpy!
private var accessLevelGeneratorSpy: AccessLevelGeneratorSpy!
private var sut: SpyGenerator!
private let type = TypeDeclaration.makeStub(name: "Color", isOptional: false)
private let type = TypeDeclaration.makeStub(name: "Color")

override func setUp() {
super.setUp()
Expand Down Expand Up @@ -127,7 +127,7 @@ final class SpyGeneratorTests: XCTestCase {
}

func test_givenProtocolWithFunctionWithtOptionalReturn_whenGenerate_thenGenerateSpy() {
let returnType = TypeDeclaration.makeStub(isOptional: true)
let returnType = TypeDeclaration.makeStub(composedType: .optional)
let protocolDeclaration = ProtocolDeclaration.makeStub(functions: [.makeStub(returnType: returnType)])

_ = sut.generate(from: protocolDeclaration, isInitWithOptionalsEnabled: false)
Expand All @@ -153,15 +153,15 @@ final class SpyGeneratorTests: XCTestCase {
}

func test_givenProtocolWithThrowingFunction_whenGenerate_thenGenerateSpy() {
let returnType = TypeDeclaration.makeStub(isOptional: true)
let returnType = TypeDeclaration.makeStub(composedType: .optional)
let functionDeclaration = FunctionDeclaration.makeStub(isThrowing: true, returnType: returnType)
let protocolDeclaration = ProtocolDeclaration.makeStub(functions: [functionDeclaration])

_ = sut.generate(from: protocolDeclaration, isInitWithOptionalsEnabled: false)

XCTAssertEqual(variableGeneratorSpy.makeCode.count, 2)
XCTAssertEqual(variableGeneratorSpy.makeCode.first?.declaration.identifier, "functionNameThrowBlock")
XCTAssertEqual(variableGeneratorSpy.makeCode.first?.declaration.type, .makeStub(name: "(() throws -> Void)?", isOptional: true, prefix: [.escaping]))
XCTAssertEqual(variableGeneratorSpy.makeCode.first?.declaration.type, .makeStub(name: "(() throws -> Void)?", prefix: [.escaping], composedType: .optional))
XCTAssertEqual(variableGeneratorSpy.makeCode.first?.declaration.isConstant, false)
XCTAssertEqual(variableGeneratorSpy.makeCode.last?.declaration.identifier, "functionNameReturn")
XCTAssertEqual(variableGeneratorSpy.makeCode.last?.declaration.type, returnType)
Expand Down Expand Up @@ -219,7 +219,7 @@ final class SpyGeneratorTests: XCTestCase {
let protocolDeclaration = ProtocolDeclaration.makeStub(
variables: [
.makeStub(),
.makeStub(type: .makeStub(isOptional: true))
.makeStub(type: .makeStub(composedType: .optional))
]
)

Expand Down
10 changes: 5 additions & 5 deletions Tests/RubiconTests/Generator/StubGeneratorTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ final class StubGeneratorTests: XCTestCase {
private var functionNameGeneratorSpy: FunctionNameGeneratorSpy!
private var initGeneratorSpy: InitGeneratorSpy!
private var sut: StubGenerator!
private let type = TypeDeclaration.makeStub(name: "Color", isOptional: false)
private let type = TypeDeclaration.makeStub(name: "Color")

override func setUp() {
super.setUp()
Expand Down Expand Up @@ -116,7 +116,7 @@ final class StubGeneratorTests: XCTestCase {
}

func test_givenProtocolWithFunctionWithtOptionalReturn_whenGenerate_thenGenerateStub() {
let returnType = TypeDeclaration.makeStub(isOptional: true)
let returnType = TypeDeclaration.makeStub(composedType: .optional)
let protocolDeclaration = ProtocolDeclaration.makeStub(functions: [.makeStub(returnType: returnType)])

_ = sut.generate(from: protocolDeclaration, nameSuffix: "Stub", isInitWithOptionalsEnabled: false)
Expand All @@ -138,15 +138,15 @@ final class StubGeneratorTests: XCTestCase {
}

func test_givenProtocolWithThrowingFunction_whenGenerate_thenGenerateStub() {
let returnType = TypeDeclaration.makeStub(isOptional: true)
let returnType = TypeDeclaration.makeStub(composedType: .optional)
let functionDeclaration = FunctionDeclaration.makeStub(isThrowing: true, returnType: returnType)
let protocolDeclaration = ProtocolDeclaration.makeStub(functions: [functionDeclaration])

_ = sut.generate(from: protocolDeclaration, nameSuffix: "Stub", isInitWithOptionalsEnabled: false)

XCTAssertEqual(variableGeneratorSpy.makeCode.count, 2)
XCTAssertEqual(variableGeneratorSpy.makeCode.first?.declaration.identifier, "functionNameThrowBlock")
XCTAssertEqual(variableGeneratorSpy.makeCode.first?.declaration.type, .makeStub(name: "(() throws -> Void)?", isOptional: true, prefix: [.escaping]))
XCTAssertEqual(variableGeneratorSpy.makeCode.first?.declaration.type, .makeStub(name: "(() throws -> Void)?", prefix: [.escaping], composedType: .optional))
XCTAssertEqual(variableGeneratorSpy.makeCode.first?.declaration.isConstant, false)
XCTAssertEqual(variableGeneratorSpy.makeCode.last?.declaration.identifier, "functionNameReturn")
XCTAssertEqual(variableGeneratorSpy.makeCode.last?.declaration.type, returnType)
Expand All @@ -171,7 +171,7 @@ final class StubGeneratorTests: XCTestCase {
let protocolDeclaration = ProtocolDeclaration.makeStub(
variables: [
.makeStub(),
.makeStub(type: .makeStub(isOptional: true))
.makeStub(type: .makeStub(composedType: .optional))
]
)

Expand Down
4 changes: 2 additions & 2 deletions Tests/RubiconTests/Generator/TypeGeneratorTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ final class TypGeneratorTests: XCTestCase {
}

func test_givenOptional_whenMakeVariable_thenGenerateCode() {
let typeDeclaration = TypeDeclaration.makeStub(name: "() -> Void?", isOptional: true)
let typeDeclaration = TypeDeclaration.makeStub(name: "() -> Void?", composedType: .optional)

let code = sut.makeVariableCode(from: typeDeclaration)

Expand All @@ -50,7 +50,7 @@ final class TypGeneratorTests: XCTestCase {
}

func test_givenOptional_whenMakeArgument_thenGenerateCode() {
let typeDeclaration = TypeDeclaration.makeStub(name: "() -> Void?", isOptional: true)
let typeDeclaration = TypeDeclaration.makeStub(name: "() -> Void?", composedType: .optional)

let code = sut.makeArgumentCode(from: typeDeclaration)

Expand Down
Loading

0 comments on commit 511d162

Please sign in to comment.