Documentation
¶
Overview ¶
Package uitest provides test fixtures shared by this module's test suites: synthetic image files in every format the viewer reads, the temp files and URIs to hand them over by, and swap-in stubs for the OS-level seams (file chooser, image clipboard).
It exists because Go can't share unexported test helpers across packages, and the previous answer to that - copying `writeTempFile`/`encodeJPEG` into each package that needed them - doesn't scale to the per-feature package split this module is working through. Everything here is deliberately viewer-free: fixtures build bytes, files, and URIs, and know nothing about the app's own types.
What stays behind, in each package's own _test.go files, is anything that reads unexported state: the viewer's channel/WaitGroup wait helpers (waitUntilLoaded, settleToast, settleThumbs, ...) synchronize on private fields, and keeping them private is what stops those sync primitives from leaking into an exported API.
Test-only code in a non-test file is intentional (the same shape as the standard library's net/http/httptest): only _test.go files import this, so it never reaches a production binary.
Index ¶
- func ApproxEqual(a, b float32) bool
- func CaptureDateJPEG(t *testing.T, w, h int, raw string) []byte
- func EncodeAnimatedGIF(t *testing.T, w, h int, colors []color.Color, delays []int) []byte
- func EncodeGIF(t *testing.T, w, h int, c color.Color) []byte
- func EncodeJPEG(t *testing.T, w, h int, c color.Color) []byte
- func EncodePNG(t *testing.T, w, h int, c color.Color) []byte
- func EncodeRAWPreview(t *testing.T, p RAWPreview) []byte
- func GPSJPEG(t *testing.T, w, h int, lat, lon float64) []byte
- func LineArtGray(edge, seed int) *image.Gray
- func LineArtJPEGURI(t *testing.T, name string, seed int) fyne.URI
- func PatternedJPEGURI(t *testing.T, name string, seed int) fyne.URI
- func PatternedJPEGURISize(t *testing.T, name string, seed, w, h int) fyne.URI
- func SVGBytes(w, h int) []byte
- func StubChooser(t *testing.T, out []byte, err error)
- func StubClipboardCopy(t *testing.T, fn func(data []byte) error)
- func StubClipboardCopyFiles(t *testing.T, fn func(paths []string) error)
- func StubSaveChooser(t *testing.T, fn func(suggestedPath string) ([]byte, error))
- func StubTrashMove(t *testing.T, fn func(path string) error)
- func StubWallpaperSet(t *testing.T, fn func(path string) error)
- func TempDirJPEGURIs(t *testing.T, names ...string) []fyne.URI
- func TempGPSJPEGURI(t *testing.T, name string, w, h int, lat, lon float64) fyne.URI
- func TempJPEGURI(t *testing.T, name string, w, h int, c color.Color) fyne.URI
- func TempRAWURI(t *testing.T, name string, w, h int, c color.Color) fyne.URI
- func TempSVGURI(t *testing.T, name string, w, h int) fyne.URI
- func TruncatedPNGHeader(t *testing.T, width, height uint32) []byte
- func WriteTempFile(t *testing.T, name string, data []byte) string
- type FakeURI
- func (f FakeURI) Authority() string
- func (f FakeURI) Extension() string
- func (f FakeURI) Fragment() string
- func (f FakeURI) MimeType() string
- func (f FakeURI) Name() string
- func (f FakeURI) Path() string
- func (f FakeURI) Query() string
- func (f FakeURI) Scheme() string
- func (f FakeURI) String() string
- type RAWPreview
- type UIQueue
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func ApproxEqual ¶
ApproxEqual reports whether two float32s are within 0.01 of each other - the tolerance layout assertions need, since Fyne's sizing math accumulates rounding noise well below one canvas point.
func CaptureDateJPEG ¶
CaptureDateJPEG builds a minimal encoded JPEG carrying a single Exif DateTime tag (0x0132) set to raw ("YYYY:MM:DD HH:MM:SS") - just enough for imaging.CaptureDate, which the capture-date sort mode relies on, to read a timestamp back, without needing a real camera-shot fixture.
func EncodeAnimatedGIF ¶
EncodeAnimatedGIF builds a multi-frame GIF, one solid-color w x h frame per entry in colors, with the matching delay (in 1/100ths of a second, gif.GIF's native unit) from delays.
func EncodeJPEG ¶
EncodeJPEG returns a solid-color w x h JPEG.
func EncodeRAWPreview ¶ added in v0.2.0
func EncodeRAWPreview(t *testing.T, p RAWPreview) []byte
EncodeRAWPreview builds a little-endian TIFF whose only image is a JPEG stored via JPEGInterchangeFormat (0x0201) and Compression=6 - the shape camera RAW files use for their embedded preview. golang.org/x/image/tiff does not decode compression 6, so the file is not a displayable TIFF: imaging has to extract the JPEG to show anything.
func GPSJPEG ¶ added in v0.1.8
GPSJPEG builds a minimal encoded JPEG carrying an Exif GPS sub-IFD (the 0x8825 pointer in IFD0, then the latitude/longitude reference and degrees/minutes/seconds tags) for the given signed decimal degrees - enough for imaging.ReadMetadata to read a position back, and so for the EXIF window's map section to have somewhere to point.
func LineArtGray ¶ added in v0.2.3
LineArtGray draws thin dark strokes on a white background: a sketch, a screenshot, a logo, a scan - the common case where the subject occupies only a small fraction of the pixels. seed picks the stroke positions, so two seeds are two unrelated pictures.
This is the fixture shape that caught the duplicate-detection bug, where reducing such an image to the dHash grid by sampling a few pixels per cell landed on the background nearly every time and reported a near-empty hash. PatternedJPEGURI's dense gradient cannot show that: it has content in every cell.
func LineArtJPEGURI ¶ added in v0.2.3
LineArtJPEGURI writes a LineArtGray image to a temp file and returns its URI, mirroring PatternedJPEGURI.
func PatternedJPEGURI ¶ added in v0.2.3
PatternedJPEGURI writes a seeded 64×48 grayscale JPEG. Solid-color JPEGs all dHash to 0, so hide-duplicates tests need patterned pixels to tell "same shot" from "different shot".
func PatternedJPEGURISize ¶ added in v0.2.8
PatternedJPEGURISize is PatternedJPEGURI at an explicit size. Same seed at two sizes is the hide-duplicates fixture for "same shot, different resolution": coordinates are nearest-neighbour mapped onto the 64x48 pattern so a 192x144 file is an upscale of the 64x48 original, not a steeper pixel-space gradient (which dHash treats as a different picture).
func SVGBytes ¶ added in v0.1.7
SVGBytes builds a synthetic SVG with the given viewBox and a filled rect covering it, so a rasterization of it has visibly non-zero pixels.
func StubChooser ¶
StubChooser makes filepicker.Choose return out/err instead of opening the OS file browser.
func StubClipboardCopy ¶
StubClipboardCopy makes clipboard.CopyImage call fn instead of shelling out to the OS clipboard.
func StubClipboardCopyFiles ¶
StubClipboardCopyFiles makes clipboard.CopyFiles call fn instead of shelling out to the OS clipboard - the file-reference twin of StubClipboardCopy, for the grid's batch copy.
func StubSaveChooser ¶
StubSaveChooser makes filepicker.ChooseSave call fn instead of opening the OS save panel. It takes a function rather than a fixed result the way StubChooser does, since a caller usually wants to assert on the suggested path it was offered as well as control what comes back.
func StubTrashMove ¶
StubTrashMove makes trash.Move call fn instead of shelling out to the OS's real trash/recycle-bin mover.
func StubWallpaperSet ¶
StubWallpaperSet makes wallpaper.Set call fn instead of changing the machine's real desktop wallpaper - the one stub here whose absence a test run would leave visibly behind on the developer's own screen.
func TempDirJPEGURIs ¶ added in v0.2.8
TempDirJPEGURIs writes solid-color 8×8 white JPEGs named names into a single temp directory and returns their file URIs in the same order. TempJPEGURI cannot be used for sibling tests: each call uses its own t.TempDir(), so the files would not share a parent.
func TempGPSJPEGURI ¶ added in v0.1.8
TempGPSJPEGURI writes GPSJPEG's output to a temp file and returns its URI, mirroring TempJPEGURI.
func TempJPEGURI ¶
TempJPEGURI writes a solid-color w x h JPEG to a temp file and returns its file URI - the one-liner behind most of this suite's "give me an image to drop" setup.
func TempRAWURI ¶ added in v0.2.0
TempRAWURI writes EncodeRAWPreview to a temp file named name (typically with a RAW extension such as .cr2) and returns its file URI.
func TempSVGURI ¶ added in v0.1.7
TempSVGURI writes SVGBytes to a temp file and returns its URI, mirroring TempJPEGURI.
func TruncatedPNGHeader ¶
TruncatedPNGHeader builds a PNG file containing only the 8-byte signature and a single, correctly-checksummed IHDR chunk declaring width x height - no IDAT/IEND, so it's useless for a full decode but perfectly readable by image.DecodeConfig, which for a non-paletted color type stops as soon as IHDR has been parsed. Used to prove imaging.ReadAndProbe/LoadImage reject an invalid declared size from the header alone, without needing the rest of the file, and to exercise the viewer's end-to-end handling of that same rejection.
Types ¶
type FakeURI ¶
type FakeURI struct {
FileName, Ext, Mime string
}
FakeURI is a minimal fyne.URI so tests can control extension and MIME type independently, without touching the filesystem. Its Path is "/"+FileName under the file scheme: storage.Parent/List on an image FakeURI can walk the real filesystem root. Use TempJPEGURI (or a real file) whenever a directory listing might run.
type RAWPreview ¶ added in v0.2.0
type RAWPreview struct {
Width, Height int
Color color.Color
Orientation uint16 // 0 omits the tag
Make, Model string
DateTime string // Exif "YYYY:MM:DD HH:MM:SS"
}
RAWPreview is the options EncodeRAWPreview uses to wrap a JPEG in a TIFF-shaped camera-RAW container. Width/Height/Color build the embedded preview; the optional tags are written into IFD0 so ReadMetadata and orientation correction can see them the way they would on a real CR2/NEF.
type UIQueue ¶ added in v0.2.3
type UIQueue struct {
// contains filtered or unexported fields
}
UIQueue collects the callbacks a background goroutine hands over for the UI goroutine to run, and runs them on whoever calls Drain.
It exists because Fyne's test driver is not a marshaling point: its DoFromGoroutine calls the function inline on the calling goroutine, so a worker's fyne.Do body runs *on the worker*, concurrently with the test goroutine that spawned it. Under -race that is a genuine data race on every widget and every unsynchronized field the body touches - the same code being perfectly safe in the app, where the real driver queues the callback onto the one UI goroutine.
A feature that hands its completions to a UIQueue gets those production semantics back under test: the callback is deferred, and runs serialized on the goroutine that drains it - which for a test is the test goroutine itself, at a point of its own choosing.
The zero value is ready to use. Do is safe from any goroutine; Drain is for one goroutine at a time, the one the test is running on.
func (*UIQueue) Do ¶ added in v0.2.3
func (q *UIQueue) Do(f func())
Do queues f, and never runs it on the calling goroutine. A nil f queues fine and panics whoever eventually Drains it - the same way fyneQueue's Do(nil) panics inside the real driver, so this seam doesn't quietly swallow a caller bug the app wouldn't.
func (*UIQueue) Drain ¶ added in v0.2.3
Drain runs everything queued so far, in the order it was queued, on the calling goroutine, and reports whether it ran anything.
The lock is dropped before the callbacks run: a callback may queue more work, directly or by spawning a worker that does, and holding the lock across one would deadlock. Work queued during a Drain therefore lands in the *next* one, so a caller that needs quiescence loops until Drain reports false.
The batch is already detached from pending by the time the loop below runs it, so a callback that panics aborts every callback still queued behind it in that same batch - they are simply never reached, not lost to a corrupted pending slice.
func (*UIQueue) Len ¶ added in v0.2.3
Len is how many callbacks are waiting for a Drain. No current adopter's tests assert on it - internal/ui/grid's asserts on the drained effect instead - but it's here for whichever of the other packages with the same latent worker-races-the-test-goroutine exposure (deletion, slideshow, favorites, exifwin, spiral, toast) adopts this queue next, in case one of them wants to show a worker deferred its paint rather than running it.