add tests (ai gen)

This commit is contained in:
2026-01-18 01:59:00 +00:00
parent f35debb152
commit 89e62ad65a
6 changed files with 370 additions and 1 deletions
+4
View File
@@ -1 +1,5 @@
my take on how notes and srs should be combind and simplified my take on how notes and srs should be combind and simplified
# Tests
Run tests with `go test ./...`
+109
View File
@@ -0,0 +1,109 @@
package main
import (
"os"
"path/filepath"
"testing"
)
// tests creating a file in a temp dir
func TestCreateFile(t *testing.T) {
tmpDir, err := os.MkdirTemp("", "mend_fs_test")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpDir)
// test valid creation
filePath := filepath.Join(tmpDir, "test.md")
err = createFile(filePath, []byte("content"))
if err != nil {
t.Errorf("expected no error, got %v", err)
}
if _, err := os.Stat(filePath); os.IsNotExist(err) {
t.Error("file was not created")
}
// test creation failure (exists)
err = createFile(filePath, []byte("content"))
if err == nil {
t.Error("expected error for existing file, got nil")
}
// test empty path
err = createFile("", []byte{})
if err == nil {
t.Error("expected error for empty path, got nil")
}
}
// tests creating a folder
func TestCreateFolder(t *testing.T) {
tmpDir, err := os.MkdirTemp("", "mend_fs_test")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpDir)
folderPath := filepath.Join(tmpDir, "subfolder")
err = createFolder(folderPath)
if err != nil {
t.Errorf("expected no error, got %v", err)
}
info, err := os.Stat(folderPath)
if os.IsNotExist(err) {
t.Error("folder was not created")
}
if !info.IsDir() {
t.Error("created path is not a directory")
}
// test creation failure (exists)
err = createFolder(folderPath)
if err == nil {
t.Error("expected error for existing folder, got nil")
}
// test empty path
err = createFolder("")
if err == nil {
t.Error("expected error for empty path, got nil")
}
}
// tests recursive deletion
func TestDeletePath(t *testing.T) {
tmpDir, err := os.MkdirTemp("", "mend_fs_test")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpDir)
subDir := filepath.Join(tmpDir, "subdir")
os.Mkdir(subDir, 0755)
fileInSubDir := filepath.Join(subDir, "file.txt")
os.WriteFile(fileInSubDir, []byte("data"), 0644)
err = deletePath(subDir)
if err != nil {
t.Errorf("expected no error, got %v", err)
}
if _, err := os.Stat(subDir); !os.IsNotExist(err) {
t.Error("directory was not deleted")
}
// test delete non-existent
err = deletePath(filepath.Join(tmpDir, "nonexistent"))
if err == nil {
t.Error("expected error for nonexistent path, got nil")
}
// test empty path
err = deletePath("")
if err == nil {
t.Error("expected error for empty path, got nil")
}
}
+147
View File
@@ -0,0 +1,147 @@
package main
import (
"os"
"path/filepath"
"testing"
)
// tests creating a new fstree
func TestNewFsTree(t *testing.T) {
tmpDir, err := os.MkdirTemp("", "mend_fstree_test")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpDir)
// setup structure:
// root/
// folder1/
// file1.md
// file2.md
os.Mkdir(filepath.Join(tmpDir, "folder1"), 0755)
os.WriteFile(filepath.Join(tmpDir, "folder1", "file1.md"), []byte(""), 0644)
os.WriteFile(filepath.Join(tmpDir, "file2.md"), []byte(""), 0644)
tree := NewFsTree(tmpDir, 0)
if tree == nil {
t.Fatal("expected tree to be created, got nil")
}
if tree.root.path != tmpDir {
t.Errorf("expected root path %s, got %s", tmpDir, tree.root.path)
}
// root children: folder1, file2.md
if len(tree.root.children) != 2 {
t.Errorf("expected 2 children, got %d", len(tree.root.children))
}
}
// tests creating nodes via tree
func TestTreeCreateNode(t *testing.T) {
tmpDir, err := os.MkdirTemp("", "mend_fstree_test")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpDir)
tree := NewFsTree(tmpDir, 0)
// create folder
err = tree.CreateNode(tree.root, "new_folder", FolderNode)
if err != nil {
t.Errorf("expected no error creating folder, got %v", err)
}
// check fs
if _, err := os.Stat(filepath.Join(tmpDir, "new_folder")); os.IsNotExist(err) {
t.Error("folder not created on fs")
}
// check tree
if len(tree.root.children) != 1 || tree.root.children[0].nodeType != FolderNode {
t.Error("tree block not updated with new folder")
}
// create file in new folder
newFolder := tree.root.children[0]
err = tree.CreateNode(newFolder, "new_file", FileNode)
if err != nil {
t.Errorf("expected no error creating file, got %v", err)
}
// check fs (.md appended automatically)
if _, err := os.Stat(filepath.Join(tmpDir, "new_folder", "new_file.md")); os.IsNotExist(err) {
t.Error("file not created on fs")
}
// check tree
if len(newFolder.children) != 1 || newFolder.children[0].nodeType != FileNode {
t.Error("tree node not updated with new file")
}
}
// tests deleting nodes
func TestTreeDeleteNode(t *testing.T) {
tmpDir, err := os.MkdirTemp("", "mend_fstree_test")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(tmpDir)
// setup: root/file.md
os.WriteFile(filepath.Join(tmpDir, "file.md"), []byte(""), 0644)
tree := NewFsTree(tmpDir, 0)
targetNode := tree.root.children[0]
err = tree.DeleteNode(targetNode)
if err != nil {
t.Errorf("expected no error deleting node, got %v", err)
}
// check fs
if _, err := os.Stat(filepath.Join(tmpDir, "file.md")); !os.IsNotExist(err) {
t.Error("file not deleted from fs")
}
// check tree
if len(tree.root.children) != 0 {
t.Error("tree node not updated after deletion")
}
}
// tests toggling expand
func TestTreeToggleExpand(t *testing.T) {
root := &FsNode{
nodeType: FolderNode,
expanded: true,
children: []*FsNode{}, // Initialize children
}
node := &FsNode{
nodeType: FolderNode,
expanded: true,
parent: root,
}
root.children = append(root.children, node)
// mocked tree for this test
tree := &FsTree{
root: root,
}
// Initial buildLines to setup state
tree.buildLines()
err := tree.ToggleExpand(node)
if err != nil {
t.Error(err)
}
if node.expanded {
t.Error("expected node to be collapsed")
}
err = tree.ToggleExpand(node)
if err != nil {
t.Error(err)
}
if !node.expanded {
t.Error("expected node to be expanded")
}
}
+1 -1
View File
@@ -8,6 +8,7 @@ require (
github.com/charmbracelet/glamour v0.10.0 github.com/charmbracelet/glamour v0.10.0
github.com/charmbracelet/lipgloss v1.1.1-0.20250404203927-76690c660834 github.com/charmbracelet/lipgloss v1.1.1-0.20250404203927-76690c660834
github.com/mattn/go-runewidth v0.0.16 github.com/mattn/go-runewidth v0.0.16
github.com/yuin/goldmark v1.7.8
) )
require ( require (
@@ -33,7 +34,6 @@ require (
github.com/muesli/termenv v0.16.0 // indirect github.com/muesli/termenv v0.16.0 // indirect
github.com/rivo/uniseg v0.4.7 // indirect github.com/rivo/uniseg v0.4.7 // indirect
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
github.com/yuin/goldmark v1.7.8 // indirect
github.com/yuin/goldmark-emoji v1.0.5 // indirect github.com/yuin/goldmark-emoji v1.0.5 // indirect
golang.org/x/net v0.33.0 // indirect golang.org/x/net v0.33.0 // indirect
golang.org/x/sys v0.36.0 // indirect golang.org/x/sys v0.36.0 // indirect
+2
View File
@@ -1,3 +1,5 @@
github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ=
github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE=
github.com/alecthomas/assert/v2 v2.7.0 h1:QtqSACNS3tF7oasA8CU6A6sXZSBDqnm7RfpLl9bZqbE= github.com/alecthomas/assert/v2 v2.7.0 h1:QtqSACNS3tF7oasA8CU6A6sXZSBDqnm7RfpLl9bZqbE=
github.com/alecthomas/assert/v2 v2.7.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= github.com/alecthomas/assert/v2 v2.7.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k=
github.com/alecthomas/chroma/v2 v2.14.0 h1:R3+wzpnUArGcQz7fCETQBzO5n9IMNi13iIs46aU4V9E= github.com/alecthomas/chroma/v2 v2.14.0 h1:R3+wzpnUArGcQz7fCETQBzO5n9IMNi13iIs46aU4V9E=
+107
View File
@@ -0,0 +1,107 @@
package main
import (
"reflect"
"testing"
)
// tests hint extraction from text
func TestExtractHints(t *testing.T) {
tests := []struct {
name string
content string
expected []string
}{
{
name: "single bold hint",
content: "This is a **hint**.",
expected: []string{"hint"},
},
{
name: "multiple bold hints",
content: "**one** and **two**",
expected: []string{"one", "two"},
},
{
name: "underscore hints",
content: "__one__ and __two__",
expected: []string{"one", "two"},
},
{
name: "mixed hints",
content: "**one** and __two__",
expected: []string{"one", "two"},
},
{
name: "no hints",
content: "just plain text",
expected: []string{},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := extractHints(tt.content)
if !reflect.DeepEqual(got, tt.expected) {
t.Errorf("extractHints() = %v, want %v", got, tt.expected)
}
})
}
}
// tests section parsing from markdown
func TestParseSections(t *testing.T) {
content := []byte(`# Title 1
Content 1 with **hint1**.
# Title 2
Content 2 with __hint2__.
`)
sections := parseSections(content)
if len(sections) != 2 {
t.Fatalf("expected 2 sections, got %d", len(sections))
}
// verify first section
if sections[0].Title != "# Title 1" {
t.Errorf("expected title '# Title 1', got '%s'", sections[0].Title)
}
if sections[0].Content != "Content 1 with **hint1**." {
t.Errorf("expected content match for section 1, got '%s'", sections[0].Content)
}
if len(sections[0].Hints) != 1 || sections[0].Hints[0] != "hint1" {
t.Error("failed to extract hint from section 1")
}
// verify second section
if sections[1].Title != "# Title 2" {
t.Errorf("expected title '# Title 2', got '%s'", sections[1].Title)
}
if sections[1].Content != "Content 2 with __hint2__." {
t.Errorf("expected content match for section 2, got '%s'", sections[1].Content)
}
if len(sections[1].Hints) != 1 || sections[1].Hints[0] != "hint2" {
t.Error("failed to extract hint from section 2")
}
}
// tests parsing with no headers
func TestParseSectionsNoHeaders(t *testing.T) {
content := []byte(`Just some content without any headers.
It has **one hint**.`)
sections := parseSections(content)
if len(sections) != 1 {
t.Fatalf("expected 1 section, got %d", len(sections))
}
if sections[0].Title != "no title" {
t.Errorf("expected 'no title', got '%s'", sections[0].Title)
}
if len(sections[0].Hints) != 1 || sections[0].Hints[0] != "one hint" {
t.Error("failed to extract hint")
}
}