Имя варианта "main" или с недопустимыми символами больше не отклоняет запрос ошибкой 400 — теперь автоматически конвертируется в валидное (sanitizeProjectVariantName), а API/UI показывают variant_warning вместо блокировки создания/переименования варианта. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
101 lines
3.1 KiB
Go
101 lines
3.1 KiB
Go
package services
|
|
|
|
import (
|
|
"path/filepath"
|
|
"testing"
|
|
|
|
"git.mchus.pro/mchus/quoteforge/internal/localdb"
|
|
)
|
|
|
|
// TestProjectServiceCreateSanitizesReservedMainVariant verifies that naming a new
|
|
// variant "main" no longer errors: the name is auto-converted to a valid one and a
|
|
// warning is returned instead of the request being rejected.
|
|
func TestProjectServiceCreateSanitizesReservedMainVariant(t *testing.T) {
|
|
local, err := newProjectTestLocalDB(t)
|
|
if err != nil {
|
|
t.Fatalf("open localdb: %v", err)
|
|
}
|
|
service := NewProjectService(local)
|
|
|
|
project, warning, err := service.Create("tester", &CreateProjectRequest{
|
|
Code: "OPS-1",
|
|
Variant: "main",
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("create project: %v", err)
|
|
}
|
|
if warning == "" {
|
|
t.Fatalf("expected a warning about the reserved variant name")
|
|
}
|
|
if project.Variant == "" || normalizeProjectVariant(project.Variant) == "main" {
|
|
t.Fatalf("expected variant to be converted away from 'main', got %q", project.Variant)
|
|
}
|
|
}
|
|
|
|
// TestProjectServiceUpdateSanitizesReservedMainVariant mirrors the create case for
|
|
// renaming an existing (non-main) variant to "main".
|
|
func TestProjectServiceUpdateSanitizesReservedMainVariant(t *testing.T) {
|
|
local, err := newProjectTestLocalDB(t)
|
|
if err != nil {
|
|
t.Fatalf("open localdb: %v", err)
|
|
}
|
|
service := NewProjectService(local)
|
|
|
|
created, _, err := service.Create("tester", &CreateProjectRequest{
|
|
Code: "OPS-1",
|
|
Variant: "Lenovo",
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("create project: %v", err)
|
|
}
|
|
|
|
mainName := "main"
|
|
updated, warning, err := service.Update(created.UUID, "tester", &UpdateProjectRequest{
|
|
Variant: &mainName,
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("update project: %v", err)
|
|
}
|
|
if warning == "" {
|
|
t.Fatalf("expected a warning about the reserved variant name")
|
|
}
|
|
if updated.Variant == "" || normalizeProjectVariant(updated.Variant) == "main" {
|
|
t.Fatalf("expected variant to be converted away from 'main', got %q", updated.Variant)
|
|
}
|
|
}
|
|
|
|
// TestSanitizeProjectVariantName_InvalidChars verifies disallowed characters are
|
|
// stripped/replaced rather than rejected outright.
|
|
func TestSanitizeProjectVariantName_InvalidChars(t *testing.T) {
|
|
sanitized, warning := sanitizeProjectVariantName("Лендинг сервер!")
|
|
if warning == "" {
|
|
t.Fatalf("expected a warning for invalid characters")
|
|
}
|
|
if !projectCodeRe.MatchString(sanitized) {
|
|
t.Fatalf("sanitized variant %q still fails projectCodeRe", sanitized)
|
|
}
|
|
}
|
|
|
|
// TestSanitizeProjectVariantName_ValidPassesThrough ensures already-valid names are
|
|
// left untouched with no warning.
|
|
func TestSanitizeProjectVariantName_ValidPassesThrough(t *testing.T) {
|
|
sanitized, warning := sanitizeProjectVariantName("lenovo-2u")
|
|
if warning != "" {
|
|
t.Fatalf("expected no warning, got %q", warning)
|
|
}
|
|
if sanitized != "lenovo-2u" {
|
|
t.Fatalf("expected unchanged variant, got %q", sanitized)
|
|
}
|
|
}
|
|
|
|
func newProjectTestLocalDB(t *testing.T) (*localdb.LocalDB, error) {
|
|
t.Helper()
|
|
dbPath := filepath.Join(t.TempDir(), "project_test.db")
|
|
local, err := localdb.New(dbPath)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
t.Cleanup(func() { _ = local.Close() })
|
|
return local, nil
|
|
}
|