Skip to content

Commit

Permalink
Test and visualize frame operations
Browse files Browse the repository at this point in the history
Extend the edwoodtest mock devdraw to support emitting HTML/SVG files
that visualize the requested draw operations. Record these
visualizations from the frame tests. Use validated visualizations as
test baselines.
  • Loading branch information
rjkroege committed Sep 19, 2022
1 parent 2160d47 commit b07f92f
Show file tree
Hide file tree
Showing 44 changed files with 5,079 additions and 188 deletions.
3 changes: 2 additions & 1 deletion acme_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package main
import (
"context"
"fmt"
"image"
"os/exec"
"reflect"
"testing"
Expand Down Expand Up @@ -212,7 +213,7 @@ func startMockWaitthread(ctx context.Context) (done <-chan struct{}) {
global.cedit = make(chan int)
warnings = nil
global.row = Row{
display: edwoodtest.NewDisplay(),
display: edwoodtest.NewDisplay(image.Rectangle{}),
tag: Text{
file: file.MakeObservableEditableBuffer("", nil),
},
Expand Down
74 changes: 70 additions & 4 deletions edwoodtest/draw.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"errors"
"fmt"
"image"
"io"
"os"
"path/filepath"
"strings"
Expand All @@ -26,22 +27,46 @@ const (
type GettableDrawOps interface {
DrawOps() []string
Clear()

// SVGDrawOps writes the accumulated SVG format drawops to w where rect
// is the area of interest for the drawops.
SVGDrawOps(w io.Writer) error
}

// mockDisplay implements draw.Display.
type mockDisplay struct {
snarfbuf []byte
mu sync.Mutex
drawops []string

// TODO(rjk): This is essentially the same as drawops above. Except that
// I have pruned the drawops array at various points. And that would mean
// that it's not the same length as svgdrawops. This would be
// unfortunate. So save extra stuff. Later, I can merge this and clean it
// up once I have finished implementing the validation of the saved
// testdata SVG out.
annotations []string
svgdrawops []string
screenimage draw.Image

// roi is the rectangle of interest.
rectofi image.Rectangle
}

// NewDisplay returns a mock draw.Display.
func NewDisplay() draw.Display {
return &mockDisplay{}
// NewDisplay returns a mock draw.Display where visulizations of the output are w.r.t. rectangle rectofi.
// Set rectofi to control SVG output.
func NewDisplay(rectofi image.Rectangle) draw.Display {
md := &mockDisplay{
rectofi: rectofi,
}
md.screenimage = newimageimpl(md, "screen-800x600", image.Rect(0, 0, 800, 600))
md.svgdrawops = append(md.svgdrawops, boundingboxsvg(0, rectofi))
md.annotations = append(md.annotations, fmt.Sprintf("target rect %v", rectofi))
return md
}

func (d *mockDisplay) ScreenImage() draw.Image {
return newimageimpl(d, "screen-800x600", image.Rect(0, 0, 800, 600))
return d.screenimage
}

func (d *mockDisplay) White() draw.Image { return newimageimpl(d, "white", image.Rectangle{}) }
Expand Down Expand Up @@ -113,6 +138,10 @@ func (d *mockDisplay) SetCursor(c *draw.Cursor) error { return nil }
func (d *mockDisplay) DrawOps() []string { return d.drawops }
func (d *mockDisplay) Clear() { d.drawops = nil }

func (d *mockDisplay) SVGDrawOps(w io.Writer) error {
return singlesvgfile(w, d.svgdrawops, d.annotations, d.rectofi)
}

var _ = draw.Image((*mockImage)(nil))

// mockImage implements draw.Image.
Expand Down Expand Up @@ -211,10 +240,35 @@ func (i *mockImage) Draw(r image.Rectangle, src, mask draw.Image, p1 image.Point
sr, rectochars(sr),
r, rectochars(r),
)

// TODO(rjk): If this is right, fold it out and make an improved case statement.
if i.d.screenimage == i {
// TODO(rjk): Why am I failing to filter out the unnecessary draws?
// I'm getting a bunch of fills that are setting up colour?
i.d.svgdrawops = append(i.d.svgdrawops, blitsvg(
len(i.d.svgdrawops),
sr,
r.Min,
blitspace+i.d.rectofi.Dx(),
))
i.d.annotations = append(i.d.annotations, op)
}
case src != nil && i.r.Dx() > 0 && i.r.Dy() > 0 && maskname == srcname && src.R().Dx() == 0 && src.R().Dy() == 0:
op = fmt.Sprintf("fill %v %s",
r, rectochars(r),
)

// TODO(rjk): If this is right, fold it out and make an improved case statement.
if i.d.screenimage == i {
// TODO(rjk): Why am I failing to filter out the unnecessary draws?
// I'm getting a bunch of fills that are setting up colour?
i.d.svgdrawops = append(i.d.svgdrawops, fillsvg(
len(i.d.svgdrawops),
r,
i.d.rectofi,
))
i.d.annotations = append(i.d.annotations, op)
}
}
i.d.drawops = append(i.d.drawops, op)
}
Expand Down Expand Up @@ -250,6 +304,18 @@ func (i *mockImage) Bytes(pt image.Point, src draw.Image, sp image.Point, f draw
)
i.d.drawops = append(i.d.drawops, op)

// TODO(rjk): Remove this duplication when I've switched to always using
// the SVG path for baselines and such.
shortop := fmt.Sprintf("string %q atpoint: %v %s fill: %s",
string(b),
pt,
pointochars(pt),
srcname,
)

i.d.svgdrawops = append(i.d.svgdrawops, bytessvg(len(i.d.svgdrawops), pt, b))
i.d.annotations = append(i.d.annotations, shortop)

// TODO(rjk): This assumes fixed width. Consider generalizing.
return pt.Add(image.Pt(f.BytesWidth(b), 0))
}
Expand Down
Loading

0 comments on commit b07f92f

Please sign in to comment.