All checks were successful
Tests / unit-tests (push) Successful in 25s
- CreateProject() sa validacijom imena (regex, duplikati, prazno) - POST /projects/create ruta sa AuthMiddleware - Modal forma na projects stranici za unos imena - 10 unit testova za CreateProject - change-password.html template i testovi - Ažuriran TESTING.md sa novom sekcijom Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
208 lines
5.1 KiB
Go
208 lines
5.1 KiB
Go
package main
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
)
|
|
|
|
func TestListProjects(t *testing.T) {
|
|
dir := t.TempDir()
|
|
|
|
// Create test projects
|
|
os.MkdirAll(filepath.Join(dir, "alpha"), 0755)
|
|
os.MkdirAll(filepath.Join(dir, "beta"), 0755)
|
|
os.MkdirAll(filepath.Join(dir, ".hidden"), 0755)
|
|
os.WriteFile(filepath.Join(dir, "file.txt"), []byte("not a dir"), 0644)
|
|
|
|
// Add README to alpha
|
|
os.WriteFile(filepath.Join(dir, "alpha", "README.md"), []byte("# Alpha Project\nSome description"), 0644)
|
|
|
|
t.Run("lists directories only", func(t *testing.T) {
|
|
projects, err := ListProjects(dir)
|
|
if err != nil {
|
|
t.Fatalf("ListProjects: %v", err)
|
|
}
|
|
if len(projects) != 2 {
|
|
t.Fatalf("got %d projects, want 2", len(projects))
|
|
}
|
|
})
|
|
|
|
t.Run("sorted alphabetically", func(t *testing.T) {
|
|
projects, err := ListProjects(dir)
|
|
if err != nil {
|
|
t.Fatalf("ListProjects: %v", err)
|
|
}
|
|
if projects[0].Name != "alpha" {
|
|
t.Errorf("first = %q, want alpha", projects[0].Name)
|
|
}
|
|
if projects[1].Name != "beta" {
|
|
t.Errorf("second = %q, want beta", projects[1].Name)
|
|
}
|
|
})
|
|
|
|
t.Run("reads README description", func(t *testing.T) {
|
|
projects, err := ListProjects(dir)
|
|
if err != nil {
|
|
t.Fatalf("ListProjects: %v", err)
|
|
}
|
|
if !projects[0].HasReadme {
|
|
t.Error("alpha should have HasReadme=true")
|
|
}
|
|
if projects[0].Description != "Alpha Project" {
|
|
t.Errorf("description = %q, want 'Alpha Project'", projects[0].Description)
|
|
}
|
|
})
|
|
|
|
t.Run("no README", func(t *testing.T) {
|
|
projects, err := ListProjects(dir)
|
|
if err != nil {
|
|
t.Fatalf("ListProjects: %v", err)
|
|
}
|
|
if projects[1].HasReadme {
|
|
t.Error("beta should have HasReadme=false")
|
|
}
|
|
if projects[1].Description != "" {
|
|
t.Errorf("description = %q, want empty", projects[1].Description)
|
|
}
|
|
})
|
|
|
|
t.Run("excludes hidden dirs", func(t *testing.T) {
|
|
projects, err := ListProjects(dir)
|
|
if err != nil {
|
|
t.Fatalf("ListProjects: %v", err)
|
|
}
|
|
for _, p := range projects {
|
|
if p.Name == ".hidden" {
|
|
t.Error("should not include hidden directories")
|
|
}
|
|
}
|
|
})
|
|
|
|
t.Run("excludes files", func(t *testing.T) {
|
|
projects, err := ListProjects(dir)
|
|
if err != nil {
|
|
t.Fatalf("ListProjects: %v", err)
|
|
}
|
|
for _, p := range projects {
|
|
if p.Name == "file.txt" {
|
|
t.Error("should not include files")
|
|
}
|
|
}
|
|
})
|
|
|
|
t.Run("nonexistent directory", func(t *testing.T) {
|
|
_, err := ListProjects("/nonexistent/path")
|
|
if err == nil {
|
|
t.Fatal("expected error for nonexistent dir")
|
|
}
|
|
})
|
|
|
|
t.Run("empty directory", func(t *testing.T) {
|
|
emptyDir := t.TempDir()
|
|
projects, err := ListProjects(emptyDir)
|
|
if err != nil {
|
|
t.Fatalf("ListProjects: %v", err)
|
|
}
|
|
if len(projects) != 0 {
|
|
t.Errorf("got %d projects, want 0", len(projects))
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestCreateProject(t *testing.T) {
|
|
t.Run("valid name creates directory", func(t *testing.T) {
|
|
dir := t.TempDir()
|
|
err := CreateProject(dir, "my-project")
|
|
if err != nil {
|
|
t.Fatalf("CreateProject: %v", err)
|
|
}
|
|
info, err := os.Stat(filepath.Join(dir, "my-project"))
|
|
if err != nil {
|
|
t.Fatalf("directory not created: %v", err)
|
|
}
|
|
if !info.IsDir() {
|
|
t.Error("expected directory, got file")
|
|
}
|
|
})
|
|
|
|
t.Run("valid name with underscore", func(t *testing.T) {
|
|
dir := t.TempDir()
|
|
err := CreateProject(dir, "my_project_2")
|
|
if err != nil {
|
|
t.Fatalf("CreateProject: %v", err)
|
|
}
|
|
if _, err := os.Stat(filepath.Join(dir, "my_project_2")); err != nil {
|
|
t.Fatalf("directory not created: %v", err)
|
|
}
|
|
})
|
|
|
|
t.Run("duplicate name returns error", func(t *testing.T) {
|
|
dir := t.TempDir()
|
|
os.MkdirAll(filepath.Join(dir, "existing"), 0755)
|
|
err := CreateProject(dir, "existing")
|
|
if err == nil {
|
|
t.Fatal("expected error for duplicate name")
|
|
}
|
|
})
|
|
|
|
t.Run("empty name returns error", func(t *testing.T) {
|
|
dir := t.TempDir()
|
|
err := CreateProject(dir, "")
|
|
if err == nil {
|
|
t.Fatal("expected error for empty name")
|
|
}
|
|
})
|
|
|
|
t.Run("dot returns error", func(t *testing.T) {
|
|
dir := t.TempDir()
|
|
err := CreateProject(dir, ".")
|
|
if err == nil {
|
|
t.Fatal("expected error for '.'")
|
|
}
|
|
})
|
|
|
|
t.Run("dotdot returns error", func(t *testing.T) {
|
|
dir := t.TempDir()
|
|
err := CreateProject(dir, "..")
|
|
if err == nil {
|
|
t.Fatal("expected error for '..'")
|
|
}
|
|
})
|
|
|
|
t.Run("hidden name returns error", func(t *testing.T) {
|
|
dir := t.TempDir()
|
|
err := CreateProject(dir, ".secret")
|
|
if err == nil {
|
|
t.Fatal("expected error for hidden name")
|
|
}
|
|
})
|
|
|
|
t.Run("special characters return error", func(t *testing.T) {
|
|
dir := t.TempDir()
|
|
invalid := []string{"foo bar", "foo/bar", "foo..bar", "a@b", "a!b", "проект"}
|
|
for _, name := range invalid {
|
|
err := CreateProject(dir, name)
|
|
if err == nil {
|
|
t.Errorf("expected error for name %q", name)
|
|
}
|
|
}
|
|
})
|
|
|
|
t.Run("name starting with hyphen returns error", func(t *testing.T) {
|
|
dir := t.TempDir()
|
|
err := CreateProject(dir, "-project")
|
|
if err == nil {
|
|
t.Fatal("expected error for name starting with hyphen")
|
|
}
|
|
})
|
|
|
|
t.Run("name starting with underscore returns error", func(t *testing.T) {
|
|
dir := t.TempDir()
|
|
err := CreateProject(dir, "_project")
|
|
if err == nil {
|
|
t.Fatal("expected error for name starting with underscore")
|
|
}
|
|
})
|
|
}
|