mirror of
https://github.com/hanzoai/forge.git
synced 2026-10-30 15:00:39 +00:00
Source files keep their SPDX-License-Identifier and Hanzo copyright line; the Gitea, Gogs and LFS Test Server copyrights they used to repeat now live once in NOTICE, alongside LICENSE. The header lint accepts any copyright line above the SPDX line, so it no longer demands an upstream one. Co-authored-by: Hanzo Dev <[email protected]>
250 lines
5.6 KiB
Go
250 lines
5.6 KiB
Go
// Copyright 2026 Hanzo AI, Inc. All rights reserved.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package openapi3gen
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"slices"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func single(got map[string][]string, key string) string {
|
|
v := got[key]
|
|
if len(v) != 1 {
|
|
return ""
|
|
}
|
|
return v[0]
|
|
}
|
|
|
|
func TestEnumKey_sortsAndJoins(t *testing.T) {
|
|
key := EnumKey([]any{"b", "a", "c"})
|
|
if key != "a|b|c" {
|
|
t.Fatalf("EnumKey = %q, want %q", key, "a|b|c")
|
|
}
|
|
}
|
|
|
|
func TestEnumKey_handlesNonStringValues(t *testing.T) {
|
|
key := EnumKey([]any{2, 1, 3})
|
|
if key != "1|2|3" {
|
|
t.Fatalf("EnumKey = %q, want %q", key, "1|2|3")
|
|
}
|
|
}
|
|
|
|
func TestScanSwaggerEnumTypes_basic(t *testing.T) {
|
|
dir := t.TempDir()
|
|
src := `package fixture
|
|
|
|
// Color is a primary color.
|
|
// swagger:enum Color
|
|
type Color string
|
|
|
|
const (
|
|
ColorRed Color = "red"
|
|
ColorGreen Color = "green"
|
|
ColorBlue Color = "blue"
|
|
)
|
|
`
|
|
if err := os.WriteFile(filepath.Join(dir, "color.go"), []byte(src), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
got, err := ScanSwaggerEnumTypes([]string{dir})
|
|
if err != nil {
|
|
t.Fatalf("ScanSwaggerEnumTypes: %v", err)
|
|
}
|
|
wantKey := EnumKey([]any{"red", "green", "blue"})
|
|
if single(got, wantKey) != "Color" {
|
|
t.Fatalf("map[%q] = %q, want %q", wantKey, got[wantKey], "Color")
|
|
}
|
|
}
|
|
|
|
func TestScanSwaggerEnumTypes_orphanAnnotation(t *testing.T) {
|
|
dir := t.TempDir()
|
|
src := `package fixture
|
|
|
|
// swagger:enum Sttype
|
|
type StateType string
|
|
|
|
const (
|
|
StateOpen StateType = "open"
|
|
)
|
|
`
|
|
if err := os.WriteFile(filepath.Join(dir, "typo.go"), []byte(src), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
_, err := ScanSwaggerEnumTypes([]string{dir})
|
|
if err == nil {
|
|
t.Fatal("expected error for annotation referencing a non-matching type name")
|
|
}
|
|
if !strings.Contains(err.Error(), "Sttype") {
|
|
t.Fatalf("error %q should mention the typo'd name Sttype", err.Error())
|
|
}
|
|
}
|
|
|
|
func TestScanSwaggerEnumTypes_collision(t *testing.T) {
|
|
dir := t.TempDir()
|
|
src := `package fixture
|
|
|
|
// swagger:enum Alpha
|
|
type Alpha string
|
|
const (
|
|
AlphaX Alpha = "x"
|
|
AlphaY Alpha = "y"
|
|
)
|
|
|
|
// swagger:enum Beta
|
|
type Beta string
|
|
const (
|
|
BetaX Beta = "x"
|
|
BetaY Beta = "y"
|
|
)
|
|
`
|
|
if err := os.WriteFile(filepath.Join(dir, "dup.go"), []byte(src), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
got, err := ScanSwaggerEnumTypes([]string{dir})
|
|
if err != nil {
|
|
t.Fatalf("ScanSwaggerEnumTypes: %v", err)
|
|
}
|
|
key := EnumKey([]any{"x", "y"})
|
|
names := got[key]
|
|
if !slices.Equal(names, []string{"Alpha", "Beta"}) {
|
|
t.Fatalf("map[%q] = %v, want [Alpha Beta]", key, names)
|
|
}
|
|
}
|
|
|
|
func TestScanSwaggerEnumTypes_parseFailure(t *testing.T) {
|
|
dir := t.TempDir()
|
|
if err := os.WriteFile(filepath.Join(dir, "bad.go"), []byte("package fixture\nfunc Foo() {"), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
_, err := ScanSwaggerEnumTypes([]string{dir})
|
|
if err == nil {
|
|
t.Fatal("expected parse error, got nil")
|
|
}
|
|
}
|
|
|
|
func TestScanSwaggerEnumTypes_annotationWithoutConsts(t *testing.T) {
|
|
dir := t.TempDir()
|
|
src := `package fixture
|
|
|
|
// swagger:enum Lonely
|
|
type Lonely string
|
|
`
|
|
if err := os.WriteFile(filepath.Join(dir, "lonely.go"), []byte(src), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
_, err := ScanSwaggerEnumTypes([]string{dir})
|
|
if err == nil {
|
|
t.Fatal("expected error for annotation without consts")
|
|
}
|
|
if !strings.Contains(err.Error(), "Lonely") {
|
|
t.Fatalf("error %q should mention Lonely", err.Error())
|
|
}
|
|
}
|
|
|
|
func TestScanSwaggerEnumTypes_constsAndTypeInDifferentFiles(t *testing.T) {
|
|
dir := t.TempDir()
|
|
// Name ordering: `a_consts.go` < `b_type.go`, so readdir returns consts first.
|
|
// Old single-pass scanner would miss the values; two-pass must not.
|
|
constsSrc := `package fixture
|
|
|
|
const (
|
|
HueA Hue = "a"
|
|
HueB Hue = "b"
|
|
)
|
|
`
|
|
typeSrc := `package fixture
|
|
|
|
// swagger:enum Hue
|
|
type Hue string
|
|
`
|
|
if err := os.WriteFile(filepath.Join(dir, "a_consts.go"), []byte(constsSrc), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := os.WriteFile(filepath.Join(dir, "b_type.go"), []byte(typeSrc), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
got, err := ScanSwaggerEnumTypes([]string{dir})
|
|
if err != nil {
|
|
t.Fatalf("ScanSwaggerEnumTypes: %v", err)
|
|
}
|
|
wantKey := EnumKey([]any{"a", "b"})
|
|
if single(got, wantKey) != "Hue" {
|
|
t.Fatalf("map[%q] = %q, want %q", wantKey, got[wantKey], "Hue")
|
|
}
|
|
}
|
|
|
|
func TestScanSwaggerEnumTypes_constsBeforeType(t *testing.T) {
|
|
dir := t.TempDir()
|
|
src := `package fixture
|
|
|
|
const (
|
|
ShadeDark Shade = "dark"
|
|
ShadeLight Shade = "light"
|
|
)
|
|
|
|
// swagger:enum Shade
|
|
type Shade string
|
|
`
|
|
if err := os.WriteFile(filepath.Join(dir, "shade.go"), []byte(src), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
got, err := ScanSwaggerEnumTypes([]string{dir})
|
|
if err != nil {
|
|
t.Fatalf("ScanSwaggerEnumTypes: %v", err)
|
|
}
|
|
wantKey := EnumKey([]any{"dark", "light"})
|
|
if single(got, wantKey) != "Shade" {
|
|
t.Fatalf("map[%q] = %q, want %q", wantKey, got[wantKey], "Shade")
|
|
}
|
|
}
|
|
|
|
func TestScanSwaggerEnumTypes_groupedTypeDecl(t *testing.T) {
|
|
dir := t.TempDir()
|
|
src := `package fixture
|
|
|
|
type (
|
|
// swagger:enum Color
|
|
Color string
|
|
// swagger:enum Shade
|
|
Shade string
|
|
)
|
|
|
|
const (
|
|
ColorRed Color = "red"
|
|
ColorBlue Color = "blue"
|
|
)
|
|
|
|
const (
|
|
ShadeDark Shade = "dark"
|
|
ShadeLight Shade = "light"
|
|
)
|
|
`
|
|
if err := os.WriteFile(filepath.Join(dir, "grouped.go"), []byte(src), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
got, err := ScanSwaggerEnumTypes([]string{dir})
|
|
if err != nil {
|
|
t.Fatalf("ScanSwaggerEnumTypes: %v", err)
|
|
}
|
|
colorKey := EnumKey([]any{"red", "blue"})
|
|
shadeKey := EnumKey([]any{"dark", "light"})
|
|
if single(got, colorKey) != "Color" {
|
|
t.Fatalf("Color: map[%q] = %q, want %q", colorKey, got[colorKey], "Color")
|
|
}
|
|
if single(got, shadeKey) != "Shade" {
|
|
t.Fatalf("Shade: map[%q] = %q, want %q", shadeKey, got[shadeKey], "Shade")
|
|
}
|
|
}
|