You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
121 lines
2.8 KiB
121 lines
2.8 KiB
package main
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
)
|
|
|
|
func newTestStore(t *testing.T) *Store {
|
|
t.Helper()
|
|
s, err := NewStore(filepath.Join(t.TempDir(), "test.db"))
|
|
if err != nil {
|
|
t.Fatalf("NewStore() failed: %v", err)
|
|
}
|
|
t.Cleanup(func() { s.Close() })
|
|
return s
|
|
}
|
|
|
|
func TestStore_CreateAndFindByCode(t *testing.T) {
|
|
s := newTestStore(t)
|
|
|
|
originalURL := "https://example.com/create-and-find"
|
|
|
|
if err := s.Create("testabc", originalURL); err != nil {
|
|
t.Fatalf("Create() failed: %v", err)
|
|
}
|
|
|
|
rec, err := s.FindByCode("testabc")
|
|
if err != nil {
|
|
t.Fatalf("FindByCode() failed: %v", err)
|
|
}
|
|
if rec == nil {
|
|
t.Fatal("FindByCode() returned nil, expected a record")
|
|
}
|
|
if rec.OriginalURL != originalURL {
|
|
t.Fatalf("expected OriginalURL %q, got %q", originalURL, rec.OriginalURL)
|
|
}
|
|
if rec.Code != "testabc" {
|
|
t.Fatalf("expected Code %q, got %q", "testabc", rec.Code)
|
|
}
|
|
}
|
|
|
|
func TestStore_FindByCode_NonExistent(t *testing.T) {
|
|
s := newTestStore(t)
|
|
|
|
rec, err := s.FindByCode("nonexist")
|
|
if err != nil {
|
|
t.Fatalf("FindByCode() for non-existent code failed: %v", err)
|
|
}
|
|
if rec != nil {
|
|
t.Fatal("expected nil for non-existent code, got a record")
|
|
}
|
|
}
|
|
|
|
func TestStore_Create_Duplicate(t *testing.T) {
|
|
s := newTestStore(t)
|
|
|
|
url := "https://example.com/dup"
|
|
if err := s.Create("dupcode", url); err != nil {
|
|
t.Fatalf("first Create() failed: %v", err)
|
|
}
|
|
if err := s.Create("dupcode", url); err == nil {
|
|
t.Fatal("second Create() with same code should fail")
|
|
}
|
|
}
|
|
|
|
func TestStore_Persistence(t *testing.T) {
|
|
tmpFile, err := os.CreateTemp("", "shortlink-*.json")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
tmpPath := tmpFile.Name()
|
|
tmpFile.Close()
|
|
defer os.Remove(tmpPath)
|
|
|
|
s1, err := NewStore(tmpPath)
|
|
if err != nil {
|
|
t.Fatalf("NewStore() failed: %v", err)
|
|
}
|
|
s1.Create("persist", "https://example.com/persist")
|
|
s1.Close()
|
|
|
|
s2, err := NewStore(tmpPath)
|
|
if err != nil {
|
|
t.Fatalf("reopen store failed: %v", err)
|
|
}
|
|
defer s2.Close()
|
|
|
|
rec, err := s2.FindByCode("persist")
|
|
if err != nil {
|
|
t.Fatalf("FindByCode() after reopen failed: %v", err)
|
|
}
|
|
if rec == nil {
|
|
t.Fatal("expected record after reopening store")
|
|
}
|
|
if rec.OriginalURL != "https://example.com/persist" {
|
|
t.Fatalf("unexpected OriginalURL: %q", rec.OriginalURL)
|
|
}
|
|
}
|
|
|
|
func TestGenerateCode(t *testing.T) {
|
|
seen := make(map[string]bool)
|
|
for i := 0; i < 100; i++ {
|
|
code, err := generateCode()
|
|
if err != nil {
|
|
t.Fatalf("generateCode() failed: %v", err)
|
|
}
|
|
if len(code) != codeLength {
|
|
t.Fatalf("expected code length %d, got %d: %q", codeLength, len(code), code)
|
|
}
|
|
for _, c := range code {
|
|
if !((c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
|
|
t.Fatalf("invalid character %c in code %q", c, code)
|
|
}
|
|
}
|
|
if seen[code] {
|
|
t.Fatal("unexpected collision: duplicate code generated")
|
|
}
|
|
seen[code] = true
|
|
}
|
|
}
|
|
|