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
141 changes: 141 additions & 0 deletions crates/lash-cli/tests/add_command_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -794,3 +794,144 @@ Prose that must stay under its heading.
"task escaped the Tasks section:\n{content}"
);
}

// ---------------------------------------------------------------------
// The reported task ID must be the indexed one
//
// `lash add` printed an ID derived by the emitter while the index stored
// one derived by the parser, and the two disagreed three ways: `v0.7.0`
// slugged to `v0-7-0` in one and `v070` in the other, the parser folded
// inline labels into the ID, and only the parser truncated at 40
// characters. Anything that copied the printed ID (`lash show`,
// `@depends-on`) failed.
// ---------------------------------------------------------------------

/// The ID out of `Created task <id> ...`.
fn reported_id(stdout: &str) -> String {
stdout
.lines()
.find_map(|line| line.split("Created task ").nth(1))
.and_then(|rest| rest.split_whitespace().next())
.unwrap_or_else(|| panic!("no created-task line in:\n{stdout}"))
.to_string()
}

#[test]
fn test_add_reports_the_id_the_index_stores() {
let project = project_with_tasks_file();
index(&project);

// Every discrepancy from the original report in one title: a dotted
// version number, an inline label, and enough characters to truncate.
let stdout = run_lash_command()
.arg("--root")
.arg(project.path())
.arg("add")
.arg("Ship v0.7.0 release notes")
.arg("--file")
.arg("tasks.md")
.arg("--label")
.arg("docs")
.assert()
.success()
.get_output()
.stdout
.clone();
let id = reported_id(&String::from_utf8(stdout).unwrap());

assert_eq!(id, "ship-v0-7-0-release-notes");

index(&project);
run_lash_command()
.arg("--root")
.arg(project.path())
.arg("show")
.arg(format!("tasks#{id}"))
.assert()
.success()
.stdout(predicate::str::contains("Ship v0.7.0 release notes"));
}

#[test]
fn test_add_reports_the_truncated_id_for_a_long_title() {
let project = project_with_tasks_file();
index(&project);

let stdout = run_lash_command()
.arg("--root")
.arg(project.path())
.arg("add")
.arg("Coverage fail fast when the coverage command fails and its output predates the run")
.arg("--file")
.arg("tasks.md")
.assert()
.success()
.get_output()
.stdout
.clone();
let id = reported_id(&String::from_utf8(stdout).unwrap());

assert_eq!(
id.chars().count(),
40,
"reported ID was not truncated: {id}"
);

index(&project);
run_lash_command()
.arg("--root")
.arg(project.path())
.arg("show")
.arg(format!("tasks#{id}"))
.assert()
.success();
}

#[test]
fn test_add_reports_the_numeric_suffix_used_to_break_a_collision() {
// Only the parser knows about the suffix, so this is the case the
// emitter could not get right on its own.
let project = project_with_tasks_file();
index(&project);

add_task(&project, "Repeated title", "tasks.md");
let stdout = add_task(&project, "Repeated title", "tasks.md");
let id = reported_id(&stdout);

assert_eq!(id, "repeated-title-2");

index(&project);
run_lash_command()
.arg("--root")
.arg(project.path())
.arg("show")
.arg("tasks#repeated-title-2")
.assert()
.success();
}

