Files
wehub-resource-sync a06f331eb8
CI / benchmark (push) Has been skipped
install-script / posix-syntax (push) Successful in 6m1s
CI / build-onnx (push) Failing after 6m43s
init-smoke / dry-run (push) Failing after 15m57s
security / govulncheck (push) Has been cancelled
security / trivy-fs (push) Has been cancelled
CI / test (1.26, ubuntu-latest) (push) Has been cancelled
Scorecard supply-chain security / Scorecard analysis (push) Has been cancelled
CI / test (1.26, macos-latest) (push) Has been cancelled
CI / build-windows (push) Has been cancelled
CI / lint (push) Has been cancelled
install-script / powershell-syntax (push) Has been cancelled
install-script / install (macos-14) (push) Has been cancelled
install-script / install (ubuntu-latest) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:33:42 +08:00

138 lines
4.1 KiB
Go

package main
import (
"bytes"
"encoding/json"
"strings"
"testing"
"github.com/stretchr/testify/require"
)
// capturedFlow records the (repo, tool, args) a dataflow verb lowered to.
type capturedFlow struct {
repo string
tool string
args map[string]any
}
// runDataflow drives the real command tree for one dataflow verb (flow/taint),
// stubbing the shared daemon seam. Returns the captured call, the buffer, and
// any error.
func runDataflow(t *testing.T, verb string, argv ...string) (*capturedFlow, *bytes.Buffer, error) {
t.Helper()
resetFlowFlags()
orig := flowDaemonTool
t.Cleanup(func() { flowDaemonTool = orig })
var cap *capturedFlow
flowDaemonTool = func(repo, tool string, args map[string]any) (json.RawMessage, error) {
cap = &capturedFlow{repo: repo, tool: tool, args: args}
return json.RawMessage(`{"status":"ok"}`), nil
}
buf := &bytes.Buffer{}
rootCmd.SetOut(buf)
rootCmd.SetErr(buf)
rootCmd.SetIn(strings.NewReader(""))
rootCmd.SetArgs(append([]string{verb}, argv...))
err := rootCmd.Execute()
return cap, buf, err
}
func resetFlowFlags() {
resetCobraFlags(flowCmd)
resetCobraFlags(taintCmd)
flowIndex = "."
flowFrom, flowTo = "", ""
flowMaxDepth, flowMaxPaths = 0, 0
flowMinTier, flowFormat = "", "json"
taintIndex = "."
taintSource, taintSink = "", ""
taintMaxDepth, taintLimit = 0, 0
taintMinTier, taintFormat = "", "json"
}
// --- flow (flow_between) ----------------------------------------------------
func TestFlow_Lowers(t *testing.T) {
cap, _, err := runDataflow(t, "flow", "--from", "A", "--to", "B")
require.NoError(t, err)
require.NotNil(t, cap)
require.Equal(t, "flow_between", cap.tool)
require.Equal(t, "A", cap.args["source_id"])
require.Equal(t, "B", cap.args["sink_id"])
require.Equal(t, "json", cap.args["format"])
}
func TestFlow_AllFlags(t *testing.T) {
cap, _, err := runDataflow(t, "flow",
"--from", "A", "--to", "B",
"--max-depth", "6", "--max-paths", "3", "--min-tier", "ast_resolved")
require.NoError(t, err)
require.Equal(t, "flow_between", cap.tool)
require.Equal(t, 6, cap.args["max_depth"])
require.Equal(t, 3, cap.args["max_paths"])
require.Equal(t, "ast_resolved", cap.args["min_tier"])
}
func TestFlow_OnlyChangedFlagsSent(t *testing.T) {
cap, _, err := runDataflow(t, "flow", "--from", "A", "--to", "B")
require.NoError(t, err)
_, hasDepth := cap.args["max_depth"]
require.False(t, hasDepth, "unset --max-depth must not be forwarded")
_, hasTier := cap.args["min_tier"]
require.False(t, hasTier, "unset --min-tier must not be forwarded")
}
func TestFlow_MissingFromTo(t *testing.T) {
_, _, err := runDataflow(t, "flow", "--from", "A")
require.Error(t, err)
require.Contains(t, err.Error(), "--from and --to are required")
}
// --- taint (taint_paths) ----------------------------------------------------
func TestTaint_Lowers(t *testing.T) {
cap, _, err := runDataflow(t, "taint", "--source", "s", "--sink", "k")
require.NoError(t, err)
require.NotNil(t, cap)
require.Equal(t, "taint_paths", cap.tool)
require.Equal(t, "s", cap.args["source_pattern"])
require.Equal(t, "k", cap.args["sink_pattern"])
}
func TestTaint_AllFlags(t *testing.T) {
cap, _, err := runDataflow(t, "taint",
"--source", "s", "--sink", "k",
"--max-depth", "10", "--limit", "30", "--min-tier", "lsp_resolved")
require.NoError(t, err)
require.Equal(t, "taint_paths", cap.tool)
require.Equal(t, 10, cap.args["max_depth"])
require.Equal(t, 30, cap.args["limit"])
require.Equal(t, "lsp_resolved", cap.args["min_tier"])
}
func TestTaint_MissingSourceSink(t *testing.T) {
_, _, err := runDataflow(t, "taint", "--source", "s")
require.Error(t, err)
require.Contains(t, err.Error(), "--source and --sink are required")
}
// TestFlow_DaemonRequired asserts the real call path returns the daemon-required
// error when no daemon tracks the repo.
func TestFlow_DaemonRequired(t *testing.T) {
resetFlowFlags()
buf := &bytes.Buffer{}
rootCmd.SetOut(buf)
rootCmd.SetErr(buf)
rootCmd.SetIn(strings.NewReader(""))
rootCmd.SetArgs([]string{"flow", "--from", "A", "--to", "B", "--index", t.TempDir()})
err := rootCmd.Execute()
require.Error(t, err)
require.Contains(t, err.Error(), "gortex track")
}