Skip to content

testutils

Go
import "github.com/andreoliwa/logseq-doctor/internal/testutils"

Index

Constants

blockIDBase is the starting numeric ID for fixture blocks.

Go
const blockIDBase = 1000

dirPerm is the permission used for directories created by the fixture framework.

Go
const dirPerm = 0o755

filePerm is the permission used for files created by the fixture framework.

Go
const filePerm = 0o600

pageIDBase is the starting numeric ID for fixture pages.

Go
const pageIDBase = 2000

Variables

ExportBuildAPIResponse exposes buildAPIResponse for white-box testing.

Go
var ExportBuildAPIResponse = buildAPIResponse //nolint:gochecknoglobals

ExportBuildSlugMap exposes buildSlugMap for white-box testing.

Go
var ExportBuildSlugMap = buildSlugMap //nolint:gochecknoglobals

ExportCollapseSlugs exposes collapseSlugs for white-box testing.

Go
var ExportCollapseSlugs = collapseSlugs //nolint:gochecknoglobals

ExportExpandSlugs exposes expandSlugs for white-box testing.

Go
var ExportExpandSlugs = expandSlugs //nolint:gochecknoglobals

ExportResolveRelativeDate exposes resolveRelativeDate for white-box testing.

Go
var ExportResolveRelativeDate = resolveRelativeDate //nolint:gochecknoglobals

Go
var baselineTime = time.Date(2025, 4, 13, 3, 33, 0, 0, time.UTC) //nolint:gochecknoglobals

slugRefPattern matches (( any slug with spaces )) in committed .md files.

Go
var slugRefPattern = regexp.MustCompile(`\(\(\s*([^)]+?)\s*\)\)`)

Go
var testStartTime = time.Now() //nolint:gochecknoglobals

func AssertGoldenJournals

Go
func AssertGoldenJournals(t *testing.T, graph *logseq.Graph, caseDirName string, pages []string)

func AssertGoldenPages

Go
func AssertGoldenPages(t *testing.T, graph *logseq.Graph, caseDirName string, pages []string)

func AssertPagesDontExist

Go
func AssertPagesDontExist(t *testing.T, graph *logseq.Graph, pages []string)

func CaptureOutput

Go
func CaptureOutput(function func()) string

CaptureOutput captures both stdout and stderr. It also works with the "color" package.

func ExportFixtureUUID

Go
func ExportFixtureUUID(f *TaskFixture, slug string) string

ExportFixtureUUID returns the UUID for the given slug in the fixture (for white-box testing).

func NewStubGraph

Go
func NewStubGraph(t *testing.T, subDir string) *logseq.Graph

NewStubGraph creates a test graph using the new directory structure. It uses graph-template as the base and loads test data from testdata/{subDir}/journals and testdata/{subDir}/pages.

func RelativeTime

Go
func RelativeTime() time.Time

func assertGoldenContent

Go
func assertGoldenContent(t *testing.T, graph *logseq.Graph, journals bool, caseDirName string, pages []string)

func buildAPIResponse

Go
func buildAPIResponse(blocks []Block, slugToUUIDMap map[string]string, now time.Time) string

buildAPIResponse generates a JSON array string from blocks, matching the Logseq API response format. now is used to resolve relative Scheduled/Deadline/Groomed date strings.

func buildBlockContent

Go
func buildBlockContent(block Block, uuid string) string

buildBlockContent constructs the Logseq block content string.

func buildBlockProperties

Go
func buildBlockProperties(block Block, uuid string, now time.Time) (map[string]string, []string)

buildBlockProperties constructs the properties map and order slice for a block.

func buildBlockRefs

Go
func buildBlockRefs(block Block, tagIDs map[string]int, pageID int) ([]refJSON, []refJSON)

buildBlockRefs builds the refs and pathRefs slices for a block.

func buildSlugMap

Go
func buildSlugMap(blocks []Block) (map[string]string, map[string]string)

buildSlugMap builds slug→UUID and UUID→slug maps from a slice of blocks. Panics if two different slugs produce the same UUID (collision detection).

func buildTagIDs

Go
func buildTagIDs(blocks []Block) map[string]int

buildTagIDs assigns stable numeric IDs to all distinct tags across blocks.

func collapseSlugs

