140 lines
4.4 KiB
Swift
140 lines
4.4 KiB
Swift
import Testing
|
|
@_spi(SGTKInternal) import Gtk
|
|
@_spi(Portico) import Portico
|
|
|
|
@MainActor @Suite(.serialized) struct ReactiveLabelTests {
|
|
|
|
// MARK: - GTK-dependent tests
|
|
|
|
@Test func explicitBindingUpdatesLabel() {
|
|
guard Gtk.initCheck() else { return }
|
|
let box = StateBox("a")
|
|
let ctx = MountContext()
|
|
let w = AnyView(Label(str: "").label(Binding(box))).makeWidget(ctx)
|
|
let lbl = w as! Gtk.Label
|
|
defer { box.set("") }
|
|
|
|
#expect(lbl.getText() == "a")
|
|
box.set("b")
|
|
#expect(lbl.getText() == "b")
|
|
}
|
|
|
|
@Test func explicitBindingUpdatesMultipleTimes() {
|
|
guard Gtk.initCheck() else { return }
|
|
let box = StateBox("first")
|
|
let ctx = MountContext()
|
|
let lbl = AnyView(Label(str: "").label(Binding(box))).makeWidget(ctx) as! Gtk.Label
|
|
defer { box.set("") }
|
|
|
|
#expect(lbl.getText() == "first")
|
|
box.set("second")
|
|
#expect(lbl.getText() == "second")
|
|
box.set("third")
|
|
#expect(lbl.getText() == "third")
|
|
}
|
|
|
|
@Test func trackedClosureUpdatesLabel() {
|
|
guard Gtk.initCheck() else { return }
|
|
let box = StateBox(0)
|
|
let lbl = AnyView(Label(str: "").label { "Count: \(box.get())" })
|
|
.makeWidget(MountContext()) as! Gtk.Label
|
|
defer { box.set(0) }
|
|
|
|
#expect(lbl.getText() == "Count: 0")
|
|
box.set(1)
|
|
#expect(lbl.getText() == "Count: 1")
|
|
box.set(2)
|
|
#expect(lbl.getText() == "Count: 2")
|
|
}
|
|
|
|
@Test func reactiveNodeMountsExactlyOnce() {
|
|
guard Gtk.initCheck() else { return }
|
|
MountProbe.count = 0
|
|
let box = StateBox(0)
|
|
let ctx = MountContext()
|
|
defer { box.set(0) }
|
|
|
|
let lbl = AnyView(ProbeLabel(box: box)).makeWidget(ctx) as! Gtk.Label
|
|
|
|
#expect(MountProbe.count == 1)
|
|
#expect(lbl.getText() == "n=0")
|
|
box.set(1)
|
|
#expect(MountProbe.count == 1)
|
|
#expect(lbl.getText() == "n=1")
|
|
}
|
|
|
|
@Test func bindingNodeMountsExactlyOnce() {
|
|
guard Gtk.initCheck() else { return }
|
|
MountProbe.count = 0
|
|
let box = StateBox("a")
|
|
let ctx = MountContext()
|
|
defer { box.set("") }
|
|
|
|
let lbl = AnyView(ProbeBindingLabel(box: box)).makeWidget(ctx) as! Gtk.Label
|
|
|
|
#expect(MountProbe.count == 1)
|
|
#expect(lbl.getText() == "a")
|
|
box.set("b")
|
|
#expect(MountProbe.count == 1)
|
|
#expect(lbl.getText() == "b")
|
|
}
|
|
|
|
@Test func constantLabelStaysUnchanged() {
|
|
guard Gtk.initCheck() else { return }
|
|
let lbl = AnyView(Label(str: "static"))
|
|
.makeWidget(MountContext()) as! Gtk.Label
|
|
|
|
#expect(lbl.getText() == "static")
|
|
}
|
|
|
|
// MARK: - Regression: wrapper not retained after mount
|
|
|
|
@Test func trackedLabelUpdatesWhenWrapperNotRetained() {
|
|
guard Gtk.initCheck() else { return }
|
|
let box = StateBox(0)
|
|
let parent = Gtk.Box(orientation: .vertical, spacing: 0)
|
|
do {
|
|
let w = AnyView(Label(str: "").label { "n=\(box.get())" }).makeWidget(MountContext())
|
|
parent.append(child: w)
|
|
}
|
|
box.set(1)
|
|
let child = Gtk.Label(retaining: parent.getFirstChild()!.pointer)
|
|
#expect(child.getText() == "n=1")
|
|
}
|
|
|
|
@Test func explicitBindingUpdatesWhenWrapperNotRetained() {
|
|
guard Gtk.initCheck() else { return }
|
|
let box = StateBox("a")
|
|
let parent = Gtk.Box(orientation: .vertical, spacing: 0)
|
|
let ctx = MountContext()
|
|
do {
|
|
let w = AnyView(Label(str: "").label(Binding(box))).makeWidget(ctx)
|
|
parent.append(child: w)
|
|
}
|
|
box.set("b")
|
|
let child = Gtk.Label(retaining: parent.getFirstChild()!.pointer)
|
|
#expect(child.getText() == "b")
|
|
}
|
|
}
|
|
|
|
// MARK: - Test helpers
|
|
|
|
@MainActor fileprivate enum MountProbe { static var count = 0 }
|
|
|
|
@MainActor fileprivate struct ProbeLabel: View, Mountable {
|
|
let box: StateBox<Int>
|
|
var body: Never { fatalError() }
|
|
func mount(_ ctx: MountContext) -> Gtk.Widget {
|
|
MountProbe.count += 1
|
|
return AnyView(Label(str: "").label { "n=\(box.get())" }).makeWidget(ctx)
|
|
}
|
|
}
|
|
|
|
@MainActor fileprivate struct ProbeBindingLabel: View, Mountable {
|
|
let box: StateBox<String>
|
|
var body: Never { fatalError() }
|
|
func mount(_ ctx: MountContext) -> Gtk.Widget {
|
|
MountProbe.count += 1
|
|
return AnyView(Label(str: "").label(Binding(box))).makeWidget(ctx)
|
|
}
|
|
}
|