axbuild 0.4.21

An OS build lib toolkit used by arceos
use std::path::PathBuf;

use super::common::test_workspace;
use crate::support::git::{
    IncrementalPackageSelection,
    manifest::{LocalRootManifestChange, RootManifestChange, classify_root_manifest_change},
    selection::select_incremental_packages_for_paths_with_root_manifest_change,
};

fn local_root_change(dependencies: &[&str], members: &[&str]) -> RootManifestChange {
    RootManifestChange::LocalWorkspace(LocalRootManifestChange {
        dependencies: dependencies
            .iter()
            .map(|dependency| (*dependency).to_string())
            .collect(),
        members: members.iter().map(PathBuf::from).collect(),
    })
}

#[test]
fn root_cargo_toml_workspace_dependency_change_keeps_incremental_package_selection() {
    let (root, metadata, workspace_packages) = test_workspace();
    let selected = select_incremental_packages_for_paths_with_root_manifest_change(
        root.path(),
        &metadata,
        &workspace_packages,
        [
            PathBuf::from("Cargo.toml"),
            PathBuf::from("crates/beta/Cargo.toml"),
        ],
        Some(local_root_change(&["beta"], &[])),
    )
    .unwrap();

    assert_eq!(
        selected,
        IncrementalPackageSelection::Packages {
            changed: vec!["beta".into()],
            affected: vec!["beta".into(), "gamma".into()],
        }
    );
}

#[test]
fn root_cargo_toml_semantic_noop_selects_no_packages() {
    let old_manifest = r#"
            [workspace]
            members = ["crates/alpha"]

            [workspace.dependencies]
            alpha = { version = "0.1.0", path = "crates/alpha" }
        "#;
    let new_manifest = r#"
            [workspace]
            members = ["crates/alpha"]

            [workspace.dependencies]
            # Comment-only edits should not force all clippy packages.
            alpha = { version = "0.1.0", path = "crates/alpha" }
        "#;
    let change = classify_root_manifest_change(old_manifest, new_manifest).unwrap();
    assert_eq!(change, local_root_change(&[], &[]));

    let (root, metadata, workspace_packages) = test_workspace();
    let selected = select_incremental_packages_for_paths_with_root_manifest_change(
        root.path(),
        &metadata,
        &workspace_packages,
        [PathBuf::from("Cargo.toml")],
        Some(change),
    )
    .unwrap();

    assert_eq!(
        selected,
        IncrementalPackageSelection::Packages {
            changed: Vec::new(),
            affected: Vec::new(),
        }
    );
}

#[test]
fn root_cargo_toml_workspace_package_metadata_change_selects_no_packages() {
    let old_manifest = r#"
            [workspace.package]
            version = "0.5.11"
            authors = ["RCore Team <yuchen@tsinghua.edu.cn>"]

            [workspace]
            members = ["crates/alpha"]

            [workspace.dependencies]
            alpha = { version = "0.1.0", path = "crates/alpha" }
        "#;
    let new_manifest = r#"
            [workspace.package]
            version = "0.5.12"
            authors = ["RCore Team <yuchen@tsinghua.edu.cn>", "CI Bot <ci@example.com>"]

            [workspace]
            members = ["crates/alpha"]

            [workspace.dependencies]
            alpha = { version = "0.1.0", path = "crates/alpha" }
        "#;
    let change = classify_root_manifest_change(old_manifest, new_manifest).unwrap();
    assert_eq!(change, local_root_change(&[], &[]));

    let (root, metadata, workspace_packages) = test_workspace();
    let selected = select_incremental_packages_for_paths_with_root_manifest_change(
        root.path(),
        &metadata,
        &workspace_packages,
        [PathBuf::from("Cargo.toml")],
        Some(change),
    )
    .unwrap();

    assert_eq!(
        selected,
        IncrementalPackageSelection::Packages {
            changed: Vec::new(),
            affected: Vec::new(),
        }
    );
}

#[test]
fn root_cargo_toml_semantic_noop_keeps_incremental_package_selection() {
    let (root, metadata, workspace_packages) = test_workspace();
    let selected = select_incremental_packages_for_paths_with_root_manifest_change(
        root.path(),
        &metadata,
        &workspace_packages,
        [
            PathBuf::from("Cargo.toml"),
            PathBuf::from("crates/beta/src/lib.rs"),
        ],
        Some(local_root_change(&[], &[])),
    )
    .unwrap();

    assert_eq!(
        selected,
        IncrementalPackageSelection::Packages {
            changed: vec!["beta".into()],
            affected: vec!["beta".into(), "gamma".into()],
        }
    );
}

#[test]
fn root_cargo_toml_workspace_dependency_change_skips_removed_packages() {
    let (root, metadata, workspace_packages) = test_workspace();
    let selected = select_incremental_packages_for_paths_with_root_manifest_change(
        root.path(),
        &metadata,
        &workspace_packages,
        [PathBuf::from("Cargo.toml")],
        Some(local_root_change(&["beta", "removed"], &[])),
    )
    .unwrap();

    assert_eq!(
        selected,
        IncrementalPackageSelection::Packages {
            changed: vec!["beta".into()],
            affected: vec!["beta".into(), "gamma".into()],
        }
    );
}

