diff --git a/AGENTS.md b/AGENTS.md index c10b6e7..61c9bf1 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -15,7 +15,7 @@ - **Types**: Use explicit types (e.g., `int64`, `float64`). Convert numbers appropriately when unmarshaling JSON - **Naming**: PascalCase for exported, camelCase for unexported. Use descriptive names - **Error handling**: Return wrapped errors with context. Define custom errors in models/errors.go. Use `ErrorIs` for error checking -- **Testing**: Use testify/assert. Table-driven tests with helper functions. Test both marshal/unmarshal for encoding types +- **Testing**: Use github.com/nalgeon/be. Table-driven tests with helper functions. Test both marshal/unmarshal for encoding types - **Concurrency**: Use channels and goroutines with WaitGroups for parallel processing (see entry.go patterns) - **Comments**: Include license header on cmd files. Document exported functions and types diff --git a/CHANGELOG.md b/CHANGELOG.md index 22bb4c0..f44599a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.0.11] - 2026-02-13 + +- ✨ Add support for mixed-level nested keys with dot/blank handling +- ✨ Refactor append_test to use standalone test functions +- ✨ Migrate from testify to nalgeon/be testing library +- ✨ Add bep.JSON helper for JSON assertion in tests + ## [0.0.10] - 2026-02-10 - ✨ Implement full support for nested fields in Meta and Entry marshalling diff --git a/config/default_test.go b/config/default_test.go index 6b6ab33..58e0fee 100644 --- a/config/default_test.go +++ b/config/default_test.go @@ -5,14 +5,13 @@ import ( fp "path/filepath" "testing" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" + "github.com/nalgeon/be" ) func TestDefaultConfig(t *testing.T) { home, _ := os.UserHomeDir() inDir := fp.Join(home, "my-log") c, err := DefaultConfig() - require.NoError(t, err) - assert.Equal(t, inDir, c.Input.Path) + be.Err(t, err, nil) + be.Equal(t, c.Input.Path, inDir) } diff --git a/config/load_test.go b/config/load_test.go index eab7c94..0306db5 100644 --- a/config/load_test.go +++ b/config/load_test.go @@ -5,8 +5,7 @@ import ( "os" "testing" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" + "github.com/nalgeon/be" ) func TestLoad(t *testing.T) { @@ -16,8 +15,8 @@ func TestLoad(t *testing.T) { fmt.Fprint(f, `[input] ext = "log"`) c, err := Load() - require.NoError(t, err) - assert.Equal(t, "log", c.Input.Ext) + be.Err(t, err, nil) + be.Equal(t, c.Input.Ext, "log") } func TestLoadBadFile(t *testing.T) { @@ -26,15 +25,15 @@ func TestLoadBadFile(t *testing.T) { defer f.Close() fmt.Fprint(f, `{"not":"toml"}`) _, err := Load() - assert.Error(t, err) + be.Err(t, err) } func TestLoadIgnoreMissingFile(t *testing.T) { def, _ := DefaultConfig() ConfigPath = "/not/a/real/file" c, err := Load() - require.NoError(t, err) - assert.Equal(t, def, c) + be.Err(t, err, nil) + be.Equal(t, c, def) } func TestOverride(t *testing.T) { @@ -43,30 +42,30 @@ func TestOverride(t *testing.T) { "input.ext": "~", } c, err := Load() - require.NoError(t, err) - assert.Equal(t, Overrides["input.path"], c.Input.Path) - assert.Equal(t, "txt", c.Input.Ext) + be.Err(t, err, nil) + be.Equal(t, c.Input.Path, Overrides["input.path"]) + be.Equal(t, c.Input.Ext, "txt") } func TestOverrideJson(t *testing.T) { Overrides = map[string]string{"input.ext": `{"a":"b"}`} c, err := Load() - require.NoError(t, err) - assert.Equal(t, "txt", c.Input.Ext) + be.Err(t, err, nil) + be.Equal(t, c.Input.Ext, "txt") } func TestTimeParse(t *testing.T) { Overrides = map[string]string{"input.ext": "now"} c, err := Load() - assert.ErrorContains(t, err, "incompatible types: TOML value has type time.Time; destination has type string") - assert.Equal(t, "txt", c.Input.Ext) + be.Err(t, err, "incompatible types: TOML value has type time.Time; destination has type string") + be.Equal(t, c.Input.Ext, "txt") } func TestStdoutMissing(t *testing.T) { var oo Outputs = map[string]Output{} std, en := oo.Stdout() - assert.False(t, en) - assert.Equal(t, Stdout{}, std) + be.True(t, !en) + be.Equal(t, std, Stdout{}) } func TestStdoutLoad(t *testing.T) { @@ -76,8 +75,8 @@ func TestStdoutLoad(t *testing.T) { defer os.Unsetenv("LOG_STDOUT_ENABLED") c, _ := Load() std, en := c.Outputs.Stdout() - assert.True(t, en) - assert.Equal(t, "json", std.Format) + be.True(t, en) + be.Equal(t, std.Format, "json") } func TestFormatJson(t *testing.T) { @@ -86,9 +85,9 @@ func TestFormatJson(t *testing.T) { } js := ff.Json() - assert.True(t, js.PrettyPrint) + be.True(t, js.PrettyPrint) ff = Formatters{} js = ff.Json() - assert.False(t, js.PrettyPrint) + be.True(t, !js.PrettyPrint) } diff --git a/files/append_test.go b/files/append_test.go index 1d6d16f..4916888 100644 --- a/files/append_test.go +++ b/files/append_test.go @@ -3,37 +3,47 @@ package files import ( "fmt" "os" + "strings" "testing" "time" "codeberg.org/danjones000/my-log/config" "codeberg.org/danjones000/my-log/models" - "github.com/stretchr/testify/suite" + "github.com/nalgeon/be" ) -func TestAppend(t *testing.T) { - suite.Run(t, new(AppendTestSuite)) +func TestAppend(tt *testing.T) { + tt.Run("success", func(t *testing.T) { + t.Run("single", appendTestSingle) + t.Run("two", appendTestTwoEntries) + t.Run("new_line", appendTestAddNewLine) + t.Run("no-new-line", appendTestDontAddNewLine) + t.Run("dot-folder", appendTestDotFolder) + t.Run("no-dot-folder", appendTestDotFolderNo) + t.Run("no-ext", appendTestNoExt) + }) + tt.Run("failure", func(t *testing.T) { + t.Run("badEntry", appendTestBadEntry) + t.Run("load-err", appendTestConfLoadErr) + t.Run("mkdir-err", appendTestMkdirErr) + t.Run("append-log-err", appendTestOpenErr) + }) } -type AppendTestSuite struct { - suite.Suite - dir string -} - -func (s *AppendTestSuite) SetupSuite() { - s.dir, _ = os.MkdirTemp("", "append-test") - config.Overrides["input.path"] = s.dir +func setupAppendTest(t *testing.T) string { + t.Helper() + dir := t.ArtifactDir() + config.Overrides["input.path"] = dir config.Overrides["input.ext"] = "log" + t.Cleanup(func() { + delete(config.Overrides, "input.path") + delete(config.Overrides, "input.ext") + }) + return dir } -func (s *AppendTestSuite) TearDownSuite() { - os.RemoveAll(s.dir) - delete(config.Overrides, "input.path") - delete(config.Overrides, "input.ext") -} - -func (s *AppendTestSuite) TestSuccess() { - defer os.Remove(s.dir + "/test.log") +func appendTestSingle(t *testing.T) { + dir := setupAppendTest(t) when := time.Now().Local() e := models.Entry{ Title: "Jimmy", @@ -48,18 +58,17 @@ func (s *AppendTestSuite) TestSuccess() { Entries: []models.Entry{e}, } err := Append(l) - s.Require().NoError(err) - s.Require().FileExists(s.dir + "/test.log") - by, err := os.ReadFile(s.dir + "/test.log") + be.Err(t, err, nil) + by, err := os.ReadFile(dir + "/test.log") + be.Err(t, err, nil) st := string(by) - s.Require().NoError(err) - s.Assert().Contains(st, "Jimmy\n") - s.Assert().Contains(st, "\n@foo 42") - s.Assert().Contains(st, "\n@bar true") + be.True(t, strings.Contains(st, "Jimmy\n")) + be.True(t, strings.Contains(st, "\n@foo 42")) + be.True(t, strings.Contains(st, "\n@bar true")) } -func (s *AppendTestSuite) TestTwoEntries() { - defer os.Remove(s.dir + "/test.log") +func appendTestTwoEntries(t *testing.T) { + dir := setupAppendTest(t) when := time.Now().Local() whens := when.Format(models.DateFormat) e := []models.Entry{ @@ -71,17 +80,16 @@ func (s *AppendTestSuite) TestTwoEntries() { Entries: e, } err := Append(l) - s.Assert().NoError(err) - s.Require().FileExists(s.dir + "/test.log") - by, _ := os.ReadFile(s.dir + "/test.log") + be.Err(t, err, nil) + by, _ := os.ReadFile(dir + "/test.log") st := string(by) - s.Assert().Contains(st, fmt.Sprintf("@begin %s - one", whens)) - s.Assert().Contains(st, fmt.Sprintf("@begin %s - two", whens)) + be.True(t, strings.Contains(st, fmt.Sprintf("@begin %s - one", whens))) + be.True(t, strings.Contains(st, fmt.Sprintf("@begin %s - two", whens))) } -func (s *AppendTestSuite) TestAddNewLine() { - defer os.Remove(s.dir + "/test.log") - os.WriteFile(s.dir+"/test.log", []byte("foo"), 0644) +func appendTestAddNewLine(t *testing.T) { + dir := setupAppendTest(t) + os.WriteFile(dir+"/test.log", []byte("foo"), 0644) when := time.Now().Local() whens := when.Format(models.DateFormat) e := []models.Entry{ @@ -92,16 +100,15 @@ func (s *AppendTestSuite) TestAddNewLine() { Entries: e, } err := Append(l) - s.Assert().NoError(err) - s.Require().FileExists(s.dir + "/test.log") - by, _ := os.ReadFile(s.dir + "/test.log") + be.Err(t, err, nil) + by, _ := os.ReadFile(dir + "/test.log") exp := fmt.Sprintf("foo\n@begin %s - one\n@id jimmy @end\n", whens) - s.Assert().Equal(exp, string(by)) + be.Equal(t, string(by), exp) } -func (s *AppendTestSuite) TestDontAddNewLine() { - defer os.Remove(s.dir + "/test.log") - os.WriteFile(s.dir+"/test.log", []byte("foo\n"), 0644) +func appendTestDontAddNewLine(t *testing.T) { + dir := setupAppendTest(t) + os.WriteFile(dir+"/test.log", []byte("foo\n"), 0644) when := time.Now().Local() whens := when.Format(models.DateFormat) e := []models.Entry{ @@ -112,15 +119,14 @@ func (s *AppendTestSuite) TestDontAddNewLine() { Entries: e, } err := Append(l) - s.Assert().NoError(err) - s.Require().FileExists(s.dir + "/test.log") - by, _ := os.ReadFile(s.dir + "/test.log") + be.Err(t, err, nil) + by, _ := os.ReadFile(dir + "/test.log") exp := fmt.Sprintf("foo\n@begin %s - one\n@id jimmy @end\n", whens) - s.Assert().Equal(exp, string(by)) + be.Equal(t, string(by), exp) } -func (s *AppendTestSuite) TestFailEntry() { - defer os.Remove(s.dir + "/test.log") +func appendTestBadEntry(t *testing.T) { + dir := setupAppendTest(t) e := models.Entry{ Title: "Jimmy", } @@ -129,14 +135,18 @@ func (s *AppendTestSuite) TestFailEntry() { Entries: []models.Entry{e}, } err := Append(l) - s.Assert().NoError(err) - s.Require().FileExists(s.dir + "/test.log") - by, _ := os.ReadFile(s.dir + "/test.log") - s.Assert().Equal([]byte{}, by) + be.Err(t, err, nil) + by, _ := os.ReadFile(dir + "/test.log") + be.Equal(t, by, []byte{}) } -func (s *AppendTestSuite) TestDotFolder() { +func appendTestDotFolder(t *testing.T) { config.Overrides["input.dotFolder"] = "true" + t.Cleanup(func() { + delete(config.Overrides, "input.dotFolder") + }) + + dir := setupAppendTest(t) e := models.Entry{ Title: "something", Date: time.Now(), @@ -146,16 +156,20 @@ func (s *AppendTestSuite) TestDotFolder() { Entries: []models.Entry{e}, } err := Append(l) - s.Require().NoError(err) - s.Require().FileExists(s.dir + "/sub/test.log") - by, err := os.ReadFile(s.dir + "/sub/test.log") + be.Err(t, err, nil) + by, err := os.ReadFile(dir + "/sub/test.log") + be.Err(t, err, nil) st := string(by) - s.Require().NoError(err) - s.Assert().Contains(st, fmt.Sprintf("@begin %s - %s", e.Date.Format(models.DateFormat), e.Title)) + be.True(t, strings.Contains(st, fmt.Sprintf("@begin %s - %s", e.Date.Format(models.DateFormat), e.Title))) } -func (s *AppendTestSuite) TestDotFolderNo() { +func appendTestDotFolderNo(t *testing.T) { config.Overrides["input.dotFolder"] = "false" + t.Cleanup(func() { + delete(config.Overrides, "input.dotFolder") + }) + + dir := setupAppendTest(t) e := models.Entry{ Title: "another", Date: time.Now(), @@ -165,19 +179,20 @@ func (s *AppendTestSuite) TestDotFolderNo() { Entries: []models.Entry{e}, } err := Append(l) - s.Require().NoError(err) - s.Require().FileExists(s.dir + "/sub.test.log") - by, err := os.ReadFile(s.dir + "/sub.test.log") + be.Err(t, err, nil) + by, err := os.ReadFile(dir + "/sub.test.log") + be.Err(t, err, nil) st := string(by) - s.Require().NoError(err) - s.Assert().Contains(st, fmt.Sprintf("@begin %s - %s", e.Date.Format(models.DateFormat), e.Title)) + be.True(t, strings.Contains(st, fmt.Sprintf("@begin %s - %s", e.Date.Format(models.DateFormat), e.Title))) } -func (s *AppendTestSuite) TestNoExt() { +func appendTestNoExt(t *testing.T) { + dir := setupAppendTest(t) config.Overrides["input.ext"] = "" - defer func() { + t.Cleanup(func() { config.Overrides["input.ext"] = "log" - }() + }) + e := models.Entry{ Title: "baz", Date: time.Now(), @@ -187,48 +202,48 @@ func (s *AppendTestSuite) TestNoExt() { Entries: []models.Entry{e}, } err := Append(l) - s.Require().NoError(err) - s.Require().FileExists(s.dir + "/foobar") - by, err := os.ReadFile(s.dir + "/foobar") + be.Err(t, err, nil) + by, err := os.ReadFile(dir + "/foobar") + be.Err(t, err, nil) st := string(by) - s.Require().NoError(err) - s.Assert().Contains(st, fmt.Sprintf("@begin %s - %s", e.Date.Format(models.DateFormat), e.Title)) + be.True(t, strings.Contains(st, fmt.Sprintf("@begin %s - %s", e.Date.Format(models.DateFormat), e.Title))) } -func (s *AppendTestSuite) TestConfLoadErr() { +func appendTestConfLoadErr(t *testing.T) { + dir := t.ArtifactDir() + currConf := config.ConfigPath - tmp, _ := os.CreateTemp("", "app-conf-*.toml") + tmp, _ := os.CreateTemp(dir, "app-conf-*.toml") fname := tmp.Name() - defer tmp.Close() - defer os.Remove(fname) + t.Cleanup(func() { tmp.Close() }) + t.Cleanup(func() { os.Remove(fname) }) fmt.Fprintln(tmp, `{"not":"toml"}`) config.ConfigPath = fname - defer func(path string) { - config.ConfigPath = path - }(currConf) + t.Cleanup(func() { config.ConfigPath = currConf }) + err := Append(models.Log{}) - s.Assert().ErrorContains(err, "toml") + be.Err(t, err, "toml") } -func (s *AppendTestSuite) TestMkdirErr() { +func appendTestMkdirErr(t *testing.T) { // Don't run this test as root config.Overrides["input.path"] = "/var/my-logs-test" - defer func(path string) { - config.Overrides["input.path"] = path - }(s.dir) + t.Cleanup(func() { delete(config.Overrides, "input.path") }) + err := Append(models.Log{}) - s.Assert().ErrorContains(err, "permission denied") + be.Err(t, err, "permission denied") } -func (s *AppendTestSuite) TestOpenErr() { +func appendTestOpenErr(t *testing.T) { + dir := setupAppendTest(t) l := models.Log{ Name: "test-open-err", } - fname := s.dir + "/test-open-err.log" - os.MkdirAll(s.dir, 0750) + fname := dir + "/test-open-err.log" + os.MkdirAll(dir, 0750) f, _ := os.Create(fname) f.Close() - os.Chmod(fname, 0400) // read only + os.Chmod(fname, 0400) err := Append(l) - s.Assert().ErrorContains(err, "permission denied") + be.Err(t, err, "permission denied") } diff --git a/formatters/json_test.go b/formatters/json_test.go index da6f111..8139369 100644 --- a/formatters/json_test.go +++ b/formatters/json_test.go @@ -5,13 +5,14 @@ import ( "testing" "time" + "codeberg.org/danjones000/my-log/internal/testutil/bep" "codeberg.org/danjones000/my-log/models" - "github.com/stretchr/testify/assert" + "github.com/nalgeon/be" ) func TestJsonName(t *testing.T) { f, _ := New("json") - assert.Equal(t, "json", f.Name()) + be.Equal(t, f.Name(), "json") } func TestJsonMeta(t *testing.T) { @@ -19,8 +20,8 @@ func TestJsonMeta(t *testing.T) { m := models.Meta{"foo", 42} exp := `{"foo":42}` o, err := f.Meta(m) - assert.NoError(t, err) - assert.JSONEq(t, exp, string(o)) + be.Err(t, err, nil) + bep.JSON(t, o, []byte(exp)) } func TestJsonEntry(t *testing.T) { @@ -34,8 +35,8 @@ func TestJsonEntry(t *testing.T) { } exp := fmt.Sprintf(`{"title":"%s","date":"%s","foo":42}`, e.Title, when.Format(time.RFC3339)) o, err := f.Entry(e) - assert.NoError(t, err) - assert.JSONEq(t, exp, string(o)) + be.Err(t, err, nil) + bep.JSON(t, o, []byte(exp)) } func TestJsonLog(t *testing.T) { @@ -50,24 +51,24 @@ func TestJsonLog(t *testing.T) { l := models.Log{"stuff", []models.Entry{e}} exp := fmt.Sprintf(`{"%s":[{"title":"%s","date":"%s","foo":42}]}`, l.Name, e.Title, when.Format(time.RFC3339)) o, err := f.Log(l) - assert.NoError(t, err) - assert.JSONEq(t, exp, string(o)) + be.Err(t, err, nil) + bep.JSON(t, o, []byte(exp)) } func TestJsonNoLogs(t *testing.T) { f, _ := New("json") o, err := f.Logs([]models.Log{}) var exp []byte - assert.NoError(t, err) - assert.Equal(t, exp, o) + be.Err(t, err, nil) + be.Equal(t, o, exp) } func TestJsonErr(t *testing.T) { f, _ := New("json") o, err := f.Meta(models.Meta{"foo", make(chan bool)}) var exp []byte - assert.Error(t, err) - assert.Equal(t, exp, o) + be.Err(t, err) + be.Equal(t, o, exp) } func TestJsonPretty(t *testing.T) { @@ -76,6 +77,6 @@ func TestJsonPretty(t *testing.T) { exp := `{ "foo": 42 }` - assert.NoError(t, err) - assert.Equal(t, exp, string(o)) + be.Err(t, err, nil) + be.Equal(t, string(o), exp) } diff --git a/formatters/new_test.go b/formatters/new_test.go index ed56be3..00f4727 100644 --- a/formatters/new_test.go +++ b/formatters/new_test.go @@ -3,20 +3,24 @@ package formatters import ( "fmt" "os" + "slices" "testing" "codeberg.org/danjones000/my-log/config" - "github.com/stretchr/testify/assert" + "github.com/nalgeon/be" ) func TestKinds(t *testing.T) { - assert.ElementsMatch(t, []string{"plain", "json", "zero"}, Kinds()) + kinds := Kinds() + for _, kind := range []string{"plain", "json", "zero"} { + be.True(t, slices.Contains(kinds, kind)) + } } func TestNewUnsupported(t *testing.T) { f, err := New("nope") - assert.Nil(t, f) - assert.Error(t, err) + be.Equal(t, f, nil) + be.Err(t, err) } func TestNewCantGetConfig(t *testing.T) { @@ -30,16 +34,16 @@ func TestNewCantGetConfig(t *testing.T) { fmt.Fprint(f, `{"not":"toml"}`) form, err := New("plain") - assert.Nil(t, form) - assert.Error(t, err) + be.Equal(t, form, nil) + be.Err(t, err) form, err = Preferred() - assert.Nil(t, form) - assert.Error(t, err) + be.Equal(t, form, nil) + be.Err(t, err) } func TestPreferred(t *testing.T) { form, err := Preferred() - assert.NotNil(t, form) - assert.NoError(t, err) + be.Err(t, err, nil) + be.True(t, form != nil) } diff --git a/formatters/null_test.go b/formatters/null_test.go index f7c26c1..587b4e5 100644 --- a/formatters/null_test.go +++ b/formatters/null_test.go @@ -5,41 +5,41 @@ import ( "time" "codeberg.org/danjones000/my-log/models" - "github.com/stretchr/testify/assert" + "github.com/nalgeon/be" ) var empty []byte func TestNullName(t *testing.T) { f, err := New("zero") - assert.NoError(t, err) - assert.Equal(t, "zero", f.Name()) + be.Err(t, err, nil) + be.Equal(t, f.Name(), "zero") } func TestNullMeta(t *testing.T) { f, _ := New("zero") o, err := f.Meta(models.Meta{"foo", 42}) - assert.NoError(t, err) - assert.Equal(t, empty, o) + be.Err(t, err, nil) + be.Equal(t, o, empty) } func TestNullEntry(t *testing.T) { f, _ := New("zero") o, err := f.Entry(models.Entry{"title", time.Now(), models.Metas{}}) - assert.NoError(t, err) - assert.Equal(t, empty, o) + be.Err(t, err, nil) + be.Equal(t, o, empty) } func TestNullLog(t *testing.T) { f, _ := New("zero") o, err := f.Log(models.Log{"jim", []models.Entry{{"title", time.Now(), models.Metas{}}}}) - assert.NoError(t, err) - assert.Equal(t, empty, o) + be.Err(t, err, nil) + be.Equal(t, o, empty) } func TestNullLogs(t *testing.T) { f, _ := New("zero") o, err := f.Logs([]models.Log{{"jim", []models.Entry{{"title", time.Now(), models.Metas{}}}}}) - assert.NoError(t, err) - assert.Equal(t, empty, o) + be.Err(t, err, nil) + be.Equal(t, o, empty) } diff --git a/formatters/plain_test.go b/formatters/plain_test.go index 487550f..4967553 100644 --- a/formatters/plain_test.go +++ b/formatters/plain_test.go @@ -9,8 +9,7 @@ import ( "codeberg.org/danjones000/my-log/models" "codeberg.org/danjones000/my-log/tools" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" + "github.com/nalgeon/be" ) func TestPlainLogs(t *testing.T) { @@ -31,101 +30,101 @@ func TestPlainLogs(t *testing.T) { logs := []models.Log{l, l2} f, err := New("plain") - require.NoError(t, err) + be.Err(t, err, nil) out, err := f.Logs(logs) - require.NoError(t, err) + be.Err(t, err, nil) read := bytes.NewReader(out) scan := bufio.NewScanner(read) scan.Scan() line := scan.Text() - assert.Equal(t, l.Name, line) + be.Equal(t, line, l.Name) scan.Scan() line = scan.Text() - assert.Equal(t, "#######", line) + be.Equal(t, line, "#######") scan.Scan() scan.Scan() line = scan.Text() - assert.Equal(t, "Title: "+e[0].Title, line) + be.Equal(t, line, "Title: "+e[0].Title) scan.Scan() line = scan.Text() - assert.Equal(t, "Date: "+e[0].Date.Format(tools.DateFormat), line) + be.Equal(t, line, "Date: "+e[0].Date.Format(tools.DateFormat)) scan.Scan() line = scan.Text() - assert.Equal(t, "foo: bar", line) + be.Equal(t, line, "foo: bar") scan.Scan() line = scan.Text() - assert.Equal(t, "baz: 42", line) + be.Equal(t, line, "baz: 42") scan.Scan() scan.Scan() line = scan.Text() - assert.Equal(t, "Title: "+e[1].Title, line) + be.Equal(t, line, "Title: "+e[1].Title) scan.Scan() line = scan.Text() - assert.Equal(t, "Date: "+e[1].Date.Format(tools.DateFormat), line) + be.Equal(t, line, "Date: "+e[1].Date.Format(tools.DateFormat)) scan.Scan() scan.Scan() line = scan.Text() - assert.Equal(t, l2.Name, line) + be.Equal(t, line, l2.Name) scan.Scan() line = scan.Text() - assert.Equal(t, "#######", line) + be.Equal(t, line, "#######") scan.Scan() scan.Scan() line = scan.Text() - assert.Equal(t, "Title: "+e2.Title, line) + be.Equal(t, line, "Title: "+e2.Title) scan.Scan() line = scan.Text() - assert.Equal(t, "Date: "+e2.Date.Format(tools.DateFormat), line) + be.Equal(t, line, "Date: "+e2.Date.Format(tools.DateFormat)) more := scan.Scan() - assert.False(t, more) + be.True(t, !more) } func TestPlainName(t *testing.T) { f, _ := New("plain") - assert.Equal(t, "plain", f.Name()) + be.Equal(t, f.Name(), "plain") } func TestPlainLogNone(t *testing.T) { f, _ := New("plain") out, err := f.Logs([]models.Log{}) - assert.NoError(t, err) - assert.Len(t, out, 0) + be.Err(t, err, nil) + be.Equal(t, len(out), 0) } func TestPlainLogNoEntries(t *testing.T) { f, _ := New("plain") out, err := f.Log(models.Log{Name: "foo"}) - assert.NoError(t, err) - assert.Len(t, out, 0) + be.Err(t, err, nil) + be.Equal(t, len(out), 0) } func TestPlainMetaEmpty(t *testing.T) { f, _ := New("plain") out, err := f.Meta(models.Meta{"foo", ""}) - assert.NoError(t, err) - assert.Len(t, out, 0) + be.Err(t, err, nil) + be.Equal(t, len(out), 0) } func TestPlainMetaError(t *testing.T) { f, _ := New("plain") out, err := f.Meta(models.Meta{"foo", make(chan bool)}) - assert.Error(t, err) - assert.Len(t, out, 0) + be.Err(t, err) + be.Equal(t, len(out), 0) } func TestPlainEntry(t *testing.T) { @@ -135,6 +134,6 @@ func TestPlainEntry(t *testing.T) { Title: "foo", Date: now, }) - assert.NoError(t, err) - assert.Equal(t, fmt.Sprintf("Title: foo\nDate: %s", now.Format(tools.DateFormat)), string(out)) + be.Err(t, err, nil) + be.Equal(t, string(out), fmt.Sprintf("Title: foo\nDate: %s", now.Format(tools.DateFormat))) } diff --git a/go.mod b/go.mod index aa282b4..0c747b1 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module codeberg.org/danjones000/my-log -go 1.21.5 +go 1.26.0 require ( github.com/BurntSushi/toml v1.3.2 @@ -8,25 +8,20 @@ require ( github.com/google/uuid v1.6.0 github.com/markusmobius/go-dateparser v1.2.3 github.com/mitchellh/mapstructure v1.5.0 + github.com/nalgeon/be v0.3.0 github.com/spf13/cobra v1.8.0 - github.com/stretchr/testify v1.9.0 ) require ( - github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/elliotchance/pie/v2 v2.7.0 // indirect github.com/hablullah/go-hijri v1.0.2 // indirect github.com/hablullah/go-juliandays v1.0.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jalaali/go-jalaali v0.0.0-20210801064154-80525e88d958 // indirect - github.com/kr/pretty v0.3.1 // indirect github.com/magefile/mage v1.14.0 // indirect - github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/tetratelabs/wazero v1.2.1 // indirect github.com/wasilibs/go-re2 v1.3.0 // indirect golang.org/x/exp v0.0.0-20220321173239-a90fa8a75705 // indirect golang.org/x/text v0.14.0 // indirect - gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index a9fbca0..bc1f80a 100644 --- a/go.sum +++ b/go.sum @@ -3,9 +3,8 @@ github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbi github.com/caarlos0/env/v10 v10.0.0 h1:yIHUBZGsyqCnpTkbjk8asUlx6RFhhEs+h7TOBdgdzXA= github.com/caarlos0/env/v10 v10.0.0/go.mod h1:ZfulV76NvVPw3tm591U4SwL3Xx9ldzBP9aGxzeN7G18= github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= -github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/elliotchance/pie/v2 v2.7.0 h1:FqoIKg4uj0G/CrLGuMS9ejnFKa92lxE1dEgBD3pShXg= github.com/elliotchance/pie/v2 v2.7.0/go.mod h1:18t0dgGFH006g4eVdDtWfgFZPQEgl10IoEO8YWEq3Og= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= @@ -18,21 +17,16 @@ github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2 github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/jalaali/go-jalaali v0.0.0-20210801064154-80525e88d958 h1:qxLoi6CAcXVzjfvu+KXIXJOAsQB62LXjsfbOaErsVzE= github.com/jalaali/go-jalaali v0.0.0-20210801064154-80525e88d958/go.mod h1:Wqfu7mjUHj9WDzSSPI5KfBclTTEnLveRUFr/ujWnTgE= -github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= -github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= -github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/magefile/mage v1.14.0 h1:6QDX3g6z1YvJ4olPhT1wksUcSa/V0a1B+pJb73fBjyo= github.com/magefile/mage v1.14.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A= github.com/markusmobius/go-dateparser v1.2.3 h1:TvrsIvr5uk+3v6poDjaicnAFJ5IgtFHgLiuMY2Eb7Nw= github.com/markusmobius/go-dateparser v1.2.3/go.mod h1:cMwQRrBUQlK1UI5TIFHEcvpsMbkWrQLXuaPNMFzuYLk= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= -github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= -github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= -github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/nalgeon/be v0.3.0 h1:QsPANqEtcOD5qT2S3KAtIkDBBn8SXUf/Lb5Bi/z4UqM= +github.com/nalgeon/be v0.3.0/go.mod h1:PMwMuBLopwKJkSHnr2qHyLcZYUTqNejN7A8RAqNWO3E= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= @@ -51,7 +45,5 @@ golang.org/x/exp v0.0.0-20220321173239-a90fa8a75705/go.mod h1:lgLbSvA5ygNOMpwM/9 golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/internal/testutil/bep/json.go b/internal/testutil/bep/json.go new file mode 100644 index 0000000..f0fb46b --- /dev/null +++ b/internal/testutil/bep/json.go @@ -0,0 +1,21 @@ +package bep + +import ( + "encoding/json" + "testing" + + "github.com/nalgeon/be" +) + +func JSON(t *testing.T, got, want []byte) { + t.Helper() + + var gotAny, wantAny any + err := json.Unmarshal(want, &wantAny) + be.Err(t, err, nil) + + err = json.Unmarshal(got, &gotAny) + be.Err(t, err, nil) + + be.Equal(t, gotAny, wantAny) +} diff --git a/models/entry_test.go b/models/entry_test.go index a4fd2b7..6372897 100644 --- a/models/entry_test.go +++ b/models/entry_test.go @@ -4,11 +4,13 @@ import ( "bufio" "encoding" "encoding/json" + "regexp" "strings" "testing" "time" - "github.com/stretchr/testify/assert" + "codeberg.org/danjones000/my-log/internal/testutil/bep" + "github.com/nalgeon/be" ) // Type assertions @@ -88,6 +90,24 @@ func TestEntryMarshal(t *testing.T) { []string{"@me:age 43", "@me:name:first Dan", "@me:name:last Jones"}, nil, }, + { + "double-nested-map-dot", + "Title DM", + when, + []Meta{{"me", map[string]any{"age": 43, "name": map[string]any{".": "Dan Jones", "nick": "Danny"}}}}, + "@begin " + whens + " - Title DM", + []string{"@me:age 43", "@me:name Dan Jones", "@me:name:nick Danny"}, + nil, + }, + { + "double-nested-map-blank", + "Title DM", + when, + []Meta{{"me", map[string]any{"age": 43, "name": map[string]any{"": "Dan Jones", "nick": "Danny"}}}}, + "@begin " + whens + " - Title DM", + []string{"@me:age 43", "@me:name Dan Jones", "@me:name:nick Danny"}, + nil, + }, { "nested-keys-in-json", "Title NKJ", @@ -108,19 +128,19 @@ func getEntryMarshalTestRunner(title string, date time.Time, fields []Meta, firs return func(t *testing.T) { en := Entry{title, date, fields} o, er := en.MarshalText() - assert.Equal(t, err, er) + be.Err(t, er, err) if first == "" { return } os := string(o) if len(lines) == 0 { - assert.Equal(t, first, os) + be.Equal(t, os, first) return } - assert.Regexp(t, first, os) + be.True(t, regexp.MustCompile(first).MatchString(os)) for _, line := range lines { - assert.Regexp(t, "(?m)^"+line, os) + be.True(t, regexp.MustCompile("(?m)^"+line).MatchString(os)) } } } @@ -169,6 +189,14 @@ func TestEntryUnmarshal(t *testing.T) { []Meta{{"me:name", "Dan"}, {"me:coder", true}}, nil, }, + { + "nested-field-dot", + "@begin " + whens + " - A Title\n@me:name Dan Jones\n@me:name:nick Danny\n@me:coder true @end", + "A Title", + when, + []Meta{{"me:name", "Dan Jones"}, {"me:name:nick", "Danny"}, {"me:coder", true}}, + nil, + }, { "json-field", "@begin " + whens + " - Some Guy\n" + `@json {"name":"Dan","coder":true} @end`, @@ -189,12 +217,12 @@ func getEntryUnmarshalTestRunner(in string, title string, date time.Time, fields e := &Entry{} er := e.UnmarshalText([]byte(in)) if err != nil { - assert.ErrorIs(t, er, err) + be.Err(t, er, err) return } - assert.Equal(t, title, e.Title) - assert.WithinRange(t, e.Date, date.Add(-time.Second), date.Add(time.Second)) + be.Equal(t, e.Title, title) + be.True(t, e.Date.After(date.Add(-time.Second)) && e.Date.Before(date.Add(time.Second))) for _, f := range fields { got := false for _, m := range e.Fields { @@ -211,7 +239,7 @@ func getEntryUnmarshalTestRunner(in string, title string, date time.Time, fields break } } - assert.Truef(t, got, "Couldn't find field %+v. We have %+v", f, e.Fields) + be.True(t, got) } } } @@ -221,13 +249,13 @@ func TestScan(t *testing.T) { read := strings.NewReader(in) scan := bufio.NewScanner(read) scan.Split(scanEntry) - assert.True(t, scan.Scan()) - assert.Equal(t, "@begin date - Title\nlong", scan.Text()) - assert.True(t, scan.Scan()) - assert.Equal(t, "@foo john\njones", scan.Text()) - assert.True(t, scan.Scan()) - assert.Equal(t, "@bar 42@nobody", scan.Text()) - assert.False(t, scan.Scan()) + be.True(t, scan.Scan()) + be.Equal(t, scan.Text(), "@begin date - Title\nlong") + be.True(t, scan.Scan()) + be.Equal(t, scan.Text(), "@foo john\njones") + be.True(t, scan.Scan()) + be.Equal(t, scan.Text(), "@bar 42@nobody") + be.True(t, !scan.Scan()) } func TestEntryJsonMarshal(t *testing.T) { @@ -256,6 +284,9 @@ func TestEntryJsonMarshal(t *testing.T) { {"nested-field", "A Title", when, []Meta{{"obj:foo", "bar"}, {"obj:title", "Sub-title"}}, `{"title":"A Title","date":"` + whens + `","obj":{"foo":"bar","title":"Sub-title"}}`, nil}, {"double-nested-field", "A Title", when, []Meta{{"obj:foo", "bar"}, {"obj:me:name", "Dan"}, {"obj:me:age", 27}}, `{"title":"A Title","date":"` + whens + `","obj":{"foo":"bar","me":{"name":"Dan","age":27}}}`, nil}, {"nested-plus-json", "A Title", when, []Meta{{"obj:foo", "bar"}, {"obj:me", json.RawMessage(`{"name":"Dan","age":27}`)}}, `{"title":"A Title","date":"` + whens + `","obj":{"foo":"bar","me":{"name":"Dan","age":27}}}`, nil}, + {"nested-part", "A Title", when, []Meta{{"obj:foo", "bar"}, {"obj:me", "Dan"}, {"obj:me:age", 27}}, `{"title":"A Title","date":"` + whens + `","obj":{"foo":"bar","me":{".":"Dan","age":27}}}`, nil}, + {"nested-part-order", "A Title", when, []Meta{{"obj:foo", "bar"}, {"obj:me:age", 27}, {"obj:me", "Dan"}}, `{"title":"A Title","date":"` + whens + `","obj":{"foo":"bar","me":{".":"Dan","age":27}}}`, nil}, + {"nested-part-order-two", "A Title", when, []Meta{{"obj:foo", "bar"}, {"obj:me:age", 27}, {"obj:me", "Dan"}, {"obj:me:cool", true}}, `{"title":"A Title","date":"` + whens + `","obj":{"foo":"bar","me":{".":"Dan","age":27,"cool":true}}}`, nil}, } for _, tt := range tests { @@ -268,10 +299,9 @@ func getEntryJsonMarshalTestRunner(title string, date time.Time, fields []Meta, e := Entry{title, date, fields} o, er := json.Marshal(e) if err == nil { - assert.JSONEq(t, out, string(o)) - + bep.JSON(t, o, []byte(out)) } else { - assert.ErrorIs(t, er, err) + be.Err(t, er, err) } } } @@ -347,14 +377,14 @@ func getEntryJsonUnmarshalTestRunner(in, title string, date time.Time, fields [] e := new(Entry) er := e.UnmarshalJSON([]byte(in)) if err != nil { - assert.ErrorIs(t, er, err) + be.Err(t, er, err) return } - assert.Nil(t, er) - assert.Equal(t, title, e.Title) - assert.WithinRange(t, e.Date, date.Add(-time.Second), date.Add(time.Second)) - assert.Len(t, e.Fields, len(fields)) + be.Equal(t, er, nil) + be.Equal(t, e.Title, title) + be.True(t, e.Date.After(date.Add(-time.Second)) && e.Date.Before(date.Add(time.Second))) + be.Equal(t, len(e.Fields), len(fields)) for _, f := range fields { got := false fTime, isTime := f.Value.(time.Time) @@ -373,13 +403,13 @@ func getEntryJsonUnmarshalTestRunner(in, title string, date time.Time, fields [] } if isTime && m.Key == f.Key { mTime, _ := mVal.(time.Time) - if assert.WithinRange(t, mTime, fTime.Add(-2*time.Second), fTime.Add(2*time.Second)) { + if mTime.After(fTime.Add(-2*time.Second)) && mTime.Before(fTime.Add(2*time.Second)) { got = true break } } } - assert.Truef(t, got, "Couldn't find field %+v. We have %+v", f, e.Fields) + be.True(t, got) } } } diff --git a/models/log_test.go b/models/log_test.go index 46bca89..fd8fb3b 100644 --- a/models/log_test.go +++ b/models/log_test.go @@ -4,8 +4,7 @@ import ( "encoding" "testing" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" + "github.com/nalgeon/be" ) var _ encoding.TextUnmarshaler = new(Log) @@ -32,15 +31,15 @@ const all = first + second + third + fourth + skip + fifth func TestLogUnmarshalBig(t *testing.T) { l := &Log{Name: "test-log"} err := l.UnmarshalText([]byte(all)) - require.NoError(t, err) - require.Len(t, l.Entries, 5) + be.Err(t, err, nil) + be.Equal(t, len(l.Entries), 5) var e Entry var f bool if e, f = findEntry(t, l, "This is simple", true); !f { return } - assert.Len(t, e.Fields, 0) + be.Equal(t, len(e.Fields), 0) for _, e := range l.Entries { findMeta(t, e, "ignoreme", true, false) @@ -51,28 +50,28 @@ func TestLogUnmarshalIgnoreGarbage(t *testing.T) { l := &Log{Name: "test-log"} in := "ignore this\n" + second + "some crap also skip -> " + third + skip err := l.UnmarshalText([]byte(in)) - require.NoError(t, err) - require.Len(t, l.Entries, 1) + be.Err(t, err, nil) + be.Equal(t, len(l.Entries), 1) en := l.Entries[0] - assert.Equal(t, "We have one thing here", en.Title) - assert.Len(t, en.Fields, 1) - assert.Equal(t, "foo", en.Fields[0].Key) - assert.Equal(t, "bar", en.Fields[0].Value) + be.Equal(t, en.Title, "We have one thing here") + be.Equal(t, len(en.Fields), 1) + be.Equal(t, en.Fields[0].Key, "foo") + be.Equal(t, en.Fields[0].Value, "bar") } func TestLogUnmarshalEmpty(t *testing.T) { l := &Log{Name: "test-log"} err := l.UnmarshalText([]byte{}) - require.NoError(t, err) - require.Len(t, l.Entries, 0) + be.Err(t, err, nil) + be.Equal(t, len(l.Entries), 0) } func TestLogUnmarshalBad(t *testing.T) { l := &Log{Name: "test-log"} err := l.UnmarshalText([]byte(badEntry)) - require.NoError(t, err) - require.Len(t, l.Entries, 0) + be.Err(t, err, nil) + be.Equal(t, len(l.Entries), 0) } func findEntry(t *testing.T, log *Log, title string, shouldFind bool) (Entry, bool) { @@ -85,9 +84,9 @@ func findEntry(t *testing.T, log *Log, title string, shouldFind bool) (Entry, bo } } if shouldFind { - found = assert.Truef(t, found, "Unable to found entry %s", title) + be.True(t, found) } else { - found = assert.Falsef(t, found, "Entry %s should not have been found but was", title) + be.True(t, !found) } return ret, found @@ -103,9 +102,9 @@ func findMeta(t *testing.T, entry Entry, key string, value any, shouldFind bool) } } if shouldFind { - found = assert.Truef(t, found, "Unable to found meta %s", key) + be.True(t, found) } else { - found = assert.Falsef(t, found, "Meta %s should not have been found but was", key) + be.True(t, !found) } return ret, found diff --git a/models/meta.go b/models/meta.go index c35f302..15ed90b 100644 --- a/models/meta.go +++ b/models/meta.go @@ -50,12 +50,16 @@ func marshalMap(pre string, mp map[string]any, buff *bytes.Buffer) error { buff.WriteRune('\n') } idx++ + newKey := pre + ":" + k + if k == "." || k == "" { + newKey = pre + } if subM, ok := v.(map[string]any); ok { - if err := marshalMap(pre+":"+k, subM, buff); err != nil { + if err := marshalMap(newKey, subM, buff); err != nil { return err } } else { - mSub := Meta{pre + ":" + k, v} + mSub := Meta{newKey, v} if err := mSub.marshalToBuff(buff); err != nil { return err } diff --git a/models/meta_test.go b/models/meta_test.go index c6dd0e4..8827444 100644 --- a/models/meta_test.go +++ b/models/meta_test.go @@ -7,7 +7,8 @@ import ( "testing" "time" - "github.com/stretchr/testify/assert" + "codeberg.org/danjones000/my-log/internal/testutil/bep" + "github.com/nalgeon/be" ) // Type assertions @@ -72,8 +73,8 @@ func getMetaTestRunner(key string, value any, out string, err error, newVal any) if valE, ok := value.(error); !ok || !errors.Is(valE, skipMarshalTest) { var o []byte o, e = st.MarshalText() - assert.Equal(t, out, string(o)) - assert.Equal(t, err, e) + be.Equal(t, string(o), out) + be.Equal(t, e, err) if e != nil { return } @@ -83,17 +84,16 @@ func getMetaTestRunner(key string, value any, out string, err error, newVal any) e = n.UnmarshalText([]byte(out)) } if newE, ok := newVal.(error); ok { - assert.ErrorIs(t, e, newE) + be.Err(t, e, newE) } else { - assert.Equal(t, key, n.Key) + be.Equal(t, n.Key, key) if ti, ok := newVal.(time.Time); ok { valT, ok := n.Value.(time.Time) - if assert.True(t, ok) { - assert.WithinRange(t, valT, ti.Add(-time.Second), ti.Add(time.Second)) - } + be.True(t, ok) + be.True(t, valT.After(ti.Add(-time.Second)) && valT.Before(ti.Add(time.Second))) } else { - assert.Equal(t, newVal, n.Value) + be.Equal(t, n.Value, newVal) } } } @@ -103,42 +103,42 @@ func TestMetasJson(t *testing.T) { ms := Metas{{"me", 41}, {"you", false}} exp := `{"me":41,"you":false}` o, err := json.Marshal(ms) - assert.NoError(t, err) - assert.JSONEq(t, exp, string(o)) + be.Err(t, err, nil) + bep.JSON(t, o, []byte(exp)) } func TestMetasJsonUnmarshal(t *testing.T) { ms := Metas{} in := `{"me":"cool","you":false}` err := json.Unmarshal([]byte(in), &ms) - assert.NoError(t, err) - assert.Len(t, ms, 2) - assert.ElementsMatch(t, Metas{ + be.Err(t, err, nil) + be.Equal(t, len(ms), 2) + be.Equal(t, ms, Metas{ {"me", "cool"}, {"you", false}, - }, ms) + }) } func TestMetasJsonError(t *testing.T) { ms := Metas{} in := "not json" err := (&ms).UnmarshalJSON([]byte(in)) - assert.Error(t, err) - assert.Len(t, ms, 0) + be.Err(t, err) + be.Equal(t, len(ms), 0) } func TestMetasAppend(t *testing.T) { ms := Metas{} ms = ms.Append("foo", 42) - assert.Len(t, ms, 1) - assert.Equal(t, Meta{"foo", 42}, ms[0]) + be.Equal(t, len(ms), 1) + be.Equal(t, ms[0], Meta{"foo", 42}) } func TestMetasAppendTo(t *testing.T) { ms := &Metas{} ms.AppendTo("foo", 42) - assert.Len(t, *ms, 1) - assert.Equal(t, Meta{"foo", 42}, (*ms)[0]) + be.Equal(t, len(*ms), 1) + be.Equal(t, (*ms)[0], Meta{"foo", 42}) } func TestMetasSet(t *testing.T) { @@ -196,7 +196,7 @@ func TestMetasSet(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { result := tt.initial.Set(tt.key, tt.value) - assert.ElementsMatch(t, tt.expected, result) + be.Equal(t, result, tt.expected) }) } } @@ -205,14 +205,14 @@ func TestMetasGet(t *testing.T) { ms := Metas{{"foo", 42}, {"bar", "hello"}} val, found := ms.Get("foo") - assert.True(t, found) - assert.Equal(t, 42, val) + be.True(t, found) + be.Equal(t, val, 42) val, found = ms.Get("bar") - assert.True(t, found) - assert.Equal(t, "hello", val) + be.True(t, found) + be.Equal(t, val, "hello") val, found = ms.Get("baz") - assert.False(t, found) - assert.Nil(t, val) + be.True(t, !found) + be.Equal(t, val, nil) } diff --git a/models/metas.go b/models/metas.go index 5b68455..92a9cec 100644 --- a/models/metas.go +++ b/models/metas.go @@ -42,6 +42,7 @@ func (ms Metas) Map() map[string]any { } func parseNestedFields(f map[string]any) { + todelete := make([]string, 0, len(f)) for k, v := range f { if strings.Contains(k, ":") { idx := strings.Index(k, ":") @@ -50,14 +51,28 @@ func parseNestedFields(f map[string]any) { nest, ok := f[top].(map[string]any) if !ok { - nest = map[string]any{} + curr := f[top] + if curr == nil { + nest = map[string]any{} + } else { + nest = map[string]any{".": curr} + } + } + + curr, ok := nest[bottom].(map[string]any) + if ok { + curr["."] = v + } else { + nest[bottom] = v } - nest[bottom] = v parseNestedFields(nest) f[top] = nest - delete(f, k) + todelete = append(todelete, k) } } + for _, k := range todelete { + delete(f, k) + } } // Implements json.Marshaler diff --git a/tools/parse_date_test.go b/tools/parse_date_test.go index 3099b88..3ed2da6 100644 --- a/tools/parse_date_test.go +++ b/tools/parse_date_test.go @@ -5,8 +5,7 @@ import ( "testing" "time" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" + "github.com/nalgeon/be" ) const day = time.Hour * 24 @@ -58,11 +57,10 @@ func getDateTest(in string, exp time.Time, err string) func(t *testing.T) { return func(t *testing.T) { out, er := ParseDate(in) if err != "" { - assert.ErrorContains(t, er, err) + be.Err(t, er, err) } else { - require.NoError(t, er) - - assert.Equal(t, exp, out) + be.Err(t, er, nil) + be.Equal(t, out, exp) } } } diff --git a/tools/parse_test.go b/tools/parse_test.go index 72fc50d..a505c5b 100644 --- a/tools/parse_test.go +++ b/tools/parse_test.go @@ -5,7 +5,7 @@ import ( "testing" "time" - "github.com/stretchr/testify/assert" + "github.com/nalgeon/be" ) func TestParse(t *testing.T) { @@ -54,20 +54,18 @@ func getParseTestRunner(in string, exp any) func(*testing.T) { out := ParseString(in) if expT, ok := exp.(time.Time); ok { ti, gotTime := out.(time.Time) - if assert.True(t, gotTime, "Should have gotten a time.Time, but didn't") { - assert.WithinRange(t, expT, ti.Add(-2*time.Second), ti.Add(2*time.Second)) - } + be.True(t, gotTime) + be.True(t, expT.After(ti.Add(-2*time.Second)) && expT.Before(ti.Add(2*time.Second))) } else { - assert.Equal(t, exp, out) + be.Equal(t, out, exp) } out = ParseBytes([]byte(in)) if expT, ok := exp.(time.Time); ok { ti, gotTime := out.(time.Time) - if assert.True(t, gotTime, "Should have gotten a time.Time, but didn't") { - assert.WithinRange(t, expT, ti.Add(-2*time.Second), ti.Add(2*time.Second)) - } + be.True(t, gotTime) + be.True(t, expT.After(ti.Add(-2*time.Second)) && expT.Before(ti.Add(2*time.Second))) } else { - assert.Equal(t, exp, out) + be.Equal(t, out, exp) } } } diff --git a/tools/write_buffer_test.go b/tools/write_buffer_test.go index 8d3ab1f..a51c835 100644 --- a/tools/write_buffer_test.go +++ b/tools/write_buffer_test.go @@ -7,7 +7,7 @@ import ( "testing" "time" - "github.com/stretchr/testify/assert" + "github.com/nalgeon/be" ) func TestWriteBuffer(t *testing.T) { @@ -52,8 +52,8 @@ func getWriteTestRunner(value any, out string, err error) func(*testing.T) { return func(t *testing.T) { buff := &bytes.Buffer{} n, er := WriteValue(buff, value) - assert.Equal(t, len(out), n) - assert.Equal(t, err, er) - assert.Equal(t, out, buff.String()) + be.Equal(t, n, len(out)) + be.Equal(t, er, err) + be.Equal(t, buff.String(), out) } }