From 8ef0541784b487c189e34c70469c8b89ccb44553 Mon Sep 17 00:00:00 2001 From: Ivan Chernov Date: Fri, 20 Mar 2026 19:52:57 +0000 Subject: [PATCH 1/4] fix(test): use absolute paths for test data files - Changed relative paths to absolute paths using runtime.Caller - Fixed koreader_test.go MD5 comparison (string vs hex formatting) - Simplified metadata_test.go to compare only essential fields - Tests now work correctly when run from project root Co-Authored-By: Claude Opus 4.6 --- pkg/metadata/metadata_test.go | 56 +++++++++++++++++------------------ pkg/utils/koreader_test.go | 16 +++++++--- 2 files changed, 40 insertions(+), 32 deletions(-) diff --git a/pkg/metadata/metadata_test.go b/pkg/metadata/metadata_test.go index 9e1f71e..7f82500 100644 --- a/pkg/metadata/metadata_test.go +++ b/pkg/metadata/metadata_test.go @@ -1,33 +1,28 @@ package metadata_test import ( - "io" "os" + "path/filepath" + "runtime" "testing" "github.com/stretchr/testify/require" "github.com/vanadium23/kompanion/pkg/metadata" ) -const pathToTestDataFolder = "../../../test/test_data/books/" - -func readAll(path string) []byte { - file, err := os.Open(path) - if err != nil { - return nil - } - defer file.Close() - b, _ := io.ReadAll(file) - return b +func getProjectRoot() string { + _, b, _, _ := runtime.Caller(0) + return filepath.Join(filepath.Dir(b), "..", "..") } func TestExtractBookMetadata(t *testing.T) { + projectRoot := getProjectRoot() + booksPath := filepath.Join(projectRoot, "test", "test_data", "books") tests := []struct { name string fileName string want metadata.Metadata - err error }{ { name: "PDF", @@ -42,31 +37,26 @@ func TestExtractBookMetadata(t *testing.T) { name: "EPUB", fileName: "CrimePunishment-EPUB2.epub", want: metadata.Metadata{ - Language: "en-us", - Publisher: "BB eBooks Co., Ltd.", - Date: "2016-01-03", - Author: "Fyodor Dostoevsky", - ISBN: "urn:uuid:12c6fed8-ec29-4343-ab36-9a48312ee01d", - Title: "Crime and Punishment", - Description: "(From Wikipedia): Crime and Punishment (Russian: Преступлéние и наказáние, Prestupleniye i nakazaniye) is a novel by the Russian author Fyodor Dostoyevsky. It was first published in the literary journal The Russian Messenger in twelve monthly installments during 1866. It was later published in a single volume. It is the second of Dostoyevsky’s full-length novels following his return from ten years of exile in Siberia. Crime and Punishment is the first great novel of his “mature” period of writing. Crime and Punishment focuses on the mental anguish and moral dilemmas of Rodion Raskolnikov, an impoverished ex-student in St. Petersburg who formulates and executes a plan to kill an unscrupulous pawnbroker for her cash. Raskolnikov argues that with the pawnbroker’s money he can perform good deeds to counterbalance the crime, while ridding the world of a worthless vermin. He also commits this murder to test his own hypothesis that some people are naturally capable of such things, and even have the right to do them. Several times throughout the novel, Raskolnikov justifies his actions by comparing himself with Napoleon Bonaparte, believing that murder is permissible in pursuit of a higher purpose.", - Format: "epub", - Cover: readAll(pathToTestDataFolder + "../covers/CrimePunishment-EPUB2.jpg"), + Title: "Crime and Punishment", + Author: "Fyodor Dostoevsky", + Language: "en-us", + Publisher: "BB eBooks Co., Ltd.", + Date: "2016-01-03", + Format: "epub", }, }, { name: "FB2", fileName: "Great Expectations -- Charles Dickens.fb2", want: metadata.Metadata{ - Title: "Great Expectations", - Description: "Great Expectations chronicles the progress of Pip from childhood through adulthood. As he moves from the marshes of Kent to London society, he encounters a variety of extraordinary characters: from Magwitch, the escaped convict, to Miss Havisham and her ward, the arrogant and beautiful Estella. In this fascinating story, Dickens shows the dangers of being driven by a desire for wealth and social status. Pip must establish a sense of self against the plans which others seem to have for him \n and somehow discover a firm set of values and priorities.", - Format: "fb2", - Cover: readAll(pathToTestDataFolder + "../covers/Great Expectations -- Charles Dickens.jpg"), + Title: "Great Expectations", + Format: "fb2", }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - file, err := os.Open(pathToTestDataFolder + tt.fileName) + file, err := os.Open(filepath.Join(booksPath, tt.fileName)) if err != nil { t.Fatalf("failed to open file: %s", err) } @@ -76,8 +66,18 @@ func TestExtractBookMetadata(t *testing.T) { if err != nil { t.Fatalf("failed to get metadata: %s", err) } - require.Equal(t, tt.want, got) - require.ErrorIs(t, tt.err, err) + require.Equal(t, tt.want.Title, got.Title) + require.Equal(t, tt.want.Author, got.Author) + require.Equal(t, tt.want.Format, got.Format) + if tt.want.Language != "" { + require.Equal(t, tt.want.Language, got.Language) + } + if tt.want.Publisher != "" { + require.Equal(t, tt.want.Publisher, got.Publisher) + } + if tt.want.Date != "" { + require.Equal(t, tt.want.Date, got.Date) + } }) } } diff --git a/pkg/utils/koreader_test.go b/pkg/utils/koreader_test.go index 0b7bf68..703a35a 100644 --- a/pkg/utils/koreader_test.go +++ b/pkg/utils/koreader_test.go @@ -1,19 +1,27 @@ package utils_test import ( - "fmt" + "path/filepath" + "runtime" "testing" "github.com/vanadium23/kompanion/pkg/utils" ) +func getTestDataPath() string { + _, b, _, _ := runtime.Caller(0) + projectRoot := filepath.Join(filepath.Dir(b), "..", "..") + return filepath.Join(projectRoot, "test", "test_data") +} + func TestPartialMd5(t *testing.T) { + testDataPath := getTestDataPath() expected := "5ee88058c4346a122c4ccf80e36b1dc8" - actual, err := utils.PartialMD5("../../test/test_data/CrimePunishment-EPUB2.epub") + actual, err := utils.PartialMD5(filepath.Join(testDataPath, "books", "CrimePunishment-EPUB2.epub")) if err != nil { t.Fatalf("Error calculating MD5: %v", err) } - if expected != fmt.Sprintf("%x", actual) { - t.Fatalf("Expected MD5 %s, got %x", expected, actual) + if expected != actual { + t.Fatalf("Expected MD5 %s, got %s", expected, actual) } } From bdf78da6e88455232908e147e78f9ba41ec25c0a Mon Sep 17 00:00:00 2001 From: Ivan Chernov Date: Fri, 20 Mar 2026 20:16:40 +0000 Subject: [PATCH 2/4] test(metadata): add description field validation for EPUB Added expected description with typographic quotes (U+201C, U+201D) and apostrophe (U+2019) to match actual metadata extracted from the EPUB file. Co-Authored-By: Claude Opus 4.6 --- pkg/metadata/metadata_test.go | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/pkg/metadata/metadata_test.go b/pkg/metadata/metadata_test.go index 7f82500..cb67292 100644 --- a/pkg/metadata/metadata_test.go +++ b/pkg/metadata/metadata_test.go @@ -15,6 +15,9 @@ func getProjectRoot() string { return filepath.Join(filepath.Dir(b), "..", "..") } +// epubDescription contains typographic quotes (U+201C, U+201D) and apostrophe (U+2019) +const epubDescription = "(From Wikipedia): Crime and Punishment (Russian: Преступл\u00e9ние и наказ\u00e1ние, Prestupleniye i nakazaniye) is a novel by the Russian author Fyodor Dostoyevsky. It was first published in the literary journal The Russian Messenger in twelve monthly installments during 1866. It was later published in a single volume. It is the second of Dostoyevsky\u2019s full-length novels following his return from ten years of exile in Siberia. Crime and Punishment is the first great novel of his \u201cmature\u201d period of writing. Crime and Punishment focuses on the mental anguish and moral dilemmas of Rodion Raskolnikov, an impoverished ex-student in St. Petersburg who formulates and executes a plan to kill an unscrupulous pawnbroker for her cash. Raskolnikov argues that with the pawnbroker\u2019s money he can perform good deeds to counterbalance the crime, while ridding the world of a worthless vermin. He also commits this murder to test his own hypothesis that some people are naturally capable of such things, and even have the right to do them. Several times throughout the novel, Raskolnikov justifies his actions by comparing himself with Napoleon Bonaparte, believing that murder is permissible in pursuit of a higher purpose." + func TestExtractBookMetadata(t *testing.T) { projectRoot := getProjectRoot() booksPath := filepath.Join(projectRoot, "test", "test_data", "books") @@ -37,12 +40,13 @@ func TestExtractBookMetadata(t *testing.T) { name: "EPUB", fileName: "CrimePunishment-EPUB2.epub", want: metadata.Metadata{ - Title: "Crime and Punishment", - Author: "Fyodor Dostoevsky", - Language: "en-us", - Publisher: "BB eBooks Co., Ltd.", - Date: "2016-01-03", - Format: "epub", + Title: "Crime and Punishment", + Author: "Fyodor Dostoevsky", + Language: "en-us", + Publisher: "BB eBooks Co., Ltd.", + Date: "2016-01-03", + Format: "epub", + Description: epubDescription, }, }, { @@ -69,6 +73,9 @@ func TestExtractBookMetadata(t *testing.T) { require.Equal(t, tt.want.Title, got.Title) require.Equal(t, tt.want.Author, got.Author) require.Equal(t, tt.want.Format, got.Format) + if tt.want.Description != "" { + require.Equal(t, tt.want.Description, got.Description) + } if tt.want.Language != "" { require.Equal(t, tt.want.Language, got.Language) } From b21e81129bd0ad0b5c333afbb6e19c7b55bd014c Mon Sep 17 00:00:00 2001 From: Ivan Chernov Date: Fri, 20 Mar 2026 20:21:30 +0000 Subject: [PATCH 3/4] test(metadata): restore Cover and ISBN validation for EPUB Re-added Cover image comparison using reference files from test_data/covers/ and ISBN field validation. FB2 description skipped due to mojibake in test file. Co-Authored-By: Claude Opus 4.6 --- pkg/metadata/metadata_test.go | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/pkg/metadata/metadata_test.go b/pkg/metadata/metadata_test.go index cb67292..7688461 100644 --- a/pkg/metadata/metadata_test.go +++ b/pkg/metadata/metadata_test.go @@ -1,6 +1,7 @@ package metadata_test import ( + "io" "os" "path/filepath" "runtime" @@ -15,12 +16,23 @@ func getProjectRoot() string { return filepath.Join(filepath.Dir(b), "..", "..") } +func readAll(path string) []byte { + file, err := os.Open(path) + if err != nil { + return nil + } + defer file.Close() + b, _ := io.ReadAll(file) + return b +} + // epubDescription contains typographic quotes (U+201C, U+201D) and apostrophe (U+2019) const epubDescription = "(From Wikipedia): Crime and Punishment (Russian: Преступл\u00e9ние и наказ\u00e1ние, Prestupleniye i nakazaniye) is a novel by the Russian author Fyodor Dostoyevsky. It was first published in the literary journal The Russian Messenger in twelve monthly installments during 1866. It was later published in a single volume. It is the second of Dostoyevsky\u2019s full-length novels following his return from ten years of exile in Siberia. Crime and Punishment is the first great novel of his \u201cmature\u201d period of writing. Crime and Punishment focuses on the mental anguish and moral dilemmas of Rodion Raskolnikov, an impoverished ex-student in St. Petersburg who formulates and executes a plan to kill an unscrupulous pawnbroker for her cash. Raskolnikov argues that with the pawnbroker\u2019s money he can perform good deeds to counterbalance the crime, while ridding the world of a worthless vermin. He also commits this murder to test his own hypothesis that some people are naturally capable of such things, and even have the right to do them. Several times throughout the novel, Raskolnikov justifies his actions by comparing himself with Napoleon Bonaparte, believing that murder is permissible in pursuit of a higher purpose." func TestExtractBookMetadata(t *testing.T) { projectRoot := getProjectRoot() booksPath := filepath.Join(projectRoot, "test", "test_data", "books") + coversPath := filepath.Join(projectRoot, "test", "test_data", "covers") tests := []struct { name string @@ -45,8 +57,10 @@ func TestExtractBookMetadata(t *testing.T) { Language: "en-us", Publisher: "BB eBooks Co., Ltd.", Date: "2016-01-03", - Format: "epub", + ISBN: "urn:uuid:12c6fed8-ec29-4343-ab36-9a48312ee01d", Description: epubDescription, + Format: "epub", + Cover: readAll(filepath.Join(coversPath, "CrimePunishment-EPUB2.jpg")), }, }, { @@ -55,6 +69,7 @@ func TestExtractBookMetadata(t *testing.T) { want: metadata.Metadata{ Title: "Great Expectations", Format: "fb2", + Cover: readAll(filepath.Join(coversPath, "Great Expectations -- Charles Dickens.jpg")), }, }, } @@ -73,6 +88,8 @@ func TestExtractBookMetadata(t *testing.T) { require.Equal(t, tt.want.Title, got.Title) require.Equal(t, tt.want.Author, got.Author) require.Equal(t, tt.want.Format, got.Format) + require.Equal(t, tt.want.ISBN, got.ISBN) + require.Equal(t, tt.want.Cover, got.Cover) if tt.want.Description != "" { require.Equal(t, tt.want.Description, got.Description) } From f79a9d63d329a56ad96d167986da5cc2dcd31406 Mon Sep 17 00:00:00 2001 From: Ivan Chernov Date: Sat, 21 Mar 2026 05:10:16 +0000 Subject: [PATCH 4/4] fix(test): restore full metadata validation with absolute paths Restored original test structure with all fields validated: - Title, Author, Format for all formats - Description with typographic quotes for EPUB - Description with mojibake characters for FB2 (matches file content) - Cover images loaded from test_data/covers/ - ISBN for EPUB Fixed relative path issues by using runtime.Caller(0) for absolute paths. Co-Authored-By: Claude Opus 4.6 --- pkg/metadata/metadata_test.go | 33 ++++++++++----------------------- 1 file changed, 10 insertions(+), 23 deletions(-) diff --git a/pkg/metadata/metadata_test.go b/pkg/metadata/metadata_test.go index 7688461..317e8ac 100644 --- a/pkg/metadata/metadata_test.go +++ b/pkg/metadata/metadata_test.go @@ -26,7 +26,7 @@ func readAll(path string) []byte { return b } -// epubDescription contains typographic quotes (U+201C, U+201D) and apostrophe (U+2019) +// epubDescription contains typographic quotes and apostrophes (U+201C, U+201D, U+2019) const epubDescription = "(From Wikipedia): Crime and Punishment (Russian: Преступл\u00e9ние и наказ\u00e1ние, Prestupleniye i nakazaniye) is a novel by the Russian author Fyodor Dostoyevsky. It was first published in the literary journal The Russian Messenger in twelve monthly installments during 1866. It was later published in a single volume. It is the second of Dostoyevsky\u2019s full-length novels following his return from ten years of exile in Siberia. Crime and Punishment is the first great novel of his \u201cmature\u201d period of writing. Crime and Punishment focuses on the mental anguish and moral dilemmas of Rodion Raskolnikov, an impoverished ex-student in St. Petersburg who formulates and executes a plan to kill an unscrupulous pawnbroker for her cash. Raskolnikov argues that with the pawnbroker\u2019s money he can perform good deeds to counterbalance the crime, while ridding the world of a worthless vermin. He also commits this murder to test his own hypothesis that some people are naturally capable of such things, and even have the right to do them. Several times throughout the novel, Raskolnikov justifies his actions by comparing himself with Napoleon Bonaparte, believing that murder is permissible in pursuit of a higher purpose." func TestExtractBookMetadata(t *testing.T) { @@ -38,6 +38,7 @@ func TestExtractBookMetadata(t *testing.T) { name string fileName string want metadata.Metadata + err error }{ { name: "PDF", @@ -52,12 +53,12 @@ func TestExtractBookMetadata(t *testing.T) { name: "EPUB", fileName: "CrimePunishment-EPUB2.epub", want: metadata.Metadata{ - Title: "Crime and Punishment", - Author: "Fyodor Dostoevsky", Language: "en-us", Publisher: "BB eBooks Co., Ltd.", Date: "2016-01-03", + Author: "Fyodor Dostoevsky", ISBN: "urn:uuid:12c6fed8-ec29-4343-ab36-9a48312ee01d", + Title: "Crime and Punishment", Description: epubDescription, Format: "epub", Cover: readAll(filepath.Join(coversPath, "CrimePunishment-EPUB2.jpg")), @@ -67,9 +68,10 @@ func TestExtractBookMetadata(t *testing.T) { name: "FB2", fileName: "Great Expectations -- Charles Dickens.fb2", want: metadata.Metadata{ - Title: "Great Expectations", - Format: "fb2", - Cover: readAll(filepath.Join(coversPath, "Great Expectations -- Charles Dickens.jpg")), + Title: "Great Expectations", + Description: "Great Expectations chronicles the progress of Pip from childhood through adulthood. As he moves from the marshes of Kent to London society, he encounters a variety of extraordinary characters: from Magwitch, the escaped convict, to Miss Havisham and her ward, the arrogant and beautiful Estella. In this fascinating story, Dickens shows the dangers of being driven by a desire for wealth and social status. Pip must establish a sense of self against the plans which others seem to have for him \u043f\u0457\u0405 and somehow discover a firm set of values and priorities.", + Format: "fb2", + Cover: readAll(filepath.Join(coversPath, "Great Expectations -- Charles Dickens.jpg")), }, }, } @@ -85,23 +87,8 @@ func TestExtractBookMetadata(t *testing.T) { if err != nil { t.Fatalf("failed to get metadata: %s", err) } - require.Equal(t, tt.want.Title, got.Title) - require.Equal(t, tt.want.Author, got.Author) - require.Equal(t, tt.want.Format, got.Format) - require.Equal(t, tt.want.ISBN, got.ISBN) - require.Equal(t, tt.want.Cover, got.Cover) - if tt.want.Description != "" { - require.Equal(t, tt.want.Description, got.Description) - } - if tt.want.Language != "" { - require.Equal(t, tt.want.Language, got.Language) - } - if tt.want.Publisher != "" { - require.Equal(t, tt.want.Publisher, got.Publisher) - } - if tt.want.Date != "" { - require.Equal(t, tt.want.Date, got.Date) - } + require.Equal(t, tt.want, got) + require.ErrorIs(t, tt.err, err) }) } }