@@ -3,129 +3,132 @@ package goformat
33import (
44 "os"
55 "path/filepath"
6- "regexp"
76 "testing"
87
98 "github.com/stretchr/testify/assert"
109 "github.com/stretchr/testify/require"
1110
12- "github.com/golangci/golangci-lint/v2/pkg/fsutils "
11+ "github.com/golangci/golangci-lint/v2/pkg/config "
1312)
1413
15- func TestMatchAnyPattern_WithSymlinks (t * testing.T ) {
16- // Create a temporary directory structure
17- tmpDir , err := os .MkdirTemp ("" , "golangci-symlink-test-*" )
18- require .NoError (t , err )
19- defer os .RemoveAll (tmpDir )
14+ func TestRunnerOptions_MatchAnyPattern (t * testing.T ) {
15+ testCases := []struct {
16+ desc string
17+ cfg * config.Config
18+ filename string
19+
20+ assertMatch assert.BoolAssertionFunc
21+ expectedCount int
22+ }{
23+ {
24+ desc : "match" ,
25+ cfg : & config.Config {
26+ Formatters : config.Formatters {
27+ Exclusions : config.FormatterExclusions {
28+ Paths : []string {`generated\.go` },
29+ },
30+ },
31+ },
32+ filename : "generated.go" ,
33+ assertMatch : assert .True ,
34+ expectedCount : 1 ,
35+ },
36+ {
37+ desc : "no match" ,
38+ cfg : & config.Config {
39+ Formatters : config.Formatters {
40+ Exclusions : config.FormatterExclusions {
41+ Paths : []string {`excluded\.go` },
42+ },
43+ },
44+ },
45+ filename : "test.go" ,
46+ assertMatch : assert .False ,
47+ expectedCount : 0 ,
48+ },
49+ {
50+ desc : "no patterns" ,
51+ cfg : & config.Config {},
52+ filename : "test.go" ,
53+ assertMatch : assert .False ,
54+ },
55+ }
2056
21- // Create two separate directories at the same level
22- realDir := filepath .Join (tmpDir , "real_project" )
23- err = os .MkdirAll (realDir , 0o755 )
24- require .NoError (t , err )
57+ for _ , test := range testCases {
58+ t .Run (test .desc , func (t * testing.T ) {
59+ t .Parallel ()
2560
26- testFile := filepath .Join (realDir , "test.go" )
27- err = os .WriteFile (testFile , []byte ("package main" ), 0o600 )
28- require .NoError (t , err )
61+ tmpDir := t .TempDir ()
2962
30- // Create a symlink in a completely different part of the tree
31- symlinkParent := filepath .Join (tmpDir , "symlinks" )
32- err = os .MkdirAll (symlinkParent , 0o755 )
33- require .NoError (t , err )
63+ testFile := filepath .Join (tmpDir , test .filename )
3464
35- symlinkDir := filepath .Join (symlinkParent , "project_link" )
36- err = os .Symlink (realDir , symlinkDir )
37- require .NoError (t , err )
65+ err := os .WriteFile (testFile , []byte ("package main" ), 0o600 )
66+ require .NoError (t , err )
3867
39- // Simulate the actual scenario:
40- // - basePath is the resolved real path (as fsutils.Getwd does when you're in a symlinked dir)
41- // - filepath.Walk from the symlink directory provides unresolved paths
42- // IMPORTANT: On macOS, tmpDir might be /var/... which is itself a symlink to /private/var/...
43- // So we need to evaluate basePath as well to simulate what fsutils.Getwd() does
44- resolvedBasePath , err := fsutils .EvalSymlinks (realDir )
45- require .NoError (t , err )
68+ test .cfg .SetConfigDir (tmpDir )
4669
47- // Create RunnerOptions with a pattern that matches files in the root directory only
48- // This pattern will match "test.go" but NOT "../../../test.go" or similar broken paths
49- pattern := regexp .MustCompile (`^[^/\\]+\.go$` )
50- opts := RunnerOptions {
51- basePath : resolvedBasePath , // Resolved path from Getwd
52- patterns : []* regexp.Regexp {pattern },
53- excludedPathCounter : map [* regexp.Regexp ]int {pattern : 0 },
54- }
70+ opts , err := NewRunnerOptions (test .cfg , false , false , false )
71+ require .NoError (t , err )
5572
56- // filepath.Walk would provide the path through the symlink
57- // When you cd into a symlink and run the command, Walk uses the symlink path
58- unresolvedFile := filepath .Join (symlinkDir , "test.go" )
59-
60- // The issue: When basePath is resolved (e.g., /private/var/...)
61- // but the file path from filepath.Walk is unresolved (e.g., /var/...),
62- // filepath.Rel produces an incorrect relative path with many ../ components
63- // like "../../../../var/.../test.go" which won't match the pattern ^[^/\\]+\.go$
64- //
65- // The fix: EvalSymlinks on the file path before calling filepath.Rel
66- // ensures both paths are in their canonical form, producing "test.go"
67- // which correctly matches the pattern.
68-
69- match , err := opts .MatchAnyPattern (unresolvedFile )
70-
71- // With the fix, pattern matching should work correctly
72- require .NoError (t , err , "Should not error when matching pattern with symlinks" )
73- assert .True (t , match , "Pattern should match test.go when accessed through symlink" )
74- assert .Equal (t , 1 , opts .excludedPathCounter [pattern ], "Counter should be incremented" )
75- }
73+ match , err := opts .MatchAnyPattern (testFile )
74+ require .NoError (t , err )
7675
77- func TestMatchAnyPattern_NoPatterns (t * testing.T ) {
78- opts := RunnerOptions {
79- basePath : "/tmp" ,
80- patterns : []* regexp.Regexp {},
81- excludedPathCounter : map [* regexp.Regexp ]int {},
82- }
76+ test .assertMatch (t , match )
8377
84- match , err := opts .MatchAnyPattern ("/tmp/test.go" )
85- require .NoError (t , err )
86- assert .False (t , match , "Should not match when no patterns are defined" )
78+ require .Len (t , opts .patterns , len (test .cfg .Formatters .Exclusions .Paths ))
79+
80+ if len (opts .patterns ) == 0 {
81+ assert .Empty (t , opts .excludedPathCounter )
82+ } else {
83+ assert .Equal (t , test .expectedCount , opts .excludedPathCounter [opts .patterns [0 ]])
84+ }
85+ })
86+ }
8787}
8888
89- func TestMatchAnyPattern_NoMatch (t * testing.T ) {
90- tmpDir , err := os .MkdirTemp ("" , "golangci-test-*" )
89+ func TestRunnerOptions_MatchAnyPattern_withSymlinks (t * testing.T ) {
90+ tmpDir := t .TempDir ()
91+
92+ testFile := filepath .Join (tmpDir , "project" , "test.go" )
93+
94+ realDir := filepath .Dir (testFile )
95+
96+ err := os .MkdirAll (realDir , 0o755 )
9197 require .NoError (t , err )
92- defer os .RemoveAll (tmpDir )
9398
94- testFile := filepath .Join (tmpDir , "test.go" )
9599 err = os .WriteFile (testFile , []byte ("package main" ), 0o600 )
96100 require .NoError (t , err )
97101
98- pattern := regexp .MustCompile (`excluded\.go` )
99- opts := RunnerOptions {
100- basePath : tmpDir ,
101- patterns : []* regexp.Regexp {pattern },
102- excludedPathCounter : map [* regexp.Regexp ]int {pattern : 0 },
103- }
102+ // Create a symlink in a completely different part of the tree.
103+ symlink := filepath .Join (tmpDir , "somewhere" , "symlink" )
104104
105- match , err := opts . MatchAnyPattern ( testFile )
105+ err = os . MkdirAll ( filepath . Dir ( symlink ), 0o755 )
106106 require .NoError (t , err )
107- assert .False (t , match , "Pattern should not match test.go" )
108- assert .Equal (t , 0 , opts .excludedPathCounter [pattern ], "Counter should not be incremented" )
109- }
110107
111- func TestMatchAnyPattern_WithMatch (t * testing.T ) {
112- tmpDir , err := os .MkdirTemp ("" , "golangci-test-*" )
108+ err = os .Symlink (realDir , symlink )
113109 require .NoError (t , err )
114- defer os .RemoveAll (tmpDir )
115110
116- testFile := filepath .Join (tmpDir , "generated.go" )
117- err = os .WriteFile (testFile , []byte ("package main" ), 0o600 )
118- require .NoError (t , err )
119-
120- pattern := regexp .MustCompile (`generated\.go` )
121- opts := RunnerOptions {
122- basePath : tmpDir ,
123- patterns : []* regexp.Regexp {pattern },
124- excludedPathCounter : map [* regexp.Regexp ]int {pattern : 0 },
111+ cfg := & config.Config {
112+ Formatters : config.Formatters {
113+ Exclusions : config.FormatterExclusions {
114+ // Creates a pattern that matches files in the root directory only.
115+ // This pattern will match `test.go" but not `../../../test.go` or similar broken paths.
116+ Paths : []string {`^[^/\\]+\.go$` },
117+ },
118+ },
125119 }
120+ cfg .SetConfigDir (realDir )
121+
122+ opts , err := NewRunnerOptions (cfg , false , false , false )
123+ require .NoError (t , err )
126124
127- match , err := opts .MatchAnyPattern (testFile )
125+ match , err := opts .MatchAnyPattern (filepath . Join ( symlink , "test.go" ) )
128126 require .NoError (t , err )
129- assert .True (t , match , "Pattern should match generated.go" )
130- assert .Equal (t , 1 , opts .excludedPathCounter [pattern ], "Counter should be incremented" )
127+
128+ assert .True (t , match )
129+
130+ require .NotEmpty (t , opts .patterns )
131+ require .Len (t , opts .patterns , len (cfg .Formatters .Exclusions .Paths ))
132+
133+ assert .Equal (t , 1 , opts .excludedPathCounter [opts .patterns [0 ]])
131134}
0 commit comments