1
0
Fork 0

Force open class for classes with same-namespace subclasses

This commit is contained in:
Brendan Szymanski 2026-07-01 18:33:05 -04:00
parent 3a033057fb
commit 9dbd2b5a7a
3 changed files with 81 additions and 8 deletions

View file

@ -605,8 +605,55 @@ func testRecordInGenerateFiles() throws {
#expect(!output.contains(", canFocus)"))
}
@Test("Optional boolean return is mapped with != 0")
func testOptionalBooleanReturnMapping() {
let result = CodeGenerator.wrapCReturnValue(callExpression: "g_value_get_boolean(&value)", returnType: .optional(.boolean))
#expect(result == "g_value_get_boolean(&value).map { $0 != 0 }")
}
@Test("Optional boolean return is mapped with != 0")
func testOptionalBooleanReturnMapping() {
let result = CodeGenerator.wrapCReturnValue(callExpression: "g_value_get_boolean(&value)", returnType: .optional(.boolean))
#expect(result == "g_value_get_boolean(&value).map { $0 != 0 }")
}
@Test("Class with subclasses is not final")
func testClassWithSubclassesIsNotFinal() throws {
let repo = Repository(namespaces: [
Namespace(name: "Gtk", version: "4.0", classes: [
Class(name: "Widget", cType: "GtkWidget", parent: "GObject.InitiallyUnowned"),
Class(name: "Button", cType: "GtkButton", parent: "Widget"),
])
])
let config = GenerationConfig(library: "Gtk", version: "4.0", girsDirectories: [],
targetDirectory: "", externalLibraries: [],
generate: ["Gtk.Widget", "Gtk.Button"], manual: [], ignore: [], objects: [])
let generator = CodeGenerator(config: config)
let files = try generator.generateFiles(repository: repo, analysis: Analyzer(config: config).analyze(repository: repo))
let widgetOutput = files["Widget.swift"] ?? ""
let buttonOutput = files["Button.swift"] ?? ""
// Widget has a subclass (Button), so it should NOT be final
#expect(widgetOutput.contains("open class Widget"))
#expect(!widgetOutput.contains("final class Widget"))
// Button has no subclasses, so it CAN be final
#expect(buttonOutput.contains("final class Button"))
}
@Test("Cross-namespace child does not force open class")
func testCrossNamespaceChildDoesNotForceOpen() throws {
// Base is in GObject namespace. Derived is in Gtk namespace (cross-namespace).
// Base should remain `final class` since the child is in a different namespace.
let repo = Repository(namespaces: [
Namespace(name: "GObject", version: "2.0", classes: [
Class(name: "Base", cType: "GBase", parent: nil),
]),
Namespace(name: "Gtk", version: "4.0", classes: [
Class(name: "Derived", cType: "GtkDerived", parent: "GObject.Base"),
]),
])
let config = GenerationConfig(library: "GObject", version: "2.0", girsDirectories: [],
targetDirectory: "", externalLibraries: [],
generate: ["GObject.Base"], manual: [], ignore: [], objects: [])
let generator = CodeGenerator(config: config)
let files = try generator.generateFiles(repository: repo, analysis: Analyzer(config: config).analyze(repository: repo))
let baseOutput = files["Base.swift"] ?? ""
// Base has a child (Derived) but in a different namespace, so it stays final
#expect(baseOutput.contains("final class Base"))
}