Skip to content

πŸ§ͺ Test gap analysis β€” 3 gaps found in azure-devops tool validation and missing-data executorΒ #664

Description

@github-actions

Test Gap Analysis

Test suite snapshot: 1,817 total tests β€” all pass βœ…
Previous open issues still active: #376 (lean runtime, logging, MCP tools list), #647 (stage/job header repos branch, update_check parse_version).

This issue tracks three new gaps discovered in the 2026-05-20 cycle.


Priority Gaps

Module Function/Path Why It Matters Suggested Test
tools/azure_devops/extension.rs mcpg_servers() β€” invalid org name (contains dots, underscores, or spaces) The alphanumeric+hyphen org-name validation was explicitly tightened in #598 to prevent shell injection; the anyhow::bail! error path is never entered by any test Call mcpg_servers() with an org containing "my.org" or "my org" and assert is_err() with a message containing "invalid characters"
tools/azure_devops/extension.rs mcpg_servers() β€” invalid toolset name (contains dots, underscores, spaces) Same pattern: toolset names are injected as npx ... -d <toolset> CLI args; the guard is only triggered by explicitly invalid input, and no test currently triggers it Call mcpg_servers() with toolsets: ["wit.invalid"] and assert is_err()
safeoutputs/missing_data.rs execute_impl() β€” execution path never invoked missing_data has only 2 tests (test_result_has_correct_name, test_params_converts_to_result). Unlike report_incomplete.rs (which has a test_execute_impl_includes_context_when_present), missing_data's executor is never called in tests β€” the success message format and context-appending branch are both untested Add #[tokio::test] async fn test_execute_impl_produces_success_message() that constructs a result and calls execute_sanitized, asserting exec.success == true and exec.message.contains("API docs")

Suggested Test Cases

1. mcpg_servers() β€” invalid org name rejects special characters

Add to the // ── AzureDevOpsExtension ─────────────────────────────────────── block in src/compile/extensions/tests.rs:

#[test]
fn test_ado_mcpg_servers_rejects_org_with_dot() {
    let fm = minimal_front_matter();
    let ctx = CompileContext::for_test_with_org(&fm, "my.corp");
    let ext = AzureDevOpsExtension::new(AzureDevOpsToolConfig::Enabled(true));
    let err = ext.mcpg_servers(&ctx).unwrap_err();
    assert!(
        err.to_string().contains("invalid characters"),
        "Should reject org names with dots: {err}"
    );
}

#[test]
fn test_ado_mcpg_servers_rejects_org_with_underscore() {
    let fm = minimal_front_matter();
    let ctx = CompileContext::for_test_with_org(&fm, "my_org");
    let ext = AzureDevOpsExtension::new(AzureDevOpsToolConfig::Enabled(true));
    let err = ext.mcpg_servers(&ctx).unwrap_err();
    assert!(
        err.to_string().contains("invalid characters"),
        "Should reject org names with underscores: {err}"
    );
}

2. mcpg_servers() β€” invalid toolset name rejects special characters

#[test]
fn test_ado_mcpg_servers_rejects_toolset_with_dot() {
    let fm = minimal_front_matter();
    let ctx = CompileContext::for_test_with_org(&fm, "myorg");
    let config = AzureDevOpsToolConfig::Object(AzureDevOpsToolConfigObject {
        enabled: true,
        org: None,
        toolsets: vec!["wit.invalid".to_string()],
        allowed: vec![],
    });
    let ext = AzureDevOpsExtension::new(config);
    let err = ext.mcpg_servers(&ctx).unwrap_err();
    assert!(
        err.to_string().contains("invalid characters") || err.to_string().contains("Invalid ADO toolset"),
        "Should reject toolset names with dots: {err}"
    );
}

3. missing_data.rs β€” execution path

Add to src/safeoutputs/missing_data.rs tests block:

#[tokio::test]
async fn test_execute_impl_success_without_context() {
    let mut result: MissingDataResult = MissingDataParams {
        data_type: "API docs".to_string(),
        reason: "needed for integration".to_string(),
        context: None,
    }
    .try_into()
    .unwrap();

    let exec = result
        .execute_sanitized(&crate::safeoutputs::ExecutionContext::default())
        .await
        .unwrap();
    assert!(exec.success, "missing-data should report success");
    assert!(
        exec.message.contains("API docs"),
        "message should include data_type: {}",
        exec.message
    );
    assert!(
        exec.message.contains("needed for integration"),
        "message should include reason: {}",
        exec.message
    );
}

#[tokio::test]
async fn test_execute_impl_success_with_context() {
    let mut result: MissingDataResult = MissingDataParams {
        data_type: "Database schema".to_string(),
        reason: "required to generate migrations".to_string(),
        context: Some("tried checking docs.example.com".to_string()),
    }
    .try_into()
    .unwrap();

    let exec = result
        .execute_sanitized(&crate::safeoutputs::ExecutionContext::default())
        .await
        .unwrap();
    assert!(exec.success);
    assert!(
        exec.message.contains("[tried checking docs.example.com]"),
        "context should be appended in brackets: {}",
        exec.message
    );
}

Coverage Summary

Module Public/Key Fns Tests Notes
tools/azure_devops/extension.rs mcpg_servers valid org: 1, invalid org: 0 Error path added/tightened in #598 has no test; is_err() path for org+toolset never entered
safeoutputs/missing_data.rs execute_impl / execute_sanitized 0 report_incomplete.rs (same structure) has an executor test; missing_data does not

This issue was created by the automated test gap finder. Previous runs: 2026-05-18 (issue #647), 2026-05-01 (issue #376). Open issues: #376, #647. Modules audited this cycle: tools/azure_devops/extension, safeoutputs/missing_data, ado/discovery, compile/extensions/tests. Total tests found: 1,817 (was 1,733 last cycle, +84).

Generated by Test Gap Finder Β· gh-aw-workflow-call-id: githubnext/ado-aw/test-gap-finder

Generated by Test Gap Finder Β· ● 5.8M Β· β—·

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions