ic-query 0.25.10

Internet Computer query library for NNS, SNS, ICRC, system canisters, and public network metadata
Documentation
use crate::sns::report::tests::{fixtures::*, *};

struct InvalidBoundedSnsNeuronsSource;

delegate_sns_discovery!(InvalidBoundedSnsNeuronsSource);

impl SnsNeuronsSource for InvalidBoundedSnsNeuronsSource {
    fn fetch_sns_neurons(
        &self,
        request: &SnsSourceRequest,
        sns: &MainnetSns,
        limit: u32,
        owner_principal_id: Option<&str>,
    ) -> Result<MainnetSnsNeurons, SnsHostError> {
        let mut neurons =
            FixtureSnsNeuronsSource.fetch_sns_neurons(request, sns, limit, owner_principal_id)?;
        neurons.neurons[0].neuron_id = "0A".to_string();
        Ok(neurons)
    }

    fn fetch_sns_neuron_page(
        &self,
        _request: &SnsSourceRequest,
        _sns: &MainnetSns,
        _limit: u32,
        _start_page_at: Option<&SnsNeuronId>,
        _owner_principal_id: Option<&str>,
    ) -> Result<MainnetSnsNeuronPage, SnsHostError> {
        unreachable!("bounded validation fixture does not refresh")
    }
}

#[test]
fn sns_neurons_resolves_list_id_and_renders_governance_neurons() {
    let mut request = neurons_request("1");
    request.owner_principal_id = Some(GOVERNANCE_A.to_string());

    let report = build_sns_neurons_report_with_source(&request, &FixtureSnsNeuronsSource)
        .expect("sns neurons report");
    let text = sns_neurons_report_text(&report);

    assert_eq!(report.schema_version, SNS_NEURONS_REPORT_SCHEMA_VERSION);
    assert_eq!(report.id, 1);
    assert_eq!(report.name, "Fixture SNS");
    assert_eq!(report.root_canister_id, ROOT_A);
    assert_eq!(report.governance_canister_id, GOVERNANCE_A);
    assert_eq!(report.requested_limit, 10);
    assert_eq!(report.owner_principal_id.as_deref(), Some(GOVERNANCE_A));
    assert_eq!(report.neuron_count, 1);
    assert_eq!(report.neurons[0].neuron_id, "0001020304");
    assert_eq!(report.neurons[0].cached_neuron_stake_e8s, 123);
    assert_eq!(report.neurons[0].maturity_e8s_equivalent, 456);
    assert_eq!(report.neurons[0].staked_maturity_e8s_equivalent, Some(789));
    assert_eq!(report.neurons[0].created_at, "2026-06-01T00:00:00Z");
    assert_eq!(report.neurons[0].source_nns_neuron_id, Some(42));
    assert_eq!(report.neurons[0].auto_stake_maturity, Some(true));
    assert_eq!(
        report.neurons[0].aging_since_timestamp_seconds,
        1_780_272_100
    );
    assert_eq!(
        report.neurons[0].dissolve_state,
        Some(SnsNeuronDissolveState::DissolveDelaySeconds(31_536_000))
    );
    assert_eq!(report.neurons[0].voting_power_percentage_multiplier, 100);
    assert_eq!(report.neurons[0].vesting_period_seconds, Some(63_072_000));
    assert_eq!(report.neurons[0].neuron_fees_e8s, 10);
    assert!(text.contains("governance_canister_id: bkyz2-fmaaa-aaaaa-qaaaq-cai"));
    assert!(text.contains("requested_limit: 10"));
    assert!(text.contains("owner_principal_id: bkyz2-fmaaa-aaaaa-qaaaq-cai"));
    assert!(text.contains("00010203"));
    assert!(!text.contains("0001020304"));
    assert!(text.contains("STAKE"));
    assert!(text.contains("MATURITY"));
    assert!(text.contains("STAKED_MATURITY"));
    assert!(text.contains("FEES"));
    assert!(text.contains("DISSOLVE"));
    assert!(text.contains("delay:31536000"));
    assert!(text.contains("AUTO_STAKE"));
    assert!(text.contains("VOTING_%"));
    assert!(!text.contains("STAKE_E8S"));
    assert!(!text.contains("MATURITY_E8S"));
    assert!(text.contains("0.00"));
    assert!(text.contains("2026-06-01T00:00:00Z"));
}

#[test]
fn sns_neurons_text_formats_optional_e8s_as_token_decimals() {
    assert_eq!(text::optional_e8s_decimal_text(None), "-");
    assert_eq!(text::optional_e8s_decimal_text(Some(50_000_000)), "0.50");
}

#[test]
fn sns_neurons_builder_rejects_noncanonical_custom_source_rows() {
    let mut request = neurons_request("1");
    request.owner_principal_id = Some(GOVERNANCE_A.to_string());

    let error = build_sns_neurons_report_with_source(&request, &InvalidBoundedSnsNeuronsSource)
        .expect_err("invalid custom-source row rejected");

    assert!(matches!(
        error,
        SnsHostError::InvalidSourceData {
            capability: "SNS neurons",
            reason,
        } if reason.contains("canonical lowercase hexadecimal")
    ));
}

#[test]
fn sns_neurons_verbose_text_keeps_full_neuron_ids() {
    let mut request = neurons_request("1");
    request.owner_principal_id = Some(GOVERNANCE_A.to_string());
    request.verbose = true;

    let report = build_sns_neurons_report_with_source(&request, &FixtureSnsNeuronsSource)
        .expect("sns neurons report");
    let text = sns_neurons_report_text(&report);

    assert!(report.verbose);
    assert!(text.contains("verbose: yes"));
    assert!(text.contains("0001020304"));
}