111 lines
3.0 KiB
Swift
111 lines
3.0 KiB
Swift
import SwiftSyntaxMacros
|
|
import SwiftSyntaxMacrosTestSupport
|
|
import XCTest
|
|
|
|
// Macro implementations build for the host, so the corresponding module is not available when cross-compiling.
|
|
// Cross-compiled tests may still make use of the macro itself in end-to-end tests.
|
|
#if canImport(DefaultsMacrosDeclarations)
|
|
@testable import DefaultsMacros
|
|
@testable import DefaultsMacrosDeclarations
|
|
|
|
let testMacros: [String: Macro.Type] = [
|
|
"ObservableDefault": ObservableDefaultMacro.self
|
|
]
|
|
#else
|
|
let testMacros: [String: Macro.Type] = [:]
|
|
#endif
|
|
|
|
final class ObservableDefaultMacroTests: XCTestCase {
|
|
func testExpansionWithMemberSyntax() throws {
|
|
#if canImport(DefaultsMacrosDeclarations)
|
|
assertMacroExpansion(
|
|
declaration(for: "Defaults.Keys.name"),
|
|
expandedSource: expectedExpansion(for: "Defaults.Keys.name"),
|
|
macros: testMacros,
|
|
indentationWidth: .tabs(1)
|
|
)
|
|
#else
|
|
throw XCTSkip("Macros are only supported when running tests for the host platform")
|
|
#endif
|
|
}
|
|
|
|
func testExpansionWithDotSyntax() throws {
|
|
#if canImport(DefaultsMacrosDeclarations)
|
|
assertMacroExpansion(
|
|
declaration(for: ".name"),
|
|
expandedSource: expectedExpansion(for: ".name"),
|
|
macros: testMacros,
|
|
indentationWidth: .tabs(1)
|
|
)
|
|
#else
|
|
throw XCTSkip("Macros are only supported when running tests for the host platform")
|
|
#endif
|
|
}
|
|
|
|
func testExpansionWithFunctionCall() throws {
|
|
#if canImport(DefaultsMacrosDeclarations)
|
|
assertMacroExpansion(
|
|
declaration(for: "getName()"),
|
|
expandedSource: expectedExpansion(for: "getName()"),
|
|
macros: testMacros,
|
|
indentationWidth: .tabs(1)
|
|
)
|
|
#else
|
|
throw XCTSkip("Macros are only supported when running tests for the host platform")
|
|
#endif
|
|
}
|
|
|
|
func testExpansionWithProperty() throws {
|
|
#if canImport(DefaultsMacrosDeclarations)
|
|
assertMacroExpansion(
|
|
declaration(for: "propertyName"),
|
|
expandedSource: expectedExpansion(for: "propertyName"),
|
|
macros: testMacros,
|
|
indentationWidth: .tabs(1)
|
|
)
|
|
#else
|
|
throw XCTSkip("Macros are only supported when running tests for the host platform")
|
|
#endif
|
|
}
|
|
|
|
private func declaration(for keyExpression: String) -> String {
|
|
#"""
|
|
@Observable
|
|
class ObservableClass {
|
|
@ObservableDefault(\#(keyExpression))
|
|
@ObservationIgnored
|
|
var name: String
|
|
}
|
|
"""#
|
|
}
|
|
|
|
private func expectedExpansion(for keyExpression: String) -> String {
|
|
#"""
|
|
@Observable
|
|
class ObservableClass {
|
|
@ObservationIgnored
|
|
var name: String {
|
|
get {
|
|
if objc_getAssociatedObject(self, &Self._objcAssociatedKey_name) == nil {
|
|
let cancellable = Defaults.publisher(\#(keyExpression))
|
|
.sink { [weak self] in
|
|
self?.name = $0.newValue
|
|
}
|
|
objc_setAssociatedObject(self, &Self._objcAssociatedKey_name, cancellable, .OBJC_ASSOCIATION_RETAIN)
|
|
}
|
|
access(keyPath: \.name)
|
|
return Defaults[\#(keyExpression)]
|
|
}
|
|
set {
|
|
withMutation(keyPath: \.name) {
|
|
Defaults[\#(keyExpression)] = newValue
|
|
}
|
|
}
|
|
}
|
|
|
|
private nonisolated(unsafe) static var _objcAssociatedKey_name: Void?
|
|
}
|
|
"""#
|
|
}
|
|
}
|