gioui.org@v0.6.1-0.20240506124620-7a9ce51988ce/io/input/semantic_test.go (about)

     1  // SPDX-License-Identifier: Unlicense OR MIT
     2  
     3  package input
     4  
     5  import (
     6  	"fmt"
     7  	"image"
     8  	"reflect"
     9  	"testing"
    10  
    11  	"gioui.org/f32"
    12  	"gioui.org/io/event"
    13  	"gioui.org/io/pointer"
    14  	"gioui.org/io/semantic"
    15  	"gioui.org/op"
    16  	"gioui.org/op/clip"
    17  )
    18  
    19  func TestEmptySemantics(t *testing.T) {
    20  	var r Router
    21  	tree := r.AppendSemantics(nil)
    22  	if len(tree) != 1 {
    23  		t.Errorf("expected 1 semantic node for empty tree, got %d", len(tree))
    24  	}
    25  }
    26  
    27  func TestSemanticTree(t *testing.T) {
    28  	var (
    29  		ops op.Ops
    30  		r   Router
    31  	)
    32  	t1 := clip.Rect(image.Rect(0, 0, 75, 75)).Push(&ops)
    33  	semantic.DescriptionOp("child1").Add(&ops)
    34  	t1.Pop()
    35  	t2 := clip.Rect(image.Rect(25, 25, 100, 100)).Push(&ops)
    36  	semantic.DescriptionOp("child2").Add(&ops)
    37  	t2.Pop()
    38  	r.Frame(&ops)
    39  	tests := []struct {
    40  		x, y float32
    41  		desc string
    42  	}{
    43  		{24, 24, "child1"},
    44  		{50, 50, "child2"},
    45  		{100, 100, ""},
    46  	}
    47  	tree := r.AppendSemantics(nil)
    48  	verifyTree(t, 0, tree[0])
    49  	for _, test := range tests {
    50  		p := f32.Pt(test.x, test.y)
    51  		id, found := r.SemanticAt(p)
    52  		if !found {
    53  			t.Errorf("no semantic node at %v", p)
    54  		}
    55  		n, found := lookupNode(tree, id)
    56  		if !found {
    57  			t.Errorf("no id %d in semantic tree", id)
    58  		}
    59  		if got := n.Desc.Description; got != test.desc {
    60  			t.Errorf("got semantic description %s at %v, expected %s", got, p, test.desc)
    61  		}
    62  	}
    63  
    64  	// Verify stable IDs.
    65  	r.Frame(&ops)
    66  	tree2 := r.AppendSemantics(nil)
    67  	if !reflect.DeepEqual(tree, tree2) {
    68  		fmt.Println("First tree:")
    69  		printTree(0, tree[0])
    70  		fmt.Println("Second tree:")
    71  		printTree(0, tree2[0])
    72  		t.Error("same semantic description lead to differing trees")
    73  	}
    74  }
    75  
    76  func TestSemanticDescription(t *testing.T) {
    77  	var ops op.Ops
    78  
    79  	h := new(int)
    80  	event.Op(&ops, h)
    81  	semantic.DescriptionOp("description").Add(&ops)
    82  	semantic.LabelOp("label").Add(&ops)
    83  	semantic.Button.Add(&ops)
    84  	semantic.EnabledOp(false).Add(&ops)
    85  	semantic.SelectedOp(true).Add(&ops)
    86  	var r Router
    87  	events(&r, -1, pointer.Filter{
    88  		Target: h,
    89  		Kinds:  pointer.Press | pointer.Release,
    90  	})
    91  	r.Frame(&ops)
    92  	tree := r.AppendSemantics(nil)
    93  	got := tree[0].Desc
    94  	exp := SemanticDesc{
    95  		Class:       1,
    96  		Description: "description",
    97  		Label:       "label",
    98  		Selected:    true,
    99  		Disabled:    true,
   100  		Gestures:    ClickGesture,
   101  		Bounds:      image.Rectangle{Min: image.Point{X: -1e+06, Y: -1e+06}, Max: image.Point{X: 1e+06, Y: 1e+06}},
   102  	}
   103  	if got != exp {
   104  		t.Errorf("semantic description mismatch:\nGot:  %+v\nWant: %+v", got, exp)
   105  	}
   106  }
   107  
   108  func lookupNode(tree []SemanticNode, id SemanticID) (SemanticNode, bool) {
   109  	for _, n := range tree {
   110  		if id == n.ID {
   111  			return n, true
   112  		}
   113  	}
   114  	return SemanticNode{}, false
   115  }
   116  
   117  func verifyTree(t *testing.T, parent SemanticID, n SemanticNode) {
   118  	t.Helper()
   119  	if n.ParentID != parent {
   120  		t.Errorf("node %d: got parent %d, want %d", n.ID, n.ParentID, parent)
   121  	}
   122  	for _, c := range n.Children {
   123  		verifyTree(t, n.ID, c)
   124  	}
   125  }
   126  
   127  func printTree(indent int, n SemanticNode) {
   128  	for i := 0; i < indent; i++ {
   129  		fmt.Print("\t")
   130  	}
   131  	fmt.Printf("%d: %+v\n", n.ID, n.Desc)
   132  	for _, c := range n.Children {
   133  		printTree(indent+1, c)
   134  	}
   135  }