200 lines
5.6 KiB
Go
200 lines
5.6 KiB
Go
package world
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
// rendererTestEnv groups the common mutable inputs used by renderer tests.
|
|
// The environment stores independent horizontal and vertical margins because
|
|
// the expanded canvas geometry is derived separately on each axis.
|
|
type rendererTestEnv struct {
|
|
world *World
|
|
drawer *fakePrimitiveDrawer
|
|
|
|
// Viewport origin and size in canvas pixel coordinates.
|
|
viewportX int
|
|
viewportY int
|
|
viewportW int
|
|
viewportH int
|
|
|
|
// Independent margins around the viewport in canvas pixels.
|
|
marginXPx int
|
|
marginYPx int
|
|
|
|
// Final expanded canvas size in pixels.
|
|
// In the default setup:
|
|
// canvasW = viewportW + 2*marginXPx
|
|
// canvasH = viewportH + 2*marginYPx
|
|
canvasW int
|
|
canvasH int
|
|
|
|
// Camera center in fixed-point world coordinates.
|
|
cameraX int
|
|
cameraY int
|
|
|
|
// Camera zoom in fixed-point representation, if needed by renderer internals.
|
|
zoomFp int
|
|
}
|
|
|
|
// newRendererTestEnv returns a baseline renderer test environment.
|
|
// The default margins are derived independently from viewport width and height.
|
|
func newRendererTestEnv() *rendererTestEnv {
|
|
viewportW := 100
|
|
viewportH := 80
|
|
|
|
marginXPx := viewportW / 4
|
|
marginYPx := viewportH / 4
|
|
|
|
return &rendererTestEnv{
|
|
world: NewWorld(10, 10),
|
|
drawer: &fakePrimitiveDrawer{},
|
|
viewportX: marginXPx,
|
|
viewportY: marginYPx,
|
|
viewportW: viewportW,
|
|
viewportH: viewportH,
|
|
marginXPx: marginXPx,
|
|
marginYPx: marginYPx,
|
|
canvasW: viewportW + 2*marginXPx,
|
|
canvasH: viewportH + 2*marginYPx,
|
|
cameraX: 5 * SCALE,
|
|
cameraY: 5 * SCALE,
|
|
zoomFp: SCALE,
|
|
}
|
|
}
|
|
|
|
// setViewport resets viewport-dependent fields and recomputes margins
|
|
// using the default test formula:
|
|
//
|
|
// marginXPx = viewportW / 4
|
|
// marginYPx = viewportH / 4
|
|
func (env *rendererTestEnv) setViewport(viewportW, viewportH int) {
|
|
env.viewportW = viewportW
|
|
env.viewportH = viewportH
|
|
|
|
env.marginXPx = viewportW / 4
|
|
env.marginYPx = viewportH / 4
|
|
|
|
env.viewportX = env.marginXPx
|
|
env.viewportY = env.marginYPx
|
|
|
|
env.canvasW = env.viewportW + 2*env.marginXPx
|
|
env.canvasH = env.viewportH + 2*env.marginYPx
|
|
}
|
|
|
|
// setViewportAndMargins overrides viewport and margins explicitly.
|
|
// This is useful for edge cases where the expanded canvas geometry
|
|
// must be controlled exactly.
|
|
func (env *rendererTestEnv) setViewportAndMargins(viewportW, viewportH, marginXPx, marginYPx int) {
|
|
env.viewportW = viewportW
|
|
env.viewportH = viewportH
|
|
|
|
env.marginXPx = marginXPx
|
|
env.marginYPx = marginYPx
|
|
|
|
env.viewportX = env.marginXPx
|
|
env.viewportY = env.marginYPx
|
|
|
|
env.canvasW = env.viewportW + 2*env.marginXPx
|
|
env.canvasH = env.viewportH + 2*env.marginYPx
|
|
}
|
|
|
|
// viewportRect returns the viewport rectangle in canvas pixel coordinates.
|
|
func (env *rendererTestEnv) viewportRect() (x, y, w, h float64) {
|
|
return float64(env.viewportX), float64(env.viewportY), float64(env.viewportW), float64(env.viewportH)
|
|
}
|
|
|
|
// canvasRect returns the full expanded canvas rectangle in canvas pixel coordinates.
|
|
func (env *rendererTestEnv) canvasRect() (x, y, w, h float64) {
|
|
return 0, 0, float64(env.canvasW), float64(env.canvasH)
|
|
}
|
|
|
|
// worldMustAddPoint adds a point to the test world and fails the test on error.
|
|
func worldMustAddPoint(t *testing.T, w *World, x, y float64) {
|
|
t.Helper()
|
|
|
|
_, err := w.AddPoint(x, y)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
// worldMustAddCircle adds a circle to the test world and fails the test on error.
|
|
func worldMustAddCircle(t *testing.T, w *World, x, y, r float64) {
|
|
t.Helper()
|
|
|
|
_, err := w.AddCircle(x, y, r)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
// worldMustAddLine adds a line to the test world and fails the test on error.
|
|
func worldMustAddLine(t *testing.T, w *World, x1, y1, x2, y2 float64) {
|
|
t.Helper()
|
|
|
|
_, err := w.AddLine(x1, y1, x2, y2)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
// requireNoDrawerCommands asserts that the renderer produced no drawing commands.
|
|
func requireNoDrawerCommands(t *testing.T, d *fakePrimitiveDrawer) {
|
|
t.Helper()
|
|
|
|
require.Empty(t, d.Commands())
|
|
}
|
|
|
|
// requireStrokeCommandAt returns a command and asserts that it is Stroke.
|
|
func requireStrokeCommandAt(t *testing.T, d *fakePrimitiveDrawer, index int) fakeDrawerCommand {
|
|
t.Helper()
|
|
|
|
cmd := requireDrawerCommandAt(t, d, index)
|
|
requireCommandName(t, cmd, "Stroke")
|
|
return cmd
|
|
}
|
|
|
|
// requireFillCommandAt returns a command and asserts that it is Fill.
|
|
func requireFillCommandAt(t *testing.T, d *fakePrimitiveDrawer, index int) fakeDrawerCommand {
|
|
t.Helper()
|
|
|
|
cmd := requireDrawerCommandAt(t, d, index)
|
|
requireCommandName(t, cmd, "Fill")
|
|
return cmd
|
|
}
|
|
|
|
// requireAddPointCommandAt returns a command and asserts that it is AddPoint.
|
|
func requireAddPointCommandAt(t *testing.T, d *fakePrimitiveDrawer, index int) fakeDrawerCommand {
|
|
t.Helper()
|
|
|
|
cmd := requireDrawerCommandAt(t, d, index)
|
|
requireCommandName(t, cmd, "AddPoint")
|
|
return cmd
|
|
}
|
|
|
|
// requireAddLineCommandAt returns a command and asserts that it is AddLine.
|
|
func requireAddLineCommandAt(t *testing.T, d *fakePrimitiveDrawer, index int) fakeDrawerCommand {
|
|
t.Helper()
|
|
|
|
cmd := requireDrawerCommandAt(t, d, index)
|
|
requireCommandName(t, cmd, "AddLine")
|
|
return cmd
|
|
}
|
|
|
|
// requireAddCircleCommandAt returns a command and asserts that it is AddCircle.
|
|
func requireAddCircleCommandAt(t *testing.T, d *fakePrimitiveDrawer, index int) fakeDrawerCommand {
|
|
t.Helper()
|
|
|
|
cmd := requireDrawerCommandAt(t, d, index)
|
|
requireCommandName(t, cmd, "AddCircle")
|
|
return cmd
|
|
}
|
|
|
|
// requireSingleClipRectOnCommand asserts that the command was issued under exactly one clip rect.
|
|
func requireSingleClipRectOnCommand(t *testing.T, cmd fakeDrawerCommand, x, y, w, h float64) {
|
|
t.Helper()
|
|
|
|
requireCommandClipRects(t, cmd, fakeClipRect{
|
|
X: x,
|
|
Y: y,
|
|
W: w,
|
|
H: h,
|
|
})
|
|
}
|