fixture_manager/
summaries.rs1use crate::context::ContextImpl;
5use anyhow::Result;
6use camino::{Utf8Path, Utf8PathBuf};
7use fixtures::json::JsonFixture;
8use guppy::graph::{
9 cargo::CargoSet,
10 summaries::{diff::SummaryDiff, Summary},
11};
12use guppy_cmdlib::PackagesAndFeatures;
13use once_cell::sync::Lazy;
14use proptest_ext::ValueGenerator;
15use std::fmt::Write;
16
17pub struct SummaryContext;
18
19impl<'g> ContextImpl<'g> for SummaryContext {
20 type IterArgs = usize;
21 type IterItem = (usize, Summary);
22 type Existing = Summary;
23
24 fn dir_name(fixture: &'g JsonFixture) -> Utf8PathBuf {
25 fixture
26 .abs_path()
27 .parent()
28 .expect("up to dirname of summary")
29 .join("summaries")
30 }
31
32 fn file_name(fixture: &'g JsonFixture, &(count, _): &Self::IterItem) -> String {
33 format!("{}-{}.toml", fixture.name(), count)
34 }
35
36 fn iter(
37 fixture: &'g JsonFixture,
38 &count: &Self::IterArgs,
39 ) -> Box<dyn Iterator<Item = Self::IterItem> + 'g> {
40 let mut generator = ValueGenerator::from_seed(fixture.name());
43
44 let graph = fixture.graph();
45
46 let packages_features_strategy = PackagesAndFeatures::strategy(graph);
47 let cargo_opts_strategy = graph.proptest1_cargo_options_strategy();
48
49 let iter = (0..count).map(move |idx| {
50 let mut iter_generator = generator.partial_clone();
53
54 let packages_features = iter_generator
55 .partial_clone()
56 .generate(&packages_features_strategy);
57 let (initials, features_only) = packages_features
58 .make_feature_sets(graph)
59 .expect("valid feature set");
60
61 let cargo_opts = iter_generator
62 .partial_clone()
63 .generate(&cargo_opts_strategy);
64 let cargo_set = CargoSet::new(initials, features_only, &cargo_opts)
65 .expect("into_cargo_set succeeded");
66
67 (
68 idx,
69 cargo_set
70 .to_summary(&cargo_opts)
71 .expect("generated summaries should serialize correctly"),
72 )
73 });
74
75 Box::new(iter)
76 }
77
78 fn parse_existing(_: &Utf8Path, contents: String) -> Result<Self::Existing> {
79 Ok(Summary::parse(&contents)?)
80 }
81
82 fn is_changed((_, summary): &Self::IterItem, existing: &Self::Existing) -> bool {
83 let diff = SummaryDiff::new(existing, summary);
84 diff.is_changed() || existing.metadata != summary.metadata
85 }
86
87 fn diff(
88 _fixture: &'g JsonFixture,
89 (_, summary): &Self::IterItem,
90 existing: Option<&Self::Existing>,
91 ) -> String {
92 static EMPTY_SUMMARY: Lazy<Summary> = Lazy::new(Summary::default);
94
95 let existing = match existing {
96 Some(summary) => summary,
97 None => &*EMPTY_SUMMARY,
98 };
99
100 let diff = SummaryDiff::new(existing, summary);
101 format!("{}", diff.report())
102 }
103
104 fn write_to_string(
105 fixture: &'g JsonFixture,
106 (_, summary): &Self::IterItem,
107 out: &mut String,
108 ) -> Result<()> {
109 writeln!(
110 out,
111 "# This summary was @generated. To regenerate, run:\n\
112 # cargo run -p fixture-manager -- generate-summaries --fixture {}\n",
113 fixture.name()
114 )?;
115
116 summary.write_to_string(out)?;
117 Ok(())
118 }
119}