@@ -20,12 +20,14 @@ import (
2020 "os"
2121 "reflect"
2222 "testing"
23+ "time"
2324
2425 "github.com/arduino/arduino-lint/internal/configuration"
2526 "github.com/arduino/arduino-lint/internal/project/projecttype"
2627 "github.com/arduino/arduino-lint/internal/util/test"
2728 "github.com/arduino/go-paths-helper"
2829 "github.com/stretchr/testify/assert"
30+ "github.com/stretchr/testify/require"
2931)
3032
3133var testDataPath * paths.Path
@@ -38,6 +40,50 @@ func init() {
3840 testDataPath = paths .New (workingDirectory , "testdata" )
3941}
4042
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+
4187func TestFindProjects (t * testing.T ) {
4288 sketchPath := testDataPath .Join ("Sketch" )
4389 libraryPath := testDataPath .Join ("Library" )
0 commit comments