package api import ( "encoding/json" "io" "net/http" "net/http/httptest" "os" "path/filepath" "testing" "github.com/markdown-editor/internal/storage" "github.com/markdown-editor/pkg/logger" ) type bytesReader struct { bytes []byte } func (r *bytesReader) Read(p []byte) (n int, err error) { if len(r.bytes) == 0 { return 0, io.EOF } n = copy(p, r.bytes) r.bytes = r.bytes[n:] return n, nil } func (r *bytesReader) Close() error { return nil } func setupTestServer(t *testing.T) (*Server, string) { // Initialize logger logger.Init() // Create temporary directory for test data tempDir := t.TempDir() // Initialize storage s := storage.NewStorage(tempDir) // Create server server, err := NewServer(tempDir, "127.0.0.1", 0) if err != nil { t.Fatalf("Failed to create server: %v", err) } // Get actual port assigned by ListenAndServe router := http.NewServeMux() router.HandleFunc("/api/files", server.handleFiles) router.HandleFunc("/api/files/", server.handleFiles) router.HandleFunc("/", server.handleFrontend) server.storage = s server.port = 0 // 0 means assign any available port return server, tempDir } func TestHandleGetFiles(t *testing.T) { server, dataDir := setupTestServer(t) // Create test files content := "Test content" testFiles := []string{"test1.md", "test2.md"} for _, filename := range testFiles { path := filepath.Join(dataDir, filename) if err := os.WriteFile(path, []byte(content), 0644); err != nil { t.Fatalf("Failed to create test file: %v", err) } } req := httptest.NewRequest("GET", "/api/files", nil) w := httptest.NewRecorder() server.handleGetFiles(w, req) if w.Code != http.StatusOK { t.Errorf("Expected status 200, got %d", w.Code) } var files []string if err := json.NewDecoder(w.Body).Decode(&files); err != nil { t.Fatalf("Failed to decode response: %v", err) } if len(files) != 2 { t.Errorf("Expected 2 files, got %d", len(files)) } } func TestHandleCreateFile(t *testing.T) { server, dataDir := setupTestServer(t) reqBody := map[string]string{ "content": "Test content", "name": "newfile.md", } reqBodyBytes, _ := json.Marshal(reqBody) req := httptest.NewRequest("POST", "/api/files", nil) req.Header.Set("Content-Type", "application/json") req.Body = &bytesReader{bytes: reqBodyBytes} w := httptest.NewRecorder() server.handleCreateFile(w, req) if w.Code != http.StatusCreated { t.Errorf("Expected status 201, got %d", w.Code) } // Verify file was created path := filepath.Join(dataDir, "newfile.md") if _, err := os.Stat(path); os.IsNotExist(err) { t.Error("File was not created") } } func TestHandleUpdateFile(t *testing.T) { server, dataDir := setupTestServer(t) // Create test file first filename := "updatefile.md" path := filepath.Join(dataDir, filename) os.WriteFile(path, []byte("Original content"), 0644) reqBody := map[string]string{ "content": "Updated content", } reqBodyBytes, _ := json.Marshal(reqBody) req := httptest.NewRequest("PUT", "/api/files/"+filename, nil) req.Header.Set("Content-Type", "application/json") req.Body = &bytesReader{bytes: reqBodyBytes} w := httptest.NewRecorder() server.handleUpdateFile(w, req) if w.Code != http.StatusOK { t.Errorf("Expected status 200, got %d", w.Code) } // Verify file content was updated newContent, err := os.ReadFile(path) if err != nil { t.Fatalf("Failed to read file: %v", err) } if string(newContent) != "Updated content" { t.Error("File content was not updated correctly") } } func TestHandleDeleteFile(t *testing.T) { server, dataDir := setupTestServer(t) // Create test file filename := "deletefile.md" path := filepath.Join(dataDir, filename) os.WriteFile(path, []byte("Test content"), 0644) req := httptest.NewRequest("DELETE", "/api/files/"+filename, nil) w := httptest.NewRecorder() server.handleDeleteFile(w, req) if w.Code != http.StatusOK { t.Errorf("Expected status 200, got %d", w.Code) } // Verify file was deleted if _, err := os.Stat(path); !os.IsNotExist(err) { t.Error("File was not deleted") } } func TestHandleStaticFiles(t *testing.T) { server, _ := setupTestServer(t) // Try to serve static file req := httptest.NewRequest("GET", "/static/index.html", nil) w := httptest.NewRecorder() server.handleFrontend(w, req) // Should return 301 redirect or 200 for index.html if w.Code != http.StatusOK && w.Code != http.StatusMovedPermanently { t.Errorf("Expected status 200 or 301, got %d", w.Code) } }