Files
sif/sif_test.go
Celeste Hickenlooper 49ecfccb4a refactor: rewrite framework detection with modular detector architecture
- create detector interface and registry for extensibility
- extract detectors to separate files: backend.go, frontend.go, cms.go, meta.go
- reduce detect.go from 785 lines to 178 lines (pure orchestrator)
- export VersionMatch and ExtractVersionOptimized for detector use
- create result.go with NewFrameworkResult and WithVulnerabilities helpers
- add url validation to New() for early error detection
- add sif_test.go with main package tests
- update detect_test.go to use external test package pattern
2026-01-03 05:57:09 -08:00

179 lines
4.2 KiB
Go

/*
·━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━·
: :
: █▀ █ █▀▀ · Blazing-fast pentesting suite :
: ▄█ █ █▀ · BSD 3-Clause License :
: :
: (c) 2022-2025 vmfunc (Celeste Hickenlooper), xyzeva, :
: lunchcat alumni & contributors :
: :
·━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━·
*/
package sif
import (
"testing"
"github.com/dropalldatabases/sif/pkg/config"
)
// mockResult is a test implementation of ScanResult
type mockResult struct {
name string
data string
}
func (m *mockResult) ResultType() string {
return m.name
}
func TestNewModuleResult(t *testing.T) {
tests := []struct {
name string
result *mockResult
wantID string
}{
{
name: "basic result",
result: &mockResult{name: "test", data: "test data"},
wantID: "test",
},
{
name: "empty name",
result: &mockResult{name: "", data: "data"},
wantID: "",
},
{
name: "complex name",
result: &mockResult{name: "framework-detection", data: "Laravel 8.0"},
wantID: "framework-detection",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
mr := NewModuleResult(tt.result)
if mr.Id != tt.wantID {
t.Errorf("NewModuleResult() Id = %q, want %q", mr.Id, tt.wantID)
}
if mr.Data != tt.result {
t.Errorf("NewModuleResult() Data = %v, want %v", mr.Data, tt.result)
}
})
}
}
func TestNew_NoTargets(t *testing.T) {
settings := &config.Settings{
URLs: []string{},
File: "",
}
_, err := New(settings)
if err == nil {
t.Error("New() should return error when no targets provided")
}
}
func TestNew_WithURLs(t *testing.T) {
settings := &config.Settings{
URLs: []string{"https://example.com"},
ApiMode: true,
}
app, err := New(settings)
if err != nil {
t.Fatalf("New() unexpected error: %v", err)
}
if app == nil {
t.Fatal("New() returned nil app")
}
if len(app.targets) != 1 {
t.Errorf("New() targets = %d, want 1", len(app.targets))
}
if app.targets[0] != "https://example.com" {
t.Errorf("New() target = %q, want %q", app.targets[0], "https://example.com")
}
}
func TestNew_URLValidation(t *testing.T) {
tests := []struct {
name string
url string
wantErr bool
}{
{
name: "valid https url",
url: "https://example.com",
wantErr: false,
},
{
name: "valid http url",
url: "http://example.com",
wantErr: false,
},
{
name: "missing protocol",
url: "example.com",
wantErr: true,
},
{
name: "invalid protocol",
url: "ftp://example.com",
wantErr: true,
},
{
name: "empty url",
url: "",
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
settings := &config.Settings{
URLs: []string{tt.url},
ApiMode: true,
}
_, err := New(settings)
if (err != nil) != tt.wantErr {
t.Errorf("New() error = %v, wantErr %v", err, tt.wantErr)
}
})
}
}
func TestModuleResult_JSON(t *testing.T) {
mr := ModuleResult{
Id: "test",
Data: map[string]string{"key": "value"},
}
// Verify the struct can be used (basic sanity check)
if mr.Id != "test" {
t.Errorf("ModuleResult.Id = %q, want %q", mr.Id, "test")
}
}
func TestUrlResult_JSON(t *testing.T) {
ur := UrlResult{
Url: "https://example.com",
Results: []ModuleResult{
{Id: "test", Data: "data"},
},
}
if ur.Url != "https://example.com" {
t.Errorf("UrlResult.Url = %q, want %q", ur.Url, "https://example.com")
}
if len(ur.Results) != 1 {
t.Errorf("UrlResult.Results = %d, want 1", len(ur.Results))
}
}