| 1 | // SPDX-License-Identifier: GPL-3.0-or-later |
| 2 | |
| 3 | package funcapi |
| 4 | |
| 5 | import ( |
| 6 | "encoding/json" |
| 7 | "testing" |
| 8 | |
| 9 | "github.com/stretchr/testify/assert" |
| 10 | "github.com/stretchr/testify/require" |
| 11 | ) |
| 12 | |
| 13 | func TestParamConfigRequiredParam(t *testing.T) { |
| 14 | sortDir := FieldSortDescending |
| 15 | cfg := ParamConfig{ |
| 16 | ID: "__sort", |
| 17 | Name: "Sort", |
| 18 | Help: "Select a sort", |
| 19 | Selection: ParamSelect, |
| 20 | UniqueView: true, |
| 21 | Options: []ParamOption{ |
| 22 | {ID: "calls", Name: "Calls"}, |
| 23 | {ID: "time", Name: "Time", Default: true, Sort: &sortDir}, |
| 24 | {ID: "disabled", Name: "Disabled", Disabled: true}, |
| 25 | }, |
| 26 | } |
| 27 | |
| 28 | param := cfg.RequiredParam() |
| 29 | assert.Equal(t, "__sort", param["id"]) |
| 30 | assert.Equal(t, "Sort", param["name"]) |
| 31 | assert.Equal(t, "select", param["type"]) |
| 32 | assert.Equal(t, "Select a sort", param["help"]) |
| 33 | assert.Equal(t, true, param["unique_view"]) |
| 34 | |
| 35 | options, ok := param["options"].([]map[string]any) |
| 36 | require.True(t, ok, "options should be []map[string]any") |
| 37 | require.Len(t, options, 3) |
| 38 | |
| 39 | assert.Equal(t, "calls", options[0]["id"]) |
| 40 | assert.Equal(t, "Calls", options[0]["name"]) |
| 41 | _, hasDefault0 := options[0]["defaultSelected"] |
| 42 | assert.False(t, hasDefault0) |
| 43 | |
| 44 | assert.Equal(t, "time", options[1]["id"]) |
| 45 | assert.Equal(t, "Time", options[1]["name"]) |
| 46 | assert.Equal(t, "descending", options[1]["sort"]) |
| 47 | assert.Equal(t, true, options[1]["defaultSelected"]) |
| 48 | |
| 49 | assert.Equal(t, "disabled", options[2]["id"]) |
| 50 | assert.Equal(t, "Disabled", options[2]["name"]) |
| 51 | assert.Equal(t, true, options[2]["disabled"]) |
| 52 | |
| 53 | data, err := json.Marshal(param) |
| 54 | require.NoError(t, err) |
| 55 | assert.Contains(t, string(data), "\"defaultSelected\"") |
| 56 | } |
| 57 | |
| 58 | func TestBuildParamOptions_DefaultFallback(t *testing.T) { |
| 59 | cfg := ParamConfig{ |
| 60 | ID: "db", |
| 61 | Name: "Database", |
| 62 | Selection: ParamSelect, |
| 63 | Options: []ParamOption{ |
| 64 | {ID: "a", Name: "A"}, |
| 65 | {ID: "b", Name: "B"}, |
| 66 | }, |
| 67 | } |
| 68 | |
| 69 | param := cfg.RequiredParam() |
| 70 | options := param["options"].([]map[string]any) |
| 71 | require.Len(t, options, 2) |
| 72 | assert.Equal(t, true, options[0]["defaultSelected"], "first option should be default when none explicitly set") |
| 73 | _, hasDefault := options[1]["defaultSelected"] |
| 74 | assert.False(t, hasDefault) |
| 75 | } |
| 76 | |
| 77 | func TestResolveParam_Select(t *testing.T) { |
| 78 | cfg := ParamConfig{ |
| 79 | ID: "db", |
| 80 | Name: "Database", |
| 81 | Selection: ParamSelect, |
| 82 | Options: []ParamOption{ |
| 83 | {ID: "a", Name: "A"}, |
| 84 | {ID: "b", Name: "B", Default: true}, |
| 85 | }, |
| 86 | } |
| 87 | |
| 88 | resolved := ResolveParam(cfg, []string{"a"}) |
| 89 | assert.Equal(t, []string{"a"}, resolved.IDs) |
| 90 | |
| 91 | resolved = ResolveParam(cfg, []string{"missing"}) |
| 92 | assert.Equal(t, []string{"b"}, resolved.IDs) |
| 93 | |
| 94 | cfg.Options[1].Default = false |
| 95 | resolved = ResolveParam(cfg, []string{"missing"}) |
| 96 | assert.Equal(t, []string{"a"}, resolved.IDs) |
| 97 | } |
| 98 | |
| 99 | func TestResolveParam_MultiSelect(t *testing.T) { |
| 100 | cfg := ParamConfig{ |
| 101 | ID: "cols", |
| 102 | Name: "Columns", |
| 103 | Selection: ParamMultiSelect, |
| 104 | Options: []ParamOption{ |
| 105 | {ID: "a", Name: "A", Default: true}, |
| 106 | {ID: "b", Name: "B"}, |
| 107 | {ID: "c", Name: "C", Default: true}, |
| 108 | }, |
| 109 | } |
| 110 | |
| 111 | resolved := ResolveParam(cfg, []string{"b", "c", "missing"}) |
| 112 | assert.Equal(t, []string{"b", "c"}, resolved.IDs) |
| 113 | |
| 114 | resolved = ResolveParam(cfg, []string{"missing"}) |
| 115 | assert.Equal(t, []string{"a", "c"}, resolved.IDs) |
| 116 | |
| 117 | cfg.Options[0].Default = false |
| 118 | cfg.Options[2].Default = false |
| 119 | resolved = ResolveParam(cfg, nil) |
| 120 | assert.Equal(t, []string{"a"}, resolved.IDs) |
| 121 | } |
| 122 | |
| 123 | func TestResolvedParamsHelpers(t *testing.T) { |
| 124 | params := ResolvedParams{ |
| 125 | "__sort": { |
| 126 | IDs: []string{"calls"}, |
| 127 | Options: []ParamOption{ |
| 128 | {ID: "calls", Column: "count_calls"}, |
| 129 | }, |
| 130 | }, |
| 131 | "db": { |
| 132 | IDs: []string{"main"}, |
| 133 | Options: []ParamOption{ |
| 134 | {ID: "main"}, |
| 135 | }, |
| 136 | }, |
| 137 | } |
| 138 | |
| 139 | assert.Equal(t, []string{"calls"}, params.Get("__sort")) |
| 140 | assert.Equal(t, "calls", params.GetOne("__sort")) |
| 141 | opt, ok := params.Option("__sort") |
| 142 | require.True(t, ok) |
| 143 | assert.Equal(t, "calls", opt.ID) |
| 144 | assert.Equal(t, "count_calls", params.Column("__sort")) |
| 145 | assert.Equal(t, "main", params.Column("db")) |
| 146 | assert.Equal(t, "", params.Column("missing")) |
| 147 | } |
| 148 | |
| 149 | func TestMergeParamConfigs(t *testing.T) { |
| 150 | base := []ParamConfig{ |
| 151 | {ID: "a"}, |
| 152 | {ID: "b"}, |
| 153 | } |
| 154 | overrides := []ParamConfig{ |
| 155 | {ID: "b", Name: "override"}, |
| 156 | {ID: "c"}, |
| 157 | } |
| 158 | |
| 159 | merged := MergeParamConfigs(base, overrides) |
| 160 | require.Len(t, merged, 3) |
| 161 | assert.Equal(t, "a", merged[0].ID) |
| 162 | assert.Equal(t, "b", merged[1].ID) |
| 163 | assert.Equal(t, "override", merged[1].Name) |
| 164 | assert.Equal(t, "c", merged[2].ID) |
| 165 | } |