test(06-02): add failing tests for JSONFormatter
This commit is contained in:
149
pkg/output/json_test.go
Normal file
149
pkg/output/json_test.go
Normal file
@@ -0,0 +1,149 @@
|
||||
package output
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/salvacybersec/keyhunter/pkg/engine"
|
||||
)
|
||||
|
||||
func TestJSONFormatter_EmptyFindings(t *testing.T) {
|
||||
var buf bytes.Buffer
|
||||
if err := (JSONFormatter{}).Format(nil, &buf, Options{}); err != nil {
|
||||
t.Fatalf("Format returned error: %v", err)
|
||||
}
|
||||
got := buf.String()
|
||||
if got != "[]\n" {
|
||||
t.Fatalf("empty findings: want %q, got %q", "[]\n", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestJSONFormatter_RegisteredUnderJSON(t *testing.T) {
|
||||
f, err := Get("json")
|
||||
if err != nil {
|
||||
t.Fatalf("Get(\"json\") error: %v", err)
|
||||
}
|
||||
if _, ok := f.(JSONFormatter); !ok {
|
||||
t.Fatalf("Get(\"json\") returned %T, want JSONFormatter", f)
|
||||
}
|
||||
}
|
||||
|
||||
func sampleFinding() engine.Finding {
|
||||
return engine.Finding{
|
||||
ProviderName: "openai",
|
||||
KeyValue: "sk-proj-abcdef1234567890XYZW",
|
||||
KeyMasked: "sk-proj-...XYZW",
|
||||
Confidence: "high",
|
||||
Source: "src/config.go",
|
||||
SourceType: "file",
|
||||
LineNumber: 42,
|
||||
Offset: 1024,
|
||||
DetectedAt: time.Date(2026, 4, 5, 12, 30, 0, 0, time.UTC),
|
||||
}
|
||||
}
|
||||
|
||||
func TestJSONFormatter_MaskedByDefault(t *testing.T) {
|
||||
f := sampleFinding()
|
||||
var buf bytes.Buffer
|
||||
if err := (JSONFormatter{}).Format([]engine.Finding{f}, &buf, Options{}); err != nil {
|
||||
t.Fatalf("Format returned error: %v", err)
|
||||
}
|
||||
var out []map[string]any
|
||||
if err := json.Unmarshal(buf.Bytes(), &out); err != nil {
|
||||
t.Fatalf("invalid JSON: %v\n%s", err, buf.String())
|
||||
}
|
||||
if len(out) != 1 {
|
||||
t.Fatalf("want 1 element, got %d", len(out))
|
||||
}
|
||||
if out[0]["key"] != f.KeyMasked {
|
||||
t.Errorf("key: want %q (masked), got %v", f.KeyMasked, out[0]["key"])
|
||||
}
|
||||
if out[0]["key_masked"] != f.KeyMasked {
|
||||
t.Errorf("key_masked: want %q, got %v", f.KeyMasked, out[0]["key_masked"])
|
||||
}
|
||||
if out[0]["provider"] != "openai" {
|
||||
t.Errorf("provider: got %v", out[0]["provider"])
|
||||
}
|
||||
if out[0]["confidence"] != "high" {
|
||||
t.Errorf("confidence: got %v", out[0]["confidence"])
|
||||
}
|
||||
if out[0]["line"].(float64) != 42 {
|
||||
t.Errorf("line: got %v", out[0]["line"])
|
||||
}
|
||||
if out[0]["detected_at"] != "2026-04-05T12:30:00Z" {
|
||||
t.Errorf("detected_at: got %v", out[0]["detected_at"])
|
||||
}
|
||||
if out[0]["verified"] != false {
|
||||
t.Errorf("verified: got %v", out[0]["verified"])
|
||||
}
|
||||
// Unverified: omitempty fields should not appear.
|
||||
if _, ok := out[0]["verify_status"]; ok {
|
||||
t.Errorf("verify_status should be omitted when empty")
|
||||
}
|
||||
}
|
||||
|
||||
func TestJSONFormatter_UnmaskRevealsKey(t *testing.T) {
|
||||
f := sampleFinding()
|
||||
var buf bytes.Buffer
|
||||
if err := (JSONFormatter{}).Format([]engine.Finding{f}, &buf, Options{Unmask: true}); err != nil {
|
||||
t.Fatalf("Format returned error: %v", err)
|
||||
}
|
||||
var out []map[string]any
|
||||
if err := json.Unmarshal(buf.Bytes(), &out); err != nil {
|
||||
t.Fatalf("invalid JSON: %v", err)
|
||||
}
|
||||
if out[0]["key"] != f.KeyValue {
|
||||
t.Errorf("key: want %q (unmasked), got %v", f.KeyValue, out[0]["key"])
|
||||
}
|
||||
if out[0]["key_masked"] != f.KeyMasked {
|
||||
t.Errorf("key_masked should remain masked, got %v", out[0]["key_masked"])
|
||||
}
|
||||
}
|
||||
|
||||
func TestJSONFormatter_VerifyFieldsPresent(t *testing.T) {
|
||||
f := sampleFinding()
|
||||
f.Verified = true
|
||||
f.VerifyStatus = "live"
|
||||
f.VerifyHTTPCode = 200
|
||||
f.VerifyMetadata = map[string]string{"org": "acme"}
|
||||
|
||||
var buf bytes.Buffer
|
||||
if err := (JSONFormatter{}).Format([]engine.Finding{f}, &buf, Options{}); err != nil {
|
||||
t.Fatalf("Format returned error: %v", err)
|
||||
}
|
||||
var out []map[string]any
|
||||
if err := json.Unmarshal(buf.Bytes(), &out); err != nil {
|
||||
t.Fatalf("invalid JSON: %v", err)
|
||||
}
|
||||
if out[0]["verified"] != true {
|
||||
t.Errorf("verified: got %v", out[0]["verified"])
|
||||
}
|
||||
if out[0]["verify_status"] != "live" {
|
||||
t.Errorf("verify_status: got %v", out[0]["verify_status"])
|
||||
}
|
||||
if out[0]["verify_http_code"].(float64) != 200 {
|
||||
t.Errorf("verify_http_code: got %v", out[0]["verify_http_code"])
|
||||
}
|
||||
meta, ok := out[0]["verify_metadata"].(map[string]any)
|
||||
if !ok {
|
||||
t.Fatalf("verify_metadata missing or wrong type: %v", out[0]["verify_metadata"])
|
||||
}
|
||||
if meta["org"] != "acme" {
|
||||
t.Errorf("verify_metadata.org: got %v", meta["org"])
|
||||
}
|
||||
}
|
||||
|
||||
func TestJSONFormatter_Indented(t *testing.T) {
|
||||
f := sampleFinding()
|
||||
var buf bytes.Buffer
|
||||
if err := (JSONFormatter{}).Format([]engine.Finding{f}, &buf, Options{}); err != nil {
|
||||
t.Fatalf("Format returned error: %v", err)
|
||||
}
|
||||
// Expect 2-space indent on at least one property line.
|
||||
if !strings.Contains(buf.String(), "\n \"provider\"") {
|
||||
t.Errorf("output not indented with 2 spaces:\n%s", buf.String())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user