Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cmd/things/add_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1124,7 +1124,7 @@ func TestAddInvalidRefusedBeforeTagsCreated(t *testing.T) {
// Things understood gives the item a date, which the read-back cannot
// check, so the add is reported not confirmed (whenPlaced).
func TestAddWhenPhraseIgnored(t *testing.T) {
dated := "start = 1, startDate = " + strconv.Itoa(int(model.ThingsDateFromTime(time.Now().AddDate(0, 0, 3))))
dated := "start = 1, startDate = " + strconv.Itoa(int(model.ThingsDateFromTime(time.Now()).AddDays(3)))
cases := []struct {
name string
extra string
Expand Down
5 changes: 4 additions & 1 deletion cmd/things/edit_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -331,7 +331,7 @@ func TestEditCertainNoOpSkipsTheWait(t *testing.T) {
deadline := int(model.ThingsDateFromTime(time.Date(2026, 10, 15, 0, 0, 0, 0, time.Local)))
day := func(offset int) string { return now.AddDate(0, 0, offset).Format("2006-01-02") }
dayInt := func(offset int) string {
return strconv.Itoa(int(model.ThingsDateFromTime(now.AddDate(0, 0, offset))))
return strconv.Itoa(int(model.ThingsDateFromTime(now).AddDays(offset)))
}

cases := []struct {
Expand Down Expand Up @@ -573,6 +573,9 @@ func TestEditReadsTagListOnce(t *testing.T) {
t.Fatalf("apply %q: %v", stmt, err)
}
}
if err := rows.Err(); err != nil {
t.Fatalf("read schema: %v", err)
}
_ = rows.Close()
fx := dbtest.NewFixture(t, sqlDB)
fx.Todo("one-1", "Post letter", 1)
Expand Down
2 changes: 1 addition & 1 deletion cmd/things/importcreate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1238,7 +1238,7 @@ func TestImportNestedInUpdateNotWarned(t *testing.T) {
func TestImportChecksWhen(t *testing.T) {
past := time.Now().AddDate(0, 0, -4).Format("2006-01-02")
today := "start = 1, startDate = " + strconv.Itoa(int(model.ThingsDateFromTime(testNow)))
tomorrow := "start = 2, startDate = " + strconv.Itoa(int(model.ThingsDateFromTime(testNow.AddDate(0, 0, 1))))
tomorrow := "start = 2, startDate = " + strconv.Itoa(int(model.ThingsDateFromTime(testNow).AddDays(1)))
for _, tc := range []struct {
name string
attrs string
Expand Down
14 changes: 7 additions & 7 deletions cmd/things/when_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ func TestPlaceWhen(t *testing.T) {
func TestWhenUnchangedTime(t *testing.T) {
now := time.Date(2026, 10, 7, 15, 0, 0, 0, time.Local)
today := model.ThingsDateFromTime(now)
tomorrow := model.ThingsDateFromTime(now.AddDate(0, 0, 1))
tomorrow := model.ThingsDateFromTime(now).AddDays(1)
reminder := func(min int, err error) func() (int, error) { return func() (int, error) { return min, err } }
cases := []struct {
name string
Expand Down Expand Up @@ -298,7 +298,7 @@ func TestPlaceWhenNearOffsetChange(t *testing.T) {
func TestEditUnmovedRowAcceptsEitherOutcome(t *testing.T) {
now := testNow
today := int(model.ThingsDateFromTime(now))
old := int(model.ThingsDateFromTime(now.AddDate(0, 0, -3)))
old := int(model.ThingsDateFromTime(now).AddDays(-3))
past := now.AddDate(0, 0, -1).Format("2006-01-02")
type row struct {
typ model.TaskType
Expand Down Expand Up @@ -376,7 +376,7 @@ func TestEditUnmovedRowAcceptsEitherOutcome(t *testing.T) {
func TestEditUnmovedRowWithOtherFieldsNeedsAChange(t *testing.T) {
fastVerify(t)
database, sqlDB := seedWritable(t)
old := int(model.ThingsDateFromTime(testNow.AddDate(0, 0, -3)))
old := int(model.ThingsDateFromTime(testNow).AddDays(-3))
if _, err := sqlDB.Exec(`UPDATE TMTask SET start = 2, startDate = ?, startBucket = 0 WHERE uuid = 'one-1'`, old); err != nil {
t.Fatal(err)
}
Expand All @@ -399,7 +399,7 @@ func TestEditUnmovedRowWithOtherFieldsNeedsAChange(t *testing.T) {
// the dropping stub fails it unless the edit skips the read-back wait.
func TestEditCarriedOverRow(t *testing.T) {
today := int(model.ThingsDateFromTime(testNow))
yesterday := int(model.ThingsDateFromTime(testNow.AddDate(0, 0, -1)))
yesterday := int(model.ThingsDateFromTime(testNow).AddDays(-1))
todayDate := testNow.Format("2006-01-02")
const reminder = 1207959552
seed := func(t *testing.T, sqlDB *sql.DB, start, date, bucket int, reminder any) {
Expand Down Expand Up @@ -614,8 +614,8 @@ func TestEditCarriedOverRow(t *testing.T) {
// part of the day, only for a place that is today.
func TestWhenPlaceHoldsCarriedOver(t *testing.T) {
today := model.ThingsDateFromTime(testNow)
yesterday := model.ThingsDateFromTime(testNow.AddDate(0, 0, -1))
tomorrow := model.ThingsDateFromTime(testNow.AddDate(0, 0, 1))
yesterday := model.ThingsDateFromTime(testNow).AddDays(-1)
tomorrow := model.ThingsDateFromTime(testNow).AddDays(1)
for _, tc := range []struct {
name string
place whenPlace
Expand Down Expand Up @@ -653,7 +653,7 @@ func TestWhenPlaceHoldsCarriedOver(t *testing.T) {
// certain no-op: --when today on a to-do in the day part with no reminder.
// The rest are sent and read back.
func TestWhenUnchangedCarriedOver(t *testing.T) {
yesterday := model.ThingsDateFromTime(testNow.AddDate(0, 0, -1))
yesterday := model.ThingsDateFromTime(testNow).AddDays(-1)
noReminder := func() (int, error) { return reminderNone, nil }
at := func(min int) func() (int, error) { return func() (int, error) { return min, nil } }
later := testNow.Add(2 * time.Hour)
Expand Down
8 changes: 4 additions & 4 deletions internal/db/membership_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ func listSet(t *testing.T, d *DB, view string, opts TaskFilter) []string {
func TestDeadlineProjectInTodayAndUpcoming(t *testing.T) {
d, fx := newFixture(t)
today := int64(model.ThingsDateFromTime(testNow))
earlier := int64(model.ThingsDateFromTime(testNow.AddDate(0, 0, -2)))
later := int64(model.ThingsDateFromTime(testNow.AddDate(0, 0, 3)))
earlier := int64(model.ThingsDateFromTime(testNow).AddDays(-2))
later := int64(model.ThingsDateFromTime(testNow).AddDays(3))

fx.Project("p-due-today", "Due today", 1, anytime(), deadline(today))
fx.Project("p-overdue", "Overdue", 2, anytime(), deadline(earlier))
Expand Down Expand Up @@ -54,7 +54,7 @@ func TestDeadlineProjectInTodayAndUpcoming(t *testing.T) {
func TestSomedayDeadlineInUpcomingAndToday(t *testing.T) {
d, fx := newFixture(t)
today := int64(model.ThingsDateFromTime(testNow))
later := int64(model.ThingsDateFromTime(testNow.AddDate(0, 0, 3)))
later := int64(model.ThingsDateFromTime(testNow).AddDays(3))

fx.Todo("t-someday-later", "Someday to-do due later", 1, someday(), deadline(later))
fx.Project("p-someday-later", "Someday project due later", 2, someday(), deadline(later))
Expand Down Expand Up @@ -199,7 +199,7 @@ func TestSearchSkipsTrashedProjectChildren(t *testing.T) {
// untrashedParent. Pinned here so search and the lists cannot drift apart.
func TestListViewsSkipTrashedProjectChildren(t *testing.T) {
d, fx := newFixture(t)
later := int64(model.ThingsDateFromTime(testNow.AddDate(0, 0, 3)))
later := int64(model.ThingsDateFromTime(testNow).AddDays(3))

fx.Area("area-work", "Work", 1)
fx.Tag("tg-urgent", "urgent", 1)
Expand Down
2 changes: 1 addition & 1 deletion internal/db/projects.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
// ListProjects lists the projects, in area order. includeCompleted lists the
// closed ones too, logged or not. Without it the listing is the open projects
// and, unless openOnly is set, the ones closed and not yet logged
// (closedTodayUnlogged), which the app's own project list still holds: on 9
// (closedUnlogged), which the app's own project list still holds: on 9
// Oct 2026 AppleScript's `projects` returned a project completed that day
// that `things projects` left out. That is the rule the task lists follow.
func (d *DB) ListProjects(areaFilter string, includeCompleted, openOnly bool) ([]model.Project, error) {
Expand Down
20 changes: 11 additions & 9 deletions internal/db/tasks.go
Original file line number Diff line number Diff line change
Expand Up @@ -216,9 +216,11 @@ func scanTask(row rowScanner) (model.Task, error) {
// project, never rows in a list, so they stay out.
const todoOrProject = "t.type IN (0, 1)"

// closedTodayUnlogged is the app's rule for a closed item Things has not yet filed
// into the Logbook. Two conditions hold at once, and measuring against the app
// on 10 Sep 2026 is what established the pair (issue #230).
// closedUnlogged is the app's rule for a closed item Things has not yet filed
// into the Logbook, for each choice of its "Move completed items to Logbook"
// setting (see the end of this comment). Under "daily", two conditions hold
// at once, and measuring against the app on 10 Sep 2026 is what established
// the pair (issue #230).
//
// The calendar day is the boundary Things actually keeps: the app's Today held
// six closed items, all closed that day, while its Logbook held forty items
Expand Down Expand Up @@ -246,9 +248,9 @@ const todoOrProject = "t.type IN (0, 1)"
// Now", whatever day it closed. Any other value, or no setting row, keeps the
// daily rule. The other two were read from the app's preferences, not measured
// in the live app, as that would mean changing the user's setting.
var closedTodayUnlogged = closedUnloggedOf("t")
var closedUnlogged = closedUnloggedOf("t")

// closedUnloggedOf is closedTodayUnlogged asked of the TMTask row aliased
// closedUnloggedOf is closedUnlogged asked of the TMTask row aliased
// alias.
func closedUnloggedOf(alias string) string {
stopDate := "COALESCE(" + alias + ".stopDate, 0)"
Expand Down Expand Up @@ -336,7 +338,7 @@ const todayDate = "COALESCE(t.startDate, " + thingsToday + ")"

// thingsToday is today's local date in the ThingsDate encoding
// (year<<16 | month<<12 | day<<7), so it compares directly with startDate and
// deadline. It comes from today_clock, as closedTodayUnlogged's day does.
// deadline. It comes from today_clock, as closedUnlogged's daily rule does.
const thingsToday = `(SELECT day FROM ` + todayClock + `)`

// heldInPlace is the set the Logbook withholds: every closed row Things has
Expand All @@ -356,7 +358,7 @@ const thingsToday = `(SELECT day FROM ` + todayClock + `)`
// withholding such a row would take it out of every list. The Logbook keeps
// them (includesTemplates) at once. Both halves of notATemplate are "IS NULL"
// tests, which are never NULL themselves.
var heldInPlace = "(" + closedTodayUnlogged + " AND " + notATemplate + ")"
var heldInPlace = "(" + closedUnlogged + " AND " + notATemplate + ")"

// notATemplate excludes the rows those views never carry: the template
// row itself, and a to-do inside a repeating project template, which carries
Expand All @@ -382,7 +384,7 @@ const parentClosed = "COALESCE(p.status, 0) IN (2, 3)"
// table gives.
const parentNotClosed = "NOT (" + parentClosed + ")"

// parentCloseUnlogged is closedTodayUnlogged asked of the parent project.
// parentCloseUnlogged is closedUnlogged asked of the parent project.
var parentCloseUnlogged = closedUnloggedOf("p")

// parentNotClosedOrUnlogged is the fold the views that show unlogged rows apply:
Expand Down Expand Up @@ -444,7 +446,7 @@ func openOrJustClosed(o whereOpts, foldsUnlogged bool) string {
// projects` and AddTarget all take. fold, when not empty, is a further test
// on the closed rows alone.
func openOrUnlogged(fold string) string {
closed := closedRows + " AND " + closedTodayUnlogged
closed := closedRows + " AND " + closedUnlogged
if fold != "" {
closed += " AND " + fold
}
Expand Down
Loading
Loading