From 5b97f0550c8505f73187e4759d64061deaad3edf Mon Sep 17 00:00:00 2001 From: Marten Seemann Date: Thu, 1 Dec 2016 23:33:19 +0700 Subject: [PATCH] implement a function to find the highest supported version --- protocol/version.go | 29 +++++++++++++++++++++++++++ protocol/version_test.go | 43 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+) diff --git a/protocol/version.go b/protocol/version.go index cd0cd475..7ad8e572 100644 --- a/protocol/version.go +++ b/protocol/version.go @@ -3,6 +3,7 @@ package protocol import ( "bytes" "encoding/binary" + "sort" "strconv" ) @@ -18,6 +19,7 @@ const ( ) // SupportedVersions lists the versions that the server supports +// must be in sorted order var SupportedVersions = []VersionNumber{ Version34, Version35, Version36, } @@ -49,6 +51,33 @@ func IsSupportedVersion(v VersionNumber) bool { return false } +type byVersionNumber []VersionNumber + +func (a byVersionNumber) Len() int { return len(a) } +func (a byVersionNumber) Swap(i, j int) { a[i], a[j] = a[j], a[i] } +func (a byVersionNumber) Less(i, j int) bool { return a[i] < a[j] } + +// HighestSupportedVersion finds the highest version number that is both present in other and in SupportedVersions +// the versions in other do not need to be ordered +// it returns true and the version number, if there is one, otherwise false +func HighestSupportedVersion(other []VersionNumber) (bool, VersionNumber) { + sort.Sort(byVersionNumber(other)) + + i := len(other) - 1 // index of other + j := len(SupportedVersions) - 1 // index of SupportedVersions + for i >= 0 && j >= 0 { + if other[i] == SupportedVersions[j] { + return true, SupportedVersions[j] + } + if other[i] > SupportedVersions[j] { + i-- + } else { + j-- + } + } + return false, 0 +} + func init() { var b bytes.Buffer for _, v := range SupportedVersions { diff --git a/protocol/version_test.go b/protocol/version_test.go index 5bcd4a45..ce2e0739 100644 --- a/protocol/version_test.go +++ b/protocol/version_test.go @@ -28,4 +28,47 @@ var _ = Describe("Version", func() { Expect(IsSupportedVersion(0)).To(BeFalse()) Expect(IsSupportedVersion(SupportedVersions[0])).To(BeTrue()) }) + + It("has supported versions in sorted order", func() { + for i := 0; i < len(SupportedVersions)-1; i++ { + Expect(SupportedVersions[i]).To(BeNumerically("<", SupportedVersions[i+1])) + } + }) + + Context("highest supported version", func() { + var initialSupportedVersions []VersionNumber + + BeforeEach(func() { + initialSupportedVersions = make([]VersionNumber, len(SupportedVersions)) + copy(initialSupportedVersions, SupportedVersions) + }) + + AfterEach(func() { + SupportedVersions = initialSupportedVersions + }) + + It("finds the supported version", func() { + SupportedVersions = []VersionNumber{1, 2, 3} + other := []VersionNumber{3, 4, 5, 6} + found, ver := HighestSupportedVersion(other) + Expect(found).To(BeTrue()) + Expect(ver).To(Equal(VersionNumber(3))) + }) + + It("picks the highest supported version", func() { + SupportedVersions = []VersionNumber{1, 2, 3, 6, 7} + other := []VersionNumber{3, 6, 1, 8, 2, 10} + found, ver := HighestSupportedVersion(other) + Expect(found).To(BeTrue()) + Expect(ver).To(Equal(VersionNumber(6))) + }) + + It("handles empty inputs", func() { + SupportedVersions = []VersionNumber{101, 102} + Expect(HighestSupportedVersion([]VersionNumber{})).To(BeFalse()) + SupportedVersions = []VersionNumber{} + Expect(HighestSupportedVersion([]VersionNumber{1, 2})).To(BeFalse()) + Expect(HighestSupportedVersion([]VersionNumber{})).To(BeFalse()) + }) + }) })