package spec
import (
"os"
"reflect"
"strings"
"testing"
)
func readTestdata(t *testing.T, name string) []byte {
t.Helper()
b, err := os.ReadFile("testdata/" + name)
if err != nil {
t.Fatal(err)
}
return b
}
func findInterface(t *testing.T, p *Protocol, name string) Interface {
t.Helper()
for _, it := range p.Interfaces {
if it.Name == name {
return it
}
}
t.Fatalf("interface %q not found", name)
return Interface{}
}
func findMessage(t *testing.T, ms []Message, name string) Message {
t.Helper()
for _, m := range ms {
if m.Name == name {
return m
}
}
t.Fatalf("message %q not found", name)
return Message{}
}
func findEnum(t *testing.T, it Interface, name string) Enum {
t.Helper()
for _, e := range it.Enums {
if e.Name == name {
return e
}
}
t.Fatalf("enum %q not found in %s", name, it.Name)
return Enum{}
}
func TestParseWayland(t *testing.T) {
p, err := Parse(readTestdata(t, "wayland.xml"))
if err != nil {
t.Fatal(err)
}
if p.Name != "wayland" {
t.Errorf("Name = %q", p.Name)
}
if !strings.Contains(p.Copyright, "Kristian") {
t.Errorf("Copyright not preserved: %q", p.Copyright)
}
if len(p.Interfaces) != 23 {
t.Errorf("got %d interfaces, want 23", len(p.Interfaces))
}
if got := findInterface(t, p, "wl_compositor").Version; got != 7 {
t.Errorf("wl_compositor version = %d, want 7", got)
}
// since on a message.
release := findMessage(t, findInterface(t, p, "wl_pointer").Requests, "release")
if release.Type != "destructor" || release.Since != 3 {
t.Errorf("wl_pointer.release = type %q since %d", release.Type, release.Since)
}
// since on an enum.
if e := findEnum(t, findInterface(t, p, "wl_data_device_manager"), "dnd_action"); !e.Bitfield || e.Since != 3 {
t.Errorf("dnd_action = bitfield %v since %d, want true 3", e.Bitfield, e.Since)
}
// bitfield.
seat := findInterface(t, p, "wl_seat")
if !findEnum(t, seat, "capability").Bitfield {
t.Error("wl_seat.capability should be a bitfield")
}
if findEnum(t, seat, "error").Bitfield {
t.Error("wl_seat.error should not be a bitfield")
}
if len(findEnum(t, seat, "capability").Entries) == 0 {
t.Error("capability has no entries")
}
// allow-null and interface refs.
var nullArg, plainArg *Arg
for _, m := range findInterface(t, p, "wl_data_device").Requests {
for i := range m.Args {
a := &m.Args[i]
if m.Name == "set_selection" && a.Name == "source" {
nullArg = a
}
if m.Name == "start_drag" && a.Name == "origin" {
plainArg = a
}
}
}
if nullArg == nil || !nullArg.AllowNull || nullArg.Interface != "wl_data_source" || nullArg.Type != "object" {
t.Errorf("set_selection.source = %+v", nullArg)
}
if plainArg == nil || plainArg.AllowNull {
t.Errorf("start_drag.origin = %+v", plainArg)
}
// enum refs, qualified and unqualified.
create := findMessage(t, findInterface(t, p, "wl_shm_pool").Requests, "create_buffer")
var enumRefs []string
for _, a := range create.Args {
if a.Enum != "" {
enumRefs = append(enumRefs, a.Enum)
}
}
if !reflect.DeepEqual(enumRefs, []string{"wl_shm.format"}) {
t.Errorf("create_buffer enum refs = %v", enumRefs)
}
var found bool
for _, a := range findMessage(t, findInterface(t, p, "wl_output").Events, "mode").Args {
if a.Name == "flags" && a.Enum == "mode" && a.Summary != "" {
found = true
}
}
if !found {
t.Error("wl_output.mode flags enum ref/summary not preserved")
}
// Descriptions.
if d := findInterface(t, p, "wl_display").Description; d == nil || d.Summary == "" || strings.TrimSpace(d.Text) == "" {
t.Errorf("description not parsed: %+v", d)
}
}
func TestParseFixture(t *testing.T) {
p, err := Parse(readTestdata(t, "protocol_fixture.xml"))
if err != nil {
t.Fatal(err)
}
if p.Name != "wlvision_fixture" || !strings.Contains(p.Copyright, "Synthetic protocol") {
t.Errorf("protocol = %q / %q", p.Name, p.Copyright)
}
if len(p.Interfaces) != 3 {
t.Fatalf("got %d interfaces", len(p.Interfaces))
}
mgr := findInterface(t, p, "zwlr_fixture_manager_v1")
if mgr.Version != 2 || len(mgr.Requests) != 10 {
t.Errorf("manager version %d requests %d", mgr.Version, len(mgr.Requests))
}
out := findMessage(t, mgr.Requests, "set_optional_output").Args[0]
if !out.AllowNull || out.Interface != "wl_output" {
t.Errorf("set_optional_output arg = %+v", out)
}
thing := findInterface(t, p, "zwlr_fixture_thing_v1")
if len(thing.Events) != 7 || len(thing.Enums) != 1 || thing.Enums[0].Entries[1].Value != "1" {
t.Errorf("thing = %d events, enums %+v", len(thing.Events), thing.Enums)
}
want := []string{"wl_seat", "zwlr_fixture_thing_v1", "wl_region", "wl_buffer", "wl_output", "zwlr_fixture_mode_v1", "wl_surface"}
if got := p.ReferencedInterfaces(); !reflect.DeepEqual(got, want) {
t.Errorf("ReferencedInterfaces = %v, want %v", got, want)
}
}
func TestParseErrors(t *testing.T) {
for name, in := range map[string]string{
"not xml": "nope",
"no name": ``,
"wrong tag": ``,
} {
if _, err := Parse([]byte(in)); err == nil {
t.Errorf("%s: expected error", name)
}
}
}