128 lines
4.1 KiB
Go
128 lines
4.1 KiB
Go
package apigen
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestFieldDocumentationAndFormat(t *testing.T) {
|
|
source := "// 项目说明\n type Req{\n// 状态\n State int `json:\"state,options=0|1\" example:\"1\" enumDescriptions:\"[\\\"禁用\\\",\\\"启用\\\"]\"` // 状态值\n /* 第一行\n 第二行 */\nName string `json:\"name\" example:\"企业名称\"`\n}\nservice demo{\n @handler echo\npost /echo (Req) returns (Req)\n}\n"
|
|
formatted, err := Format([]byte(source))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
again, err := Format(formatted)
|
|
if err != nil || !bytes.Equal(formatted, again) {
|
|
t.Fatal("format is not idempotent", err, string(again))
|
|
}
|
|
if !bytes.Contains(formatted, []byte(" // 状态\n State")) {
|
|
t.Fatal(string(formatted))
|
|
}
|
|
spec, err := parseText(t, string(formatted))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
c, err := Compile(spec)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if spec.Types[0].Fields[0].Description != "状态\n状态值" || spec.Types[0].Fields[1].Description != "第一行\n第二行" {
|
|
t.Fatalf("%+v", spec.Types[0].Fields)
|
|
}
|
|
schema, err := c.Bindings["Req"].ResponseSchema()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
state := schema.Properties["state"]
|
|
if state.Description != "状态\n状态值" || len(state.EnumDescriptions) != 2 || state.Example != json.Number("1") {
|
|
t.Fatalf("%+v", state)
|
|
}
|
|
dir := t.TempDir()
|
|
entry := filepath.Join(dir, "demo.api")
|
|
writeFile(t, entry, source)
|
|
if _, err = FormatProject(entry, true); err == nil {
|
|
t.Fatal("check accepted drift")
|
|
}
|
|
if readFile(t, entry) != source {
|
|
t.Fatal("check wrote source")
|
|
}
|
|
if _, err = FormatProject(entry, false); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, err = FormatProject(entry, true); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
project := filepath.Join(t.TempDir(), "demo")
|
|
if _, err = Generate(Options{API: entry, Dir: project, Module: "example.com/docs", FrameworkDir: frameworkRoot(t)}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
dto := readFile(t, filepath.Join(project, "internal/types/"+dtoFile("demo.api:1:1")))
|
|
if !strings.Contains(dto, "// 状态值") || !strings.Contains(dto, `description:"状态\n状态值"`) {
|
|
t.Fatal(dto)
|
|
}
|
|
// Invalid examples fail before project output is created.
|
|
bad := strings.Replace(source, "example:\"1\"", "example:\"9\"", 1)
|
|
writeFile(t, entry, bad)
|
|
if _, err = FormatProject(entry, false); err == nil {
|
|
t.Fatal("invalid enum example accepted")
|
|
}
|
|
if data, _ := os.ReadFile(entry); string(data) != bad {
|
|
t.Fatal("invalid source changed")
|
|
}
|
|
}
|
|
|
|
func TestFormatAlignsFieldsAndPreservesTokens(t *testing.T) {
|
|
source := []byte("type Req {\n Name string `json:\"name\"` // 名称\n Sequence int64 `json:\"sequence\"` // 编号\n}\n")
|
|
out, err := Format(source)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
again, err := Format(out)
|
|
if err != nil || !bytes.Equal(out, again) {
|
|
t.Fatal("alignment not idempotent", err)
|
|
}
|
|
lines := strings.Split(string(out), "\n")
|
|
if strings.Index(lines[1], "`") != strings.Index(lines[2], "`") || strings.Index(lines[1], "//") != strings.Index(lines[2], "//") {
|
|
t.Fatal("fields not aligned", string(out))
|
|
}
|
|
for _, literal := range []string{"`json:\"name\"`", "`json:\"sequence\"`", "// 名称", "// 编号"} {
|
|
if !bytes.Contains(out, []byte(literal)) {
|
|
t.Fatal("literal changed", literal)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestRequestPolicyCannotCreateGETBody(t *testing.T) {
|
|
for _, source := range []string{
|
|
"service demo { @handler get\n @request(body: required)\n get /x }",
|
|
"@app(request: {\"body\":\"optional\"})\n service demo { @handler get\n get /x }",
|
|
} {
|
|
spec, err := parseText(t, source)
|
|
if err == nil {
|
|
_, err = Compile(spec)
|
|
}
|
|
if err == nil {
|
|
t.Fatal("GET body policy accepted")
|
|
}
|
|
}
|
|
}
|
|
func TestFormatLiteralPreservation(t *testing.T) {
|
|
source := []byte("type Demo {\n Body string `json:\"body\"\ndescription:\"literal space\"`\n}\n")
|
|
out, err := Format(source)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !bytes.Contains(out, []byte("`json:\"body\"\ndescription:\"literal space\"`")) {
|
|
t.Fatal(string(out))
|
|
}
|
|
for _, src := range []string{"type X {", "}", "info (title:\"unterminated)"} {
|
|
if _, err := Format([]byte(src)); err == nil {
|
|
t.Fatal("invalid input accepted")
|
|
}
|
|
}
|
|
}
|