Files
Ascently/sync/main_test.go

362 lines
7.9 KiB
Go

package main
import (
"encoding/json"
"path/filepath"
"strings"
"testing"
"time"
)
func TestSyncServerAuthentication(t *testing.T) {
server := &SyncServer{authToken: "test-token"}
tests := []struct {
name string
token string
expected bool
}{
{"Valid token", "test-token", true},
{"Invalid token", "wrong-token", false},
{"Empty token", "", false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Test the authentication logic directly without HTTP
result := strings.Compare(tt.token, server.authToken) == 0
if result != tt.expected {
t.Errorf("authenticate() = %v, want %v", result, tt.expected)
}
})
}
}
func TestLoadDataNonExistentFile(t *testing.T) {
tempDir := t.TempDir()
server := &SyncServer{
dataFile: filepath.Join(tempDir, "nonexistent.json"),
}
backup, err := server.loadData()
if err != nil {
t.Errorf("loadData() error = %v, want nil", err)
}
if backup == nil {
t.Error("Expected backup to be non-nil")
}
if len(backup.Gyms) != 0 || len(backup.Problems) != 0 || len(backup.Sessions) != 0 || len(backup.Attempts) != 0 {
t.Error("Expected empty backup data")
}
if backup.Version != "2.0" || backup.FormatVersion != "2.0" {
t.Error("Expected version and format version to be 2.0")
}
}
func TestSaveAndLoadData(t *testing.T) {
tempDir := t.TempDir()
server := &SyncServer{
dataFile: filepath.Join(tempDir, "test.json"),
imagesDir: filepath.Join(tempDir, "images"),
}
testData := &ClimbDataBackup{
Version: "2.0",
FormatVersion: "2.0",
Gyms: []BackupGym{
{
ID: "gym1",
Name: "Test Gym",
},
},
Problems: []BackupProblem{
{
ID: "problem1",
GymID: "gym1",
ClimbType: "BOULDER",
Difficulty: DifficultyGrade{
System: "V",
Grade: "V5",
NumericValue: 5,
},
IsActive: true,
},
},
Sessions: []BackupClimbSession{},
Attempts: []BackupAttempt{},
}
err := server.saveData(testData)
if err != nil {
t.Errorf("saveData() error = %v", err)
}
loadedData, err := server.loadData()
if err != nil {
t.Errorf("loadData() error = %v", err)
}
if len(loadedData.Gyms) != 1 || loadedData.Gyms[0].ID != "gym1" {
t.Error("Loaded gym data doesn't match saved data")
}
if len(loadedData.Problems) != 1 || loadedData.Problems[0].ID != "problem1" {
t.Error("Loaded problem data doesn't match saved data")
}
}
func TestMinFunction(t *testing.T) {
tests := []struct {
a, b, expected int
}{
{5, 3, 3},
{2, 8, 2},
{4, 4, 4},
{0, 1, 0},
{-1, 2, -1},
}
for _, tt := range tests {
result := min(tt.a, tt.b)
if result != tt.expected {
t.Errorf("min(%d, %d) = %d, want %d", tt.a, tt.b, result, tt.expected)
}
}
}
func TestClimbDataBackupValidation(t *testing.T) {
tests := []struct {
name string
backup ClimbDataBackup
isValid bool
}{
{
name: "Valid backup",
backup: ClimbDataBackup{
Version: "2.0",
FormatVersion: "2.0",
Gyms: []BackupGym{},
Problems: []BackupProblem{},
Sessions: []BackupClimbSession{},
Attempts: []BackupAttempt{},
},
isValid: true,
},
{
name: "Missing version",
backup: ClimbDataBackup{
FormatVersion: "2.0",
Gyms: []BackupGym{},
Problems: []BackupProblem{},
Sessions: []BackupClimbSession{},
Attempts: []BackupAttempt{},
},
isValid: false,
},
{
name: "Missing format version",
backup: ClimbDataBackup{
Version: "2.0",
Gyms: []BackupGym{},
Problems: []BackupProblem{},
Sessions: []BackupClimbSession{},
Attempts: []BackupAttempt{},
},
isValid: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Test basic validation logic
hasVersion := tt.backup.Version != ""
hasFormatVersion := tt.backup.FormatVersion != ""
isValid := hasVersion && hasFormatVersion
if isValid != tt.isValid {
t.Errorf("validation = %v, want %v", isValid, tt.isValid)
}
})
}
}
func TestBackupDataStructures(t *testing.T) {
t.Run("BackupGym", func(t *testing.T) {
gym := BackupGym{
ID: "gym1",
Name: "Test Gym",
SupportedClimbTypes: []string{"BOULDER", "ROPE"},
DifficultySystems: []string{"V", "YDS"},
CustomDifficultyGrades: []string{},
CreatedAt: "2024-01-01T10:00:00Z",
UpdatedAt: "2024-01-01T10:00:00Z",
}
if gym.ID != "gym1" {
t.Errorf("Expected gym ID 'gym1', got %s", gym.ID)
}
if len(gym.SupportedClimbTypes) != 2 {
t.Errorf("Expected 2 climb types, got %d", len(gym.SupportedClimbTypes))
}
})
t.Run("BackupProblem", func(t *testing.T) {
problem := BackupProblem{
ID: "problem1",
GymID: "gym1",
ClimbType: "BOULDER",
Difficulty: DifficultyGrade{
System: "V",
Grade: "V5",
NumericValue: 5,
},
IsActive: true,
CreatedAt: "2024-01-01T10:00:00Z",
UpdatedAt: "2024-01-01T10:00:00Z",
}
if problem.ClimbType != "BOULDER" {
t.Errorf("Expected climb type 'BOULDER', got %s", problem.ClimbType)
}
if problem.Difficulty.Grade != "V5" {
t.Errorf("Expected difficulty 'V5', got %s", problem.Difficulty.Grade)
}
})
}
func TestDifficultyGrade(t *testing.T) {
tests := []struct {
name string
grade DifficultyGrade
expectedGrade string
expectedValue int
}{
{
name: "V-Scale grade",
grade: DifficultyGrade{
System: "V",
Grade: "V5",
NumericValue: 5,
},
expectedGrade: "V5",
expectedValue: 5,
},
{
name: "YDS grade",
grade: DifficultyGrade{
System: "YDS",
Grade: "5.10a",
NumericValue: 10,
},
expectedGrade: "5.10a",
expectedValue: 10,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if tt.grade.Grade != tt.expectedGrade {
t.Errorf("Expected grade %s, got %s", tt.expectedGrade, tt.grade.Grade)
}
if tt.grade.NumericValue != tt.expectedValue {
t.Errorf("Expected numeric value %d, got %d", tt.expectedValue, tt.grade.NumericValue)
}
})
}
}
func TestJSONSerialization(t *testing.T) {
backup := ClimbDataBackup{
Version: "2.0",
FormatVersion: "2.0",
Gyms: []BackupGym{
{
ID: "gym1",
Name: "Test Gym",
},
},
Problems: []BackupProblem{
{
ID: "problem1",
GymID: "gym1",
ClimbType: "BOULDER",
Difficulty: DifficultyGrade{
System: "V",
Grade: "V5",
NumericValue: 5,
},
IsActive: true,
},
},
Sessions: []BackupClimbSession{},
Attempts: []BackupAttempt{},
}
// Test JSON marshaling
jsonData, err := json.Marshal(backup)
if err != nil {
t.Errorf("Failed to marshal JSON: %v", err)
}
// Test JSON unmarshaling
var unmarshaledBackup ClimbDataBackup
err = json.Unmarshal(jsonData, &unmarshaledBackup)
if err != nil {
t.Errorf("Failed to unmarshal JSON: %v", err)
}
if unmarshaledBackup.Version != backup.Version {
t.Errorf("Version mismatch after JSON round-trip")
}
if len(unmarshaledBackup.Gyms) != len(backup.Gyms) {
t.Errorf("Gyms count mismatch after JSON round-trip")
}
}
func TestTimestampHandling(t *testing.T) {
now := time.Now().UTC()
timestamp := now.Format(time.RFC3339)
// Test that timestamp is in correct format
parsedTime, err := time.Parse(time.RFC3339, timestamp)
if err != nil {
t.Errorf("Failed to parse timestamp: %v", err)
}
if parsedTime.Year() != now.Year() {
t.Errorf("Year mismatch in timestamp")
}
}
func TestFilePathHandling(t *testing.T) {
tempDir := t.TempDir()
tests := []struct {
name string
filename string
isValid bool
}{
{"Valid filename", "test.json", true},
{"Valid path", filepath.Join(tempDir, "data.json"), true},
{"Empty filename", "", false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
isEmpty := tt.filename == ""
isValid := !isEmpty
if isValid != tt.isValid {
t.Errorf("File path validation = %v, want %v", isValid, tt.isValid)
}
})
}
}