Go
func collapseSlugs(content string, uuidToSlugMap map[string]string) string

collapseSlugs replaces ((uuid)) with (( slug )) in content. UUIDs not present in uuidToSlugMap are left unchanged.

func copyDirTree

Go
func copyDirTree(src, dst string) error

copyDirTree copies a directory tree recursively from src to dst.

func expandSlugs

Go
func expandSlugs(content string, slugToUUIDMap map[string]string) string

expandSlugs replaces (( slug )) with ((uuid)) in content. Slugs not present in slugToUUIDMap are left unchanged.

func resolveJournalDayInt

Go
func resolveJournalDayInt(rel string, now time.Time) int

resolveJournalDayInt resolves a relative date string to a Logseq journalDay int. Returns 0 if rel is empty or invalid.

func resolveRelativeDate

Go
func resolveRelativeDate(rel string, now time.Time) (time.Time, error)

resolveRelativeDate parses a relative date string like "+3d", "-1w", "+2m", "+1y" and returns the resolved time. Empty string returns the zero time. "0" returns now. Supported units: d (days), w (weeks), m (months), y (years).

func slugToUUID

Go
func slugToUUID(slug string) string

slugToUUID derives a deterministic UUID from a slug using FNV-32a. Format: {h8}-0000-0000-0000-{h8}0000 where h8 = zero-padded 8-char hex of fnv32a(slug).

func toJournalDayInt

Go
func toJournalDayInt(t time.Time) int

toJournalDayInt converts a time.Time to the Logseq journalDay integer format (YYYYMMDD).

type Block

Block is a generic Logseq block fixture. Most callers use the Task() constructor which sets Marker. The framework is built on Block internally so non-task blocks (plain content, property blocks) can be added in the future without architectural changes — just add a Block constructor alongside Task().

Go
type Block struct {
    Slug       string
    Marker     string // content.TaskString* from logseq-go (e.g. TaskStringTodo), or "" for non-task blocks
    Text       string
    Tags       []string
    Scheduled  string            // relative date: "+3d", "-1w", "+2m", "+1y", "" for none
    Deadline   string            // same format as Scheduled
    Priority   string            // "A", "B", "C", or ""
    Groomed    string            // relative date for groomed:: property, "" means no property
    JournalDay string            // "2025-03-02" format; defaults to baseline date (2025-04-13)
    ExtraProps map[string]string // arbitrary Logseq block properties
}

func Task

Go
func Task(slug, status, text string, opts ...BlockOpt) Block

Task constructs a Block with Marker set. Use BlockOpts for optional fields.

type BlockOpt

BlockOpt is a functional option for configuring a Block.

Go
type BlockOpt func(*Block)

func WithDeadline

Go
func WithDeadline(rel string) BlockOpt

WithDeadline sets the Deadline relative date.

func WithExtraProps

Go
func WithExtraProps(props map[string]string) BlockOpt

WithExtraProps sets arbitrary Logseq block properties.

func WithGroomed

Go
func WithGroomed(rel string) BlockOpt

WithGroomed sets the Groomed relative date (e.g. "-7d").

func WithJournalDay

Go
func WithJournalDay(day string) BlockOpt

WithJournalDay sets the journal page date ("2025-03-02").

func WithPriority

Go
func WithPriority(p string) BlockOpt

WithPriority sets the Priority ("A", "B", or "C").

func WithScheduled

Go
func WithScheduled(rel string) BlockOpt

WithScheduled sets the Scheduled relative date (e.g. "+3d", "-1w").

func WithTags

Go
func WithTags(tags ...string) BlockOpt

WithTags sets the Tags field.

type TaskFixture

TaskFixture holds block definitions and generates fake API responses for a test.

Go
type TaskFixture struct {
    t          *testing.T
    blocks     []Block
    slugToUUID map[string]string
    uuidToSlug map[string]string
}

func NewFixture

Go
func NewFixture(t *testing.T, blocks ...Block) *TaskFixture

NewFixture creates a TaskFixture from the given blocks.

func (*TaskFixture) Add

Go
func (f *TaskFixture) Add(blocks ...Block) *TaskFixture

Add appends blocks to the fixture and returns it for chaining. Panics if any new slug collides with an existing one.

func (*TaskFixture) AssertGoldenJournals

