package hlog import ( "os" "path/filepath" "strings" "testing" ) func TestNewLogFile(t *testing.T) { tests := []struct { name string dir string filename string append bool preCreate string // content to pre-create in file write string // content to write during test wantErr bool }{ { name: "create new file in append mode", dir: t.TempDir(), filename: "test.log", append: true, write: "test content", wantErr: false, }, { name: "create new file in overwrite mode", dir: t.TempDir(), filename: "test.log", append: false, write: "test content", wantErr: false, }, { name: "append to existing file", dir: t.TempDir(), filename: "existing.log", append: true, preCreate: "existing content\n", write: "new content\n", wantErr: false, }, { name: "overwrite existing file", dir: t.TempDir(), filename: "existing.log", append: false, preCreate: "old content\n", write: "new content\n", wantErr: false, }, { name: "invalid directory", dir: "/nonexistent/invalid/path", filename: "test.log", append: true, wantErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { logPath := filepath.Join(tt.dir, tt.filename) // Pre-create file if needed if tt.preCreate != "" { err := os.WriteFile(logPath, []byte(tt.preCreate), 0663) if err != nil { t.Fatalf("Failed to create pre-existing file: %v", err) } } // Create log file file, err := newLogFile(tt.dir, tt.filename, tt.append) if tt.wantErr { if err == nil { t.Errorf("newLogFile() expected error but got nil") if file != nil { file.Close() } } return } if err != nil { t.Errorf("newLogFile() unexpected error = %v", err) return } if file == nil { t.Errorf("newLogFile() returned nil file") return } defer file.Close() // Write test content if tt.write != "" { _, err = file.WriteString(tt.write) if err != nil { t.Errorf("Failed to write to file: %v", err) return } file.Sync() } // Verify file contents file.Close() content, err := os.ReadFile(logPath) if err != nil { t.Errorf("Failed to read file: %v", err) return } contentStr := string(content) if tt.append && tt.preCreate != "" { // In append mode, both old and new content should exist if !strings.Contains(contentStr, tt.preCreate) { t.Errorf("Append mode: file missing pre-existing content. Got: %s", contentStr) } if !strings.Contains(contentStr, tt.write) { t.Errorf("Append mode: file missing new content. Got: %s", contentStr) } } else if !tt.append && tt.preCreate != "" { // In overwrite mode, only new content should exist if strings.Contains(contentStr, tt.preCreate) { t.Errorf("Overwrite mode: file still contains old content. Got: %s", contentStr) } if !strings.Contains(contentStr, tt.write) { t.Errorf("Overwrite mode: file missing new content. Got: %s", contentStr) } } else { // New file, should only have new content if !strings.Contains(contentStr, tt.write) { t.Errorf("New file: missing expected content. Got: %s", contentStr) } } }) } } func TestNewLogFile_Permissions(t *testing.T) { tempDir := t.TempDir() filename := "permissions_test.log" file, err := newLogFile(tempDir, filename, true) if err != nil { t.Fatalf("newLogFile() error = %v", err) } file.Close() logPath := filepath.Join(tempDir, filename) _, err = os.Stat(logPath) if err != nil { t.Fatalf("Failed to stat file: %v", err) } // Note: Actual file permissions may differ from requested permissions // due to umask settings, so we just verify the file was created // The OS will apply umask to the requested 0663 permissions } func TestNewLogFile_MultipleAppends(t *testing.T) { tempDir := t.TempDir() filename := "multiple_appends.log" messages := []string{ "first message\n", "second message\n", "third message\n", } // Write messages sequentially for _, msg := range messages { file, err := newLogFile(tempDir, filename, true) if err != nil { t.Fatalf("newLogFile() error = %v", err) } _, err = file.WriteString(msg) if err != nil { t.Fatalf("WriteString() error = %v", err) } file.Close() } // Verify all messages are present logPath := filepath.Join(tempDir, filename) content, err := os.ReadFile(logPath) if err != nil { t.Fatalf("Failed to read file: %v", err) } contentStr := string(content) for _, msg := range messages { if !strings.Contains(contentStr, msg) { t.Errorf("File missing message: %s. Got: %s", msg, contentStr) } } } func TestNewLogFile_OverwriteClears(t *testing.T) { tempDir := t.TempDir() filename := "overwrite_clear.log" // Create file with initial content initialContent := "this should be removed\n" file1, err := newLogFile(tempDir, filename, true) if err != nil { t.Fatalf("newLogFile() error = %v", err) } file1.WriteString(initialContent) file1.Close() // Open in overwrite mode newContent := "new content only\n" file2, err := newLogFile(tempDir, filename, false) if err != nil { t.Fatalf("newLogFile() error = %v", err) } file2.WriteString(newContent) file2.Close() // Verify only new content exists logPath := filepath.Join(tempDir, filename) content, err := os.ReadFile(logPath) if err != nil { t.Fatalf("Failed to read file: %v", err) } contentStr := string(content) if strings.Contains(contentStr, initialContent) { t.Errorf("File still contains initial content after overwrite. Got: %s", contentStr) } if !strings.Contains(contentStr, newContent) { t.Errorf("File missing new content. Got: %s", contentStr) } }