diff --git a/tests/stack_flows.rs b/tests/stack_flows.rs index 7fce414..54bde10 100644 --- a/tests/stack_flows.rs +++ b/tests/stack_flows.rs @@ -1820,3 +1820,66 @@ fn view_says_how_many_commits_each_member_holds() { assert_eq!(members[0]["commits"], 1, "{json:#}"); assert_eq!(members[1]["commits"], 2, "{json:#}"); } + +/// `stack sync --json` is *one* object, carrying both halves. +/// +/// Rule 1 of `--json` is one value on stdout, and this is the command most +/// able to break it: it runs a rebase and a reconcile, each of which used to +/// emit its own object. The two were refactored to return their reports for +/// exactly this reason, and nothing checked it until now — `.json()` parses +/// the whole of stdout, so a second object fails here rather than in +/// somebody's `jq`. +#[test] +fn sync_json_is_one_object_describing_both_halves() { + let world = published_stack("sync-json"); + world.checkout.git(&["checkout", "-q", "main"]); + world + .checkout + .commit("unrelated.txt", "theirs\n", "feat: landed meanwhile", None); + world.checkout.sync_remote("main"); + world.checkout.git(&["checkout", "-q", "feature"]); + world.checkout.amend_file("three.txt", "three, revised\n"); + + let report = world.run(&["stack", "sync", "--json"]).success().json(); + + assert_eq!(report["rebase"]["rebased"], true, "{report:#}"); + assert_ne!( + report["rebase"]["was"], report["rebase"]["now"], + "a rebase that moved nothing is not a rebase: {report:#}" + ); + assert_eq!(report["reconcile"]["changed"], true, "{report:#}"); + assert_eq!(report["reconcile"]["total"], 3, "{report:#}"); +} + +/// `stack rebase --json` on a branch already on top of its target says so +/// and moves nothing. +#[test] +fn rebase_json_reports_an_up_to_date_branch() { + let world = published_stack("rebase-json-noop"); + let tip = world.checkout.head(); + + let report = world.run(&["stack", "rebase", "--json"]).success().json(); + + assert_eq!(report["rebased"], false, "{report:#}"); + assert_eq!(report["was"], report["now"], "{report:#}"); + assert_eq!(world.checkout.head(), tip, "the branch moved anyway"); +} + +/// `stack mark --json` lists the marks, their positions, and the subjects +/// they end. +#[test] +fn mark_json_lists_positions_and_subjects() { + let world = Scenario::new("mark-json"); + three_commit_branch(&world); + world.run(&["stack", "mark", "part1", "HEAD~1"]).success(); + + let report = world.run(&["stack", "mark", "--json"]).success().json(); + + assert_eq!(report["branch"], "feature", "{report:#}"); + assert_eq!(report["commits"], 3, "{report:#}"); + let marks = report["marks"].as_array().expect("marks array"); + assert_eq!(marks.len(), 1, "{report:#}"); + assert_eq!(marks[0]["name"], "part1", "{report:#}"); + assert_eq!(marks[0]["position"], 2, "{report:#}"); + assert_eq!(marks[0]["subject"], "feat: middle", "{report:#}"); +}