Files
go-omni/cmd/go-omni/apigen/documentRefs_test.go

108 lines
4.0 KiB
Go

package apigen
import (
"encoding/json"
"fmt"
apierrors "git.yuntuo.hk/k2safe/go-omni/errors"
"strings"
"testing"
)
func TestSharedErrorDocumentReferences(t *testing.T) {
source := `@app(defaultResponse: Common)
response Common(codeType:int32;successCode:0;errorCode:9999;messageField:msg;dataMode:always)
service demo {
`
for i := 0; i < 16; i++ {
kind := "string"
if i%2 == 0 {
kind = "int64"
}
source += fmt.Sprintf("@handler list%d\nget /list%d returns ([]%s)\n", i, i, kind)
}
source += "}\n"
spec, err := parseText(t, source)
if err != nil {
t.Fatal(err)
}
catalog := apierrors.Catalog{DefaultStatus: 400, Definitions: map[string]apierrors.Definition{}}
for i := 0; i < 80; i++ {
status := 400
if i%2 == 0 {
status = 200
}
catalog.Definitions[fmt.Sprintf("ERROR_%d", i)] = apierrors.Definition{Status: status, Code: 400000 + i, Message: strings.Repeat("说明", 40) + "{label}不能超过{max}个字符", Params: []apierrors.Parameter{{Name: "label", Type: "string", Example: "企业名称"}, {Name: "max", Type: "int", Example: 100}}}
}
spec.DocumentCatalog = &catalog
compiled, err := Compile(spec)
if err != nil {
t.Fatal(err)
}
var raw map[string]any
if err = json.Unmarshal(compiled.Document, &raw); err != nil {
t.Fatal(err)
}
components := raw["components"].(map[string]any)
for _, kind := range []string{"responses", "examples"} {
if len(components[kind].(map[string]any)) == 0 {
t.Fatal("missing shared", kind)
}
}
expanded := document(t, compiled)
for i := 0; i < 16; i++ {
responses := operation(t, expanded, fmt.Sprintf("/list%d", i), "get")["responses"].(map[string]any)
for _, status := range []string{"200", "400"} {
media := responses[status].(map[string]any)["content"].(map[string]any)["application/json"].(map[string]any)
if len(media["examples"].(map[string]any)) != 40 {
t.Fatal("examples lost")
}
if status == "200" {
choices := media["schema"].(map[string]any)["anyOf"].([]any)
if len(choices) != 2 || choices[0].(map[string]any)["properties"].(map[string]any)["data"].(map[string]any)["type"] != "array" {
t.Fatal("200 success shape lost")
}
}
for _, example := range media["examples"].(map[string]any) {
value := example.(map[string]any)["value"].(map[string]any)
if _, ok := value["data"]; !ok || value["data"] != nil || !strings.Contains(value["msg"].(string), "企业名称不能超过100个字符") {
t.Fatal(value)
}
}
}
}
expandedBytes, _ := json.MarshalIndent(expanded, "", " ")
if len(compiled.Document)*5 > len(expandedBytes) {
t.Fatalf("poor dedup: %d vs %d", len(compiled.Document), len(expandedBytes))
}
again, err := Compile(spec)
if err != nil || string(again.Document) != string(compiled.Document) {
t.Fatal("non-deterministic document", err)
}
before, _ := json.Marshal(raw)
compactDocument(raw)
data, _ := json.Marshal(raw)
if string(data) != string(before) {
t.Fatal("compaction not idempotent")
}
}
func TestSharedSchemasAndLiteralExampleReference(t *testing.T) {
doc := map[string]any{"components": map[string]any{}, "paths": map[string]any{}}
paths := doc["paths"].(map[string]any)
for _, name := range []string{"first", "second", "third"} {
schema := map[string]any{"type": "object", "description": strings.Repeat("schema description ", 40)}
example := map[string]any{"summary": strings.Repeat("example ", 50), "value": map[string]any{"$ref": "literal business field"}}
paths["/"+name] = map[string]any{"get": map[string]any{"responses": map[string]any{"200": map[string]any{"description": name, "content": map[string]any{"application/json": map[string]any{"schema": schema, "examples": map[string]any{"same": example}}}}}}}
}
compactDocument(doc)
components := doc["components"].(map[string]any)
if len(components["schemas"].(map[string]any)) != 1 {
t.Fatal("schema not shared")
}
for _, example := range components["examples"].(map[string]any) {
if example.(map[string]any)["value"].(map[string]any)["$ref"] != "literal business field" {
t.Fatal("payload reference interpreted")
}
}
}