From e8fb298ea5764de04a9aea10b9d3ca496c93e52b Mon Sep 17 00:00:00 2001 From: Dan Jones Date: Sun, 28 Jan 2024 01:13:25 -0600 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20Entry=20with=20TextMarshaler?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- models/entry.go | 71 +++++++++++++++++++++++++++++++++++ models/entry_test.go | 89 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 160 insertions(+) create mode 100644 models/entry_test.go diff --git a/models/entry.go b/models/entry.go index 2640e7f..09461e4 100644 --- a/models/entry.go +++ b/models/entry.go @@ -1 +1,72 @@ package models + +import ( + "bytes" + "errors" + "strings" + "sync" + "time" +) + +const DateFormat = "January 02, 2006 at 03:04:05PM -0700" + +type Entry struct { + Title string + Date time.Time + Fields []Meta +} + +type metaRes struct { + out []byte + err error +} + +func (e Entry) getFieldMarshalChan() chan metaRes { + size := len(e.Fields) + ch := make(chan metaRes, size) + var wg sync.WaitGroup + + // @todo figure out a way to handle json field + for i := 0; i < size; i++ { + wg.Add(1) + go func(i int) { + defer wg.Done() + o, er := e.Fields[i].MarshalText() + ch <- metaRes{o, er} + + }(i) + } + + go func() { + wg.Wait() + close(ch) + }() + return ch +} + +func (e Entry) MarshalText() ([]byte, error) { + e.Title = strings.TrimSpace(e.Title) + if e.Title == "" { + return []byte{}, errors.New("Empty title") + } + if e.Date == (time.Time{}) { + return []byte{}, errors.New("Empty date") + } + ch := e.getFieldMarshalChan() + buff := &bytes.Buffer{} + buff.WriteString("@begin ") + buff.WriteString(e.Date.Format(DateFormat)) + buff.WriteString(" - ") + buff.WriteString(e.Title) + + for res := range ch { + if res.err == nil && len(res.out) > 0 { + buff.WriteString("\n") + buff.Write(res.out) + } + } + + buff.WriteString(" @end") + + return buff.Bytes(), nil +} diff --git a/models/entry_test.go b/models/entry_test.go new file mode 100644 index 0000000..146e9d3 --- /dev/null +++ b/models/entry_test.go @@ -0,0 +1,89 @@ +package models + +import ( + "encoding" + //"encoding/json" + "errors" + "testing" + "time" + + "github.com/stretchr/testify/assert" +) + +// Type assertions +var _ encoding.TextMarshaler = Entry{} + +func TestEntry(t *testing.T) { + when := time.Now() + whens := when.Format(DateFormat) + simple := []Meta{} + nolines := []string{} + tests := []struct { + name string + title string + date time.Time + fields []Meta + first string + lines []string + err error + }{ + {"no-title", "", when, simple, "", nolines, errors.New("Empty title")}, + {"zero-date", "Empty title", time.Time{}, simple, "", nolines, errors.New("Empty date")}, + {"one-line", "A Title", when, simple, "@begin " + whens + " - A Title @end", nolines, nil}, + { + "one-field", + "Title 2", + when, + []Meta{{"age", 41}}, + "@begin " + whens + " - Title 2", + []string{"@age 41 @end"}, + nil, + }, + { + "three-fields", + "Title 3", + when, + []Meta{{"age", 41}, {"cool", true}, {"name", "Jim"}}, + "@begin " + whens + " - Title 3", + []string{"@age 41", "@cool true", "@name Jim"}, + nil, + }, + /* uncomment when implemented + { + "json-field", + "Title J", + when, + []Meta{{"json", json.RawMessage(`{"age": 41, "cool": true, "name": "Jim"}`)}}, + "@begin " + whens + " - Title J", + []string{"@age 41", "@cool true", "@name Jim"}, + nil, + }, + */ + } + + for _, tt := range tests { + t.Run(tt.name, getEntryTestRunner(tt.title, tt.date, tt.fields, tt.first, tt.lines, tt.err)) + } + +} + +func getEntryTestRunner(title string, date time.Time, fields []Meta, first string, lines []string, err error) func(*testing.T) { + return func(t *testing.T) { + en := Entry{title, date, fields} + o, er := en.MarshalText() + assert.Equal(t, err, er) + if first == "" { + return + } + if len(lines) == 0 { + assert.Equal(t, first, string(o)) + return + } + + os := string(o) + assert.Regexp(t, "^"+first, os) + for _, line := range lines { + assert.Regexp(t, "(?m)^"+line, os) + } + } +}