diff --git a/zddc/internal/handler/fileapi_test.go b/zddc/internal/handler/fileapi_test.go index 92a6140..7e333b3 100644 --- a/zddc/internal/handler/fileapi_test.go +++ b/zddc/internal/handler/fileapi_test.go @@ -918,3 +918,34 @@ func TestFileAPI_MoveRenamesHistoryDir(t *testing.T) { t.Errorf("history should NOT follow a cross-dir move; err=%v", err) } } + +// TestFileAPI_PreservesCase — mkdir + PUT must keep the basename's case +// verbatim (tracking numbers are uppercase; the server must not normalize). +func TestFileAPI_PreservesCase(t *testing.T) { + // working//… is the realistic create surface; the harness + // auto-registers Acme so the party gate passes. Subfolder + file names + // under it are arbitrary — isolates the basename-case question. + _, do, root := fileAPITestSetup(t, []string{"Proj/working/Acme"}, nil) + base := filepath.Join(root, "Proj", "working", "Acme") + + rec := do(http.MethodPost, "/Proj/working/Acme/MixedCaseDir", "alice@example.com", nil, map[string]string{"X-ZDDC-Op": "mkdir"}) + if rec.Code != http.StatusCreated && rec.Code != http.StatusOK { + t.Fatalf("mkdir: %d %s", rec.Code, rec.Body.String()) + } + rec = do(http.MethodPut, "/Proj/working/Acme/UPPER-Name.MD", "alice@example.com", []byte("# hi\n"), map[string]string{"Content-Type": "text/markdown"}) + if rec.Code != http.StatusCreated && rec.Code != http.StatusOK { + t.Fatalf("put: %d %s", rec.Code, rec.Body.String()) + } + ents, _ := os.ReadDir(base) + var names []string + for _, e := range ents { + names = append(names, e.Name()) + } + t.Logf("on-disk under working/Acme: %v", names) + if _, err := os.Stat(filepath.Join(base, "MixedCaseDir")); err != nil { + t.Errorf("mkdir case NOT preserved (%v)", names) + } + if _, err := os.Stat(filepath.Join(base, "UPPER-Name.MD")); err != nil { + t.Errorf("PUT case NOT preserved (%v)", names) + } +}