#[test]
fn test_add_reported_id_resolves_as_a_dependency_target() {
// The consequence that made this more than an ergonomic problem: a
// `@depends-on` written against the reported ID used to dangle, and the
// dangling-reference check rejects it.
let project = project_with_tasks_file();
index(&project);

let stdout = add_task(&project, "Ship v0.7.0 release notes", "tasks.md");
let id = reported_id(&stdout);
index(&project);

run_lash_command()
.arg("--root")
.arg(project.path())
.arg("add")
.arg("Follow-up task")
.arg("--file")
.arg("tasks.md")
.arg("--depends-on")
.arg(&id)
.assert()
.success()
.stderr(predicate::str::contains("Warning").not());
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,16 @@ expression: normalized
├── ○ api.md (backend.api)
│ ├── [x] Design REST API (backend.api#design-rest-api)
│ │ ├── [x] Define endpoints (backend.api#define-endpoints)
│ │ └── [x] Design request/response schemas (backend.api#design-requestresponse-schemas)
│ ├── [ ] Implement authentication #security (backend.api#implement-authentication-security) #security
│ │ └── [x] Design request/response schemas (backend.api#design-request-response-schemas)
│ ├── [ ] Implement authentication #security (backend.api#implement-authentication) #security
│ │ ├── [x] JWT token generation (backend.api#jwt-token-generation)
│ │ ├── [ ] OAuth2 integration #p1 (backend.api#oauth2-integration-p1) #p1
│ │ ├── [ ] OAuth2 integration #p1 (backend.api#oauth2-integration) #p1
│ │ └── [ ] Session management (backend.api#session-management)
│ ├── [ ] Implement CRUD endpoints #core (backend.api#implement-crud-endpoints-core) #core
│ ├── [ ] Implement CRUD endpoints #core (backend.api#implement-crud-endpoints) #core
│ │ ├── [x] User endpoints (backend.api#user-endpoints)
│ │ ├── [ ] Task endpoints (backend.api#task-endpoints)
│ │ └── [ ] Project endpoints (backend.api#project-endpoints)
│ └── [ ] Add API documentation #docs (backend.api#add-api-documentation-docs) #docs
│ └── [ ] Add API documentation #docs (backend.api#add-api-documentation) #docs
│ ├── [ ] OpenAPI spec (backend.api#openapi-spec)
│ └── [ ] Example requests (backend.api#example-requests)
├── ✓ database.md (backend.database)
Expand All @@ -27,64 +27,64 @@ expression: normalized
│ │ ├── [x] Tasks table (backend.database#tasks-table)
│ │ ├── [x] Projects table (backend.database#projects-table)
│ │ └── [x] Relationships (backend.database#relationships)
│ ├── [x] Set up migrations #infrastructure (backend.database#set-up-migrations-infrastructure) #infrastructure
│ ├── [x] Set up migrations #infrastructure (backend.database#set-up-migrations) #infrastructure
│ │ ├── [x] Migration framework (backend.database#migration-framework)
│ │ ├── [x] Initial schema migration (backend.database#initial-schema-migration)
│ │ └── [x] Seed data (backend.database#seed-data)
│ ├── [x] Add database layer #core (backend.database#add-database-layer-core) #core
│ ├── [x] Add database layer #core (backend.database#add-database-layer) #core
│ │ ├── [x] Connection pooling (backend.database#connection-pooling)
│ │ ├── [x] Query builders (backend.database#query-builders)
│ │ └── [x] Transaction support (backend.database#transaction-support)
│ └── [x] Performance optimization #performance (backend.database#performance-optimization-performance) #performance
│ └── [x] Performance optimization #performance (backend.database#performance-optimization) #performance
│ ├── [x] Add indexes (backend.database#add-indexes)
│ └── [x] Query optimization (backend.database#query-optimization)
└── ○ tests.md (backend.tests)
├── [x] Set up test infrastructure (backend.tests#set-up-test-infrastructure)
│ ├── [x] Test database (backend.tests#test-database)
│ ├── [x] Test fixtures (backend.tests#test-fixtures)
│ └── [x] Helper functions (backend.tests#helper-functions)
├── [ ] Unit tests #unit-testing (backend.tests#unit-tests-unit-testing) #unit-testing
├── [ ] Unit tests #unit-testing (backend.tests#unit-tests) #unit-testing
│ ├── [x] Model tests (backend.tests#model-tests)
│ ├── [ ] Service tests (backend.tests#service-tests)
│ └── [ ] Utility tests (backend.tests#utility-tests)
├── [ ] Integration tests #integration-testing (backend.tests#integration-tests-integration-testing) #integration-testing
├── [ ] Integration tests #integration-testing (backend.tests#integration-tests) #integration-testing
│ ├── [x] API endpoint tests (backend.tests#api-endpoint-tests)
│ ├── [ ] Database integration tests (backend.tests#database-integration-tests)
│ └── [ ] Auth flow tests (backend.tests#auth-flow-tests)
└── [ ] Performance tests #performance (backend.tests#performance-tests-performance) #performance
└── [ ] Performance tests #performance (backend.tests#performance-tests) #performance
├── [ ] Load testing (backend.tests#load-testing)
└── [ ] Stress testing (backend.tests#stress-testing)
└── docs/
├── ○ api-docs.md (docs.api)
│ ├── [ ] API reference documentation #docs (docs.api#api-reference-documentation-docs) #docs
│ ├── [ ] API reference documentation #docs (docs.api#api-reference-documentation) #docs
│ │ ├── [ ] Authentication endpoints (docs.api#authentication-endpoints)
│ │ ├── [ ] User endpoints (docs.api#user-endpoints)
│ │ ├── [ ] Task endpoints (docs.api#task-endpoints)
│ │ └── [ ] Project endpoints (docs.api#project-endpoints)
│ ├── [ ] API guide #guides (docs.api#api-guide-guides) #guides
│ ├── [ ] API guide #guides (docs.api#api-guide) #guides
│ │ ├── [ ] Getting started (docs.api#getting-started)
│ │ ├── [ ] Authentication guide (docs.api#authentication-guide)
│ │ ├── [ ] Rate limiting (docs.api#rate-limiting)
│ │ └── [ ] Error handling (docs.api#error-handling)
│ └── [ ] Code examples #examples (docs.api#code-examples-examples) #examples
│ └── [ ] Code examples #examples (docs.api#code-examples) #examples
│ ├── [ ] cURL examples (docs.api#curl-examples)
│ ├── [ ] JavaScript examples (docs.api#javascript-examples)
│ └── [ ] Python examples (docs.api#python-examples)
└── ○ user-guide.md (docs.user-guide)
├── [ ] Getting started guide #guides (docs.user-guide#getting-started-guide-guides) #guides
├── [ ] Getting started guide #guides (docs.user-guide#getting-started-guide) #guides
│ ├── [ ] Installation (docs.user-guide#installation)
│ ├── [ ] Quick start (docs.user-guide#quick-start)
│ └── [ ] Basic concepts (docs.user-guide#basic-concepts)
├── [ ] Feature documentation #features (docs.user-guide#feature-documentation-features) #features
├── [ ] Feature documentation #features (docs.user-guide#feature-documentation) #features
│ ├── [ ] Task management (docs.user-guide#task-management)
│ ├── [ ] Project organization (docs.user-guide#project-organization)
│ ├── [ ] Collaboration (docs.user-guide#collaboration)
│ └── [ ] Search and filtering (docs.user-guide#search-and-filtering)
├── [ ] Tutorial #tutorials (docs.user-guide#tutorial-tutorials) #tutorials
├── [ ] Tutorial #tutorials (docs.user-guide#tutorial) #tutorials
│ ├── [ ] First project (docs.user-guide#first-project)
│ ├── [ ] Team workflow (docs.user-guide#team-workflow)
│ └── [ ] Advanced features (docs.user-guide#advanced-features)
└── [ ] FAQ #support (docs.user-guide#faq-support) #support
└── [ ] FAQ #support (docs.user-guide#faq) #support
├── [ ] Common questions (docs.user-guide#common-questions)
├── [ ] Troubleshooting (docs.user-guide#troubleshooting)
└── [ ] Best practices (docs.user-guide#best-practices)
Expand All @@ -94,36 +94,36 @@ expression: normalized
│ │ ├── [x] Choose framework (frontend.components#choose-framework)
│ │ ├── [x] Configure build (frontend.components#configure-build)
│ │ └── [x] Set up storybook (frontend.components#set-up-storybook)
│ ├── [ ] Implement base components #components (frontend.components#implement-base-components-components) #components
│ ├── [ ] Implement base components #components (frontend.components#implement-base-components) #components
│ │ ├── [x] Button (frontend.components#button)
│ │ ├── [x] Input (frontend.components#input)
│ │ ├── [x] Card (frontend.components#card)
│ │ ├── [ ] Modal (frontend.components#modal)
│ │ └── [ ] Dropdown (frontend.components#dropdown)
│ ├── [ ] Implement feature components #features (frontend.components#implement-feature-components-features) #features
│ ├── [ ] Implement feature components #features (frontend.components#implement-feature-components) #features
│ │ ├── [ ] Login form (frontend.components#login-form)
│ │ ├── [ ] Task list (frontend.components#task-list)
│ │ ├── [ ] Task detail (frontend.components#task-detail)
│ │ └── [ ] Project dashboard (frontend.components#project-dashboard)
│ └── [ ] Add component tests #testing (frontend.components#add-component-tests-testing) #testing
│ └── [ ] Add component tests #testing (frontend.components#add-component-tests) #testing
│ ├── [x] Unit tests (frontend.components#unit-tests)
│ └── [ ] Visual regression tests (frontend.components#visual-regression-tests)
├── ○ state.md (frontend.state)
│ ├── [x] Set up state management (frontend.state#set-up-state-management)
│ │ ├── [x] Choose library (frontend.state#choose-library)
│ │ ├── [x] Configure store (frontend.state#configure-store)
│ │ └── [x] Define state shape (frontend.state#define-state-shape)
│ ├── [ ] Implement state slices #state (frontend.state#implement-state-slices-state) #state
│ ├── [ ] Implement state slices #state (frontend.state#implement-state-slices) #state
│ │ ├── [x] Auth state (frontend.state#auth-state)
│ │ ├── [ ] Tasks state (frontend.state#tasks-state)
│ │ ├── [ ] Projects state (frontend.state#projects-state)
│ │ └── [ ] UI state (frontend.state#ui-state)
│ ├── [ ] Add API integration #api (frontend.state#add-api-integration-api) #api
│ ├── [ ] Add API integration #api (frontend.state#add-api-integration) #api
│ │ ├── [x] API client (frontend.state#api-client)
│ │ ├── [ ] Data fetching (frontend.state#data-fetching)
│ │ ├── [ ] Caching strategy (frontend.state#caching-strategy)
│ │ └── [ ] Error handling (frontend.state#error-handling)
│ └── [ ] Add state tests #testing (frontend.state#add-state-tests-testing) #testing
│ └── [ ] Add state tests #testing (frontend.state#add-state-tests) #testing
│ ├── [ ] Reducer tests (frontend.state#reducer-tests)
│ ├── [ ] Action tests (frontend.state#action-tests)
│ └── [ ] Selector tests (frontend.state#selector-tests)
Expand All @@ -132,34 +132,34 @@ expression: normalized
│ ├── [x] Test runner (frontend.tests#test-runner)
│ ├── [x] Testing library (frontend.tests#testing-library)
│ └── [x] Mock API (frontend.tests#mock-api)
├── [ ] Component tests #component-testing (frontend.tests#component-tests-component-testing) #component-testing
├── [ ] Component tests #component-testing (frontend.tests#component-tests) #component-testing
│ ├── [x] Base component tests (frontend.tests#base-component-tests)
│ ├── [ ] Feature component tests (frontend.tests#feature-component-tests)
│ └── [ ] Integration tests (frontend.tests#integration-tests)
├── [ ] E2E tests #e2e-testing (frontend.tests#e2e-tests-e2e-testing) #e2e-testing
├── [ ] E2E tests #e2e-testing (frontend.tests#e2e-tests) #e2e-testing
│ ├── [ ] User flows (frontend.tests#user-flows)
│ ├── [ ] Critical paths (frontend.tests#critical-paths)
│ └── [ ] Error scenarios (frontend.tests#error-scenarios)
└── [ ] Visual tests #visual-testing (frontend.tests#visual-tests-visual-testing) #visual-testing
└── [ ] Visual tests #visual-testing (frontend.tests#visual-tests) #visual-testing
├── [ ] Snapshot tests (frontend.tests#snapshot-tests)
└── [ ] Visual regression (frontend.tests#visual-regression)
└── ○ lash.index.md (medium-project)
├── [x] Project initialization (medium-project#project-initialization)
│ ├── [x] Set up repository (medium-project#set-up-repository)
│ ├── [x] Configure build system (medium-project#configure-build-system)
│ └── [x] Set up CI/CD (medium-project#set-up-cicd)
├── [ ] Backend development #backend (medium-project#backend-development-backend) #backend
│ └── [x] Set up CI/CD (medium-project#set-up-ci-cd)
├── [ ] Backend development #backend (medium-project#backend-development) #backend
│ ├── [x] Database schema (medium-project#database-schema)
│ ├── [ ] API implementation (medium-project#api-implementation)
│ └── [ ] Backend tests (medium-project#backend-tests)
├── [ ] Frontend development #frontend (medium-project#frontend-development-frontend) #frontend
├── [ ] Frontend development #frontend (medium-project#frontend-development) #frontend
│ ├── [ ] UI components (medium-project#ui-components)
│ ├── [ ] State management (medium-project#state-management)
│ └── [ ] Frontend tests (medium-project#frontend-tests)
├── [ ] Documentation #docs (medium-project#documentation-docs) #docs
├── [ ] Documentation #docs (medium-project#documentation) #docs
│ ├── [ ] API docs (medium-project#api-docs)
│ └── [ ] User guide (medium-project#user-guide)
└── [ ] Deployment #ops (medium-project#deployment-ops) #ops
└── [ ] Deployment #ops (medium-project#deployment) #ops
├── [ ] Staging environment (medium-project#staging-environment)
└── [ ] Production deployment (medium-project#production-deployment)

Expand Down
Loading
Loading