portico/Tests/PorticoTests/WidgetRefTests.swift

102 lines
4.2 KiB
Swift

import Testing
@_spi(SGTKInternal) import Gtk
@_spi(SGTKInternal) import Adw
@_spi(Portico) import Portico
@MainActor @Suite(.serialized) struct WidgetRefTests {
@Test func backwardReference() {
guard Gtk.initCheck() else { return }
let ref = WidgetRef<Adw.Carousel>()
let context = MountContext()
let root = AnyView(VStack {
Carousel { Label(str: "a") }.ref(ref)
CarouselIndicatorDots().carousel(ref.projectedValue)
}).makeWidget(context) as! Gtk.Box
let first = root.getFirstChild()!
let carousel = Adw.Carousel(retaining: first.pointer)
let dots = Adw.CarouselIndicatorDots(retaining: first.getNextSibling()!.pointer)
#expect(dots.getCarousel()?.pointer == carousel.pointer)
}
@Test func forwardReference() {
guard Gtk.initCheck() else { return }
let ref = WidgetRef<Adw.Carousel>()
let context = MountContext()
let root = AnyView(VStack {
CarouselIndicatorDots().carousel(ref.projectedValue)
Carousel { Label(str: "a") }.ref(ref)
}).makeWidget(context) as! Gtk.Box
let first = root.getFirstChild()!
let dots = Adw.CarouselIndicatorDots(retaining: first.pointer)
let carousel = Adw.Carousel(retaining: first.getNextSibling()!.pointer)
#expect(dots.getCarousel()?.pointer == carousel.pointer)
}
@Test func latePublishFromForEach() {
guard Gtk.initCheck() else { return }
let ref = WidgetRef<Adw.Carousel>()
let items = StateBox<[Int]>([])
let context = MountContext()
let root = AnyView(VStack {
CarouselIndicatorDots().carousel(ref.projectedValue)
ForEach(Binding(items), id: \.self) { _ in Carousel().ref(ref) }
}).makeWidget(context) as! Gtk.Box
let first = root.getFirstChild()!
let dots = Adw.CarouselIndicatorDots(retaining: first.pointer)
#expect(dots.getCarousel() == nil)
items.set([1])
let carousel = Adw.Carousel(retaining: first.getNextSibling()!.pointer)
#expect(dots.getCarousel()?.pointer == carousel.pointer)
}
@Test func teardownClearsPublishedWidget() {
guard Gtk.initCheck() else { return }
let ref = WidgetRef<Adw.Carousel>()
let items = StateBox<[Int]>([])
let ctx = MountContext()
_ = AnyView(VStack {
CarouselIndicatorDots().carousel(ref.projectedValue)
ForEach(Binding(items), id: \.self) { _ in
Carousel().ref(ref)
}
}).makeWidget(ctx)
items.set([1])
#expect(ref.wrappedValue != nil)
ctx.registry.teardown()
#expect(ref.wrappedValue == nil)
}
/// A `WidgetRef` declared at the concrete subclass feeds a modifier whose property
/// is declared `Gtk.Widget?`; the generated overload is generic, so `Binding`'s
/// invariance does not reject it.
/// A `WidgetRef` declared at the concrete subclass feeds a modifier whose property
/// is declared `Gtk.Widget?`; the generated overload is generic.
@Test func widgetTypedBindingOverload() {
guard Gtk.initCheck() else { return }
let entryRef = WidgetRef<Gtk.Entry>()
let context = MountContext()
let root = AnyView(VStack {
Entry().ref(entryRef)
Label(str: "N").mnemonicWidget(entryRef.projectedValue)
}).makeWidget(context) as! Gtk.Box
let first = root.getFirstChild()!
let entry = Gtk.Entry(retaining: first.pointer)
let label = Gtk.Label(retaining: first.getNextSibling()!.pointer)
#expect(label.getMnemonicWidget()?.pointer == entry.pointer)
}
@Test func loweredNullableBindingOverload() {
guard Gtk.initCheck() else { return }
let stackRef = WidgetRef<Gtk.Stack>()
let root = AnyView(VStack {
Stack().ref(stackRef)
StackSidebar().stack(stackRef.projectedValue)
}).makeWidget(MountContext()) as! Gtk.Box
let first = root.getFirstChild()!
let stack = Gtk.Stack(retaining: first.pointer)
let sidebar = Gtk.StackSidebar(retaining: first.getNextSibling()!.pointer)
#expect(sidebar.getStack()?.pointer == stack.pointer)
}
}