// Copyright (C) 2026 Danilo M. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License version 2 as // published by the Free Software Foundation. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. package notify import ( "bytes" "image/png" "testing" "github.com/godbus/dbus/v5" ) // rawVariant builds the (iiibiiay) struct the bus delivers for image-data. func rawVariant(w, h, stride int, alpha bool, ch int, data []byte) dbus.Variant { return dbus.MakeVariant([]interface{}{ int32(w), int32(h), int32(stride), alpha, int32(8), int32(ch), data, }) } func TestImageDataFromHints(t *testing.T) { // 2x1 RGBA: red, green. rgba := []byte{255, 0, 0, 255, 0, 255, 0, 255} cases := []struct { name string hints map[string]dbus.Variant wantW int want bool }{ {"image-data wins", map[string]dbus.Variant{ "image-data": rawVariant(2, 1, 8, true, 4, rgba), "image-path": dbus.MakeVariant("/tmp/x.png"), }, 2, true}, {"icon_data fallback", map[string]dbus.Variant{ "icon_data": rawVariant(2, 1, 8, true, 4, rgba), }, 2, true}, {"image_data alias", map[string]dbus.Variant{ "image_data": rawVariant(2, 1, 8, true, 4, rgba), }, 2, true}, {"absent", map[string]dbus.Variant{}, 0, false}, } for _, c := range cases { t.Run(c.name, func(t *testing.T) { got, ok := ImageDataFromHints(c.hints) if ok != c.want { t.Fatalf("ok = %v, want %v", ok, c.want) } if ok && got.Width != c.wantW { t.Fatalf("width = %d, want %d", got.Width, c.wantW) } }) } } func TestImagePathFromHints(t *testing.T) { got, ok := ImagePathFromHints(map[string]dbus.Variant{"image-path": dbus.MakeVariant("/tmp/shot.png")}) if !ok || got != "/tmp/shot.png" { t.Fatalf("got %q ok=%v", got, ok) } if _, ok := ImagePathFromHints(map[string]dbus.Variant{}); ok { t.Fatal("empty hints must not report a path") } } func TestRawImagePNG(t *testing.T) { // 2x1 RGBA on a rowstride wider than the data, to prove stride is honoured. r := &RawImage{Width: 2, Height: 1, RowStride: 12, HasAlpha: true, BitsPerSample: 8, Channels: 4, Data: []byte{255, 0, 0, 255, 0, 255, 0, 255, 9, 9, 9, 9}} data, err := r.PNG() if err != nil { t.Fatalf("PNG: %v", err) } img, err := png.Decode(bytes.NewReader(data)) if err != nil { t.Fatalf("decode: %v", err) } if img.Bounds().Dx() != 2 || img.Bounds().Dy() != 1 { t.Fatalf("bounds = %v", img.Bounds()) } r0, g0, b0, a0 := img.At(0, 0).RGBA() if r0>>8 != 255 || g0>>8 != 0 || b0>>8 != 0 || a0>>8 != 255 { t.Fatalf("pixel 0 = %d %d %d %d", r0>>8, g0>>8, b0>>8, a0>>8) } } func TestRawImagePNGRejectsBadData(t *testing.T) { if _, err := (&RawImage{Width: 0, Height: 1, Channels: 4, BitsPerSample: 8}).PNG(); err == nil { t.Fatal("zero width must error") } if _, err := (&RawImage{Width: 1, Height: 1, Channels: 2, BitsPerSample: 8}).PNG(); err == nil { t.Fatal("channels 2 must error") } }