187 lines
6.7 KiB
Swift
187 lines
6.7 KiB
Swift
import Adwaita
|
||
import CAdw
|
||
import CGtkWidgets
|
||
import Testing
|
||
|
||
// MARK: - Helpers
|
||
|
||
/// Initialize GTK once per test suite.
|
||
func ensureGTKInit() {
|
||
struct Once {
|
||
static let initialized: Bool = {
|
||
gtk_init()
|
||
return true
|
||
}()
|
||
}
|
||
_ = Once.initialized
|
||
}
|
||
|
||
/// Create a simple test widget that reports a fixed size.
|
||
func makeFixedChild(width: Int, height: Int) -> UnsafeMutablePointer<GtkWidget>? {
|
||
let box = gtk_box_new(.GTK_ORIENTATION_VERTICAL, 0)
|
||
gtk_widget_set_size_request(box, Int32(width), Int32(height))
|
||
gtk_widget_realize(box)
|
||
return box
|
||
}
|
||
|
||
/// Measure a widget and return (minimum, natural).
|
||
func measureWidget(
|
||
_ widget: UnsafeMutablePointer<GtkWidget>?,
|
||
orientation: GtkOrientation,
|
||
forSize: Int = -1
|
||
) -> (minimum: Int, natural: Int) {
|
||
var min: Int32 = 0
|
||
var nat: Int32 = 0
|
||
gtk_widget_measure(widget, orientation, Int32(forSize), &min, &nat, nil, nil)
|
||
return (Int(min), Int(nat))
|
||
}
|
||
|
||
// MARK: - AspectContainer Tests
|
||
|
||
@Suite("Widget Tests", .serialized)
|
||
struct WidgetTests {
|
||
|
||
init() {
|
||
ensureGTKInit()
|
||
}
|
||
|
||
@Test("Reports height = width × ratio when for_size is known")
|
||
func measureWithKnownWidth() {
|
||
let container = aspect_container_new(2.0)!
|
||
let child = makeFixedChild(width: 100, height: 50)
|
||
gtk_widget_set_parent(child, container)
|
||
|
||
let (minH, natH) = measureWidget(
|
||
container, orientation: .GTK_ORIENTATION_VERTICAL, forSize: 100)
|
||
#expect(minH == 200, "height = 100 × 2.0 = 200")
|
||
#expect(natH == 200, "natural height = 200")
|
||
}
|
||
|
||
@Test("Reports height = child_min_w × ratio when for_size is unknown")
|
||
func measureFallback() {
|
||
let container = aspect_container_new(1.5)!
|
||
let child = makeFixedChild(width: 100, height: 100)
|
||
gtk_widget_set_parent(child, container)
|
||
gtk_widget_set_size_request(container, 100, -1)
|
||
|
||
let (minH, natH) = measureWidget(
|
||
container, orientation: .GTK_ORIENTATION_VERTICAL, forSize: -1)
|
||
#expect(minH == 150, "height = 100 × 1.5 = 150 (minimum)")
|
||
#expect(natH == 150, "natural = 150")
|
||
}
|
||
|
||
@Test("max_width caps reported width")
|
||
func maxWidthCapsWidth() {
|
||
let container = aspect_container_new(1.5)!
|
||
let child = makeFixedChild(width: 300, height: 300)
|
||
gtk_widget_set_parent(child, container)
|
||
aspect_container_set_max_width(container.opaque(), 200)
|
||
|
||
let (minW, natW) = measureWidget(
|
||
container, orientation: .GTK_ORIENTATION_HORIZONTAL, forSize: -1)
|
||
#expect(minW == 200, "capped at 200")
|
||
#expect(natW == 200, "capped at 200")
|
||
}
|
||
|
||
@Test("max_width affects height calculation")
|
||
func maxWidthAffectsHeight() {
|
||
let container = aspect_container_new(2.0)!
|
||
let child = makeFixedChild(width: 300, height: 150)
|
||
gtk_widget_set_parent(child, container)
|
||
aspect_container_set_max_width(container.opaque(), 100)
|
||
|
||
let (minH, natH) = measureWidget(
|
||
container, orientation: .GTK_ORIENTATION_VERTICAL, forSize: -1)
|
||
#expect(minH == 200, "height = max_width × ratio = 200")
|
||
#expect(natH == 200, "natural = 200")
|
||
}
|
||
|
||
@Test("Changing aspect ratio triggers resize")
|
||
func changeAspectRatio() {
|
||
let container = aspect_container_new(1.0)!
|
||
let child = makeFixedChild(width: 100, height: 100)
|
||
gtk_widget_set_parent(child, container)
|
||
aspect_container_set_aspect_ratio(container.opaque(), 0.5)
|
||
|
||
let (minH, natH) = measureWidget(
|
||
container, orientation: .GTK_ORIENTATION_VERTICAL, forSize: 100)
|
||
#expect(minH == 50, "height = 100 × 0.5 = 50")
|
||
#expect(natH == 50, "natural = 50")
|
||
}
|
||
|
||
@Test("Horizontal measure returns 0 without max_width")
|
||
func horizontalMeasureNoMaxWidth() {
|
||
let container = aspect_container_new(1.5)!
|
||
let child = makeFixedChild(width: 300, height: 200)
|
||
gtk_widget_set_parent(child, container)
|
||
|
||
let (minW, natW) = measureWidget(
|
||
container, orientation: .GTK_ORIENTATION_HORIZONTAL, forSize: -1)
|
||
#expect(minW == 0, "no max_width → reports 0")
|
||
#expect(natW == 0, "no max_width → reports 0")
|
||
}
|
||
|
||
// MARK: - AspectContainer Tests
|
||
|
||
/// Helper: create a FlowGrid with `n` children, each having a given size.
|
||
func makeFlowGrid(
|
||
minimumSize: Int = 100,
|
||
columnSpacing: Int = 0,
|
||
rowSpacing: Int = 0,
|
||
childSize: Int = 100,
|
||
count: Int = 4
|
||
) -> UnsafeMutablePointer<GtkWidget>? {
|
||
let grid = flow_grid_new(Int32(minimumSize), Int32(columnSpacing), Int32(rowSpacing))
|
||
for _ in 0..<count {
|
||
let child = gtk_box_new(.GTK_ORIENTATION_VERTICAL, 0)
|
||
gtk_widget_set_size_request(child, Int32(childSize), Int32(childSize))
|
||
gtk_widget_set_parent(child, grid)
|
||
}
|
||
return grid
|
||
}
|
||
|
||
@Test("Height = tallest child height when for_size is known")
|
||
func measureTalliesRowHeights() {
|
||
let grid = makeFlowGrid(
|
||
minimumSize: 150, columnSpacing: 0, rowSpacing: 0, childSize: 100, count: 6)
|
||
|
||
let (minH, natH) = measureWidget(grid, orientation: .GTK_ORIENTATION_VERTICAL, forSize: 300)
|
||
#expect(minH == 300, "3 rows × 100 = 300")
|
||
#expect(natH == 300, "natural = 300")
|
||
}
|
||
|
||
@Test("Column spacing is accounted for in column count")
|
||
func columnSpacingAffectsCount() {
|
||
let noSpacing = makeFlowGrid(
|
||
minimumSize: 100, columnSpacing: 0, rowSpacing: 0, childSize: 100, count: 4)
|
||
let withSpacing = makeFlowGrid(
|
||
minimumSize: 100, columnSpacing: 50, rowSpacing: 0, childSize: 100, count: 4)
|
||
|
||
let (h1, _) = measureWidget(noSpacing, orientation: .GTK_ORIENTATION_VERTICAL, forSize: 250)
|
||
#expect(h1 == 200, "250 width → 2 cols × 2 rows × 100 = 200")
|
||
|
||
let (h2, _) = measureWidget(
|
||
withSpacing, orientation: .GTK_ORIENTATION_VERTICAL, forSize: 250)
|
||
#expect(h2 == 200, "250 width → 2 cols × 2 rows × 100 = 200")
|
||
}
|
||
|
||
@Test("Row spacing adds to total height")
|
||
func rowSpacingAddsHeight() {
|
||
let grid = makeFlowGrid(
|
||
minimumSize: 100, columnSpacing: 0, rowSpacing: 10, childSize: 100, count: 6)
|
||
|
||
let (minH, natH) = measureWidget(grid, orientation: .GTK_ORIENTATION_VERTICAL, forSize: 300)
|
||
#expect(minH == 210, "2 rows × 100 + 1 spacing × 10 = 210")
|
||
#expect(natH == 210, "natural = 210")
|
||
}
|
||
|
||
@Test("Single child fills one cell")
|
||
func singleChild() {
|
||
let grid = makeFlowGrid(minimumSize: 200, childSize: 150, count: 1)
|
||
|
||
let (minH, natH) = measureWidget(grid, orientation: .GTK_ORIENTATION_VERTICAL, forSize: 400)
|
||
#expect(minH == 150, "single row = child height")
|
||
#expect(natH == 150, "natural = 150")
|
||
}
|
||
|
||
}
|