From bde028930b4a0ac359d561f093c59b83520ea5d8 Mon Sep 17 00:00:00 2001 From: Robin Eklind Date: Mon, 1 Jul 2019 02:50:23 +0800 Subject: [PATCH 1/6] internal/natsort: copy sortorder package from fvbommel/util@efcd4e0f97874370259c7d93e12aad57911dea81 The code is written by Frits van Bommel (@fvbommel) and released under an MIT license. This commit copies the code of sortorder without modification, and inclues the LICENSE file of the parent directory (util). Follow-up commits will relax the vanity import and make minor adjustments to the API. --- internal/natsort/LICENSE | 17 +++ internal/natsort/README.md | 5 + internal/natsort/doc.go | 5 + internal/natsort/natsort.go | 76 ++++++++++ internal/natsort/natsort_test.go | 230 +++++++++++++++++++++++++++++++ 5 files changed, 333 insertions(+) create mode 100644 internal/natsort/LICENSE create mode 100644 internal/natsort/README.md create mode 100644 internal/natsort/doc.go create mode 100644 internal/natsort/natsort.go create mode 100644 internal/natsort/natsort_test.go diff --git a/internal/natsort/LICENSE b/internal/natsort/LICENSE new file mode 100644 index 00000000..5c695fb5 --- /dev/null +++ b/internal/natsort/LICENSE @@ -0,0 +1,17 @@ +The MIT License (MIT) +Copyright (c) 2015 Frits van Bommel +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/internal/natsort/README.md b/internal/natsort/README.md new file mode 100644 index 00000000..ed8da0e2 --- /dev/null +++ b/internal/natsort/README.md @@ -0,0 +1,5 @@ +## sortorder [![GoDoc](https://godoc.org/vbom.ml/util/sortorder?status.svg)](https://godoc.org/vbom.ml/util/sortorder) + + import "vbom.ml/util/sortorder" + +Sort orders and comparison functions. diff --git a/internal/natsort/doc.go b/internal/natsort/doc.go new file mode 100644 index 00000000..61b37a93 --- /dev/null +++ b/internal/natsort/doc.go @@ -0,0 +1,5 @@ +// Package sortorder implements sort orders and comparison functions. +// +// Currently, it only implements so-called "natural order", where integers +// embedded in strings are compared by value. +package sortorder // import "vbom.ml/util/sortorder" diff --git a/internal/natsort/natsort.go b/internal/natsort/natsort.go new file mode 100644 index 00000000..66a52c71 --- /dev/null +++ b/internal/natsort/natsort.go @@ -0,0 +1,76 @@ +package sortorder + +// Natural implements sort.Interface to sort strings in natural order. This +// means that e.g. "abc2" < "abc12". +// +// Non-digit sequences and numbers are compared separately. The former are +// compared bytewise, while the latter are compared numerically (except that +// the number of leading zeros is used as a tie-breaker, so e.g. "2" < "02") +// +// Limitation: only ASCII digits (0-9) are considered. +type Natural []string + +func (n Natural) Len() int { return len(n) } +func (n Natural) Swap(i, j int) { n[i], n[j] = n[j], n[i] } +func (n Natural) Less(i, j int) bool { return NaturalLess(n[i], n[j]) } + +func isdigit(b byte) bool { return '0' <= b && b <= '9' } + +// NaturalLess compares two strings using natural ordering. This means that e.g. +// "abc2" < "abc12". +// +// Non-digit sequences and numbers are compared separately. The former are +// compared bytewise, while the latter are compared numerically (except that +// the number of leading zeros is used as a tie-breaker, so e.g. "2" < "02") +// +// Limitation: only ASCII digits (0-9) are considered. +func NaturalLess(str1, str2 string) bool { + idx1, idx2 := 0, 0 + for idx1 < len(str1) && idx2 < len(str2) { + c1, c2 := str1[idx1], str2[idx2] + dig1, dig2 := isdigit(c1), isdigit(c2) + switch { + case dig1 != dig2: // Digits before other characters. + return dig1 // True if LHS is a digit, false if the RHS is one. + case !dig1: // && !dig2, because dig1 == dig2 + // UTF-8 compares bytewise-lexicographically, no need to decode + // codepoints. + if c1 != c2 { + return c1 < c2 + } + idx1++ + idx2++ + default: // Digits + // Eat zeros. + for ; idx1 < len(str1) && str1[idx1] == '0'; idx1++ { + } + for ; idx2 < len(str2) && str2[idx2] == '0'; idx2++ { + } + // Eat all digits. + nonZero1, nonZero2 := idx1, idx2 + for ; idx1 < len(str1) && isdigit(str1[idx1]); idx1++ { + } + for ; idx2 < len(str2) && isdigit(str2[idx2]); idx2++ { + } + // If lengths of numbers with non-zero prefix differ, the shorter + // one is less. + if len1, len2 := idx1-nonZero1, idx2-nonZero2; len1 != len2 { + return len1 < len2 + } + // If they're equal, string comparison is correct. + if nr1, nr2 := str1[nonZero1:idx1], str2[nonZero2:idx2]; nr1 != nr2 { + return nr1 < nr2 + } + // Otherwise, the one with less zeros is less. + // Because everything up to the number is equal, comparing the index + // after the zeros is sufficient. + if nonZero1 != nonZero2 { + return nonZero1 < nonZero2 + } + } + // They're identical so far, so continue comparing. + } + // So far they are identical. At least one is ended. If the other continues, + // it sorts last. + return len(str1) < len(str2) +} diff --git a/internal/natsort/natsort_test.go b/internal/natsort/natsort_test.go new file mode 100644 index 00000000..5680c949 --- /dev/null +++ b/internal/natsort/natsort_test.go @@ -0,0 +1,230 @@ +package sortorder + +import ( + "flag" + "math/rand" + "reflect" + "sort" + "strconv" + "testing" + + "github.com/xlab/handysort" +) + +func TestStringSort(t *testing.T) { + a := []string{ + "ab", "abc1", + "abc01", "abc2", + "abc5", "abc10", + } + b := []string{ + "abc5", "abc1", + "abc01", "ab", + "abc10", "abc2", + } + sort.Sort(Natural(b)) + if !reflect.DeepEqual(a, b) { + t.Errorf("Error: sort failed, expected: %#q, got: %#q", a, b) + } +} + +func TestNaturalLess(t *testing.T) { + testset := []struct { + s1, s2 string + less bool + }{ + {"0", "00", true}, + {"00", "0", false}, + {"aa", "ab", true}, + {"ab", "abc", true}, + {"abc", "ad", true}, + {"ab1", "ab2", true}, + {"ab1c", "ab1c", false}, + {"ab12", "abc", true}, + {"ab2a", "ab10", true}, + {"a0001", "a0000001", true}, + {"a10", "abcdefgh2", true}, + {"аб2аб", "аб10аб", true}, + {"2аб", "3аб", true}, + // + {"a1b", "a01b", true}, + {"a01b", "a1b", false}, + {"ab01b", "ab010b", true}, + {"ab010b", "ab01b", false}, + {"a01b001", "a001b01", true}, + {"a001b01", "a01b001", false}, + {"a1", "a1x", true}, + {"1ax", "1b", true}, + {"1b", "1ax", false}, + // + {"082", "83", true}, + // + {"083a", "9a", false}, + {"9a", "083a", true}, + } + for _, v := range testset { + if res := NaturalLess(v.s1, v.s2); res != v.less { + t.Errorf("Compared %#q to %#q: expected %v, got %v", + v.s1, v.s2, v.less, res) + } + if res := handysort.StringLess(v.s1, v.s2); res != v.less { + t.Logf("handysort: Compared %#q to %#q: expected %v, got %v", + v.s1, v.s2, v.less, res) + } + } +} + +var testEquivalence = flag.Bool("equivalence", false, "Test equivalence with handysort") + +func TestEquivalenceToXlabStringLess(t *testing.T) { + if !*testEquivalence { + t.Skip("Skipping exhaustive test without -equivalence") + } + + set := testSet(300) + for _, list := range set[:1] { + list = list[:100] + for _, lhs := range list { + for _, rhs := range list { + nl := NaturalLess(lhs, rhs) + sl := handysort.StringLess(lhs, rhs) + if nl != sl { + t.Errorf("difference to handysort: %v vs %v for %#q < %#q", nl, sl, lhs, rhs) + } + } + } + } +} + +func BenchmarkStdStringSort(b *testing.B) { + set := testSet(300) + arr := make([]string, len(set[0])) + b.ResetTimer() + for i := 0; i < b.N; i++ { + for _, list := range set { + b.StopTimer() + copy(arr, list) + b.StartTimer() + + sort.Strings(arr) + } + } +} + +func BenchmarkNaturalStringSort(b *testing.B) { + set := testSet(300) + arr := make([]string, len(set[0])) + b.ResetTimer() + for i := 0; i < b.N; i++ { + for _, list := range set { + b.StopTimer() + copy(arr, list) + b.StartTimer() + + sort.Sort(Natural(arr)) + } + } +} + +func BenchmarkHandyStringSort(b *testing.B) { + set := testSet(300) + arr := make([]string, len(set[0])) + b.ResetTimer() + for i := 0; i < b.N; i++ { + for _, list := range set { + b.StopTimer() + copy(arr, list) + b.StartTimer() + + sort.Sort(handysort.Strings(arr)) + } + } +} + +func BenchmarkStdStringLess(b *testing.B) { + set := testSet(300) + b.ResetTimer() + for i := 0; i < b.N; i++ { + for j := range set[0] { + k := (j + 1) % len(set[0]) + _ = set[0][j] < set[0][k] + } + } +} + +func BenchmarkNaturalLess(b *testing.B) { + set := testSet(300) + b.ResetTimer() + for i := 0; i < b.N; i++ { + for j := range set[0] { + k := (j + 1) % len(set[0]) + _ = NaturalLess(set[0][j], set[0][k]) + } + } +} + +func BenchmarkHandyStringLess(b *testing.B) { + set := testSet(300) + b.ResetTimer() + for i := 0; i < b.N; i++ { + for j := range set[0] { + k := (j + 1) % len(set[0]) + _ = handysort.StringLess(set[0][j], set[0][k]) + } + } +} + +// Get 1000 arrays of 10000-string-arrays (less if -short is specified). +func testSet(seed int) [][]string { + gen := &generator{ + src: rand.New(rand.NewSource( + int64(seed), + )), + } + n := 1000 + if testing.Short() { + n = 1 + } + set := make([][]string, n) + for i := range set { + strings := make([]string, 10000) + for idx := range strings { + // Generate a random string + strings[idx] = gen.NextString() + } + set[i] = strings + } + return set +} + +type generator struct { + src *rand.Rand +} + +func (g *generator) NextInt(max int) int { + return g.src.Intn(max) +} + +// Gets random random-length alphanumeric string. +func (g *generator) NextString() (str string) { + // Random-length 3-8 chars part + strlen := g.src.Intn(6) + 3 + // Random-length 1-3 num + numlen := g.src.Intn(3) + 1 + // Random position for num in string + numpos := g.src.Intn(strlen + 1) + // Generate the number + var num string + for i := 0; i < numlen; i++ { + num += strconv.Itoa(g.src.Intn(10)) + } + // Put it all together + for i := 0; i < strlen+1; i++ { + if i == numpos { + str += num + } else { + str += string('a' + g.src.Intn(16)) + } + } + return str +} From eebb5f5e5b66c368668f9e6c92c6c219f53052cd Mon Sep 17 00:00:00 2001 From: Robin Eklind Date: Mon, 1 Jul 2019 03:23:04 +0800 Subject: [PATCH 2/6] internal/natsort: rename sortorder to natsort and remove vanity import --- internal/natsort/README.md | 11 ++++++++--- internal/natsort/doc.go | 5 ----- internal/natsort/natsort.go | 7 ++++++- internal/natsort/natsort_test.go | 2 +- 4 files changed, 15 insertions(+), 10 deletions(-) delete mode 100644 internal/natsort/doc.go diff --git a/internal/natsort/README.md b/internal/natsort/README.md index ed8da0e2..8bc32e45 100644 --- a/internal/natsort/README.md +++ b/internal/natsort/README.md @@ -1,5 +1,10 @@ -## sortorder [![GoDoc](https://godoc.org/vbom.ml/util/sortorder?status.svg)](https://godoc.org/vbom.ml/util/sortorder) +# natsort - import "vbom.ml/util/sortorder" +This is a fork of the `sortorder` package of [github.com/fvbommel/util](https://github.com/fvbommel/util). -Sort orders and comparison functions. +## License + +* [MIT](./LICENSE) + - the original implementation of `sortorder` was released by [Frits van Bommel](https://github.com/fvbommel) under an MIT license. +* [Public domain](../../UNLICENSE) + - any changes made in this fork are released into the public domain. diff --git a/internal/natsort/doc.go b/internal/natsort/doc.go deleted file mode 100644 index 61b37a93..00000000 --- a/internal/natsort/doc.go +++ /dev/null @@ -1,5 +0,0 @@ -// Package sortorder implements sort orders and comparison functions. -// -// Currently, it only implements so-called "natural order", where integers -// embedded in strings are compared by value. -package sortorder // import "vbom.ml/util/sortorder" diff --git a/internal/natsort/natsort.go b/internal/natsort/natsort.go index 66a52c71..0d31ad85 100644 --- a/internal/natsort/natsort.go +++ b/internal/natsort/natsort.go @@ -1,4 +1,9 @@ -package sortorder +// Package natsort implements natural sort. In "Natural Sort Order" integers +// embedded in strings are compared by value. +// +// References: +// https://blog.codinghorror.com/sorting-for-humans-natural-sort-order/ +package natsort // Natural implements sort.Interface to sort strings in natural order. This // means that e.g. "abc2" < "abc12". diff --git a/internal/natsort/natsort_test.go b/internal/natsort/natsort_test.go index 5680c949..74cd2f35 100644 --- a/internal/natsort/natsort_test.go +++ b/internal/natsort/natsort_test.go @@ -1,4 +1,4 @@ -package sortorder +package natsort import ( "flag" From 785c448fb8e1932ce8ba4c20d2ee7ffd52b57780 Mon Sep 17 00:00:00 2001 From: Robin Eklind Date: Mon, 1 Jul 2019 03:34:55 +0800 Subject: [PATCH 3/6] internal/natsort: add Strings, rename Natural to Order and NaturalLess to Less Also, remove usage of github.com/xlab/handysort from test cases. --- internal/natsort/natsort.go | 32 +++++++++----- internal/natsort/natsort_test.go | 75 +++++--------------------------- 2 files changed, 32 insertions(+), 75 deletions(-) diff --git a/internal/natsort/natsort.go b/internal/natsort/natsort.go index 0d31ad85..20008804 100644 --- a/internal/natsort/natsort.go +++ b/internal/natsort/natsort.go @@ -5,31 +5,43 @@ // https://blog.codinghorror.com/sorting-for-humans-natural-sort-order/ package natsort -// Natural implements sort.Interface to sort strings in natural order. This -// means that e.g. "abc2" < "abc12". +import ( + "sort" +) + +// Strings sorts the given slice of strings in natural order. +func Strings(a []string) { + sort.Sort(Order(a)) +} + +// Order implements sort.Interface to sort strings in natural order. This means +// that e.g. "abc2" < "abc12". // // Non-digit sequences and numbers are compared separately. The former are // compared bytewise, while the latter are compared numerically (except that // the number of leading zeros is used as a tie-breaker, so e.g. "2" < "02") // // Limitation: only ASCII digits (0-9) are considered. -type Natural []string +type Order []string -func (n Natural) Len() int { return len(n) } -func (n Natural) Swap(i, j int) { n[i], n[j] = n[j], n[i] } -func (n Natural) Less(i, j int) bool { return NaturalLess(n[i], n[j]) } +func (n Order) Len() int { return len(n) } +func (n Order) Swap(i, j int) { n[i], n[j] = n[j], n[i] } +func (n Order) Less(i, j int) bool { return Less(n[i], n[j]) } -func isdigit(b byte) bool { return '0' <= b && b <= '9' } +// isdigit reports whether the given byte is a decimal digit. +func isdigit(b byte) bool { + return '0' <= b && b <= '9' +} -// NaturalLess compares two strings using natural ordering. This means that e.g. -// "abc2" < "abc12". +// Less compares two strings using natural ordering. This means that e.g. "abc2" +// < "abc12". // // Non-digit sequences and numbers are compared separately. The former are // compared bytewise, while the latter are compared numerically (except that // the number of leading zeros is used as a tie-breaker, so e.g. "2" < "02") // // Limitation: only ASCII digits (0-9) are considered. -func NaturalLess(str1, str2 string) bool { +func Less(str1, str2 string) bool { idx1, idx2 := 0, 0 for idx1 < len(str1) && idx2 < len(str2) { c1, c2 := str1[idx1], str2[idx2] diff --git a/internal/natsort/natsort_test.go b/internal/natsort/natsort_test.go index 74cd2f35..b26a1741 100644 --- a/internal/natsort/natsort_test.go +++ b/internal/natsort/natsort_test.go @@ -1,17 +1,14 @@ package natsort import ( - "flag" "math/rand" "reflect" "sort" "strconv" "testing" - - "github.com/xlab/handysort" ) -func TestStringSort(t *testing.T) { +func TestStrings(t *testing.T) { a := []string{ "ab", "abc1", "abc01", "abc2", @@ -22,13 +19,13 @@ func TestStringSort(t *testing.T) { "abc01", "ab", "abc10", "abc2", } - sort.Sort(Natural(b)) + Strings(b) if !reflect.DeepEqual(a, b) { t.Errorf("Error: sort failed, expected: %#q, got: %#q", a, b) } } -func TestNaturalLess(t *testing.T) { +func TestLess(t *testing.T) { testset := []struct { s1, s2 string less bool @@ -63,40 +60,14 @@ func TestNaturalLess(t *testing.T) { {"9a", "083a", true}, } for _, v := range testset { - if res := NaturalLess(v.s1, v.s2); res != v.less { + if res := Less(v.s1, v.s2); res != v.less { t.Errorf("Compared %#q to %#q: expected %v, got %v", v.s1, v.s2, v.less, res) } - if res := handysort.StringLess(v.s1, v.s2); res != v.less { - t.Logf("handysort: Compared %#q to %#q: expected %v, got %v", - v.s1, v.s2, v.less, res) - } } } -var testEquivalence = flag.Bool("equivalence", false, "Test equivalence with handysort") - -func TestEquivalenceToXlabStringLess(t *testing.T) { - if !*testEquivalence { - t.Skip("Skipping exhaustive test without -equivalence") - } - - set := testSet(300) - for _, list := range set[:1] { - list = list[:100] - for _, lhs := range list { - for _, rhs := range list { - nl := NaturalLess(lhs, rhs) - sl := handysort.StringLess(lhs, rhs) - if nl != sl { - t.Errorf("difference to handysort: %v vs %v for %#q < %#q", nl, sl, lhs, rhs) - } - } - } - } -} - -func BenchmarkStdStringSort(b *testing.B) { +func BenchmarkStdStrings(b *testing.B) { set := testSet(300) arr := make([]string, len(set[0])) b.ResetTimer() @@ -111,7 +82,7 @@ func BenchmarkStdStringSort(b *testing.B) { } } -func BenchmarkNaturalStringSort(b *testing.B) { +func BenchmarkStrings(b *testing.B) { set := testSet(300) arr := make([]string, len(set[0])) b.ResetTimer() @@ -121,27 +92,12 @@ func BenchmarkNaturalStringSort(b *testing.B) { copy(arr, list) b.StartTimer() - sort.Sort(Natural(arr)) + Strings(arr) } } } -func BenchmarkHandyStringSort(b *testing.B) { - set := testSet(300) - arr := make([]string, len(set[0])) - b.ResetTimer() - for i := 0; i < b.N; i++ { - for _, list := range set { - b.StopTimer() - copy(arr, list) - b.StartTimer() - - sort.Sort(handysort.Strings(arr)) - } - } -} - -func BenchmarkStdStringLess(b *testing.B) { +func BenchmarkStdLess(b *testing.B) { set := testSet(300) b.ResetTimer() for i := 0; i < b.N; i++ { @@ -152,24 +108,13 @@ func BenchmarkStdStringLess(b *testing.B) { } } -func BenchmarkNaturalLess(b *testing.B) { - set := testSet(300) - b.ResetTimer() - for i := 0; i < b.N; i++ { - for j := range set[0] { - k := (j + 1) % len(set[0]) - _ = NaturalLess(set[0][j], set[0][k]) - } - } -} - -func BenchmarkHandyStringLess(b *testing.B) { +func BenchmarkLess(b *testing.B) { set := testSet(300) b.ResetTimer() for i := 0; i < b.N; i++ { for j := range set[0] { k := (j + 1) % len(set[0]) - _ = handysort.StringLess(set[0][j], set[0][k]) + _ = Less(set[0][j], set[0][k]) } } } From 757f554648e36a8fd353fff3e8ef537770a0128c Mon Sep 17 00:00:00 2001 From: Robin Eklind Date: Mon, 1 Jul 2019 23:56:57 +0800 Subject: [PATCH 4/6] internal/natsort: refine natural sorting order Prior to this commit, the array `a` as defined below: a := []string{ "foo20", "foo.bar", "foo2", "foo.10", "foo.1", "foo.20", "foo.11", "foo1", "foobar", "foo21", "foo10", "foo11", "foo.21", "foo.2", } would be sorted as follows: "foo1" "foo2" "foo10" "foo11" "foo20" "foo21" "foo.1" "foo.2" "foo.10" "foo.11" "foo.20" "foo.21" "foo.bar" "foobar" That is, digits would be considered "less" than other characters. After this commit, the same slice would be sorted as follows: "foo.1" "foo.2" "foo.10" "foo.11" "foo.20" "foo.21" "foo.bar" "foo1" "foo2" "foo10" "foo11" "foo20" "foo21" "foobar" This conforms to the sorting behaviour of many File Managers and may thus be considered expected behaviour for users. Note, this is the first commit to internal/natsort that diverges in functionality from the sortorder package of @fvbommel. As such, natsort should now be considered a fork and not just a vendored mirror. As stated in the README.md document of the internal/natsort directory, the original code written by Frits van Bommel is licensed under an MIT license. Any subsequent changes made to the code base after the fork are hereby released into the public domain. This commit also extends the test cases. --- internal/natsort/natsort.go | 20 ++++++------ internal/natsort/natsort_test.go | 54 +++++++++++++++++++++++++------- 2 files changed, 51 insertions(+), 23 deletions(-) diff --git a/internal/natsort/natsort.go b/internal/natsort/natsort.go index 20008804..4400e2ba 100644 --- a/internal/natsort/natsort.go +++ b/internal/natsort/natsort.go @@ -47,17 +47,7 @@ func Less(str1, str2 string) bool { c1, c2 := str1[idx1], str2[idx2] dig1, dig2 := isdigit(c1), isdigit(c2) switch { - case dig1 != dig2: // Digits before other characters. - return dig1 // True if LHS is a digit, false if the RHS is one. - case !dig1: // && !dig2, because dig1 == dig2 - // UTF-8 compares bytewise-lexicographically, no need to decode - // codepoints. - if c1 != c2 { - return c1 < c2 - } - idx1++ - idx2++ - default: // Digits + case dig1 && dig2: // Digits // Eat zeros. for ; idx1 < len(str1) && str1[idx1] == '0'; idx1++ { } @@ -84,6 +74,14 @@ func Less(str1, str2 string) bool { if nonZero1 != nonZero2 { return nonZero1 < nonZero2 } + default: // non-digit characters + // UTF-8 compares bytewise-lexicographically, no need to decode + // codepoints. + if c1 != c2 { + return c1 < c2 + } + idx1++ + idx2++ } // They're identical so far, so continue comparing. } diff --git a/internal/natsort/natsort_test.go b/internal/natsort/natsort_test.go index b26a1741..a9b1f52f 100644 --- a/internal/natsort/natsort_test.go +++ b/internal/natsort/natsort_test.go @@ -9,19 +9,46 @@ import ( ) func TestStrings(t *testing.T) { - a := []string{ - "ab", "abc1", - "abc01", "abc2", - "abc5", "abc10", - } - b := []string{ - "abc5", "abc1", - "abc01", "ab", - "abc10", "abc2", + golden := []struct { + in []string + want []string + }{ + { + in: []string{"abc5", "abc1", "abc01", "ab", "abc10", "abc2"}, + want: []string{ + "ab", + "abc1", + "abc01", + "abc2", + "abc5", + "abc10", + }, + }, + { + in: []string{"foo20", "foo.bar", "foo2", "foo.10", "foo.1", "foo.20", "foo.11", "foo1", "foobar", "foo21", "foo10", "foo11", "foo.21", "foo.2"}, + want: []string{ + "foo.1", + "foo.2", + "foo.10", + "foo.11", + "foo.20", + "foo.21", + "foo.bar", + "foo1", + "foo2", + "foo10", + "foo11", + "foo20", + "foo21", + "foobar", + }, + }, } - Strings(b) - if !reflect.DeepEqual(a, b) { - t.Errorf("Error: sort failed, expected: %#q, got: %#q", a, b) + for _, g := range golden { + Strings(g.in) + if !reflect.DeepEqual(g.want, g.in) { + t.Errorf("Error: sort failed, expected: %#q, got: %#q", g.want, g.in) + } } } @@ -58,6 +85,9 @@ func TestLess(t *testing.T) { // {"083a", "9a", false}, {"9a", "083a", true}, + // + {"foo.bar", "foo123", true}, + {"foo123", "foo.bar", false}, } for _, v := range testset { if res := Less(v.s1, v.s2); res != v.less { From e123e6f9f83dbab8e506e1b975777708dd5cb7a1 Mon Sep 17 00:00:00 2001 From: Robin Eklind Date: Mon, 1 Jul 2019 23:59:24 +0800 Subject: [PATCH 5/6] all: replace rickypai/natsort with internal/natsort See commit llir/llvm@757f554648e36a8fd353fff3e8ef537770a0128c for details. Updates #92. --- asm/translate.go | 2 +- go.mod | 1 - go.sum | 2 -- ir/module.go | 2 +- 4 files changed, 2 insertions(+), 5 deletions(-) diff --git a/asm/translate.go b/asm/translate.go index 706d222b..5c106abb 100644 --- a/asm/translate.go +++ b/asm/translate.go @@ -89,12 +89,12 @@ import ( "github.com/llir/ll/ast" "github.com/llir/llvm/internal/enc" + "github.com/llir/llvm/internal/natsort" "github.com/llir/llvm/ir" "github.com/llir/llvm/ir/constant" "github.com/llir/llvm/ir/metadata" "github.com/llir/llvm/ir/types" "github.com/pkg/errors" - "github.com/rickypai/natsort" ) // translate translates the given AST module into an equivalent IR module. diff --git a/go.mod b/go.mod index 93febfde..45b98137 100644 --- a/go.mod +++ b/go.mod @@ -7,6 +7,5 @@ require ( github.com/mewmew/float v0.0.0-20181121163145-c0f786d7da73 github.com/mewspring/tools v0.0.0-20190326052302-906fcc68b3d8 github.com/pkg/errors v0.8.1 - github.com/rickypai/natsort v0.0.0-20180124032556-f194e6bd5b0c golang.org/x/tools v0.0.0-20190330180304-aef51cc3777c ) diff --git a/go.sum b/go.sum index 5ed960b9..01fe68bb 100644 --- a/go.sum +++ b/go.sum @@ -13,8 +13,6 @@ github.com/mewspring/tools v0.0.0-20190326052302-906fcc68b3d8 h1:DSZ+nV7JOU9CznT github.com/mewspring/tools v0.0.0-20190326052302-906fcc68b3d8/go.mod h1:UAdVbSksr+7Bg+z4mga16OaBg3qAcgdaF3x3AeqJHEs= github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/rickypai/natsort v0.0.0-20180124032556-f194e6bd5b0c h1:wq5MmT1Whub72MXlR2I5jWTQ3Q5wkNXnVBY21Q3Qzis= -github.com/rickypai/natsort v0.0.0-20180124032556-f194e6bd5b0c/go.mod h1:ECfieXu+EwvGnmpzRZvaAN0U/Jese1LX/BqX3HF1Kl0= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/image v0.0.0-20190220214146-31aff87c08e9/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= diff --git a/ir/module.go b/ir/module.go index 86e03f7e..d1280367 100644 --- a/ir/module.go +++ b/ir/module.go @@ -5,12 +5,12 @@ import ( "strings" "github.com/llir/llvm/internal/enc" + "github.com/llir/llvm/internal/natsort" "github.com/llir/llvm/ir/enum" "github.com/llir/llvm/ir/metadata" "github.com/llir/llvm/ir/types" "github.com/llir/llvm/ir/value" "github.com/pkg/errors" - "github.com/rickypai/natsort" ) // === [ Modules ] ============================================================= From 685a7e31e19c1645d4acd0bf04bb9581d5ddeaa5 Mon Sep 17 00:00:00 2001 From: Robin Eklind Date: Tue, 2 Jul 2019 01:39:52 +0800 Subject: [PATCH 6/6] travis: skip -u in go get to play nicer with Go modules --- .travis.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index c20fb431..bfb92d4c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,11 +16,11 @@ install: - go get -t ./... before_script: - - go get -u golang.org/x/tools/cmd/cover - - go get -u golang.org/x/tools/cmd/goimports - - go get -u golang.org/x/lint/golint - - go get -u github.com/mattn/goveralls - - go get -u github.com/golangci/golangci-lint/cmd/golangci-lint + - go get golang.org/x/tools/cmd/cover + - go get golang.org/x/tools/cmd/goimports + - go get golang.org/x/lint/golint + - go get github.com/mattn/goveralls + - go get github.com/golangci/golangci-lint/cmd/golangci-lint - wget https://raw.githubusercontent.com/mewmew/ci/master/ci_checks.sh - chmod +x ci_checks.sh