Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 49 additions & 5 deletions internal/builder/builder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package builder

import (
"os"
"strings"
"testing"

"github.com/neomen/buildtree/internal/parser"
Expand All @@ -13,7 +14,8 @@ func TestBuildTree_SimpleStructure(t *testing.T) {
if err != nil {
t.Fatal(err)
}
defer os.Chdir(originalDir) // Восстанавливаем оригинальную директорию
// Restoring the original directory
defer os.Chdir(originalDir)

err = os.Chdir(tempDir)
if err != nil {
Expand Down Expand Up @@ -402,7 +404,8 @@ func TestBuildTree_WindowsReservedNames(t *testing.T) {
Level: 0,
Children: []*parser.Node{
{
Name: "CON", // Windows reserved name
// Windows reserved name
Name: "CON",
IsDir: true,
Level: 1,
},
Expand All @@ -412,7 +415,8 @@ func TestBuildTree_WindowsReservedNames(t *testing.T) {
Level: 1,
},
{
Name: "LPT1", // Windows reserved name
// Windows reserved name
Name: "LPT1",
IsDir: false,
Level: 1,
},
Expand All @@ -430,8 +434,35 @@ func TestBuildTree_WindowsReservedNames(t *testing.T) {
}

// Check that Windows reserved names were not created
assertNotExists(t, "project/CON")
assertNotExists(t, "project/LPT1")
// On Windows, we can't use standard methods to check for reserved names
// as they get redirected to devices. Instead, we check the directory contents.
entries, err := os.ReadDir("project")
if err != nil {
t.Fatalf("Error reading project directory: %v", err)
}

// Check that only normal names were created
foundNormalDir := false
foundNormalFile := false

for _, entry := range entries {
name := entry.Name()
switch name {
case "normal_dir":
foundNormalDir = true
case "normal_file.txt":
foundNormalFile = true
case "CON", "LPT1":
t.Errorf("Reserved name %s was created but should not be", name)
}
}

if !foundNormalDir {
t.Error("Normal directory was not created")
}
if !foundNormalFile {
t.Error("Normal file was not created")
}

// Check that normal names were created
assertDirExists(t, "project/normal_dir")
Expand Down Expand Up @@ -496,7 +527,20 @@ func assertNotExists(t *testing.T, path string) {
t.Errorf("Expected %s to not exist, but it does", path)
return
}

// On Windows, we ignore errors related to invalid file names
// as this is the expected behavior
if !os.IsNotExist(err) {
// Checking if the error is related to an invalid file name in Windows
if isWindowsInvalidNameError(err) {
// This is the expected behavior for Windows, so we don't consider it an error
return
}
t.Errorf("Unexpected error checking if %s exists: %v", path, err)
}
}

// isWindowsInvalidNameError checks if the error is related to an invalid file name in Windows
func isWindowsInvalidNameError(err error) bool {
return strings.Contains(err.Error(), "The filename, directory name, or volume label syntax is incorrect")
}
19 changes: 10 additions & 9 deletions internal/parser/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ func ParseInput(input string) (*Node, error) {
input = normalizeTreeSymbols(input)
lines := strings.Split(input, "\n")

// Проверяем, что ввод не пустой после обработки
// Check that the input is not empty after processing
if strings.TrimSpace(input) == "" {
return nil, ErrEmptyInput
}
Expand Down Expand Up @@ -100,7 +100,7 @@ func ParseInput(input string) (*Node, error) {
}

func parseLine(line string) (level int, name string, isDir bool) {
// Удаляем комментарии в начале
// Deleting comments at the beginning
if idx := strings.Index(line, "#"); idx != -1 {
line = line[:idx]
}
Expand All @@ -124,14 +124,14 @@ func parseLine(line string) (level int, name string, isDir bool) {
realLevel := level / 4
name = extractName(remaining)

// Проверяем, является ли это директорией
// Checking if this is a directory
if strings.HasSuffix(name, "/") {
isDir = true
name = strings.TrimSuffix(name, "/")
} else {
// Проверяем, есть ли у имени расширение
// Если нет точки в имени, возможно, это директория без слеша
// Это эвристика, можно улучшить
// Checking if the name has an extension
// If there is no dot in the name, it is possible that it is a directory without a slash
// This is a heuristic, it can be improved
if !strings.Contains(name, ".") && !strings.Contains(name, string(os.PathSeparator)) {
isDir = true
}
Expand All @@ -143,14 +143,14 @@ func parseLine(line string) (level int, name string, isDir bool) {
func extractName(line string) string {
name := strings.TrimSpace(line)

// Удаляем все возможные префиксы элементов дерева
// Removing all possible prefixes of tree elements
prefixes := []string{"── ", "-- ", "─ ", "- ", "└──", "├──", "│", "└─", "├─", "└", "├"}
for _, prefix := range prefixes {
name = strings.TrimPrefix(name, prefix)
}
name = strings.TrimSpace(name)

// Удаляем любые оставшиеся символы деревьев из начала имени
// Remove any remaining tree characters from the beginning of the name
for strings.HasPrefix(name, "├") || strings.HasPrefix(name, "└") ||
strings.HasPrefix(name, "│") || strings.HasPrefix(name, "─") ||
strings.HasPrefix(name, "|") || strings.HasPrefix(name, "-") {
Expand All @@ -163,14 +163,15 @@ func extractName(line string) string {
name = strings.TrimSpace(name)
}

// Удаляем комментарии в конце
// Deleting comments at the end
if idx := strings.Index(name, "#"); idx != -1 {
name = strings.TrimSpace(name[:idx])
}

return name
}

// Bringing different types of tree to a uniform condition
func normalizeTreeSymbols(input string) string {
input = strings.ReplaceAll(input, "|--", "├──")
input = strings.ReplaceAll(input, "'--", "└──")
Expand Down
Loading