Go
func (f *TaskFixture) AssertGoldenJournals(t *testing.T, graph *logseq.Graph, caseDirName string, pages []string)

AssertGoldenJournals is like AssertGoldenPages but for journals/.

func (*TaskFixture) AssertGoldenPages

Go
func (f *TaskFixture) AssertGoldenPages(t *testing.T, graph *logseq.Graph, caseDirName string, pages []string)

AssertGoldenPages collapses UUIDs back to slugs in each output page, then compares against golden files in testdata/{caseDirName}/pages/.

func (*TaskFixture) FakeBacklog

Go
func (f *TaskFixture) FakeBacklog(t *testing.T, configPage, caseDirName string) backlog.Backlog

FakeBacklog creates a backlog.Backlog backed by: - a temp graph populated from testdata/{caseDirName}/ with slugs expanded to UUIDs - a fake Logseq API returning generated JSON grouped by tag

configPage is the backlog config page name (e.g. "bk", "ov"). caseDirName is the subdirectory under testdata/ for this test case (may be empty).

func (*TaskFixture) assertGoldenFiles

Go
func (f *TaskFixture) assertGoldenFiles(t *testing.T, graph *logseq.Graph, journals bool, caseDirName string, pages []string)

func (*TaskFixture) copyExpandedMDs

Go
func (f *TaskFixture) copyExpandedMDs(t *testing.T, src, dst string)

copyExpandedMDs copies .md files from src to dst, expanding slugs to UUIDs in each file. Silently skips if src does not exist.

func (*TaskFixture) fakeAPI

Go
func (f *TaskFixture) fakeAPI(t *testing.T) *mockLogseqAPI

fakeAPI creates a mockLogseqAPI returning generated JSON grouped by tag.

func (*TaskFixture) fakeGraph

Go
func (f *TaskFixture) fakeGraph(t *testing.T, caseDirName string) *logseq.Graph

fakeGraph builds a temp graph with slug-expanded .md files from testdata/{caseDirName}/. Uses the graph-template as the base and expands slugs in the page files.

type blockJSON

blockJSON is the JSON structure matching testdata/stub-api/*.jsonl entries.

Go
type blockJSON struct {
    UUID                 string            `json:"uuid"`
    Marker               string            `json:"marker,omitempty"`
    Content              string            `json:"content"`
    Deadline             int               `json:"deadline,omitempty"`
    Scheduled            int               `json:"scheduled,omitempty"`
    Page                 pageJSON          `json:"page"`
    Properties           map[string]string `json:"properties"`
    PropertiesOrder      []string          `json:"propertiesOrder"`
    PropertiesTextValues map[string]string `json:"propertiesTextValues"`
    Refs                 []refJSON         `json:"refs"`
    PathRefs             []refJSON         `json:"pathRefs"`
    Format               string            `json:"format"`
    ID                   int               `json:"id"`
    Parent               refJSON           `json:"parent"`
    Left                 refJSON           `json:"left"`
}

type mockLogseqAPI

Go
type mockLogseqAPI struct {
    mock.Mock

    tagResponses map[string]string
}

func newMockLogseqAPIFromMap

Go
func newMockLogseqAPIFromMap(t *testing.T, responses map[string]string) *mockLogseqAPI

newMockLogseqAPIFromMap creates a mockLogseqAPI that returns pre-built JSON responses keyed by tag.

func (*mockLogseqAPI) PostDatascriptQuery

Go
func (m *mockLogseqAPI) PostDatascriptQuery(query string) (string, error)

func (*mockLogseqAPI) PostQuery

Go
func (m *mockLogseqAPI) PostQuery(query string) (string, error)

func (*mockLogseqAPI) UpsertBlockProperty

Go
func (m *mockLogseqAPI) UpsertBlockProperty(_ string, _ string, _ string) error

type pageJSON

Go
type pageJSON struct {
    JournalDay   int    `json:"journalDay"`
    Name         string `json:"name"`
    OriginalName string `json:"originalName"`
    ID           int    `json:"id"`
}

func buildJournalPage

Go
func buildJournalPage(block Block, now time.Time, pageID int) pageJSON

buildJournalPage derives the page JSON for a block.

type refJSON

Go
type refJSON struct {
    ID int `json:"id"`
}

Generated by gomarkdoc