136 lines
3.2 KiB
Go
136 lines
3.2 KiB
Go
package lint
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func sampleFindings() []Finding {
|
|
return []Finding{
|
|
{
|
|
RuleID: "go-sec-001",
|
|
Title: "SQL injection",
|
|
Severity: "high",
|
|
File: "store/query.go",
|
|
Line: 42,
|
|
Match: `db.Query("SELECT * FROM users WHERE name LIKE ?", "%"+input+"%")`,
|
|
Fix: "Use parameterised LIKE with EscapeLike()",
|
|
},
|
|
{
|
|
RuleID: "go-cor-003",
|
|
Title: "Silent error swallowing",
|
|
Severity: "medium",
|
|
File: "handler.go",
|
|
Line: 17,
|
|
Match: `_ = service.Process(data)`,
|
|
Fix: "Handle the error",
|
|
},
|
|
{
|
|
RuleID: "go-sec-004",
|
|
Title: "Non-constant-time auth",
|
|
Severity: "high",
|
|
File: "auth/check.go",
|
|
Line: 88,
|
|
Match: `if token == expectedToken {`,
|
|
Fix: "Use subtle.ConstantTimeCompare",
|
|
},
|
|
}
|
|
}
|
|
|
|
func TestSummarise_Good(t *testing.T) {
|
|
findings := sampleFindings()
|
|
summary := Summarise(findings)
|
|
|
|
assert.Equal(t, 3, summary.Total)
|
|
assert.Equal(t, 2, summary.BySeverity["high"])
|
|
assert.Equal(t, 1, summary.BySeverity["medium"])
|
|
}
|
|
|
|
func TestSummarise_Good_Empty(t *testing.T) {
|
|
summary := Summarise(nil)
|
|
assert.Equal(t, 0, summary.Total)
|
|
assert.Empty(t, summary.BySeverity)
|
|
}
|
|
|
|
func TestWriteJSON_Good_Roundtrip(t *testing.T) {
|
|
findings := sampleFindings()
|
|
var buf bytes.Buffer
|
|
err := WriteJSON(&buf, findings)
|
|
require.NoError(t, err)
|
|
|
|
var decoded []Finding
|
|
err = json.Unmarshal(buf.Bytes(), &decoded)
|
|
require.NoError(t, err)
|
|
|
|
assert.Len(t, decoded, 3)
|
|
assert.Equal(t, "go-sec-001", decoded[0].RuleID)
|
|
assert.Equal(t, 42, decoded[0].Line)
|
|
assert.Equal(t, "handler.go", decoded[1].File)
|
|
}
|
|
|
|
func TestWriteJSON_Good_PrettyPrinted(t *testing.T) {
|
|
findings := sampleFindings()
|
|
var buf bytes.Buffer
|
|
err := WriteJSON(&buf, findings)
|
|
require.NoError(t, err)
|
|
|
|
// Pretty-printed JSON should contain indentation.
|
|
assert.Contains(t, buf.String(), " ")
|
|
assert.Contains(t, buf.String(), "\n")
|
|
}
|
|
|
|
func TestWriteJSON_Good_Empty(t *testing.T) {
|
|
var buf bytes.Buffer
|
|
err := WriteJSON(&buf, nil)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "[]\n", buf.String())
|
|
}
|
|
|
|
func TestWriteJSONL_Good_LineCount(t *testing.T) {
|
|
findings := sampleFindings()
|
|
var buf bytes.Buffer
|
|
err := WriteJSONL(&buf, findings)
|
|
require.NoError(t, err)
|
|
|
|
lines := strings.Split(strings.TrimSpace(buf.String()), "\n")
|
|
assert.Len(t, lines, 3)
|
|
|
|
// Each line should be valid JSON.
|
|
for _, line := range lines {
|
|
var f Finding
|
|
err := json.Unmarshal([]byte(line), &f)
|
|
require.NoError(t, err)
|
|
}
|
|
}
|
|
|
|
func TestWriteJSONL_Good_Empty(t *testing.T) {
|
|
var buf bytes.Buffer
|
|
err := WriteJSONL(&buf, nil)
|
|
require.NoError(t, err)
|
|
assert.Empty(t, buf.String())
|
|
}
|
|
|
|
func TestWriteText_Good(t *testing.T) {
|
|
findings := sampleFindings()
|
|
var buf bytes.Buffer
|
|
WriteText(&buf, findings)
|
|
|
|
output := buf.String()
|
|
assert.Contains(t, output, "store/query.go:42")
|
|
assert.Contains(t, output, "[high]")
|
|
assert.Contains(t, output, "SQL injection")
|
|
assert.Contains(t, output, "go-sec-001")
|
|
assert.Contains(t, output, "handler.go:17")
|
|
assert.Contains(t, output, "[medium]")
|
|
}
|
|
|
|
func TestWriteText_Good_Empty(t *testing.T) {
|
|
var buf bytes.Buffer
|
|
WriteText(&buf, nil)
|
|
assert.Empty(t, buf.String())
|
|
}
|