@@ -20,12 +20,14 @@ import (
20
20
"os"
21
21
"reflect"
22
22
"testing"
23
+ "time"
23
24
24
25
"github.com/arduino/arduino-lint/internal/configuration"
25
26
"github.com/arduino/arduino-lint/internal/project/projecttype"
26
27
"github.com/arduino/arduino-lint/internal/util/test"
27
28
"github.com/arduino/go-paths-helper"
28
29
"github.com/stretchr/testify/assert"
30
+ "github.com/stretchr/testify/require"
29
31
)
30
32
31
33
var testDataPath * paths.Path
@@ -38,6 +40,50 @@ func init() {
38
40
testDataPath = paths .New (workingDirectory , "testdata" )
39
41
}
40
42
43
+ func TestSymlinkLoop (t * testing.T ) {
44
+ // Set up directory structure of test library.
45
+ libraryPath , err := paths .TempDir ().MkTempDir ("TestSymlinkLoop" )
46
+ defer libraryPath .RemoveAll () // Clean up after the test.
47
+ require .Nil (t , err )
48
+ err = libraryPath .Join ("TestSymlinkLoop.h" ).WriteFile ([]byte {})
49
+ require .Nil (t , err )
50
+ examplesPath := libraryPath .Join ("examples" )
51
+ err = examplesPath .Mkdir ()
52
+ require .Nil (t , err )
53
+
54
+ // It's probably most friendly for contributors using Windows to create the symlinks needed for the test on demand.
55
+ err = os .Symlink (examplesPath .Join (".." ).String (), examplesPath .Join ("UpGoer1" ).String ())
56
+ require .Nil (t , err , "This test must be run as administrator on Windows to have symlink creation privilege." )
57
+ // It's necessary to have multiple symlinks to a parent directory to create the loop.
58
+ err = os .Symlink (examplesPath .Join (".." ).String (), examplesPath .Join ("UpGoer2" ).String ())
59
+ require .Nil (t , err )
60
+
61
+ configuration .Initialize (test .ConfigurationFlags (), []string {libraryPath .String ()})
62
+
63
+ // The failure condition is FindProjects() never returning, testing for which requires setting up a timeout.
64
+ done := make (chan bool )
65
+ go func () {
66
+ _ , err = FindProjects ()
67
+ done <- true
68
+ }()
69
+
70
+ assert .Eventually (
71
+ t ,
72
+ func () bool {
73
+ select {
74
+ case <- done :
75
+ return true
76
+ default :
77
+ return false
78
+ }
79
+ },
80
+ 20 * time .Second ,
81
+ 10 * time .Millisecond ,
82
+ "Infinite symlink loop during project discovery" ,
83
+ )
84
+ require .Nil (t , err )
85
+ }
86
+
41
87
func TestFindProjects (t * testing.T ) {
42
88
sketchPath := testDataPath .Join ("Sketch" )
43
89
libraryPath := testDataPath .Join ("Library" )
0 commit comments