add fs lib to walk file tree
This commit is contained in:
@@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
This file has the raw file io operations that are used by FsTree
|
||||||
|
or elsewhere in the app. Nowhere else should there be a direct
|
||||||
|
fileopen
|
||||||
|
|
||||||
|
- ruinivist, 30Dec25
|
||||||
|
*/
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
)
|
||||||
|
|
||||||
|
func walkFileSystemAndBuildTree(rootPath string, node *FsNode) error {
|
||||||
|
if node == nil {
|
||||||
|
return errors.New("node cannot be nil")
|
||||||
|
}
|
||||||
|
if len(node.children) > 0 {
|
||||||
|
return errors.New("node already has children")
|
||||||
|
}
|
||||||
|
|
||||||
|
entries, err := os.ReadDir(rootPath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, entry := range entries {
|
||||||
|
childPath := filepath.Join(rootPath, entry.Name())
|
||||||
|
|
||||||
|
var nodeType FsNodeType
|
||||||
|
if entry.IsDir() {
|
||||||
|
nodeType = FolderNode
|
||||||
|
} else {
|
||||||
|
nodeType = FileNode
|
||||||
|
}
|
||||||
|
|
||||||
|
childNode := &FsNode{
|
||||||
|
nodeType: nodeType,
|
||||||
|
path: childPath,
|
||||||
|
children: make([]*FsNode, 0),
|
||||||
|
parent: node,
|
||||||
|
expanded: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
node.children = append(node.children, childNode)
|
||||||
|
|
||||||
|
// Recursively walk subdirectories
|
||||||
|
if entry.IsDir() {
|
||||||
|
if err := walkFileSystemAndBuildTree(childPath, childNode); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
+153
@@ -0,0 +1,153 @@
|
|||||||
|
/*
|
||||||
|
another test that is entirely ae ayee generated
|
||||||
|
- ruinivist, 30Dec25
|
||||||
|
*/
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestWalkFileSystemAndBuildTree(t *testing.T) {
|
||||||
|
t.Run("build tree from real directory", func(t *testing.T) {
|
||||||
|
// Create temporary directory structure
|
||||||
|
tmpDir := t.TempDir()
|
||||||
|
|
||||||
|
// Create test structure:
|
||||||
|
// tmpDir/
|
||||||
|
// file1.txt
|
||||||
|
// file2.go
|
||||||
|
// folder1/
|
||||||
|
// nested.txt
|
||||||
|
// folder2/
|
||||||
|
os.WriteFile(filepath.Join(tmpDir, "file1.txt"), []byte("content"), 0644)
|
||||||
|
os.WriteFile(filepath.Join(tmpDir, "file2.go"), []byte("code"), 0644)
|
||||||
|
os.Mkdir(filepath.Join(tmpDir, "folder1"), 0755)
|
||||||
|
os.WriteFile(filepath.Join(tmpDir, "folder1", "nested.txt"), []byte("nested"), 0644)
|
||||||
|
os.Mkdir(filepath.Join(tmpDir, "folder2"), 0755)
|
||||||
|
|
||||||
|
// Build tree
|
||||||
|
root := &FsNode{
|
||||||
|
nodeType: FolderNode,
|
||||||
|
path: tmpDir,
|
||||||
|
children: make([]*FsNode, 0),
|
||||||
|
expanded: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
err := walkFileSystemAndBuildTree(tmpDir, root)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("walkFileSystemAndBuildTree() error = %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify structure
|
||||||
|
if len(root.children) != 4 {
|
||||||
|
t.Fatalf("root children count = %d, want 4", len(root.children))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check children exist and have correct types
|
||||||
|
fileCount := 0
|
||||||
|
folderCount := 0
|
||||||
|
var folder1 *FsNode
|
||||||
|
|
||||||
|
for _, child := range root.children {
|
||||||
|
if child.parent != root {
|
||||||
|
t.Errorf("child %q parent pointer incorrect", child.FileName())
|
||||||
|
}
|
||||||
|
|
||||||
|
if child.nodeType == FileNode {
|
||||||
|
fileCount++
|
||||||
|
} else if child.nodeType == FolderNode {
|
||||||
|
folderCount++
|
||||||
|
if child.FileName() == "folder1" {
|
||||||
|
folder1 = child
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if fileCount != 2 {
|
||||||
|
t.Errorf("file count = %d, want 2", fileCount)
|
||||||
|
}
|
||||||
|
if folderCount != 2 {
|
||||||
|
t.Errorf("folder count = %d, want 2", folderCount)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify nested structure
|
||||||
|
if folder1 == nil {
|
||||||
|
t.Fatal("folder1 not found")
|
||||||
|
}
|
||||||
|
if len(folder1.children) != 1 {
|
||||||
|
t.Errorf("folder1 children count = %d, want 1", len(folder1.children))
|
||||||
|
}
|
||||||
|
if folder1.children[0].FileName() != "nested.txt" {
|
||||||
|
t.Errorf("nested file name = %q, want %q", folder1.children[0].FileName(), "nested.txt")
|
||||||
|
}
|
||||||
|
if folder1.children[0].nodeType != FileNode {
|
||||||
|
t.Errorf("nested node type = %v, want %v", folder1.children[0].nodeType, FileNode)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("error when node is nil", func(t *testing.T) {
|
||||||
|
tmpDir := t.TempDir()
|
||||||
|
err := walkFileSystemAndBuildTree(tmpDir, nil)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("walkFileSystemAndBuildTree() with nil node should return error")
|
||||||
|
}
|
||||||
|
if err.Error() != "node cannot be nil" {
|
||||||
|
t.Errorf("error message = %q", err.Error())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("error when node already has children", func(t *testing.T) {
|
||||||
|
tmpDir := t.TempDir()
|
||||||
|
root := &FsNode{
|
||||||
|
nodeType: FolderNode,
|
||||||
|
path: tmpDir,
|
||||||
|
children: []*FsNode{{nodeType: FileNode, path: "dummy"}},
|
||||||
|
expanded: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
err := walkFileSystemAndBuildTree(tmpDir, root)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("walkFileSystemAndBuildTree() with existing children should return error")
|
||||||
|
}
|
||||||
|
if err.Error() != "node already has children" {
|
||||||
|
t.Errorf("error message = %q", err.Error())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("error when path does not exist", func(t *testing.T) {
|
||||||
|
root := &FsNode{
|
||||||
|
nodeType: FolderNode,
|
||||||
|
path: "/nonexistent/path",
|
||||||
|
children: make([]*FsNode, 0),
|
||||||
|
expanded: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
err := walkFileSystemAndBuildTree("/nonexistent/path", root)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("walkFileSystemAndBuildTree() with nonexistent path should return error")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("empty directory", func(t *testing.T) {
|
||||||
|
tmpDir := t.TempDir()
|
||||||
|
root := &FsNode{
|
||||||
|
nodeType: FolderNode,
|
||||||
|
path: tmpDir,
|
||||||
|
children: make([]*FsNode, 0),
|
||||||
|
expanded: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
err := walkFileSystemAndBuildTree(tmpDir, root)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("walkFileSystemAndBuildTree() error = %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(root.children) != 0 {
|
||||||
|
t.Errorf("empty directory should have 0 children, got %d", len(root.children))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user