Ctrl K
ComunidadGuías…

pluginapi/config_test.go

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
package pluginapi

import (
	"encoding/json"
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

var testSchema = []Field{
	{Key: "name"}, {Key: "mode"}, {Key: "flag"}, {Key: "n"}, {Key: "f"}, {Key: "opt"},
	{Key: "status"}, {Key: "list"}, {Key: "lines"}, {Key: "roles"},
}

func parse(t *testing.T, raw string) *Config {
	t.Helper()
	c, err := ParseConfig("demo", testSchema, json.RawMessage(raw))
	require.NoError(t, err, "ParseConfig(%s): %v", raw, err)

	return c
}

func TestParseConfigRejectsUnknownAndInvalid(t *testing.T) {
	for raw, want := range map[string]string{
		`{"bogus": 1}`: `demo: invalid config: unknown field "bogus"`,
		`{"name": `:    "demo: invalid config:",
		`[1]`:          "demo: invalid config:",
	} {
		_, err := ParseConfig("demo", testSchema, json.RawMessage(raw))
		require.Error(t, err)
		assert.Contains(t, err.Error(), want)
	}
	for _, raw := range []string{``, `  `, `null`, `{}`} {
		c, err := ParseConfig("demo", testSchema, json.RawMessage(raw))
		require.NoError(t, err)
		assert.Equal(t, "d", c.String("name", "d"), "%q: %v", raw, err)
	}
}

func TestConfigReaders(t *testing.T) {
	c := parse(t, `{"name": "x", "mode": "b", "flag": "yes", "n": "42", "f": 0.5, "opt": "0.25", "status": 451, "list": "a, b\n c,,", "lines": "one\n\n# two", "roles": "system, USER"}`)
	assert.Equal(t, "x", c.String("name", ""))
	assert.Equal(t, "d", c.String("missing", "d"))
	assert.Equal(t, "b", c.Choice("mode", "a", "a", "b"))
	assert.Equal(t, "a", c.Choice("missing", "a", "a", "b"))
	assert.True(t, c.Bool("flag"))
	assert.False(t, c.Bool("missing"))

	for raw, want := range map[string]bool{`true`: true, `false`: false, `"on"`: true, `"off"`: false, `"1"`: true, `"0"`: false, `"YES"`: true, `"no"`: false, `""`: false} {
		got := parse(t, `{"flag": `+raw+`}`).Bool("flag")
		assert.Equal(t, want, got, "Bool(%s) = %v", raw, got)
	}
	assert.Equal(t, 42, c.Int("n", 0, 0, 100))
	assert.Equal(t, 7, c.Int("missing", 7, 0, 100))
	assert.Equal(t, 0.5, c.Float("f", 0, 0, 1))
	assert.Equal(t, float64(2), c.Float("missing", 2, 0, 3))
	v := c.OptionalFloat("opt", 0, 1)
	require.NotNil(t, v)
	assert.Equal(t, 0.25, *v)
	assert.Nil(t, c.OptionalFloat("missing", 0, 1))
	assert.Equal(t, 451, c.BlockStatus("status"))
	assert.Equal(t, 0, c.BlockStatus("missing"))
	got := c.List("list")
	assert.Equal(t, []string{"a", "b", "c"}, got)
	assert.Nil(t, c.List("missing"))
	got = c.Lines("lines")
	assert.Equal(t, []string{"one", "", "# two"}, got)

	assert.Equal(t, map[Role]bool{RoleSystem: true, RoleDeveloper: true, RoleUser: true}, c.Roles("roles"), "Roles")
	assert.Equal(t, map[Role]bool{RoleUser: true}, c.Roles("missing", RoleUser), "Roles default")
	assert.NotNil(t, c.Raw("name"))
	assert.Nil(t, c.Raw("missing"))
	err := c.Err()
	require.NoError(t, err)

	c = parse(t, `{"list": [" a ", "", "b"], "lines": ["x", "y"], "roles": [], "flag": false, "n": ""}`)
	got = c.List("list")
	assert.Equal(t, []string{"a", "b"}, got)
	got = c.Lines("lines")
	assert.Equal(t, []string{"x", "y"}, got)

	assert.Empty(t, c.Roles("roles", RoleUser), "Roles empty")
	assert.False(t, c.Bool("flag"))
	assert.Equal(t, 5, c.Int("n", 5, 0, 9))
}

func TestConfigErrors(t *testing.T) {
	tests := []struct {
		raw  string
		read func(c *Config)
		want string
	}{
		{`{"name": 5}`, func(c *Config) { c.String("name", "") }, "demo: name must be a string"},
		{`{"mode": "z"}`, func(c *Config) { c.Choice("mode", "a", "a", "b") }, `demo: mode must be one of a, b; got "z"`},
		{`{"flag": "maybe"}`, func(c *Config) { c.Bool("flag") }, "demo: flag must be true or false"},
		{`{"n": "abc"}`, func(c *Config) { c.Int("n", 0, 0, 9) }, `demo: n must be a number, got "abc"`},
		{`{"n": true}`, func(c *Config) { c.Int("n", 0, 0, 9) }, "demo: n must be a number, got true"},
		{`{"n": 1.5}`, func(c *Config) { c.Int("n", 0, 0, 9) }, "demo: n must be a whole number, got 1.5"},
		{`{"n": 10}`, func(c *Config) { c.Int("n", 0, 0, 9) }, "demo: n must be between 0 and 9, got 10"},
		{`{"f": 3}`, func(c *Config) { c.Float("f", 0, 0, 2) }, "demo: f must be between 0 and 2, got 3"},
		{`{"f": "NaN"}`, func(c *Config) { c.Float("f", 0, 0, 2) }, `demo: f must be a number, got "NaN"`},
		{`{"f": "Inf"}`, func(c *Config) { c.Float("f", 0, 0, 2) }, `demo: f must be a number, got "Inf"`},
		{`{"opt": "nan"}`, func(c *Config) { c.OptionalFloat("opt", 0, 1) }, `demo: opt must be a number, got "nan"`},
		{`{"opt": -1}`, func(c *Config) { c.OptionalFloat("opt", 0, 1) }, "demo: opt must be between 0 and 1, got -1"},
		{`{"status": 302}`, func(c *Config) { c.BlockStatus("status") }, "demo: status must be an HTTP status between 400 and 599, got 302"},
		{`{"status": 600}`, func(c *Config) { c.BlockStatus("status") }, "demo: status must be an HTTP status between 400 and 599, got 600"},
		{`{"list": 5}`, func(c *Config) { c.List("list") }, "demo: list must be a list of strings"},
		{`{"lines": 5}`, func(c *Config) { c.Lines("lines") }, "demo: lines must be text or a list of strings"},
		{`{"roles": ["robot"]}`, func(c *Config) { c.Roles("roles") }, `demo: roles has unknown role "robot"`},
	}
	for _, tt := range tests {
		c := parse(t, tt.raw)
		tt.read(c)
		err := c.Err()
		require.Error(t, err)
		assert.Contains(t, err.Error(), tt.want)
	}
	// The first problem wins and later reads keep their defaults.
	c := parse(t, `{"name": 5, "n": "x"}`)
	assert.Equal(t, "d", c.String("name", "d"))
	assert.Equal(t, 3, c.Int("n", 3, 0, 9))
	err := c.Err()
	require.Error(t, err)
	assert.Contains(t, err.Error(), "name must be a string")
}

func TestEnforcement(t *testing.T) {
	e := Enforcement{Action: ActionBlock, Message: "no", BlockStatus: 451}
	d := e.Enforce("c", 1)
	assert.Equal(t, ActionBlock, d.Action)
	assert.Equal(t, 451, d.Status)
	assert.Equal(t, "c", d.Code)
	assert.Equal(t, "no", d.Message)
	assert.Equal(t, 1, d.Detail, "block = %+v", d)

	e.Action = ActionRespond
	d = e.Enforce("c", nil)
	assert.Equal(t, ActionRespond, d.Action)
	assert.Equal(t, "c", d.Code)
	assert.Equal(t, "no", d.Response.Text(0), "respond = %+v", d)

	e.RespondText = "sorry"
	d = e.Reject("c", nil)
	assert.Equal(t, "sorry", d.Response.Text(0), "respond text = %+v", d)

	e.Action = ActionWarn
	d = e.Enforce("c", 2)
	assert.Equal(t, ActionWarn, d.Action)
	assert.Equal(t, "c", d.Code)
	assert.Equal(t, "no", d.Message)
	assert.Equal(t, 2, d.Detail, "warn = %+v", d)
	d = e.Reject("c", nil)
	assert.Equal(t, ActionBlock, d.Action)
	assert.Equal(t, 451, d.Status, "reject under warn = %+v", d)
	f := BlockStatusField()
	assert.Equal(t, "block_status", f.Key)
	assert.Equal(t, InputNumber, f.Input)
	assert.NotEmpty(t, f.Help, "field = %+v", f)
}