From 24e1e6d1e1cb1ab128976fe928b5b2f16c8f8c45 Mon Sep 17 00:00:00 2001
From: Henry <cryptix@riseup.net>
Date: Mon, 20 Oct 2014 18:27:40 +0200
Subject: [PATCH] config: custom AutoUpdate type for validity

---
 config/version.go      | 71 +++++++++++++++++++++++++++++++++++-------
 config/version_test.go | 36 +++++++++++++++++++++
 updates/updates.go     |  2 +-
 3 files changed, 96 insertions(+), 13 deletions(-)
 create mode 100644 config/version_test.go

diff --git a/config/version.go b/config/version.go
index 1bd641ad4..88534ebc7 100644
--- a/config/version.go
+++ b/config/version.go
@@ -1,7 +1,9 @@
 package config
 
 import (
+	"errors"
 	"strconv"
+	"strings"
 	"time"
 )
 
@@ -23,12 +25,8 @@ type Version struct {
 	// (Note: cannot use time.Duration because marshalling with json breaks it)
 	CheckPeriod string
 
-	// AutoUpdate is optional and has these these options:
-	// - "never" do not auto-update
-	// - "patch" auto-update on new patch versions
-	// - "minor" auto-update on new minor (or patch) versions (Default)
-	// - "major" auto-update on any new version
-	AutoUpdate string
+	// AutoUpdate is optional
+	AutoUpdate AutoUpdateSetting
 }
 
 // supported Version.Check values
@@ -43,13 +41,62 @@ const (
 	CheckIgnore = "ignore"
 )
 
-// supported Version.AutoUpdate values
-// BUG(cryptix): make this a custom type that implements json.Unmarshaller() to verify values
+// AutoUpdateSetting implements json.Unmarshaler to check values in config
+// supported values:
+// 	"never" - do not auto-update
+// 	"patch" - auto-update on new patch versions
+// 	"minor" - auto-update on new minor (or patch) versions (Default)
+// 	"major" - auto-update on any new version
+type AutoUpdateSetting int
+
+// UnmarshalJSON checks the input against known strings
+func (s *AutoUpdateSetting) UnmarshalJSON(in []byte) error {
+
+	switch strings.ToLower(string(in)) {
+	case `"never"`:
+		*s = UpdateNever
+	case `"major"`:
+		*s = UpdateMajor
+	case `"minor"`:
+		*s = UpdateMinor
+	case `"patch"`:
+		*s = UpdatePatch
+	default:
+		*s = UpdateMinor
+		return ErrUnknownAutoUpdateSetting
+	}
+	return nil
+}
+
+// MarshalJSON converts the value back to JSON string
+func (s AutoUpdateSetting) MarshalJSON() ([]byte, error) {
+	return []byte(`"` + s.String() + `"`), nil
+}
+
+// String converts valye to human readable string
+func (s AutoUpdateSetting) String() string {
+	switch s {
+	case UpdateNever:
+		return "never"
+	case UpdateMajor:
+		return "major"
+	case UpdateMinor:
+		return "minor"
+	case UpdatePatch:
+		return "patch"
+	default:
+		return ErrUnknownAutoUpdateSetting.Error()
+	}
+}
+
+// ErrUnknownAutoUpdateSetting is returned when an unknown value is read from the config
+var ErrUnknownAutoUpdateSetting = errors.New("unknown value for AutoUpdate")
+
 const (
-	UpdateNever = "never"
-	UpdatePatch = "patch"
-	UpdateMinor = "minor"
-	UpdateMajor = "major"
+	UpdateMinor AutoUpdateSetting = iota // first value so that it is the zero value and thus the default
+	UpdatePatch
+	UpdateMajor
+	UpdateNever
 )
 
 // defaultCheckPeriod governs h
diff --git a/config/version_test.go b/config/version_test.go
new file mode 100644
index 000000000..01b1a6433
--- /dev/null
+++ b/config/version_test.go
@@ -0,0 +1,36 @@
+package config
+
+import (
+	"strings"
+	"testing"
+)
+
+func TestAutoUpdateValues(t *testing.T) {
+	var tval struct {
+		AutoUpdate AutoUpdateSetting
+	}
+	tests := []struct {
+		input string
+		val   AutoUpdateSetting
+		err   error
+	}{
+		{`{"hello":123}`, UpdateMinor, nil}, // default
+		{`{"AutoUpdate": "never"}`, UpdateNever, nil},
+		{`{"AutoUpdate": "patch"}`, UpdatePatch, nil},
+		{`{"AutoUpdate": "minor"}`, UpdateMinor, nil},
+		{`{"AutoUpdate": "major"}`, UpdateMajor, nil},
+		{`{"AutoUpdate": "blarg"}`, UpdateMinor, ErrUnknownAutoUpdateSetting},
+	}
+
+	for i, tc := range tests {
+		err := Decode(strings.NewReader(tc.input), &tval)
+		if err != tc.err {
+			t.Fatalf("%d failed - got err %q wanted %v", i, err, tc.err)
+		}
+
+		if tval.AutoUpdate != tc.val {
+			t.Fatalf("%d failed - got val %q where we wanted %q", i, tval.AutoUpdate, tc.val)
+		}
+	}
+
+}
diff --git a/updates/updates.go b/updates/updates.go
index c6cf45783..443bf461a 100644
--- a/updates/updates.go
+++ b/updates/updates.go
@@ -64,7 +64,7 @@ func AbleToApply() error {
 
 // ShouldAutoUpdate decides wether a new version should be applied
 // checks against config setting and new version string. returns false in case of error
-func ShouldAutoUpdate(setting, newVer string) bool {
+func ShouldAutoUpdate(setting config.AutoUpdateSetting, newVer string) bool {
 	if setting == config.UpdateNever {
 		return false
 	}
-- 
GitLab