✨ Add plain text formatter
This commit is contained in:
		
					parent
					
						
							
								286ac4557d
							
						
					
				
			
			
				commit
				
					
						89e6c2b3bd
					
				
			
		
					 5 changed files with 276 additions and 0 deletions
				
			
		
							
								
								
									
										10
									
								
								formatters/interface.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								formatters/interface.go
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,10 @@ | ||||||
|  | package formatters | ||||||
|  | 
 | ||||||
|  | import "codeberg.org/danjones000/my-log/models" | ||||||
|  | 
 | ||||||
|  | type Formatter interface { | ||||||
|  | 	Name() string | ||||||
|  | 	Log(models.Log) (out []byte, err error) | ||||||
|  | 	Entry(models.Entry) (out []byte, err error) | ||||||
|  | 	Meta(models.Meta) (out []byte, err error) | ||||||
|  | } | ||||||
							
								
								
									
										34
									
								
								formatters/new.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								formatters/new.go
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,34 @@ | ||||||
|  | package formatters | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"errors" | ||||||
|  | 
 | ||||||
|  | 	"codeberg.org/danjones000/my-log/config" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | type formatMaker func(oo config.Outputs) (Formatter, error) | ||||||
|  | 
 | ||||||
|  | var formatterMap = map[string]formatMaker{ | ||||||
|  | 	"plain": newPlain, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func New(kind string) (f Formatter, err error) { | ||||||
|  | 	conf, err := config.Load() | ||||||
|  | 	if err != nil { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if make, ok := formatterMap[kind]; ok { | ||||||
|  | 		return make(conf.Outputs) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return nil, errors.New("unimplemented") | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func Kinds() []string { | ||||||
|  | 	r := []string{} | ||||||
|  | 	for kind, _ := range formatterMap { | ||||||
|  | 		r = append(r, kind) | ||||||
|  | 	} | ||||||
|  | 	return r | ||||||
|  | } | ||||||
							
								
								
									
										35
									
								
								formatters/new_test.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								formatters/new_test.go
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,35 @@ | ||||||
|  | package formatters | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"fmt" | ||||||
|  | 	"os" | ||||||
|  | 	"testing" | ||||||
|  | 
 | ||||||
|  | 	"codeberg.org/danjones000/my-log/config" | ||||||
|  | 	"github.com/stretchr/testify/assert" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | func TestKinds(t *testing.T) { | ||||||
|  | 	assert.Equal(t, []string{"plain"}, Kinds()) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func TestNewUnsupported(t *testing.T) { | ||||||
|  | 	f, err := New("nope") | ||||||
|  | 	assert.Nil(t, f) | ||||||
|  | 	assert.Error(t, err) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func TestNewCantGetConfig(t *testing.T) { | ||||||
|  | 	f, _ := os.CreateTemp("", "test") | ||||||
|  | 	oldConf := config.ConfigPath | ||||||
|  | 	config.ConfigPath = f.Name() | ||||||
|  | 	defer f.Close() | ||||||
|  | 	defer func() { | ||||||
|  | 		config.ConfigPath = oldConf | ||||||
|  | 	}() | ||||||
|  | 
 | ||||||
|  | 	fmt.Fprint(f, `{"not":"toml"}`) | ||||||
|  | 	form, err := New("plain") | ||||||
|  | 	assert.Nil(t, form) | ||||||
|  | 	assert.Error(t, err) | ||||||
|  | } | ||||||
							
								
								
									
										88
									
								
								formatters/plain.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										88
									
								
								formatters/plain.go
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,88 @@ | ||||||
|  | package formatters | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"bytes" | ||||||
|  | 
 | ||||||
|  | 	"codeberg.org/danjones000/my-log/config" | ||||||
|  | 	"codeberg.org/danjones000/my-log/models" | ||||||
|  | 	"codeberg.org/danjones000/my-log/tools" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | func newPlain(oo config.Outputs) (Formatter, error) { | ||||||
|  | 	return &PlainText{}, nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | type PlainText struct { | ||||||
|  | 	// config might go here some day | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (pt *PlainText) Name() string { | ||||||
|  | 	return "plain" | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (pt *PlainText) Log(log models.Log) (out []byte, err error) { | ||||||
|  | 	if len(log.Entries) == 0 { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	buff := &bytes.Buffer{} | ||||||
|  | 	buff.WriteString(log.Name) | ||||||
|  | 	buff.WriteString("\n#######") | ||||||
|  | 	written := false | ||||||
|  | 	for _, e := range log.Entries { | ||||||
|  | 		bb := pt.entryBuffer(e) | ||||||
|  | 		if bb.Len() > 0 { | ||||||
|  | 			buff.WriteByte(10) | ||||||
|  | 			buff.WriteByte(10) | ||||||
|  | 			buff.ReadFrom(bb) | ||||||
|  | 			written = true | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	if written { | ||||||
|  | 		out = buff.Bytes() | ||||||
|  | 	} | ||||||
|  | 	return | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (pt *PlainText) entryBuffer(entry models.Entry) *bytes.Buffer { | ||||||
|  | 	buff := &bytes.Buffer{} | ||||||
|  | 	buff.WriteString("Title: ") | ||||||
|  | 	buff.WriteString(entry.Title) | ||||||
|  | 	buff.WriteByte(10) | ||||||
|  | 	buff.WriteString("Date: ") | ||||||
|  | 	buff.WriteString(entry.Date.Format(tools.DateFormat)) | ||||||
|  | 	for _, m := range entry.Fields { | ||||||
|  | 		bb, err := pt.metaBuffer(m) | ||||||
|  | 		if (bb.Len() > 0) && (err == nil) { | ||||||
|  | 			buff.WriteByte(10) | ||||||
|  | 			buff.ReadFrom(bb) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return buff | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (pt *PlainText) Entry(entry models.Entry) ([]byte, error) { | ||||||
|  | 	buff := pt.entryBuffer(entry) | ||||||
|  | 	return buff.Bytes(), nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (pt *PlainText) metaBuffer(meta models.Meta) (*bytes.Buffer, error) { | ||||||
|  | 	buff := &bytes.Buffer{} | ||||||
|  | 	buff.WriteString(meta.Key) | ||||||
|  | 	buff.WriteString(": ") | ||||||
|  | 	n, err := tools.WriteValue(buff, meta.Value) | ||||||
|  | 	if n == 0 || err != nil { | ||||||
|  | 		return &bytes.Buffer{}, err | ||||||
|  | 	} | ||||||
|  | 	return buff, nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (pt *PlainText) Meta(meta models.Meta) (out []byte, err error) { | ||||||
|  | 	buff, err := pt.metaBuffer(meta) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	out = buff.Bytes() | ||||||
|  | 	return | ||||||
|  | } | ||||||
							
								
								
									
										109
									
								
								formatters/plain_test.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										109
									
								
								formatters/plain_test.go
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,109 @@ | ||||||
|  | package formatters | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"bufio" | ||||||
|  | 	"bytes" | ||||||
|  | 	"fmt" | ||||||
|  | 	"testing" | ||||||
|  | 	"time" | ||||||
|  | 
 | ||||||
|  | 	"codeberg.org/danjones000/my-log/models" | ||||||
|  | 	"codeberg.org/danjones000/my-log/tools" | ||||||
|  | 	"github.com/stretchr/testify/assert" | ||||||
|  | 	"github.com/stretchr/testify/require" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | func TestPlainLog(t *testing.T) { | ||||||
|  | 	m := []models.Meta{ | ||||||
|  | 		{"foo", "bar"}, | ||||||
|  | 		{"baz", 42}, | ||||||
|  | 	} | ||||||
|  | 	e := []models.Entry{ | ||||||
|  | 		{Title: "one", Date: time.Now(), Fields: m}, | ||||||
|  | 		{Title: "small", Date: time.Now()}, | ||||||
|  | 	} | ||||||
|  | 	l := models.Log{"stuff", e} | ||||||
|  | 
 | ||||||
|  | 	f, err := New("plain") | ||||||
|  | 	require.NoError(t, err) | ||||||
|  | 
 | ||||||
|  | 	out, err := f.Log(l) | ||||||
|  | 	require.NoError(t, err) | ||||||
|  | 
 | ||||||
|  | 	read := bytes.NewReader(out) | ||||||
|  | 	scan := bufio.NewScanner(read) | ||||||
|  | 
 | ||||||
|  | 	scan.Scan() | ||||||
|  | 	line := scan.Text() | ||||||
|  | 	assert.Equal(t, l.Name, line) | ||||||
|  | 
 | ||||||
|  | 	scan.Scan() | ||||||
|  | 	line = scan.Text() | ||||||
|  | 	assert.Equal(t, "#######", line) | ||||||
|  | 
 | ||||||
|  | 	scan.Scan() | ||||||
|  | 	scan.Scan() | ||||||
|  | 	line = scan.Text() | ||||||
|  | 	assert.Equal(t, "Title: "+e[0].Title, line) | ||||||
|  | 
 | ||||||
|  | 	scan.Scan() | ||||||
|  | 	line = scan.Text() | ||||||
|  | 	assert.Equal(t, "Date: "+e[0].Date.Format(tools.DateFormat), line) | ||||||
|  | 
 | ||||||
|  | 	scan.Scan() | ||||||
|  | 	line = scan.Text() | ||||||
|  | 	assert.Equal(t, "foo: bar", line) | ||||||
|  | 
 | ||||||
|  | 	scan.Scan() | ||||||
|  | 	line = scan.Text() | ||||||
|  | 	assert.Equal(t, "baz: 42", line) | ||||||
|  | 
 | ||||||
|  | 	scan.Scan() | ||||||
|  | 	scan.Scan() | ||||||
|  | 	line = scan.Text() | ||||||
|  | 	assert.Equal(t, "Title: "+e[1].Title, line) | ||||||
|  | 
 | ||||||
|  | 	scan.Scan() | ||||||
|  | 	line = scan.Text() | ||||||
|  | 	assert.Equal(t, "Date: "+e[1].Date.Format(tools.DateFormat), line) | ||||||
|  | 
 | ||||||
|  | 	more := scan.Scan() | ||||||
|  | 	assert.False(t, more) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func TestPlainName(t *testing.T) { | ||||||
|  | 	f, _ := New("plain") | ||||||
|  | 	assert.Equal(t, "plain", f.Name()) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 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) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func TestPlainMetaEmpty(t *testing.T) { | ||||||
|  | 	f, _ := New("plain") | ||||||
|  | 	out, err := f.Meta(models.Meta{"foo", ""}) | ||||||
|  | 	assert.NoError(t, err) | ||||||
|  | 	assert.Len(t, 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) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func TestPlainEntry(t *testing.T) { | ||||||
|  | 	f, _ := New("plain") | ||||||
|  | 	now := time.Now() | ||||||
|  | 	out, err := f.Entry(models.Entry{ | ||||||
|  | 		Title: "foo", | ||||||
|  | 		Date:  now, | ||||||
|  | 	}) | ||||||
|  | 	assert.NoError(t, err) | ||||||
|  | 	assert.Equal(t, fmt.Sprintf("Title: foo\nDate: %s", now.Format(tools.DateFormat)), string(out)) | ||||||
|  | } | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue