feat: 初始版本 - ttychart-mcp 终端图表 MCP 服务
- 支持三种图表: 折线图、柱状图、散点图 - MCP 协议支持 (stdio + HTTP) - 完整的单元测试和集成测试 - Docker 支持 - Makefile 构建脚本
This commit is contained in:
284
tools/charts/line_test.go
Normal file
284
tools/charts/line_test.go
Normal file
@@ -0,0 +1,284 @@
|
||||
// Package charts 图表单元测试
|
||||
//
|
||||
// 对所有图表类型进行单元测试
|
||||
//
|
||||
// 作者: titor
|
||||
// 创建日期: 2026-04-15
|
||||
package charts
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
// TestLineChart_NewLineChart 测试创建折线图
|
||||
func TestLineChart_NewLineChart(t *testing.T) {
|
||||
// 测试正常创建
|
||||
chart := NewLineChart(50, 10)
|
||||
if chart == nil {
|
||||
t.Error("NewLineChart 返回 nil")
|
||||
}
|
||||
|
||||
// 测试零值创建
|
||||
chart0 := NewLineChart(0, 0)
|
||||
if chart0 == nil {
|
||||
t.Error("NewLineChart(0,0) 返回 nil")
|
||||
}
|
||||
}
|
||||
|
||||
// TestLineChart_SetData 测试设置数据
|
||||
func TestLineChart_SetData(t *testing.T) {
|
||||
chart := NewLineChart(0, 0)
|
||||
|
||||
// 测试设置数据
|
||||
data := []float64{1.0, 2.0, 3.0, 4.0, 5.0}
|
||||
chart.SetData(data)
|
||||
|
||||
// 验证数据设置正确
|
||||
if len(chart.Data) != len(data) {
|
||||
t.Errorf("数据长度不匹配: got %d, want %d", len(chart.Data), len(data))
|
||||
}
|
||||
|
||||
// 测试空数据
|
||||
chart.SetData(nil)
|
||||
if chart.Data != nil {
|
||||
t.Error("设置 nil 后数据不为 nil")
|
||||
}
|
||||
}
|
||||
|
||||
// TestLineChart_SetTitle 测试设置标题
|
||||
func TestLineChart_SetTitle(t *testing.T) {
|
||||
chart := NewLineChart(0, 0)
|
||||
|
||||
// 测试设置标题
|
||||
title := "测试折线图"
|
||||
chart.SetTitle(title)
|
||||
|
||||
// 验证标题设置正确
|
||||
if chart.Title != title {
|
||||
t.Errorf("标题不匹配: got %s, want %s", chart.Title, title)
|
||||
}
|
||||
}
|
||||
|
||||
// TestLineChart_SetLabels 测试设置标签
|
||||
func TestLineChart_SetLabels(t *testing.T) {
|
||||
chart := NewLineChart(0, 0)
|
||||
|
||||
// 测试设置标签
|
||||
labels := []string{"周一", "周二", "周三", "周四", "周五"}
|
||||
chart.SetLabels(labels)
|
||||
|
||||
// 验证标签设置正确
|
||||
if len(chart.Labels) != len(labels) {
|
||||
t.Errorf("标签长度不匹配: got %d, want %d", len(chart.Labels), len(labels))
|
||||
}
|
||||
}
|
||||
|
||||
// TestLineChart_Render 测试渲染折线图
|
||||
func TestLineChart_Render(t *testing.T) {
|
||||
// 测试空数据渲染
|
||||
chart := NewLineChart(30, 10)
|
||||
result := chart.Render()
|
||||
if result == "" {
|
||||
t.Error("空数据渲染结果为空")
|
||||
}
|
||||
|
||||
// 测试有数据渲染
|
||||
chart.SetData([]float64{10, 20, 15, 25, 30})
|
||||
result = chart.Render()
|
||||
if result == "" {
|
||||
t.Error("有数据渲染结果为空")
|
||||
}
|
||||
|
||||
// 测试有标题渲染
|
||||
chart.SetTitle("温度趋势")
|
||||
result = chart.Render()
|
||||
if result == "" {
|
||||
t.Error("有标题渲染结果为空")
|
||||
}
|
||||
|
||||
// 验证包含标题
|
||||
if len(result) < len("温度趋势") {
|
||||
t.Error("渲染结果长度异常")
|
||||
}
|
||||
}
|
||||
|
||||
// TestLineChart_findMinMax 测试查找最小最大值
|
||||
func TestLineChart_findMinMax(t *testing.T) {
|
||||
chart := NewLineChart(0, 0)
|
||||
|
||||
// 测试空数据
|
||||
minVal, maxVal := chart.findMinMax()
|
||||
if minVal != 0 || maxVal != 1 {
|
||||
t.Errorf("空数据范围错误: min=%f, max=%f", minVal, maxVal)
|
||||
}
|
||||
|
||||
// 测试单点数据
|
||||
chart.SetData([]float64{5.0})
|
||||
minVal, maxVal = chart.findMinMax()
|
||||
if minVal == maxVal {
|
||||
t.Error("单点数据 min 和 max 相同")
|
||||
}
|
||||
|
||||
// 测试多点数据
|
||||
chart.SetData([]float64{1.0, 5.0, 3.0, 8.0, 2.0})
|
||||
minVal, maxVal = chart.findMinMax()
|
||||
if minVal >= maxVal {
|
||||
t.Errorf("数据范围错误: min=%f, max=%f", minVal, maxVal)
|
||||
}
|
||||
}
|
||||
|
||||
// TestBarChart_NewBarChart 测试创建柱状图
|
||||
func TestBarChart_NewBarChart(t *testing.T) {
|
||||
// 测试垂直柱状图
|
||||
barV := NewBarChart(60, 10, false)
|
||||
if barV == nil {
|
||||
t.Error("NewBarChart 垂直返回 nil")
|
||||
}
|
||||
|
||||
// 测试水平柱状图
|
||||
barH := NewBarChart(60, 10, true)
|
||||
if barH == nil {
|
||||
t.Error("NewBarChart 水平返回 nil")
|
||||
}
|
||||
}
|
||||
|
||||
// TestBarChart_SetData 测试设置柱状图数据
|
||||
func TestBarChart_SetData(t *testing.T) {
|
||||
chart := NewBarChart(60, 10, false)
|
||||
|
||||
// 测试设置数据
|
||||
data := []BarDataItem{
|
||||
{Label: "苹果", Value: 100},
|
||||
{Label: "香蕉", Value: 80},
|
||||
{Label: "橙子", Value: 120},
|
||||
}
|
||||
chart.SetData(data)
|
||||
|
||||
// 验证数据设置正确
|
||||
if len(chart.Data) != len(data) {
|
||||
t.Errorf("数据长度不匹配: got %d, want %d", len(chart.Data), len(data))
|
||||
}
|
||||
|
||||
// 测试空数据
|
||||
chart.SetData(nil)
|
||||
if chart.Data != nil {
|
||||
t.Error("设置 nil 后数据不为 nil")
|
||||
}
|
||||
}
|
||||
|
||||
// TestBarChart_Render 测试渲染柱状图
|
||||
func TestBarChart_Render(t *testing.T) {
|
||||
// 测试空数据渲染
|
||||
chart := NewBarChart(60, 10, false)
|
||||
result := chart.Render()
|
||||
if result == "" {
|
||||
t.Error("空数据渲染结果为空")
|
||||
}
|
||||
|
||||
// 测试有数据渲染
|
||||
chart.SetData([]BarDataItem{
|
||||
{Label: "苹果", Value: 100},
|
||||
{Label: "香蕉", Value: 80},
|
||||
})
|
||||
result = chart.Render()
|
||||
if result == "" {
|
||||
t.Error("有数据渲染结果为空")
|
||||
}
|
||||
|
||||
// 测试有标题渲染
|
||||
chart.SetTitle("水果销量")
|
||||
result = chart.Render()
|
||||
if result == "" {
|
||||
t.Error("有标题渲染结果为空")
|
||||
}
|
||||
|
||||
// 测试水平柱状图
|
||||
chartH := NewBarChart(60, 10, true)
|
||||
chartH.SetData([]BarDataItem{
|
||||
{Label: "A", Value: 50},
|
||||
{Label: "B", Value: 30},
|
||||
})
|
||||
result = chartH.Render()
|
||||
if result == "" {
|
||||
t.Error("水平柱状图渲染结果为空")
|
||||
}
|
||||
}
|
||||
|
||||
// TestScatterChart_NewScatterChart 测试创建散点图
|
||||
func TestScatterChart_NewScatterChart(t *testing.T) {
|
||||
chart := NewScatterChart(50, 20)
|
||||
if chart == nil {
|
||||
t.Error("NewScatterChart 返回 nil")
|
||||
}
|
||||
}
|
||||
|
||||
// TestScatterChart_SetData 测试设置散点图数据
|
||||
func TestScatterChart_SetData(t *testing.T) {
|
||||
chart := NewScatterChart(50, 20)
|
||||
|
||||
// 测试设置数据
|
||||
data := []ScatterDataItem{
|
||||
{X: 1.0, Y: 5.0},
|
||||
{X: 2.0, Y: 8.0},
|
||||
{X: 3.0, Y: 3.0},
|
||||
}
|
||||
chart.SetData(data)
|
||||
|
||||
// 验证数据设置正确
|
||||
if len(chart.Data) != len(data) {
|
||||
t.Errorf("数据长度不匹配: got %d, want %d", len(chart.Data), len(data))
|
||||
}
|
||||
}
|
||||
|
||||
// TestScatterChart_Render 测试渲染散点图
|
||||
func TestScatterChart_Render(t *testing.T) {
|
||||
// 测试空数据渲染
|
||||
chart := NewScatterChart(50, 20)
|
||||
result := chart.Render()
|
||||
if result == "" {
|
||||
t.Error("空数据渲染结果为空")
|
||||
}
|
||||
|
||||
// 测试有数据渲染
|
||||
chart.SetData([]ScatterDataItem{
|
||||
{X: 1.0, Y: 5.0},
|
||||
{X: 2.0, Y: 8.0},
|
||||
{X: 3.0, Y: 3.0},
|
||||
})
|
||||
result = chart.Render()
|
||||
if result == "" {
|
||||
t.Error("有数据渲染结果为空")
|
||||
}
|
||||
|
||||
// 测试有标题渲染
|
||||
chart.SetTitle("成绩分布")
|
||||
result = chart.Render()
|
||||
if result == "" {
|
||||
t.Error("有标题渲染结果为空")
|
||||
}
|
||||
}
|
||||
|
||||
// TestScatterChart_findMinMax 测试散点图最小最大值
|
||||
func TestScatterChart_findMinMax(t *testing.T) {
|
||||
chart := NewScatterChart(50, 20)
|
||||
|
||||
// 测试空数据
|
||||
minX, maxX := chart.findMinMaxX()
|
||||
minY, maxY := chart.findMinMaxY()
|
||||
if minX != 0 || maxX != 1 || minY != 0 || maxY != 1 {
|
||||
t.Errorf("空数据范围错误")
|
||||
}
|
||||
|
||||
// 测试有数据
|
||||
chart.SetData([]ScatterDataItem{
|
||||
{X: 1.0, Y: 5.0},
|
||||
{X: 2.0, Y: 8.0},
|
||||
{X: 3.0, Y: 3.0},
|
||||
})
|
||||
minX, maxX = chart.findMinMaxX()
|
||||
minY, maxY = chart.findMinMaxY()
|
||||
|
||||
if minX >= maxX || minY >= maxY {
|
||||
t.Error("数<><E695B0><EFBFBD>范围错误")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user