117 lines
3.5 KiB
Go
117 lines
3.5 KiB
Go
// Copyright (c) 2026 Petr Balvín <opensource@petrbalvin.org> (https://petrbalvin.org)
|
|||
|
|
// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0
|
||
|
|
|
||
|
|
package payloads
|
||
|
|
|
||
|
|
import (
|
||
|
|
"strings"
|
||
|
|
"testing"
|
||
|
|
|
||
|
|
"sourcedock.dev/petrbalvin/volumen/internal/frontmatter"
|
||
|
|
"sourcedock.dev/petrbalvin/volumen/internal/post"
|
||
|
|
)
|
||
|
|
|
||
|
|
// The write form normalises identifiers as it stores them: a doi.org
|
||
|
|
// URL becomes the bare DOI, an iD gains its upper-case X.
|
||
|
|
func TestIdentifiersNormaliseOnWrite(t *testing.T) {
|
||
|
|
p, err := PostFromParams(map[string]string{
|
||
|
|
"title": "A paper",
|
||
|
|
"slug": "a-paper",
|
||
|
|
"body": "b",
|
||
|
|
"doi": "https://doi.org/10.5281/zenodo.1234567",
|
||
|
|
"orcid": "0000-0000-0000-001x",
|
||
|
|
}, nil)
|
||
|
|
if err != nil {
|
||
|
|
t.Fatalf("PostFromParams: %v", err)
|
||
|
|
}
|
||
|
|
if got := p.DOI(); got != "10.5281/zenodo.1234567" {
|
||
|
|
t.Fatalf("stored doi = %q", got)
|
||
|
|
}
|
||
|
|
if got := p.ORCID(); got != "0000-0000-0000-001X" {
|
||
|
|
t.Fatalf("stored orcid = %q", got)
|
||
|
|
}
|
||
|
|
// Identifiers are reserved: they never appear in the custom fields.
|
||
|
|
if fields := p.CustomFields(); fields != nil {
|
||
|
|
t.Fatalf("CustomFields leaked identifiers: %v", fields)
|
||
|
|
}
|
||
|
|
|
||
|
|
s := newStoreWithPosts(t, nil)
|
||
|
|
if err := CreationError(p, s, nil); err != nil {
|
||
|
|
t.Fatalf("valid identifiers refused: %v", err)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestIdentifierValidationErrors(t *testing.T) {
|
||
|
|
s := newStoreWithPosts(t, nil)
|
||
|
|
base := func(key, value string) *post.Post {
|
||
|
|
meta := frontmatter.NewMeta()
|
||
|
|
meta.Set("slug", "x")
|
||
|
|
meta.Set("title", "T")
|
||
|
|
meta.Set(key, value)
|
||
|
|
return post.New(meta, "body")
|
||
|
|
}
|
||
|
|
cases := []struct {
|
||
|
|
key, value, want string
|
||
|
|
}{
|
||
|
|
{"doi", "20.1234/x", "DOI must look like 10.xxxx/suffix."},
|
||
|
|
{"doi", "10.1", "DOI must look like 10.xxxx/suffix."},
|
||
|
|
{"orcid", "0000-0002-1825-0098", "ORCID must look like 0000-0002-1825-0097."},
|
||
|
|
{"orcid", "not-an-orcid", "ORCID must look like 0000-0002-1825-0097."},
|
||
|
|
}
|
||
|
|
for _, tc := range cases {
|
||
|
|
err := CreationError(base(tc.key, tc.value), s, nil)
|
||
|
|
if err == nil || !strings.Contains(err.Error(), tc.want) {
|
||
|
|
t.Errorf("%s %q: error = %v, want %q", tc.key, tc.value, err, tc.want)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
// Both empty stay empty: the fields remain optional.
|
||
|
|
if err := CreationError(base("doi", ""), s, nil); err != nil {
|
||
|
|
t.Errorf("empty doi refused: %v", err)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// The read shapes carry the identifiers, and the SEO block publishes
|
||
|
|
// them: an identifier property on the article, one on its author.
|
||
|
|
func TestIdentifiersInPayloads(t *testing.T) {
|
||
|
|
meta := frontmatter.NewMeta()
|
||
|
|
meta.Set("slug", "paper")
|
||
|
|
meta.Set("title", "Paper")
|
||
|
|
meta.Set("author", "Petr Balvín")
|
||
|
|
meta.Set("doi", "https://doi.org/10.1000/xyz")
|
||
|
|
meta.Set("orcid", "0000-0002-1825-0097")
|
||
|
|
p := post.New(meta, "body text here")
|
||
|
|
|
||
|
|
summary := BuildSummary(p)
|
||
|
|
if summary.DOI != "10.1000/xyz" {
|
||
|
|
t.Fatalf("summary doi = %q", summary.DOI)
|
||
|
|
}
|
||
|
|
if summary.ORCID != "0000-0002-1825-0097" {
|
||
|
|
t.Fatalf("summary orcid = %q", summary.ORCID)
|
||
|
|
}
|
||
|
|
|
||
|
|
m, err := BuildMeta(p, "https://example.com")
|
||
|
|
if err != nil {
|
||
|
|
t.Fatalf("BuildMeta: %v", err)
|
||
|
|
}
|
||
|
|
for _, want := range []string{
|
||
|
|
`"identifier":"https://doi.org/10.1000/xyz"`,
|
||
|
|
`"identifier":"https://orcid.org/0000-0002-1825-0097"`,
|
||
|
|
} {
|
||
|
|
if !strings.Contains(m.JSONLD, want) {
|
||
|
|
t.Fatalf("json_ld missing %s:\n%s", want, m.JSONLD)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// A stored value that is no identifier at all survives the read
|
||
|
|
// untouched rather than vanishing.
|
||
|
|
broken := post.New(func() *frontmatter.Meta {
|
||
|
|
m := frontmatter.NewMeta()
|
||
|
|
m.Set("slug", "broken")
|
||
|
|
m.Set("doi", "10.ONE_HUNDRED/x")
|
||
|
|
return m
|
||
|
|
}(), "b")
|
||
|
|
if got := BuildSummary(broken).DOI; got != "10.ONE_HUNDRED/x" {
|
||
|
|
t.Fatalf("invalid stored doi dropped on read: %q", got)
|
||
|
|
}
|
||
|
|
}
|