-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathlinkguard_test.go
More file actions
186 lines (160 loc) · 4.98 KB
/
Copy pathlinkguard_test.go
File metadata and controls
186 lines (160 loc) · 4.98 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
package linkguard_test
import (
"reflect"
"testing"
"github.com/solrac97gr/linkguard"
"github.com/solrac97gr/linkguard/shannon"
"github.com/solrac97gr/linkguard/types"
"github.com/solrac97gr/linkguard/unicode"
)
// Mock analysis method for testing custom analyzers
type mockAnalysis struct {
name string
weightValue float64
scoreValue float64
}
func (m *mockAnalysis) Analyze(rawURL string, result *types.Result) float64 {
// For testing, we can set a mock flag
if m.name == "MockSuspicious" {
result.Reasons = append(result.Reasons, "mock suspicious reason")
}
return m.scoreValue
}
func (m *mockAnalysis) Weight() float64 {
return m.weightValue
}
func (m *mockAnalysis) Name() string {
return m.name
}
func TestNewAnalyzer_Default(t *testing.T) {
analyzer := linkguard.NewAnalyzer()
methods := analyzer.Methods()
if len(methods) != 3 {
t.Fatalf("Expected 3 default methods, got %d", len(methods))
}
expectedNames := []string{"Entropy Analysis", "Unicode Analysis", "Structure Analysis"}
for i, method := range methods {
if method.Name() != expectedNames[i] {
t.Errorf("Expected method %d to be %s, got %s", i, expectedNames[i], method.Name())
}
}
}
func TestNewAnalyzer_Custom(t *testing.T) {
customMethods := []types.AnalysisMethod{
shannon.New(0.5),
unicode.New(0.5),
}
analyzer := linkguard.NewAnalyzer(customMethods...)
methods := analyzer.Methods()
if len(methods) != 2 {
t.Fatalf("Expected 2 custom methods, got %d", len(methods))
}
if methods[0].Name() != "Entropy Analysis" || methods[1].Name() != "Unicode Analysis" {
t.Error("Custom methods not set correctly")
}
}
func TestAnalyzer_Analyze_Simple(t *testing.T) {
analyzer := linkguard.NewAnalyzer()
result := analyzer.Analyze("https://example.com")
if result.Risk != types.RiskNone {
t.Errorf("Expected RiskNone for clean URL, got %s", result.Risk)
}
if result.Score > 0.1 {
t.Errorf("Expected low score for clean URL, got %f", result.Score)
}
if !reflect.DeepEqual(result.URL, "https://example.com") {
t.Errorf("Expected URL to be 'https://example.com', got %s", result.URL)
}
}
func TestAnalyzer_Analyze_Suspicious(t *testing.T) {
analyzer := linkguard.NewAnalyzer()
// URL with homoglyphs, high entropy, and suspicious TLD
url := "https://раураl.tk/ab_cde-fgh123?q=randomstring"
result := analyzer.Analyze(url)
if !result.IsSuspicious() {
t.Error("Expected URL to be suspicious")
}
if result.Risk < types.RiskMedium {
t.Errorf("Expected at least RiskMedium, got %s", result.Risk)
}
if len(result.Reasons) == 0 {
t.Error("Expected reasons for suspicious URL")
}
}
func TestDefaultMethods(t *testing.T) {
methods := linkguard.DefaultMethods()
if len(methods) != 3 {
t.Errorf("Expected 3 default methods, got %d", len(methods))
}
}
func TestAddMethod(t *testing.T) {
analyzer := linkguard.NewAnalyzer()
initialCount := len(analyzer.Methods())
analyzer.AddMethod(&mockAnalysis{name: "Test", weightValue: 0.1, scoreValue: 0.5})
newCount := len(analyzer.Methods())
if newCount != initialCount+1 {
t.Errorf("Expected method count to be %d, got %d", initialCount+1, newCount)
}
}
func TestRiskFromScore(t *testing.T) {
// This is testing an internal function, which is not ideal, but good for coverage.
// Access via a public wrapper if this test is considered inappropriate.
tests := []struct {
score float64
expected types.RiskLevel
}{
{0.1, types.RiskNone},
{0.2, types.RiskLow},
{0.4, types.RiskMedium},
{0.7, types.RiskHigh},
{0.9, types.RiskCritical},
}
// Since riskFromScore is not exported, we test it via the public Analyze method.
for _, tt := range tests {
analyzer := linkguard.NewAnalyzer(&mockAnalysis{
name: "Mock",
weightValue: 1.0,
scoreValue: tt.score,
})
result := analyzer.Analyze("http://mock.url")
if result.Risk != tt.expected {
t.Errorf("For score %f, expected risk %s, got %s", tt.score, tt.expected, result.Risk)
}
}
}
func TestBuildReasons(t *testing.T) {
// Also testing an internal function via a public method.
result := types.Result{
Entropy: 5.0,
UnicodeFlags: types.UnicodeReport{
MixedScripts: true,
HomoglyphCount: 1,
ScriptsFound: []string{"ASCII", "Cyrillic"},
},
StructureFlags: types.StructureReport{
HasIPAddress: true,
},
}
analyzer := linkguard.NewAnalyzer() // Use a real analyzer to trigger buildReasons
// Manually construct a result to test reason generation
result.Reasons = analyzer.Analyze("http://1.2.3.4/раураl").Reasons
if len(result.Reasons) < 3 {
t.Errorf("Expected at least 3 reasons, got %d", len(result.Reasons))
}
}
func BenchmarkAnalyze(b *testing.B) {
analyzer := linkguard.NewAnalyzer()
url := "https://www.google.com/search?q=golang+benchmarks"
b.ResetTimer()
for i := 0; i < b.N; i++ {
analyzer.Analyze(url)
}
}
func BenchmarkAnalyze_Suspicious(b *testing.B) {
analyzer := linkguard.NewAnalyzer()
url := "https://microsоft.com/login/auth?next=http%3A%2F%2Fevil.tk"
b.ResetTimer()
for i := 0; i < b.N; i++ {
analyzer.Analyze(url)
}
}