249 lines
8 KiB
Swift
249 lines
8 KiB
Swift
import Testing
|
|
@_spi(SGTKInternal) import Gtk
|
|
@_spi(Portico) import Portico
|
|
|
|
@MainActor @Suite(.serialized) struct ModifierTests {
|
|
|
|
// MARK: - Static modifiers
|
|
|
|
@Test func staticPreferredWidth() {
|
|
guard Gtk.initCheck() else { return }
|
|
let w = AnyView(Label(str: "x").preferredWidth(42)).makeWidget(MountContext())
|
|
#expect(w.getSizeRequest().width == 42)
|
|
}
|
|
|
|
@Test func staticPreferredHeight() {
|
|
guard Gtk.initCheck() else { return }
|
|
let w = AnyView(Label(str: "x").preferredHeight(99)).makeWidget(MountContext())
|
|
#expect(w.getSizeRequest().height == 99)
|
|
}
|
|
|
|
@Test func staticHexpand() {
|
|
guard Gtk.initCheck() else { return }
|
|
let w = AnyView(Label(str: "x").hexpand(true)).makeWidget(MountContext())
|
|
#expect(w.getHexpand() == true)
|
|
let w2 = AnyView(Label(str: "x").hexpand(false)).makeWidget(MountContext())
|
|
#expect(w2.getHexpand() == false)
|
|
}
|
|
|
|
@Test func staticVexpand() {
|
|
guard Gtk.initCheck() else { return }
|
|
let w = AnyView(Label(str: "x").vexpand(true)).makeWidget(MountContext())
|
|
#expect(w.getVexpand() == true)
|
|
}
|
|
|
|
@Test func staticMargin() {
|
|
guard Gtk.initCheck() else { return }
|
|
let w = AnyView(Label(str: "x").margin(7)).makeWidget(MountContext())
|
|
#expect(w.getMarginStart() == 7)
|
|
#expect(w.getMarginEnd() == 7)
|
|
#expect(w.getMarginTop() == 7)
|
|
#expect(w.getMarginBottom() == 7)
|
|
}
|
|
|
|
@Test func staticCssClass() {
|
|
guard Gtk.initCheck() else { return }
|
|
let w = AnyView(Label(str: "x").cssClass("myclass")).makeWidget(MountContext())
|
|
#expect(w.hasCssClass(cssClass: "myclass"))
|
|
}
|
|
|
|
// MARK: - Reactive modifiers
|
|
|
|
@Test func reactivePreferredWidth() {
|
|
guard Gtk.initCheck() else { return }
|
|
let box = StateBox<Int32>(40)
|
|
let context = MountContext()
|
|
let w = AnyView(Label(str: "x").preferredWidth(Binding(box))).makeWidget(context)
|
|
defer { box.set(0) }
|
|
|
|
#expect(w.getSizeRequest().width == 40)
|
|
box.set(60)
|
|
#expect(w.getSizeRequest().width == 60)
|
|
}
|
|
@Test func reactiveCssClass() {
|
|
guard Gtk.initCheck() else { return }
|
|
let box = StateBox("a")
|
|
let context = MountContext()
|
|
let w = AnyView(Label(str: "x").cssClass(Binding(box))).makeWidget(context)
|
|
defer { box.set("") }
|
|
|
|
#expect(w.hasCssClass(cssClass: "a"))
|
|
box.set("b")
|
|
#expect(!w.hasCssClass(cssClass: "a"))
|
|
#expect(w.hasCssClass(cssClass: "b"))
|
|
}
|
|
|
|
@Test func reactivePreferredHeight() {
|
|
guard Gtk.initCheck() else { return }
|
|
let box = StateBox<Int32>(99)
|
|
let context = MountContext()
|
|
let w = AnyView(Label(str: "x").preferredHeight(Binding(box))).makeWidget(context)
|
|
_ = box
|
|
|
|
#expect(w.getSizeRequest().height == 99)
|
|
box.set(150)
|
|
#expect(w.getSizeRequest().height == 150)
|
|
}
|
|
|
|
@Test func reactiveHexpand() {
|
|
guard Gtk.initCheck() else { return }
|
|
let box = StateBox<Bool>(false)
|
|
let context = MountContext()
|
|
let w = AnyView(Label(str: "x").hexpand(Binding(box))).makeWidget(context)
|
|
_ = box
|
|
|
|
#expect(w.getHexpand() == false)
|
|
box.set(true)
|
|
#expect(w.getHexpand() == true)
|
|
}
|
|
|
|
@Test func reactiveVexpand() {
|
|
guard Gtk.initCheck() else { return }
|
|
let box = StateBox<Bool>(false)
|
|
let context = MountContext()
|
|
let w = AnyView(Label(str: "x").vexpand(Binding(box))).makeWidget(context)
|
|
_ = box
|
|
|
|
#expect(w.getVexpand() == false)
|
|
box.set(true)
|
|
#expect(w.getVexpand() == true)
|
|
}
|
|
|
|
@Test func reactiveMargin() {
|
|
guard Gtk.initCheck() else { return }
|
|
let box = StateBox<Int32>(5)
|
|
let context = MountContext()
|
|
let w = AnyView(Label(str: "x").margin(Binding(box))).makeWidget(context)
|
|
_ = box
|
|
|
|
#expect(w.getMarginStart() == 5)
|
|
#expect(w.getMarginEnd() == 5)
|
|
#expect(w.getMarginTop() == 5)
|
|
#expect(w.getMarginBottom() == 5)
|
|
box.set(12)
|
|
#expect(w.getMarginStart() == 12)
|
|
#expect(w.getMarginEnd() == 12)
|
|
#expect(w.getMarginTop() == 12)
|
|
#expect(w.getMarginBottom() == 12)
|
|
}
|
|
|
|
// MARK: - Axis preservation
|
|
|
|
@Test func axisPreservation() {
|
|
guard Gtk.initCheck() else { return }
|
|
let w = AnyView(
|
|
Label(str: "x")
|
|
.preferredWidth(42)
|
|
.preferredHeight(99)
|
|
).makeWidget(MountContext())
|
|
let sr = w.getSizeRequest()
|
|
#expect(sr.width == 42)
|
|
#expect(sr.height == 99)
|
|
}
|
|
|
|
@Test func reactiveWidthPreservesHeight() {
|
|
guard Gtk.initCheck() else { return }
|
|
let box = StateBox<Int32>(50)
|
|
let context = MountContext()
|
|
let w = AnyView(
|
|
Label(str: "x")
|
|
.preferredWidth(100)
|
|
.preferredHeight(200)
|
|
.preferredWidth(Binding(box))
|
|
).makeWidget(context)
|
|
defer { box.set(0) }
|
|
|
|
// After static: width=100, height=200
|
|
// After reactive initial: width=50, height=200 (width overwritten, height preserved)
|
|
let sr = w.getSizeRequest()
|
|
#expect(sr.height == 200)
|
|
|
|
box.set(80)
|
|
let sr2 = w.getSizeRequest()
|
|
#expect(sr2.width == 80)
|
|
#expect(sr2.height == 200)
|
|
}
|
|
|
|
// MARK: - .bind modifier
|
|
|
|
@Test func bindBoolToVisible() {
|
|
guard Gtk.initCheck() else { return }
|
|
let box = StateBox<Bool>(true)
|
|
let context = MountContext()
|
|
let w = AnyView(Label(str: "x").bind(Binding(box), to: "visible"))
|
|
.makeWidget(context)
|
|
defer { box.set(false) }
|
|
|
|
#expect(w.getVisible() == true)
|
|
box.set(false)
|
|
#expect(w.getVisible() == false)
|
|
}
|
|
|
|
@Test func bindStringToTooltip() {
|
|
guard Gtk.initCheck() else { return }
|
|
let box = StateBox("hello")
|
|
let context = MountContext()
|
|
let w = AnyView(Label(str: "x").bind(Binding(box), to: "tooltip-text"))
|
|
.makeWidget(context)
|
|
defer { box.set("") }
|
|
|
|
#expect(w.getTooltipText() == "hello")
|
|
box.set("world")
|
|
#expect(w.getTooltipText() == "world")
|
|
}
|
|
|
|
@Test func bindIntToWidthRequest() {
|
|
guard Gtk.initCheck() else { return }
|
|
let box = StateBox<Int32>(50)
|
|
let context = MountContext()
|
|
let w = AnyView(Label(str: "x").bind(Binding(box), to: "width-request"))
|
|
.makeWidget(context)
|
|
_ = box
|
|
|
|
#expect(w.getSizeRequest().width == 50)
|
|
box.set(120)
|
|
#expect(w.getSizeRequest().width == 120)
|
|
}
|
|
|
|
@Test func bindDoubleToOpacity() {
|
|
guard Gtk.initCheck() else { return }
|
|
let box = StateBox<Double>(1.0)
|
|
let context = MountContext()
|
|
let w = AnyView(Label(str: "x").bind(Binding(box), to: "opacity"))
|
|
.makeWidget(context)
|
|
_ = box
|
|
|
|
#expect(w.getOpacity() == 1.0)
|
|
box.set(0.0)
|
|
#expect(w.getOpacity() == 0.0)
|
|
}
|
|
|
|
// MARK: - Raw widget drop-in
|
|
|
|
@Test func rawWidgetInVStack() {
|
|
guard Gtk.initCheck() else { return }
|
|
let raw = Gtk.Label(str: "raw")
|
|
let container = AnyView(VStack(spacing: 0) { raw }).makeWidget(
|
|
MountContext())
|
|
|
|
// VStack is backed by Gtk.Box — verify the raw label is a child
|
|
// GTK wrappers create new Swift objects for the same GObject, so
|
|
// compare the underlying object pointers instead of using ===.
|
|
var found = false
|
|
var cur = container.getFirstChild()
|
|
while let c = cur {
|
|
if c.pointer == raw.pointer { found = true; break }
|
|
cur = c.getNextSibling()
|
|
}
|
|
#expect(found)
|
|
}
|
|
|
|
@Test func rawWidgetModifierChain() {
|
|
guard Gtk.initCheck() else { return }
|
|
let raw = Gtk.Label(str: "chained")
|
|
let w = AnyView(raw.preferredWidth(100).hexpand(true)).makeWidget(
|
|
MountContext())
|
|
#expect(w.getSizeRequest().width == 100)
|
|
#expect(w.getHexpand() == true)
|
|
}
|
|
}
|