maddy

Fork https://github.com/foxcpp/maddy

git clone git://git.lin.moe/go/maddy.git

  1/*
  2Maddy Mail Server - Composable all-in-one email server.
  3Copyright © 2019-2020 Max Mazurov <fox.cpp@disroot.org>, Maddy Mail Server contributors
  4
  5This program is free software: you can redistribute it and/or modify
  6it under the terms of the GNU General Public License as published by
  7the Free Software Foundation, either version 3 of the License, or
  8(at your option) any later version.
  9
 10This program is distributed in the hope that it will be useful,
 11but WITHOUT ANY WARRANTY; without even the implied warranty of
 12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 13GNU General Public License for more details.
 14
 15You should have received a copy of the GNU General Public License
 16along with this program.  If not, see <https://www.gnu.org/licenses/>.
 17*/
 18
 19package config
 20
 21import (
 22	"testing"
 23)
 24
 25func TestMapProcess(t *testing.T) {
 26	cfg := Node{
 27		Children: []Node{
 28			{
 29				Name: "foo",
 30				Args: []string{"bar"},
 31			},
 32		},
 33	}
 34
 35	m := NewMap(nil, cfg)
 36
 37	foo := ""
 38	m.Custom("foo", false, true, nil, func(_ *Map, n Node) (interface{}, error) {
 39		return n.Args[0], nil
 40	}, &foo)
 41
 42	_, err := m.Process()
 43	if err != nil {
 44		t.Fatalf("Unexpected failure: %v", err)
 45	}
 46
 47	if foo != "bar" {
 48		t.Errorf("Incorrect value stored in variable, want 'bar', got '%s'", foo)
 49	}
 50}
 51
 52func TestMapProcess_MissingRequired(t *testing.T) {
 53	cfg := Node{
 54		Children: []Node{},
 55	}
 56
 57	m := NewMap(nil, cfg)
 58
 59	foo := ""
 60	m.Custom("foo", false, true, nil, func(_ *Map, n Node) (interface{}, error) {
 61		return n.Args[0], nil
 62	}, &foo)
 63
 64	_, err := m.Process()
 65	if err == nil {
 66		t.Errorf("Expected failure")
 67	}
 68}
 69
 70func TestMapProcess_InheritGlobal(t *testing.T) {
 71	cfg := Node{
 72		Children: []Node{},
 73	}
 74
 75	m := NewMap(map[string]interface{}{"foo": "bar"}, cfg)
 76
 77	foo := ""
 78	m.Custom("foo", true, true, nil, func(_ *Map, n Node) (interface{}, error) {
 79		return n.Args[0], nil
 80	}, &foo)
 81
 82	_, err := m.Process()
 83	if err != nil {
 84		t.Fatalf("Unexpected failure: %v", err)
 85	}
 86
 87	if foo != "bar" {
 88		t.Errorf("Incorrect value stored in variable, want 'bar', got '%s'", foo)
 89	}
 90}
 91
 92func TestMapProcess_InheritGlobal_MissingRequired(t *testing.T) {
 93	cfg := Node{
 94		Children: []Node{},
 95	}
 96
 97	m := NewMap(map[string]interface{}{}, cfg)
 98
 99	foo := ""
100	m.Custom("foo", false, true, nil, func(_ *Map, n Node) (interface{}, error) {
101		return n.Args[0], nil
102	}, &foo)
103
104	_, err := m.Process()
105	if err == nil {
106		t.Errorf("Expected failure")
107	}
108}
109
110func TestMapProcess_InheritGlobal_Override(t *testing.T) {
111	cfg := Node{
112		Children: []Node{
113			{
114				Name: "foo",
115				Args: []string{"bar"},
116			},
117		},
118	}
119
120	m := NewMap(map[string]interface{}{}, cfg)
121
122	foo := ""
123	m.Custom("foo", false, true, nil, func(_ *Map, n Node) (interface{}, error) {
124		return n.Args[0], nil
125	}, &foo)
126
127	_, err := m.Process()
128	if err != nil {
129		t.Fatalf("Unexpected failure: %v", err)
130	}
131
132	if foo != "bar" {
133		t.Errorf("Incorrect value stored in variable, want 'bar', got '%s'", foo)
134	}
135}
136
137func TestMapProcess_DefaultValue(t *testing.T) {
138	cfg := Node{
139		Children: []Node{},
140	}
141
142	m := NewMap(nil, cfg)
143
144	foo := ""
145	m.Custom("foo", false, false, func() (interface{}, error) {
146		return "bar", nil
147	}, func(_ *Map, n Node) (interface{}, error) {
148		return n.Args[0], nil
149	}, &foo)
150
151	_, err := m.Process()
152	if err != nil {
153		t.Fatalf("Unexpected failure: %v", err)
154	}
155
156	if foo != "bar" {
157		t.Errorf("Incorrect value stored in variable, want 'bar', got '%s'", foo)
158	}
159}
160
161func TestMapProcess_InheritGlobal_DefaultValue(t *testing.T) {
162	cfg := Node{
163		Children: []Node{},
164	}
165
166	m := NewMap(map[string]interface{}{"foo": "baz"}, cfg)
167
168	foo := ""
169	m.Custom("foo", true, false, func() (interface{}, error) {
170		return "bar", nil
171	}, func(_ *Map, n Node) (interface{}, error) {
172		return n.Args[0], nil
173	}, &foo)
174
175	_, err := m.Process()
176	if err != nil {
177		t.Fatalf("Unexpected failure: %v", err)
178	}
179
180	if foo != "baz" {
181		t.Errorf("Incorrect value stored in variable, want 'baz', got '%s'", foo)
182	}
183
184	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		}
189
190		if foo != "bar" {
191			t.Errorf("Incorrect value stored in variable, want 'bar', got '%s'", foo)
192		}
193	})
194}
195
196func 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	}
209
210	m := NewMap(nil, cfg)
211
212	foo := ""
213	m.Custom("foo", false, true, nil, func(_ *Map, n Node) (interface{}, error) {
214		return n.Args[0], nil
215	}, &foo)
216
217	_, err := m.Process()
218	if err == nil {
219		t.Errorf("Expected failure")
220	}
221}
222
223func 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	}
236
237	m := NewMap(nil, cfg)
238
239	foo := ""
240	m.Custom("bar", false, true, nil, func(_ *Map, n Node) (interface{}, error) {
241		return n.Args[0], nil
242	}, &foo)
243
244	_, err := m.Process()
245	if err == nil {
246		t.Errorf("Expected failure")
247	}
248
249	m.AllowUnknown()
250
251	unknown, err := m.Process()
252	if err != nil {
253		t.Errorf("Unexpected failure: %v", err)
254	}
255
256	if len(unknown) != 1 {
257		t.Fatalf("Wrong amount of unknown nodes: %v", len(unknown))
258	}
259
260	if unknown[0].Name != "foo" {
261		t.Fatalf("Wrong node in unknown: %v", unknown[0].Name)
262	}
263}
264
265func TestMapInt(t *testing.T) {
266	cfg := Node{
267		Children: []Node{
268			{
269				Name: "foo",
270				Args: []string{"1"},
271			},
272		},
273	}
274
275	m := NewMap(nil, cfg)
276
277	foo := 0
278	m.Int("foo", false, true, 0, &foo)
279
280	_, err := m.Process()
281	if err != nil {
282		t.Fatalf("Unexpected failure: %v", err)
283	}
284
285	if foo != 1 {
286		t.Errorf("Incorrect value stored in variable, want 1, got %d", foo)
287	}
288}
289
290func TestMapInt_Invalid(t *testing.T) {
291	cfg := Node{
292		Children: []Node{
293			{
294				Name: "foo",
295				Args: []string{"AAAA"},
296			},
297		},
298	}
299
300	m := NewMap(nil, cfg)
301
302	foo := 0
303	m.Int("foo", false, true, 0, &foo)
304
305	_, err := m.Process()
306	if err == nil {
307		t.Errorf("Expected failure")
308	}
309}
310
311func TestMapFloat(t *testing.T) {
312	cfg := Node{
313		Children: []Node{
314			{
315				Name: "foo",
316				Args: []string{"1"},
317			},
318		},
319	}
320
321	m := NewMap(nil, cfg)
322
323	foo := 0.0
324	m.Float("foo", false, true, 0, &foo)
325
326	_, err := m.Process()
327	if err != nil {
328		t.Fatalf("Unexpected failure: %v", err)
329	}
330
331	if foo != 1.0 {
332		t.Errorf("Incorrect value stored in variable, want 1, got %v", foo)
333	}
334}
335
336func TestMapFloat_Invalid(t *testing.T) {
337	cfg := Node{
338		Children: []Node{
339			{
340				Name: "foo",
341				Args: []string{"AAAA"},
342			},
343		},
344	}
345
346	m := NewMap(nil, cfg)
347
348	foo := 0.0
349	m.Float("foo", false, true, 0, &foo)
350
351	_, err := m.Process()
352	if err == nil {
353		t.Errorf("Expected failure")
354	}
355}
356
357func 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	}
373
374	m := NewMap(nil, cfg)
375
376	foo, bar, baz, boo := false, false, false, false
377	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)
381
382	_, err := m.Process()
383	if err != nil {
384		t.Fatalf("Unexpected failure: %v", err)
385	}
386
387	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}
400
401func 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			return
407		}
408		if err == nil && !ok {
409			t.Errorf("unexpected parseDataSize('%s') success, got %d", s, val)
410			return
411		}
412		if val != expected {
413			t.Errorf("parseDataSize('%s') != %d", s, expected)
414			return
415		}
416	}
417
418	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}
432
433func TestMap_Callback(t *testing.T) {
434	called := map[string]int{}
435
436	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 nil
460	})
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 nil
467	})
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 nil
474	})
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}