Files
MujicaUI/candlestick_chart_test.go
T

151 lines
4.4 KiB
Go

package mujica
import (
"math"
"strings"
"testing"
"time"
"github.com/egoist/mygo/ui"
)
// sampleCandles is a deterministic random walk, hourly from 2026-01-01.
func sampleCandles(n int) []Candle {
out := make([]Candle, n)
price := 100.0
base := time.Date(2026, 1, 1, 0, 0, 0, 0, time.UTC)
for i := range out {
o := price
c := o + math.Sin(float64(i)*0.7)*1.5 + math.Cos(float64(i)*0.13)*0.8
hi, lo := max(o, c)+0.6+math.Abs(math.Sin(float64(i)))*0.5, min(o, c)-0.5-math.Abs(math.Cos(float64(i)))*0.4
out[i] = Candle{Time: base.Add(time.Duration(i) * time.Hour), Open: o, High: hi, Low: lo, Close: c, Volume: 1000 + float64(i%17)*130}
price = c
}
return out
}
func mktState0(r ChartResult) *mktState {
return *ui.Local(r.Element, "mujica.mkt", func() *mktState { return nil })
}
func TestCandlestickChartDrawsOnlyVisible(t *testing.T) {
candles := sampleCandles(100000)
var view MarketView
var res ChartResult
tt := ui.NewTester(func(c *ui.Context) {
Use(c, Settings{})
res = CandlestickChart(c, candles, &view, CandlestickOptions{Frame: ChartFrame{Label: "BTC"}})
}, 900, 400)
tt.Frame()
st := mktState0(res)
if st.drawn != 120 {
t.Fatalf("drew %d candles of 100000", st.drawn)
}
tt.Key(0, ui.KeyTab)
for range 40 {
tt.Key(0, ui.KeyMinus)
}
if st.drawn > 900/3 || view.Count > 900/3 {
t.Fatalf("zoomed out: drew %d, view %+v", st.drawn, view)
}
}
func TestCandlestickChartKeyboardPanZoomReadout(t *testing.T) {
candles := sampleCandles(500)
view := MarketView{Count: 50}
var res ChartResult
tt := ui.NewTester(func(c *ui.Context) {
Use(c, Settings{})
res = CandlestickChart(c, candles, &view, CandlestickOptions{Frame: ChartFrame{Label: "BTC"}})
}, 900, 400)
tt.Key(0, ui.KeyTab)
tt.Key(0, ui.KeyEnd)
if res.Point != 499 || !tt.HasText("2026-01-21 19:00") {
t.Fatalf("End: point %d texts %q", res.Point, tt.Texts())
}
tt.Key(ui.Shift, ui.KeyLeft)
if view.End != 495 || view.Count != 50 {
t.Fatalf("Shift+Left: %+v", view)
}
tt.Key(0, ui.KeyEqual)
if view.Count != 40 {
t.Fatalf("zoom in: %+v", view)
}
tt.Key(0, ui.KeyHome)
tt.Frame()
if f, _ := marketWindow(view, 500, 300); f != 0 {
t.Fatalf("Home did not bring the first candle into view: %+v", view)
}
found := false
for _, s := range tt.Texts() {
found = found || strings.Contains(s, "O 100.00") && strings.Contains(s, "Vol 1,000")
}
if !found {
t.Fatalf("readout %q", tt.Texts())
}
}
func TestCandlestickChartDragPansAndRejects(t *testing.T) {
candles := sampleCandles(300)
view := MarketView{Count: 100}
tt := ui.NewTester(func(c *ui.Context) {
Use(c, Settings{})
CandlestickChart(c, candles, &view, CandlestickOptions{Frame: ChartFrame{Label: "BTC"}}).Element.Width(860)
}, 900, 400)
tt.Frame()
tt.Press(400, 150)
tt.Move(560, 150) // about 20 candles of 8 DIPs
tt.Release(560, 150)
if view.End < 275 || view.End > 285 {
t.Fatalf("drag right shows older candles: %+v", view)
}
for name, f := range map[string]func(c *ui.Context){
"type": func(c *ui.Context) {
CandlestickChart(c, candles, &view, CandlestickOptions{Frame: ChartFrame{Label: "x"}, Type: 9})
},
"order": func(c *ui.Context) {
bad := []Candle{candles[1], candles[0]}
CandlestickChart(c, bad, &view, CandlestickOptions{Frame: ChartFrame{Label: "x"}})
},
"prices": func(c *ui.Context) {
bad := []Candle{{Time: candles[0].Time, Open: 5, High: 4, Low: 3, Close: 4}}
CandlestickChart(c, bad, &view, CandlestickOptions{Frame: ChartFrame{Label: "x"}})
},
} {
func() {
defer func() {
if recover() == nil {
t.Errorf("%s: no panic", name)
}
}()
ui.NewTester(func(c *ui.Context) { Use(c, Settings{}); f(c) }, 300, 200)
}()
}
}
func TestCandlestickChartTrendColors(t *testing.T) {
candles := sampleCandles(30)
view := MarketView{Count: 30}
var res ChartResult
tt := ui.NewTester(func(c *ui.Context) {
Use(c, Settings{Locale: ZhCN})
UseTrend(c, RedUp)
res = CandlestickChart(c, candles, &view, CandlestickOptions{Frame: ChartFrame{Label: "沪深300"}})
}, 600, 300)
tt.Key(0, ui.KeyTab)
tt.Key(0, ui.KeyRight)
if res.Point != 0 || !tt.HasText("开 100.00") {
t.Fatalf("zh readout %q", tt.Texts())
}
}
func TestCandlestickChartSnapshot(t *testing.T) {
candles := sampleCandles(80)
view := MarketView{Count: 60}
snapshot(t, "candlestick_chart", 640, 320, func(c *ui.Context) {
ui.Column(c).Padding(12).Children(func() {
CandlestickChart(c, candles, &view, CandlestickOptions{Frame: ChartFrame{Label: "BTC", Height: 260}})
})
})
}