1/*2Maddy Mail Server - Composable all-in-one email server.3Copyright © 2019-2020 Max Mazurov <fox.cpp@disroot.org>, Maddy Mail Server contributors45This program is free software: you can redistribute it and/or modify6it under the terms of the GNU General Public License as published by7the Free Software Foundation, either version 3 of the License, or8(at your option) any later version.910This program is distributed in the hope that it will be useful,11but WITHOUT ANY WARRANTY; without even the implied warranty of12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the13GNU General Public License for more details.1415You should have received a copy of the GNU General Public License16along with this program. If not, see <https://www.gnu.org/licenses/>.17*/1819package config2021import (22 "testing"23)2425func TestMapProcess(t *testing.T) {26 cfg := Node{27 Children: []Node{28 {29 Name: "foo",30 Args: []string{"bar"},31 },32 },33 }3435 m := NewMap(nil, cfg)3637 foo := ""38 m.Custom("foo", false, true, nil, func(_ *Map, n Node) (interface{}, error) {39 return n.Args[0], nil40 }, &foo)4142 _, err := m.Process()43 if err != nil {44 t.Fatalf("Unexpected failure: %v", err)45 }4647 if foo != "bar" {48 t.Errorf("Incorrect value stored in variable, want 'bar', got '%s'", foo)49 }50}5152func TestMapProcess_MissingRequired(t *testing.T) {53 cfg := Node{54 Children: []Node{},55 }5657 m := NewMap(nil, cfg)5859 foo := ""60 m.Custom("foo", false, true, nil, func(_ *Map, n Node) (interface{}, error) {61 return n.Args[0], nil62 }, &foo)6364 _, err := m.Process()65 if err == nil {66 t.Errorf("Expected failure")67 }68}6970func TestMapProcess_InheritGlobal(t *testing.T) {71 cfg := Node{72 Children: []Node{},73 }7475 m := NewMap(map[string]interface{}{"foo": "bar"}, cfg)7677 foo := ""78 m.Custom("foo", true, true, nil, func(_ *Map, n Node) (interface{}, error) {79 return n.Args[0], nil80 }, &foo)8182 _, err := m.Process()83 if err != nil {84 t.Fatalf("Unexpected failure: %v", err)85 }8687 if foo != "bar" {88 t.Errorf("Incorrect value stored in variable, want 'bar', got '%s'", foo)89 }90}9192func TestMapProcess_InheritGlobal_MissingRequired(t *testing.T) {93 cfg := Node{94 Children: []Node{},95 }9697 m := NewMap(map[string]interface{}{}, cfg)9899 foo := ""100 m.Custom("foo", false, true, nil, func(_ *Map, n Node) (interface{}, error) {101 return n.Args[0], nil102 }, &foo)103104 _, err := m.Process()105 if err == nil {106 t.Errorf("Expected failure")107 }108}109110func TestMapProcess_InheritGlobal_Override(t *testing.T) {111 cfg := Node{112 Children: []Node{113 {114 Name: "foo",115 Args: []string{"bar"},116 },117 },118 }119120 m := NewMap(map[string]interface{}{}, cfg)121122 foo := ""123 m.Custom("foo", false, true, nil, func(_ *Map, n Node) (interface{}, error) {124 return n.Args[0], nil125 }, &foo)126127 _, err := m.Process()128 if err != nil {129 t.Fatalf("Unexpected failure: %v", err)130 }131132 if foo != "bar" {133 t.Errorf("Incorrect value stored in variable, want 'bar', got '%s'", foo)134 }135}136137func TestMapProcess_DefaultValue(t *testing.T) {138 cfg := Node{139 Children: []Node{},140 }141142 m := NewMap(nil, cfg)143144 foo := ""145 m.Custom("foo", false, false, func() (interface{}, error) {146 return "bar", nil147 }, func(_ *Map, n Node) (interface{}, error) {148 return n.Args[0], nil149 }, &foo)150151 _, err := m.Process()152 if err != nil {153 t.Fatalf("Unexpected failure: %v", err)154 }155156 if foo != "bar" {157 t.Errorf("Incorrect value stored in variable, want 'bar', got '%s'", foo)158 }159}160161func TestMapProcess_InheritGlobal_DefaultValue(t *testing.T) {162 cfg := Node{163 Children: []Node{},164 }165166 m := NewMap(map[string]interface{}{"foo": "baz"}, cfg)167168 foo := ""169 m.Custom("foo", true, false, func() (interface{}, error) {170 return "bar", nil171 }, func(_ *Map, n Node) (interface{}, error) {172 return n.Args[0], nil173 }, &foo)174175 _, err := m.Process()176 if err != nil {177 t.Fatalf("Unexpected failure: %v", err)178 }179180 if foo != "baz" {181 t.Errorf("Incorrect value stored in variable, want 'baz', got '%s'", foo)182 }183184 t.Run("no global", func(t *testing.T) {185 _, err := m.ProcessWith(map[string]interface{}{}, cfg)186 if err != nil {187 t.Fatalf("Unexpected failure: %v", err)188 }189190 if foo != "bar" {191 t.Errorf("Incorrect value stored in variable, want 'bar', got '%s'", foo)192 }193 })194}195196func TestMapProcess_Duplicate(t *testing.T) {197 cfg := Node{198 Children: []Node{199 {200 Name: "foo",201 Args: []string{"bar"},202 },203 {204 Name: "foo",205 Args: []string{"bar"},206 },207 },208 }209210 m := NewMap(nil, cfg)211212 foo := ""213 m.Custom("foo", false, true, nil, func(_ *Map, n Node) (interface{}, error) {214 return n.Args[0], nil215 }, &foo)216217 _, err := m.Process()218 if err == nil {219 t.Errorf("Expected failure")220 }221}222223func TestMapProcess_Unexpected(t *testing.T) {224 cfg := Node{225 Children: []Node{226 {227 Name: "foo",228 Args: []string{"baz"},229 },230 {231 Name: "bar",232 Args: []string{"baz"},233 },234 },235 }236237 m := NewMap(nil, cfg)238239 foo := ""240 m.Custom("bar", false, true, nil, func(_ *Map, n Node) (interface{}, error) {241 return n.Args[0], nil242 }, &foo)243244 _, err := m.Process()245 if err == nil {246 t.Errorf("Expected failure")247 }248249 m.AllowUnknown()250251 unknown, err := m.Process()252 if err != nil {253 t.Errorf("Unexpected failure: %v", err)254 }255256 if len(unknown) != 1 {257 t.Fatalf("Wrong amount of unknown nodes: %v", len(unknown))258 }259260 if unknown[0].Name != "foo" {261 t.Fatalf("Wrong node in unknown: %v", unknown[0].Name)262 }263}264265func TestMapInt(t *testing.T) {266 cfg := Node{267 Children: []Node{268 {269 Name: "foo",270 Args: []string{"1"},271 },272 },273 }274275 m := NewMap(nil, cfg)276277 foo := 0278 m.Int("foo", false, true, 0, &foo)279280 _, err := m.Process()281 if err != nil {282 t.Fatalf("Unexpected failure: %v", err)283 }284285 if foo != 1 {286 t.Errorf("Incorrect value stored in variable, want 1, got %d", foo)287 }288}289290func TestMapInt_Invalid(t *testing.T) {291 cfg := Node{292 Children: []Node{293 {294 Name: "foo",295 Args: []string{"AAAA"},296 },297 },298 }299300 m := NewMap(nil, cfg)301302 foo := 0303 m.Int("foo", false, true, 0, &foo)304305 _, err := m.Process()306 if err == nil {307 t.Errorf("Expected failure")308 }309}310311func TestMapFloat(t *testing.T) {312 cfg := Node{313 Children: []Node{314 {315 Name: "foo",316 Args: []string{"1"},317 },318 },319 }320321 m := NewMap(nil, cfg)322323 foo := 0.0324 m.Float("foo", false, true, 0, &foo)325326 _, err := m.Process()327 if err != nil {328 t.Fatalf("Unexpected failure: %v", err)329 }330331 if foo != 1.0 {332 t.Errorf("Incorrect value stored in variable, want 1, got %v", foo)333 }334}335336func TestMapFloat_Invalid(t *testing.T) {337 cfg := Node{338 Children: []Node{339 {340 Name: "foo",341 Args: []string{"AAAA"},342 },343 },344 }345346 m := NewMap(nil, cfg)347348 foo := 0.0349 m.Float("foo", false, true, 0, &foo)350351 _, err := m.Process()352 if err == nil {353 t.Errorf("Expected failure")354 }355}356357func TestMapBool(t *testing.T) {358 cfg := Node{359 Children: []Node{360 {361 Name: "foo",362 },363 {364 Name: "bar",365 Args: []string{"yes"},366 },367 {368 Name: "baz",369 Args: []string{"no"},370 },371 },372 }373374 m := NewMap(nil, cfg)375376 foo, bar, baz, boo := false, false, false, false377 m.Bool("foo", false, false, &foo)378 m.Bool("bar", false, false, &bar)379 m.Bool("baz", false, false, &baz)380 m.Bool("boo", false, false, &boo)381382 _, err := m.Process()383 if err != nil {384 t.Fatalf("Unexpected failure: %v", err)385 }386387 if !foo {388 t.Errorf("Incorrect value stored in variable foo, want true, got false")389 }390 if !bar {391 t.Errorf("Incorrect value stored in variable bar, want true, got false")392 }393 if baz {394 t.Errorf("Incorrect value stored in variable baz, want false, got true")395 }396 if boo {397 t.Errorf("Incorrect value stored in variable boo, want false, got true")398 }399}400401func TestParseDataSize(t *testing.T) {402 check := func(s string, ok bool, expected int) {403 val, err := ParseDataSize(s)404 if err != nil && ok {405 t.Errorf("unexpected parseDataSize('%s') fail: %v", s, err)406 return407 }408 if err == nil && !ok {409 t.Errorf("unexpected parseDataSize('%s') success, got %d", s, val)410 return411 }412 if val != expected {413 t.Errorf("parseDataSize('%s') != %d", s, expected)414 return415 }416 }417418 check("1M", true, 1024*1024)419 check("1K", true, 1024)420 check("1b", true, 1)421 check("1M 5b", true, 1024*1024+5)422 check("1M 5K 5b", true, 1024*1024+5*1024+5)423 check("0", true, 0)424 check("1", false, 0)425 check("1d", false, 0)426 check("d", false, 0)427 check("unrelated", false, 0)428 check("1M5b", false, 0)429 check("", false, 0)430 check("-5M", false, 0)431}432433func TestMap_Callback(t *testing.T) {434 called := map[string]int{}435436 cfg := Node{437 Children: []Node{438 {439 Name: "test2",440 Args: []string{"a"},441 },442 {443 Name: "test3",444 Args: []string{"b"},445 },446 {447 Name: "test3",448 Args: []string{"b"},449 },450 {451 Name: "unrelated",452 Args: []string{"b"},453 },454 },455 }456 m := NewMap(nil, cfg)457 m.Callback("test1", func(*Map, Node) error {458 called["test1"]++459 return nil460 })461 m.Callback("test2", func(_ *Map, n Node) error {462 called["test2"]++463 if n.Args[0] != "a" {464 t.Fatal("Wrong n.Args[0] for test2:", n.Args[0])465 }466 return nil467 })468 m.Callback("test3", func(_ *Map, n Node) error {469 called["test3"]++470 if n.Args[0] != "b" {471 t.Fatal("Wrong n.Args[0] for test2:", n.Args[0])472 }473 return nil474 })475 m.AllowUnknown()476 others, err := m.Process()477 if err != nil {478 t.Fatal("Unexpected error:", err)479 }480 if called["test1"] != 0 {481 t.Error("test1 CB was called when it should not")482 }483 if called["test2"] != 1 {484 t.Error("test2 CB was not called when it should")485 }486 if called["test3"] != 2 {487 t.Error("test3 CB was not called when it should")488 }489 if len(others) != 1 {490 t.Error("Wrong amount of unmatched directives")491 }492 if others[0].Name != "unrelated" {493 t.Error("Wrong directive returned in unmatched slice:", others[0].Name)494 }495}