mirror of
https://tangled.org/evan.jarrett.net/at-container-registry
synced 2026-08-29 04:06:58 +00:00
321 lines
8.6 KiB
Go
321 lines
8.6 KiB
Go
package handlers
|
|
|
|
import (
|
|
"encoding/json"
|
|
"testing"
|
|
)
|
|
|
|
func TestNewJSONLDOrganization(t *testing.T) {
|
|
registryURL := "atcr.io"
|
|
shortName := "ATCR"
|
|
fullName := "AT Container Registry"
|
|
org := NewJSONLDOrganization(registryURL, shortName, fullName)
|
|
|
|
// Verify required fields
|
|
if org.Context != "https://schema.org" {
|
|
t.Errorf("Context = %q, want %q", org.Context, "https://schema.org")
|
|
}
|
|
if org.Type != "Organization" {
|
|
t.Errorf("Type = %q, want %q", org.Type, "Organization")
|
|
}
|
|
if org.Name != shortName {
|
|
t.Errorf("Name = %q, want %q", org.Name, shortName)
|
|
}
|
|
if org.AlternateName != fullName {
|
|
t.Errorf("AlternateName = %q, want %q", org.AlternateName, fullName)
|
|
}
|
|
if org.URL != "https://atcr.io" {
|
|
t.Errorf("URL = %q, want %q", org.URL, "https://atcr.io")
|
|
}
|
|
if org.Logo != "https://atcr.io/favicon.svg" {
|
|
t.Errorf("Logo = %q, want %q", org.Logo, "https://atcr.io/favicon.svg")
|
|
}
|
|
|
|
// Verify it marshals to valid JSON
|
|
data, err := json.Marshal(org)
|
|
if err != nil {
|
|
t.Fatalf("Failed to marshal organization: %v", err)
|
|
}
|
|
if len(data) == 0 {
|
|
t.Error("Marshaled JSON is empty")
|
|
}
|
|
}
|
|
|
|
func TestNewJSONLDWebSite(t *testing.T) {
|
|
registryURL := "atcr.io"
|
|
shortName := "ATCR"
|
|
site := NewJSONLDWebSite(registryURL, shortName)
|
|
|
|
// Verify required fields
|
|
if site.Context != "https://schema.org" {
|
|
t.Errorf("Context = %q, want %q", site.Context, "https://schema.org")
|
|
}
|
|
if site.Type != "WebSite" {
|
|
t.Errorf("Type = %q, want %q", site.Type, "WebSite")
|
|
}
|
|
if site.Name != shortName {
|
|
t.Errorf("Name = %q, want %q", site.Name, shortName)
|
|
}
|
|
if site.URL != "https://atcr.io" {
|
|
t.Errorf("URL = %q, want %q", site.URL, "https://atcr.io")
|
|
}
|
|
|
|
// Verify search action
|
|
if site.PotentialAction == nil {
|
|
t.Fatal("PotentialAction is nil")
|
|
}
|
|
if site.PotentialAction.Type != "SearchAction" {
|
|
t.Errorf("PotentialAction.Type = %q, want %q", site.PotentialAction.Type, "SearchAction")
|
|
}
|
|
if site.PotentialAction.Target == nil {
|
|
t.Fatal("PotentialAction.Target is nil")
|
|
}
|
|
expectedTemplate := "https://atcr.io/search?q={search_term_string}"
|
|
if site.PotentialAction.Target.URLTemplate != expectedTemplate {
|
|
t.Errorf("URLTemplate = %q, want %q", site.PotentialAction.Target.URLTemplate, expectedTemplate)
|
|
}
|
|
|
|
// Verify it marshals to valid JSON
|
|
data, err := json.Marshal(site)
|
|
if err != nil {
|
|
t.Fatalf("Failed to marshal website: %v", err)
|
|
}
|
|
if len(data) == 0 {
|
|
t.Error("Marshaled JSON is empty")
|
|
}
|
|
}
|
|
|
|
func TestNewJSONLDSoftwareSourceCode(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
registryURL string
|
|
handle string
|
|
repoName string
|
|
description string
|
|
license string
|
|
sourceURL string
|
|
}{
|
|
{
|
|
name: "full details",
|
|
registryURL: "atcr.io",
|
|
handle: "alice.bsky.social",
|
|
repoName: "myapp",
|
|
description: "A cool container image",
|
|
license: "MIT",
|
|
sourceURL: "https://github.com/alice/myapp",
|
|
},
|
|
{
|
|
name: "minimal details",
|
|
registryURL: "atcr.io",
|
|
handle: "bob.test",
|
|
repoName: "simple",
|
|
description: "",
|
|
license: "",
|
|
sourceURL: "",
|
|
},
|
|
{
|
|
name: "with license only",
|
|
registryURL: "localhost:5000",
|
|
handle: "dev",
|
|
repoName: "test-image",
|
|
description: "Test image",
|
|
license: "Apache-2.0",
|
|
sourceURL: "",
|
|
},
|
|
}
|
|
|
|
shortName := "ATCR"
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
code := NewJSONLDSoftwareSourceCode(
|
|
tt.registryURL,
|
|
tt.handle,
|
|
tt.repoName,
|
|
tt.description,
|
|
tt.license,
|
|
tt.sourceURL,
|
|
shortName,
|
|
)
|
|
|
|
// Verify required fields
|
|
if code.Context != "https://schema.org" {
|
|
t.Errorf("Context = %q, want %q", code.Context, "https://schema.org")
|
|
}
|
|
if code.Type != "SoftwareSourceCode" {
|
|
t.Errorf("Type = %q, want %q", code.Type, "SoftwareSourceCode")
|
|
}
|
|
|
|
expectedName := tt.handle + "/" + tt.repoName
|
|
if code.Name != expectedName {
|
|
t.Errorf("Name = %q, want %q", code.Name, expectedName)
|
|
}
|
|
|
|
expectedCodeRepo := "https://" + tt.registryURL + "/r/" + tt.handle + "/" + tt.repoName
|
|
if code.CodeRepository != expectedCodeRepo {
|
|
t.Errorf("CodeRepository = %q, want %q", code.CodeRepository, expectedCodeRepo)
|
|
}
|
|
|
|
// Verify author
|
|
if code.Author == nil {
|
|
t.Fatal("Author is nil")
|
|
}
|
|
if code.Author.Type != "Person" {
|
|
t.Errorf("Author.Type = %q, want %q", code.Author.Type, "Person")
|
|
}
|
|
if code.Author.Name != tt.handle {
|
|
t.Errorf("Author.Name = %q, want %q", code.Author.Name, tt.handle)
|
|
}
|
|
|
|
// Verify publisher
|
|
if code.Publisher == nil {
|
|
t.Fatal("Publisher is nil")
|
|
}
|
|
if code.Publisher.Name != shortName {
|
|
t.Errorf("Publisher.Name = %q, want %q", code.Publisher.Name, shortName)
|
|
}
|
|
|
|
// Verify optional fields
|
|
if tt.license != "" && code.License != tt.license {
|
|
t.Errorf("License = %q, want %q", code.License, tt.license)
|
|
}
|
|
if tt.license == "" && code.License != "" {
|
|
t.Errorf("License = %q, want empty", code.License)
|
|
}
|
|
|
|
if tt.sourceURL != "" && code.IsBasedOn != tt.sourceURL {
|
|
t.Errorf("IsBasedOn = %q, want %q", code.IsBasedOn, tt.sourceURL)
|
|
}
|
|
if tt.sourceURL == "" && code.IsBasedOn != "" {
|
|
t.Errorf("IsBasedOn = %q, want empty", code.IsBasedOn)
|
|
}
|
|
|
|
// Verify it marshals to valid JSON
|
|
data, err := json.Marshal(code)
|
|
if err != nil {
|
|
t.Fatalf("Failed to marshal code: %v", err)
|
|
}
|
|
if len(data) == 0 {
|
|
t.Error("Marshaled JSON is empty")
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestNewJSONLDProfilePage(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
registryURL string
|
|
handle string
|
|
avatar string
|
|
}{
|
|
{
|
|
name: "with avatar",
|
|
registryURL: "atcr.io",
|
|
handle: "alice.bsky.social",
|
|
avatar: "https://cdn.bsky.app/avatar/alice.jpg",
|
|
},
|
|
{
|
|
name: "without avatar",
|
|
registryURL: "atcr.io",
|
|
handle: "bob.test",
|
|
avatar: "",
|
|
},
|
|
{
|
|
name: "localhost registry",
|
|
registryURL: "localhost:5000",
|
|
handle: "dev",
|
|
avatar: "",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
page := NewJSONLDProfilePage(tt.registryURL, tt.handle, tt.avatar)
|
|
|
|
// Verify required fields
|
|
if page.Context != "https://schema.org" {
|
|
t.Errorf("Context = %q, want %q", page.Context, "https://schema.org")
|
|
}
|
|
if page.Type != "ProfilePage" {
|
|
t.Errorf("Type = %q, want %q", page.Type, "ProfilePage")
|
|
}
|
|
|
|
// Verify main entity
|
|
if page.MainEntity == nil {
|
|
t.Fatal("MainEntity is nil")
|
|
}
|
|
if page.MainEntity.Type != "Person" {
|
|
t.Errorf("MainEntity.Type = %q, want %q", page.MainEntity.Type, "Person")
|
|
}
|
|
if page.MainEntity.Name != tt.handle {
|
|
t.Errorf("MainEntity.Name = %q, want %q", page.MainEntity.Name, tt.handle)
|
|
}
|
|
|
|
expectedURL := "https://" + tt.registryURL + "/u/" + tt.handle
|
|
if page.MainEntity.URL != expectedURL {
|
|
t.Errorf("MainEntity.URL = %q, want %q", page.MainEntity.URL, expectedURL)
|
|
}
|
|
|
|
// Verify avatar handling
|
|
if tt.avatar != "" && page.MainEntity.Image != tt.avatar {
|
|
t.Errorf("MainEntity.Image = %q, want %q", page.MainEntity.Image, tt.avatar)
|
|
}
|
|
if tt.avatar == "" && page.MainEntity.Image != "" {
|
|
t.Errorf("MainEntity.Image = %q, want empty", page.MainEntity.Image)
|
|
}
|
|
|
|
// Verify it marshals to valid JSON
|
|
data, err := json.Marshal(page)
|
|
if err != nil {
|
|
t.Fatalf("Failed to marshal page: %v", err)
|
|
}
|
|
if len(data) == 0 {
|
|
t.Error("Marshaled JSON is empty")
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestJSONLD_ValidJSON(t *testing.T) {
|
|
// Test that all constructors produce valid JSON that can be unmarshaled
|
|
registryURL := "atcr.io"
|
|
shortName := "ATCR"
|
|
fullName := "AT Container Registry"
|
|
|
|
testCases := []struct {
|
|
name string
|
|
data any
|
|
}{
|
|
{"Organization", NewJSONLDOrganization(registryURL, shortName, fullName)},
|
|
{"WebSite", NewJSONLDWebSite(registryURL, shortName)},
|
|
{"SoftwareSourceCode", NewJSONLDSoftwareSourceCode(registryURL, "alice", "myapp", "desc", "MIT", "https://github.com/alice/myapp", shortName)},
|
|
{"ProfilePage", NewJSONLDProfilePage(registryURL, "alice", "https://example.com/avatar.jpg")},
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
// Marshal to JSON
|
|
data, err := json.MarshalIndent(tc.data, "", " ")
|
|
if err != nil {
|
|
t.Fatalf("Failed to marshal %s: %v", tc.name, err)
|
|
}
|
|
|
|
// Unmarshal back to verify it's valid JSON
|
|
var result map[string]any
|
|
if err := json.Unmarshal(data, &result); err != nil {
|
|
t.Fatalf("Failed to unmarshal %s: %v\nJSON: %s", tc.name, err, string(data))
|
|
}
|
|
|
|
// Verify @context is present
|
|
if _, ok := result["@context"]; !ok {
|
|
t.Errorf("%s missing @context field", tc.name)
|
|
}
|
|
|
|
// Verify @type is present
|
|
if _, ok := result["@type"]; !ok {
|
|
t.Errorf("%s missing @type field", tc.name)
|
|
}
|
|
})
|
|
}
|
|
}
|