mirror of
https://github.com/gen2brain/cbconvert
synced 2026-06-30 09:11:54 +02:00
Add more tests
This commit is contained in:
@@ -1,9 +1,12 @@
|
||||
package cbconvert
|
||||
|
||||
import (
|
||||
"archive/zip"
|
||||
"fmt"
|
||||
"image"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
@@ -100,6 +103,397 @@ func TestThumbnail(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestConvertResize(t *testing.T) {
|
||||
tmpDir, err := os.MkdirTemp(os.TempDir(), "cbc")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
opts := NewOptions()
|
||||
opts.OutDir = tmpDir
|
||||
opts.Width = 100
|
||||
|
||||
conv := New(opts)
|
||||
|
||||
files, err := conv.Files([]string{"testdata/test.cbz"})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
for _, file := range files {
|
||||
if err := conv.Convert(file); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
img := firstPage(t, conv, filepath.Join(tmpDir, "test.cbz"))
|
||||
if got := img.Bounds().Dx(); got != 100 {
|
||||
t.Errorf("resized width: got %d, want 100", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConvertFit(t *testing.T) {
|
||||
tmpDir, err := os.MkdirTemp(os.TempDir(), "cbc")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
opts := NewOptions()
|
||||
opts.OutDir = tmpDir
|
||||
opts.Width = 120
|
||||
opts.Height = 120
|
||||
opts.Fit = true
|
||||
|
||||
conv := New(opts)
|
||||
|
||||
files, err := conv.Files([]string{"testdata/test.cbz"})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
for _, file := range files {
|
||||
if err := conv.Convert(file); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
img := firstPage(t, conv, filepath.Join(tmpDir, "test.cbz"))
|
||||
w, h := img.Bounds().Dx(), img.Bounds().Dy()
|
||||
if w > 120 || h > 120 {
|
||||
t.Errorf("fit exceeded bounds: got %dx%d, want <= 120x120", w, h)
|
||||
}
|
||||
if w != 120 && h != 120 {
|
||||
t.Errorf("fit did not touch a bound: got %dx%d, want one side == 120", w, h)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConvertTar(t *testing.T) {
|
||||
tmpDir, err := os.MkdirTemp(os.TempDir(), "cbc")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
opts := NewOptions()
|
||||
opts.OutDir = tmpDir
|
||||
opts.Archive = "tar"
|
||||
|
||||
conv := New(opts)
|
||||
|
||||
files, err := conv.Files([]string{"testdata/test.cbz"})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
for _, file := range files {
|
||||
if err := conv.Convert(file); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
out := filepath.Join(tmpDir, "test.cbt")
|
||||
list, err := conv.archiveList(out)
|
||||
if err != nil {
|
||||
t.Fatalf("read tar output: %v", err)
|
||||
}
|
||||
if len(list) != 2 {
|
||||
t.Errorf("expected 2 pages in tar output, got %d: %v", len(list), list)
|
||||
}
|
||||
}
|
||||
|
||||
func TestImageTransforms(t *testing.T) {
|
||||
conv := New(NewOptions())
|
||||
|
||||
f, err := os.Open("testdata/test/00.jpg")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
src, err := conv.imageDecode(f)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
srcW, srcH := src.Bounds().Dx(), src.Bounds().Dy()
|
||||
|
||||
conv.Opts.Rotate = 90
|
||||
rotated := conv.imageTransform(src)
|
||||
if rotated.Bounds().Dx() != srcH || rotated.Bounds().Dy() != srcW {
|
||||
t.Errorf("rotate 90: got %dx%d, want %dx%d", rotated.Bounds().Dx(), rotated.Bounds().Dy(), srcH, srcW)
|
||||
}
|
||||
|
||||
conv.Opts = NewOptions()
|
||||
conv.Opts.Grayscale = true
|
||||
gray := conv.imageTransform(src)
|
||||
if !isGrayScale(gray) {
|
||||
t.Errorf("grayscale: result is not grayscale")
|
||||
}
|
||||
|
||||
conv.Opts = NewOptions()
|
||||
conv.Opts.Brightness = 20
|
||||
conv.Opts.Contrast = 20
|
||||
adjusted := conv.imageTransform(src)
|
||||
if adjusted.Bounds().Dx() != srcW || adjusted.Bounds().Dy() != srcH {
|
||||
t.Errorf("brightness/contrast changed dimensions: got %dx%d, want %dx%d",
|
||||
adjusted.Bounds().Dx(), adjusted.Bounds().Dy(), srcW, srcH)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCoverName(t *testing.T) {
|
||||
conv := New(NewOptions())
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
images []string
|
||||
want string
|
||||
}{
|
||||
{"empty", nil, ""},
|
||||
{"natural sort", []string{"10.jpg", "2.jpg", "1.jpg"}, "1.jpg"},
|
||||
{"cover prefix wins", []string{"01.jpg", "cover.jpg", "02.jpg"}, "cover.jpg"},
|
||||
{"front prefix wins", []string{"01.jpg", "front.png", "00.jpg"}, "front.png"},
|
||||
{"cover suffix wins", []string{"01.jpg", "page_cover.jpg"}, "page_cover.jpg"},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := conv.coverName(tt.images); got != tt.want {
|
||||
t.Errorf("coverName(%v) = %q, want %q", tt.images, got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCoverDirectory(t *testing.T) {
|
||||
tmpDir, err := os.MkdirTemp(os.TempDir(), "cbc")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
opts := NewOptions()
|
||||
opts.OutDir = tmpDir
|
||||
|
||||
conv := New(opts)
|
||||
|
||||
files, err := conv.Files([]string{"testdata/test"})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(files) != 1 {
|
||||
t.Fatalf("expected 1 directory file, got %d", len(files))
|
||||
}
|
||||
|
||||
for _, file := range files {
|
||||
if err := conv.Cover(file); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
if _, err := os.Stat(filepath.Join(tmpDir, "test.jpg")); err != nil {
|
||||
t.Errorf("directory cover not written: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFileType(t *testing.T) {
|
||||
tests := []struct {
|
||||
path string
|
||||
want string
|
||||
}{
|
||||
{"testdata/test.cbz", "ZIP"},
|
||||
{"testdata/test.cbr", "RAR"},
|
||||
{"testdata/test.cb7", "7Z"},
|
||||
{"testdata/test.cbt", "TAR"},
|
||||
{"testdata/test.pdf", "PDF"},
|
||||
{"testdata/test", "DIR"},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.path, func(t *testing.T) {
|
||||
if got := FileType(tt.path); got != tt.want {
|
||||
t.Errorf("FileType(%q) = %q, want %q", tt.path, got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCombine(t *testing.T) {
|
||||
tmpDir, err := os.MkdirTemp(os.TempDir(), "cbc")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
opts := NewOptions()
|
||||
opts.OutDir = tmpDir
|
||||
opts.OutFile = "merged"
|
||||
|
||||
conv := New(opts)
|
||||
|
||||
files, err := conv.Files([]string{"testdata/test.cbz", "testdata/test.cbt"})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(files) != 2 {
|
||||
t.Fatalf("expected 2 input files, got %d", len(files))
|
||||
}
|
||||
|
||||
if err := conv.Combine(files); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
zr, err := zip.OpenReader(filepath.Join(tmpDir, "merged.cbz"))
|
||||
if err != nil {
|
||||
t.Fatalf("open combined archive: %v", err)
|
||||
}
|
||||
defer zr.Close()
|
||||
|
||||
var names []string
|
||||
for _, f := range zr.File {
|
||||
names = append(names, f.Name)
|
||||
}
|
||||
|
||||
if len(names) != 4 {
|
||||
t.Fatalf("expected 4 pages in combined archive, got %d: %v", len(names), names)
|
||||
}
|
||||
|
||||
// each input is prefixed so identically named pages do not collide
|
||||
var first, second int
|
||||
for _, n := range names {
|
||||
switch {
|
||||
case strings.HasPrefix(n, "0001_"):
|
||||
first++
|
||||
case strings.HasPrefix(n, "0002_"):
|
||||
second++
|
||||
}
|
||||
}
|
||||
if first != 2 || second != 2 {
|
||||
t.Errorf("expected 2 pages from each input, got 0001_=%d 0002_=%d: %v", first, second, names)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSubfolders(t *testing.T) {
|
||||
page0, err := os.ReadFile("testdata/test/00.jpg")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
page1, err := os.ReadFile("testdata/test/01.jpg")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
inDir, err := os.MkdirTemp(os.TempDir(), "cbc-in")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(inDir)
|
||||
|
||||
src := filepath.Join(inDir, "chapters.cbz")
|
||||
buildZip(t, src, []zipEntry{
|
||||
{"chapter1/00.jpg", page0},
|
||||
{"chapter1/01.jpg", page1},
|
||||
{"chapter2/00.jpg", page0},
|
||||
{"chapter2/01.jpg", page1},
|
||||
})
|
||||
|
||||
tmpDir, err := os.MkdirTemp(os.TempDir(), "cbc-out")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
opts := NewOptions()
|
||||
opts.OutDir = tmpDir
|
||||
|
||||
conv := New(opts)
|
||||
|
||||
files, err := conv.Files([]string{src})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
for _, file := range files {
|
||||
if err := conv.Convert(file); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
zr, err := zip.OpenReader(filepath.Join(tmpDir, "chapters.cbz"))
|
||||
if err != nil {
|
||||
t.Fatalf("open output archive: %v", err)
|
||||
}
|
||||
defer zr.Close()
|
||||
|
||||
// without subfolder preservation chapter2/00 overwrites chapter1/00 and only 2 pages survive
|
||||
if len(zr.File) != 4 {
|
||||
var names []string
|
||||
for _, f := range zr.File {
|
||||
names = append(names, f.Name)
|
||||
}
|
||||
t.Fatalf("expected 4 pages from numbered subfolders, got %d: %v", len(zr.File), names)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMeta(t *testing.T) {
|
||||
tmpDir, err := os.MkdirTemp(os.TempDir(), "cbc")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
// operate on a copy so the fixture stays intact
|
||||
data, err := os.ReadFile("testdata/test.cbz")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
archive := filepath.Join(tmpDir, "meta.cbz")
|
||||
if err := os.WriteFile(archive, data, 0644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
conv := New(NewOptions())
|
||||
|
||||
conv.Opts = NewOptions()
|
||||
conv.Opts.CommentBody = "hello world"
|
||||
if _, err := conv.Meta(archive); err != nil {
|
||||
t.Fatalf("set comment: %v", err)
|
||||
}
|
||||
|
||||
conv.Opts = NewOptions()
|
||||
conv.Opts.Comment = true
|
||||
got, err := conv.Meta(archive)
|
||||
if err != nil {
|
||||
t.Fatalf("get comment: %v", err)
|
||||
}
|
||||
if got != "hello world" {
|
||||
t.Errorf("comment roundtrip: got %q, want %q", got, "hello world")
|
||||
}
|
||||
|
||||
extra := filepath.Join(tmpDir, "ComicInfo.xml")
|
||||
if err := os.WriteFile(extra, []byte("<ComicInfo/>"), 0644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
conv.Opts = NewOptions()
|
||||
conv.Opts.FileAdd = extra
|
||||
if _, err := conv.Meta(archive); err != nil {
|
||||
t.Fatalf("add file: %v", err)
|
||||
}
|
||||
if !archiveHas(t, conv, archive, "ComicInfo.xml") {
|
||||
t.Errorf("added file not found in archive")
|
||||
}
|
||||
|
||||
conv.Opts = NewOptions()
|
||||
conv.Opts.FileRemove = "ComicInfo.xml"
|
||||
if _, err := conv.Meta(archive); err != nil {
|
||||
t.Fatalf("remove file: %v", err)
|
||||
}
|
||||
if archiveHas(t, conv, archive, "ComicInfo.xml") {
|
||||
t.Errorf("removed file still present in archive")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRecursive(t *testing.T) {
|
||||
inDir, err := os.MkdirTemp(os.TempDir(), "cbc-in")
|
||||
if err != nil {
|
||||
@@ -152,3 +546,75 @@ func TestRecursive(t *testing.T) {
|
||||
t.Errorf("expected output relative to input root at %s: %v", want, err)
|
||||
}
|
||||
}
|
||||
|
||||
type zipEntry struct {
|
||||
name string
|
||||
data []byte
|
||||
}
|
||||
|
||||
func buildZip(t *testing.T, path string, entries []zipEntry) {
|
||||
t.Helper()
|
||||
|
||||
f, err := os.Create(path)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
zw := zip.NewWriter(f)
|
||||
for _, e := range entries {
|
||||
w, err := zw.Create(e.name)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := w.Write(e.data); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
if err := zw.Close(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func firstPage(t *testing.T, conv *Converter, archive string) image.Image {
|
||||
t.Helper()
|
||||
|
||||
zr, err := zip.OpenReader(archive)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer zr.Close()
|
||||
|
||||
if len(zr.File) == 0 {
|
||||
t.Fatalf("archive %s has no entries", archive)
|
||||
}
|
||||
|
||||
rc, err := zr.File[0].Open()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer rc.Close()
|
||||
|
||||
img, err := conv.imageDecode(rc)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
return img
|
||||
}
|
||||
|
||||
func archiveHas(t *testing.T, conv *Converter, archive, name string) bool {
|
||||
t.Helper()
|
||||
|
||||
list, err := conv.archiveList(archive)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, n := range list {
|
||||
if n == name {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user