add test suite
This commit is contained in:
@@ -84,7 +84,7 @@ func Write(result *walker.Result, outputPath string, appendMode bool, singleFile
|
||||
language := extToLang(filepath.Ext(entry.RelPath))
|
||||
lines := countLines(content)
|
||||
|
||||
fmt.Fprintf(&sb, "--- FILE: ./%s (%d bytes, %d lines) ---\n", entry.RelPath, entry.Size, lines)
|
||||
fmt.Fprintf(&sb, "--- FILE: ./%s (%d bytes, %d lines) ---\n", entry.RelPath, len(content), lines)
|
||||
fmt.Fprintf(&sb, "%s", fenceChars)
|
||||
if language != "" {
|
||||
fmt.Fprintf(&sb, "%s", language)
|
||||
@@ -161,7 +161,7 @@ func WriteSlices(result *walker.Result, outputDir, repoName string) ([]string, e
|
||||
generated = append(generated, pickInfoPaths(pickInfos)...)
|
||||
}
|
||||
|
||||
if err := writeRootIndex(rootPath, absRoot, rootName, repoName, topLevelDirs, result.Commit, result.Instructions, treeRoot, result.Cfg, pickInfos); err != nil {
|
||||
if err := writeRootIndex(rootPath, absRoot, rootName, repoName, topLevelDirs, rootFiles, result.Commit, result.Instructions, treeRoot, result.Cfg, pickInfos); err != nil {
|
||||
return nil, fmt.Errorf("failed to write root index: %w", err)
|
||||
}
|
||||
|
||||
@@ -170,7 +170,7 @@ func WriteSlices(result *walker.Result, outputDir, repoName string) ([]string, e
|
||||
}
|
||||
|
||||
for _, dirName := range dirNames {
|
||||
sliceName := strings.TrimSuffix(dirName, "/") + "_" + repoName + ".md"
|
||||
sliceName := dirName + "_" + repoName + ".md"
|
||||
sliceDir := filepath.Join(outputDir, dirName)
|
||||
if err := os.MkdirAll(sliceDir, 0755); err != nil {
|
||||
return nil, fmt.Errorf("cannot create slice directory %s: %w", sliceDir, err)
|
||||
@@ -283,7 +283,7 @@ func writePickFile(path, absRoot, relPath string, omitTest bool, commit *git.Com
|
||||
|
||||
fmt.Fprintf(&sb, "Tree: %s\n\n", tree.RenderBreadcrumb(absRoot, relPath))
|
||||
|
||||
fmt.Fprintf(&sb, "--- FILE: ./%s (%d bytes, %d lines) ---\n", relPath, infoSize(fullPath), lines)
|
||||
fmt.Fprintf(&sb, "--- FILE: ./%s (%d bytes, %d lines) ---\n", relPath, len(content), lines)
|
||||
sb.WriteString(fenceChars)
|
||||
if language != "" {
|
||||
sb.WriteString(language)
|
||||
@@ -299,15 +299,7 @@ func writePickFile(path, absRoot, relPath string, omitTest bool, commit *git.Com
|
||||
return err
|
||||
}
|
||||
|
||||
func infoSize(path string) int64 {
|
||||
info, err := os.Stat(path)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
return info.Size()
|
||||
}
|
||||
|
||||
func writeRootIndex(path, absRoot, rootName, repoName string, topLevelDirs map[string][]walker.Entry, commit *git.CommitInfo, instContent string, treeRoot *tree.Node, cfg *config.Config, picks []PickInfo) error {
|
||||
func writeRootIndex(path, absRoot, rootName, repoName string, topLevelDirs map[string][]walker.Entry, rootFiles []walker.Entry, commit *git.CommitInfo, instContent string, treeRoot *tree.Node, cfg *config.Config, picks []PickInfo) error {
|
||||
f, err := os.Create(path)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot create root index: %w", err)
|
||||
@@ -337,8 +329,11 @@ func writeRootIndex(path, absRoot, rootName, repoName string, topLevelDirs map[s
|
||||
sb.WriteString("|------------|-----------|-------|-------------|\n")
|
||||
|
||||
rootSliceFile := "root_" + repoName + ".md"
|
||||
rootFileCount := len(topLevelDirs)
|
||||
rootFileCount := len(rootFiles)
|
||||
rootTotalBytes := int64(0)
|
||||
for _, e := range rootFiles {
|
||||
rootTotalBytes += e.Size
|
||||
}
|
||||
fmt.Fprintf(&sb, "| %s | (root) | %d | %d |\n", rootSliceFile, rootFileCount, rootTotalBytes)
|
||||
|
||||
for _, dirName := range sortedKeys(topLevelDirs) {
|
||||
@@ -348,7 +343,7 @@ func writeRootIndex(path, absRoot, rootName, repoName string, topLevelDirs map[s
|
||||
for _, e := range entries {
|
||||
totalBytes += e.Size
|
||||
}
|
||||
sliceFile := filepath.Join(dirName, strings.TrimSuffix(dirName, "/")+"_"+repoName+".md")
|
||||
sliceFile := filepath.Join(dirName, dirName+"_"+repoName+".md")
|
||||
fmt.Fprintf(&sb, "| %s | %s/ | %d | %d |\n", sliceFile, dirName, fileCount, totalBytes)
|
||||
}
|
||||
sb.WriteString("\n")
|
||||
@@ -398,7 +393,7 @@ func writeRootSliceFile(path, absRoot string, rootFiles []walker.Entry, omitTest
|
||||
}
|
||||
language := extToLang(filepath.Ext(entry.RelPath))
|
||||
lines := countLines(content)
|
||||
fmt.Fprintf(&sb, "--- FILE: ./%s (%d bytes, %d lines) ---\n", entry.RelPath, entry.Size, lines)
|
||||
fmt.Fprintf(&sb, "--- FILE: ./%s (%d bytes, %d lines) ---\n", entry.RelPath, len(content), lines)
|
||||
fmt.Fprintf(&sb, "%s", fenceChars)
|
||||
if language != "" {
|
||||
fmt.Fprintf(&sb, "%s", language)
|
||||
@@ -442,7 +437,7 @@ func writeDirSlice(path, absDir, absRoot, dirName string, fileEntries []walker.E
|
||||
}
|
||||
language := extToLang(filepath.Ext(entry.RelPath))
|
||||
lines := countLines(content)
|
||||
fmt.Fprintf(&sb, "--- FILE: ./%s (%d bytes, %d lines) ---\n", entry.RelPath, entry.Size, lines)
|
||||
fmt.Fprintf(&sb, "--- FILE: ./%s (%d bytes, %d lines) ---\n", entry.RelPath, len(content), lines)
|
||||
fmt.Fprintf(&sb, "%s", fenceChars)
|
||||
if language != "" {
|
||||
fmt.Fprintf(&sb, "%s", language)
|
||||
@@ -582,20 +577,13 @@ func stripTestBlocks(content string) string {
|
||||
|
||||
for i < len(lines) {
|
||||
line := lines[i]
|
||||
|
||||
if !foundBrace {
|
||||
if strings.Contains(line, "{") {
|
||||
braceDepth += strings.Count(line, "{") - strings.Count(line, "}")
|
||||
foundBrace = true
|
||||
}
|
||||
i++
|
||||
continue
|
||||
}
|
||||
|
||||
braceDepth += strings.Count(line, "{") - strings.Count(line, "}")
|
||||
if strings.Contains(line, "{") {
|
||||
foundBrace = true
|
||||
}
|
||||
i++
|
||||
|
||||
if braceDepth <= 0 {
|
||||
if foundBrace && braceDepth <= 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
@@ -639,6 +627,7 @@ func extToLang(ext string) string {
|
||||
".cpp": "cpp",
|
||||
".hpp": "cpp",
|
||||
".txt": "text",
|
||||
".toml": "toml",
|
||||
}
|
||||
|
||||
if lang, ok := mapping[strings.ToLower(ext)]; ok {
|
||||
|
||||
@@ -0,0 +1,202 @@
|
||||
package renderer
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"git.flo.fo/FLO/dirmd/internal/config"
|
||||
"git.flo.fo/FLO/dirmd/internal/tree"
|
||||
)
|
||||
|
||||
func TestCountLines_empty(t *testing.T) {
|
||||
if got := countLines(""); got != 0 {
|
||||
t.Errorf("countLines(\"\") = %d; want 0", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCountLines_basic(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input string
|
||||
want int
|
||||
}{
|
||||
{"one_line_no_newline", "hello", 1},
|
||||
{"one_line_with_newline", "hello\n", 1},
|
||||
{"two_lines", "hello\nworld", 2},
|
||||
{"two_lines_trailing", "hello\nworld\n", 2},
|
||||
{"three_lines", "a\nb\nc", 3},
|
||||
{"empty_lines", "a\n\nb", 3},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := countLines(tt.input); got != tt.want {
|
||||
t.Errorf("countLines(%q) = %d; want %d", tt.input, got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestStripTestBlocks_rust(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input string
|
||||
want string
|
||||
}{
|
||||
{"no_test_block", "fn main() {}\nfn helper() {}", "fn main() {}\nfn helper() {}"},
|
||||
{"cfg_test_block", "#[cfg(test)]\nmod tests {\n #[test]\n fn test_one() {}\n}", ""},
|
||||
{"mixed_content", "pub fn main() {}\n#[cfg(test)]\nmod tests {\n #[test]\n fn t() {}\n}\npub fn end() {}", "pub fn main() {}\npub fn end() {}"},
|
||||
{"nested_braces", "#[cfg(test)]\nmod tests {\n mod inner {\n #[test]\n fn t() {}\n }\n}", ""},
|
||||
{"multiple_blocks", "#[cfg(test)]\nmod t1 {}\n#[cfg(test)]\nmod t2 {}", ""},
|
||||
{"cfg_all_test", "#[cfg(all(test, unix))]\nmod tests {}", ""},
|
||||
{"cfg_any_test", "#[cfg(any(test, feature = \"foo\"))]\nmod tests {}", ""},
|
||||
{"empty_after_strip", "#[cfg(test)]\nmod tests {}", ""},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := stripTestBlocks(tt.input); got != tt.want {
|
||||
t.Errorf("stripTestBlocks(%q)\ngot:\n%s\nwant:\n%s", tt.input, got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestExtToLang(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
ext string
|
||||
want string
|
||||
}{
|
||||
{"go", ".go", "go"},
|
||||
{"markdown", ".md", "markdown"},
|
||||
{"yaml_upper", ".YAML", "yaml"},
|
||||
{"yaml_yml", ".yml", "yaml"},
|
||||
{"javascript", ".js", "javascript"},
|
||||
{"typescript", ".ts", "typescript"},
|
||||
{"css", ".css", "css"},
|
||||
{"html", ".html", "html"},
|
||||
{"json", ".json", "json"},
|
||||
{"xml", ".xml", "xml"},
|
||||
{"sql", ".sql", "sql"},
|
||||
{"bash", ".sh", "bash"},
|
||||
{"python", ".py", "python"},
|
||||
{"rust", ".rs", "rust"},
|
||||
{"c", ".c", "c"},
|
||||
{"cpp", ".cpp", "cpp"},
|
||||
{"txt", ".txt", "text"},
|
||||
{"toml", ".toml", "toml"},
|
||||
{"unknown", ".xyz", ""},
|
||||
{"empty", "", ""},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := extToLang(tt.ext); got != tt.want {
|
||||
t.Errorf("extToLang(%q) = %q; want %q", tt.ext, got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestHasAnyAnnotation_none(t *testing.T) {
|
||||
root := &tree.Node{Name: "root", IsDir: true, Children: map[string]*tree.Node{
|
||||
"file.go": {Name: "file.go", IsDir: false},
|
||||
}}
|
||||
if hasAnyAnnotation(root) {
|
||||
t.Error("hasAnyAnnotation should be false for clean tree")
|
||||
}
|
||||
}
|
||||
|
||||
func TestHasAnyAnnotation_present(t *testing.T) {
|
||||
root := &tree.Node{Name: "root", IsDir: true, Children: map[string]*tree.Node{
|
||||
".git": {Name: ".git", IsDir: true, Annotation: "ignored (default)"},
|
||||
}}
|
||||
if !hasAnyAnnotation(root) {
|
||||
t.Error("hasAnyAnnotation should be true with annotation")
|
||||
}
|
||||
}
|
||||
|
||||
func TestHasAnyAnnotation_deep(t *testing.T) {
|
||||
root := &tree.Node{Name: "root", IsDir: true, Children: map[string]*tree.Node{
|
||||
"internal": {Name: "internal", IsDir: true, Children: map[string]*tree.Node{
|
||||
"deep": {Name: "deep", IsDir: true, Annotation: "tests omitted (--omit-test)"},
|
||||
}},
|
||||
}}
|
||||
if !hasAnyAnnotation(root) {
|
||||
t.Error("hasAnyAnnotation should be true for deep annotation")
|
||||
}
|
||||
}
|
||||
|
||||
func TestFormatFlags_nil(t *testing.T) {
|
||||
if FormatFlags(nil) != "" {
|
||||
t.Error("FormatFlags(nil) should be empty")
|
||||
}
|
||||
}
|
||||
|
||||
func TestFormatFlags_empty(t *testing.T) {
|
||||
cfg := &config.Config{
|
||||
MaxDepth: config.DefaultMaxDepth,
|
||||
MaxSize: config.DefaultMaxSize,
|
||||
}
|
||||
if out := FormatFlags(cfg); out != "" {
|
||||
t.Errorf("FormatFlags(default config) = %q; want empty", out)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFormatFlags_set(t *testing.T) {
|
||||
cfg := &config.Config{
|
||||
OmitTest: true,
|
||||
OmitMd: true,
|
||||
MaxDepth: 10,
|
||||
}
|
||||
out := FormatFlags(cfg)
|
||||
if !strings.Contains(out, "--omit-test") {
|
||||
t.Error("missing --omit-test")
|
||||
}
|
||||
if !strings.Contains(out, "--omit-md") {
|
||||
t.Error("missing --omit-md")
|
||||
}
|
||||
if !strings.Contains(out, "--max-depth 10") {
|
||||
t.Error("missing --max-depth 10")
|
||||
}
|
||||
}
|
||||
|
||||
func TestFormatFlags_extra_ignores(t *testing.T) {
|
||||
cfg := &config.Config{
|
||||
Ignores: append(config.DefaultIgnores, "mycustomdir"),
|
||||
}
|
||||
out := FormatFlags(cfg)
|
||||
if !strings.Contains(out, "mycustomdir") {
|
||||
t.Error("missing custom ignore in output")
|
||||
}
|
||||
if strings.Contains(out, "node_modules") {
|
||||
t.Error("default ignore leaked into Ignored line")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetMinus(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
haystack []string
|
||||
defaults []string
|
||||
want []string
|
||||
}{
|
||||
{"empty", nil, []string{"a"}, nil},
|
||||
{"all_default", []string{"a", "b"}, []string{"a", "b"}, nil},
|
||||
{"one_extra", []string{"a", "c"}, []string{"a"}, []string{"c"}},
|
||||
{"duplicates_deduped", []string{"c", "c", "a"}, []string{"a"}, []string{"c"}},
|
||||
{"no_defaults", []string{"x"}, nil, []string{"x"}},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := setMinus(tt.haystack, tt.defaults)
|
||||
if len(got) != len(tt.want) {
|
||||
t.Errorf("setMinus() length = %d; want %d", len(got), len(tt.want))
|
||||
return
|
||||
}
|
||||
for i := range got {
|
||||
if got[i] != tt.want[i] {
|
||||
t.Errorf("setMinus()[%d] = %q; want %q", i, got[i], tt.want[i])
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user