diff --git a/utils/techutils/techutils.go b/utils/techutils/techutils.go index 56d6a53f..4710aa76 100644 --- a/utils/techutils/techutils.go +++ b/utils/techutils/techutils.go @@ -496,13 +496,26 @@ func getExistingRootDir(path string, workingDirectoryToIndicators map[string][]s for wd := range workingDirectoryToIndicators { parentWd := filepath.Dir(wd) parentRoot := filepath.Dir(root) - if parentRoot != parentWd && strings.HasPrefix(root, wd) { + if parentRoot != parentWd && hasCompletePathPrefix(root, wd) { root = wd } } return } +// This functions checks if wd is a PATH prefix for root. Examples: +// root = dir1/dir2/dir3 | wd = dir1/dir --> false (wd is prefix to root, but is not actually a valid part of its path) +// root = dir1/dir2/dir3 | wd = dir1/dir2 --> true +func hasCompletePathPrefix(root, wd string) bool { + if !strings.HasPrefix(root, wd) { + return false + } + rootParts := strings.Split(root, string(filepath.Separator)) + wdParts := strings.Split(wd, string(filepath.Separator)) + idxToCheck := len(wdParts) - 1 + return rootParts[idxToCheck] == wdParts[idxToCheck] +} + // DetectedTechnologiesToSlice returns a string slice that includes all the names of the detected technologies. func DetectedTechnologiesToSlice(detected map[Technology]map[string][]string) []string { keys := make([]string, 0, len(detected)) diff --git a/utils/techutils/techutils_test.go b/utils/techutils/techutils_test.go index 0230e952..796e4d57 100644 --- a/utils/techutils/techutils_test.go +++ b/utils/techutils/techutils_test.go @@ -290,6 +290,17 @@ func TestGetExistingRootDir(t *testing.T) { }, expected: "directory", }, + { + // This test case checks that we capture the correct root when sub is a prefix to root, but not an actual path prefix + // Example: root = "dir1/dir2", sub = "dir" -> root indeed starts with 'dir' but 'dir' is not a path prefix to the root + name: "match root when root's letters start with sub's letters", + path: filepath.Join("dir3", "dir"), + workingDirectoryToIndicators: map[string][]string{ + filepath.Join("dir3", "dir"): {filepath.Join("dir3", "dir", "package.json")}, + "dir": {filepath.Join("dir", "package.json")}, + }, + expected: filepath.Join("dir3", "dir"), + }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { @@ -298,6 +309,39 @@ func TestGetExistingRootDir(t *testing.T) { } } +func TestHasCompletePathPrefix(t *testing.T) { + tests := []struct { + name string + root string + wd string + expected bool + }{ + { + name: "no prefix", + root: filepath.Join("dir1", "dir2"), + wd: filepath.Join("some", "other", "project"), + expected: false, + }, + { + name: "prefix but not a path prefix", + root: filepath.Join("dir1", "dir2"), + wd: "dir", + expected: false, + }, + { + name: "path prefix", + root: filepath.Join("dir1", "dir2"), + wd: "dir1", + expected: true, + }, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + assert.Equal(t, test.expected, hasCompletePathPrefix(test.root, test.wd)) + }) + } +} + func TestCleanSubDirectories(t *testing.T) { tests := []struct { name string @@ -531,6 +575,17 @@ func TestGetTechInformationFromWorkingDir(t *testing.T) { "dir4": {filepath.Join("dir4", "package.json")}, }, }, + { + name: "pnpmTestWithProvidedTechFromUser", + tech: Pnpm, + requestedDescriptors: make(map[Technology][]string), + techProvidedByUser: true, + expected: map[string][]string{ + filepath.Join("dir3", "dir"): {filepath.Join("dir3", "dir", "package.json")}, + "dir": {filepath.Join("dir", "package.json")}, + "dir4": {filepath.Join("dir4", "package.json")}, + }, + }, } for _, test := range tests {