func newTestTask(t *testing.T, db data.DB, u *models.User) *models.Task { tsk := new(models.Task) tsk.SetID(db.NewID()) tsk.CreatedAt = models.TimestampFrom(time.Now()) tsk.OwnerId = u.ID().String() tsk.UpdatedAt = models.TimestampFrom(time.Now()) if err := db.Save(tsk); err != nil { t.Fatalf("Error newTestTask: %s", err) } return tsk }
// --- `elos todo today` {{{ func TestTodoToday(t *testing.T) { ui, db, user, c := newMockTodoCommand(t) // load a task into the db tsk := newTestTask(t, db, user) taskName := "Take out the trash" tsk.Name = taskName task.StopAndComplete(tsk) if err := db.Save(tsk); err != nil { t.Fatal(err) } tsk2 := newTestTask(t, db, user) task2Name := "shouldn't show up" tsk2.Name = task2Name tsk2.CompletedAt = models.TimestampFrom(time.Now().Add(-48 * time.Hour)) if err := db.Save(tsk2); err != nil { t.Fatal(err) } t.Log("running: `elos todo today`") code := c.Run([]string{"today"}) t.Log("command 'today' terminated") errput := ui.ErrorWriter.String() output := ui.OutputWriter.String() t.Logf("Error output:\n %s", errput) t.Logf("Output:\n %s", output) // verify there were no errors if errput != "" { t.Fatalf("Expected no error output, got: %s", errput) } // verify success if code != success { t.Fatalf("Expected successful exit code along with empty error output.") } // verify some of the output if !strings.Contains(output, taskName) { t.Fatalf("Output should have contained a task we completed today: %s", taskName) } if strings.Contains(output, task2Name) { t.Fatalf("Output should not have contained: '%s', the name of a task completed 2 days ago", task2Name) } }
// promptNewTask implements the process of creating a task using text // input and output // // Use for creating a new task, which promptNewTask returns a handle to. // // promptNewTask adds the task to c.tasks. // func (c *TodoCommand) promptNewTask() (task *models.Task, err error) { var ( hasDeadline bool hasPrereqs bool ) task = new(models.Task) task.SetID(c.DB.NewID()) task.CreatedAt = models.TimestampFrom(time.Now()) task.OwnerId = c.UserID if task.Name, err = stringInput(c.UI, "Name:"); err != nil { return } if hasDeadline, err = yesNo(c.UI, "Does it have a deadline?"); err != nil { return } else if hasDeadline { if task.DeadlineAt, err = timestamp(dateInput(c.UI, "Deadline:")); err != nil { return } } if hasPrereqs, err = yesNo(c.UI, "Does it have any prerequisites?"); err != nil { return } else if hasPrereqs { var currentTaskPrereq, newTaskPrereq bool if len(c.tasks) > 0 { c.printTaskList() if currentTaskPrereq, err = yesNo(c.UI, "Any dependencies that are current?"); err != nil { return } else if currentTaskPrereq { for currentTaskPrereq { var indexOfCurrent int if indexOfCurrent, err = intInput(c.UI, "Which number?"); err != nil { return } if indexOfCurrent < 0 || indexOfCurrent > len(c.tasks)-1 { c.UI.Warn("That isn't a valid index") continue } addId := c.tasks[indexOfCurrent].Id for _, id := range task.PrerequisiteIds { if id == addId { goto noadd } } task.PrerequisiteIds = append(task.PrerequisiteIds, addId) noadd: if currentTaskPrereq, err = yesNo(c.UI, "Any more current prereqs?"); err != nil { return } } } } if newTaskPrereq, err = yesNo(c.UI, "Any dependencies that are new tasks?"); err != nil { return } else if newTaskPrereq { var newTask *models.Task for newTaskPrereq { if newTask, err = c.promptNewTask(); err != nil { return } task.PrerequisiteIds = append(task.PrerequisiteIds, newTask.Id) if newTaskPrereq, err = yesNo(c.UI, "Any more new prereqs?"); err != nil { return } } } } task.UpdatedAt = models.TimestampFrom(time.Now()) // if successful save if err = c.DB.Save(task); err == nil { c.tasks = append(c.tasks, task) c.UI.Output("Task created") } return }
func timestamp(t time.Time, err error) (*models.Timestamp, error) { return models.TimestampFrom(t), err }
func TestRecords(t *testing.T) { cases := map[string]struct { args []string code int in, err, out []byte prior, posterior data.State }{ // elos records kinds {{{ "elos records kinds": { args: []string{"kinds"}, out: []byte(strings.Join(apply(s(models.Kinds), func(s string) string { return "* " + s }), "\n") + "\n"), prior: data.State{ models.Kind_USER: []*data.Record{ &data.Record{ Kind: models.Kind_USER, User: &models.User{ Id: "1", }, }, }, models.Kind_CREDENTIAL: []*data.Record{ &data.Record{ Kind: models.Kind_CREDENTIAL, Credential: &models.Credential{ Id: "2", Type: models.Credential_PASSWORD, Public: "pu", Private: "pr", OwnerId: "1", }, }, }, }, }, // }}} // elos records count {{{ "elos records count": { args: []string{"count"}, in: []byte("SESSION\n"), out: []byte("Which kind? [string]:2\n"), prior: data.State{ models.Kind_USER: []*data.Record{ &data.Record{ Kind: models.Kind_USER, User: &models.User{ Id: "1", }, }, &data.Record{ Kind: models.Kind_USER, User: &models.User{ Id: "2", }, }, }, models.Kind_CREDENTIAL: []*data.Record{ &data.Record{ Kind: models.Kind_CREDENTIAL, Credential: &models.Credential{ Id: "3", Type: models.Credential_PASSWORD, Public: "pu", Private: "pr", OwnerId: "1", }, }, &data.Record{ Kind: models.Kind_CREDENTIAL, Credential: &models.Credential{ Id: "4", Type: models.Credential_PASSWORD, Public: "2pu", Private: "pr", OwnerId: "2", }, }, }, models.Kind_SESSION: []*data.Record{ &data.Record{ Kind: models.Kind_SESSION, Session: &models.Session{ Id: "5", AccessToken: "non-empty", ExpiresAt: models.TimestampFrom(time.Now().Add(5 * time.Minute)).WithoutNanos(), OwnerId: "1", CredentialId: "3", }, }, &data.Record{ Kind: models.Kind_SESSION, Session: &models.Session{ Id: "4", AccessToken: "non-empty", ExpiresAt: models.TimestampFrom(time.Now().Add(5 * time.Minute)).WithoutNanos(), OwnerId: "1", CredentialId: "3", }, }, &data.Record{ Kind: models.Kind_SESSION, Session: &models.Session{ Id: "4", AccessToken: "non-empty", ExpiresAt: models.TimestampFrom(time.Now().Add(5 * time.Minute)).WithoutNanos(), OwnerId: "2", CredentialId: "4", }, }, }, }, }, // }}} // TODO(nclandolfi) test query and changes } for n, c := range cases { t.Run(n, func(t *testing.T) { db := mem.NewDB() dbc, conn, err := data.DBBothLocal(db) if err != nil { t.Fatalf("data.DBBothLocal error: %v", err) } defer conn.Close() if err := data.Seed(context.Background(), dbc, c.prior); err != nil { t.Fatalf("data.Seed error: %v", err) } ui := &cli.MockUi{ InputReader: bytes.NewBuffer(c.in), } cmd := &RecordsCommand{ UI: ui, UserID: c.prior[models.Kind_USER][0].User.Id, DBClient: dbc, } if got, want := cmd.Run(c.args), c.code; got != want { t.Log(ui.ErrorWriter.String()) t.Fatalf("cmd.Run(%v): got %d, want %d", c.args, got, want) } if got, want := ui.ErrorWriter.String(), string(c.err); got != want { t.Fatalf("ui.ErrorWriter.String(): got %q, want %q", got, want) } if got, want := ui.OutputWriter.String(), string(c.out); got != want { t.Fatalf("ui.OutputWriter.String(): got %q, want %q", got, want) } finalState := c.prior if c.posterior != nil { finalState = c.posterior } if got, want := data.CompareState(context.Background(), dbc, finalState), error(nil); got != want { t.Fatalf("data.CompareState: got %v, want %v", got, want) } }) } }
// TestTodoFix tests the `fix` subcommand func TestTodoFix(t *testing.T) { ui, db, user, c := newMockTodoCommand(t) // load a task into the db task := newTestTask(t, db, user) task.Name = "Take out the trash" task.DeadlineAt = models.TimestampFrom(time.Now().Add(-36 * time.Hour)) if err := db.Save(task); err != nil { t.Fatal(err) } // load input input := strings.Join([]string{ "2020", // year "1", // month "1", // day "12", // hour "0", // minute }, "\n") ui.InputReader = bytes.NewBufferString(input) t.Log("running: `elos todo fix`") code := c.Run([]string{"fix"}) t.Log("command 'fix' terminated") errput := ui.ErrorWriter.String() output := ui.OutputWriter.String() t.Logf("Error output:\n %s", errput) t.Logf("Output:\n %s", output) // verify there were no errors if errput != "" { t.Fatalf("Expected no error output, got: %s", errput) } // verify success if code != success { t.Fatalf("Expected successful exit code along with empty error output.") } // verify some of the output if !strings.Contains(output, task.Name) { t.Fatalf("Output should have contained a the out of date task's name") } if !strings.Contains(output, "New Deadline") { t.Fatalf("Output should have asked for a new deadline") } t.Log("Checking that the task's deadline was changed") if err := db.PopulateByID(task); err != nil { t.Fatal(err) } t.Logf("Here's the task:\n%+v", task) if !task.DeadlineAt.Time().After(time.Now()) { t.Fatalf("Expected the task's deadline to be after now") } }
func TestCal(t *testing.T) { //TODO(nclandolfi): fix test t.Skip() NOW := time.Now() cases := map[string]struct { prior data.State userID string args []string input io.Reader code int errput string output string // IF posterior is nil, prior will be used posterior data.State }{ "simple cal week": { prior: data.State{ models.Kind_USER: []*data.Record{ &data.Record{ Kind: models.Kind_USER, User: &models.User{ Id: "1", }, }, }, models.Kind_CREDENTIAL: []*data.Record{ &data.Record{ Kind: models.Kind_CREDENTIAL, Credential: &models.Credential{ Id: "2", OwnerId: "1", Type: models.Credential_PASSWORD, Public: "pu", Private: "pr", }, }, }, models.Kind_FIXTURE: []*data.Record{ &data.Record{ Kind: models.Kind_FIXTURE, Fixture: &models.Fixture{ Id: "3", OwnerId: "1", StartTime: models.TimestampFrom(NOW.Add(1 * time.Hour)), EndTime: models.TimestampFrom(NOW.Add(2 * time.Hour)), }, }, }, }, input: new(bytes.Buffer), userID: "1", args: []string{"week"}, }, } for n, c := range cases { t.Run(n, func(t *testing.T) { db := mem.NewDB() dbc, conn, err := data.DBBothLocal(db) if err != nil { t.Fatalf("data.DBBothLocal error: %v", err) } defer conn.Close() if err := data.Seed(context.Background(), dbc, c.prior); err != nil { t.Fatalf("data.Seed error: %v", err) } if c.input == nil { t.Fatal("c.input must be non-nil") } ui := &cli.MockUi{ InputReader: c.input, } cmd := &CalCommand{ UI: ui, UserID: c.userID, DB: data.DB(dbc), } if got, want := cmd.Run(c.args), c.code; got != want { t.Log(ui.ErrorWriter.String()) t.Fatalf("cmd.Run(%v): got %d, want %d", c.args, got, want) } if got, want := ui.ErrorWriter.String(), c.errput; got != want { t.Fatalf("ui.ErrorWriter.String(): got %q, want %q", got, want) } if got, want := ui.OutputWriter.String(), c.output; got != want { t.Fatalf("ui.OutputWriter.String(): got %q, want %q", got, want) } finalState := c.prior if c.posterior != nil { finalState = c.posterior } if got, want := data.CompareState(context.Background(), dbc, finalState), error(nil); got != want { t.Fatalf("data.CompareState: got %v, want %v", got, want) } }) } }