package strategy import ( "github.com/shopspring/decimal" "testing" ) // --- SMA 的表格式驅動測試 --- func TestSMA(t *testing.T) { d10 := decimal.NewFromInt(10) d20 := decimal.NewFromInt(20) d30 := decimal.NewFromInt(30) d40 := decimal.NewFromInt(40) d50 := decimal.NewFromInt(50) // 定義 Push 過程中的檢查點結構 type pushCheck struct { wantSMA decimal.Decimal wantOK bool } testCases := []struct { name string n uint inputs []decimal.Decimal pushChecks []pushCheck // 驗證每一次 Push 的回傳值 wantFinalSMA decimal.Decimal // 驗證最後 GetSMA 的回傳值 wantFinalOK bool }{ { name: "SMA-5 未滿載", n: 5, inputs: []decimal.Decimal{d10, d20, d30}, pushChecks: []pushCheck{ {decimal.Zero, false}, {decimal.Zero, false}, {decimal.Zero, false}, }, wantFinalSMA: decimal.Zero, wantFinalOK: false, }, { name: "SMA-3 剛好滿載", n: 3, inputs: []decimal.Decimal{d10, d20, d30}, pushChecks: []pushCheck{ {decimal.Zero, false}, {decimal.Zero, false}, {decimal.NewFromInt(20), true}, // (10+20+30)/3 }, wantFinalSMA: decimal.NewFromInt(20), wantFinalOK: true, }, { name: "SMA-3 滾動計算", n: 3, inputs: []decimal.Decimal{d10, d20, d30, d40, d50}, pushChecks: []pushCheck{ {decimal.Zero, false}, {decimal.Zero, false}, {decimal.NewFromInt(20), true}, // (10+20+30)/3 {decimal.NewFromInt(30), true}, // (20+30+40)/3 {decimal.NewFromInt(40), true}, // (30+40+50)/3 }, wantFinalSMA: decimal.NewFromInt(40), wantFinalOK: true, }, { name: "SMA-1 邊界情況", n: 1, inputs: []decimal.Decimal{d10, d20, d30}, pushChecks: []pushCheck{ {d10, true}, {d20, true}, {d30, true}, }, wantFinalSMA: d30, wantFinalOK: true, }, { name: "SMA-0 無效情況", n: 0, inputs: []decimal.Decimal{d10, d20, d30}, pushChecks: []pushCheck{ {decimal.Zero, false}, {decimal.Zero, false}, {decimal.Zero, false}, }, wantFinalSMA: decimal.Zero, wantFinalOK: false, }, { name: "在空實例上呼叫 GetSMA", n: 5, inputs: []decimal.Decimal{}, pushChecks: []pushCheck{}, wantFinalSMA: decimal.Zero, wantFinalOK: false, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { sma := NewSMA(tc.n) // 驗證每一次 Push 的結果 for i, input := range tc.inputs { gotSMA, gotOK := sma.Push(input) // 確保 pushChecks 陣列不會索引越界 if i < len(tc.pushChecks) { check := tc.pushChecks[i] if gotOK != check.wantOK { t.Errorf("Push #%d 的 OK 狀態錯誤: got %v, want %v", i+1, gotOK, check.wantOK) } if !gotSMA.Equals(check.wantSMA) { t.Errorf("Push #%d 的 SMA 值錯誤: got %s, want %s", i+1, gotSMA.String(), check.wantSMA.String()) } } } // 在所有 Push 操作完成後,驗證最終 GetSMA 的結果 finalSMA, finalOK := sma.GetSMA() if finalOK != tc.wantFinalOK { t.Errorf("最終 GetSMA 的 OK 狀態錯誤: got %v, want %v", finalOK, tc.wantFinalOK) } if !finalSMA.Equals(tc.wantFinalSMA) { t.Errorf("最終 GetSMA 的 SMA 值錯誤: got %s, want %s", finalSMA.String(), tc.wantFinalSMA.String()) } }) } }