Skip to content
quarry Artifact [d7be882e63]
Login

Artifact [d7be882e63]

Artifact d7be882e6355c616cf009308c9a706c68c758d1eb4aef63ee065458ffd31195a:


package ops

import (
	"context"
	"strings"
	"testing"
)

type valIn struct {
	Repo  string   `json:"repo" validate:"required,max=64"`
	Limit int      `json:"limit" validate:"min=1,max=500"`
	Sort  string   `json:"sort" validate:"oneof=asc|desc"`
	Tags  []string `json:"tags" validate:"max=10"`
	Note  string   `json:"note"`
}

func TestValidateOK(t *testing.T) {
	in := valIn{Repo: "sqlite", Limit: 50, Sort: "asc", Note: "anything"}
	if err := Validate(in); err != nil {
		t.Fatal(err)
	}
}

func TestValidateRequired(t *testing.T) {
	err := Validate(valIn{Limit: 1, Sort: "asc"})
	if err == nil || !strings.Contains(err.Error(), "repo") || !strings.Contains(err.Error(), "required") {
		t.Fatalf("want required error naming repo, got %v", err)
	}
}

func TestValidateNumericBounds(t *testing.T) {
	if err := Validate(valIn{Repo: "r", Limit: 0, Sort: "asc"}); err == nil {
		t.Fatal("want min violation for limit=0, got nil")
	}
	if err := Validate(valIn{Repo: "r", Limit: 501, Sort: "asc"}); err == nil {
		t.Fatal("want max violation for limit=501, got nil")
	}
}

func TestValidateStringAndSliceLength(t *testing.T) {
	if err := Validate(valIn{Repo: strings.Repeat("x", 65), Limit: 1, Sort: "asc"}); err == nil {
		t.Fatal("want max-length violation for repo, got nil")
	}
	long := make([]string, 11)
	if err := Validate(valIn{Repo: "r", Limit: 1, Sort: "asc", Tags: long}); err == nil {
		t.Fatal("want max-length violation for tags, got nil")
	}
}

func TestValidateOneof(t *testing.T) {
	if err := Validate(valIn{Repo: "r", Limit: 1, Sort: "sideways"}); err == nil {
		t.Fatal("want oneof violation, got nil")
	}
	// Empty non-required oneof field passes: oneof only constrains set values.
	if err := Validate(valIn{Repo: "r", Limit: 1}); err != nil {
		t.Fatal(err)
	}
}

func TestValidateOptionalFieldAdmitsZero(t *testing.T) {
	// Pin the semantics: min/max apply unconditionally. An optional field
	// is one without `required` whose bounds admit the zero value.
	type opt struct {
		N int `json:"n" validate:"max=5"`
	}
	if err := Validate(opt{}); err != nil {
		t.Fatal(err)
	}
}

func TestRegisterRejectsBadValidateTag(t *testing.T) {
	type badTag struct {
		X int `json:"x" validate:"min=notanumber"`
	}
	r := NewRegistry()
	err := Register(r, Op[badTag, echoOut]{
		Name:  "bad.tag",
		Kind:  Query,
		Route: "GET /bad",
		Run:   func(_ context.Context, _ badTag) (echoOut, error) { return echoOut{}, nil },
	})
	if err == nil || !strings.Contains(err.Error(), "validate") {
		t.Fatalf("want validate-tag error at register time, got %v", err)
	}
}

func TestRegisterRejectsUnknownRule(t *testing.T) {
	type badRule struct {
		X string `json:"x" validate:"shiny"`
	}
	r := NewRegistry()
	err := Register(r, Op[badRule, echoOut]{
		Name:  "bad.rule",
		Kind:  Query,
		Route: "GET /badrule",
		Run:   func(_ context.Context, _ badRule) (echoOut, error) { return echoOut{}, nil },
	})
	if err == nil || !strings.Contains(err.Error(), "shiny") {
		t.Fatalf("want unknown-rule error, got %v", err)
	}
}