569 lines
16 KiB
Go
569 lines
16 KiB
Go
package ui
|
|
|
|
import (
|
|
"math"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"charm.land/lipgloss/v2"
|
|
)
|
|
|
|
const classicPeakTestGlyphs = "⎺⎻⎼⎽"
|
|
const classicPeakTestEpsilon = 1e-9
|
|
|
|
func withPanelWidth(t *testing.T, width int) {
|
|
t.Helper()
|
|
prevWidth := PanelWidth
|
|
PanelWidth = width
|
|
t.Cleanup(func() {
|
|
PanelWidth = prevWidth
|
|
})
|
|
}
|
|
|
|
func uniformBands(level float64) []float64 {
|
|
return uniformBandsN(DefaultSpectrumBands, level)
|
|
}
|
|
|
|
func uniformBandsN(count int, level float64) []float64 {
|
|
bands := make([]float64, count)
|
|
for i := range bands {
|
|
bands[i] = level
|
|
}
|
|
return bands
|
|
}
|
|
|
|
func repeatedClassicPeakSlice(width int, level float64) []float64 {
|
|
cols := classicPeakColsForWidth(width)
|
|
out := make([]float64, cols)
|
|
for i := range out {
|
|
out[i] = level
|
|
}
|
|
return out
|
|
}
|
|
|
|
func activateMode(t *testing.T, v *Visualizer, mode VisMode) visModeDriver {
|
|
t.Helper()
|
|
v.Mode = mode
|
|
driver := v.syncDriverMode()
|
|
if driver == nil {
|
|
t.Fatalf("syncDriverMode() returned nil for mode %v", mode)
|
|
}
|
|
return driver
|
|
}
|
|
|
|
func classicPeakDriverFor(t *testing.T, v *Visualizer) *classicPeakDriver {
|
|
t.Helper()
|
|
driver, ok := v.driverFor(VisClassicPeak).(*classicPeakDriver)
|
|
if !ok || driver == nil {
|
|
t.Fatal("driverFor(VisClassicPeak) did not return *classicPeakDriver")
|
|
}
|
|
return driver
|
|
}
|
|
|
|
func terrainDriverFor(t *testing.T, v *Visualizer) *terrainDriver {
|
|
t.Helper()
|
|
driver, ok := v.driverFor(VisTerrain).(*terrainDriver)
|
|
if !ok || driver == nil {
|
|
t.Fatal("driverFor(VisTerrain) did not return *terrainDriver")
|
|
}
|
|
return driver
|
|
}
|
|
|
|
func TestClassicPeakModeLookup(t *testing.T) {
|
|
got, ok := StringToVisModeExact("ClassicPeak")
|
|
if !ok || got != VisClassicPeak {
|
|
t.Fatalf("StringToVisModeExact(ClassicPeak) = (%v, %v), want (%v, true)", got, ok, VisClassicPeak)
|
|
}
|
|
|
|
v := NewVisualizer(44100)
|
|
v.Mode = VisClassicPeak
|
|
if got := v.ModeName(); got != "ClassicPeak" {
|
|
t.Fatalf("ModeName() = %q, want %q", got, "ClassicPeak")
|
|
}
|
|
}
|
|
|
|
func TestVisualizerFrameAdvancesOnTickNotRender(t *testing.T) {
|
|
v := NewVisualizer(44100)
|
|
|
|
v.Analyze(make([]float64, defaultFFTSize), spectrumAnalysisSpec(DefaultSpectrumBands))
|
|
if v.frame != 0 {
|
|
t.Fatalf("Analyze() advanced frame to %d, want 0 before tick", v.frame)
|
|
}
|
|
|
|
v.bands = uniformBands(0.5)
|
|
v.Render()
|
|
if v.frame != 0 {
|
|
t.Fatalf("Render() advanced frame to %d, want 0 before tick", v.frame)
|
|
}
|
|
|
|
v.Tick(VisTickContext{})
|
|
if v.frame != 1 {
|
|
t.Fatalf("Tick() advanced frame to %d, want 1", v.frame)
|
|
}
|
|
|
|
v.bands = uniformBands(0.5)
|
|
v.Render()
|
|
if v.frame != 1 {
|
|
t.Fatalf("Render() advanced frame to %d after tick, want 1", v.frame)
|
|
}
|
|
}
|
|
|
|
func TestClassicPeakLaunchAndSettle(t *testing.T) {
|
|
withPanelWidth(t, 8)
|
|
cols := classicPeakColsForWidth(PanelWidth)
|
|
|
|
v := NewVisualizer(44100)
|
|
activateMode(t, v, VisClassicPeak)
|
|
driver := classicPeakDriverFor(t, v)
|
|
v.bands = uniformBands(0.2)
|
|
driver.sync(v)
|
|
v.Render()
|
|
|
|
if len(driver.barPos) != cols {
|
|
t.Fatalf("initial bar count = %d, want %d", len(driver.barPos), cols)
|
|
}
|
|
if len(driver.peakPos) != cols {
|
|
t.Fatalf("initial cap count = %d, want %d", len(driver.peakPos), cols)
|
|
}
|
|
for i, pos := range driver.barPos {
|
|
if math.Abs(pos-0.2) > classicPeakTestEpsilon {
|
|
t.Fatalf("initial bar[%d] = %v, want 0.2", i, pos)
|
|
}
|
|
}
|
|
for i, pos := range driver.peakPos {
|
|
if math.Abs(pos-0.2) > classicPeakTestEpsilon {
|
|
t.Fatalf("initial cap[%d] = %v, want 0.2", i, pos)
|
|
}
|
|
if driver.peakVel[i] != 0 {
|
|
t.Fatalf("initial velocity[%d] = %v, want 0", i, driver.peakVel[i])
|
|
}
|
|
if driver.peakHold[i] != 0 {
|
|
t.Fatalf("initial hold[%d] = %v, want 0", i, driver.peakHold[i])
|
|
}
|
|
}
|
|
|
|
v.bands = uniformBands(0.8)
|
|
driver.sync(v)
|
|
for i, pos := range driver.barPos {
|
|
if math.Abs(pos-0.2) > classicPeakTestEpsilon {
|
|
t.Fatalf("bars snapped on sync[%d] = %v, want 0.2", i, pos)
|
|
}
|
|
}
|
|
for i, pos := range driver.peakPos {
|
|
if math.Abs(pos-0.8) > classicPeakTestEpsilon {
|
|
t.Fatalf("cap launch[%d] = %v, want 0.8", i, pos)
|
|
}
|
|
if driver.peakVel[i] <= 0 {
|
|
t.Fatalf("velocity on sync[%d] = %v, want > 0", i, driver.peakVel[i])
|
|
}
|
|
if driver.peakHold[i] != 0 {
|
|
t.Fatalf("hold on sync[%d] = %v, want 0", i, driver.peakHold[i])
|
|
}
|
|
}
|
|
|
|
now := time.Now()
|
|
driver.advance(v, now)
|
|
for i, pos := range driver.barPos {
|
|
if pos <= 0.2 || pos >= 0.8 {
|
|
t.Fatalf("animated bar[%d] = %v, want between 0.2 and 0.8", i, pos)
|
|
}
|
|
if driver.peakPos[i] <= 0.8 {
|
|
t.Fatalf("animated cap[%d] = %v, want > 0.8", i, driver.peakPos[i])
|
|
}
|
|
if driver.peakPos[i] <= pos {
|
|
t.Fatalf("animated cap[%d] = %v, want > bar %v", i, driver.peakPos[i], pos)
|
|
}
|
|
if driver.peakVel[i] <= 0 {
|
|
t.Fatalf("launch velocity[%d] = %v, want > 0", i, driver.peakVel[i])
|
|
}
|
|
}
|
|
|
|
v.bands = uniformBands(0.3)
|
|
driver.sync(v)
|
|
for i, pos := range driver.barPos {
|
|
if pos <= 0.3 {
|
|
t.Fatalf("settling bar[%d] = %v, want > 0.3", i, pos)
|
|
}
|
|
if driver.peakPos[i] <= pos {
|
|
t.Fatalf("settling cap[%d] = %v, want > bar %v", i, driver.peakPos[i], pos)
|
|
}
|
|
}
|
|
|
|
for step := 1; step <= 128 && driver.animating(v); step++ {
|
|
driver.advance(v, now.Add(time.Duration(step)*tickClassicPeak))
|
|
}
|
|
if driver.animating(v) {
|
|
t.Fatal("animating() = true after settle window, want false")
|
|
}
|
|
for i, pos := range driver.barPos {
|
|
if math.Abs(pos-0.3) > classicPeakVisibleEpsilon {
|
|
t.Fatalf("settled bar[%d] = %v, want about 0.3", i, pos)
|
|
}
|
|
}
|
|
for i, pos := range driver.peakPos {
|
|
if math.Abs(pos-0.3) > classicPeakVisibleEpsilon {
|
|
t.Fatalf("settled cap[%d] = %v, want about 0.3", i, pos)
|
|
}
|
|
if driver.peakVel[i] != 0 {
|
|
t.Fatalf("settled velocity[%d] = %v, want 0", i, driver.peakVel[i])
|
|
}
|
|
if driver.peakHold[i] != 0 {
|
|
t.Fatalf("settled hold[%d] = %v, want 0", i, driver.peakHold[i])
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestClassicPeakHangsBrieflyAtApex(t *testing.T) {
|
|
withPanelWidth(t, 8)
|
|
|
|
v := NewVisualizer(44100)
|
|
activateMode(t, v, VisClassicPeak)
|
|
driver := classicPeakDriverFor(t, v)
|
|
v.bands = uniformBands(0.2)
|
|
driver.sync(v)
|
|
v.Render()
|
|
|
|
v.bands = uniformBands(0.8)
|
|
driver.sync(v)
|
|
|
|
now := time.Now()
|
|
foundHold := false
|
|
for step := 1; step <= 32; step++ {
|
|
driver.advance(v, now.Add(time.Duration(step)*tickClassicPeak))
|
|
if driver.peakHold[0] <= 0 {
|
|
continue
|
|
}
|
|
foundHold = true
|
|
heldPos := driver.peakPos[0]
|
|
heldVel := driver.peakVel[0]
|
|
heldFor := driver.peakHold[0]
|
|
|
|
driver.advance(v, now.Add(time.Duration(step+1)*tickClassicPeak))
|
|
|
|
if driver.peakPos[0] != heldPos {
|
|
t.Fatalf("held cap moved: got %v, want %v", driver.peakPos[0], heldPos)
|
|
}
|
|
if driver.peakVel[0] != heldVel {
|
|
t.Fatalf("held cap velocity changed: got %v, want %v", driver.peakVel[0], heldVel)
|
|
}
|
|
if driver.peakHold[0] >= heldFor {
|
|
t.Fatalf("hold timer did not decrease: got %v, want < %v", driver.peakHold[0], heldFor)
|
|
}
|
|
break
|
|
}
|
|
|
|
if !foundHold {
|
|
t.Fatal("peakHold never activated")
|
|
}
|
|
}
|
|
|
|
func TestClassicPeakDoesNotRelaunchWhileAirborne(t *testing.T) {
|
|
withPanelWidth(t, 8)
|
|
|
|
v := NewVisualizer(44100)
|
|
activateMode(t, v, VisClassicPeak)
|
|
driver := classicPeakDriverFor(t, v)
|
|
v.bands = uniformBands(0.2)
|
|
driver.sync(v)
|
|
v.Render()
|
|
|
|
v.bands = uniformBands(0.8)
|
|
driver.sync(v)
|
|
launchPos := append([]float64(nil), driver.peakPos...)
|
|
launchVel := append([]float64(nil), driver.peakVel...)
|
|
|
|
v.bands = uniformBands(0.95)
|
|
driver.sync(v)
|
|
|
|
for i, pos := range driver.peakPos {
|
|
if pos != launchPos[i] {
|
|
t.Fatalf("cap relaunched in air[%d] = %v, want %v", i, pos, launchPos[i])
|
|
}
|
|
if driver.peakVel[i] != launchVel[i] {
|
|
t.Fatalf("velocity changed in air[%d] = %v, want %v", i, driver.peakVel[i], launchVel[i])
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestClassicPeakResetsOnModeSwitchAndWidthChange(t *testing.T) {
|
|
withPanelWidth(t, 6)
|
|
cols6 := classicPeakColsForWidth(PanelWidth)
|
|
|
|
v := NewVisualizer(44100)
|
|
activateMode(t, v, VisClassicPeak)
|
|
driver := classicPeakDriverFor(t, v)
|
|
v.bands = uniformBands(0.4)
|
|
driver.sync(v)
|
|
v.Render()
|
|
driver.barPos[1] = 0.7
|
|
driver.peakPos[1] = 0.9
|
|
driver.peakVel[1] = 1.2
|
|
|
|
activateMode(t, v, VisBars)
|
|
activateMode(t, v, VisClassicPeak)
|
|
driver.sync(v)
|
|
if len(driver.barPos) != cols6 {
|
|
t.Fatalf("reset bar len = %d, want %d", len(driver.barPos), cols6)
|
|
}
|
|
if len(driver.peakPos) != cols6 {
|
|
t.Fatalf("reset cap len = %d, want %d", len(driver.peakPos), cols6)
|
|
}
|
|
for i, pos := range driver.barPos {
|
|
if math.Abs(pos-0.4) > classicPeakTestEpsilon {
|
|
t.Fatalf("reset bar[%d] = %v, want 0.4", i, pos)
|
|
}
|
|
}
|
|
for i, pos := range driver.peakPos {
|
|
if math.Abs(pos-0.4) > classicPeakTestEpsilon {
|
|
t.Fatalf("reset cap[%d] = %v, want 0.4", i, pos)
|
|
}
|
|
if driver.peakVel[i] != 0 {
|
|
t.Fatalf("reset velocity[%d] = %v, want 0", i, driver.peakVel[i])
|
|
}
|
|
if driver.peakHold[i] != 0 {
|
|
t.Fatalf("reset hold[%d] = %v, want 0", i, driver.peakHold[i])
|
|
}
|
|
}
|
|
|
|
PanelWidth = 8
|
|
cols8 := classicPeakColsForWidth(PanelWidth)
|
|
driver.sync(v)
|
|
if len(driver.barPos) != cols8 {
|
|
t.Fatalf("resize bar len = %d, want %d", len(driver.barPos), cols8)
|
|
}
|
|
if len(driver.peakPos) != cols8 {
|
|
t.Fatalf("resize cap len = %d, want %d", len(driver.peakPos), cols8)
|
|
}
|
|
for i, pos := range driver.barPos {
|
|
if math.Abs(pos-0.4) > classicPeakTestEpsilon {
|
|
t.Fatalf("resize bar[%d] = %v, want 0.4", i, pos)
|
|
}
|
|
}
|
|
for i, pos := range driver.peakPos {
|
|
if math.Abs(pos-0.4) > classicPeakTestEpsilon {
|
|
t.Fatalf("resize cap[%d] = %v, want 0.4", i, pos)
|
|
}
|
|
if driver.peakVel[i] != 0 {
|
|
t.Fatalf("resize velocity[%d] = %v, want 0", i, driver.peakVel[i])
|
|
}
|
|
if driver.peakHold[i] != 0 {
|
|
t.Fatalf("resize hold[%d] = %v, want 0", i, driver.peakHold[i])
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestClassicPeakAnimatingWhenCapIsAboveBar(t *testing.T) {
|
|
withPanelWidth(t, 8)
|
|
|
|
v := NewVisualizer(44100)
|
|
activateMode(t, v, VisClassicPeak)
|
|
driver := classicPeakDriverFor(t, v)
|
|
v.bands = uniformBands(0.3)
|
|
driver.barPos = repeatedClassicPeakSlice(PanelWidth, 0.3)
|
|
driver.peakPos = repeatedClassicPeakSlice(PanelWidth, 0.5)
|
|
driver.peakVel = repeatedClassicPeakSlice(PanelWidth, 0)
|
|
|
|
if !driver.animating(v) {
|
|
t.Fatal("animating() = false, want true when caps are still above the bar")
|
|
}
|
|
}
|
|
|
|
func TestClassicPeakAnimatingWhenBarsAreSettling(t *testing.T) {
|
|
withPanelWidth(t, 8)
|
|
|
|
v := NewVisualizer(44100)
|
|
activateMode(t, v, VisClassicPeak)
|
|
driver := classicPeakDriverFor(t, v)
|
|
v.bands = uniformBands(0.7)
|
|
driver.barPos = repeatedClassicPeakSlice(PanelWidth, 0.5)
|
|
driver.peakPos = repeatedClassicPeakSlice(PanelWidth, 0.5)
|
|
driver.peakVel = repeatedClassicPeakSlice(PanelWidth, 0)
|
|
|
|
if !driver.animating(v) {
|
|
t.Fatal("animating() = false, want true while bars are still easing to target")
|
|
}
|
|
}
|
|
|
|
func TestClassicPeakRetainsDetailAtRightEdge(t *testing.T) {
|
|
v := NewVisualizer(44100)
|
|
activateMode(t, v, VisClassicPeak)
|
|
driver := classicPeakDriverFor(t, v)
|
|
|
|
bands := make([]float64, classicPeakSpectrumBands)
|
|
copy(bands[len(bands)-6:], []float64{0.55, 0.46, 0.37, 0.28, 0.19, 0.1})
|
|
v.bands = bands
|
|
|
|
levels := driver.levels(v)
|
|
if len(levels) < 4 {
|
|
t.Fatalf("levels len = %d, want at least 4", len(levels))
|
|
}
|
|
|
|
foundStep := false
|
|
for i := len(levels) - 4; i < len(levels)-1; i++ {
|
|
if math.Abs(levels[i]-levels[i+1]) > 0.01 {
|
|
foundStep = true
|
|
break
|
|
}
|
|
}
|
|
if !foundStep {
|
|
t.Fatalf("right edge flattened unexpectedly: tail=%v", levels[len(levels)-4:])
|
|
}
|
|
}
|
|
|
|
func TestClassicPeakRenderHidesLandedCaps(t *testing.T) {
|
|
withPanelWidth(t, 8)
|
|
|
|
v := NewVisualizer(44100)
|
|
activateMode(t, v, VisClassicPeak)
|
|
v.Rows = 5
|
|
v.bands = uniformBands(0.6)
|
|
|
|
out := v.Render()
|
|
if strings.ContainsAny(out, classicPeakTestGlyphs) {
|
|
t.Fatalf("Render() showed a cap even though peaks were seeded at the bar height: %q", out)
|
|
}
|
|
}
|
|
|
|
func TestClassicPeakRenderShowsAttachedCapWhileSettling(t *testing.T) {
|
|
withPanelWidth(t, 8)
|
|
|
|
v := NewVisualizer(44100)
|
|
activateMode(t, v, VisClassicPeak)
|
|
driver := classicPeakDriverFor(t, v)
|
|
v.Rows = 5
|
|
v.bands = uniformBands(0.61)
|
|
driver.barPos = repeatedClassicPeakSlice(PanelWidth, 0.61)
|
|
driver.peakPos = repeatedClassicPeakSlice(PanelWidth, 0.68)
|
|
driver.peakVel = repeatedClassicPeakSlice(PanelWidth, 0)
|
|
|
|
out := v.Render()
|
|
if !strings.ContainsAny(out, classicPeakTestGlyphs) {
|
|
t.Fatalf("Render() did not show an attached settling cap: %q", out)
|
|
}
|
|
}
|
|
|
|
func TestClassicPeakPauseFreezesStateAndClearsAnimationClock(t *testing.T) {
|
|
withPanelWidth(t, 8)
|
|
|
|
v := NewVisualizer(44100)
|
|
activateMode(t, v, VisClassicPeak)
|
|
driver := classicPeakDriverFor(t, v)
|
|
v.Rows = 5
|
|
v.bands = uniformBands(0.6)
|
|
driver.barPos = repeatedClassicPeakSlice(PanelWidth, 0.6)
|
|
driver.peakPos = repeatedClassicPeakSlice(PanelWidth, 0.82)
|
|
driver.peakVel = repeatedClassicPeakSlice(PanelWidth, 1.1)
|
|
driver.peakHold = repeatedClassicPeakSlice(PanelWidth, classicPeakApexHold)
|
|
|
|
snapshotPeak := append([]float64(nil), driver.peakPos...)
|
|
snapshotVel := append([]float64(nil), driver.peakVel...)
|
|
snapshotHold := append([]float64(nil), driver.peakHold...)
|
|
|
|
driver.lastTick = time.Now()
|
|
v.Tick(VisTickContext{Now: time.Now(), Paused: true})
|
|
|
|
for i := range driver.peakPos {
|
|
if driver.peakPos[i] != snapshotPeak[i] {
|
|
t.Fatalf("paused cap[%d] = %v, want frozen %v", i, driver.peakPos[i], snapshotPeak[i])
|
|
}
|
|
if driver.peakVel[i] != snapshotVel[i] {
|
|
t.Fatalf("paused velocity[%d] = %v, want frozen %v", i, driver.peakVel[i], snapshotVel[i])
|
|
}
|
|
if driver.peakHold[i] != snapshotHold[i] {
|
|
t.Fatalf("paused hold[%d] = %v, want frozen %v", i, driver.peakHold[i], snapshotHold[i])
|
|
}
|
|
}
|
|
if !driver.animating(v) {
|
|
t.Fatal("animating() = false, want true while caps still airborne")
|
|
}
|
|
if got := v.TickInterval(VisTickContext{Paused: true}); got != TickSlow {
|
|
t.Fatalf("TickInterval(paused) = %v, want %v", got, TickSlow)
|
|
}
|
|
}
|
|
|
|
func TestClassicPeakOverlayFreezesStateAndClearsAnimationClock(t *testing.T) {
|
|
withPanelWidth(t, 8)
|
|
|
|
v := NewVisualizer(44100)
|
|
activateMode(t, v, VisClassicPeak)
|
|
driver := classicPeakDriverFor(t, v)
|
|
v.Rows = 5
|
|
v.bands = uniformBands(0.6)
|
|
driver.barPos = repeatedClassicPeakSlice(PanelWidth, 0.6)
|
|
driver.peakPos = repeatedClassicPeakSlice(PanelWidth, 0.82)
|
|
driver.peakVel = repeatedClassicPeakSlice(PanelWidth, 1.1)
|
|
driver.peakHold = repeatedClassicPeakSlice(PanelWidth, classicPeakApexHold)
|
|
|
|
snapshotPeak := append([]float64(nil), driver.peakPos...)
|
|
snapshotVel := append([]float64(nil), driver.peakVel...)
|
|
snapshotHold := append([]float64(nil), driver.peakHold...)
|
|
|
|
driver.lastTick = time.Now()
|
|
driver.Tick(v, VisTickContext{Now: time.Now(), OverlayActive: true})
|
|
|
|
if !driver.lastTick.IsZero() {
|
|
t.Fatalf("lastTick after overlay = %v, want zero", driver.lastTick)
|
|
}
|
|
for i := range driver.peakPos {
|
|
if driver.peakPos[i] != snapshotPeak[i] {
|
|
t.Fatalf("overlay cap[%d] = %v, want frozen %v", i, driver.peakPos[i], snapshotPeak[i])
|
|
}
|
|
if driver.peakVel[i] != snapshotVel[i] {
|
|
t.Fatalf("overlay velocity[%d] = %v, want frozen %v", i, driver.peakVel[i], snapshotVel[i])
|
|
}
|
|
if driver.peakHold[i] != snapshotHold[i] {
|
|
t.Fatalf("overlay hold[%d] = %v, want frozen %v", i, driver.peakHold[i], snapshotHold[i])
|
|
}
|
|
}
|
|
if !driver.animating(v) {
|
|
t.Fatal("animating() = false, want true while overlay hides airborne caps")
|
|
}
|
|
if got := v.TickInterval(VisTickContext{OverlayActive: true}); got != TickSlow {
|
|
t.Fatalf("TickInterval(overlay) = %v, want %v", got, TickSlow)
|
|
}
|
|
}
|
|
|
|
func TestClassicPeakRenderFillsEvenWidthPanels(t *testing.T) {
|
|
withPanelWidth(t, 8)
|
|
|
|
v := NewVisualizer(44100)
|
|
activateMode(t, v, VisClassicPeak)
|
|
v.Rows = 5
|
|
v.bands = uniformBands(0.6)
|
|
|
|
out := v.Render()
|
|
for line := range strings.SplitSeq(out, "\n") {
|
|
if got := lipgloss.Width(line); got != PanelWidth {
|
|
t.Fatalf("Render() line width = %d, want %d for even panel width: %q", got, PanelWidth, line)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestClassicPeakEvenWidthKeepsBarsSeparated(t *testing.T) {
|
|
withPanelWidth(t, 8)
|
|
|
|
v := NewVisualizer(44100)
|
|
activateMode(t, v, VisClassicPeak)
|
|
v.Rows = 5
|
|
v.bands = uniformBands(0.6)
|
|
|
|
out := strings.Split(v.Render(), "\n")
|
|
if len(out) == 0 {
|
|
t.Fatalf("Render() returned too few rows: %q", out)
|
|
}
|
|
found := false
|
|
for _, line := range out {
|
|
if strings.Contains(line, "█") {
|
|
if strings.Contains(line, "███") {
|
|
t.Fatalf("Render() merged adjacent bars on even widths: %q", line)
|
|
}
|
|
found = true
|
|
break
|
|
}
|
|
}
|
|
if !found {
|
|
t.Fatalf("Render() did not render any bar rows: %q", out)
|
|
}
|
|
}
|