(fixture: &ParsedFixture)
| 573 | } |
| 574 | |
| 575 | async fn run_definition(fixture: &ParsedFixture) -> Result<(), String> { |
| 576 | let backend = create_fixture_backend(); |
| 577 | let uri = open_files(&backend, fixture).await; |
| 578 | |
| 579 | let position = Position { |
| 580 | line: fixture.cursor_line, |
| 581 | character: fixture.cursor_char, |
| 582 | }; |
| 583 | |
| 584 | let params = GotoDefinitionParams { |
| 585 | text_document_position_params: TextDocumentPositionParams { |
| 586 | text_document: TextDocumentIdentifier { uri: uri.clone() }, |
| 587 | position, |
| 588 | }, |
| 589 | work_done_progress_params: WorkDoneProgressParams::default(), |
| 590 | partial_result_params: PartialResultParams::default(), |
| 591 | }; |
| 592 | |
| 593 | let result = backend |
| 594 | .goto_definition(params) |
| 595 | .await |
| 596 | .map_err(|e| format!("Goto definition request failed: {e}"))?; |
| 597 | |
| 598 | if fixture.meta.expect_definition.is_empty() { |
| 599 | return Err("Definition fixture has no `// expect_definition:` assertions".to_string()); |
| 600 | } |
| 601 | |
| 602 | let locations = match result { |
| 603 | Some(GotoDefinitionResponse::Scalar(loc)) => vec![loc], |
| 604 | Some(GotoDefinitionResponse::Array(locs)) => locs, |
| 605 | Some(GotoDefinitionResponse::Link(links)) => links |
| 606 | .into_iter() |
| 607 | .map(|link| Location { |
| 608 | uri: link.target_uri, |
| 609 | range: link.target_selection_range, |
| 610 | }) |
| 611 | .collect(), |
| 612 | None => Vec::new(), |
| 613 | }; |
| 614 | |
| 615 | for expected in &fixture.meta.expect_definition { |
| 616 | if expected.starts_with("self:") { |
| 617 | // `self:LINE` — definition is in the cursor file at the given line (1-based). |
| 618 | let expected_line: u32 = expected |
| 619 | .strip_prefix("self:") |
| 620 | .unwrap() |
| 621 | .trim() |
| 622 | .parse() |
| 623 | .map_err(|e| format!("Invalid line in expect_definition: {e}"))?; |
| 624 | |
| 625 | let found = locations.iter().any(|loc| { |
| 626 | loc.uri == uri && loc.range.start.line == expected_line.saturating_sub(1) |
| 627 | }); |
| 628 | if !found { |
| 629 | let actual: Vec<String> = locations |
| 630 | .iter() |
| 631 | .map(|l| format!("{}:{}", l.uri.path(), l.range.start.line + 1)) |
| 632 | .collect(); |
no test coverage detected