1
0
Fork 0

Add monorepo generation integration tests

This commit is contained in:
Brendan Szymanski 2026-07-01 20:50:14 -04:00
parent 173ad4bd65
commit 880c1574d5

View file

@ -0,0 +1,143 @@
import Foundation
import Testing
@testable import SwiftGtkGenCore
@Suite("MonorepoGeneration")
struct MonorepoGenerationTests {
private static func tempDir() -> String {
let d = NSTemporaryDirectory() + "monorepo_integ_\(UUID().uuidString)"
try? FileManager.default.createDirectory(atPath: d, withIntermediateDirectories: true)
return d
}
/// Creates two mock GIR files: a root (GLib) and a dependent (GObject).
private func buildTwoPackageConfig() throws -> (MonorepoConfig, MultiPackageAnalyzer) {
let tmp = Self.tempDir()
let glibXML = """
<?xml version="1.0"?>
<repository version="1.2"
xmlns="http://www.gtk.org/introspection/core/1.0"
xmlns:c="http://www.gtk.org/introspection/c/1.0"
xmlns:glib="http://www.gtk.org/introspection/glib/1.0">
<c:include name="glib.h"/>
<package name="glib-2.0"/>
<namespace name="GLib" version="2.0"
shared-library="libglib-2.0.so.0"
c:identifier-prefixes="G">
<enumeration name="LogLevel" c:type="GLogLevel">
<member name="error" value="4" c:identifier="G_LOG_ERROR"/>
</enumeration>
</namespace>
</repository>
"""
let gobjXML = """
<?xml version="1.0"?>
<repository version="1.2"
xmlns="http://www.gtk.org/introspection/core/1.0"
xmlns:c="http://www.gtk.org/introspection/c/1.0"
xmlns:glib="http://www.gtk.org/introspection/glib/1.0">
<include name="GLib" version="2.0"/>
<c:include name="glib-object.h"/>
<package name="gobject-2.0"/>
<namespace name="GObject" version="2.0"
shared-library="libgobject-2.0.so.0"
c:identifier-prefixes="G">
<class name="Object" c:type="GObject" parent="GObject.InitiallyUnowned">
<method name="get_data" c:identifier="g_object_get_data">
<return-value transfer-ownership="none">
<type name="gpointer"/>
</return-value>
<parameters>
<parameter name="key" transfer-ownership="none">
<type name="utf8"/>
</parameter>
</parameters>
</method>
</class>
</namespace>
</repository>
"""
let glibPath = tmp + "/GLib-2.0.gir"
let gobjPath = tmp + "/GObject-2.0.gir"
try glibXML.write(toFile: glibPath, atomically: true, encoding: .utf8)
try gobjXML.write(toFile: gobjPath, atomically: true, encoding: .utf8)
let entries: [PackageEntry] = [
PackageEntry(name: "GLib", girPath: glibPath),
PackageEntry(name: "GObject", girPath: gobjPath),
]
let config = MonorepoConfig(outputDir: tmp, packages: entries)
let analyzer = MultiPackageAnalyzer(config: config)
return (config, analyzer)
}
@Test func generatesSwiftFilesForBothPackages() throws {
let (_, analyzer) = try buildTwoPackageConfig()
let analysis = try analyzer.analyze()
let generator = CodeGenerator(config: GenerationConfig(
library: "GObject", version: "2.0", girsDirectories: [],
targetDirectory: "", externalLibraries: [],
generate: [], manual: [], ignore: [], objects: []
))
let outputs = try generator.generateMonorepo(analysis: analysis)
#expect(outputs.count == 2, "Both GLib and GObject should produce output")
let glibFiles = outputs["GLib"] ?? [:]
#expect(glibFiles.keys.contains("LogLevel.swift"), "GLib enum should be generated")
let gobjFiles = outputs["GObject"] ?? [:]
#expect(gobjFiles.keys.contains("Object.swift"), "GObject class should be generated")
}
@Test func generatesPackageSwiftWithAllTargets() throws {
let (_, analyzer) = try buildTwoPackageConfig()
let analysis = try analyzer.analyze()
let scaffolding = CodeGenerator.generateMonorepoScaffolding(analysis: analysis)
let pkgSwift = scaffolding["Package.swift"]
#expect(pkgSwift != nil)
#expect(pkgSwift?.contains(".systemLibrary(name: \"CGLib\"") == true)
#expect(pkgSwift?.contains(".systemLibrary(name: \"CGObject\"") == true)
#expect(pkgSwift?.contains("name: \"GLib\",") == true)
#expect(pkgSwift?.contains("name: \"GObject\",") == true)
#expect(pkgSwift?.contains("dependencies: [\"CGLib\"]") == true)
}
@Test func generatesReexportUmbrellaForDependent() throws {
let (_, analyzer) = try buildTwoPackageConfig()
let analysis = try analyzer.analyze()
let scaffolding = CodeGenerator.generateMonorepoScaffolding(analysis: analysis)
let gobjUmbrella = scaffolding["Sources/GObject/GObject.swift"]
#expect(gobjUmbrella?.contains("@_exported import GLib") == true)
let glibUmbrella = scaffolding["Sources/GLib/GLib.swift"]
#expect(glibUmbrella?.contains("@_exported import") == false,
"GLib is root, should not re-export anything")
}
@Test func generatedFilesHaveCrossModuleImports() throws {
let (_, analyzer) = try buildTwoPackageConfig()
let analysis = try analyzer.analyze()
let generator = CodeGenerator(config: GenerationConfig(
library: "GObject", version: "2.0", girsDirectories: [],
targetDirectory: "", externalLibraries: [],
generate: [], manual: [], ignore: [], objects: []
))
let outputs = try generator.generateMonorepo(analysis: analysis)
let gobjFile = outputs["GObject"]?["Object.swift"] ?? ""
#expect(gobjFile.contains("import CGLib") || gobjFile.contains("import CGObject"),
"Should import its own C bridge")
#expect(gobjFile.contains("import GLib"),
"GObject dep should import GLib")
}
}