Update golangci-lint to v2.12.2 with canonical config (closes #60)
check / check (push) Has been cancelled
check / check (push) Has been cancelled
Adopts golangci-lint v2.12.2 and the canonical .golangci.yml (default: all), and fixes all resulting findings across the tree. Two intended behavior changes: absent MFFilePath.Mtime is handled explicitly in freshen, list and export rather than dereferenced (main panicked); gpg positional key IDs now follow an explicit -- end-of-options marker. All twelve reworded user-visible error messages restored to byte-identical parity with main and pinned by tests.
This commit was merged in pull request #59.
This commit is contained in:
+84
-17
@@ -1,3 +1,4 @@
|
||||
//nolint:testpackage // white-box tests exercise unexported internals
|
||||
package mfer
|
||||
|
||||
import (
|
||||
@@ -12,6 +13,8 @@ import (
|
||||
)
|
||||
|
||||
func TestNewScanner(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
s := NewScanner()
|
||||
assert.NotNil(t, s)
|
||||
assert.Equal(t, FileCount(0), s.FileCount())
|
||||
@@ -19,12 +22,18 @@ func TestNewScanner(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestNewScannerWithOptions(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
t.Run("nil options", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
s := NewScannerWithOptions(nil)
|
||||
assert.NotNil(t, s)
|
||||
})
|
||||
|
||||
t.Run("with options", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
fs := afero.NewMemMapFs()
|
||||
opts := &ScannerOptions{
|
||||
IncludeDotfiles: true,
|
||||
@@ -37,6 +46,8 @@ func TestNewScannerWithOptions(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestScannerEnumerateFile(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
fs := afero.NewMemMapFs()
|
||||
require.NoError(t, afero.WriteFile(fs, "/test.txt", []byte("hello world"), 0o644))
|
||||
|
||||
@@ -54,6 +65,8 @@ func TestScannerEnumerateFile(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestScannerEnumerateFileMissing(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
fs := afero.NewMemMapFs()
|
||||
s := NewScannerWithOptions(&ScannerOptions{Fs: fs})
|
||||
err := s.EnumerateFile("/nonexistent.txt")
|
||||
@@ -61,11 +74,14 @@ func TestScannerEnumerateFileMissing(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestScannerEnumeratePath(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
fs := afero.NewMemMapFs()
|
||||
require.NoError(t, fs.MkdirAll("/testdir/subdir", 0o755))
|
||||
require.NoError(t, afero.WriteFile(fs, "/testdir/file1.txt", []byte("one"), 0o644))
|
||||
require.NoError(t, afero.WriteFile(fs, "/testdir/file2.txt", []byte("two"), 0o644))
|
||||
require.NoError(t, afero.WriteFile(fs, "/testdir/subdir/file3.txt", []byte("three"), 0o644))
|
||||
require.NoError(t,
|
||||
afero.WriteFile(fs, "/testdir/subdir/file3.txt", []byte("three"), 0o644))
|
||||
|
||||
s := NewScannerWithOptions(&ScannerOptions{Fs: fs})
|
||||
err := s.EnumeratePath("/testdir", nil)
|
||||
@@ -76,6 +92,8 @@ func TestScannerEnumeratePath(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestScannerEnumeratePathWithProgress(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
fs := afero.NewMemMapFs()
|
||||
require.NoError(t, fs.MkdirAll("/testdir", 0o755))
|
||||
require.NoError(t, afero.WriteFile(fs, "/testdir/file1.txt", []byte("one"), 0o644))
|
||||
@@ -100,6 +118,8 @@ func TestScannerEnumeratePathWithProgress(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestScannerEnumeratePaths(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
fs := afero.NewMemMapFs()
|
||||
require.NoError(t, fs.MkdirAll("/dir1", 0o755))
|
||||
require.NoError(t, fs.MkdirAll("/dir2", 0o755))
|
||||
@@ -114,13 +134,20 @@ func TestScannerEnumeratePaths(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestScannerExcludeDotfiles(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
fs := afero.NewMemMapFs()
|
||||
require.NoError(t, fs.MkdirAll("/testdir/.hidden", 0o755))
|
||||
require.NoError(t, afero.WriteFile(fs, "/testdir/visible.txt", []byte("visible"), 0o644))
|
||||
require.NoError(t, afero.WriteFile(fs, "/testdir/.hidden.txt", []byte("hidden"), 0o644))
|
||||
require.NoError(t, afero.WriteFile(fs, "/testdir/.hidden/inside.txt", []byte("inside"), 0o644))
|
||||
require.NoError(t,
|
||||
afero.WriteFile(fs, "/testdir/visible.txt", []byte("visible"), 0o644))
|
||||
require.NoError(t,
|
||||
afero.WriteFile(fs, "/testdir/.hidden.txt", []byte("hidden"), 0o644))
|
||||
require.NoError(t,
|
||||
afero.WriteFile(fs, "/testdir/.hidden/inside.txt", []byte("inside"), 0o644))
|
||||
|
||||
t.Run("exclude by default", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
s := NewScannerWithOptions(&ScannerOptions{Fs: fs, IncludeDotfiles: false})
|
||||
err := s.EnumeratePath("/testdir", nil)
|
||||
require.NoError(t, err)
|
||||
@@ -131,6 +158,8 @@ func TestScannerExcludeDotfiles(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("include when enabled", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
s := NewScannerWithOptions(&ScannerOptions{Fs: fs, IncludeDotfiles: true})
|
||||
err := s.EnumeratePath("/testdir", nil)
|
||||
require.NoError(t, err)
|
||||
@@ -140,34 +169,43 @@ func TestScannerExcludeDotfiles(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestScannerToManifest(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
fs := afero.NewMemMapFs()
|
||||
require.NoError(t, fs.MkdirAll("/testdir", 0o755))
|
||||
require.NoError(t, afero.WriteFile(fs, "/testdir/file1.txt", []byte("content one"), 0o644))
|
||||
require.NoError(t, afero.WriteFile(fs, "/testdir/file2.txt", []byte("content two"), 0o644))
|
||||
require.NoError(t,
|
||||
afero.WriteFile(fs, "/testdir/file1.txt", []byte("content one"), 0o644))
|
||||
require.NoError(t,
|
||||
afero.WriteFile(fs, "/testdir/file2.txt", []byte("content two"), 0o644))
|
||||
|
||||
s := NewScannerWithOptions(&ScannerOptions{Fs: fs})
|
||||
err := s.EnumeratePath("/testdir", nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
var buf bytes.Buffer
|
||||
|
||||
err = s.ToManifest(context.Background(), &buf, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Manifest should have magic bytes
|
||||
assert.True(t, buf.Len() > 0)
|
||||
assert.Positive(t, buf.Len())
|
||||
assert.Equal(t, MAGIC, string(buf.Bytes()[:8]))
|
||||
}
|
||||
|
||||
func TestScannerToManifestWithProgress(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
fs := afero.NewMemMapFs()
|
||||
require.NoError(t, fs.MkdirAll("/testdir", 0o755))
|
||||
require.NoError(t, afero.WriteFile(fs, "/testdir/file.txt", bytes.Repeat([]byte("x"), 1000), 0o644))
|
||||
require.NoError(t,
|
||||
afero.WriteFile(fs, "/testdir/file.txt", bytes.Repeat([]byte("x"), 1000), 0o644))
|
||||
|
||||
s := NewScannerWithOptions(&ScannerOptions{Fs: fs})
|
||||
err := s.EnumeratePath("/testdir", nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
var buf bytes.Buffer
|
||||
|
||||
progress := make(chan ScanStatus, 10)
|
||||
|
||||
err = s.ToManifest(context.Background(), &buf, progress)
|
||||
@@ -188,12 +226,15 @@ func TestScannerToManifestWithProgress(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestScannerToManifestContextCancellation(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
fs := afero.NewMemMapFs()
|
||||
require.NoError(t, fs.MkdirAll("/testdir", 0o755))
|
||||
// Create many files to ensure we have time to cancel
|
||||
for i := 0; i < 100; i++ {
|
||||
for i := range 100 {
|
||||
name := string(rune('a'+i%26)) + string(rune('0'+i/26)) + ".txt"
|
||||
require.NoError(t, afero.WriteFile(fs, "/testdir/"+name, bytes.Repeat([]byte("x"), 100), 0o644))
|
||||
require.NoError(t,
|
||||
afero.WriteFile(fs, "/testdir/"+name, bytes.Repeat([]byte("x"), 100), 0o644))
|
||||
}
|
||||
|
||||
s := NewScannerWithOptions(&ScannerOptions{Fs: fs})
|
||||
@@ -204,24 +245,30 @@ func TestScannerToManifestContextCancellation(t *testing.T) {
|
||||
cancel() // Cancel immediately
|
||||
|
||||
var buf bytes.Buffer
|
||||
|
||||
err = s.ToManifest(ctx, &buf, nil)
|
||||
assert.ErrorIs(t, err, context.Canceled)
|
||||
}
|
||||
|
||||
func TestScannerToManifestEmptyScanner(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
fs := afero.NewMemMapFs()
|
||||
s := NewScannerWithOptions(&ScannerOptions{Fs: fs})
|
||||
|
||||
var buf bytes.Buffer
|
||||
|
||||
err := s.ToManifest(context.Background(), &buf, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Should still produce a valid manifest
|
||||
assert.True(t, buf.Len() > 0)
|
||||
assert.Positive(t, buf.Len())
|
||||
assert.Equal(t, MAGIC, string(buf.Bytes()[:8]))
|
||||
}
|
||||
|
||||
func TestScannerFilesCopiesSlice(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
fs := afero.NewMemMapFs()
|
||||
require.NoError(t, afero.WriteFile(fs, "/test.txt", []byte("hello"), 0o644))
|
||||
|
||||
@@ -236,10 +283,13 @@ func TestScannerFilesCopiesSlice(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestScannerEnumerateFS(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
fs := afero.NewMemMapFs()
|
||||
require.NoError(t, fs.MkdirAll("/testdir/sub", 0o755))
|
||||
require.NoError(t, afero.WriteFile(fs, "/testdir/file.txt", []byte("hello"), 0o644))
|
||||
require.NoError(t, afero.WriteFile(fs, "/testdir/sub/nested.txt", []byte("world"), 0o644))
|
||||
require.NoError(t,
|
||||
afero.WriteFile(fs, "/testdir/sub/nested.txt", []byte("world"), 0o644))
|
||||
|
||||
// Create a basepath filesystem
|
||||
baseFs := afero.NewBasePathFs(fs, "/testdir")
|
||||
@@ -252,13 +302,17 @@ func TestScannerEnumerateFS(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestSendEnumerateStatusNonBlocking(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
// Channel with no buffer - send should not block
|
||||
ch := make(chan EnumerateStatus)
|
||||
|
||||
// This should not block
|
||||
done := make(chan bool)
|
||||
|
||||
go func() {
|
||||
sendEnumerateStatus(ch, EnumerateStatus{FilesFound: 1})
|
||||
|
||||
done <- true
|
||||
}()
|
||||
|
||||
@@ -271,12 +325,16 @@ func TestSendEnumerateStatusNonBlocking(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestSendScanStatusNonBlocking(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
// Channel with no buffer - send should not block
|
||||
ch := make(chan ScanStatus)
|
||||
|
||||
done := make(chan bool)
|
||||
|
||||
go func() {
|
||||
sendScanStatus(ch, ScanStatus{ScannedFiles: 1})
|
||||
|
||||
done <- true
|
||||
}()
|
||||
|
||||
@@ -289,14 +347,19 @@ func TestSendScanStatusNonBlocking(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestSendStatusNilChannel(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
// Should not panic with nil channel
|
||||
sendEnumerateStatus(nil, EnumerateStatus{})
|
||||
sendScanStatus(nil, ScanStatus{})
|
||||
}
|
||||
|
||||
func TestScannerFileEntryFields(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
fs := afero.NewMemMapFs()
|
||||
now := time.Now().Truncate(time.Second)
|
||||
|
||||
require.NoError(t, afero.WriteFile(fs, "/test.txt", []byte("content"), 0o644))
|
||||
require.NoError(t, fs.Chtimes("/test.txt", now, now))
|
||||
|
||||
@@ -315,11 +378,13 @@ func TestScannerFileEntryFields(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestScannerLargeFileEnumeration(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
fs := afero.NewMemMapFs()
|
||||
require.NoError(t, fs.MkdirAll("/testdir", 0o755))
|
||||
|
||||
// Create 100 files
|
||||
for i := 0; i < 100; i++ {
|
||||
for i := range 100 {
|
||||
name := "/testdir/" + string(rune('a'+i%26)) + string(rune('0'+i/26%10)) + ".txt"
|
||||
require.NoError(t, afero.WriteFile(fs, name, []byte("data"), 0o644))
|
||||
}
|
||||
@@ -330,20 +395,20 @@ func TestScannerLargeFileEnumeration(t *testing.T) {
|
||||
err := s.EnumeratePath("/testdir", progress)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Drain channel
|
||||
for range progress {
|
||||
}
|
||||
// progress is fully buffered and closed; no draining needed
|
||||
|
||||
assert.Equal(t, FileCount(100), s.FileCount())
|
||||
assert.Equal(t, FileSize(400), s.TotalBytes()) // 100 * 4 bytes
|
||||
}
|
||||
|
||||
func TestIsHiddenPath(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
path string
|
||||
hidden bool
|
||||
}{
|
||||
{"file.txt", false},
|
||||
{testFileName, false},
|
||||
{".hidden", true},
|
||||
{"dir/file.txt", false},
|
||||
{"dir/.hidden", true},
|
||||
@@ -360,6 +425,8 @@ func TestIsHiddenPath(t *testing.T) {
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.path, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert.Equal(t, tt.hidden, IsHiddenPath(tt.path), "IsHiddenPath(%q)", tt.path)
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user