Cybersecurity-Projects/PROJECTS/beginner/simple-vulnerability-scanner/internal/pyproject/parser_test.go

168 lines
3.1 KiB
Go

/*
©AngelaMos | 2026
parser_test.go
Tests for PEP 508 dependency string parsing and version spec extraction in parser.go
Tests:
TestParseDependency - name, spec, extras, and markers for ten dependency string formats
TestExtractMinVersion - lower-bound extraction from >=, ==, ~=, !=, and empty specs
*/
package pyproject
import (
"testing"
)
//nolint:gocognit,funlen
func TestParseDependency(t *testing.T) {
t.Parallel()
tests := []struct {
name string
input string
wantPkg string
wantSpc string
extras []string
markers string
}{
{
name: "simple with lower bound",
input: "requests>=2.28.0",
wantPkg: "requests",
wantSpc: ">=2.28.0",
},
{
name: "range constraint",
input: "django>=3.2,<4.0",
wantPkg: "django",
wantSpc: ">=3.2,<4.0",
},
{
name: "extras",
input: "flask[async]>=2.0",
wantPkg: "flask",
wantSpc: ">=2.0",
extras: []string{"async"},
},
{
name: "multiple extras",
input: "requests[security, socks]>=2.28.0",
wantPkg: "requests",
wantSpc: ">=2.28.0",
extras: []string{"security", "socks"},
},
{
name: "markers",
input: `pandas>=1.5; python_version>='3.8'`,
wantPkg: "pandas",
wantSpc: ">=1.5",
markers: "python_version>='3.8'",
},
{
name: "bare name no version",
input: "numpy",
wantPkg: "numpy",
wantSpc: "",
},
{
name: "exact pin",
input: "black==23.7.0",
wantPkg: "black",
wantSpc: "==23.7.0",
},
{
name: "compatible release",
input: "setuptools~=68.0",
wantPkg: "setuptools",
wantSpc: "~=68.0",
},
{
name: "not equal",
input: "urllib3!=2.0.0",
wantPkg: "urllib3",
wantSpc: "!=2.0.0",
},
{
name: "whitespace around",
input: " click >= 8.0.0 ",
wantPkg: "click",
wantSpc: ">= 8.0.0",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
dep := ParseDependency(tt.input, "")
if dep.Name != tt.wantPkg {
t.Errorf(
"Name = %q, want %q", dep.Name, tt.wantPkg,
)
}
if dep.Spec != tt.wantSpc {
t.Errorf(
"Spec = %q, want %q", dep.Spec, tt.wantSpc,
)
}
if tt.markers != "" && dep.Markers != tt.markers {
t.Errorf(
"Markers = %q, want %q",
dep.Markers, tt.markers,
)
}
if len(tt.extras) > 0 {
if len(dep.Extras) != len(tt.extras) {
t.Fatalf(
"Extras = %v, want %v",
dep.Extras, tt.extras,
)
}
for i, e := range tt.extras {
if dep.Extras[i] != e {
t.Errorf(
"Extras[%d] = %q, want %q",
i, dep.Extras[i], e,
)
}
}
}
})
}
}
func TestExtractMinVersion(t *testing.T) {
t.Parallel()
tests := []struct {
spec string
want string
}{
{">=2.28.0", "2.28.0"},
{">=3.2,<4.0", "3.2"},
{"==23.7.0", "23.7.0"},
{"==3.2.*", "3.2"},
{"~=68.0", "68.0"},
{"!=2.0", ""},
{">1.0", ""},
{"", ""},
}
for _, tt := range tests {
t.Run(tt.spec, func(t *testing.T) {
t.Parallel()
got := ExtractMinVersion(tt.spec)
if got != tt.want {
t.Errorf(
"ExtractMinVersion(%q) = %q, want %q",
tt.spec, got, tt.want,
)
}
})
}
}