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 }