package feature_test import ( "fmt" "strings" "testing" "github.com/restic/restic/internal/feature" rtest "github.com/restic/restic/internal/test" ) var ( alpha = feature.FlagName("alpha-feature") beta = feature.FlagName("beta-feature") stable = feature.FlagName("stable-feature") deprecated = feature.FlagName("deprecated-feature") ) var testFlags = map[feature.FlagName]feature.FlagDesc{ alpha: { Type: feature.Alpha, Description: "alpha", }, beta: { Type: feature.Beta, Description: "beta", }, stable: { Type: feature.Stable, Description: "stable", }, deprecated: { Type: feature.Deprecated, Description: "deprecated", }, } func buildTestFlagSet() *feature.FlagSet { flags := feature.New() flags.SetFlags(testFlags) return flags } func TestFeatureDefaults(t *testing.T) { flags := buildTestFlagSet() for _, exp := range []struct { flag feature.FlagName value bool }{ {alpha, false}, {beta, true}, {stable, true}, {deprecated, false}, } { rtest.Assert(t, flags.Enabled(exp.flag) == exp.value, "expected flag %v to have value %v got %v", exp.flag, exp.value, flags.Enabled(exp.flag)) } } func panicIfCalled(msg string) { panic(msg) } func TestEmptyApply(t *testing.T) { flags := buildTestFlagSet() rtest.OK(t, flags.Apply("", panicIfCalled)) rtest.Assert(t, !flags.Enabled(alpha), "expected alpha feature to be disabled") rtest.Assert(t, flags.Enabled(beta), "expected beta feature to be enabled") } func TestFeatureApply(t *testing.T) { flags := buildTestFlagSet() rtest.OK(t, flags.Apply(string(alpha), panicIfCalled)) rtest.Assert(t, flags.Enabled(alpha), "expected alpha feature to be enabled") rtest.OK(t, flags.Apply(fmt.Sprintf("%s=false", alpha), panicIfCalled)) rtest.Assert(t, !flags.Enabled(alpha), "expected alpha feature to be disabled") rtest.OK(t, flags.Apply(fmt.Sprintf("%s=true", alpha), panicIfCalled)) rtest.Assert(t, flags.Enabled(alpha), "expected alpha feature to be enabled again") rtest.OK(t, flags.Apply(fmt.Sprintf("%s=false", beta), panicIfCalled)) rtest.Assert(t, !flags.Enabled(beta), "expected beta feature to be disabled") logMsg := "" log := func(msg string) { logMsg = msg } rtest.OK(t, flags.Apply(fmt.Sprintf("%s=false", stable), log)) rtest.Assert(t, flags.Enabled(stable), "expected stable feature to remain enabled") rtest.Assert(t, strings.Contains(logMsg, string(stable)), "unexpected log message for stable flag: %v", logMsg) logMsg = "" rtest.OK(t, flags.Apply(fmt.Sprintf("%s=true", deprecated), log)) rtest.Assert(t, !flags.Enabled(deprecated), "expected deprecated feature to remain disabled") rtest.Assert(t, strings.Contains(logMsg, string(deprecated)), "unexpected log message for deprecated flag: %v", logMsg) } func TestFeatureMultipleApply(t *testing.T) { flags := buildTestFlagSet() rtest.OK(t, flags.Apply(fmt.Sprintf("%s=true,%s=false", alpha, beta), panicIfCalled)) rtest.Assert(t, flags.Enabled(alpha), "expected alpha feature to be enabled") rtest.Assert(t, !flags.Enabled(beta), "expected beta feature to be disabled") } func TestFeatureApplyInvalid(t *testing.T) { flags := buildTestFlagSet() err := flags.Apply("invalid-flag", panicIfCalled) rtest.Assert(t, err != nil && strings.Contains(err.Error(), "unknown feature flag"), "expected unknown feature flag error, got: %v", err) err = flags.Apply(fmt.Sprintf("%v=invalid", alpha), panicIfCalled) rtest.Assert(t, err != nil && strings.Contains(err.Error(), "failed to parse value"), "expected parsing error, got: %v", err) } func assertPanic(t *testing.T) { if r := recover(); r == nil { t.Fatal("should have panicked") } } func TestFeatureQueryInvalid(t *testing.T) { defer assertPanic(t) flags := buildTestFlagSet() flags.Enabled("invalid-flag") } func TestFeatureSetInvalidPhase(t *testing.T) { defer assertPanic(t) flags := feature.New() flags.SetFlags(map[feature.FlagName]feature.FlagDesc{ "invalid": { Type: "invalid", }, }) } func TestFeatureList(t *testing.T) { flags := buildTestFlagSet() rtest.Equals(t, []feature.Help{ {string(alpha), string(feature.Alpha), false, "alpha"}, {string(beta), string(feature.Beta), true, "beta"}, {string(deprecated), string(feature.Deprecated), false, "deprecated"}, {string(stable), string(feature.Stable), true, "stable"}, }, flags.List()) }