Скрытый макрос

Ты наверняка знаешь о скрытом функционале компилятора: свойства, методы, атрибуты и прочие выражения, доступ к которым можно получить с помощью нижнего подчеркивания:

var number: Int {
    @inline(__always) get {
        return number
    }
}

// или другой пример
func makeSomething(@_implicitSelfCapture fn: @escaping () -> Void) { 
    fn()
}

// или еще один
_canBeClass(MainActor.self)

Так вот, библиотека Swift Testing включает макрос, доступ к которому можно получить таким же способом — через нижнее подчеркивание:

@Test
func matchFileSourceLocation() {
	let fileLine: Int = 33
	let locationOfThisTest = #_sourceLocation()
	#expect(fileLine == locationOfThisTest.line)
}

❌ Expectation failed: (fileLine → 33) == (locationOfThisTest.line → 39)

Макрос #_sourceLocation()

Независимый макрос указывающий на местоположение в исходном коде. Сценарии использования могут быть разными, например для улучшения читаемости сообщений об ошибках в тестах, указании на конкретный модуль или имя исходного файла.

Информация о модуле, имени файла и других свойствах собирается на этапе компиляции.

func getTestLocation(testName: String = #function) {
	let location = #_sourceLocation()
	print("Запущен тест \(testName) в файле \(location.fileName)\nМодуль: \(location.moduleName)")
}

@Test
func followTheWhiteRabbit() {
	getTestLocation()
	
	let movie = Movie(name: "The Matrix")
	#expect(movie.mainCharacter == "Keanu Beeves")
}

◇ Test followTheWhiteRabbit() started.

Запущен тест followTheWhiteRabbit() в файле IssueExample.swift
Модуль: ModernAppTests

❌ Expectation failed: "Keanu Beeves" == "Keanu Reeves"

Реализация

За реализацию макрос отвечает тип данных SourceLocation. Ниже я перечислил все доступные свойства на момент выхода книги:

struct SourceLocation: Sendable {
	var fileID: String {...}
	var fileName: String {...}
	var moduleName: String {...}
	var line: Int {...}
	var column: Int {...}
}
  • fileID уникальный идентификатор исходного файла.
  • fileName имя исходного файла.
  • moduleName имя модуля, в котором находится данный исходный файл.
  • line строка по счету в исходном файле.
  • column столбец по счету в исходном файле.

note

SourceLocation используется в реализации макроса @Test и других трейтах.

Если интересно, почему в имени макроса присутствует нижнее подчеркивание, то взгляни на объявление:

@freestanding(expression)
public macro _sourceLocation() -> SourceLocation = #externalMacro(module: "TestingMacros", type: "SourceLocationMacro")

Ранее ты изучил информацию о атрибуте @freestanding(...) и знаешь, что это обозначает. Если это не так, ничего страшного, просто вернись назад и освежи знания.


Доступ к макросу развязывает пальцы и ты можешь сделать интеграцию с каким-либо мессенджером. Вместо вызова функции print() можно будет отправлять запросы в группу телеграма и видеть ход выполнения тестов. Другой вопрос, насколько это целесообразно — решай сам.