mirror of
https://github.com/Dvorinka/Devour.git
synced 2026-06-03 20:13:03 +00:00
updage
This commit is contained in:
@@ -0,0 +1,601 @@
|
||||
package quality
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestNewStateManager(t *testing.T) {
|
||||
dataDir := "/tmp/test_state"
|
||||
sm := NewStateManager(dataDir)
|
||||
|
||||
if sm == nil {
|
||||
t.Error("NewStateManager() should not return nil")
|
||||
}
|
||||
|
||||
if sm.dataDir != dataDir {
|
||||
t.Errorf("NewStateManager() dataDir = %v, want %v", sm.dataDir, dataDir)
|
||||
}
|
||||
|
||||
expectedStateFile := filepath.Join(dataDir, "state.json")
|
||||
if sm.stateFile != expectedStateFile {
|
||||
t.Errorf("NewStateManager() stateFile = %v, want %v", sm.stateFile, expectedStateFile)
|
||||
}
|
||||
|
||||
expectedHistoryDir := filepath.Join(dataDir, "history")
|
||||
if sm.historyDir != expectedHistoryDir {
|
||||
t.Errorf("NewStateManager() historyDir = %v, want %v", sm.historyDir, expectedHistoryDir)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStateManager_Load(t *testing.T) {
|
||||
tmpDir, err := os.MkdirTemp("", "state_test")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create temp dir: %v", err)
|
||||
}
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
sm := NewStateManager(tmpDir)
|
||||
|
||||
// Test loading non-existent file
|
||||
state, err := sm.Load()
|
||||
if err != nil {
|
||||
t.Errorf("Load() should not error for non-existent file: %v", err)
|
||||
}
|
||||
|
||||
if state == nil {
|
||||
t.Error("Load() should return empty state for non-existent file")
|
||||
}
|
||||
|
||||
if len(state.Findings) != 0 {
|
||||
t.Errorf("Load() should return empty findings for non-existent file, got %d", len(state.Findings))
|
||||
}
|
||||
|
||||
if state.Metadata == nil {
|
||||
t.Error("Load() should initialize metadata map")
|
||||
}
|
||||
|
||||
// Test loading existing file
|
||||
testState := &State{
|
||||
Findings: []Finding{
|
||||
{ID: "test1", Type: "test", Title: "Test Finding 1", Status: StatusOpen},
|
||||
{ID: "test2", Type: "test", Title: "Test Finding 2", Status: StatusFixed},
|
||||
},
|
||||
ScanCount: 5,
|
||||
Metadata: map[string]string{"env": "test"},
|
||||
}
|
||||
|
||||
data, _ := json.Marshal(testState)
|
||||
stateFile := sm.stateFile
|
||||
os.WriteFile(stateFile, data, 0644)
|
||||
|
||||
loadedState, err := sm.Load()
|
||||
if err != nil {
|
||||
t.Errorf("Load() failed: %v", err)
|
||||
}
|
||||
|
||||
if loadedState.ScanCount != 5 {
|
||||
t.Errorf("Load() ScanCount = %v, want 5", loadedState.ScanCount)
|
||||
}
|
||||
|
||||
if len(loadedState.Findings) != 2 {
|
||||
t.Errorf("Load() findings count = %v, want 2", len(loadedState.Findings))
|
||||
}
|
||||
|
||||
if loadedState.Metadata["env"] != "test" {
|
||||
t.Errorf("Load() metadata = %v, want test", loadedState.Metadata["env"])
|
||||
}
|
||||
}
|
||||
|
||||
func TestStateManager_Load_InvalidJSON(t *testing.T) {
|
||||
tmpDir, err := os.MkdirTemp("", "state_test")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create temp dir: %v", err)
|
||||
}
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
sm := NewStateManager(tmpDir)
|
||||
|
||||
// Write invalid JSON
|
||||
stateFile := sm.stateFile
|
||||
os.WriteFile(stateFile, []byte("{ invalid json"), 0644)
|
||||
|
||||
_, err = sm.Load()
|
||||
if err == nil {
|
||||
t.Error("Load() should error for invalid JSON")
|
||||
}
|
||||
}
|
||||
|
||||
func TestStateManager_Save(t *testing.T) {
|
||||
tmpDir, err := os.MkdirTemp("", "state_test")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create temp dir: %v", err)
|
||||
}
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
sm := NewStateManager(tmpDir)
|
||||
|
||||
state := &State{
|
||||
Findings: []Finding{
|
||||
{ID: "test1", Type: "test", Title: "Test Finding", Status: StatusOpen},
|
||||
},
|
||||
Scorecard: &Scorecard{TotalScore: 100, StrictScore: 50},
|
||||
ScanCount: 1,
|
||||
Metadata: map[string]string{"env": "test"},
|
||||
}
|
||||
|
||||
err = sm.Save(state)
|
||||
if err != nil {
|
||||
t.Errorf("Save() failed: %v", err)
|
||||
}
|
||||
|
||||
// Verify file was created
|
||||
if _, err := os.Stat(sm.stateFile); err != nil {
|
||||
t.Errorf("Save() should create state file: %v", err)
|
||||
}
|
||||
|
||||
// Verify content hash was calculated
|
||||
if state.ContentHash == "" {
|
||||
t.Error("Save() should calculate content hash")
|
||||
}
|
||||
|
||||
// Load and verify
|
||||
loadedState, err := sm.Load()
|
||||
if err != nil {
|
||||
t.Errorf("Save() failed to load saved state: %v", err)
|
||||
}
|
||||
|
||||
if len(loadedState.Findings) != 1 {
|
||||
t.Errorf("Save() should save findings, got %d", len(loadedState.Findings))
|
||||
}
|
||||
|
||||
if loadedState.ScanCount != 1 {
|
||||
t.Errorf("Save() should increment scan count, got %d", loadedState.ScanCount)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStateManager_Save_History(t *testing.T) {
|
||||
tmpDir, err := os.MkdirTemp("", "state_test")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create temp dir: %v", err)
|
||||
}
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
sm := NewStateManager(tmpDir)
|
||||
|
||||
state := &State{
|
||||
Findings: []Finding{{ID: "test", Type: "test", Title: "Test", Status: StatusOpen}},
|
||||
Scorecard: &Scorecard{TotalScore: 100, StrictScore: 50},
|
||||
}
|
||||
|
||||
err = sm.Save(state)
|
||||
if err != nil {
|
||||
t.Errorf("Save() failed: %v", err)
|
||||
}
|
||||
|
||||
// Check history directory was created
|
||||
if _, err := os.Stat(sm.historyDir); err != nil {
|
||||
t.Errorf("Save() should create history directory: %v", err)
|
||||
}
|
||||
|
||||
// Check history file was created
|
||||
historyFiles, err := filepath.Glob(filepath.Join(sm.historyDir, "*.json"))
|
||||
if err != nil {
|
||||
t.Errorf("Save() failed to list history files: %v", err)
|
||||
}
|
||||
|
||||
if len(historyFiles) != 1 {
|
||||
t.Errorf("Save() should create 1 history file, got %d", len(historyFiles))
|
||||
}
|
||||
}
|
||||
|
||||
func TestStateManager_Merge(t *testing.T) {
|
||||
sm := NewStateManager("/tmp")
|
||||
|
||||
existingState := &State{
|
||||
Findings: []Finding{
|
||||
{ID: "existing1", Type: "test", Title: "Existing 1", Status: StatusOpen, Score: 5},
|
||||
{ID: "existing2", Type: "test", Title: "Existing 2", Status: StatusOpen, Score: 10},
|
||||
{ID: "existing3", Type: "test", Title: "Existing 3", Status: StatusOpen, Score: 15},
|
||||
},
|
||||
}
|
||||
|
||||
newFindings := []Finding{
|
||||
{ID: "existing1", Type: "test", Title: "Existing 1 Changed", Status: StatusOpen, Score: 5}, // Changed
|
||||
{ID: "new1", Type: "test", Title: "New Finding", Status: StatusOpen, Score: 20}, // Added
|
||||
{ID: "new2", Type: "test", Title: "New Finding 2", Status: StatusOpen, Score: 25}, // Added
|
||||
}
|
||||
|
||||
diff := sm.Merge(existingState, newFindings)
|
||||
|
||||
if len(diff.Added) != 2 {
|
||||
t.Errorf("Merge() added count = %v, want 2", len(diff.Added))
|
||||
}
|
||||
|
||||
if len(diff.Changed) != 1 {
|
||||
t.Errorf("Merge() changed count = %v, want 1", len(diff.Changed))
|
||||
}
|
||||
|
||||
if len(diff.Resolved) != 2 {
|
||||
t.Errorf("Merge() resolved count = %v, want 2", len(diff.Resolved))
|
||||
}
|
||||
|
||||
if len(existingState.Findings) != 3 {
|
||||
t.Errorf("Merge() should update state findings count to %d, got %d", len(newFindings), len(existingState.Findings))
|
||||
}
|
||||
|
||||
if existingState.ScanCount != 1 {
|
||||
t.Errorf("Merge() should increment scan count to 1, got %d", existingState.ScanCount)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStateManager_Merge_Resolved(t *testing.T) {
|
||||
sm := NewStateManager("/tmp")
|
||||
|
||||
existingState := &State{
|
||||
Findings: []Finding{
|
||||
{ID: "open1", Type: "test", Title: "Open Finding", Status: StatusOpen},
|
||||
{ID: "open2", Type: "test", Title: "Open Finding 2", Status: StatusOpen},
|
||||
},
|
||||
}
|
||||
|
||||
newFindings := []Finding{
|
||||
{ID: "open1", Type: "test", Title: "Open Finding", Status: StatusOpen}, // Kept
|
||||
{ID: "new1", Type: "test", Title: "New Finding", Status: StatusOpen}, // Added
|
||||
}
|
||||
|
||||
diff := sm.Merge(existingState, newFindings)
|
||||
|
||||
if len(diff.Added) != 1 {
|
||||
t.Errorf("Merge() added count = %v, want 1", len(diff.Added))
|
||||
}
|
||||
|
||||
if len(diff.Resolved) != 1 {
|
||||
t.Errorf("Merge() resolved count = %v, want 1", len(diff.Resolved))
|
||||
}
|
||||
|
||||
if diff.Resolved[0].ID != "open2" {
|
||||
t.Errorf("Merge() resolved wrong finding: %s", diff.Resolved[0].ID)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStateManager_Diff(t *testing.T) {
|
||||
sm := NewStateManager("/tmp")
|
||||
|
||||
oldState := &State{
|
||||
Findings: []Finding{
|
||||
{ID: "old1", Type: "test", Title: "Old Finding", Status: StatusOpen},
|
||||
{ID: "old2", Type: "test", Title: "Old Finding 2", Status: StatusFixed},
|
||||
},
|
||||
}
|
||||
|
||||
newState := &State{
|
||||
Findings: []Finding{
|
||||
{ID: "old1", Type: "test", Title: "Old Finding Changed", Status: StatusOpen}, // Changed
|
||||
{ID: "new1", Type: "test", Title: "New Finding", Status: StatusOpen}, // Added
|
||||
{ID: "old2", Type: "test", Title: "Old Finding 2", Status: StatusOpen}, // Regression
|
||||
},
|
||||
}
|
||||
|
||||
diff := sm.Diff(oldState, newState)
|
||||
|
||||
if len(diff.Added) != 1 {
|
||||
t.Errorf("Diff() added count = %v, want 1", len(diff.Added))
|
||||
}
|
||||
|
||||
if len(diff.Changed) != 2 {
|
||||
t.Errorf("Diff() changed count = %v, want 2", len(diff.Changed))
|
||||
}
|
||||
|
||||
if len(diff.Removed) != 0 {
|
||||
t.Errorf("Diff() removed count = %v, want 0", len(diff.Removed))
|
||||
}
|
||||
|
||||
if len(diff.Regressions) != 1 {
|
||||
t.Errorf("Diff() regressions count = %v, want 1", len(diff.Regressions))
|
||||
}
|
||||
}
|
||||
|
||||
func TestStateManager_calculateHash(t *testing.T) {
|
||||
sm := NewStateManager("/tmp")
|
||||
|
||||
findings := []Finding{
|
||||
{ID: "test1", Type: "test", Title: "Test 1", Status: StatusOpen},
|
||||
{ID: "test2", Type: "test", Title: "Test 2", Status: StatusOpen},
|
||||
}
|
||||
|
||||
hash1 := sm.calculateHash(findings)
|
||||
hash2 := sm.calculateHash(findings)
|
||||
|
||||
if hash1 != hash2 {
|
||||
t.Errorf("calculateHash() should be deterministic, got %s and %s", hash1, hash2)
|
||||
}
|
||||
|
||||
if len(hash1) != 16 {
|
||||
t.Errorf("calculateHash() should return 16 character hash, got %d", len(hash1))
|
||||
}
|
||||
|
||||
// Test with different order
|
||||
reversed := []Finding{findings[1], findings[0]}
|
||||
hash3 := sm.calculateHash(reversed)
|
||||
|
||||
if hash1 != hash3 {
|
||||
t.Errorf("calculateHash() should be order-independent, got %s and %s", hash1, hash3)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStateManager_saveHistory(t *testing.T) {
|
||||
tmpDir, err := os.MkdirTemp("", "state_test")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create temp dir: %v", err)
|
||||
}
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
sm := NewStateManager(tmpDir)
|
||||
|
||||
state := &State{
|
||||
Findings: []Finding{{ID: "test", Type: "test", Title: "Test", Status: StatusOpen}},
|
||||
Scorecard: &Scorecard{TotalScore: 100, StrictScore: 50},
|
||||
ContentHash: "testhash",
|
||||
}
|
||||
|
||||
err = sm.saveHistory(state)
|
||||
if err != nil {
|
||||
t.Errorf("saveHistory() failed: %v", err)
|
||||
}
|
||||
|
||||
// Check history file was created
|
||||
files, err := filepath.Glob(filepath.Join(sm.historyDir, "*.json"))
|
||||
if err != nil {
|
||||
t.Errorf("saveHistory() failed to list files: %v", err)
|
||||
}
|
||||
|
||||
if len(files) != 1 {
|
||||
t.Errorf("saveHistory() should create 1 file, got %d", len(files))
|
||||
}
|
||||
|
||||
// Verify snapshot content
|
||||
snapshotFile := files[0]
|
||||
data, err := os.ReadFile(snapshotFile)
|
||||
if err != nil {
|
||||
t.Errorf("saveHistory() failed to read snapshot file: %v", err)
|
||||
}
|
||||
|
||||
// The file contains the full state, not a snapshot
|
||||
var savedState State
|
||||
if err := json.Unmarshal(data, &savedState); err != nil {
|
||||
t.Errorf("saveHistory() failed to parse saved state: %v", err)
|
||||
}
|
||||
|
||||
if len(savedState.Findings) != 1 {
|
||||
t.Errorf("saveHistory() saved state findings count = %v, want 1", len(savedState.Findings))
|
||||
}
|
||||
|
||||
if savedState.Scorecard.TotalScore != 100 {
|
||||
t.Errorf("saveHistory() saved state score = %v, want 100", savedState.Scorecard.TotalScore)
|
||||
}
|
||||
|
||||
if savedState.ContentHash != "testhash" {
|
||||
t.Errorf("saveHistory() saved state hash = %v, want testhash", savedState.ContentHash)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStateManager_ResolveFinding(t *testing.T) {
|
||||
sm := NewStateManager("/tmp")
|
||||
|
||||
state := &State{
|
||||
Findings: []Finding{
|
||||
{ID: "test1", Type: "test", Title: "Test Finding", Status: StatusOpen},
|
||||
{ID: "test2", Type: "test", Title: "Test Finding 2", Status: StatusOpen},
|
||||
},
|
||||
}
|
||||
|
||||
// Resolve existing finding
|
||||
err := sm.ResolveFinding(state, "test1", StatusFixed, "Fixed the issue")
|
||||
if err != nil {
|
||||
t.Errorf("ResolveFinding() failed: %v", err)
|
||||
}
|
||||
|
||||
if state.Findings[0].Status != StatusFixed {
|
||||
t.Errorf("ResolveFinding() status = %v, want Fixed", state.Findings[0].Status)
|
||||
}
|
||||
|
||||
if state.Findings[0].Metadata["resolution_note"] != "Fixed the issue" {
|
||||
t.Errorf("ResolveFinding() resolution_note = %v, want 'Fixed the issue'", state.Findings[0].Metadata["resolution_note"])
|
||||
}
|
||||
|
||||
// Try to resolve non-existent finding
|
||||
err = sm.ResolveFinding(state, "nonexistent", StatusFixed, "note")
|
||||
if err == nil {
|
||||
t.Error("ResolveFinding() should error for non-existent finding")
|
||||
}
|
||||
}
|
||||
|
||||
func TestStateManager_GetFinding(t *testing.T) {
|
||||
sm := NewStateManager("/tmp")
|
||||
|
||||
state := &State{
|
||||
Findings: []Finding{
|
||||
{ID: "test1", Type: "test", Title: "Test Finding", Status: StatusOpen},
|
||||
{ID: "test2", Type: "test", Title: "Test Finding 2", Status: StatusOpen},
|
||||
},
|
||||
}
|
||||
|
||||
// Get existing finding
|
||||
finding := sm.GetFinding(state, "test1")
|
||||
if finding == nil {
|
||||
t.Error("GetFinding() should return finding for existing ID")
|
||||
}
|
||||
|
||||
if finding.ID != "test1" {
|
||||
t.Errorf("GetFinding() returned wrong finding ID: %s", finding.ID)
|
||||
}
|
||||
|
||||
// Get non-existent finding
|
||||
finding = sm.GetFinding(state, "nonexistent")
|
||||
if finding != nil {
|
||||
t.Error("GetFinding() should return nil for non-existent ID")
|
||||
}
|
||||
}
|
||||
|
||||
func TestStateManager_GetOpenFindings(t *testing.T) {
|
||||
sm := NewStateManager("/tmp")
|
||||
|
||||
state := &State{
|
||||
Findings: []Finding{
|
||||
{ID: "open1", Type: "test", Title: "Open Finding", Status: StatusOpen},
|
||||
{ID: "fixed1", Type: "test", Title: "Fixed Finding", Status: StatusFixed},
|
||||
{ID: "open2", Type: "test", Title: "Open Finding 2", Status: StatusOpen},
|
||||
},
|
||||
}
|
||||
|
||||
open := sm.GetOpenFindings(state)
|
||||
if len(open) != 2 {
|
||||
t.Errorf("GetOpenFindings() count = %v, want 2", len(open))
|
||||
}
|
||||
|
||||
for _, f := range open {
|
||||
if f.Status != StatusOpen {
|
||||
t.Errorf("GetOpenFindings() should only return open findings, got %v", f.Status)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestStateManager_GetFindingsByTier(t *testing.T) {
|
||||
sm := NewStateManager("/tmp")
|
||||
|
||||
state := &State{
|
||||
Findings: []Finding{
|
||||
{ID: "t1", Type: "test", Title: "T1 Finding", Status: StatusOpen, Severity: SeverityT1},
|
||||
{ID: "t2", Type: "test", Title: "T2 Finding", Status: StatusOpen, Severity: SeverityT2},
|
||||
{ID: "t3", Type: "test", Title: "T3 Finding", Status: StatusOpen, Severity: SeverityT3},
|
||||
{ID: "t4", Type: "test", Title: "T4 Finding", Status: StatusOpen, Severity: SeverityT4},
|
||||
},
|
||||
}
|
||||
|
||||
byTier := sm.GetFindingsByTier(state)
|
||||
if len(byTier) != 4 {
|
||||
t.Errorf("GetFindingsByTier() should return 4 tiers, got %d", len(byTier))
|
||||
}
|
||||
|
||||
if len(byTier[SeverityT1]) != 1 {
|
||||
t.Errorf("GetFindingsByTier() T1 count = %v, want 1", len(byTier[SeverityT1]))
|
||||
}
|
||||
|
||||
if len(byTier[SeverityT4]) != 1 {
|
||||
t.Errorf("GetFindingsByTier() T4 count = %v, want 1", len(byTier[SeverityT4]))
|
||||
}
|
||||
}
|
||||
|
||||
func TestStateManager_GetTrend(t *testing.T) {
|
||||
sm := NewStateManager("/tmp")
|
||||
|
||||
state := &State{
|
||||
History: []StateSnapshot{
|
||||
{Timestamp: time.Now().Add(-4 * time.Hour), Score: 100, Findings: 10},
|
||||
{Timestamp: time.Now().Add(-3 * time.Hour), Score: 90, Findings: 12},
|
||||
{Timestamp: time.Now().Add(-2 * time.Hour), Score: 80, Findings: 15},
|
||||
{Timestamp: time.Now().Add(-1 * time.Hour), Score: 70, Findings: 18},
|
||||
{Timestamp: time.Now(), Score: 60, Findings: 20},
|
||||
},
|
||||
}
|
||||
|
||||
// Get last 3 snapshots
|
||||
trend := sm.GetTrend(state, 3)
|
||||
if len(trend) != 3 {
|
||||
t.Errorf("GetTrend() should return 3 snapshots, got %d", len(trend))
|
||||
}
|
||||
|
||||
// Verify order (should be chronological, oldest first)
|
||||
if trend[0].Score != 80 {
|
||||
t.Errorf("GetTrend() first snapshot should be oldest: %d", trend[0].Score)
|
||||
}
|
||||
|
||||
if trend[2].Score != 60 {
|
||||
t.Errorf("GetTrend() last snapshot should be most recent: %d", trend[2].Score)
|
||||
}
|
||||
|
||||
// Request more than available
|
||||
allTrend := sm.GetTrend(state, 10)
|
||||
if len(allTrend) != 5 {
|
||||
t.Errorf("GetTrend() should return all available snapshots when requesting more than available: %d", len(allTrend))
|
||||
}
|
||||
}
|
||||
|
||||
func TestFindingsEqual(t *testing.T) {
|
||||
finding1 := Finding{
|
||||
ID: "test", Type: "test", Title: "Test", File: "test.go", Line: 10,
|
||||
Severity: SeverityT2, Score: 5, Status: StatusOpen,
|
||||
}
|
||||
|
||||
finding2 := Finding{
|
||||
ID: "test", Type: "test", Title: "Test", File: "test.go", Line: 10,
|
||||
Severity: SeverityT2, Score: 5, Status: StatusOpen,
|
||||
}
|
||||
|
||||
finding3 := Finding{
|
||||
ID: "different", Type: "test", Title: "Different", File: "test.go", Line: 10,
|
||||
Severity: SeverityT2, Score: 5, Status: StatusOpen,
|
||||
}
|
||||
|
||||
if !findingsEqual(finding1, finding2) {
|
||||
t.Error("findingsEqual() should return true for equal findings")
|
||||
}
|
||||
|
||||
if findingsEqual(finding1, finding3) {
|
||||
t.Error("findingsEqual() should return false for different findings")
|
||||
}
|
||||
}
|
||||
|
||||
func TestFindingsEqual_DifferentStatus(t *testing.T) {
|
||||
finding1 := Finding{ID: "test", Type: "test", Status: StatusOpen}
|
||||
finding2 := Finding{ID: "test", Type: "test", Status: StatusFixed}
|
||||
|
||||
if findingsEqual(finding1, finding2) {
|
||||
t.Error("findingsEqual() should return false for different status")
|
||||
}
|
||||
}
|
||||
|
||||
func TestFormatDiff(t *testing.T) {
|
||||
diff := &StateDiff{
|
||||
Added: []Finding{
|
||||
{ID: "new1", Title: "New Finding 1"},
|
||||
{ID: "new2", Title: "New Finding 2"},
|
||||
},
|
||||
Removed: []Finding{
|
||||
{ID: "old1", Title: "Old Finding 1"},
|
||||
},
|
||||
Changed: []Finding{
|
||||
{ID: "changed1", Title: "Changed Finding 1"},
|
||||
},
|
||||
Resolved: []Finding{
|
||||
{ID: "resolved1", Title: "Resolved Finding 1"},
|
||||
},
|
||||
Regressions: []Finding{
|
||||
{ID: "regression1", Title: "Regression Finding 1"},
|
||||
},
|
||||
}
|
||||
|
||||
output := FormatDiff(diff)
|
||||
|
||||
expected := "[+] Added: 2 findings\n - new1: New Finding 1\n - new2: New Finding 2\n[-] Removed: 1 findings\n - old1: Old Finding 1\n[~] Changed: 1 findings\n - changed1: Changed Finding 1\n[OK] Resolved: 1 findings\n - resolved1: Resolved Finding 1\n[!] Regressions: 1 findings\n - regression1: Regression Finding 1\n"
|
||||
|
||||
if output != expected {
|
||||
t.Errorf("FormatDiff() output mismatch:\nGot:\n%s\nExpected:\n%s", output, expected)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFormatDiff_Empty(t *testing.T) {
|
||||
diff := &StateDiff{}
|
||||
|
||||
output := FormatDiff(diff)
|
||||
|
||||
expected := "No changes detected\n"
|
||||
|
||||
if output != expected {
|
||||
t.Errorf("FormatDiff() empty diff output mismatch:\nGot:\n%s\nExpected:\n%s", output, expected)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user