package main import ( "bytes" "encoding/json" "io" "net/http" "net/http/httptest" "os" "path/filepath" "testing" "time" "github.com/gorilla/mux" "markdown-editor/internal/handlers" "markdown-editor/internal/logger" "markdown-editor/internal/server" "markdown-editor/internal/storage" ) func TestCRUDRoundTrip(t *testing.T) { // Create a temporary data directory tmpDir, err := os.MkdirTemp("", "markdown-editor-test") if err != nil { t.Fatalf("Failed to create temp dir: %v", err) } defer os.RemoveAll(tmpDir) // Initialize storage storage, err := storage.NewFileStorage(tmpDir) if err != nil { t.Fatalf("Failed to initialize storage: %v", err) } // Initialize logger log := logger.NewLogger() // Initialize handlers handlers := handlers.NewHandlers(log, storage) // Create a router router := mux.NewRouter() apiRouter := router.PathPrefix("/api").Subrouter() apiRouter.Handle("/files", handlers.CreateFile()).Methods("POST") apiRouter.Handle("/files/{filename}", handlers.GetFile()).Methods("GET") apiRouter.Handle("/files/{filename}", handlers.UpdateFile()).Methods("PUT") apiRouter.Handle("/files/{filename}", handlers.DeleteFile()).Methods("DELETE") apiRouter.Handle("/files", handlers.ListFiles()).Methods("GET") // Test Create t.Run("Create", func(t *testing.T) { body := map[string]interface{}{ "filename": "test.md", "content": "# Test Content", } bodyBytes, _ := json.Marshal(body) req := httptest.NewRequest("POST", "/api/files", bytes.NewBuffer(bodyBytes)) req.Header.Set("Content-Type", "application/json") w := httptest.NewRecorder() router.ServeHTTP(w, req) if w.Code != http.StatusOK { t.Errorf("Expected status 200, got %d", w.Code) } var resp map[string]string json.NewDecoder(w.Body).Decode(&resp) if resp["message"] != "file created successfully" { t.Errorf("Expected success message, got: %s", resp["message"]) } }) // Test Read t.Run("Read", func(t *testing.T) { req := httptest.NewRequest("GET", "/api/files/test.md", nil) w := httptest.NewRecorder() router.ServeHTTP(w, req) if w.Code != http.StatusOK { t.Errorf("Expected status 200, got %d", w.Code) } var resp map[string]interface{} json.NewDecoder(w.Body).Decode(&resp) if resp["filename"] != "test.md" { t.Errorf("Expected filename 'test.md', got: %s", resp["filename"]) } if resp["content"] != "# Test Content" { t.Errorf("Expected content '# Test Content', got: %s", resp["content"]) } }) // Test Update t.Run("Update", func(t *testing.T) { body := map[string]interface{}{ "content": "# Updated Content", } bodyBytes, _ := json.Marshal(body) req := httptest.NewRequest("PUT", "/api/files/test.md", bytes.NewBuffer(bodyBytes)) req.Header.Set("Content-Type", "application/json") w := httptest.NewRecorder() router.ServeHTTP(w, req) if w.Code != http.StatusOK { t.Errorf("Expected status 200, got %d", w.Code) } var resp map[string]string json.NewDecoder(w.Body).Decode(&resp) if resp["message"] != "file updated successfully" { t.Errorf("Expected success message, got: %s", resp["message"]) } }) // Test List t.Run("List", func(t *testing.T) { req := httptest.NewRequest("GET", "/api/files", nil) w := httptest.NewRecorder() router.ServeHTTP(w, req) if w.Code != http.StatusOK { t.Errorf("Expected status 200, got %d", w.Code) } var resp map[string]interface{} json.NewDecoder(w.Body).Decode(&resp) files := resp["files"].([]interface{}) if len(files) != 1 { t.Errorf("Expected 1 file, got %d", len(files)) } if files[0] != "test.md" { t.Errorf("Expected 'test.md', got: %s", files[0]) } }) // Test Delete t.Run("Delete", func(t *testing.T) { req := httptest.NewRequest("DELETE", "/api/files/test.md", nil) w := httptest.NewRecorder() router.ServeHTTP(w, req) if w.Code != http.StatusOK { t.Errorf("Expected status 200, got %d", w.Code) } var resp map[string]string json.NewDecoder(w.Body).Decode(&resp) if resp["message"] != "file deleted successfully" { t.Errorf("Expected success message, got: %s", resp["message"]) } }) } func TestStaticAssetServing(t *testing.T) { // Create a temporary data directory dataDir, err := os.MkdirTemp("", "data-test") if err != nil { t.Fatalf("Failed to create data dir: %v", err) } defer os.RemoveAll(dataDir) // Create a temporary frontend build directory frontendDir, err := os.MkdirTemp("", "frontend-build-test") if err != nil { t.Fatalf("Failed to create frontend dir: %v", err) } defer os.RemoveAll(frontendDir) // Create a test index.html file indexPath := filepath.Join(frontendDir, "index.html") if err := os.WriteFile(indexPath, []byte("Test"), 0644); err != nil { t.Fatalf("Failed to create test file: %v", err) } // Change the frontend build directory temporarily originalDir := os.Getenv("FRONTEND_BUILD_DIR") os.Setenv("FRONTEND_BUILD_DIR", frontendDir) defer os.Setenv("FRONTEND_BUILD_DIR", originalDir) // Start the server go func() { if err := server.StartServer(dataDir, 8081, "127.0.0.1"); err != nil { t.Logf("Server error: %v", err) } }() // Give the server time to start time.Sleep(100 * time.Millisecond) // Test static file serving resp, err := http.Get("http://127.0.0.1:8081/index.html") if err != nil { t.Skipf("Server not ready yet: %v", err) return } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { t.Errorf("Expected status 200, got %d", resp.StatusCode) return } body, _ := io.ReadAll(resp.Body) if string(body) != "Test" { t.Errorf("Expected test HTML content, got: %s", string(body)) } }