From 5f46006783383588e1a74cafd9c56f79ae6c96c4 Mon Sep 17 00:00:00 2001 From: ikedam Date: Sun, 18 Sep 2022 14:17:01 +0000 Subject: [PATCH] feat: go template function uniqueOlderCommits/uniqueNewerCommits is available * They allow to remove duplicated log entries. Closes #29 --- README.md | 7 + chglog.go | 105 ++++++++++- chglog_test.go | 472 +++++++++++++++++++++++++++++++++++++++++++++++++ utils.go | 18 ++ utils_test.go | 27 +++ 5 files changed, 625 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 3e767100..f13d0a7b 100644 --- a/README.md +++ b/README.md @@ -459,6 +459,13 @@ We have implemented the following custom template functions. These override func | `replace` | `func(s, old, new string, n int) string` | Replace `old` with `new` within string `s`, `n` times using `strings.Replace` | | `upperFirst` | `func(s string) string` | Upper case the first character of a string | +Following custom template functions are also available. + +| Name | Signature | Description | +| :------------------- | :---------------------------------------------------- | :---------------------------------------------------------------------------- | +| `uniqueOlderCommits` | `func(commits []*Commit, fields ...string) []*Commit` | Removes duplicated commits. Duplication is evaluated with fields specified. If your logs are created with ".Scope" and ".Subject", specify "Scope" "Subject" to remove duplicated logs. Newer logs, that means ones coming upper in changelogs will be removed for duplication. | +| `uniqueNewerCommits` | `func(commits []*Commit, fields ...string) []*Commit` | Removes duplicated commits just like `uniqueOlderCommits`, but older logs will be removed for duplication. | + If you are not satisfied with the prepared template please try customizing one. --- diff --git a/chglog.go b/chglog.go index fc5cf9e3..b5ef3839 100644 --- a/chglog.go +++ b/chglog.go @@ -344,10 +344,12 @@ func (gen *Generator) render(w io.Writer, unreleased *Unreleased, versions []*Ve // While Sprig provides these functions, they change the standard input // order which leads to a regression. For an example see: // https://github.com/Masterminds/sprig/blob/master/functions.go#L149 - "contains": strings.Contains, - "hasPrefix": strings.HasPrefix, - "hasSuffix": strings.HasSuffix, - "replace": strings.Replace, + "contains": strings.Contains, + "hasPrefix": strings.HasPrefix, + "hasSuffix": strings.HasSuffix, + "replace": strings.Replace, + "uniqueOlderCommits": uniqueOlderCommits, + "uniqueNewerCommits": uniqueNewerCommits, } fname := filepath.Base(gen.config.Template) @@ -360,3 +362,98 @@ func (gen *Generator) render(w io.Writer, unreleased *Unreleased, versions []*Ve Versions: versions, }) } + +// uniqueOlderCommits remmoves duplicated commits. +// Newer commits are removed when duplicated. +// Tests duplication with fields specified with `fields`. +func uniqueOlderCommits(commits []*Commit, fields ...string) ([]*Commit, error) { + if len(fields) == 0 { + return nil, fmt.Errorf("specify at least one field") + } + if len(commits) == 0 { + return nil, nil + } + filtered := make([]*Commit, 0, len(commits)) + for idx, commit := range commits { + // compare with older commits and skip if duplicated. + duplicated, err := hasDuplicatedCommit(commits[idx+1:], commit, fields) + if err != nil { + return nil, err + } + if duplicated { + continue + } + filtered = append(filtered, commit) + } + return filtered, nil +} + +// uniqueNewerCommits remmoves duplicated commits. +// Older commits are removed when duplicated. +// Tests duplication with fields specified with `fields`. +func uniqueNewerCommits(commits []*Commit, fields ...string) ([]*Commit, error) { + if len(fields) == 0 { + return nil, fmt.Errorf("specify at least one field") + } + if len(commits) == 0 { + return nil, nil + } + filtered := make([]*Commit, 0, len(commits)) + for idx, commit := range commits { + // compare with newer commits and skip if duplicated. + duplicated, err := hasDuplicatedCommit(commits[:idx], commit, fields) + if err != nil { + return nil, err + } + if duplicated { + continue + } + filtered = append(filtered, commit) + } + return filtered, nil +} + +func hasDuplicatedCommit(targetCommits []*Commit, commit *Commit, fields []string) (bool, error) { + for _, targetCommit := range targetCommits { + duplicated, err := isDuplicatedCommit(commit, targetCommit, fields) + if err != nil { + return false, err + } + if duplicated { + return true, nil + } + } + return false, nil +} + +func isDuplicatedCommit(commit1 *Commit, commit2 *Commit, fields []string) (bool, error) { + for _, field := range fields { + a, ok := dotGetNilable(commit1, field) + if !ok { + return false, fmt.Errorf("cannot extract field \"%v\" for commit \"%v\"", field, commit1.Hash.Short) + } + b, ok := dotGetNilable(commit2, field) + if !ok { + return false, fmt.Errorf("cannot extract field \"%v\" for commit \"%v\"", field, commit1.Hash.Short) + } + // Here, `nil` for interface. + if a == nil || b == nil { + if a != nil || b != nil { + // not duplicated ones if something differs. + return false, nil + } + // considered to be same. + continue + } + eq, err := compare(a, "==", b) + if err != nil { + return false, err + } + if !eq { + // not duplicated ones if something differs. + return false, nil + } + } + // duplicated ones if nothing differs. + return true, nil +} diff --git a/chglog_test.go b/chglog_test.go index a00359bb..d28bc608 100644 --- a/chglog_test.go +++ b/chglog_test.go @@ -629,3 +629,475 @@ func TestGeneratorWithSprig(t *testing.T) { [2.0.0]: https://github.com/git-chglog/git-chglog/compare/1.0.0...2.0.0`, expected) } + +func TestUniqueOlderCommits(t *testing.T) { + tests := []struct { + name string + commits []*Commit + fields []string + expected []*Commit + expectError assert.ErrorAssertionFunc + }{ + { + name: "Duplication detected", + commits: []*Commit{ + {Hash: &Hash{Short: "1"}, Subject: "log1"}, + {Hash: &Hash{Short: "2"}, Subject: "log2"}, + {Hash: &Hash{Short: "3"}, Subject: "log1"}, // Duplicated! + {Hash: &Hash{Short: "4"}, Subject: "log4"}, + }, + fields: []string{"Subject"}, + expected: []*Commit{ + // {Hash: &Hash{Short: "1"}, Subject: "log1"}, + {Hash: &Hash{Short: "2"}, Subject: "log2"}, + {Hash: &Hash{Short: "3"}, Subject: "log1"}, // Duplicated! + {Hash: &Hash{Short: "4"}, Subject: "log4"}, + }, + expectError: assert.NoError, + }, + { + name: "2 duplications detected", + commits: []*Commit{ + {Hash: &Hash{Short: "1"}, Subject: "log1"}, + {Hash: &Hash{Short: "2"}, Subject: "log2"}, + {Hash: &Hash{Short: "3"}, Subject: "log2"}, // Duplicated! + {Hash: &Hash{Short: "4"}, Subject: "log1"}, // Duplicated! + }, + fields: []string{"Subject"}, + expected: []*Commit{ + // {Hash: &Hash{Short: "1"}, Subject: "log1"}, + // {Hash: &Hash{Short: "2"}, Subject: "log2"}, + {Hash: &Hash{Short: "3"}, Subject: "log2"}, // Duplicated! + {Hash: &Hash{Short: "4"}, Subject: "log1"}, // Duplicated! + }, + expectError: assert.NoError, + }, + { + name: "A double duplication detected", + commits: []*Commit{ + {Hash: &Hash{Short: "1"}, Subject: "log1"}, + {Hash: &Hash{Short: "2"}, Subject: "log2"}, + {Hash: &Hash{Short: "3"}, Subject: "log1"}, // Duplicated! + {Hash: &Hash{Short: "4"}, Subject: "log1"}, // Duplicated! + }, + fields: []string{"Subject"}, + expected: []*Commit{ + // {Hash: &Hash{Short: "1"}, Subject: "log1"}, + {Hash: &Hash{Short: "2"}, Subject: "log2"}, + // {Hash: &Hash{Short: "3"}, Subject: "log1"}, // Duplicated! + {Hash: &Hash{Short: "4"}, Subject: "log1"}, // Duplicated! + }, + expectError: assert.NoError, + }, + { + name: "No duplicates", + commits: []*Commit{ + {Hash: &Hash{Short: "1"}, Subject: "log1"}, + {Hash: &Hash{Short: "2"}, Subject: "log2"}, + {Hash: &Hash{Short: "3"}, Subject: "log3"}, + {Hash: &Hash{Short: "4"}, Subject: "log4"}, + }, + fields: []string{"Subject"}, + expected: []*Commit{ + {Hash: &Hash{Short: "1"}, Subject: "log1"}, + {Hash: &Hash{Short: "2"}, Subject: "log2"}, + {Hash: &Hash{Short: "3"}, Subject: "log3"}, + {Hash: &Hash{Short: "4"}, Subject: "log4"}, + }, + expectError: assert.NoError, + }, + { + name: "No commits (empty)", + commits: []*Commit{}, + fields: []string{"Subject"}, + expected: nil, + expectError: assert.NoError, + }, + { + name: "No commits (nil)", + commits: nil, + fields: []string{"Subject"}, + expected: nil, + expectError: assert.NoError, + }, + { + name: "Empty fields (error)", + commits: []*Commit{ + {Hash: &Hash{Short: "1"}, Subject: "log1"}, + {Hash: &Hash{Short: "2"}, Subject: "log2"}, + {Hash: &Hash{Short: "3"}, Subject: "log1"}, // Duplicated! + {Hash: &Hash{Short: "4"}, Subject: "log4"}, + }, + fields: []string{}, + expected: nil, + expectError: assert.Error, + }, + { + name: "nil for fields (error)", + commits: []*Commit{ + {Hash: &Hash{Short: "1"}, Subject: "log1"}, + {Hash: &Hash{Short: "2"}, Subject: "log2"}, + {Hash: &Hash{Short: "3"}, Subject: "log1"}, // Duplicated! + {Hash: &Hash{Short: "4"}, Subject: "log4"}, + }, + fields: nil, + expected: nil, + expectError: assert.Error, + }, + { + name: "bad field (error)", + commits: []*Commit{ + {Hash: &Hash{Short: "1"}, Subject: "log1"}, + {Hash: &Hash{Short: "2"}, Subject: "log2"}, + {Hash: &Hash{Short: "3"}, Subject: "log1"}, // Duplicated! + {Hash: &Hash{Short: "4"}, Subject: "log4"}, + }, + fields: []string{"NoSuchField"}, + expected: nil, + expectError: assert.Error, + }, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + actual, err := uniqueOlderCommits( + test.commits, + test.fields..., + ) + test.expectError(t, err) + assert.Equal(t, test.expected, actual) + }) + } +} + +func TestUniqueNewerCommits(t *testing.T) { + tests := []struct { + name string + commits []*Commit + fields []string + expected []*Commit + expectError assert.ErrorAssertionFunc + }{ + { + name: "Duplication detected", + commits: []*Commit{ + {Hash: &Hash{Short: "1"}, Subject: "log1"}, + {Hash: &Hash{Short: "2"}, Subject: "log2"}, + {Hash: &Hash{Short: "3"}, Subject: "log1"}, // Duplicated! + {Hash: &Hash{Short: "4"}, Subject: "log4"}, + }, + fields: []string{"Subject"}, + expected: []*Commit{ + {Hash: &Hash{Short: "1"}, Subject: "log1"}, + {Hash: &Hash{Short: "2"}, Subject: "log2"}, + // {Hash: &Hash{Short: "3"}, Subject: "log1"}, // Duplicated! + {Hash: &Hash{Short: "4"}, Subject: "log4"}, + }, + expectError: assert.NoError, + }, + { + name: "2 duplications detected", + commits: []*Commit{ + {Hash: &Hash{Short: "1"}, Subject: "log1"}, + {Hash: &Hash{Short: "2"}, Subject: "log2"}, + {Hash: &Hash{Short: "3"}, Subject: "log2"}, // Duplicated! + {Hash: &Hash{Short: "4"}, Subject: "log1"}, // Duplicated! + }, + fields: []string{"Subject"}, + expected: []*Commit{ + {Hash: &Hash{Short: "1"}, Subject: "log1"}, + {Hash: &Hash{Short: "2"}, Subject: "log2"}, + // {Hash: &Hash{Short: "3"}, Subject: "log2"}, // Duplicated! + // {Hash: &Hash{Short: "4"}, Subject: "log1"}, // Duplicated! + }, + expectError: assert.NoError, + }, + { + name: "A double duplication detected", + commits: []*Commit{ + {Hash: &Hash{Short: "1"}, Subject: "log1"}, + {Hash: &Hash{Short: "2"}, Subject: "log2"}, + {Hash: &Hash{Short: "3"}, Subject: "log1"}, // Duplicated! + {Hash: &Hash{Short: "4"}, Subject: "log1"}, // Duplicated! + }, + fields: []string{"Subject"}, + expected: []*Commit{ + {Hash: &Hash{Short: "1"}, Subject: "log1"}, + {Hash: &Hash{Short: "2"}, Subject: "log2"}, + // {Hash: &Hash{Short: "3"}, Subject: "log1"}, // Duplicated! + // {Hash: &Hash{Short: "4"}, Subject: "log1"}, // Duplicated! + }, + expectError: assert.NoError, + }, + { + name: "No duplicates", + commits: []*Commit{ + {Hash: &Hash{Short: "1"}, Subject: "log1"}, + {Hash: &Hash{Short: "2"}, Subject: "log2"}, + {Hash: &Hash{Short: "3"}, Subject: "log3"}, + {Hash: &Hash{Short: "4"}, Subject: "log4"}, + }, + fields: []string{"Subject"}, + expected: []*Commit{ + {Hash: &Hash{Short: "1"}, Subject: "log1"}, + {Hash: &Hash{Short: "2"}, Subject: "log2"}, + {Hash: &Hash{Short: "3"}, Subject: "log3"}, + {Hash: &Hash{Short: "4"}, Subject: "log4"}, + }, + expectError: assert.NoError, + }, + { + name: "No commits (empty)", + commits: []*Commit{}, + fields: []string{"Subject"}, + expected: nil, + expectError: assert.NoError, + }, + { + name: "No commits (nil)", + commits: nil, + fields: []string{"Subject"}, + expected: nil, + expectError: assert.NoError, + }, + { + name: "Empty fields (error)", + commits: []*Commit{ + {Hash: &Hash{Short: "1"}, Subject: "log1"}, + {Hash: &Hash{Short: "2"}, Subject: "log2"}, + {Hash: &Hash{Short: "3"}, Subject: "log1"}, // Duplicated! + {Hash: &Hash{Short: "4"}, Subject: "log4"}, + }, + fields: []string{}, + expected: nil, + expectError: assert.Error, + }, + { + name: "nil for fields (error)", + commits: []*Commit{ + {Hash: &Hash{Short: "1"}, Subject: "log1"}, + {Hash: &Hash{Short: "2"}, Subject: "log2"}, + {Hash: &Hash{Short: "3"}, Subject: "log1"}, // Duplicated! + {Hash: &Hash{Short: "4"}, Subject: "log4"}, + }, + fields: nil, + expected: nil, + expectError: assert.Error, + }, + { + name: "bad field (error)", + commits: []*Commit{ + {Hash: &Hash{Short: "1"}, Subject: "log1"}, + {Hash: &Hash{Short: "2"}, Subject: "log2"}, + {Hash: &Hash{Short: "3"}, Subject: "log1"}, // Duplicated! + {Hash: &Hash{Short: "4"}, Subject: "log4"}, + }, + fields: []string{"NoSuchField"}, + expected: nil, + expectError: assert.Error, + }, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + actual, err := uniqueNewerCommits( + test.commits, + test.fields..., + ) + test.expectError(t, err) + assert.Equal(t, test.expected, actual) + }) + } +} + +func TestHasDuplicatedCommit(t *testing.T) { + tests := []struct { + name string + targetCommits []*Commit + commit *Commit + fields []string + expected bool + expectError assert.ErrorAssertionFunc + }{ + { + name: "Duplication found", + targetCommits: []*Commit{ + {Hash: &Hash{Short: "1"}, Subject: "log1"}, + {Hash: &Hash{Short: "2"}, Subject: "log2"}, + {Hash: &Hash{Short: "3"}, Subject: "log3"}, + }, + commit: &Commit{Hash: &Hash{Short: "99"}, Subject: "log2"}, + fields: []string{"Subject"}, + expected: true, + expectError: assert.NoError, + }, + { + name: "Duplication not found", + targetCommits: []*Commit{ + {Hash: &Hash{Short: "1"}, Subject: "log1"}, + {Hash: &Hash{Short: "2"}, Subject: "log2"}, + {Hash: &Hash{Short: "3"}, Subject: "log3"}, + }, + commit: &Commit{Hash: &Hash{Short: "99"}, Subject: "log99"}, + fields: []string{"Subject"}, + expected: false, + expectError: assert.NoError, + }, + { + name: "No commits (empty)", + targetCommits: []*Commit{}, + commit: &Commit{Hash: &Hash{Short: "99"}, Subject: "log1"}, + fields: []string{"Subject"}, + expected: false, + expectError: assert.NoError, + }, + { + name: "No commits (nil)", + targetCommits: []*Commit{}, + commit: &Commit{Hash: &Hash{Short: "99"}, Subject: "log1"}, + fields: []string{"Subject"}, + expected: false, + expectError: assert.NoError, + }, + { + name: "Empty fields: Nothing to compare and everything is duplicated", + targetCommits: []*Commit{ + {Hash: &Hash{Short: "1"}, Subject: "log1"}, + {Hash: &Hash{Short: "2"}, Subject: "log2"}, + {Hash: &Hash{Short: "3"}, Subject: "log3"}, + }, + commit: &Commit{Hash: &Hash{Short: "99"}, Subject: "log1"}, + fields: []string{}, + expected: true, + expectError: assert.NoError, + }, + { + name: "nil for fields: Nothing to compare and everything is duplicated", + targetCommits: []*Commit{ + {Hash: &Hash{Short: "1"}, Subject: "log1"}, + {Hash: &Hash{Short: "2"}, Subject: "log2"}, + {Hash: &Hash{Short: "3"}, Subject: "log3"}, + }, + commit: &Commit{Hash: &Hash{Short: "99"}, Subject: "log1"}, + fields: nil, + expected: true, + expectError: assert.NoError, + }, + { + name: "bad field (error)", + targetCommits: []*Commit{ + {Hash: &Hash{Short: "1"}, Subject: "log1"}, + {Hash: &Hash{Short: "2"}, Subject: "log2"}, + {Hash: &Hash{Short: "3"}, Subject: "log3"}, + }, + commit: &Commit{Hash: &Hash{Short: "99"}, Subject: "log1"}, + fields: []string{"NoSuchField"}, + expected: false, + expectError: assert.Error, + }, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + actual, err := hasDuplicatedCommit( + test.targetCommits, + test.commit, + test.fields, + ) + test.expectError(t, err) + assert.Equal(t, test.expected, actual) + }) + } +} + +func TestIsDuplicatedCommit(t *testing.T) { + tests := []struct { + name string + commit1 *Commit + commit2 *Commit + fields []string + expected bool + expectError assert.ErrorAssertionFunc + }{ + { + name: "Duplicated for single field", + commit1: &Commit{Hash: &Hash{Short: "1"}, Subject: "log1"}, + commit2: &Commit{Hash: &Hash{Short: "2"}, Subject: "log1"}, + fields: []string{"Subject"}, + expected: true, + expectError: assert.NoError, + }, + { + name: "Not duplicted for single field", + commit1: &Commit{Hash: &Hash{Short: "1"}, Subject: "log1"}, + commit2: &Commit{Hash: &Hash{Short: "2"}, Subject: "log2"}, + fields: []string{"Subject"}, + expected: false, + expectError: assert.NoError, + }, + { + name: "Duplicated for multiple fields", + commit1: &Commit{Hash: &Hash{Short: "1"}, Scope: "chore", Subject: "log1", JiraIssueID: "FOO-1"}, + commit2: &Commit{Hash: &Hash{Short: "2"}, Scope: "chore", Subject: "log1", JiraIssueID: "FOO-1"}, + fields: []string{"Scope", "Subject", "JiraIssueID"}, + expected: true, + expectError: assert.NoError, + }, + { + name: "Not duplicted for multiple fields", + commit1: &Commit{Hash: &Hash{Short: "1"}, Scope: "chore", Subject: "log1", JiraIssueID: "FOO-1"}, + commit2: &Commit{Hash: &Hash{Short: "2"}, Scope: "chore", Subject: "log1", JiraIssueID: "FOO-2"}, + fields: []string{"Scope", "Subject", "JiraIssueID"}, + expected: false, + expectError: assert.NoError, + }, + { + name: "Nested", + commit1: &Commit{Hash: &Hash{Short: "1"}, Subject: "log1", Author: &Author{Name: "user1"}}, + commit2: &Commit{Hash: &Hash{Short: "2"}, Subject: "log2", Author: &Author{Name: "user1"}}, + fields: []string{"Author.Name"}, + expected: true, + expectError: assert.NoError, + }, + { + name: "Nested: dereference nil", + commit1: &Commit{Hash: &Hash{Short: "1"}, Subject: "log1", Author: &Author{Name: "user1"}}, + commit2: &Commit{Hash: &Hash{Short: "2"}, Subject: "log2", Author: nil}, + fields: []string{"Author.Name"}, + expected: false, + expectError: assert.NoError, + }, + { + name: "Empty fields: Nothing to compare and everything is duplicated", + commit1: &Commit{Hash: &Hash{Short: "1"}, Subject: "log1"}, + commit2: &Commit{Hash: &Hash{Short: "2"}, Subject: "log2"}, + fields: []string{}, + expected: true, + expectError: assert.NoError, + }, + { + name: "nil for fields: Nothing to compare and everything is duplicated", + commit1: &Commit{Hash: &Hash{Short: "1"}, Subject: "log1"}, + commit2: &Commit{Hash: &Hash{Short: "2"}, Subject: "log2"}, + fields: nil, + expected: true, + expectError: assert.NoError, + }, + { + name: "bad field (error)", + commit1: &Commit{Hash: &Hash{Short: "1"}, Subject: "log1"}, + commit2: &Commit{Hash: &Hash{Short: "2"}, Subject: "log2"}, + fields: []string{"NoSuchField"}, + expected: false, + expectError: assert.Error, + }, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + actual, err := isDuplicatedCommit( + test.commit1, + test.commit2, + test.fields, + ) + test.expectError(t, err) + assert.Equal(t, test.expected, actual) + }) + } +} diff --git a/utils.go b/utils.go index ccf866a3..f715c090 100644 --- a/utils.go +++ b/utils.go @@ -8,6 +8,14 @@ import ( ) func dotGet(target interface{}, prop string) (interface{}, bool) { + return dotGetImpl(target, prop, false) +} + +func dotGetNilable(target interface{}, prop string) (interface{}, bool) { + return dotGetImpl(target, prop, true) +} + +func dotGetImpl(target interface{}, prop string, nilable bool) (interface{}, bool) { path := strings.Split(prop, ".") if len(path) == 0 { @@ -18,6 +26,10 @@ func dotGet(target interface{}, prop string) (interface{}, bool) { var value reflect.Value if reflect.TypeOf(target).Kind() == reflect.Ptr { + if nilable && reflect.ValueOf(target).IsNil() { + // avoid dereferencing nil. + return nil, true + } value = reflect.ValueOf(target).Elem() } else { value = reflect.ValueOf(target) @@ -79,6 +91,8 @@ func compareString(a string, operator string, b string) bool { return a < b case ">": return a > b + case "==": + return a == b default: return false } @@ -90,6 +104,8 @@ func compareInt(a int, operator string, b int) bool { return a < b case ">": return a > b + case "==": + return a == b default: return false } @@ -101,6 +117,8 @@ func compareTime(a time.Time, operator string, b time.Time) bool { return !a.After(b) case ">": return a.After(b) + case "==": + return a.Equal(b) default: return false } diff --git a/utils_test.go b/utils_test.go index 5afbd060..9389b2fe 100644 --- a/utils_test.go +++ b/utils_test.go @@ -81,6 +81,27 @@ func TestDotGet(t *testing.T) { assert.Nil(val) } +func TestDotGetNilable(t *testing.T) { + assert := assert.New(t) + + type Nest struct { + Str string + } + + type Sample struct { + Nest *Nest + } + + sample := Sample{ + Nest: nil, + } + + // Dereferencing nil + val, ok := dotGetNilable(&sample, "Nest.Str") + assert.True(ok) + assert.Equal(val, nil) +} + func TestCompare(t *testing.T) { assert := assert.New(t) @@ -96,10 +117,16 @@ func TestCompare(t *testing.T) { {0, ">", 1, false}, {1, ">", 0, true}, {1, "<", 0, false}, + {0, "==", 1, false}, + {1, "==", 1, true}, {"a", "<", "b", true}, {"a", ">", "b", false}, + {"a", "==", "b", false}, + {"b", "==", "b", true}, {time.Unix(1518018017, 0), "<", time.Unix(1518018043, 0), true}, {time.Unix(1518018017, 0), ">", time.Unix(1518018043, 0), false}, + {time.Unix(1518018017, 0), "==", time.Unix(1518018043, 0), false}, + {time.Unix(1518018043, 0), "==", time.Unix(1518018043, 0), true}, } for _, sa := range table {