seemingly good
parent
28310b0dd6
commit
109c7c48bc
|
|
@ -1,9 +1,11 @@
|
||||||
package mytinytodo
|
package mytinytodo
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"local/mytinytodoclient/mytinytodo/remote"
|
"local/mytinytodoclient/mytinytodo/remote"
|
||||||
"local/rproxy3/storage"
|
"local/rproxy3/storage"
|
||||||
"log"
|
"log"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
|
@ -12,7 +14,10 @@ import (
|
||||||
|
|
||||||
const nsQueue = "delta"
|
const nsQueue = "delta"
|
||||||
const keyQueue = "queue"
|
const keyQueue = "queue"
|
||||||
const nsTasks = "delta"
|
const nsLists = "lists"
|
||||||
|
const keyLists = "lists"
|
||||||
|
const nsTasks = "tasks"
|
||||||
|
const keyTasks = "tasks"
|
||||||
|
|
||||||
type Buffer struct {
|
type Buffer struct {
|
||||||
config *Config
|
config *Config
|
||||||
|
|
@ -31,8 +36,8 @@ func NewBuffer(config *Config) (*Buffer, error) {
|
||||||
dbLock: &sync.RWMutex{},
|
dbLock: &sync.RWMutex{},
|
||||||
interval: time.Second * 10,
|
interval: time.Second * 10,
|
||||||
}
|
}
|
||||||
go b.Dequeue()
|
go b.notDoneCallback(b.Dequeue)
|
||||||
go b.RefreshLocal()
|
go b.notDoneCallback(b.RefreshLocal)
|
||||||
return b, nil
|
return b, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -40,36 +45,38 @@ func (buffer *Buffer) Close() {
|
||||||
close(buffer.done)
|
close(buffer.done)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (buffer *Buffer) Enqueue(op remote.Op, listID, taskName string, taskTags ...string) error {
|
func (buffer *Buffer) Enqueue(op remote.Op, listID, taskTitle string, taskTags ...string) error {
|
||||||
buffer.dbLock.Lock()
|
buffer.dbLock.Lock()
|
||||||
defer buffer.dbLock.Unlock()
|
defer buffer.dbLock.Unlock()
|
||||||
qop := &QueuedOp{
|
qop := &QueuedOp{
|
||||||
Op: op,
|
Op: op,
|
||||||
ListID: listID,
|
List: remote.List{ID: listID},
|
||||||
TaskName: taskName,
|
Task: remote.Task{Title: taskTitle},
|
||||||
TaskTags: taskTags,
|
TaskTags: taskTags,
|
||||||
}
|
}
|
||||||
uuid, _ := uuid.NewRandom()
|
uuid, _ := uuid.NewRandom()
|
||||||
key := uuid.String()
|
key := uuid.String()
|
||||||
|
|
||||||
todo := NewStringArray()
|
todo := NewStringArray()
|
||||||
if err := buffer.db.Get(nsQueue, keyQueue, todo); err != nil {
|
if err := buffer.db.Get(nsQueue, keyQueue, todo); err != nil && err != storage.ErrNotFound {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
sa := todo.StringArray()
|
sa := todo.StringArray()
|
||||||
sa = append(sa, key)
|
sa = append(sa, key)
|
||||||
todo = NewStringArray(sa...)
|
todo = NewStringArray(sa...)
|
||||||
if err := buffer.db.Set(nsTasks, key, qop); err != nil {
|
if err := buffer.db.Set(nsQueue, key, qop); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := buffer.db.Set(nsQueue, keyQueue, todo); err != nil {
|
if err := buffer.db.Set(nsQueue, keyQueue, todo); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("enqueued task %v as %v, %vth in line", qop, key, len(sa))
|
log.Printf("enqueued task %v as %v, %vth in line", qop, key, len(sa))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (buffer *Buffer) Dequeue() {
|
func (buffer *Buffer) Dequeue() {
|
||||||
buffer.notDoneCallback(func() {
|
|
||||||
client, err := remote.NewClient(buffer.config.Config)
|
client, err := remote.NewClient(buffer.config.Config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("cannot create client: %v", err)
|
log.Printf("cannot create client: %v", err)
|
||||||
|
|
@ -79,6 +86,7 @@ func (buffer *Buffer) Dequeue() {
|
||||||
log.Printf("cannot client.lists: %v", err)
|
log.Printf("cannot client.lists: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer.dbLock.Lock()
|
buffer.dbLock.Lock()
|
||||||
defer buffer.dbLock.Unlock()
|
defer buffer.dbLock.Unlock()
|
||||||
todo := NewStringArray()
|
todo := NewStringArray()
|
||||||
|
|
@ -86,29 +94,74 @@ func (buffer *Buffer) Dequeue() {
|
||||||
log.Printf("cannot get %v.%v: %v", nsQueue, keyQueue, err)
|
log.Printf("cannot get %v.%v: %v", nsQueue, keyQueue, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
sa := todo.StringArray()
|
sa := todo.StringArray()
|
||||||
nsa := []string{}
|
nsa := []string{}
|
||||||
for i := range sa {
|
for i := range sa {
|
||||||
qop := &QueuedOp{}
|
qop := &QueuedOp{}
|
||||||
if err := buffer.db.Get(nsTasks, sa[i], qop); err != nil {
|
if err := buffer.db.Get(nsQueue, sa[i], qop); err != nil {
|
||||||
log.Printf("cannot get %v.%v: %v", nsTasks, sa[i], err)
|
log.Printf("cannot get %v.%v: %v", nsQueue, sa[i], err)
|
||||||
nsa = append(nsa, sa[i])
|
nsa = append(nsa, sa[i])
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
log.Printf("UPSERT %v", qop)
|
var err error
|
||||||
|
switch qop.Op {
|
||||||
|
case remote.NEW:
|
||||||
|
err = client.NewTask(qop.List, qop.Task, strings.Join(qop.TaskTags, ","))
|
||||||
|
case remote.CLOSE:
|
||||||
|
err = client.CloseTask(qop.Task)
|
||||||
|
case remote.OPEN:
|
||||||
|
err = client.OpenTask(qop.Task)
|
||||||
|
default:
|
||||||
|
err = fmt.Errorf("cannot dequeue op %v", qop.Op)
|
||||||
}
|
}
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("failed op %v: %v", qop.Op, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if err := buffer.db.Set(nsQueue, sa[i], nil); err != nil {
|
||||||
|
log.Printf("cannot unset %v.%v: %v", nsQueue, sa[i], err)
|
||||||
|
nsa = append(nsa, sa[i])
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if err := buffer.db.Set(nsQueue, keyQueue, NewStringArray(nsa...)); err != nil {
|
if err := buffer.db.Set(nsQueue, keyQueue, NewStringArray(nsa...)); err != nil {
|
||||||
log.Printf("cannot update queue: %v", err)
|
log.Printf("cannot update queue: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (buffer *Buffer) RefreshLocal() {
|
func (buffer *Buffer) RefreshLocal() {
|
||||||
buffer.notDoneCallback(func() {
|
client, err := remote.NewClient(buffer.config.Config)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("cannot create client: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
lists, err := client.Lists()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("cannot client.lists: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
buffer.dbLock.Lock()
|
buffer.dbLock.Lock()
|
||||||
defer buffer.dbLock.Unlock()
|
defer buffer.dbLock.Unlock()
|
||||||
})
|
if err := buffer.db.Set(nsLists, keyLists, &lists); err != nil {
|
||||||
|
log.Printf("cannot set lists: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, list := range lists {
|
||||||
|
tasks, err := client.Tasks(list)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("cannot client.tasks(%v): %v", list, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if err := buffer.db.Set(nsTasks, list.ID, &tasks); err != nil {
|
||||||
|
log.Printf("cannot set tasks(%v): %v", list.ID, tasks)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (buffer *Buffer) notDoneCallback(foo func()) {
|
func (buffer *Buffer) notDoneCallback(foo func()) {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package mytinytodo
|
package mytinytodo
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"local/mytinytodoclient/mytinytodo/remote"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"os"
|
"os"
|
||||||
|
|
@ -15,15 +16,59 @@ func TestNewBuffer(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBufferEnqueue(t *testing.T) {
|
func TestBufferEnqueue(t *testing.T) {
|
||||||
t.Fatal("not implemented")
|
b, s := mockBuffer(t)
|
||||||
|
defer b.Close()
|
||||||
|
defer s.Close()
|
||||||
|
|
||||||
|
if err := b.Enqueue(remote.NEW, "list", "task", "one", "tag", "two"); err != nil {
|
||||||
|
t.Errorf("cannot enqueue: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
todo1 := NewStringArray()
|
||||||
|
if err := b.db.Get(nsQueue, keyQueue, todo1); err != nil || len(todo1.StringArray()) != 1 {
|
||||||
|
t.Fatalf("enqueue didnt create list: %v (%d)", err, len(todo1.StringArray()))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBufferDequeue(t *testing.T) {
|
func TestBufferDequeue(t *testing.T) {
|
||||||
t.Fatal("not implemented")
|
b, s := mockBuffer(t)
|
||||||
|
defer b.Close()
|
||||||
|
defer s.Close()
|
||||||
|
|
||||||
|
if err := b.Enqueue(remote.NEW, "list", "task", "one", "tag", "two"); err != nil {
|
||||||
|
t.Fatalf("cannot enqueue to dequeue: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
todo1 := NewStringArray()
|
||||||
|
if err := b.db.Get(nsQueue, keyQueue, todo1); err != nil || len(todo1.StringArray()) != 1 {
|
||||||
|
t.Fatalf("enqueue didnt create list: %v (%d)", err, len(todo1.StringArray()))
|
||||||
|
}
|
||||||
|
|
||||||
|
b.Dequeue()
|
||||||
|
|
||||||
|
todo2 := NewStringArray()
|
||||||
|
if err := b.db.Get(nsQueue, keyQueue, todo2); err != nil || len(todo2.StringArray()) != 0 {
|
||||||
|
t.Fatalf("dequeue didnt remove from list: %v (%d)", err, len(todo2.StringArray()))
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBufferRefreshLocal(t *testing.T) {
|
func TestBufferRefreshLocal(t *testing.T) {
|
||||||
t.Fatal("not implemented")
|
b, s := mockBuffer(t)
|
||||||
|
defer b.Close()
|
||||||
|
defer s.Close()
|
||||||
|
|
||||||
|
b.RefreshLocal()
|
||||||
|
|
||||||
|
var lists remote.Lists
|
||||||
|
if err := b.db.Get(nsLists, keyLists, &lists); err != nil || lists.Length() != 1 {
|
||||||
|
t.Fatalf("refreshLocal didnt create list: %v (%d)", err, lists.Length())
|
||||||
|
}
|
||||||
|
|
||||||
|
var tasks remote.Tasks
|
||||||
|
if err := b.db.Get(nsTasks, lists.ListArray()[0].ID, &tasks); err != nil || tasks.Length() != 1 {
|
||||||
|
t.Fatalf("failed to parse task on refresh: %v (%d)", err, tasks.Length())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBufferNotDoneCallback(t *testing.T) {
|
func TestBufferNotDoneCallback(t *testing.T) {
|
||||||
|
|
@ -41,6 +86,19 @@ func TestBufferNotDoneCallback(t *testing.T) {
|
||||||
|
|
||||||
func mockBuffer(t *testing.T) (*Buffer, *httptest.Server) {
|
func mockBuffer(t *testing.T) (*Buffer, *httptest.Server) {
|
||||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
w.Write([]byte(`
|
||||||
|
{
|
||||||
|
"list":[
|
||||||
|
{
|
||||||
|
"id":"id",
|
||||||
|
"name":"name",
|
||||||
|
"title":"title",
|
||||||
|
"compl":0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
`))
|
||||||
}))
|
}))
|
||||||
osArgsWas := os.Args[:]
|
osArgsWas := os.Args[:]
|
||||||
os.Args = []string{"skip", "-remote", srv.URL, "-p", ""}
|
os.Args = []string{"skip", "-remote", srv.URL, "-p", ""}
|
||||||
|
|
|
||||||
|
|
@ -36,8 +36,8 @@ func (sa *StringArray) Decode(b []byte) error {
|
||||||
|
|
||||||
type QueuedOp struct {
|
type QueuedOp struct {
|
||||||
Op remote.Op
|
Op remote.Op
|
||||||
ListID string
|
List remote.List
|
||||||
TaskName string
|
Task remote.Task
|
||||||
TaskTags []string
|
TaskTags []string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -38,8 +38,8 @@ func TestPackableQueuedOp(t *testing.T) {
|
||||||
cases := []*QueuedOp{
|
cases := []*QueuedOp{
|
||||||
&QueuedOp{
|
&QueuedOp{
|
||||||
Op: remote.NEW,
|
Op: remote.NEW,
|
||||||
ListID: "1",
|
List: remote.List{ID: "1"},
|
||||||
TaskName: "name",
|
Task: remote.Task{Title: "title"},
|
||||||
TaskTags: []string{"some", "tags"},
|
TaskTags: []string{"some", "tags"},
|
||||||
},
|
},
|
||||||
&QueuedOp{},
|
&QueuedOp{},
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,7 @@ func (c *Client) ParseArgs() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) Lists() ([]List, error) {
|
func (c *Client) Lists() (Lists, error) {
|
||||||
client, err := NewHTTP(c.config.remote, c.config.password)
|
client, err := NewHTTP(c.config.remote, c.config.password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -63,10 +63,10 @@ func (c *Client) Lists() ([]List, error) {
|
||||||
} else if err := json.NewDecoder(resp.Body).Decode(&lists); err != nil {
|
} else if err := json.NewDecoder(resp.Body).Decode(&lists); err != nil {
|
||||||
return nil, fmt.Errorf("cannot read lists: %v", err)
|
return nil, fmt.Errorf("cannot read lists: %v", err)
|
||||||
}
|
}
|
||||||
return lists.Lists, nil
|
return Lists(lists.Lists), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) Tasks(list List) ([]Task, error) {
|
func (c *Client) Tasks(list List) (Tasks, error) {
|
||||||
client, err := NewHTTP(c.config.remote, c.config.password)
|
client, err := NewHTTP(c.config.remote, c.config.password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -77,7 +77,7 @@ func (c *Client) Tasks(list List) ([]Task, error) {
|
||||||
} else if err := json.NewDecoder(resp.Body).Decode(&tasks); err != nil {
|
} else if err := json.NewDecoder(resp.Body).Decode(&tasks); err != nil {
|
||||||
return nil, fmt.Errorf("cannot read tasks: %v", err)
|
return nil, fmt.Errorf("cannot read tasks: %v", err)
|
||||||
}
|
}
|
||||||
return tasks.Tasks, nil
|
return Tasks(tasks.Tasks), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) NewTask(list List, task Task, tags string) error {
|
func (c *Client) NewTask(list List, task Task, tags string) error {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,10 @@
|
||||||
package remote
|
package remote
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/gob"
|
||||||
|
)
|
||||||
|
|
||||||
type loadListsResponse struct {
|
type loadListsResponse struct {
|
||||||
Lists []List `json:"list"`
|
Lists []List `json:"list"`
|
||||||
}
|
}
|
||||||
|
|
@ -8,3 +13,41 @@ type List struct {
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Lists []List
|
||||||
|
|
||||||
|
func (l *List) Encode() ([]byte, error) {
|
||||||
|
buf := bytes.NewBuffer(nil)
|
||||||
|
enc := gob.NewEncoder(buf)
|
||||||
|
err := enc.Encode(*l)
|
||||||
|
return buf.Bytes(), err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *List) Decode(b []byte) error {
|
||||||
|
buf := bytes.NewBuffer(b)
|
||||||
|
enc := gob.NewDecoder(buf)
|
||||||
|
err := enc.Decode(l)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ls *Lists) Encode() ([]byte, error) {
|
||||||
|
buf := bytes.NewBuffer(nil)
|
||||||
|
enc := gob.NewEncoder(buf)
|
||||||
|
err := enc.Encode(*ls)
|
||||||
|
return buf.Bytes(), err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ls *Lists) Decode(b []byte) error {
|
||||||
|
buf := bytes.NewBuffer(b)
|
||||||
|
enc := gob.NewDecoder(buf)
|
||||||
|
err := enc.Decode(ls)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ls Lists) Length() int {
|
||||||
|
return len(ls.ListArray())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ls Lists) ListArray() []List {
|
||||||
|
return []List(ls)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,46 @@
|
||||||
|
package remote
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestListEncodeDecode(t *testing.T) {
|
||||||
|
L := &List{
|
||||||
|
ID: "id",
|
||||||
|
Name: "name",
|
||||||
|
}
|
||||||
|
|
||||||
|
b, err := L.Encode()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("cannot encode list: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
M := &List{}
|
||||||
|
if err := M.Decode(b); err != nil {
|
||||||
|
t.Fatalf("cannot decode list: %v", err)
|
||||||
|
} else if *L != *M {
|
||||||
|
t.Fatalf("wrong decode list: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestListsEncodeDecode(t *testing.T) {
|
||||||
|
L := Lists([]List{List{
|
||||||
|
ID: "id",
|
||||||
|
Name: "name",
|
||||||
|
}})
|
||||||
|
LS := &L
|
||||||
|
|
||||||
|
b, err := LS.Encode()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("cannot encode list: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
M := Lists([]List{})
|
||||||
|
MS := &M
|
||||||
|
if err := MS.Decode(b); err != nil {
|
||||||
|
t.Fatalf("cannot decode list: %v", err)
|
||||||
|
} else if fmt.Sprintf("%v", *LS) != fmt.Sprintf("%v", *MS) {
|
||||||
|
t.Fatalf("wrong decode list: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,10 @@
|
||||||
package remote
|
package remote
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/gob"
|
||||||
|
)
|
||||||
|
|
||||||
type loadTasksResponse struct {
|
type loadTasksResponse struct {
|
||||||
Tasks []Task `json:"list"`
|
Tasks []Task `json:"list"`
|
||||||
}
|
}
|
||||||
|
|
@ -9,3 +14,41 @@ type Task struct {
|
||||||
Title string `json:"title"`
|
Title string `json:"title"`
|
||||||
Complete int `json:"compl"`
|
Complete int `json:"compl"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Tasks []Task
|
||||||
|
|
||||||
|
func (t *Task) Encode() ([]byte, error) {
|
||||||
|
buf := bytes.NewBuffer(nil)
|
||||||
|
enc := gob.NewEncoder(buf)
|
||||||
|
err := enc.Encode(*t)
|
||||||
|
return buf.Bytes(), err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Task) Decode(b []byte) error {
|
||||||
|
buf := bytes.NewBuffer(b)
|
||||||
|
enc := gob.NewDecoder(buf)
|
||||||
|
err := enc.Decode(t)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ts *Tasks) Encode() ([]byte, error) {
|
||||||
|
buf := bytes.NewBuffer(nil)
|
||||||
|
enc := gob.NewEncoder(buf)
|
||||||
|
err := enc.Encode(*ts)
|
||||||
|
return buf.Bytes(), err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ts *Tasks) Decode(b []byte) error {
|
||||||
|
buf := bytes.NewBuffer(b)
|
||||||
|
enc := gob.NewDecoder(buf)
|
||||||
|
err := enc.Decode(ts)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ts Tasks) Length() int {
|
||||||
|
return len(ts.TaskArray())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ts Tasks) TaskArray() []Task {
|
||||||
|
return []Task(ts)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
package remote
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestTaskEncodeDecode(t *testing.T) {
|
||||||
|
L := &Task{
|
||||||
|
ID: "id",
|
||||||
|
Title: "title",
|
||||||
|
Complete: 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
b, err := L.Encode()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("cannot encode task: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
M := &Task{}
|
||||||
|
if err := M.Decode(b); err != nil {
|
||||||
|
t.Fatalf("cannot decode task: %v", err)
|
||||||
|
} else if *L != *M {
|
||||||
|
t.Fatalf("wrong decode task: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTasksEncodeDecode(t *testing.T) {
|
||||||
|
L := Tasks([]Task{Task{
|
||||||
|
ID: "id",
|
||||||
|
Title: "title",
|
||||||
|
Complete: 0,
|
||||||
|
}})
|
||||||
|
LS := &L
|
||||||
|
|
||||||
|
b, err := LS.Encode()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("cannot encode task: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
M := Tasks([]Task{})
|
||||||
|
MS := &M
|
||||||
|
if err := MS.Decode(b); err != nil {
|
||||||
|
t.Fatalf("cannot decode task: %v", err)
|
||||||
|
} else if fmt.Sprintf("%v", *LS) != fmt.Sprintf("%v", *MS) {
|
||||||
|
t.Fatalf("wrong decode task: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue