From b923d7fc679901d9724cdd9ba4450e8eea448168 Mon Sep 17 00:00:00 2001 From: Paul Buetow Date: Sat, 31 Aug 2024 10:55:05 +0300 Subject: refactored entry.Shared to be a map --- internal/server/repository/repository_test.go | 28 ++++--- internal/types/entry.go | 95 ++++++++++-------------- internal/types/entry_test.go | 102 +++++++++++++++++--------- 3 files changed, 120 insertions(+), 105 deletions(-) diff --git a/internal/server/repository/repository_test.go b/internal/server/repository/repository_test.go index b4eb0c2..72bc52d 100644 --- a/internal/server/repository/repository_test.go +++ b/internal/server/repository/repository_test.go @@ -251,12 +251,16 @@ func TestRepositoryMergeFromPartner(t *testing.T) { } // Validate the correct test setup - if ent.Shared[1].Name != "LinkedIn" || ent.Shared[1].Is != false { - t.Error("for the test expected LinkedIn not to be shared", ent.Shared[1]) + if ent.IsShared("LinkedIn") { + t.Error("for the test expected LinkedIn not to be shared") } // Simulate that the entry was shared to LinkedIn social media! - ent.Shared[1].Is = true + linkedIn, ok := ent.Shared["LinkedIn"] + if !ok { + t.Error("expected to have a LinkedIn shared entry") + } + linkedIn.Is = true if err := repo1.Update(ent); err != nil { t.Error(err) } @@ -304,10 +308,10 @@ func makeAnEntry() (types.Entry, error) { entry := ` { "Body": "Body text here", - "Shared": [ - { "Name": "Mastodon", "Is": true }, - { "Name": "LinkedIn", "Is": false } - ] + "Shared": { + "Mastodon": { "Is": true }, + "LinkedIn": { "Is": false } + } } ` return types.NewEntry([]byte(entry)) @@ -317,11 +321,11 @@ func makeAnotherEntry() (types.Entry, error) { entry := ` { "Body": "Another text here", - "Shared": [ - { "Name": "Mastodon", "Is": true }, - { "Name": "LinkedIn", "Is": true }, - { "Name": "foo.zone", "Is": false } - ] + "Shared": { + "Mastodon": { "Is": true }, + "LinkedIn": { "Is": true }, + "foo.zone": { "Is": false } + } } ` return types.NewEntry([]byte(entry)) diff --git a/internal/types/entry.go b/internal/types/entry.go index 6ac3533..96efbc5 100644 --- a/internal/types/entry.go +++ b/internal/types/entry.go @@ -4,36 +4,22 @@ import ( "crypto/sha256" "encoding/json" "fmt" + "maps" "os" + "sort" "strings" - "sync" ) -// Tells me whether the entry was shared to the sm platform named Name -type Shared struct { - Name string `json:"name"` - Is bool `json:"is,omitempty"` -} - -func (s Shared) String() string { - return fmt.Sprintf("Name:%s;Is:%v", s.Name, s.Is) -} - -func (s Shared) Equals(other Shared) bool { - return s.Name == other.Name && s.Is == other.Is -} - type Entry struct { // The unique ID of this entry. - ID string `json:"id,omitempty"` - Body string `json:"body"` - Shared []Shared `json:"shared,omitempty"` - Epoch int `json:"epoch,omitempty"` + ID string `json:"id,omitempty"` + Body string `json:"body"` + Shared map[string]Shared `json:"shared,omitempty"` + Epoch int `json:"epoch,omitempty"` // The checksum of the whole entry, can change depending on the state. checksum string checksumDirty bool - mu *sync.Mutex } func NewEntry(bytes []byte) (Entry, error) { @@ -53,9 +39,7 @@ func NewEntry(bytes []byte) (Entry, error) { func NewEntryFromCopy(other Entry) (Entry, error) { e := other e.initialize() - - e.Shared = make([]Shared, len(other.Shared)) - copy(e.Shared, other.Shared) + e.Shared = maps.Clone(other.Shared) return e, nil } @@ -80,7 +64,9 @@ func NewEntryFromTextFile(filePath string) (Entry, error) { } func (e *Entry) initialize() { - e.mu = &sync.Mutex{} + if e.Shared == nil { + e.Shared = make(map[string]Shared) + } e.checksumDirty = true } @@ -92,23 +78,19 @@ func (e Entry) Equals(other Entry) bool { return false case e.ID != other.ID: return false - case len(e.Shared) != len(other.Shared): - return false + // case len(e.Shared) != len(other.Shared): + // return false } - otherShared := make(map[string]Shared) - for _, shared := range other.Shared { - otherShared[shared.Name] = shared - } + return maps.Equal(e.Shared, other.Shared) +} - for _, shared := range e.Shared { - otherShared, ok := otherShared[shared.Name] - if !ok || !shared.Equals(otherShared) { - return false - } +func (e Entry) IsShared(name string) bool { + shared, ok := e.Shared[name] + if !ok { + return false } - - return true + return shared.Is } /** @@ -133,29 +115,19 @@ func (e Entry) Update(other Entry) (Entry, bool, error) { changed = true } - sharedMap := make(map[string]Shared) - for _, shared := range e.Shared { - sharedMap[shared.Name] = shared - } - - for _, otherShared := range other.Shared { - shared, ok := sharedMap[otherShared.Name] + for otherName, otherShared := range other.Shared { + shared, ok := e.Shared[otherName] switch { case !ok: - sharedMap[otherShared.Name] = shared + e.Shared[otherName] = shared changed = true case otherShared.Is && !shared.Is: shared.Is = true - sharedMap[otherShared.Name] = shared + e.Shared[otherName] = shared changed = true } } - e.Shared = e.Shared[:0] - for _, shared := range sharedMap { - e.Shared = append(e.Shared, shared) - } - if changed { e.checksumDirty = true } @@ -182,14 +154,26 @@ func (e Entry) checksumBase() string { sb.WriteString(e.ID) sb.WriteString(";") sb.WriteString(fmt.Sprintf("Epoch:%d;", e.Epoch)) - sb.WriteString("Shared:[") - for i, shared := range e.Shared { + sb.WriteString("Shared:{") + + keys := make([]string, 0, len(e.Shared)) + for key := range e.Shared { + keys = append(keys, key) + } + sort.Strings(keys) + + for i, sharedName := range keys { if i > 0 { sb.WriteString(",") } + shared := e.Shared[sharedName] + sb.WriteString(sharedName) + sb.WriteString(":{") sb.WriteString(shared.String()) + sb.WriteString("}") } - sb.WriteString("];") + + sb.WriteString("};") sb.WriteString("Body:") sb.WriteString(e.Body) @@ -197,9 +181,6 @@ func (e Entry) checksumBase() string { } func (e *Entry) Checksum() string { - e.mu.Lock() - defer e.mu.Unlock() - if !e.checksumDirty { return e.checksum } diff --git a/internal/types/entry_test.go b/internal/types/entry_test.go index a403928..fe0a0cd 100644 --- a/internal/types/entry_test.go +++ b/internal/types/entry_test.go @@ -1,6 +1,62 @@ package types -import "testing" +import ( + "testing" +) + +func oneEntry() (Entry, error) { + ent := ` + { + "body": "Body text here", + "shared": { + "Foo": { "Is": true }, + "Bar": { "Is": false } + } + } + ` + return NewEntry([]byte(ent)) +} + +func anotherEntry() (Entry, error) { + ent := ` + { + "body": "Body text here", + "shared": { + "Foo": { "Is": true }, + "Bar": { "Is": true }, + "Baz": { "Is": false } + } + } + ` + return NewEntry([]byte(ent)) +} + +func twoDifferentEntries() (ent1, ent2 Entry, err error) { + if ent1, err = oneEntry(); err != nil { + return + } + ent2, err = anotherEntry() + return +} + +func TestNewEntryFromJSON(t *testing.T) { + ent1, err := oneEntry() + if err != nil { + t.Error(err) + return + } + + t.Log("ent1", ent1) + if len(ent1.Shared) != 2 { + t.Error("expected to have two shared entries in ent1") + } + if !ent1.IsShared("Foo") { + t.Error("Foo should be shared") + } + if ent1.IsShared("Bar") { + t.Error("Bar should not be shared") + } +} func TestEntryChecksum(t *testing.T) { t.Parallel() @@ -11,7 +67,7 @@ func TestEntryChecksum(t *testing.T) { return } - expected := "e139c0788fbc0d9cce370e4918c1cbc8862184d9461bd1238c02b7f80cb042fe" + expected := "4dbd4f04d7917b1f1bd0807cf39a260efe51085d49b40469fca27b7f89cc73bd" got := ent.Checksum() if expected != got { @@ -64,7 +120,10 @@ func TestUpdate(t *testing.T) { } var changed bool - ent1, changed, _ = ent1.Update(ent2) + if ent1, changed, err = ent1.Update(ent2); err != nil { + t.Error(err) + } + if len(ent1.Shared) != 3 { t.Error("expected 3 entries after update", ent1) } @@ -73,43 +132,14 @@ func TestUpdate(t *testing.T) { t.Error("expected the entry to be changed after update") } - var isShared int + var sharedCount int for _, shared := range ent1.Shared { if shared.Is { - isShared++ + sharedCount++ } } - if isShared != 2 { - t.Error("expected 2 shared entries after update but got", isShared, ent1) + if sharedCount != 2 { + t.Error("expected 2 shared entries after update but got", sharedCount, ent1) } } - -func twoDifferentEntries() (ent1, ent2 Entry, err error) { - ent1Str := ` - { - "Body": "Body text here", - "Shared": [ - { "Name": "Foo", "Is": true }, - { "Name": "Bar", "Is": false } - ] - } - ` - ent1, err = NewEntry([]byte(ent1Str)) - if err != nil { - return - } - - ent2Str := ` - { - "Body": "Body text here", - "Shared": [ - { "Name": "Foo", "Is": true }, - { "Name": "Bar", "Is": true }, - { "Name": "Baz", "Is": false } - ] - } - ` - ent2, err = NewEntry([]byte(ent2Str)) - return -} -- cgit v1.2.3