140 lines
4.9 KiB
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"))
|
|
}
|
|
}
|