mirror of
https://github.com/dnote/dnote
synced 2026-03-15 06:55:49 +01:00
* Lock in dep * Log v2 edit data when editing * Migrate edit_note actions with incorrect data
376 lines
12 KiB
Go
376 lines
12 KiB
Go
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"log"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"testing"
|
|
|
|
"github.com/pkg/errors"
|
|
|
|
"github.com/dnote/actions"
|
|
"github.com/dnote/cli/core"
|
|
"github.com/dnote/cli/infra"
|
|
"github.com/dnote/cli/testutils"
|
|
"github.com/dnote/cli/utils"
|
|
)
|
|
|
|
var binaryName = "test-dnote"
|
|
|
|
func TestMain(m *testing.M) {
|
|
if err := exec.Command("go", "build", "-o", binaryName).Run(); err != nil {
|
|
log.Print(errors.Wrap(err, "Failed to build a binary").Error())
|
|
os.Exit(1)
|
|
}
|
|
|
|
os.Exit(m.Run())
|
|
}
|
|
|
|
func newDnoteCmd(ctx infra.DnoteCtx, arg ...string) (*exec.Cmd, *bytes.Buffer, error) {
|
|
var stderr bytes.Buffer
|
|
|
|
binaryPath, err := filepath.Abs(binaryName)
|
|
if err != nil {
|
|
return &exec.Cmd{}, &stderr, errors.Wrap(err, "Failed to get the absolute path to the test binary")
|
|
}
|
|
|
|
cmd := exec.Command(binaryPath, arg...)
|
|
cmd.Env = []string{fmt.Sprintf("DNOTE_DIR=%s", ctx.DnoteDir), fmt.Sprintf("DNOTE_HOME_DIR=%s", ctx.HomeDir)}
|
|
cmd.Stderr = &stderr
|
|
|
|
return cmd, &stderr, nil
|
|
}
|
|
|
|
func runDnoteCmd(ctx infra.DnoteCtx, arg ...string) {
|
|
cmd, stderr, err := newDnoteCmd(ctx, arg...)
|
|
if err != nil {
|
|
panic(errors.Wrap(err, "Failed to get command").Error())
|
|
}
|
|
|
|
if err := cmd.Run(); err != nil {
|
|
panic(errors.Wrapf(err, "Failed to run command %s", stderr.String()))
|
|
}
|
|
}
|
|
|
|
func TestInit(t *testing.T) {
|
|
// Setup
|
|
ctx := testutils.InitCtx("./tmp")
|
|
testutils.SetupTmp(ctx)
|
|
defer testutils.ClearTmp(ctx)
|
|
|
|
// Execute
|
|
runDnoteCmd(ctx)
|
|
|
|
// Test
|
|
if !utils.FileExists(ctx.DnoteDir) {
|
|
t.Errorf("dnote directory was not initialized")
|
|
}
|
|
if !utils.FileExists(fmt.Sprintf("%s/%s", ctx.DnoteDir, core.DnoteFilename)) {
|
|
t.Errorf("dnote file was not initialized")
|
|
}
|
|
if !utils.FileExists(fmt.Sprintf("%s/%s", ctx.DnoteDir, core.ConfigFilename)) {
|
|
t.Errorf("config file was not initialized")
|
|
}
|
|
if !utils.FileExists(fmt.Sprintf("%s/%s", ctx.DnoteDir, core.TimestampFilename)) {
|
|
t.Errorf("timestamp file was not initialized")
|
|
}
|
|
if !utils.FileExists(fmt.Sprintf("%s/%s", ctx.DnoteDir, core.ActionFilename)) {
|
|
t.Errorf("action file was not initialized")
|
|
}
|
|
}
|
|
|
|
func TestAdd_NewBook_ContentFlag(t *testing.T) {
|
|
// Setup
|
|
ctx := testutils.InitCtx("./tmp")
|
|
testutils.SetupTmp(ctx)
|
|
defer testutils.ClearTmp(ctx)
|
|
|
|
// Execute
|
|
runDnoteCmd(ctx, "add", "js", "-c", "foo")
|
|
|
|
// Test
|
|
dnote, err := core.GetDnote(ctx)
|
|
if err != nil {
|
|
t.Fatal(errors.Wrap(err, "Failed to get dnote"))
|
|
}
|
|
actionSlice, err := core.ReadActionLog(ctx)
|
|
if err != nil {
|
|
t.Fatal(errors.Wrap(err, "Failed to read actions"))
|
|
}
|
|
|
|
if len(actionSlice) != 2 {
|
|
t.Fatalf("action log length mismatch. got %d", len(actionSlice))
|
|
}
|
|
|
|
book := dnote["js"]
|
|
note := book.Notes[0]
|
|
bookAction := actionSlice[0]
|
|
noteAction := actionSlice[1]
|
|
|
|
var noteActionData actions.AddNoteDataV1
|
|
var bookActionData actions.AddBookDataV1
|
|
err = json.Unmarshal(bookAction.Data, &bookActionData)
|
|
if err != nil {
|
|
log.Fatalf("Failed to unmarshal the action data: %s", err)
|
|
}
|
|
err = json.Unmarshal(noteAction.Data, ¬eActionData)
|
|
if err != nil {
|
|
log.Fatalf("Failed to unmarshal the action data: %s", err)
|
|
}
|
|
|
|
testutils.AssertEqual(t, bookAction.Type, actions.ActionAddBook, "bookAction type mismatch")
|
|
testutils.AssertNotEqual(t, bookActionData.BookName, "", "bookAction data note_uuid mismatch")
|
|
testutils.AssertNotEqual(t, bookAction.Timestamp, 0, "bookAction timestamp mismatch")
|
|
testutils.AssertEqual(t, noteAction.Type, actions.ActionAddNote, "noteAction type mismatch")
|
|
testutils.AssertEqual(t, noteActionData.Content, "foo", "noteAction data name mismatch")
|
|
testutils.AssertNotEqual(t, noteActionData.NoteUUID, nil, "noteAction data note_uuid mismatch")
|
|
testutils.AssertNotEqual(t, noteActionData.BookName, "", "noteAction data note_uuid mismatch")
|
|
testutils.AssertNotEqual(t, noteAction.Timestamp, 0, "noteAction timestamp mismatch")
|
|
testutils.AssertEqual(t, len(book.Notes), 1, "Book should have one note")
|
|
testutils.AssertNotEqual(t, note.UUID, "", "Note should have UUID")
|
|
testutils.AssertEqual(t, note.Content, "foo", "Note content mismatch")
|
|
testutils.AssertNotEqual(t, note.AddedOn, int64(0), "Note added_on mismatch")
|
|
}
|
|
|
|
func TestAdd_ExistingBook_ContentFlag(t *testing.T) {
|
|
// Setup
|
|
ctx := testutils.InitCtx("./tmp")
|
|
testutils.SetupTmp(ctx)
|
|
defer testutils.ClearTmp(ctx)
|
|
|
|
// init files by running root command
|
|
runDnoteCmd(ctx)
|
|
testutils.WriteFile(ctx, "./testutils/fixtures/dnote1.json", "dnote")
|
|
|
|
// Execute
|
|
runDnoteCmd(ctx, "add", "js", "-c", "foo")
|
|
|
|
// Test
|
|
dnote, err := core.GetDnote(ctx)
|
|
if err != nil {
|
|
t.Fatal(errors.Wrap(err, "Failed to get dnote"))
|
|
}
|
|
actionSlice, err := core.ReadActionLog(ctx)
|
|
if err != nil {
|
|
t.Fatal(errors.Wrap(err, "Failed to read actions"))
|
|
}
|
|
|
|
book := dnote["js"]
|
|
action := actionSlice[0]
|
|
|
|
var actionData actions.AddNoteDataV1
|
|
err = json.Unmarshal(action.Data, &actionData)
|
|
if err != nil {
|
|
log.Fatalf("Failed to unmarshal the action data: %s", err)
|
|
}
|
|
|
|
testutils.AssertEqual(t, len(actionSlice), 1, "There should be 1 action")
|
|
testutils.AssertEqual(t, action.Type, actions.ActionAddNote, "action type mismatch")
|
|
testutils.AssertEqual(t, actionData.Content, "foo", "action data name mismatch")
|
|
testutils.AssertNotEqual(t, actionData.NoteUUID, "", "action data note_uuid mismatch")
|
|
testutils.AssertEqual(t, actionData.BookName, "js", "action data book_name mismatch")
|
|
testutils.AssertNotEqual(t, action.Timestamp, 0, "action timestamp mismatch")
|
|
testutils.AssertEqual(t, len(book.Notes), 2, "Book should have one note")
|
|
testutils.AssertNotEqual(t, book.Notes[0].UUID, "", "Note should have UUID")
|
|
testutils.AssertEqual(t, book.Notes[0].Content, "Booleans have toString()", "Note content mismatch")
|
|
testutils.AssertNotEqual(t, book.Notes[1].UUID, "", "Note should have UUID")
|
|
testutils.AssertEqual(t, book.Notes[1].Content, "foo", "Note content mismatch")
|
|
}
|
|
|
|
func TestEdit_ContentFlag(t *testing.T) {
|
|
// Setup
|
|
ctx := testutils.InitCtx("./tmp")
|
|
testutils.SetupTmp(ctx)
|
|
defer testutils.ClearTmp(ctx)
|
|
|
|
// init files by running root command
|
|
runDnoteCmd(ctx)
|
|
testutils.WriteFile(ctx, "./testutils/fixtures/dnote2.json", "dnote")
|
|
|
|
// Execute
|
|
runDnoteCmd(ctx, "edit", "js", "1", "-c", "foo bar")
|
|
|
|
// Test
|
|
dnote, err := core.GetDnote(ctx)
|
|
if err != nil {
|
|
t.Fatal(errors.Wrap(err, "Failed to get dnote"))
|
|
}
|
|
actionSlice, err := core.ReadActionLog(ctx)
|
|
if err != nil {
|
|
t.Fatal(errors.Wrap(err, "Failed to read actions"))
|
|
}
|
|
|
|
book := dnote["js"]
|
|
action := actionSlice[0]
|
|
|
|
var actionData actions.EditNoteDataV2
|
|
err = json.Unmarshal(action.Data, &actionData)
|
|
if err != nil {
|
|
log.Fatalf("Failed to unmarshal the action data: %s", err)
|
|
}
|
|
|
|
testutils.AssertEqual(t, len(actionSlice), 1, "There should be 1 action")
|
|
testutils.AssertEqual(t, action.Type, actions.ActionEditNote, "action type mismatch")
|
|
testutils.AssertEqual(t, action.Schema, 2, "action schema mismatch")
|
|
testutils.AssertEqual(t, *actionData.Content, "foo bar", "action data name mismatch")
|
|
testutils.AssertEqual(t, actionData.FromBook, "js", "action data from_book mismatch")
|
|
if actionData.ToBook != nil {
|
|
t.Errorf("action data to_book mismatch. Expected %+v. Got %+v", nil, actionData.ToBook)
|
|
}
|
|
testutils.AssertEqual(t, actionData.NoteUUID, "f0d0fbb7-31ff-45ae-9f0f-4e429c0c797f", "action data note_uuis mismatch")
|
|
testutils.AssertNotEqual(t, action.Timestamp, 0, "action timestamp mismatch")
|
|
testutils.AssertEqual(t, len(book.Notes), 2, "Book should have one note")
|
|
testutils.AssertEqual(t, book.Notes[0].UUID, "43827b9a-c2b0-4c06-a290-97991c896653", "Note should have UUID")
|
|
testutils.AssertEqual(t, book.Notes[0].Content, "Booleans have toString()", "Note content mismatch")
|
|
testutils.AssertEqual(t, book.Notes[1].UUID, "f0d0fbb7-31ff-45ae-9f0f-4e429c0c797f", "Note should have UUID")
|
|
testutils.AssertEqual(t, book.Notes[1].Content, "foo bar", "Note content mismatch")
|
|
testutils.AssertNotEqual(t, book.Notes[1].EditedOn, int64(0), "Note edited_on mismatch")
|
|
}
|
|
|
|
func TestRemoveNote(t *testing.T) {
|
|
// Setup
|
|
ctx := testutils.InitCtx("./tmp")
|
|
testutils.SetupTmp(ctx)
|
|
defer testutils.ClearTmp(ctx)
|
|
|
|
// init files by running root command
|
|
runDnoteCmd(ctx)
|
|
testutils.WriteFile(ctx, "./testutils/fixtures/dnote3.json", "dnote")
|
|
|
|
// Execute
|
|
cmd, stderr, err := newDnoteCmd(ctx, "remove", "js", "1")
|
|
if err != nil {
|
|
panic(errors.Wrap(err, "Failed to get command"))
|
|
}
|
|
stdin, err := cmd.StdinPipe()
|
|
if err != nil {
|
|
panic(errors.Wrap(err, "Failed to get stdin %s"))
|
|
}
|
|
defer stdin.Close()
|
|
|
|
// Start the program
|
|
err = cmd.Start()
|
|
if err != nil {
|
|
panic(errors.Wrap(err, "Failed to start command"))
|
|
}
|
|
|
|
// confirm
|
|
_, err = io.WriteString(stdin, "y\n")
|
|
if err != nil {
|
|
panic(errors.Wrap(err, "Failed to write to stdin"))
|
|
}
|
|
|
|
err = cmd.Wait()
|
|
if err != nil {
|
|
panic(errors.Wrapf(err, "Failed to run command %s", stderr.String()))
|
|
}
|
|
|
|
// Test
|
|
dnote, err := core.GetDnote(ctx)
|
|
if err != nil {
|
|
t.Fatal(errors.Wrap(err, "Failed to get dnote"))
|
|
}
|
|
actionSlice, err := core.ReadActionLog(ctx)
|
|
if err != nil {
|
|
t.Fatal(errors.Wrap(err, "Failed to read actions"))
|
|
}
|
|
|
|
if len(actionSlice) != 1 {
|
|
t.Fatalf("action log length mismatch. got %d", len(actionSlice))
|
|
}
|
|
|
|
book := dnote["js"]
|
|
otherBook := dnote["linux"]
|
|
action := actionSlice[0]
|
|
|
|
var actionData actions.RemoveNoteDataV1
|
|
err = json.Unmarshal(action.Data, &actionData)
|
|
if err != nil {
|
|
log.Fatalf("Failed to unmarshal the action data: %s", err)
|
|
}
|
|
|
|
testutils.AssertEqual(t, len(actionSlice), 1, "There should be 1 action")
|
|
testutils.AssertEqual(t, action.Type, actions.ActionRemoveNote, "action type mismatch")
|
|
testutils.AssertEqual(t, actionData.NoteUUID, "f0d0fbb7-31ff-45ae-9f0f-4e429c0c797f", "action data note_uuid mismatch")
|
|
testutils.AssertEqual(t, actionData.BookName, "js", "action data book_name mismatch")
|
|
testutils.AssertNotEqual(t, action.Timestamp, 0, "action timestamp mismatch")
|
|
testutils.AssertEqual(t, len(book.Notes), 1, "Book should have one note")
|
|
testutils.AssertEqual(t, len(otherBook.Notes), 1, "Other book should have one note")
|
|
testutils.AssertEqual(t, book.Notes[0].UUID, "43827b9a-c2b0-4c06-a290-97991c896653", "Note should have UUID")
|
|
testutils.AssertEqual(t, book.Notes[0].Content, "Booleans have toString()", "Note content mismatch")
|
|
}
|
|
|
|
func TestRemoveBook(t *testing.T) {
|
|
// Setup
|
|
ctx := testutils.InitCtx("./tmp")
|
|
testutils.SetupTmp(ctx)
|
|
defer testutils.ClearTmp(ctx)
|
|
|
|
// init files by running root command
|
|
runDnoteCmd(ctx)
|
|
testutils.WriteFile(ctx, "./testutils/fixtures/dnote3.json", "dnote")
|
|
|
|
// Execute
|
|
cmd, stderr, err := newDnoteCmd(ctx, "remove", "-b", "js")
|
|
if err != nil {
|
|
panic(errors.Wrap(err, "Failed to get command"))
|
|
}
|
|
stdin, err := cmd.StdinPipe()
|
|
if err != nil {
|
|
panic(errors.Wrap(err, "Failed to get stdin %s"))
|
|
}
|
|
defer stdin.Close()
|
|
|
|
// Start the program
|
|
err = cmd.Start()
|
|
if err != nil {
|
|
panic(errors.Wrap(err, "Failed to start command"))
|
|
}
|
|
|
|
// confirm
|
|
_, err = io.WriteString(stdin, "y\n")
|
|
if err != nil {
|
|
panic(errors.Wrap(err, "Failed to write to stdin"))
|
|
}
|
|
|
|
err = cmd.Wait()
|
|
if err != nil {
|
|
panic(errors.Wrapf(err, "Failed to run command %s", stderr.String()))
|
|
}
|
|
|
|
// Test
|
|
dnote, err := core.GetDnote(ctx)
|
|
if err != nil {
|
|
t.Fatal(errors.Wrap(err, "Failed to get dnote"))
|
|
}
|
|
actionSlice, err := core.ReadActionLog(ctx)
|
|
if err != nil {
|
|
t.Fatal(errors.Wrap(err, "Failed to read actions"))
|
|
}
|
|
|
|
if len(actionSlice) != 1 {
|
|
t.Fatalf("action log length mismatch. got %d", len(actionSlice))
|
|
}
|
|
|
|
book := dnote["linux"]
|
|
action := actionSlice[0]
|
|
|
|
var actionData actions.RemoveBookDataV1
|
|
err = json.Unmarshal(action.Data, &actionData)
|
|
if err != nil {
|
|
log.Fatalf("Failed to unmarshal the action data: %s", err)
|
|
}
|
|
|
|
testutils.AssertEqual(t, len(actionSlice), 1, "There should be 1 action")
|
|
testutils.AssertEqual(t, action.Type, actions.ActionRemoveBook, "action type mismatch")
|
|
testutils.AssertEqual(t, actionData.BookName, "js", "action data name mismatch")
|
|
testutils.AssertNotEqual(t, action.Timestamp, 0, "action timestamp mismatch")
|
|
testutils.AssertEqual(t, len(dnote), 1, "There should be 1 book")
|
|
testutils.AssertEqual(t, book.Name, "linux", "Remaining book name mismatch")
|
|
testutils.AssertEqual(t, len(book.Notes), 1, "Remaining book should have one note")
|
|
}
|