// Copyright 2015 Matthew Holt and The Caddy Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package caddy import ( "fmt" "os" "path/filepath" "runtime" "testing" ) func TestReplacer(t *testing.T) { type testCase struct { input, expect, empty string } rep := testReplacer() // ReplaceAll for i, tc := range []testCase{ { input: "{", expect: "{", }, { input: "foo{", expect: "foo{", }, { input: "foo{bar", expect: "foo{bar", }, { input: "foo{bar}", expect: "foo", }, { input: "}", expect: "}", }, { input: "{}", expect: "", }, { input: `{"json": "object"}`, expect: "", }, { input: `{{`, expect: "{{", }, { input: `{{}`, expect: "", }, } { actual := rep.ReplaceAll(tc.input, tc.empty) if actual != tc.expect { t.Errorf("Test %d: '%s': expected '%s' but got '%s'", i, tc.input, tc.expect, actual) } } } func TestReplacerSet(t *testing.T) { rep := testReplacer() for _, tc := range []struct { variable string value string }{ { variable: "test1", value: "val1", }, { variable: "asdf", value: "123", }, { variable: "äöü", value: "öö_äü", }, { variable: "with space", value: "space value", }, { variable: "1", value: "test-123", }, { variable: "mySuper_IP", value: "1.2.3.4", }, { variable: "testEmpty", value: "", }, } { rep.Set(tc.variable, tc.value) // test if key is added if val, ok := rep.static[tc.variable]; ok { if val != tc.value { t.Errorf("Expected value '%s' for key '%s' got '%s'", tc.value, tc.variable, val) } } else { t.Errorf("Expected existing key '%s' found nothing", tc.variable) } } // test if all keys are still there (by length) length := len(rep.static) if len(rep.static) != 7 { t.Errorf("Expected length '%v' got '%v'", 7, length) } } func TestReplacerReplaceKnown(t *testing.T) { rep := replacer{ providers: []ReplacerFunc{ // split our possible vars to two functions (to test if both functions are called) func(key string) (val string, ok bool) { switch key { case "test1": return "val1", true case "asdf": return "123", true case "äöü": return "öö_äü", true case "with space": return "space value", true default: return "NOOO", false } }, func(key string) (val string, ok bool) { switch key { case "1": return "test-123", true case "mySuper_IP": return "1.2.3.4", true case "testEmpty": return "", true default: return "NOOO", false } }, }, } for _, tc := range []struct { testInput string expected string }{ { // test vars without space testInput: "{test1}{asdf}{äöü}{1}{with space}{mySuper_IP}", expected: "val1123öö_äütest-123space value1.2.3.4", }, { // test vars with space testInput: "{test1} {asdf} {äöü} {1} {with space} {mySuper_IP} ", expected: "val1 123 öö_äü test-123 space value 1.2.3.4 ", }, { // test with empty val testInput: "{test1} {testEmpty} {asdf} {1} ", expected: "val1 EMPTY 123 test-123 ", }, { // test vars with not finished placeholders testInput: "{te{test1}{as{{df{1}", expected: "{teval1{as{{dftest-123", }, { // test with non existing vars testInput: "{test1} {nope} {1} ", expected: "val1 {nope} test-123 ", }, } { actual := rep.ReplaceKnown(tc.testInput, "EMPTY") // test if all are replaced as expected if actual != tc.expected { t.Errorf("Expected '%s' got '%s' for '%s'", tc.expected, actual, tc.testInput) } } } func TestReplacerDelete(t *testing.T) { rep := replacer{ static: map[string]string{ "key1": "val1", "key2": "val2", "key3": "val3", "key4": "val4", }, } startLen := len(rep.static) toDel := []string{ "key2", "key4", } for _, key := range toDel { rep.Delete(key) // test if key is removed from static map if _, ok := rep.static[key]; ok { t.Errorf("Expected '%s' to be removed. It is still in static map.", key) } } // check if static slice is smaller expected := startLen - len(toDel) actual := len(rep.static) if len(rep.static) != expected { t.Errorf("Expected length '%v' got length '%v'", expected, actual) } } func TestReplacerMap(t *testing.T) { rep := testReplacer() for i, tc := range []ReplacerFunc{ func(key string) (val string, ok bool) { return "", false }, func(key string) (val string, ok bool) { return "", false }, } { rep.Map(tc) // test if function (which listens on specific key) is added by checking length if len(rep.providers) == i+1 { // check if the last function is the one we just added pTc := fmt.Sprintf("%p", tc) pRep := fmt.Sprintf("%p", rep.providers[i]) if pRep != pTc { t.Errorf("Expected func pointer '%s' got '%s'", pTc, pRep) } } else { t.Errorf("Expected providers length '%v' got length '%v'", i+1, len(rep.providers)) } } } func TestReplacerNew(t *testing.T) { var tc = NewReplacer() rep, ok := tc.(*replacer) if ok { if len(rep.providers) != 2 { t.Errorf("Expected providers length '%v' got length '%v'", 2, len(rep.providers)) } else { // test if default global replacements are added as the first provider hostname, _ := os.Hostname() os.Setenv("CADDY_REPLACER_TEST", "envtest") defer os.Setenv("CADDY_REPLACER_TEST", "") for _, tc := range []struct { variable string value string }{ { variable: "system.hostname", value: hostname, }, { variable: "system.slash", value: string(filepath.Separator), }, { variable: "system.os", value: runtime.GOOS, }, { variable: "system.arch", value: runtime.GOARCH, }, { variable: "env.CADDY_REPLACER_TEST", value: "envtest", }, } { if val, ok := rep.providers[0](tc.variable); ok { if val != tc.value { t.Errorf("Expected value '%s' for key '%s' got '%s'", tc.value, tc.variable, val) } } else { t.Errorf("Expected key '%s' to be recognized by first provider", tc.variable) } } } } else { t.Errorf("Expected type of replacer %T got %T ", &replacer{}, tc) } } func testReplacer() replacer { return replacer{ providers: make([]ReplacerFunc, 0), static: make(map[string]string), } }