mirror of
https://github.com/StackExchange/dnscontrol.git
synced 2025-12-09 13:46:07 +08:00
210 lines
8.4 KiB
Go
210 lines
8.4 KiB
Go
package bind
|
||
|
||
import (
|
||
"reflect"
|
||
"testing"
|
||
|
||
"github.com/StackExchange/dnscontrol/v4/pkg/domaintags"
|
||
)
|
||
|
||
func Test_makeFileName(t *testing.T) {
|
||
fmtDefault := "%U.zone"
|
||
fmtBasic := "%U - %T - %D"
|
||
fmtFancy := "%T%?_%D.zone" // Include the tag_ only if there is a tag
|
||
fmtErrorPct := "literal%"
|
||
fmtErrorOpt := "literal%?"
|
||
fmtErrorUnk := "literal%o" // Unknown % verb
|
||
|
||
ff := domaintags.DomainFixedForms{
|
||
NameRaw: "domy",
|
||
NameASCII: "idn",
|
||
NameUnicode: "uni",
|
||
UniqueName: "unique!taga",
|
||
Tag: "tagy",
|
||
}
|
||
tagless := domaintags.DomainFixedForms{
|
||
NameRaw: "domy",
|
||
NameASCII: "idn",
|
||
NameUnicode: "uni",
|
||
UniqueName: "unique",
|
||
Tag: "",
|
||
}
|
||
|
||
type args struct {
|
||
format string
|
||
ff domaintags.DomainFixedForms
|
||
}
|
||
tests := []struct {
|
||
name string
|
||
args args
|
||
want string
|
||
}{
|
||
// Test corner cases and common cases.
|
||
{"literal", args{"literal", ff}, "literal"},
|
||
{"basic", args{fmtBasic, ff}, "domy!tagy - tagy - domy"},
|
||
{"solo", args{"%D", ff}, "domy"},
|
||
{"front", args{"%Daaa", ff}, "domyaaa"},
|
||
{"tail", args{"bbb%D", ff}, "bbbdomy"},
|
||
{"def", args{fmtDefault, ff}, "domy!tagy.zone"},
|
||
{"fanWI", args{fmtFancy, ff}, "tagy_domy.zone"},
|
||
{"fanWO", args{fmtFancy, tagless}, "domy.zone"},
|
||
{"errP", args{fmtErrorPct, ff}, "literal%(format may not end in %)"},
|
||
{"errQ", args{fmtErrorOpt, ff}, "literal%(format may not end in %?)"},
|
||
{"errU", args{fmtErrorUnk, ff}, "literal%(unknown %verb %o)"},
|
||
}
|
||
|
||
for _, tt := range tests {
|
||
t.Run(tt.name, func(t *testing.T) {
|
||
if got := makeFileName(tt.args.format, tt.args.ff); got != tt.want {
|
||
t.Errorf("makeFileName(%q) = %q, want %q", tt.args.format, got, tt.want)
|
||
}
|
||
})
|
||
}
|
||
}
|
||
|
||
func Test_makeFileName_2(t *testing.T) {
|
||
ff1 := domaintags.MakeDomainFixForms(`EXAMple.com`)
|
||
ff2 := domaintags.MakeDomainFixForms(`EXAMple.com!myTag`)
|
||
ff3 := domaintags.MakeDomainFixForms(`рф.com!myTag`)
|
||
|
||
tests := []struct {
|
||
name string
|
||
format string
|
||
want1 string
|
||
want2 string
|
||
want3 string
|
||
descr string // Not used in test, just for documentation generation
|
||
}{
|
||
// NOTE: "Domain" in these descriptions means the domain name without any split horizon tag. Technically the "Zone".
|
||
{`T`, `%T`, ``, `myTag`, `myTag`, `the tag`},
|
||
{`c`, `%c`, `example.com`, `example.com!myTag`, `xn--p1ai.com!myTag`, `canonical name, globally unique and comparable`},
|
||
{`a`, `%a`, `example.com`, `example.com`, `xn--p1ai.com`, `ASCII domain (Punycode, downcased)`},
|
||
{`u`, `%u`, `example.com`, `example.com`, `рф.com`, `Unicode domain (non-Unicode parts downcased)`},
|
||
{`r`, `%r`, `EXAMple.com`, `EXAMple.com`, `рф.com`, "Raw (unmodified) Domain from `D()` (risky!)"},
|
||
{`f`, `%f`, `example.com`, `example.com_myTag`, `xn--p1ai.com_myTag`, "like `%c` but better for filenames (`%a%?_%T`)"},
|
||
{`F`, `%F`, `example.com`, `myTag_example.com`, `myTag_xn--p1ai.com`, "like `%f` but reversed order (`%T%?_%a`)"},
|
||
{`%?x`, `%?x`, ``, `x`, `x`, "returns `x` if tag exists, otherwise \"\""},
|
||
{`%`, `%%`, `%`, `%`, `%`, `a literal percent sign`},
|
||
|
||
// Pre-v4.28 names kept for compatibility (note: pre v4.28 did not permit mixed case domain names, we downcased them here for the tests)
|
||
{`U`, `%U`, `example.com`, `example.com!myTag`, `рф.com!myTag`, "(deprecated, use `%c`) Same as `%D%?!%T` (risky!)"},
|
||
{`D`, `%D`, `example.com`, `example.com`, `рф.com`, "(deprecated, use `%r`) mangles Unicode (risky!)"},
|
||
{`%T%?_%D.zone`, `%T%?_%D.zone`, `example.com.zone`, `myTag_example.com.zone`, `myTag_рф.com.zone`, `mentioned in the docs`},
|
||
{`db_%T%?_%D`, `db_%T%?_%D`, `db_example.com`, `db_myTag_example.com`, `db_myTag_рф.com`, `mentioned in the docs`},
|
||
{`db_%D`, `db_%D`, `db_example.com`, `db_example.com`, `db_рф.com`, `mentioned in the docs`},
|
||
|
||
// Examples used in the documentation for the BIND provider
|
||
{`%c.zone`, `%c.zone`, "example.com.zone", "example.com!myTag.zone", "xn--p1ai.com!myTag.zone", "Default format (v4.28 and later)"},
|
||
{`%U.zone`, `%U.zone`, `example.com.zone`, `example.com!myTag.zone`, `рф.com!myTag.zone`, "Default format (pre-v4.28) (risky!)"},
|
||
{`db_%f`, `db_%f`, `db_example.com`, `db_example.com_myTag`, `db_xn--p1ai.com_myTag`, "Recommended in a popular DNS book"},
|
||
{`db_a%?_%T`, `db_%a%?_%T`, `db_example.com`, `db_example.com_myTag`, `db_xn--p1ai.com_myTag`, "same as above but using `%?_`"},
|
||
}
|
||
|
||
for _, tt := range tests {
|
||
t.Run(tt.name, func(t *testing.T) {
|
||
got1 := makeFileName(tt.format, ff1)
|
||
if got1 != tt.want1 {
|
||
t.Errorf("makeFileName(%q) = ff1 %q, want %q", tt.format, got1, tt.want1)
|
||
}
|
||
got2 := makeFileName(tt.format, ff2)
|
||
if got2 != tt.want2 {
|
||
t.Errorf("makeFileName(%q) = ff2 %q, want %q", tt.format, got2, tt.want2)
|
||
}
|
||
got3 := makeFileName(tt.format, ff3)
|
||
if got3 != tt.want3 {
|
||
t.Errorf("makeFileName(%q) = ff3 %q, want %q", tt.format, got3, tt.want3)
|
||
}
|
||
//Uncomment to regenerate lines used in documentation/provider/bind.md 's table:
|
||
// fmt.Print(strings.ReplaceAll(fmt.Sprintf("| `%s` | %s | `%s` | `%s` | `%s` |\n", tt.format, tt.descr, got1, got2, got3), "``", "`\"\"` (null)"))
|
||
//Uncomment to regenerate the above test cases:
|
||
// fmt.Printf("{`%s`, `%s`, `%s`, `%s`, `%s`, %q},\n", tt.name, tt.format, got1, got2, got3, tt.descr)
|
||
})
|
||
}
|
||
}
|
||
|
||
func Test_makeExtractor(t *testing.T) {
|
||
type args struct {
|
||
format string
|
||
}
|
||
tests := []struct {
|
||
name string
|
||
args args
|
||
want string
|
||
wantErr bool
|
||
}{
|
||
{"c", args{"%c.zone"}, `(.*)!.+\.zone|(.*)\.zone`, false},
|
||
{"a", args{"%a.zone"}, `(.*)\.zone`, false},
|
||
{"u", args{"%u.zone"}, `(.*)\.zone`, false},
|
||
{"r", args{"%r.zone"}, `(.*)\.zone`, false},
|
||
// TODO: Add test cases.
|
||
{"u", args{"%U.zone"}, `(.*)!.+\.zone|(.*)\.zone`, false},
|
||
{"d", args{"%D.zone"}, `(.*)\.zone`, false},
|
||
{"basic", args{"%U - %T - %D"}, `(.*)!.+ - .* - (.*)|(.*) - - (.*)`, false},
|
||
{"bk1", args{"db_%U"}, `db_(.*)!.+|db_(.*)`, false},
|
||
{"bk2", args{"db_%T_%D"}, `db_.*_(.*)`, false},
|
||
{"fan", args{"%T%?_%D.zone"}, `.*_(.*)\.zone|(.*)\.zone`, false},
|
||
}
|
||
for _, tt := range tests {
|
||
t.Run(tt.name, func(t *testing.T) {
|
||
got, err := makeExtractor(tt.args.format)
|
||
if (err != nil) != tt.wantErr {
|
||
t.Errorf("makeExtractor() error = %v, wantErr %v", err, tt.wantErr)
|
||
return
|
||
}
|
||
if got != tt.want {
|
||
t.Errorf("makeExtractor() = %v, want %v", got, tt.want)
|
||
}
|
||
})
|
||
}
|
||
}
|
||
|
||
func Test_extractZonesFromFilenames(t *testing.T) {
|
||
type args struct {
|
||
format string
|
||
names []string
|
||
}
|
||
|
||
// A list of filenames one might find in a directory.
|
||
filelist := []string{
|
||
"foo!one.zone", // u
|
||
"dom.tld!two.zone", // u
|
||
"foo.zone", // d
|
||
"dom.tld.zone", // d
|
||
"foo!one - one - foo", // basic
|
||
"dom.tld!two - two - dom.tld", // basic
|
||
"db_foo", // bk1
|
||
"db_dom.tld", // bk1
|
||
"db_dom.tld!tag", // bk1
|
||
"db_inside_foo", // bk2
|
||
"db_outside_dom.tld", // bk2
|
||
"db__example.com", // bk2
|
||
"dom.zone", // fan
|
||
"example.com.zone", // fan (no tag)
|
||
"mytag_example.com.zone", // fan (w/ tag)
|
||
"dom.zone", // fan (no tag)
|
||
"mytag_dom.zone", // fan (w/ tag)
|
||
}
|
||
|
||
tests := []struct {
|
||
name string
|
||
args args
|
||
want []string
|
||
}{
|
||
{"0", args{"%D.zone", []string{"foo.zone", "dom.tld.zone"}}, []string{"foo", "dom.tld"}},
|
||
{"1", args{"%U.zone", []string{"foo.zone", "dom.tld.zone"}}, []string{"foo", "dom.tld"}},
|
||
{"2", args{"%T%?_%D.zone", []string{"inside_ex.tld.zone", "foo.zone", "dom.tld.zone"}}, []string{"ex.tld", "foo", "dom.tld"}},
|
||
{"d", args{"%D.zone", filelist}, []string{"foo!one", "dom.tld!two", "foo", "dom.tld", "dom", "example.com", "mytag_example.com", "dom", "mytag_dom"}},
|
||
{"u", args{"%U.zone", filelist}, []string{"foo", "dom.tld", "foo", "dom.tld", "dom", "example.com", "mytag_example.com", "dom", "mytag_dom"}},
|
||
{"bk1", args{"db_%U", filelist}, []string{"foo", "dom.tld", "dom.tld", "inside_foo", "outside_dom.tld", "_example.com"}},
|
||
{"bk2", args{"db_%T_%D", filelist}, []string{"foo", "dom.tld", "example.com"}},
|
||
{"fan", args{"%T%?_%D.zone", filelist}, []string{"foo!one", "dom.tld!two", "foo", "dom.tld", "dom", "example.com", "example.com", "dom", "dom"}},
|
||
}
|
||
for _, tt := range tests {
|
||
t.Run(tt.name, func(t *testing.T) {
|
||
if got := extractZonesFromFilenames(tt.args.format, tt.args.names); !reflect.DeepEqual(got, tt.want) {
|
||
ext, _ := makeExtractor(tt.args.format)
|
||
t.Errorf("extractZonesFromFilenames() = %v, want %v Fm=%s Ex=%s", got, tt.want, tt.args.format, ext)
|
||
}
|
||
})
|
||
}
|
||
}
|