#[test]
fn root_manifest_classifier_uses_package_name_for_local_dependency_alias() {
    let old_manifest = r#"
            [workspace]
            members = ["crates/alpha"]

            [workspace.dependencies]
            alpha_alias = { version = "0.1.0", path = "crates/alpha", package = "alpha" }
        "#;
    let new_manifest = r#"
            [workspace]
            members = ["crates/alpha"]

            [workspace.dependencies]
            alpha_alias = { version = "0.2.0", path = "crates/alpha", package = "alpha" }
        "#;

    let change = classify_root_manifest_change(old_manifest, new_manifest).unwrap();

    assert_eq!(change, local_root_change(&["alpha"], &[]));
}

#[test]
fn root_manifest_classifier_tracks_local_dependency_alias_package_change() {
    let old_manifest = r#"
            [workspace]
            members = ["crates/alpha", "crates/beta"]

            [workspace.dependencies]
            local_alias = { version = "0.1.0", path = "crates/alpha", package = "alpha" }
        "#;
    let new_manifest = r#"
            [workspace]
            members = ["crates/alpha", "crates/beta"]

            [workspace.dependencies]
            local_alias = { version = "0.1.0", path = "crates/beta", package = "beta" }
        "#;

    let change = classify_root_manifest_change(old_manifest, new_manifest).unwrap();

    assert_eq!(change, local_root_change(&["alpha", "beta"], &[]));
}

#[test]
fn root_manifest_classifier_accepts_local_workspace_dependency_removal() {
    let old_manifest = r#"
            [workspace]
            members = ["crates/alpha"]

            [workspace.dependencies]
            alpha = { version = "0.1.0", path = "crates/alpha" }
            beta = { version = "0.1.0", path = "crates/beta" }
        "#;
    let new_manifest = r#"
            [workspace]
            members = ["crates/alpha"]

            [workspace.dependencies]
            alpha = { version = "0.1.0", path = "crates/alpha" }
        "#;

    let change = classify_root_manifest_change(old_manifest, new_manifest).unwrap();

    assert_eq!(change, local_root_change(&["beta"], &[]));
}

#[test]
fn root_manifest_classifier_keeps_external_dependency_changes_hard() {
    let old_manifest = r#"
            [workspace]
            members = ["crates/alpha"]

            [workspace.dependencies]
            anyhow = "1.0"
        "#;
    let new_manifest = r#"
            [workspace]
            members = ["crates/alpha"]

            [workspace.dependencies]
            anyhow = "2.0"
        "#;

    let change = classify_root_manifest_change(old_manifest, new_manifest).unwrap();

    assert_eq!(change, RootManifestChange::Hard);
}

#[test]
fn root_manifest_classifier_keeps_literal_workspace_member_changes_incremental() {
    let old_manifest = r#"
            [workspace]
            members = ["crates/alpha"]

            [workspace.dependencies]
            alpha = { version = "0.1.0", path = "crates/alpha" }
        "#;
    let new_manifest = r#"
            [workspace]
            members = ["crates/alpha", "crates/beta"]

            [workspace.dependencies]
            alpha = { version = "0.1.0", path = "crates/alpha" }
        "#;

    let change = classify_root_manifest_change(old_manifest, new_manifest).unwrap();

    assert_eq!(change, local_root_change(&[], &["crates/beta"]));

    let (root, metadata, workspace_packages) = test_workspace();
    let selected = select_incremental_packages_for_paths_with_root_manifest_change(
        root.path(),
        &metadata,
        &workspace_packages,
        [PathBuf::from("Cargo.toml")],
        Some(change),
    )
    .unwrap();

    assert_eq!(
        selected,
        IncrementalPackageSelection::Packages {
            changed: vec!["beta".into()],
            affected: vec!["beta".into(), "gamma".into()],
        }
    );
}

#[test]
fn root_manifest_classifier_ignores_unchanged_workspace_member_globs() {
    let old_manifest = r#"
            [workspace]
            members = ["crates/alpha", "apps/arceos/*"]

            [workspace.dependencies]
            alpha = { version = "0.1.0", path = "crates/alpha" }
        "#;
    let new_manifest = r#"
            [workspace]
            members = ["crates/alpha", "crates/beta", "apps/arceos/*"]

            [workspace.dependencies]
            alpha = { version = "0.1.0", path = "crates/alpha" }
        "#;

    let change = classify_root_manifest_change(old_manifest, new_manifest).unwrap();

    assert_eq!(change, local_root_change(&[], &["crates/beta"]));
}

#[test]
fn root_manifest_classifier_keeps_changed_workspace_member_globs_hard() {
    let old_manifest = r#"
            [workspace]
            members = ["crates/alpha", "apps/arceos/*"]

            [workspace.dependencies]
            alpha = { version = "0.1.0", path = "crates/alpha" }
        "#;
    let new_manifest = r#"
            [workspace]
            members = ["crates/alpha", "apps/arceos/*", "apps/starry/*"]

            [workspace.dependencies]
            alpha = { version = "0.1.0", path = "crates/alpha" }
        "#;

    let change = classify_root_manifest_change(old_manifest, new_manifest).unwrap();

    assert_eq!(change, RootManifestChange::Hard);
}