299 lines
7.5 KiB
Go
299 lines
7.5 KiB
Go
package gopher
|
|
|
|
import (
|
|
"net"
|
|
"testing"
|
|
|
|
"gemini-grc/common/errors"
|
|
"gemini-grc/config"
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
func TestConstructPayloadFromPath(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
input string
|
|
expected string
|
|
}{
|
|
{
|
|
name: "Path with Gopher item type",
|
|
input: "/1/path/to/resource",
|
|
expected: "/path/to/resource",
|
|
},
|
|
{
|
|
name: "Path with different item type",
|
|
input: "/0/another/path",
|
|
expected: "/another/path",
|
|
},
|
|
{
|
|
name: "Path without item type but with leading slash",
|
|
input: "/simple/path",
|
|
expected: "/simple/path",
|
|
},
|
|
{
|
|
name: "Path without item type and without leading slash",
|
|
input: "no/leading/slash",
|
|
expected: "/no/leading/slash",
|
|
},
|
|
{
|
|
name: "Empty path",
|
|
input: "",
|
|
expected: "/",
|
|
},
|
|
{
|
|
name: "Single character item type",
|
|
input: "/h/homepage",
|
|
expected: "/homepage",
|
|
},
|
|
{
|
|
name: "Single slash",
|
|
input: "/",
|
|
expected: "/",
|
|
},
|
|
{
|
|
name: "Item type-looking path",
|
|
input: "/1",
|
|
expected: "/1",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
result := constructPayloadFromPath(tt.input)
|
|
if result != tt.expected {
|
|
t.Errorf("constructPayloadFromPath(%q) = %q, want %q",
|
|
tt.input, result, tt.expected)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestParseLinks(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
currentURL string
|
|
input string
|
|
want int // number of expected links
|
|
wantErr bool
|
|
}{
|
|
{
|
|
name: "Empty input",
|
|
currentURL: "gopher://example.com:70",
|
|
input: "",
|
|
want: 0,
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "Single directory link",
|
|
currentURL: "gopher://example.com:70",
|
|
input: "1About Us\t/about\texample.com",
|
|
want: 1,
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "Single text file link",
|
|
currentURL: "gopher://example.com:70",
|
|
input: "0README\t/readme.txt\texample.com",
|
|
want: 1,
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "Multiple links of different types",
|
|
currentURL: "gopher://example.com:70",
|
|
input: "1About Us\t/about\texample.com\n0README\t/readme.txt\texample.com\n1Contact\t/contact\texample.com",
|
|
want: 3,
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "Ignore non-linkable types",
|
|
currentURL: "gopher://example.com:70",
|
|
input: "iInfo line\t/info\texample.com\n1Directory\t/dir\texample.com\n0Text\t/text.txt\texample.com",
|
|
want: 2,
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "Malformed lines",
|
|
currentURL: "gopher://example.com:70",
|
|
input: "1Incomplete line\n0No tabs\n1Missing parts\t",
|
|
want: 0,
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "Mixed valid and invalid lines",
|
|
currentURL: "gopher://example.com:70",
|
|
input: "1Valid link\t/valid\texample.com\n1Incomplete\t\n0Text file\t/text.txt\texample.com\n1Another valid\t/another\texample.com",
|
|
want: 3,
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "Absolute URLs",
|
|
currentURL: "gopher://example.com:70",
|
|
input: "1External link\tgopher://external.com/path\texternal.com\n0Document\tgopher://other.com/doc.txt\tother.com",
|
|
want: 2,
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "With whitespace",
|
|
currentURL: "gopher://example.com:70",
|
|
input: " 1Padded line \t/padded\texample.com\n0Text file \t/doc.txt\texample.com",
|
|
want: 2,
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "Special characters in paths",
|
|
currentURL: "gopher://example.com:70",
|
|
input: "1Special chars\t/path with spaces\texample.com\n0Doc\t/über/päth.txt\texample.com",
|
|
want: 2,
|
|
wantErr: false,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got := getGopherPageLinks(tt.input)
|
|
assert.Equal(t, tt.want, len(got), "expected %d links, got %d", tt.want, len(got))
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestCheckForError(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
input string
|
|
wantError bool
|
|
errorPrefix string
|
|
}{
|
|
{
|
|
name: "No error",
|
|
input: "1Directory\t/dir\texample.com\n0Text\t/text.txt\texample.com",
|
|
wantError: false,
|
|
errorPrefix: "",
|
|
},
|
|
{
|
|
name: "Simple error message",
|
|
input: "3Error: File not found\t\texample.com",
|
|
wantError: true,
|
|
errorPrefix: "gopher error: 3Error: File not found",
|
|
},
|
|
{
|
|
name: "Error with multiple tabs",
|
|
input: "3File not found\t/error\texample.com\t70",
|
|
wantError: true,
|
|
errorPrefix: "gopher error: 3File not found",
|
|
},
|
|
{
|
|
name: "Error among valid entries",
|
|
input: `1Welcome\t/welcome\texample.com
|
|
3Access denied\t\texample.com
|
|
0README\t/readme.txt\texample.com`,
|
|
wantError: false,
|
|
errorPrefix: "",
|
|
},
|
|
{
|
|
name: "Error with no tabs",
|
|
input: "3Server is down for maintenance",
|
|
wantError: true,
|
|
errorPrefix: "gopher error: 3Server is down for maintenance",
|
|
},
|
|
{
|
|
name: "Multiple errors (should return first)",
|
|
input: `3First error\t\texample.com
|
|
3Second error\t\texample.com`,
|
|
wantError: true,
|
|
errorPrefix: "gopher error: 3First error",
|
|
},
|
|
{
|
|
name: "Error with whitespace",
|
|
input: " 3 Error with spaces \t\texample.com",
|
|
wantError: true,
|
|
errorPrefix: "gopher error: 3 Error with spaces",
|
|
},
|
|
{
|
|
name: "Empty input",
|
|
input: "",
|
|
wantError: false,
|
|
errorPrefix: "",
|
|
},
|
|
{
|
|
name: "Just newlines",
|
|
input: "\n\n\n",
|
|
wantError: false,
|
|
errorPrefix: "",
|
|
},
|
|
{
|
|
name: "Error after empty lines",
|
|
input: `
|
|
|
|
3Error after empty lines\t\texample.com`,
|
|
wantError: true,
|
|
errorPrefix: "gopher error: 3Error after empty lines",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
err := checkForError(tt.input)
|
|
|
|
if !tt.wantError {
|
|
assert.NoError(t, err)
|
|
return
|
|
}
|
|
|
|
assert.Error(t, err)
|
|
assert.Contains(t, err.Error(), tt.errorPrefix)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestConnectAndGetDataTimeout(t *testing.T) {
|
|
// Start a test server that doesn't respond
|
|
listener, err := net.Listen("tcp", "localhost:0")
|
|
if err != nil {
|
|
t.Fatalf("Failed to start listener: %v", err)
|
|
}
|
|
defer listener.Close()
|
|
|
|
// Accept the connection but don't respond
|
|
go func() {
|
|
conn, err := listener.Accept()
|
|
if err != nil {
|
|
t.Logf("Failed to accept connection: %v", err)
|
|
return
|
|
}
|
|
defer conn.Close()
|
|
|
|
// Keep the connection open without sending any data to simulate a timeout
|
|
select {}
|
|
}()
|
|
|
|
// Construct the URL of our test server
|
|
address := listener.Addr().String()
|
|
testURL := "gopher://" + address + "/testpath"
|
|
|
|
// Save original config values
|
|
originalTimeout := config.CONFIG.ResponseTimeout
|
|
originalMaxSize := config.CONFIG.MaxResponseSize
|
|
|
|
// Set test config values
|
|
config.CONFIG.ResponseTimeout = 1 // Set a very short timeout for this test
|
|
config.CONFIG.MaxResponseSize = 1024 // Just for consistency, we won't reach this
|
|
|
|
// Test the function
|
|
_, err = connectAndGetData(testURL)
|
|
|
|
// Reset config values
|
|
config.CONFIG.ResponseTimeout = originalTimeout
|
|
config.CONFIG.MaxResponseSize = originalMaxSize
|
|
|
|
// Check if the error is due to timeout
|
|
if err == nil {
|
|
t.Error("Expected an error due to timeout, but got no error")
|
|
} else if !errors.IsHostError(err) {
|
|
t.Errorf("Expected a HostError, but got: %v", err)
|
|
} else {
|
|
// Here you might want to check if the specific error message contains 'timeout'
|
|
// However, since we don't have the exact error string, we're checking the type
|
|
t.Logf("Successfully timed out: %v", err)
|
|
}
|
|
}
|