Skip to content

Commit

Permalink
Add unit tests to all macro examples
Browse files Browse the repository at this point in the history
  • Loading branch information
Matejkob committed Sep 7, 2023
1 parent b745d78 commit 4cfedda
Show file tree
Hide file tree
Showing 21 changed files with 1,453 additions and 278 deletions.
4 changes: 3 additions & 1 deletion Examples/Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,9 @@ let package = Package(
.testTarget(
name: "MacroExamplesImplementationTests",
dependencies: [
"MacroExamplesImplementation"
"MacroExamplesImplementation",
.product(name: "SwiftSyntaxMacros", package: "swift-syntax"),
.product(name: "SwiftSyntaxMacrosTestSupport", package: "swift-syntax"),
],
path: "Tests/MacroExamples/Implementation"
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ private func replaceFirstLabel(
}

var tuple = tuple
tuple[tuple.startIndex] = firstElement
tuple[tuple.startIndex] =
firstElement
.with(\.label, .identifier(newLabel))
.with(\.colon, .colonToken())
return tuple
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,11 @@ public protocol ExpressibleByFontLiteral {

/// Font literal similar to, e.g., #colorLiteral.
@freestanding(expression)
public macro fontLiteral<T>(name: String, size: Int, weight: FontWeight) -> T = #externalMacro(
module: "MacroExamplesImplementation",
type: "FontLiteralMacro"
) where T: ExpressibleByFontLiteral
public macro fontLiteral<T>(name: String, size: Int, weight: FontWeight) -> T =
#externalMacro(
module: "MacroExamplesImplementation",
type: "FontLiteralMacro"
) where T: ExpressibleByFontLiteral

// MARK: - Stringify Macro

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2023 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

import MacroExamplesImplementation
import SwiftSyntaxMacros
import SwiftSyntaxMacrosTestSupport
import XCTest

final class DictionaryStorageMacroTests: XCTestCase {
private let macros: [String: Macro.Type] = [
"DictionaryStorage": DictionaryStorageMacro.self,
"DictionaryStorageProperty": DictionaryStoragePropertyMacro.self,
]

func testExpansionConvertsStoredProperties() {
assertMacroExpansion(
"""
@DictionaryStorage
struct Point {
var x: Int = 1
var y: Int = 2
}
""",
expandedSource: """
struct Point {
var x: Int = 1 {
get {
_storage["x", default: 1] as! Int
}
set {
_storage["x"] = newValue
}
}
var y: Int = 2 {
get {
_storage["y", default: 2] as! Int
}
set {
_storage["y"] = newValue
}
}
var _storage: [String: Any] = [:]
}
""",
macros: macros
)
}

func testExpansionWithoutInitializersEmitsError() {
assertMacroExpansion(
"""
@DictionaryStorage
class Point {
let x: Int
let y: Int
}
""",
expandedSource: """
class Point {
let x: Int
let y: Int
var _storage: [String: Any] = [:]
}
""",
diagnostics: [
DiagnosticSpec(message: "stored property must have an initializer", line: 3, column: 3),
DiagnosticSpec(message: "stored property must have an initializer", line: 4, column: 3),
],
macros: macros
)
}

func testExpansionIgnoresComputedProperties() {
assertMacroExpansion(
"""
@DictionaryStorage
struct Test {
var value: Int {
get { return 0 }
set {}
}
}
""",
expandedSource: """
struct Test {
var value: Int {
get { return 0 }
set {}
}
var _storage: [String: Any] = [:]
}
""",
macros: macros
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2023 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

import MacroExamplesImplementation
import SwiftSyntaxMacros
import SwiftSyntaxMacrosTestSupport
import XCTest

final class ObservableMacroTests: XCTestCase {
private let macros: [String: Macro.Type] = [
"Observable": ObservableMacro.self,
"ObservableProperty": ObservablePropertyMacro.self,
]

func testExpansion() {
assertMacroExpansion(
"""
@Observable
final class Dog {
var name: String?
var treat: Treat?
var isHappy: Bool = true
init() {}
func bark() {
print("bork bork")
}
}
""",
expandedSource: #"""
final class Dog {
var name: String? {
get {
_registrar.beginAccess(\.name)
defer {
_registrar.endAccess()
}
return _storage.name
}
set {
_registrar.beginAccess(\.name)
_registrar.register(observable: self, willSet: \.name, to: newValue)
defer {
_registrar.register(observable: self, didSet: \.name)
_registrar.endAccess()
}
_storage.name = newValue
}
}
var treat: Treat? {
get {
_registrar.beginAccess(\.treat)
defer {
_registrar.endAccess()
}
return _storage.treat
}
set {
_registrar.beginAccess(\.treat)
_registrar.register(observable: self, willSet: \.treat, to: newValue)
defer {
_registrar.register(observable: self, didSet: \.treat)
_registrar.endAccess()
}
_storage.treat = newValue
}
}
var isHappy: Bool = true {
get {
_registrar.beginAccess(\.isHappy)
defer {
_registrar.endAccess()
}
return _storage.isHappy
}
set {
_registrar.beginAccess(\.isHappy)
_registrar.register(observable: self, willSet: \.isHappy, to: newValue)
defer {
_registrar.register(observable: self, didSet: \.isHappy)
_registrar.endAccess()
}
_storage.isHappy = newValue
}
}
init() {}
func bark() {
print("bork bork")
}
let _registrar = ObservationRegistrar<Dog >()
public nonisolated func addObserver(_ observer: some Observer<Dog >) {
_registrar.addObserver(observer)
}
public nonisolated func removeObserver(_ observer: some Observer<Dog >) {
_registrar.removeObserver(observer)
}
private func withTransaction<T>(_ apply: () throws -> T) rethrows -> T {
_registrar.beginAccess()
defer {
_registrar.endAccess()
}
return try apply()
}
private struct Storage {
var name: String?
var treat: Treat?
var isHappy: Bool = true
}
private var _storage = Storage()
}
extension Dog: Observable {
}
"""#,
macros: macros
)
}
}
Loading

0 comments on commit 4cfedda

Please sign in to comment.