package widgetpreview import "testing" func validWidget() map[string]any { return map[string]any{ "id": "00000000-0000-0000-0000-000000000001", "type": "timeseries", "title": "CPU", "data": map[string]any{"sourceType": "semantic-metric", "metric": "host.cpu.utilization", "range": "1h", "aggregation": "avg", "limit": float64(100)}, "visualization": map[string]any{"decimals": float64(1), "min": float64(0), "max": float64(100), "thresholds": []any{}}, "behavior": map[string]any{"liveIntervalSeconds": float64(5)}, } } func TestValidateRejectsUnboundedOrRawConfiguration(t *testing.T) { widget := validWidget() widget["data"].(map[string]any)["metric"] = "promql:up" if fields := Validate(widget); fields["data.metric"] == "" { t.Fatal("expected raw query rejection") } widget["data"].(map[string]any)["limit"] = float64(1001) if fields := Validate(widget); fields["data.limit"] == "" { t.Fatal("expected limit rejection") } } func TestValidateRejectsInvertedThresholdRange(t *testing.T) { widget := validWidget() widget["visualization"].(map[string]any)["min"] = float64(90) widget["visualization"].(map[string]any)["max"] = float64(10) if fields := Validate(widget); fields["visualization.max"] == "" { t.Fatal("expected min/max rejection") } } func TestPreviewReturnsExplicitStatesAndLimits(t *testing.T) { widget := validWidget() widget["data"].(map[string]any)["limit"] = float64(1000) for _, state := range []string{"loading", "empty", "error", "stale"} { result, err := Preview(widget, state) if err != nil { t.Fatalf("state %s: %v", state, err) } if result.State != state || result.Limits.AppliedRows != 1000 || result.Limits.MaxPoints != MaxPoints { t.Fatalf("unexpected %s result: %+v", state, result) } } }