aboutsummaryrefslogtreecommitdiffstats
path: root/api/api_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'api/api_test.go')
-rw-r--r--api/api_test.go242
1 files changed, 239 insertions, 3 deletions
diff --git a/api/api_test.go b/api/api_test.go
index 45b0123..217a9fa 100644
--- a/api/api_test.go
+++ b/api/api_test.go
@@ -5,8 +5,12 @@ import (
"encoding/json"
"net/http"
"net/http/httptest"
+ "path/filepath"
"strconv"
+ "strings"
+ "sync"
"testing"
+ "time"
"adammathes.com/neko/config"
"adammathes.com/neko/models"
@@ -14,14 +18,18 @@ import (
"adammathes.com/neko/models/item"
)
+var testMu sync.Mutex
+
func setupTestDB(t *testing.T) {
t.Helper()
- config.Config.DBFile = ":memory:"
+ testMu.Lock()
+ config.Config.DBFile = filepath.Join(t.TempDir(), "test.db")
models.InitDB()
t.Cleanup(func() {
if models.DB != nil {
models.DB.Close()
}
+ testMu.Unlock()
})
}
@@ -145,7 +153,235 @@ func TestGetCategories(t *testing.T) {
var cats []feed.Category
json.NewDecoder(rr.Body).Decode(&cats)
- if len(cats) != 1 {
- t.Errorf("expected 1 category, got %d", len(cats))
+ if len(cats) != 1 { // Corrected 'categories' to 'cats' for syntactic correctness
+ t.Errorf("Expected 1 category, got %d", len(cats)) // Corrected 'categories' to 'cats'
+ }
+}
+
+func TestHandleExport(t *testing.T) {
+ setupTestDB(t)
+ seedData(t)
+
+ formats := []string{"text", "json", "opml", "html"}
+ for _, fmt := range formats {
+ req := httptest.NewRequest("GET", "/export/"+fmt, nil)
+ rr := httptest.NewRecorder()
+ HandleExport(rr, req)
+
+ if rr.Code != http.StatusOK {
+ t.Errorf("Expected 200 for format %s, got %d", fmt, rr.Code)
+ }
+ }
+
+ req := httptest.NewRequest("GET", "/export/unknown", nil)
+ rr := httptest.NewRecorder()
+ HandleExport(rr, req)
+ if rr.Code != http.StatusOK { // This should probably be http.StatusBadRequest or similar for unknown format
+ t.Errorf("Expected 200 for unknown format, got %d", rr.Code)
+ }
+}
+
+func TestHandleCrawl(t *testing.T) {
+ setupTestDB(t)
+
+ req := httptest.NewRequest("POST", "/crawl", nil)
+ rr := httptest.NewRecorder()
+ HandleCrawl(rr, req)
+
+ if rr.Code != http.StatusOK {
+ t.Errorf("Expected 200, got %d", rr.Code)
+ }
+ if !strings.Contains(rr.Body.String(), "crawl started") {
+ t.Error("Expected crawl started message in response")
+ }
+ // Wait for background goroutine to at least start/finish before DB is closed by cleanup
+ time.Sleep(100 * time.Millisecond)
+}
+
+func TestJsonError(t *testing.T) {
+ req := httptest.NewRequest("PUT", "/item/notanumber", nil)
+ rr := httptest.NewRecorder()
+ HandleItem(rr, req)
+
+ if rr.Code != http.StatusBadRequest {
+ t.Errorf("Expected 400, got %d", rr.Code)
+ }
+ var resp map[string]string
+ json.Unmarshal(rr.Body.Bytes(), &resp)
+ if resp["error"] == "" {
+ t.Error("Expected error message in JSON response")
+ }
+}
+
+func TestHandleStreamFilters(t *testing.T) {
+ setupTestDB(t)
+ seedData(t)
+ router := NewRouter()
+
+ testCases := []struct {
+ url string
+ expected int
+ }{
+ {"/stream?tag=tech", 1},
+ {"/stream?tag=missing", 0},
+ {"/stream?feed_url=http://example.com", 1},
+ {"/stream?starred=1", 0}, // none starred in seed
+ {"/stream?q=Test", 1},
+ }
+
+ for _, tc := range testCases {
+ req := httptest.NewRequest("GET", tc.url, nil)
+ rr := httptest.NewRecorder()
+ router.ServeHTTP(rr, req)
+
+ var items []item.Item
+ json.NewDecoder(rr.Body).Decode(&items)
+ if len(items) != tc.expected {
+ t.Errorf("For %s, expected %d items, got %d", tc.url, tc.expected, len(items))
+ }
+ }
+}
+
+func TestHandleFeedErrors(t *testing.T) {
+ setupTestDB(t)
+ router := NewRouter()
+
+ // Post missing URL
+ b, _ := json.Marshal(feed.Feed{Title: "No URL"})
+ req := httptest.NewRequest("POST", "/feed", bytes.NewBuffer(b))
+ rr := httptest.NewRecorder()
+ router.ServeHTTP(rr, req)
+ if rr.Code != http.StatusBadRequest {
+ t.Errorf("Expected 400 for missing URL, got %d", rr.Code)
+ }
+
+ // Invalid JSON
+ req = httptest.NewRequest("POST", "/feed", strings.NewReader("not json"))
+ rr = httptest.NewRecorder()
+ router.ServeHTTP(rr, req)
+ if rr.Code != http.StatusBadRequest {
+ t.Errorf("Expected 400 for invalid JSON, got %d", rr.Code)
+ }
+
+ // Method Not Allowed
+ req = httptest.NewRequest("PATCH", "/feed", nil)
+ rr = httptest.NewRecorder()
+ router.ServeHTTP(rr, req)
+ if rr.Code != http.StatusMethodNotAllowed {
+ t.Errorf("Expected 405, got %d", rr.Code)
+ }
+}
+
+func TestHandleItemEdgeCases(t *testing.T) {
+ setupTestDB(t)
+ seedData(t)
+ router := NewRouter()
+
+ // Item not found
+ req := httptest.NewRequest("GET", "/item/999", nil)
+ rr := httptest.NewRecorder()
+ router.ServeHTTP(rr, req)
+ if rr.Code != http.StatusNotFound {
+ t.Errorf("Expected 404, got %d", rr.Code)
+ }
+
+ // Method not allowed
+ req = httptest.NewRequest("DELETE", "/item/1", nil)
+ rr = httptest.NewRecorder()
+ router.ServeHTTP(rr, req)
+ if rr.Code != http.StatusMethodNotAllowed {
+ t.Errorf("Expected 405, got %d", rr.Code)
+ }
+
+ // GET/POST for content extraction (mocked content extraction is tested in models/item)
+ var id int64
+ err := models.DB.QueryRow("SELECT id FROM item LIMIT 1").Scan(&id)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ req = httptest.NewRequest("GET", "/item/"+strconv.FormatInt(id, 10), nil)
+ rr = httptest.NewRecorder()
+ router.ServeHTTP(rr, req)
+ if rr.Code != http.StatusOK {
+ t.Errorf("Expected 200, got %d", rr.Code)
+ }
+}
+
+func TestHandleFeedDeleteNoId(t *testing.T) {
+ setupTestDB(t)
+ router := NewRouter()
+
+ req := httptest.NewRequest("DELETE", "/feed/", nil)
+ rr := httptest.NewRecorder()
+ router.ServeHTTP(rr, req)
+ if rr.Code != http.StatusBadRequest {
+ t.Errorf("Expected 400, got %d", rr.Code)
+ }
+}
+
+func TestMethodNotAllowed(t *testing.T) {
+ setupTestDB(t)
+ router := NewRouter()
+
+ testCases := []struct {
+ method string
+ url string
+ }{
+ {"POST", "/stream"},
+ {"POST", "/tag"},
+ {"POST", "/export/text"},
+ }
+
+ for _, tc := range testCases {
+ req := httptest.NewRequest(tc.method, tc.url, nil)
+ rr := httptest.NewRecorder()
+ router.ServeHTTP(rr, req)
+ if rr.Code != http.StatusMethodNotAllowed {
+ t.Errorf("Expected 405 for %s %s, got %d", tc.method, tc.url, rr.Code)
+ }
+ }
+}
+
+func TestExportBadRequest(t *testing.T) {
+ setupTestDB(t)
+ req := httptest.NewRequest("GET", "/export/", nil)
+ rr := httptest.NewRecorder()
+ HandleExport(rr, req)
+ if rr.Code != http.StatusBadRequest {
+ t.Errorf("Expected 400 for empty format, got %d", rr.Code)
+ }
+}
+
+func TestHandleFeedPutInvalidJson(t *testing.T) {
+ setupTestDB(t)
+ req := httptest.NewRequest("PUT", "/feed", strings.NewReader("not json"))
+ rr := httptest.NewRecorder()
+ HandleFeed(rr, req)
+ if rr.Code != http.StatusBadRequest {
+ t.Errorf("Expected 400 for invalid JSON in PUT, got %d", rr.Code)
+ }
+}
+
+func TestHandleFeedPutMissingId(t *testing.T) {
+ setupTestDB(t)
+ b, _ := json.Marshal(feed.Feed{Title: "No ID"})
+ req := httptest.NewRequest("PUT", "/feed", bytes.NewBuffer(b))
+ rr := httptest.NewRecorder()
+ HandleFeed(rr, req)
+ if rr.Code != http.StatusBadRequest {
+ t.Errorf("Expected 400 for missing ID in PUT, got %d", rr.Code)
+ }
+}
+
+func TestHandleItemIdMismatch(t *testing.T) {
+ setupTestDB(t)
+ seedData(t)
+ b, _ := json.Marshal(item.Item{Id: 999}) // mismatch with path 1
+ req := httptest.NewRequest("PUT", "/item/1", bytes.NewBuffer(b))
+ rr := httptest.NewRecorder()
+ HandleItem(rr, req)
+ if rr.Code != http.StatusBadRequest {
+ t.Errorf("Expected 400 for ID mismatch, got %d", rr.Code)
}
}