test(keymap): pin wayland-format keymaps for fd reference cases
- commit
- 30529e3b69ce8dbb82f1535aba7f2f46ffd3f694
- author
- brice · · 2026-09-28 07:10 UTC
- parent
- 4e91a36
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· arch-gpg Verified for the committer email
6 files · +8495 -20
M README.md +1 -1
| @@ -15,6 +15,6 @@ defer state.Close() | |||
| 15 | 15 | text, err := state.UTF8(xkbcommon.WaylandKeycode(evdevKeycode)) | |
| 16 | 16 | ``` | |
| 17 | 17 | ||
| 18 | - | Use `NewKeymapFD(fd, size)` for Wayland `xkb_v1` keymaps; it maps the supplied size with `PROT_READ|MAP_PRIVATE` and requires a trailing NUL. **The caller retains and must close the FD**, on success and failure. `UpdateMask` accepts Wayland modifier masks and group indices. `ComposeState.Feed` and `Status` distinguish composing, composed, cancelled, and ignored keysyms; use `UTF8` only for a composed result. Objects retain their native parents; close each object, in any order. Do not copy value structs containing a mutex. | |
| 18 | + | Use `NewKeymapFD(fd, size)` for Wayland `xkb_v1` keymaps; it copies exactly `size` bytes with `pread` (at most 16 MiB), fails on a short read, and accepts an optional trailing NUL. **The caller retains and must close the FD**, on success and failure. `UpdateMask` accepts Wayland modifier masks and group indices. `ComposeState.Feed` and `Status` distinguish composing, composed, cancelled, and ignored keysyms; use `UTF8` only for a composed result. Objects retain their native parents; close each object, in any order. Do not copy value structs containing a mutex. | |
| 19 | 19 | ||
| 20 | 20 | Pinned upstream headers and licenses are in `upstream/`; `upstream/METADATA` and `SHA256SUMS` identify their exact source. Run `GOWORK=off go generate ./...` to regenerate `raw/generated.go`; consumers do not run generation. The generator checks the selected ABI declarations against the headers. `github.com/bnema/purego v0.13.0-bnema.1` matches purego-vulkan and supports `Dlopen`, `Dlsym`, and `RegisterFunc` with cgo disabled. | |
| @@ -15,6 +15,6 @@ defer state.Close() | |||||
| 15 | text, err := state.UTF8(xkbcommon.WaylandKeycode(evdevKeycode)) | 15 | text, err := state.UTF8(xkbcommon.WaylandKeycode(evdevKeycode)) | ||
| 16 | ``` | 16 | ``` | ||
| 17 | 17 | ||||
| 18 | - | Use `NewKeymapFD(fd, size)` for Wayland `xkb_v1` keymaps; it maps the supplied size with `PROT_READ|MAP_PRIVATE` and requires a trailing NUL. **The caller retains and must close the FD**, on success and failure. `UpdateMask` accepts Wayland modifier masks and group indices. `ComposeState.Feed` and `Status` distinguish composing, composed, cancelled, and ignored keysyms; use `UTF8` only for a composed result. Objects retain their native parents; close each object, in any order. Do not copy value structs containing a mutex. | 18 | + | Use `NewKeymapFD(fd, size)` for Wayland `xkb_v1` keymaps; it copies exactly `size` bytes with `pread` (at most 16 MiB), fails on a short read, and accepts an optional trailing NUL. **The caller retains and must close the FD**, on success and failure. `UpdateMask` accepts Wayland modifier masks and group indices. `ComposeState.Feed` and `Status` distinguish composing, composed, cancelled, and ignored keysyms; use `UTF8` only for a composed result. Objects retain their native parents; close each object, in any order. Do not copy value structs containing a mutex. |
| 19 | 19 | ||||
| 20 | Pinned upstream headers and licenses are in `upstream/`; `upstream/METADATA` and `SHA256SUMS` identify their exact source. Run `GOWORK=off go generate ./...` to regenerate `raw/generated.go`; consumers do not run generation. The generator checks the selected ABI declarations against the headers. `github.com/bnema/purego v0.13.0-bnema.1` matches purego-vulkan and supports `Dlopen`, `Dlsym`, and `RegisterFunc` with cgo disabled. | 20 | Pinned upstream headers and licenses are in `upstream/`; `upstream/METADATA` and `SHA256SUMS` identify their exact source. Run `GOWORK=off go generate ./...` to regenerate `raw/generated.go`; consumers do not run generation. The generator checks the selected ABI declarations against the headers. `github.com/bnema/purego v0.13.0-bnema.1` matches purego-vulkan and supports `Dlopen`, `Dlsym`, and `RegisterFunc` with cgo disabled. | ||
A testdata/keymaps/de.xkb +2090 -0 large diff (2090 lines changed): collapsed
A testdata/keymaps/fr.xkb +2084 -0 large diff (2084 lines changed): collapsed
A testdata/keymaps/us.xkb +2081 -0 large diff (2081 lines changed): collapsed
A testdata/keymaps/us_fr.xkb +2227 -0 large diff (2227 lines changed): collapsed
M xkbcommon_test.go +12 -19
| @@ -238,9 +238,6 @@ func TestLayoutsAndDifferential(t *testing.T) { | |||
| 238 | 238 | // binding under test. Every case compiles through the Wayland FD path. | |
| 239 | 239 | func TestFDReferenceKeyEvents(t *testing.T) { | |
| 240 | 240 | c := live(t) | |
| 241 | - | if _, e := exec.LookPath("xkbcli"); e != nil { | |
| 242 | - | t.Logf("xkbcli compile-keymap/how-to-type comparison skipped: %v", e) | |
| 243 | - | } | |
| 244 | 241 | for _, tc := range []struct { | |
| 245 | 242 | layout, key, utf8, modifiers string | |
| 246 | 243 | evdev, group, sym uint32 | |
| @@ -256,23 +253,19 @@ func TestFDReferenceKeyEvents(t *testing.T) { | |||
| 256 | 253 | {"us,fr", "a", "a", "", 16, 1, raw.XKB_KEY_a}, | |
| 257 | 254 | } { | |
| 258 | 255 | t.Run(tc.layout+"/"+tc.key+"/"+tc.modifiers, func(t *testing.T) { | |
| 259 | - | // xkbcli independently compiles the text used by the Wayland FD path. | |
| 260 | - | // Without it, still check the fixed reference table against rules. | |
| 261 | - | var k *Keymap | |
| 262 | - | if _, e := exec.LookPath("xkbcli"); e == nil { | |
| 263 | - | text, e := exec.Command("xkbcli", "compile-keymap", "--layout", tc.layout, "--output-format", "1").Output() | |
| 264 | - | if e != nil { | |
| 265 | - | t.Fatal(e) | |
| 266 | - | } | |
| 267 | - | f := keymapFile(t, append(text, 0)) | |
| 268 | - | k, e = c.NewKeymapFD(int(f.Fd()), len(text)+1) | |
| 269 | - | if e != nil { | |
| 270 | - | t.Fatal(e) | |
| 271 | - | } | |
| 272 | - | t.Cleanup(func() { k.Close() }) | |
| 273 | - | } else { | |
| 274 | - | k = rules(t, c, tc.layout) | |
| 256 | + | // Wayland-format keymaps pinned in testdata/keymaps were produced by | |
| 257 | + | // `xkbcli compile-keymap --output-format 1` (libxkbcommon 1.13.2), so | |
| 258 | + | // the FD path is always exercised without optional tools. | |
| 259 | + | text, e := os.ReadFile("testdata/keymaps/" + strings.ReplaceAll(tc.layout, ",", "_") + ".xkb") | |
| 260 | + | if e != nil { | |
| 261 | + | t.Fatal(e) | |
| 262 | + | } | |
| 263 | + | f := keymapFile(t, append(text, 0)) | |
| 264 | + | k, e := c.NewKeymapFD(int(f.Fd()), len(text)+1) | |
| 265 | + | if e != nil { | |
| 266 | + | t.Fatal(e) | |
| 275 | 267 | } | |
| 268 | + | t.Cleanup(func() { k.Close() }) | |
| 276 | 269 | s := state(t, k) | |
| 277 | 270 | var mask uint32 | |
| 278 | 271 | if tc.modifiers != "" { | |
| @@ -238,9 +238,6 @@ func TestLayoutsAndDifferential(t *testing.T) { | |||||
| 238 | // binding under test. Every case compiles through the Wayland FD path. | 238 | // binding under test. Every case compiles through the Wayland FD path. | ||
| 239 | func TestFDReferenceKeyEvents(t *testing.T) { | 239 | func TestFDReferenceKeyEvents(t *testing.T) { | ||
| 240 | c := live(t) | 240 | c := live(t) | ||
| 241 | - | if _, e := exec.LookPath("xkbcli"); e != nil { | |||
| 242 | - | t.Logf("xkbcli compile-keymap/how-to-type comparison skipped: %v", e) | |||
| 243 | - | } | |||
| 244 | for _, tc := range []struct { | 241 | for _, tc := range []struct { | ||
| 245 | layout, key, utf8, modifiers string | 242 | layout, key, utf8, modifiers string | ||
| 246 | evdev, group, sym uint32 | 243 | evdev, group, sym uint32 | ||
| @@ -256,23 +253,19 @@ func TestFDReferenceKeyEvents(t *testing.T) { | |||||
| 256 | {"us,fr", "a", "a", "", 16, 1, raw.XKB_KEY_a}, | 253 | {"us,fr", "a", "a", "", 16, 1, raw.XKB_KEY_a}, | ||
| 257 | } { | 254 | } { | ||
| 258 | t.Run(tc.layout+"/"+tc.key+"/"+tc.modifiers, func(t *testing.T) { | 255 | t.Run(tc.layout+"/"+tc.key+"/"+tc.modifiers, func(t *testing.T) { | ||
| 259 | - | // xkbcli independently compiles the text used by the Wayland FD path. | 256 | + | // Wayland-format keymaps pinned in testdata/keymaps were produced by |
| 260 | - | // Without it, still check the fixed reference table against rules. | 257 | + | // `xkbcli compile-keymap --output-format 1` (libxkbcommon 1.13.2), so |
| 261 | - | var k *Keymap | 258 | + | // the FD path is always exercised without optional tools. |
| 262 | - | if _, e := exec.LookPath("xkbcli"); e == nil { | 259 | + | text, e := os.ReadFile("testdata/keymaps/" + strings.ReplaceAll(tc.layout, ",", "_") + ".xkb") |
| 263 | - | text, e := exec.Command("xkbcli", "compile-keymap", "--layout", tc.layout, "--output-format", "1").Output() | 260 | + | if e != nil { |
| 264 | - | if e != nil { | 261 | + | t.Fatal(e) |
| 265 | - | t.Fatal(e) | 262 | + | } |
| 266 | - | } | 263 | + | f := keymapFile(t, append(text, 0)) |
| 267 | - | f := keymapFile(t, append(text, 0)) | 264 | + | k, e := c.NewKeymapFD(int(f.Fd()), len(text)+1) |
| 268 | - | k, e = c.NewKeymapFD(int(f.Fd()), len(text)+1) | 265 | + | if e != nil { |
| 269 | - | if e != nil { | 266 | + | t.Fatal(e) |
| 270 | - | t.Fatal(e) | |||
| 271 | - | } | |||
| 272 | - | t.Cleanup(func() { k.Close() }) | |||
| 273 | - | } else { | |||
| 274 | - | k = rules(t, c, tc.layout) | |||
| 275 | } | 267 | } | ||
| 268 | + | t.Cleanup(func() { k.Close() }) | |||
| 276 | s := state(t, k) | 269 | s := state(t, k) | ||
| 277 | var mask uint32 | 270 | var mask uint32 | ||
| 278 | if tc.modifiers != "" { | 271 | if tc.modifiers != "" { | ||