package remap import ( "fmt" "reflect" "regexp" "testing" ) type ( testMatcher struct { Nm string S string M *ReMap All bool Expected map[string][][]byte ExpectedStr map[string][]string ParamInclNoMatch bool ParamInclNoMatchStrict bool ParamInclMustMatch bool } ) func TestRemap(t *testing.T) { var matches map[string][][]byte for midx, m := range []testMatcher{ // 1 testMatcher{ Nm: "No matches", S: "this is a test", M: &ReMap{regexp.MustCompile(``)}, Expected: nil, }, // 2 testMatcher{ Nm: "Single mid match", S: "This contains a single match in the middle of a string", M: &ReMap{regexp.MustCompile(`\s+(?Pmatch)\s+`)}, Expected: map[string][][]byte{ "g1": [][]byte{[]byte("match")}, }, }, // 3 testMatcher{ Nm: "multi mid match", S: "This contains a single match and another match in the middle of a string", M: &ReMap{regexp.MustCompile(`\s+(?Pmatch) and another (?Pmatch)\s+`)}, Expected: map[string][][]byte{ "g1": [][]byte{ []byte("match"), []byte("match"), }, }, }, // 4 testMatcher{ Nm: "line match", S: "This\ncontains a\nsingle\nmatch\non a dedicated line", M: &ReMap{regexp.MustCompile(`(?m)^(?Pmatch)$`)}, Expected: map[string][][]byte{ "g1": [][]byte{ []byte("match"), }, }, }, // 5 testMatcher{ Nm: "multiline match", S: "This\ncontains a\nsingle match and another\nmatch\nin the middle of a string", M: &ReMap{regexp.MustCompile(`\s+(?Pmatch) and another\s+(?Pmatch)\s+`)}, All: true, Expected: map[string][][]byte{ "g1": [][]byte{ []byte("match"), []byte("match"), }, }, }, // 6 // More closely mirrors something closer to real-life testMatcher{ Nm: "mixed match", S: " # No longer log hits/reqs/resps to file.\n" + " #access_log /mnt/nginx_logs/vhost/tenant/site/access.log main;\n" + " #error_log /mnt/nginx_logs/vhost/tenant/site/error.log;\n" + " access_log off;\n" + " error_log /dev/null;\n\n" + " ssl_certificate /etc/nginx/tls/crt/tenant.pem;\n" + " ssl_certificate_key /etc/nginx/tls/key/tenant.pem;\n\n", M: &ReMap{regexp.MustCompile(`(?m)^\s*(?:error|access)_log\s+(?P.+);\s*$`)}, All: true, Expected: map[string][][]byte{ "logpath": [][]byte{ []byte("off"), []byte("/dev/null"), }, }, }, } { if m.All { matches = m.M.MapAll([]byte(m.S), false, false, false) } else { matches = m.M.Map([]byte(m.S), false, false, false) } t.Logf( "#%d:\n\tsrc:\t'%s'\n\tptrn:\t'%s'\n\tmatch:\t%s\n", midx+1, m.S, m.M.Regexp.String(), testBmapToStrMap(matches), ) if !reflect.DeepEqual(matches, m.Expected) { t.Fatalf("Case #%d (\"%s\"): expected '%#v' != received '%#v'", midx+1, m.Nm, m.Expected, matches) } } } func TestRemapParams(t *testing.T) { var matches map[string][][]byte for midx, m := range []testMatcher{ testMatcher{ Nm: "", S: "this is a test", M: &ReMap{regexp.MustCompile(``)}, Expected: nil, ParamInclNoMatch: false, ParamInclNoMatchStrict: false, ParamInclMustMatch: false, }, testMatcher{ Nm: "", S: "this is a test", M: &ReMap{regexp.MustCompile(``)}, Expected: nil, ParamInclNoMatch: false, ParamInclNoMatchStrict: true, ParamInclMustMatch: false, }, testMatcher{ Nm: "", S: "this is a test", M: &ReMap{regexp.MustCompile(``)}, Expected: nil, ParamInclNoMatch: false, ParamInclNoMatchStrict: true, ParamInclMustMatch: true, }, testMatcher{ Nm: "", S: "this is a test", M: &ReMap{regexp.MustCompile(``)}, Expected: nil, ParamInclNoMatch: false, ParamInclNoMatchStrict: false, ParamInclMustMatch: true, }, testMatcher{ Nm: "", S: "this is a test", M: &ReMap{regexp.MustCompile(``)}, Expected: make(map[string][][]byte), ParamInclNoMatch: true, ParamInclNoMatchStrict: false, ParamInclMustMatch: false, }, testMatcher{ Nm: "", S: "this is a test", M: &ReMap{regexp.MustCompile(``)}, Expected: make(map[string][][]byte), ParamInclNoMatch: true, ParamInclNoMatchStrict: true, ParamInclMustMatch: false, }, testMatcher{ Nm: "", S: "this is a test", M: &ReMap{regexp.MustCompile(``)}, Expected: make(map[string][][]byte), ParamInclNoMatch: true, ParamInclNoMatchStrict: true, ParamInclMustMatch: true, }, testMatcher{ Nm: "", S: "this is a test", M: &ReMap{regexp.MustCompile(``)}, Expected: make(map[string][][]byte), ParamInclNoMatch: true, ParamInclNoMatchStrict: false, ParamInclMustMatch: true, }, } { if m.All { matches = m.M.MapAll([]byte(m.S), m.ParamInclNoMatch, m.ParamInclNoMatchStrict, m.ParamInclMustMatch) } else { matches = m.M.Map([]byte(m.S), m.ParamInclNoMatch, m.ParamInclNoMatchStrict, m.ParamInclMustMatch) } t.Logf( "%d: %v/%v/%v: %#v\n", midx+1, m.ParamInclNoMatch, m.ParamInclNoMatchStrict, m.ParamInclMustMatch, matches, ) if !reflect.DeepEqual(matches, m.Expected) { t.Fatalf("Case #%d (\"%s\"): '%#v' != '%#v'", midx+1, m.Nm, m.ExpectedStr, matches) } } } func TestRemapString(t *testing.T) { var matches map[string][]string for midx, m := range []testMatcher{ // 1 testMatcher{ Nm: "No matches", S: "this is a test", M: &ReMap{regexp.MustCompile(``)}, ExpectedStr: nil, }, // 2 testMatcher{ Nm: "Single mid match", S: "This contains a single match in the middle of a string", M: &ReMap{regexp.MustCompile(`\s+(?Pmatch)\s+`)}, ExpectedStr: map[string][]string{ "g1": []string{"match"}, }, }, // 3 testMatcher{ Nm: "multi mid match", S: "This contains a single match and another match in the middle of a string", M: &ReMap{regexp.MustCompile(`\s+(?Pmatch) and another (?Pmatch)\s+`)}, ExpectedStr: map[string][]string{ "g1": []string{ "match", "match", }, }, }, // 4 testMatcher{ Nm: "line match", S: "This\ncontains a\nsingle\nmatch\non a dedicated line", M: &ReMap{regexp.MustCompile(`(?m)^(?Pmatch)$`)}, ExpectedStr: map[string][]string{ "g1": []string{ "match", }, }, }, // 5 testMatcher{ Nm: "multiline match", S: "This\ncontains a\nsingle match and another\nmatch\nin the middle of a string", M: &ReMap{regexp.MustCompile(`\s+(?Pmatch) and another\s+(?Pmatch)\s+`)}, All: true, ExpectedStr: map[string][]string{ "g1": []string{ "match", "match", }, }, }, // 6 // More closely mirrors something closer to real-life testMatcher{ Nm: "mixed match", S: " # No longer log hits/reqs/resps to file.\n" + " #access_log /mnt/nginx_logs/vhost/tenant/site/access.log main;\n" + " #error_log /mnt/nginx_logs/vhost/tenant/site/error.log;\n" + " access_log off;\n" + " error_log /dev/null;\n\n" + " ssl_certificate /etc/nginx/tls/crt/tenant.pem;\n" + " ssl_certificate_key /etc/nginx/tls/key/tenant.pem;\n\n", M: &ReMap{regexp.MustCompile(`(?m)^\s*(?:error|access)_log\s+(?P.+);\s*$`)}, All: true, ExpectedStr: map[string][]string{ "logpath": []string{ "off", "/dev/null", }, }, }, } { if m.All { matches = m.M.MapStringAll(m.S, false, false, false) } else { matches = m.M.MapString(m.S, false, false, false) } t.Logf( "#%d:\n\tsrc:\t'%s'\n\tptrn:\t'%s'\n\tmatch:\t%s\n", midx+1, m.S, m.M.Regexp.String(), testSmapToStrMap(matches), ) if !reflect.DeepEqual(matches, m.ExpectedStr) { t.Fatalf("Case #%d (\"%s\"): '%#v' != '%#v'", midx+1, m.Nm, m.ExpectedStr, matches) } } } func testBmapToStrMap(bmap map[string][][]byte) (s string) { if bmap == nil { return } s = "\n" for k, v := range bmap { s += fmt.Sprintf("\t%s\n", k) for _, i := range v { s += fmt.Sprintf("\t\t%s\n", string(i)) } } return } func testSmapToStrMap(smap map[string][]string) (s string) { if smap == nil { return } s = "\n" for k, v := range smap { s += fmt.Sprintf("\t%s\n", k) for _, i := range v { s += fmt.Sprintf("\t\t%s\n", i) } } return }