package internal import ( "path" "reflect" "strconv" "strings" "sync" "testing" "github.com/spf13/viper" "github.com/stretchr/testify/assert" ) func TestOptionToString(t *testing.T) { t.Run("no prefix", func(t *testing.T) { opt := "test" result := optionToString(opt) assertEqual(t, result, "--test") }) t.Run("single prefix", func(t *testing.T) { opt := "-test" result := optionToString(opt) assertEqual(t, result, "-test") }) t.Run("double prefix", func(t *testing.T) { opt := "--test" result := optionToString(opt) assertEqual(t, result, "--test") }) } func TestAppendOneOptionToSlice(t *testing.T) { t.Run("string flag", func(t *testing.T) { result := []string{} optionMap := OptionMap{"string-flag": []interface{}{"/root"}} appendOptionsToSlice(&result, optionMap) expected := []string{ "--string-flag", "/root", } assertSliceEqual(t, result, expected) }) t.Run("bool flag", func(t *testing.T) { result := []string{} optionMap := OptionMap{"boolean-flag": []interface{}{true}} appendOptionsToSlice(&result, optionMap) expected := []string{ "--boolean-flag", } assertSliceEqual(t, result, expected) }) t.Run("int flag", func(t *testing.T) { result := []string{} optionMap := OptionMap{"int-flag": []interface{}{123}} appendOptionsToSlice(&result, optionMap) expected := []string{ "--int-flag", "123", } assertSliceEqual(t, result, expected) }) } func TestAppendMultipleOptionsToSlice(t *testing.T) { result := []string{} optionMap := OptionMap{ "string-flag": []interface{}{"/root"}, "int-flag": []interface{}{123}, } appendOptionsToSlice(&result, optionMap) expected := []string{ "--string-flag", "/root", "--int-flag", "123", } if len(result) != len(expected) { t.Errorf("got length %d, want length %d", len(result), len(expected)) } // checks that expected option comes after flag, regardless of key order in map for i, v := range expected { v = strings.TrimPrefix(v, "--") if value, ok := optionMap[v]; ok { if val, ok := value[0].(int); ok { if expected[i+1] != strconv.Itoa(val) { t.Errorf("Flags and options order are mismatched. got %v, want %v", result, expected) } } } } } func TestAppendOptionWithMultipleValuesToSlice(t *testing.T) { result := []string{} optionMap := OptionMap{ "string-flag": []interface{}{"/root", "/bin"}, } appendOptionsToSlice(&result, optionMap) expected := []string{ "--string-flag", "/root", "--string-flag", "/bin", } assertSliceEqual(t, result, expected) } func TestGetOptionsOneKey(t *testing.T) { optionMap := OptionMap{ "string-flag": []interface{}{"/root"}, } options := Options{"backend": optionMap} keys := []string{"backend"} result := getOptions(options, keys) expected := []string{ "--string-flag", "/root", } assertSliceEqual(t, result, expected) } func TestGetOptionsMultipleKeys(t *testing.T) { firstOptionMap := OptionMap{ "string-flag": []interface{}{"/root"}, } secondOptionMap := OptionMap{ "boolean-flag": []interface{}{true}, "int-flag": []interface{}{123}, } options := Options{ "all": firstOptionMap, "forget": secondOptionMap, } keys := []string{"all", "forget"} result := getOptions(options, keys) expected := []string{ "--string-flag", "/root", "--boolean-flag", "--int-flag", "123", } reflect.DeepEqual(result, expected) } func TestSaveConfigProducesReadableConfig(t *testing.T) { workDir := t.TempDir() viper.SetConfigFile(path.Join(workDir, ".autorestic.yml")) // Required to appease the config reader viper.Set("version", 2) c := Config{ Version: "2", Locations: map[string]Location{ "test": { Type: "local", name: "test", From: []string{"in-dir"}, To: []string{"test"}, // ForgetOption & ConfigOption have previously marshalled in a way that // can't get read correctly ForgetOption: "foo", CopyOption: map[string][]string{"foo": {"bar"}}, }, }, Backends: map[string]Backend{ "test": { name: "test", Type: "local", Path: "backup-target", Key: "supersecret", }, }, } err := c.SaveConfig() assert.NoError(t, err) // Ensure we the config reading logic actually runs config = nil once = sync.Once{} readConfig := GetConfig() assert.NotNil(t, readConfig) assert.Equal(t, c, *readConfig) } func assertEqual[T comparable](t testing.TB, result, expected T) { t.Helper() if result != expected { t.Errorf("got %v, want %v", result, expected) } } func assertSliceEqual(t testing.TB, result, expected []string) { t.Helper() if len(result) != len(expected) { t.Errorf("got length %d, want length %d", len(result), len(expected)) } for i := range result { assertEqual(t, result[i], expected[i]) } }