refactor(structure): reorganize codebase into domain-focused modules
This commit is contained in:
268
src/cli/commands/sync/sync_tests.rs
Normal file
268
src/cli/commands/sync/sync_tests.rs
Normal file
@@ -0,0 +1,268 @@
|
||||
use super::*;
|
||||
|
||||
fn default_options() -> SyncOptions {
|
||||
SyncOptions {
|
||||
full: false,
|
||||
force: false,
|
||||
no_embed: false,
|
||||
no_docs: false,
|
||||
no_events: false,
|
||||
robot_mode: false,
|
||||
dry_run: false,
|
||||
issue_iids: vec![],
|
||||
mr_iids: vec![],
|
||||
project: None,
|
||||
preflight_only: false,
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn append_failures_skips_zeroes() {
|
||||
let mut summary = "base".to_string();
|
||||
append_failures(&mut summary, &[("errors", 0), ("failures", 0)]);
|
||||
assert_eq!(summary, "base");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn append_failures_renders_non_zero_counts() {
|
||||
let mut summary = "base".to_string();
|
||||
append_failures(&mut summary, &[("errors", 2), ("failures", 1)]);
|
||||
assert!(summary.contains("base"));
|
||||
assert!(summary.contains("2 errors"));
|
||||
assert!(summary.contains("1 failures"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn summarize_status_enrichment_reports_skipped_when_all_skipped() {
|
||||
let projects = vec![ProjectStatusEnrichment {
|
||||
path: "vs/typescript-code".to_string(),
|
||||
mode: "skipped".to_string(),
|
||||
reason: None,
|
||||
seen: 0,
|
||||
enriched: 0,
|
||||
cleared: 0,
|
||||
without_widget: 0,
|
||||
partial_errors: 0,
|
||||
first_partial_error: None,
|
||||
error: None,
|
||||
}];
|
||||
|
||||
let (summary, has_errors) = summarize_status_enrichment(&projects);
|
||||
assert!(summary.contains("0 statuses updated"));
|
||||
assert!(summary.contains("skipped"));
|
||||
assert!(!has_errors);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn summarize_status_enrichment_reports_errors() {
|
||||
let projects = vec![ProjectStatusEnrichment {
|
||||
path: "vs/typescript-code".to_string(),
|
||||
mode: "fetched".to_string(),
|
||||
reason: None,
|
||||
seen: 3,
|
||||
enriched: 1,
|
||||
cleared: 1,
|
||||
without_widget: 0,
|
||||
partial_errors: 2,
|
||||
first_partial_error: None,
|
||||
error: Some("boom".to_string()),
|
||||
}];
|
||||
|
||||
let (summary, has_errors) = summarize_status_enrichment(&projects);
|
||||
assert!(summary.contains("1 statuses updated"));
|
||||
assert!(summary.contains("1 cleared"));
|
||||
assert!(summary.contains("3 seen"));
|
||||
assert!(summary.contains("3 errors"));
|
||||
assert!(has_errors);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_print_timings_only_when_enabled_and_non_empty() {
|
||||
let stages = vec![StageTiming {
|
||||
name: "x".to_string(),
|
||||
elapsed_ms: 10,
|
||||
items_processed: 0,
|
||||
items_skipped: 0,
|
||||
errors: 0,
|
||||
rate_limit_hits: 0,
|
||||
retries: 0,
|
||||
project: None,
|
||||
sub_stages: vec![],
|
||||
}];
|
||||
|
||||
assert!(should_print_timings(true, &stages));
|
||||
assert!(!should_print_timings(false, &stages));
|
||||
assert!(!should_print_timings(true, &[]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn issue_sub_rows_include_project_and_statuses() {
|
||||
let rows = issue_sub_rows(&[ProjectSummary {
|
||||
path: "vs/typescript-code".to_string(),
|
||||
items_upserted: 2,
|
||||
discussions_synced: 0,
|
||||
events_fetched: 0,
|
||||
events_failed: 0,
|
||||
statuses_enriched: 1,
|
||||
statuses_seen: 5,
|
||||
status_errors: 0,
|
||||
mr_diffs_fetched: 0,
|
||||
mr_diffs_failed: 0,
|
||||
}]);
|
||||
|
||||
assert_eq!(rows.len(), 1);
|
||||
assert!(rows[0].contains("vs/typescript-code"));
|
||||
assert!(rows[0].contains("2 issues"));
|
||||
assert!(rows[0].contains("1 statuses updated"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mr_sub_rows_include_project_and_diff_failures() {
|
||||
let rows = mr_sub_rows(&[ProjectSummary {
|
||||
path: "vs/python-code".to_string(),
|
||||
items_upserted: 3,
|
||||
discussions_synced: 0,
|
||||
events_fetched: 0,
|
||||
events_failed: 0,
|
||||
statuses_enriched: 0,
|
||||
statuses_seen: 0,
|
||||
status_errors: 0,
|
||||
mr_diffs_fetched: 4,
|
||||
mr_diffs_failed: 1,
|
||||
}]);
|
||||
|
||||
assert_eq!(rows.len(), 1);
|
||||
assert!(rows[0].contains("vs/python-code"));
|
||||
assert!(rows[0].contains("3 MRs"));
|
||||
assert!(rows[0].contains("4 diffs"));
|
||||
assert!(rows[0].contains("1 diff failures"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn status_sub_rows_include_project_and_skip_reason() {
|
||||
let rows = status_sub_rows(&[ProjectStatusEnrichment {
|
||||
path: "vs/python-code".to_string(),
|
||||
mode: "skipped".to_string(),
|
||||
reason: Some("disabled".to_string()),
|
||||
seen: 0,
|
||||
enriched: 0,
|
||||
cleared: 0,
|
||||
without_widget: 0,
|
||||
partial_errors: 0,
|
||||
first_partial_error: None,
|
||||
error: None,
|
||||
}]);
|
||||
|
||||
assert_eq!(rows.len(), 1);
|
||||
assert!(rows[0].contains("vs/python-code"));
|
||||
assert!(rows[0].contains("0 statuses updated"));
|
||||
assert!(rows[0].contains("skipped (disabled)"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_surgical_with_issues() {
|
||||
let opts = SyncOptions {
|
||||
issue_iids: vec![1],
|
||||
..default_options()
|
||||
};
|
||||
assert!(opts.is_surgical());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_surgical_with_mrs() {
|
||||
let opts = SyncOptions {
|
||||
mr_iids: vec![10],
|
||||
..default_options()
|
||||
};
|
||||
assert!(opts.is_surgical());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_surgical_empty() {
|
||||
let opts = default_options();
|
||||
assert!(!opts.is_surgical());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn max_surgical_targets_is_100() {
|
||||
assert_eq!(SyncOptions::MAX_SURGICAL_TARGETS, 100);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sync_result_default_omits_surgical_fields() {
|
||||
let result = SyncResult::default();
|
||||
let json = serde_json::to_value(&result).unwrap();
|
||||
assert!(json.get("surgical_mode").is_none());
|
||||
assert!(json.get("surgical_iids").is_none());
|
||||
assert!(json.get("entity_results").is_none());
|
||||
assert!(json.get("preflight_only").is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sync_result_with_surgical_fields_serializes_correctly() {
|
||||
let result = SyncResult {
|
||||
surgical_mode: Some(true),
|
||||
surgical_iids: Some(SurgicalIids {
|
||||
issues: vec![7, 42],
|
||||
merge_requests: vec![10],
|
||||
}),
|
||||
entity_results: Some(vec![
|
||||
EntitySyncResult {
|
||||
entity_type: "issue".to_string(),
|
||||
iid: 7,
|
||||
outcome: "synced".to_string(),
|
||||
error: None,
|
||||
toctou_reason: None,
|
||||
},
|
||||
EntitySyncResult {
|
||||
entity_type: "issue".to_string(),
|
||||
iid: 42,
|
||||
outcome: "skipped_toctou".to_string(),
|
||||
error: None,
|
||||
toctou_reason: Some("updated_at changed".to_string()),
|
||||
},
|
||||
]),
|
||||
preflight_only: Some(false),
|
||||
..SyncResult::default()
|
||||
};
|
||||
let json = serde_json::to_value(&result).unwrap();
|
||||
assert_eq!(json["surgical_mode"], true);
|
||||
assert_eq!(json["surgical_iids"]["issues"], serde_json::json!([7, 42]));
|
||||
assert_eq!(json["entity_results"].as_array().unwrap().len(), 2);
|
||||
assert_eq!(json["entity_results"][1]["outcome"], "skipped_toctou");
|
||||
assert_eq!(json["preflight_only"], false);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn entity_sync_result_omits_none_fields() {
|
||||
let entity = EntitySyncResult {
|
||||
entity_type: "merge_request".to_string(),
|
||||
iid: 10,
|
||||
outcome: "synced".to_string(),
|
||||
error: None,
|
||||
toctou_reason: None,
|
||||
};
|
||||
let json = serde_json::to_value(&entity).unwrap();
|
||||
assert!(json.get("error").is_none());
|
||||
assert!(json.get("toctou_reason").is_none());
|
||||
assert!(json.get("entity_type").is_some());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_surgical_with_both_issues_and_mrs() {
|
||||
let opts = SyncOptions {
|
||||
issue_iids: vec![1, 2],
|
||||
mr_iids: vec![10],
|
||||
..default_options()
|
||||
};
|
||||
assert!(opts.is_surgical());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_not_surgical_with_only_project() {
|
||||
let opts = SyncOptions {
|
||||
project: Some("group/repo".to_string()),
|
||||
..default_options()
|
||||
};
|
||||
assert!(!opts.is_surgical());
|
||||
}
|
||||
Reference in New Issue
Block a user