portico/Tests/PorticoTests/StyleClassTests.swift

140 lines
4.9 KiB
Swift

import Testing
@_spi(SGTKInternal) import Gtk
import Adw
@_spi(Portico) import Portico
@MainActor @Suite(.serialized) struct StyleClassTests {
// MARK: - Static modifier
@Test func defaultTrueAddsClass() {
guard Gtk.initCheck() else { return }
let w = AnyView(Button(label: "x").suggestedAction()).makeWidget(MountContext())
#expect(w.hasCssClass(cssClass: "suggested-action"))
}
@Test func explicitFalseIsNoOp() {
guard Gtk.initCheck() else { return }
let w = AnyView(Label(str: "x").card(false)).makeWidget(MountContext())
#expect(!w.hasCssClass(cssClass: "card"))
}
// MARK: - Reactive modifier
@Test func bindingTogglesInPlace() {
guard Gtk.initCheck() else { return }
let box = StateBox(false)
let context = MountContext()
let w = AnyView(Label(str: "x").card(Binding(box))).makeWidget(context)
defer { box.set(false) }
#expect(!w.hasCssClass(cssClass: "card"))
box.set(true)
#expect(w.hasCssClass(cssClass: "card"))
box.set(false)
#expect(!w.hasCssClass(cssClass: "card"))
}
@Test func bindingInitialTrue() {
guard Gtk.initCheck() else { return }
let box = StateBox(true)
let context = MountContext()
let w = AnyView(Label(str: "x").card(Binding(box))).makeWidget(context)
defer { box.set(false) }
#expect(w.hasCssClass(cssClass: "card"))
}
// MARK: - Teardown
@Test func teardownStopsToggling() {
let box = StateBox(false)
let ctx = MountContext()
let w = AnyView(Label(str: "x").card(Binding(box))).makeWidget(ctx)
#expect(!w.hasCssClass(cssClass: "card"))
ctx.registry.teardown()
box.set(true)
#expect(!w.hasCssClass(cssClass: "card"))
box.set(false)
}
// MARK: - WidgetView host preserves type
@Test func widgetViewHostPreservesType() {
guard Gtk.initCheck() else { return }
let view = Button(label: "x").card().suggestedAction().label("y")
let w = AnyView(view).makeWidget(MountContext())
#expect(w is Gtk.Button)
#expect((w as! Gtk.Button).getLabel() == "y")
#expect(w.hasCssClass(cssClass: "card"))
#expect(w.hasCssClass(cssClass: "suggested-action"))
}
// MARK: - Stack host
@Test func stackHostAppliesClass() {
guard Gtk.initCheck() else { return }
let w1 = AnyView(HStack(spacing: 0) { Label(str: "a") }.linked()).makeWidget(MountContext())
#expect(w1 is Gtk.Box)
#expect(w1.hasCssClass(cssClass: "linked"))
let w2 = AnyView(VStack { Label(str: "b") }.card()).makeWidget(MountContext())
#expect(w2 is Gtk.Box)
#expect(w2.hasCssClass(cssClass: "card"))
}
// MARK: - Renamed colliders do not shadow
@Test func renamedCollidersDoNotShadow() {
guard Gtk.initCheck() else { return }
// `monospace(true)` routes to the GObject property modifier on Gtk.TextView
// (which is CSS-class-backed in GTK, so both paths work equivalently there)
let tv1 = TextView().monospace(true)
let w1 = AnyView(tv1).makeWidget(MountContext())
#expect(w1.hasCssClass(cssClass: "monospace"))
#expect((w1 as! Gtk.TextView).getMonospace() == true)
// `monospaceStyle()` on a non-TextView widget adds only the CSS class
let lbl = Label(str: "code").monospaceStyle()
let w2 = AnyView(lbl).makeWidget(MountContext())
#expect(w2.hasCssClass(cssClass: "monospace"))
}
// MARK: - Per-widget scoping
@Test func perWidgetScoping() {
guard Gtk.initCheck() else { return }
let w1 = AnyView(MenuButton().suggestedAction()).makeWidget(MountContext())
#expect(w1.hasCssClass(cssClass: "suggested-action"))
let w2 = AnyView(SplitButton().destructiveAction()).makeWidget(MountContext())
#expect(w2.hasCssClass(cssClass: "destructive-action"))
}
// MARK: - Universal modifiers apply to Gtk.Widget directly
@Test func universalOnRawWidget() {
guard Gtk.initCheck() else { return }
let raw = Gtk.Label(str: "x")
let w = AnyView(raw.card()).makeWidget(MountContext())
#expect(w.hasCssClass(cssClass: "card"))
}
// MARK: - Multiple classes compose
@Test func multipleClassesCompose() {
guard Gtk.initCheck() else { return }
let w = AnyView(Label(str: "x").card().dimmed().title1()).makeWidget(MountContext())
#expect(w.hasCssClass(cssClass: "card"))
#expect(w.hasCssClass(cssClass: "dimmed"))
#expect(w.hasCssClass(cssClass: "title-1"))
}
// MARK: - Box scoped modifiers
@Test func boxScopedModifiers() {
guard Gtk.initCheck() else { return }
let w = AnyView(Box(orientation: .horizontal, spacing: 0).linked().toolbar()).makeWidget(MountContext())
#expect(w.hasCssClass(cssClass: "linked"))
#expect(w.hasCssClass(cssClass: "toolbar"))
}
}