197 lines
7 KiB
Swift
197 lines
7 KiB
Swift
import Testing
|
|
@_spi(SGTKInternal) import Adw
|
|
@_spi(SGTKInternal) import Gtk
|
|
@_spi(Portico) import Portico
|
|
|
|
private enum AccentKey: EnvironmentKey {
|
|
static let defaultValue = "default-accent"
|
|
}
|
|
|
|
extension EnvironmentValues {
|
|
fileprivate var accent: String {
|
|
get { self[AccentKey.self] }
|
|
set { self[AccentKey.self] = newValue }
|
|
}
|
|
}
|
|
|
|
private struct AccentLabel: View {
|
|
@Environment(\.accent) private var accent
|
|
|
|
var body: some View {
|
|
Label(str: "").label { accent }
|
|
}
|
|
}
|
|
|
|
@MainActor @Suite(.serialized) struct ForEachSpreadTests {
|
|
private func directLabels(_ widget: Gtk.Widget) -> [String] {
|
|
var result: [String] = []
|
|
var child = widget.getFirstChild()
|
|
while let current = child {
|
|
if current.cssName == "label" {
|
|
result.append(Gtk.Label(retaining: current.pointer).getText())
|
|
} else {
|
|
result.append("<\(current.cssName)>")
|
|
}
|
|
child = current.getNextSibling()
|
|
}
|
|
return result
|
|
}
|
|
|
|
private func wrappedLabels(_ widget: Gtk.Widget) -> [String] {
|
|
var result: [String] = []
|
|
var child = widget.getFirstChild()
|
|
while let current = child {
|
|
if let inner = current.getFirstChild() {
|
|
result.append(Gtk.Label(retaining: inner.pointer).getText())
|
|
}
|
|
child = current.getNextSibling()
|
|
}
|
|
return result
|
|
}
|
|
|
|
@Test func spreadsIntoWrapBoxWithoutWrapper() {
|
|
guard Gtk.initCheck() else { return }
|
|
let items = StateBox([(1, "Nachos"), (2, "Tacos")])
|
|
let view = WrapBox {
|
|
Label(str: "Header")
|
|
ForEach(Binding(items), id: \.0) { Label(str: $0.1) }
|
|
}
|
|
let wrap = AnyView(view).makeWidget(MountContext()) as! Adw.WrapBox
|
|
|
|
#expect(directLabels(wrap) == ["Header", "Nachos", "Tacos"])
|
|
}
|
|
|
|
@Test func wrapBoxDiffRespectsLeadingStaticChild() {
|
|
guard Gtk.initCheck() else { return }
|
|
let items = StateBox([(1, "Nachos"), (2, "Tacos")])
|
|
let view = WrapBox {
|
|
Label(str: "Header")
|
|
ForEach(Binding(items), id: \.0) { Label(str: $0.1) }
|
|
}
|
|
let wrap = AnyView(view).makeWidget(MountContext()) as! Adw.WrapBox
|
|
|
|
items.set([(1, "Nachos"), (2, "Tacos"), (3, "Enchiladas")])
|
|
#expect(directLabels(wrap) == ["Header", "Nachos", "Tacos", "Enchiladas"])
|
|
items.set([(2, "Tacos"), (3, "Enchiladas")])
|
|
#expect(directLabels(wrap) == ["Header", "Tacos", "Enchiladas"])
|
|
items.set([(3, "Enchiladas"), (2, "Tacos")])
|
|
#expect(directLabels(wrap) == ["Header", "Enchiladas", "Tacos"])
|
|
}
|
|
|
|
@Test func spreadsIntoListBoxAndRemovesWrappedRow() {
|
|
guard Gtk.initCheck() else { return }
|
|
let items = StateBox([(1, "One"), (2, "Two"), (3, "Three")])
|
|
let view = ListBox {
|
|
ForEach(Binding(items), id: \.0) { Label(str: $0.1) }
|
|
}
|
|
let list = AnyView(view).makeWidget(MountContext()) as! Gtk.ListBox
|
|
|
|
#expect(wrappedLabels(list) == ["One", "Two", "Three"])
|
|
items.set([(1, "One"), (3, "Three")])
|
|
#expect(wrappedLabels(list) == ["One", "Three"])
|
|
}
|
|
|
|
@Test func spreadsIntoCarousel() {
|
|
guard Gtk.initCheck() else { return }
|
|
let items = StateBox([(1, "One"), (2, "Two"), (3, "Three")])
|
|
let view = Carousel {
|
|
ForEach(Binding(items), id: \.0) { Label(str: $0.1) }
|
|
}
|
|
let carousel = AnyView(view).makeWidget(MountContext()) as! Adw.Carousel
|
|
|
|
#expect(carousel.getNPages() == 3)
|
|
items.set([(1, "One"), (3, "Three")])
|
|
#expect(carousel.getNPages() == 2)
|
|
}
|
|
|
|
@Test func twoForEachRegionsStayIndependent() {
|
|
guard Gtk.initCheck() else { return }
|
|
let first = StateBox([(1, "A1"), (2, "A2")])
|
|
let second = StateBox([(3, "B1"), (4, "B2")])
|
|
let view = WrapBox {
|
|
ForEach(Binding(first), id: \.0) { Label(str: $0.1) }
|
|
ForEach(Binding(second), id: \.0) { Label(str: $0.1) }
|
|
}
|
|
let wrap = AnyView(view).makeWidget(MountContext()) as! Adw.WrapBox
|
|
|
|
first.set([(1, "A1"), (2, "A2"), (5, "A3")])
|
|
#expect(directLabels(wrap) == ["A1", "A2", "A3", "B1", "B2"])
|
|
}
|
|
|
|
@Test func groupSurvivesEnvironmentModifier() {
|
|
guard Gtk.initCheck() else { return }
|
|
let items = StateBox([1, 2])
|
|
let view = WrapBox {
|
|
ForEach(Binding(items), id: \.self) { _ in AccentLabel() }
|
|
.environment(\.accent, "scoped")
|
|
}
|
|
let wrap = AnyView(view).makeWidget(MountContext()) as! Adw.WrapBox
|
|
|
|
#expect(directLabels(wrap) == ["scoped", "scoped"])
|
|
}
|
|
|
|
@Test func ledgerDownwardRangeMoveOnIndexHost() {
|
|
guard Gtk.initCheck() else { return }
|
|
let list = Gtk.ListBox()
|
|
let ledger = ChildLedger(host: list)
|
|
let region = ledger.addRegion()
|
|
for name in ["A", "B", "C", "D"] {
|
|
region.insert(Gtk.Label(str: name), at: region.count)
|
|
}
|
|
#expect(wrappedLabels(list) == ["A", "B", "C", "D"])
|
|
|
|
region.move(from: 1, count: 2, to: 2)
|
|
#expect(wrappedLabels(list) == ["A", "D", "B", "C"])
|
|
|
|
region.move(from: 0, count: 1, to: 3)
|
|
#expect(wrappedLabels(list) == ["D", "B", "C", "A"])
|
|
}
|
|
|
|
@Test func ledgerDownwardRangeMoveOnSiblingHost() {
|
|
guard Gtk.initCheck() else { return }
|
|
let box = Gtk.Box(orientation: .vertical, spacing: 0)
|
|
let ledger = ChildLedger(host: box)
|
|
let region = ledger.addRegion()
|
|
for name in ["A", "B", "C", "D"] {
|
|
region.insert(Gtk.Label(str: name), at: region.count)
|
|
}
|
|
#expect(directLabels(box) == ["A", "B", "C", "D"])
|
|
|
|
region.move(from: 1, count: 2, to: 2)
|
|
#expect(directLabels(box) == ["A", "D", "B", "C"])
|
|
|
|
region.move(from: 0, count: 1, to: 3)
|
|
#expect(directLabels(box) == ["D", "B", "C", "A"])
|
|
}
|
|
|
|
@Test func ledgerUpwardRangeMoveOnSiblingHost() {
|
|
guard Gtk.initCheck() else { return }
|
|
let box = Gtk.Box(orientation: .vertical, spacing: 0)
|
|
let ledger = ChildLedger(host: box)
|
|
let region = ledger.addRegion()
|
|
for name in ["A", "B", "C", "D"] {
|
|
region.insert(Gtk.Label(str: name), at: region.count)
|
|
}
|
|
|
|
region.move(from: 2, count: 2, to: 0)
|
|
#expect(directLabels(box) == ["C", "D", "A", "B"])
|
|
|
|
region.move(from: 3, count: 1, to: 1)
|
|
#expect(directLabels(box) == ["C", "B", "D", "A"])
|
|
}
|
|
|
|
@Test func fallsBackToBoxInSingleWidgetPosition() {
|
|
guard Gtk.initCheck() else { return }
|
|
let items = StateBox([(1, "One"), (2, "Two")])
|
|
let view = ScrolledWindow {
|
|
ForEach(Binding(items), id: \.0) { Label(str: $0.1) }
|
|
}
|
|
let scrolled = AnyView(view).makeWidget(MountContext()) as! Gtk.ScrolledWindow
|
|
var child = scrolled.getChild()!
|
|
while child.cssName != "box" {
|
|
child = child.getFirstChild()!
|
|
}
|
|
let box = Gtk.Box(retaining: child.pointer)
|
|
#expect(directLabels(box) == ["One", "Two"])
|
|
}
|
|
}
|