From 9c3d8cd3987f815a96c235ada514947343ed6731 Mon Sep 17 00:00:00 2001 From: Anna Shaleva Date: Thu, 12 Nov 2020 17:08:54 +0300 Subject: [PATCH] smartcontract: fix nef.GetVersion It should be able to parse versions like `1.1.1-rc.1`. Close #1540. --- pkg/smartcontract/nef/nef.go | 35 +++++---- pkg/smartcontract/nef/nef_test.go | 113 +++++++++++++++++++----------- 2 files changed, 88 insertions(+), 60 deletions(-) diff --git a/pkg/smartcontract/nef/nef.go b/pkg/smartcontract/nef/nef.go index 39f6433bf..c4958e500 100644 --- a/pkg/smartcontract/nef/nef.go +++ b/pkg/smartcontract/nef/nef.go @@ -82,52 +82,51 @@ func NewFile(script []byte) (File, error) { } // GetVersion returns Version from the given string. It accepts the following formats: -// `major.minor.build-[...]` -// `major.minor.build.revision-[...]` +// `major[-...].minor[-...].build[-...]` and `major[-...].minor[-...].build[-...].revision[-...]` // where `major`, `minor`, `build` and `revision` are 32-bit integers with base=10 func GetVersion(version string) (Version, error) { var ( result Version + err error ) versions := strings.SplitN(version, ".", 4) if len(versions) < 3 { return result, errors.New("invalid version format") } - major, err := strconv.ParseInt(versions[0], 10, 32) + result.Major, err = parseDashedVersion(versions[0]) if err != nil { return result, fmt.Errorf("failed to parse major version: %w", err) } - result.Major = int32(major) - - minor, err := strconv.ParseInt(versions[1], 10, 32) + result.Minor, err = parseDashedVersion(versions[1]) if err != nil { return result, fmt.Errorf("failed to parse minor version: %w", err) } - result.Minor = int32(minor) - - b := versions[2] - if len(versions) == 3 { - b = strings.SplitN(b, "-", 2)[0] - } - build, err := strconv.ParseInt(b, 10, 32) + result.Build, err = parseDashedVersion(versions[2]) if err != nil { return result, fmt.Errorf("failed to parse build version: %w", err) } - result.Build = int32(build) - if len(versions) == 4 { - r := strings.SplitN(versions[3], "-", 2)[0] - revision, err := strconv.ParseInt(r, 10, 32) + result.Revision, err = parseDashedVersion(versions[3]) if err != nil { return result, fmt.Errorf("failed to parse revision version: %w", err) } - result.Revision = int32(revision) } return result, nil } +// parseDashedVersion extracts int from string of the format `int[-...]` where `int` is +// a 32-bit integer with base=10. +func parseDashedVersion(version string) (int32, error) { + version = strings.SplitN(version, "-", 2)[0] + result, err := strconv.ParseInt(version, 10, 32) + if err != nil { + return 0, err + } + return int32(result), nil +} + // EncodeBinary implements io.Serializable interface. func (v *Version) EncodeBinary(w *io.BinWriter) { w.WriteU32LE(uint32(v.Major)) diff --git a/pkg/smartcontract/nef/nef_test.go b/pkg/smartcontract/nef/nef_test.go index b0de75e10..a2c0a119c 100644 --- a/pkg/smartcontract/nef/nef_test.go +++ b/pkg/smartcontract/nef/nef_test.go @@ -93,48 +93,77 @@ func TestBytesFromBytes(t *testing.T) { } func TestGetVersion(t *testing.T) { - _, err := GetVersion("qwerty") - require.Error(t, err) - - _, err = GetVersion("1.pre") - require.Error(t, err) - - _, err = GetVersion("1.1.pre") - require.Error(t, err) - - _, err = GetVersion("1.1.1.pre") - require.Error(t, err) - - actual, err := GetVersion("1.1.1-pre") - require.NoError(t, err) - expected := Version{ - Major: 1, - Minor: 1, - Build: 1, - Revision: 0, + testCases := map[string]struct { + input string + fails bool + expected Version + }{ + "major only": { + input: "1", + fails: true, + }, + "major and minor only": { + input: "1.1", + fails: true, + }, + "major, minor and revision only": { + input: "1.1.1", + expected: Version{ + Major: 1, + Minor: 1, + Build: 1, + Revision: 0, + }, + }, + "full version": { + input: "1.1.1.1", + expected: Version{ + Major: 1, + Minor: 1, + Build: 1, + Revision: 1, + }, + }, + "dashed, without revision": { + input: "1-pre.2-pre.3-pre", + expected: Version{ + Major: 1, + Minor: 2, + Build: 3, + Revision: 0, + }, + }, + "dashed, full version": { + input: "1-pre.2-pre.3-pre.4-pre", + expected: Version{ + Major: 1, + Minor: 2, + Build: 3, + Revision: 4, + }, + }, + "dashed build": { + input: "1.2.3-pre.4", + expected: Version{ + Major: 1, + Minor: 2, + Build: 3, + Revision: 4, + }, + }, + "extra versions": { + input: "1.2.3.4.5", + fails: true, + }, } - require.Equal(t, expected, actual) - - actual, err = GetVersion("0.90.0-pre") - require.NoError(t, err) - expected = Version{ - Major: 0, - Minor: 90, - Build: 0, - Revision: 0, + for name, test := range testCases { + t.Run(name, func(t *testing.T) { + actual, err := GetVersion(test.input) + if test.fails { + require.NotNil(t, err) + } else { + require.Equal(t, test.expected, actual) + } + }) } - require.Equal(t, expected, actual) - - actual, err = GetVersion("1.1.1.1-pre") - require.NoError(t, err) - expected = Version{ - Major: 1, - Minor: 1, - Build: 1, - Revision: 1, - } - require.Equal(t, expected, actual) - - _, err = GetVersion("1.1.1.1.1") - require.Error(t, err) }