From 16186a344a7b61633cb7342aac37ac56ad83d261 Mon Sep 17 00:00:00 2001 From: Adam Mathes Date: Thu, 12 Feb 2026 19:55:05 -0800 Subject: =?UTF-8?q?Add=20comprehensive=20test=20suite=20=E2=80=94=2081%=20?= =?UTF-8?q?cross-package=20coverage?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bug fixes: - config: remove unused log import - item: fix Printf format %d->%t for boolean ReadState - util: update stale config.Read -> config.Init, remove config.Config.DBServer Test files added: - config/config_test.go: Init, readConfig, addDefaults (100%) - vlog/vlog_test.go: Printf, Println verbose/silent (100%) - models/db_test.go: InitDB tests - models/feed/feed_test.go: CRUD, filter, Categories, NewFeed, ResolveFeedURL (87%) - models/item/item_test.go: CRUD, Filter with category/search/starred, rewriteImages (71%) - exporter/exporter_test.go: all export formats (91%) - importer/importer_test.go: InsertIItem, ImportJSON (90%) - crawler/crawler_test.go: GetFeedContent, CrawlFeed, CrawlWorker, Crawl (89%) - web/web_test.go: auth, login/logout, stream, item, feed, category, export, crawl, imageProxy handlers (77%) Remaining 0% functions require HTTP/rice.MustFindBox/main entry and can't be unit tested without refactoring (see tickets NK-gqkh96, NK-6q9nyg). --- exporter/exporter_test.go | 111 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 exporter/exporter_test.go (limited to 'exporter/exporter_test.go') diff --git a/exporter/exporter_test.go b/exporter/exporter_test.go new file mode 100644 index 0000000..d4cc994 --- /dev/null +++ b/exporter/exporter_test.go @@ -0,0 +1,111 @@ +package exporter + +import ( + "encoding/json" + "strings" + "testing" + + "adammathes.com/neko/config" + "adammathes.com/neko/models" +) + +func setupTestDB(t *testing.T) { + t.Helper() + config.Config.DBFile = ":memory:" + models.InitDB() + t.Cleanup(func() { + if models.DB != nil { + models.DB.Close() + } + }) +} + +func seedFeeds(t *testing.T) { + t.Helper() + _, err := models.DB.Exec("INSERT INTO feed(url, web_url, title, category) VALUES(?, ?, ?, ?)", + "https://a.com/feed", "https://a.com", "Alpha Feed", "tech") + if err != nil { + t.Fatal(err) + } + _, err = models.DB.Exec("INSERT INTO feed(url, web_url, title, category) VALUES(?, ?, ?, ?)", + "https://b.com/feed", "https://b.com", "Beta Feed", "news") + if err != nil { + t.Fatal(err) + } +} + +func TestExportText(t *testing.T) { + setupTestDB(t) + seedFeeds(t) + + result := ExportFeeds("text") + if !strings.Contains(result, "https://a.com/feed") { + t.Error("text export should contain feed URL a") + } + if !strings.Contains(result, "https://b.com/feed") { + t.Error("text export should contain feed URL b") + } +} + +func TestExportJSON(t *testing.T) { + setupTestDB(t) + seedFeeds(t) + + result := ExportFeeds("json") + var feeds []interface{} + err := json.Unmarshal([]byte(result), &feeds) + if err != nil { + t.Fatalf("JSON export should be valid JSON: %v", err) + } + if len(feeds) != 2 { + t.Errorf("JSON export should contain 2 feeds, got %d", len(feeds)) + } +} + +func TestExportOPML(t *testing.T) { + setupTestDB(t) + seedFeeds(t) + + result := ExportFeeds("opml") + if !strings.Contains(result, "") { + t.Error("OPML export should close opml tag") + } +} + +func TestExportHTML(t *testing.T) { + setupTestDB(t) + seedFeeds(t) + + result := ExportFeeds("html") + if !strings.Contains(result, "") { + t.Error("HTML export should contain html tag") + } + if !strings.Contains(result, "Alpha Feed") { + t.Error("HTML export should contain feed title") + } +} + +func TestExportUnknownFormat(t *testing.T) { + setupTestDB(t) + seedFeeds(t) + + result := ExportFeeds("unknown") + if result != "" { + t.Errorf("Unknown format should return empty string, got %q", result) + } +} + +func TestExportEmpty(t *testing.T) { + setupTestDB(t) + + result := ExportFeeds("text") + if result != "" { + t.Errorf("Export with no feeds should be empty, got %q", result) + } +} -- cgit v1.2.3