aboutsummaryrefslogtreecommitdiff
path: root/internal/engine/facts_test.go
blob: 7d844a0fcf35e309ac4a6d003011726ff4075923 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
// SPDX-License-Identifier: GPL-3.0-or-later

package engine

import (
	"context"
	"os"
	"path/filepath"
	"testing"
	"time"

	"krino/internal/cond"
	"krino/internal/extract"
	"krino/internal/scan"
)

// contentFacts builds a *facts for a real text file, under a Dir whose
// ContentVariants is variants, for exercising B2's raw-release directly.
func contentFacts(t *testing.T, body string, variants []cond.Options) *facts {
	t.Helper()
	p := filepath.Join(t.TempDir(), "a.txt")
	if err := os.WriteFile(p, []byte(body), 0o644); err != nil {
		t.Fatal(err)
	}
	fi, err := os.Stat(p)
	if err != nil {
		t.Fatal(err)
	}
	e := &Engine{Extract: extract.New(), Now: time.Now}
	d := &Dir{Name: "d", ContentVariants: variants}
	file := scan.File{Path: p, Rel: "a.txt", Name: "a.txt", Size: fi.Size(), ModTime: fi.ModTime()}
	run := newMatchRun(e, d, context.Background(), time.Now(), []scan.File{file})
	return newFacts(run, file)
}

// TestContentReleasesRawWithOneVariant: B2. A directory whose rules use
// exactly one (ignoreCase, fold) variant releases the raw extracted text
// once that variant's normalised copy exists.
func TestContentReleasesRawWithOneVariant(t *testing.T) {
	f := contentFacts(t, "Hello World", []cond.Options{{IgnoreCase: true, Fold: false}})
	const want = "hello world"
	got, err := f.Content(true, false)
	if err != nil {
		t.Fatal(err)
	}
	if got != want {
		t.Fatalf("got %q, want %q", got, want)
	}
	if f.content != "" {
		t.Errorf("raw text not released with a single content variant: %q", f.content)
	}
	// A second call for the same (already cached) variant must still work
	// from normCache, without needing the released raw text.
	if got, err := f.Content(true, false); err != nil || got != want {
		t.Errorf("second call for the cached variant: got %q, %v, want %q", got, err, want)
	}
}

// TestContentKeepsRawWithTwoVariants: B2. A directory whose rules use two
// distinct variants must not release the raw text after the first: the
// second variant still needs it, and normalising it correctly (not from an
// emptied string) is the proof the raw text was kept.
func TestContentKeepsRawWithTwoVariants(t *testing.T) {
	f := contentFacts(t, "Hello World", []cond.Options{
		{IgnoreCase: true, Fold: false},
		{IgnoreCase: false, Fold: false},
	})
	if got, err := f.Content(true, false); err != nil || got != "hello world" {
		t.Fatalf("first variant: got %q, %v", got, err)
	}
	if f.content == "" {
		t.Fatal("raw text released after only the first of two variants")
	}
	if got, err := f.Content(false, false); err != nil || got != "Hello World" {
		t.Fatalf("second variant: got %q, %v, want the unfolded original (raw text must still be available)", got, err)
	}
}

// TestDisplayOriginalAbbreviatesHome: a duplicate's original is shown
// root-relative inside the root, and home-abbreviated outside it, the way
// every other user-visible path is; a path outside $HOME stays absolute.
func TestDisplayOriginalAbbreviatesHome(t *testing.T) {
	h := sandbox(t)
	root := filepath.Join(h, "downloads")
	for _, tt := range []struct{ orig, want string }{
		{filepath.Join(root, "x", "a.pdf"), "x/a.pdf"},
		{filepath.Join(h, "docs", "work", "a.pdf"), "~/docs/work/a.pdf"},
		{"/srv/share/a.pdf", "/srv/share/a.pdf"},
	} {
		if got := displayOriginal(tt.orig, root); got != tt.want {
			t.Errorf("displayOriginal(%q) = %q, want %q", tt.orig, got, tt.want)
		}
	}
}