nbuild_core/models/cargo/
visitor.rs

1use tracing::{info_span, trace};
2
3use super::{Dependency, Package};
4
5/// A visitor over cargo packages
6pub trait Visitor {
7    /// Entry point for a visitor. Defaults to visiting all dependencies which are not optional.
8    fn visit(&mut self, package: &mut Package)
9    where
10        Self: Sized,
11    {
12        self.visit_package(package);
13
14        for dependency in package.dependencies_iter() {
15            let dependency_span = info_span!(
16                "processing dependency",
17                name = dependency.name,
18                package_name = dependency.package.borrow().name,
19                optional = dependency.optional,
20            );
21            let _dependency_span_guard = dependency_span.enter();
22
23            if !dependency.optional {
24                self.visit_dependency(dependency);
25
26                dependency.package.borrow_mut().visit(self);
27            }
28        }
29    }
30
31    /// Visit a package
32    fn visit_package(&mut self, _package: &mut Package) {}
33
34    /// Visit a dependency of a package
35    fn visit_dependency(&mut self, _dependency: &Dependency) {}
36}
37
38/// Visitor to resolve the enabled dependencies and the features on those dependencies
39pub struct ResolveVisitor;
40
41impl Visitor for ResolveVisitor {
42    fn visit_dependency(&mut self, dependency: &Dependency) {
43        add_default(dependency);
44        activate_features(dependency);
45    }
46
47    fn visit_package(&mut self, package: &mut Package) {
48        loop {
49            let new_features = unpack_features(package);
50
51            if !new_features.is_empty() {
52                trace!(?new_features, "adding new features");
53
54                package.enabled_features.extend(new_features);
55            } else {
56                break;
57            }
58        }
59
60        unpack_optionals_features(package);
61    }
62}
63
64/// Add the "default" feature if default-features is not false
65/// https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#choosing-features
66fn add_default(dependency: &Dependency) {
67    if dependency.uses_default_features
68        && dependency.package.borrow().features.contains_key("default")
69    {
70        trace!("enabling default feature");
71
72        dependency
73            .package
74            .borrow_mut()
75            .enabled_features
76            .insert("default".to_string());
77    }
78}
79
80/// Activate all the feature on a dependency
81fn activate_features(dependency: &Dependency) {
82    if !dependency.features.is_empty() {
83        let features: Vec<String> = dependency
84            .features
85            .clone()
86            .iter()
87            .filter(|&f| dependency.package.borrow().features.contains_key(f))
88            .cloned()
89            .collect();
90
91        trace!(?features, "enabling features");
92
93        dependency
94            .package
95            .borrow_mut()
96            .enabled_features
97            .extend(features);
98    }
99}
100
101/// Get new features on a crate's "chain" that have not been seen before
102fn unpack_features(package: &mut Package) -> Vec<String> {
103    package
104        .enabled_features
105        .iter()
106        .filter_map(|f| package.features.get(f))
107        .flatten()
108        .cloned()
109        .filter(|f| !package.enabled_features.contains(f)) // Don't process a "leaf" feature
110        .filter_map(|f| {
111            // Activate an optional dependency that is turned on by a feature
112            // https://doc.rust-lang.org/cargo/reference/features.html#optional-dependencies
113            if let Some(dependency_name) = f.strip_prefix("dep:") {
114                if let Some(dependency) = package
115                    .dependencies
116                    .iter_mut()
117                    .chain(package.build_dependencies.iter_mut())
118                    .find(|d| d.name == dependency_name)
119                {
120                    trace!(name = dependency_name, "activating optional dependency");
121                    dependency.optional = false;
122                }
123
124                // We are activating an optional dependency and not enabling a new feature
125                return None;
126            } else {
127                // Activate a dependency's features
128                // https://doc.rust-lang.org/cargo/reference/features.html#dependency-features
129                if let Some((dependency_name, feature)) = f.split_once('/') {
130                    if let Some(dependency) = package
131                        .dependencies
132                        .iter_mut()
133                        .chain(package.build_dependencies.iter_mut())
134                        .find(|d| d.name == dependency_name)
135                    {
136                        let feature = feature.to_string();
137
138                        if !dependency.features.contains(&feature) {
139                            dependency.features.push(feature);
140                        }
141
142                        return Some(dependency_name.to_string());
143                    }
144                }
145            }
146
147            Some(f)
148        })
149        .filter(|f| !package.enabled_features.contains(f)) // We only want to unpack new features
150        .collect()
151}
152
153/// Activate features on optional dependencies where the dependencies was made non-optional by a previous feature
154/// https://doc.rust-lang.org/cargo/reference/features.html#dependency-features
155fn unpack_optionals_features(package: &mut Package) {
156    let new_dependencies_features: Vec<_> = package
157        .enabled_features
158        .iter()
159        .filter_map(|f| f.split_once("?/"))
160        .map(|(d, f)| (d.to_string(), f.to_string()))
161        .collect();
162
163    for (dependency_name, feature) in new_dependencies_features {
164        if let Some(dependency) = package
165            .dependencies_iter_mut()
166            .find(|d| d.name == dependency_name && !d.optional)
167        {
168            if !dependency.features.contains(&feature) {
169                dependency.features.push(feature.clone());
170            }
171
172            trace!(
173                dependency = dependency_name,
174                feature,
175                "adding feature on optional dependency"
176            );
177        }
178
179        package
180            .enabled_features
181            .remove(&format!("{dependency_name}?/{feature}"));
182    }
183}
184
185#[cfg(test)]
186mod tests {
187    use std::{cell::RefCell, collections::HashMap, rc::Rc};
188
189    use crate::models::cargo::{Dependency, Package};
190
191    use pretty_assertions::assert_eq;
192
193    fn make_package_node(
194        name: &str,
195        features: Vec<(&str, Vec<&str>)>,
196        dependency: Option<Dependency>,
197    ) -> Package {
198        let dependencies = if let Some(dependency) = dependency {
199            vec![dependency]
200        } else {
201            Default::default()
202        };
203
204        Package {
205            name: name.to_string(),
206            lib_name: None,
207            version: "0.1.0".parse().unwrap(),
208            source: "sha".into(),
209            lib_path: None,
210            build_path: None,
211            proc_macro: false,
212            dependencies,
213            build_dependencies: Default::default(),
214            features: HashMap::from_iter(features.into_iter().map(|(b, d)| {
215                (
216                    b.to_string(),
217                    d.into_iter().map(ToString::to_string).collect(),
218                )
219            })),
220            enabled_features: Default::default(),
221            edition: "2021".to_string(),
222        }
223    }
224
225    // Defaults should not be enabled when no-defaults is used
226    #[test]
227    fn no_defaults() {
228        let mut child = make_package_node(
229            "child",
230            vec![
231                ("default", vec!["one", "two"]),
232                ("one", vec![]),
233                ("two", vec![]),
234            ],
235            None,
236        );
237
238        let mut input = make_package_node(
239            "parent",
240            vec![],
241            Some(Dependency {
242                name: "child".to_string(),
243                package: RefCell::new(child.clone()).into(),
244                optional: false,
245                uses_default_features: false,
246                features: vec!["one".to_string()],
247            }),
248        );
249
250        input.resolve();
251
252        child.enabled_features.insert("one".to_string());
253        let expected = make_package_node(
254            "parent",
255            vec![],
256            Some(Dependency {
257                name: "child".to_string(),
258                package: RefCell::new(child.clone()).into(),
259                optional: false,
260                uses_default_features: false,
261                features: vec!["one".to_string()],
262            }),
263        );
264
265        assert_eq!(input, expected);
266    }
267
268    // Enable defaults correctly
269    #[test]
270    fn defaults() {
271        let mut child = make_package_node(
272            "child",
273            vec![
274                ("default", vec!["one", "two"]),
275                ("one", vec![]),
276                ("two", vec![]),
277            ],
278            None,
279        );
280
281        let mut input = make_package_node(
282            "parent",
283            vec![],
284            Some(Dependency {
285                name: "child".to_string(),
286                package: RefCell::new(child.clone()).into(),
287                optional: false,
288                uses_default_features: true,
289                features: vec![],
290            }),
291        );
292
293        input.resolve();
294
295        child.enabled_features.extend([
296            "one".to_string(),
297            "two".to_string(),
298            "default".to_string(),
299        ]);
300        let expected = make_package_node(
301            "parent",
302            vec![],
303            Some(Dependency {
304                name: "child".to_string(),
305                package: RefCell::new(child.clone()).into(),
306                optional: false,
307                uses_default_features: true,
308                features: vec![],
309            }),
310        );
311
312        assert_eq!(input, expected);
313    }
314
315    // Enable everything on a chain of defaults
316    #[test]
317    fn defaults_chain() {
318        let mut child = make_package_node(
319            "child",
320            vec![
321                ("default", vec!["one"]),
322                ("one", vec!["two"]),
323                ("two", vec![]),
324            ],
325            None,
326        );
327
328        let mut input = make_package_node(
329            "parent",
330            vec![],
331            Some(Dependency {
332                name: "child".to_string(),
333                package: RefCell::new(child.clone()).into(),
334                optional: false,
335                uses_default_features: true,
336                features: vec![],
337            }),
338        );
339
340        input.resolve();
341
342        child.enabled_features.extend([
343            "one".to_string(),
344            "two".to_string(),
345            "default".to_string(),
346        ]);
347        let expected = make_package_node(
348            "parent",
349            vec![],
350            Some(Dependency {
351                name: "child".to_string(),
352                package: RefCell::new(child.clone()).into(),
353                optional: false,
354                uses_default_features: true,
355                features: vec![],
356            }),
357        );
358
359        assert_eq!(input, expected);
360    }
361
362    // Optionals should not enable default features since they will not be used
363    #[test]
364    fn optional_no_defaults() {
365        let child = make_package_node(
366            "child",
367            vec![
368                ("default", vec!["one", "two"]),
369                ("one", vec![]),
370                ("two", vec![]),
371            ],
372            None,
373        );
374        let build = make_package_node("build", vec![("default", vec!["hi"]), ("hi", vec![])], None);
375
376        let mut input = make_package_node(
377            "parent",
378            vec![],
379            Some(Dependency {
380                name: "child".to_string(),
381                package: RefCell::new(child.clone()).into(),
382                optional: true,
383                uses_default_features: true,
384                features: vec![],
385            }),
386        );
387        input.build_dependencies.push(Dependency {
388            name: "build".to_string(),
389            package: RefCell::new(build.clone()).into(),
390            optional: true,
391            uses_default_features: true,
392            features: vec![],
393        });
394
395        input.resolve();
396
397        let mut expected = make_package_node(
398            "parent",
399            vec![],
400            Some(Dependency {
401                name: "child".to_string(),
402                package: RefCell::new(child).into(),
403                optional: true,
404                uses_default_features: true,
405                features: vec![],
406            }),
407        );
408        expected.build_dependencies.push(Dependency {
409            name: "build".to_string(),
410            package: RefCell::new(build).into(),
411            optional: true,
412            uses_default_features: true,
413            features: vec![],
414        });
415
416        assert_eq!(input, expected);
417    }
418
419    // Optionals should not enable any features since they will not be used
420    #[test]
421    fn optional_features() {
422        let child = make_package_node("child", vec![("one", vec![]), ("two", vec![])], None);
423        let build = make_package_node("build", vec![("hi", vec![])], None);
424
425        let mut input = make_package_node(
426            "parent",
427            vec![],
428            Some(Dependency {
429                name: "child".to_string(),
430                package: RefCell::new(child.clone()).into(),
431                optional: true,
432                uses_default_features: true,
433                features: vec!["one".to_string()],
434            }),
435        );
436        input.build_dependencies.push(Dependency {
437            name: "build".to_string(),
438            package: RefCell::new(build.clone()).into(),
439            optional: true,
440            uses_default_features: true,
441            features: vec!["hi".to_string()],
442        });
443
444        input.resolve();
445
446        let mut expected = make_package_node(
447            "parent",
448            vec![],
449            Some(Dependency {
450                name: "child".to_string(),
451                package: RefCell::new(child).into(),
452                optional: true,
453                uses_default_features: true,
454                features: vec!["one".to_string()],
455            }),
456        );
457        expected.build_dependencies.push(Dependency {
458            name: "build".to_string(),
459            package: RefCell::new(build).into(),
460            optional: true,
461            uses_default_features: true,
462            features: vec!["hi".to_string()],
463        });
464
465        assert_eq!(input, expected);
466    }
467
468    // Enable everything on a chain
469    #[test]
470    fn chain() {
471        let mut child = make_package_node(
472            "child",
473            vec![
474                ("one", vec!["two"]),
475                ("two", vec!["three"]),
476                ("three", vec![]),
477            ],
478            None,
479        );
480        let mut build = make_package_node(
481            "build",
482            vec![("hi", vec!["world"]), ("world", vec![])],
483            None,
484        );
485
486        let mut input = make_package_node(
487            "parent",
488            vec![],
489            Some(Dependency {
490                name: "child".to_string(),
491                package: RefCell::new(child.clone()).into(),
492                optional: false,
493                uses_default_features: true,
494                features: vec!["one".to_string()],
495            }),
496        );
497        input.build_dependencies.push(Dependency {
498            name: "build".to_string(),
499            package: RefCell::new(build.clone()).into(),
500            optional: false,
501            uses_default_features: true,
502            features: vec!["hi".to_string()],
503        });
504
505        input.resolve();
506
507        child
508            .enabled_features
509            .extend(["one".to_string(), "two".to_string(), "three".to_string()]);
510        build
511            .enabled_features
512            .extend(["hi".to_string(), "world".to_string()]);
513
514        let mut expected = make_package_node(
515            "parent",
516            vec![],
517            Some(Dependency {
518                name: "child".to_string(),
519                package: RefCell::new(child.clone()).into(),
520                optional: false,
521                uses_default_features: true,
522                features: vec!["one".to_string()],
523            }),
524        );
525        expected.build_dependencies.push(Dependency {
526            name: "build".to_string(),
527            package: RefCell::new(build.clone()).into(),
528            optional: false,
529            uses_default_features: true,
530            features: vec!["hi".to_string()],
531        });
532
533        assert_eq!(input, expected);
534    }
535
536    // Dependencies behind a feature should be enabled
537    #[test]
538    fn feature_dependency() {
539        let mut optional = make_package_node("optional", vec![("feature", vec![])], None);
540        let mut optional_build =
541            make_package_node("optional", vec![("build_feature", vec![])], None);
542
543        let mut child = make_package_node(
544            "child",
545            vec![
546                ("one", vec!["optional"]),
547                ("optional", vec!["dep:optional"]),
548            ],
549            Some(Dependency {
550                name: "optional".to_string(),
551                package: RefCell::new(optional.clone()).into(),
552                optional: true,
553                uses_default_features: true,
554                features: vec!["feature".to_string()],
555            }),
556        );
557        let mut build = make_package_node(
558            "build",
559            vec![("hi", vec!["dep:optional"])],
560            Some(Dependency {
561                name: "optional".to_string(),
562                package: RefCell::new(optional_build.clone()).into(),
563                optional: true,
564                uses_default_features: true,
565                features: vec!["build_feature".to_string()],
566            }),
567        );
568
569        let mut input = make_package_node(
570            "parent",
571            vec![],
572            Some(Dependency {
573                name: "child".to_string(),
574                package: RefCell::new(child.clone()).into(),
575                optional: false,
576                uses_default_features: true,
577                features: vec!["one".to_string()],
578            }),
579        );
580        input.build_dependencies.push(Dependency {
581            name: "build".to_string(),
582            package: RefCell::new(build.clone()).into(),
583            optional: false,
584            uses_default_features: true,
585            features: vec!["hi".to_string()],
586        });
587
588        input.resolve();
589
590        optional.enabled_features.extend(["feature".to_string()]);
591        optional_build
592            .enabled_features
593            .extend(["build_feature".to_string()]);
594
595        child.dependencies[0].optional = false;
596        child.dependencies[0].package = RefCell::new(optional).into();
597        child
598            .enabled_features
599            .extend(["one".to_string(), "optional".to_string()]);
600
601        build.dependencies[0].optional = false;
602        build.dependencies[0].package = RefCell::new(optional_build).into();
603        build.enabled_features.extend(["hi".to_string()]);
604
605        let mut expected = make_package_node(
606            "parent",
607            vec![],
608            Some(Dependency {
609                name: "child".to_string(),
610                package: RefCell::new(child.clone()).into(),
611                optional: false,
612                uses_default_features: true,
613                features: vec!["one".to_string()],
614            }),
615        );
616        expected.build_dependencies.push(Dependency {
617            name: "build".to_string(),
618            package: RefCell::new(build.clone()).into(),
619            optional: false,
620            uses_default_features: true,
621            features: vec!["hi".to_string()],
622        });
623
624        assert_eq!(input, expected);
625    }
626
627    // Renamed dependencies behind a feature should be enabled
628    #[test]
629    fn feature_renamed_dependency() {
630        let rename = make_package_node("rename", vec![], None);
631        let build_rename = make_package_node("build_rename", vec![], None);
632        let mut child = make_package_node(
633            "child",
634            vec![
635                ("new_name", vec!["dep:new_name"]),
636                ("new_build_name", vec!["dep:new_build_name"]),
637            ],
638            Some(Dependency {
639                name: "new_name".to_string(),
640                package: RefCell::new(rename.clone()).into(),
641                optional: true,
642                uses_default_features: true,
643                features: vec![],
644            }),
645        );
646        child.build_dependencies.push(Dependency {
647            name: "new_build_name".to_string(),
648            package: RefCell::new(build_rename.clone()).into(),
649            optional: true,
650            uses_default_features: true,
651            features: vec![],
652        });
653
654        let mut input = make_package_node(
655            "parent",
656            vec![],
657            Some(Dependency {
658                name: "child".to_string(),
659                package: RefCell::new(child.clone()).into(),
660                optional: false,
661                uses_default_features: true,
662                features: vec!["new_name".to_string(), "new_build_name".to_string()],
663            }),
664        );
665
666        input.resolve();
667
668        child.dependencies[0].optional = false;
669        child.dependencies[0].package = RefCell::new(rename).into();
670        child.build_dependencies[0].optional = false;
671        child.build_dependencies[0].package = RefCell::new(build_rename).into();
672        child
673            .enabled_features
674            .extend(["new_name".to_string(), "new_build_name".to_string()]);
675
676        let expected = make_package_node(
677            "parent",
678            vec![],
679            Some(Dependency {
680                name: "child".to_string(),
681                package: RefCell::new(child.clone()).into(),
682                optional: false,
683                uses_default_features: true,
684                features: vec!["new_name".to_string(), "new_build_name".to_string()],
685            }),
686        );
687
688        assert_eq!(input, expected);
689    }
690
691    // Features on dependencies behind a feature should be enabled
692    #[test]
693    fn feature_dependency_features() {
694        let optional = make_package_node("optional", vec![("feature", vec![])], None);
695        let build_optional =
696            make_package_node("build_optional", vec![("build_feature", vec![])], None);
697        let mut child = make_package_node(
698            "child",
699            vec![
700                (
701                    "one",
702                    vec!["optional/feature", "build_optional/build_feature"],
703                ),
704                ("optional", vec!["dep:optional"]),
705                ("build_optional", vec!["dep:build_optional"]),
706            ],
707            Some(Dependency {
708                name: "optional".to_string(),
709                package: RefCell::new(optional.clone()).into(),
710                optional: true,
711                uses_default_features: true,
712                features: vec![],
713            }),
714        );
715        child.build_dependencies.push(Dependency {
716            name: "build_optional".to_string(),
717            package: RefCell::new(build_optional.clone()).into(),
718            optional: true,
719            uses_default_features: true,
720            features: vec![],
721        });
722
723        let mut input = make_package_node(
724            "parent",
725            vec![],
726            Some(Dependency {
727                name: "child".to_string(),
728                package: RefCell::new(child.clone()).into(),
729                optional: false,
730                uses_default_features: true,
731                features: vec!["one".to_string()],
732            }),
733        );
734
735        input.resolve();
736
737        child.dependencies[0].optional = false;
738        child.dependencies[0].features.push("feature".to_string());
739        child.dependencies[0].package = RefCell::new(optional).into();
740        child.dependencies[0]
741            .package
742            .borrow_mut()
743            .enabled_features
744            .extend(["feature".to_string()]);
745        child.build_dependencies[0].optional = false;
746        child.build_dependencies[0]
747            .features
748            .push("build_feature".to_string());
749        child.build_dependencies[0].package = RefCell::new(build_optional).into();
750        child.build_dependencies[0]
751            .package
752            .borrow_mut()
753            .enabled_features
754            .extend(["build_feature".to_string()]);
755        child.enabled_features.extend([
756            "one".to_string(),
757            "optional".to_string(),
758            "build_optional".to_string(),
759        ]);
760
761        let expected = make_package_node(
762            "parent",
763            vec![],
764            Some(Dependency {
765                name: "child".to_string(),
766                package: RefCell::new(child.clone()).into(),
767                optional: false,
768                uses_default_features: true,
769                features: vec!["one".to_string()],
770            }),
771        );
772
773        assert_eq!(input, expected);
774    }
775
776    // Default dependencies chain behind a feature should be enabled
777    #[test]
778    fn feature_dependency_defaults() {
779        let optional = make_package_node(
780            "optional",
781            vec![("default", vec!["std"]), ("std", vec![])],
782            None,
783        );
784        let build_optional = make_package_node(
785            "optional",
786            vec![("default", vec!["build"]), ("build", vec![])],
787            None,
788        );
789        let mut child = make_package_node(
790            "child",
791            vec![
792                ("one", vec!["optional", "build_optional"]),
793                ("optional", vec!["dep:optional"]),
794                ("build_optional", vec!["dep:build_optional"]),
795            ],
796            Some(Dependency {
797                name: "optional".to_string(),
798                package: RefCell::new(optional.clone()).into(),
799                optional: true,
800                uses_default_features: true,
801                features: vec![],
802            }),
803        );
804        child.build_dependencies.push(Dependency {
805            name: "build_optional".to_string(),
806            package: RefCell::new(build_optional.clone()).into(),
807            optional: true,
808            uses_default_features: true,
809            features: vec![],
810        });
811
812        let mut input = make_package_node(
813            "parent",
814            vec![],
815            Some(Dependency {
816                name: "child".to_string(),
817                package: RefCell::new(child.clone()).into(),
818                optional: false,
819                uses_default_features: true,
820                features: vec!["one".to_string()],
821            }),
822        );
823
824        input.resolve();
825
826        child.dependencies[0].optional = false;
827        child.dependencies[0].package = RefCell::new(optional).into();
828        child.dependencies[0]
829            .package
830            .borrow_mut()
831            .enabled_features
832            .extend(["std".to_string(), "default".to_string()]);
833        child.build_dependencies[0].optional = false;
834        child.build_dependencies[0].package = RefCell::new(build_optional).into();
835        child.build_dependencies[0]
836            .package
837            .borrow_mut()
838            .enabled_features
839            .extend(["build".to_string(), "default".to_string()]);
840        child.enabled_features.extend([
841            "one".to_string(),
842            "optional".to_string(),
843            "build_optional".to_string(),
844        ]);
845
846        let expected = make_package_node(
847            "parent",
848            vec![],
849            Some(Dependency {
850                name: "child".to_string(),
851                package: RefCell::new(child.clone()).into(),
852                optional: false,
853                uses_default_features: true,
854                features: vec!["one".to_string()],
855            }),
856        );
857
858        assert_eq!(input, expected);
859    }
860
861    // Default features on a dependency (with no-defaults) behind a feature should not be enabled
862    #[test]
863    fn feature_dependency_no_defaults() {
864        let optional = make_package_node(
865            "optional",
866            vec![("default", vec!["std"]), ("std", vec![])],
867            None,
868        );
869        let build_optional = make_package_node(
870            "build_optional",
871            vec![("default", vec!["build"]), ("build", vec![])],
872            None,
873        );
874        let mut child = make_package_node(
875            "child",
876            vec![
877                ("one", vec!["optional", "build_optional"]),
878                ("optional", vec!["dep:optional"]),
879                ("build_optional", vec!["dep:build_optional"]),
880            ],
881            Some(Dependency {
882                name: "optional".to_string(),
883                package: RefCell::new(optional.clone()).into(),
884                optional: true,
885                uses_default_features: false,
886                features: vec![],
887            }),
888        );
889        child.build_dependencies.push(Dependency {
890            name: "build_optional".to_string(),
891            package: RefCell::new(build_optional.clone()).into(),
892            optional: true,
893            uses_default_features: false,
894            features: vec![],
895        });
896
897        let mut input = make_package_node(
898            "parent",
899            vec![],
900            Some(Dependency {
901                name: "child".to_string(),
902                package: RefCell::new(child.clone()).into(),
903                optional: false,
904                uses_default_features: true,
905                features: vec!["one".to_string()],
906            }),
907        );
908
909        input.resolve();
910
911        child.dependencies[0].optional = false;
912        child.dependencies[0].package = RefCell::new(optional).into();
913        child.build_dependencies[0].optional = false;
914        child.build_dependencies[0].package = RefCell::new(build_optional).into();
915        child.enabled_features.extend([
916            "one".to_string(),
917            "optional".to_string(),
918            "build_optional".to_string(),
919        ]);
920
921        let expected = make_package_node(
922            "parent",
923            vec![],
924            Some(Dependency {
925                name: "child".to_string(),
926                package: RefCell::new(child.clone()).into(),
927                optional: false,
928                uses_default_features: true,
929                features: vec!["one".to_string()],
930            }),
931        );
932
933        assert_eq!(input, expected);
934    }
935
936    // Features on optional dependencies should be enabled if the dependency is enabled
937    #[test]
938    fn feature_on_optional_dependency() {
939        let optional = make_package_node(
940            "optional",
941            vec![("disabled", vec![]), ("enabled", vec![])],
942            None,
943        );
944        let build_optional = make_package_node(
945            "build_optional",
946            vec![("build_disabled", vec![]), ("build_enabled", vec![])],
947            None,
948        );
949        let mut child = make_package_node(
950            "child",
951            vec![
952                ("optional", vec!["dep:optional"]),
953                ("build_optional", vec!["dep:build_optional"]),
954                (
955                    "hi",
956                    vec!["optional?/enabled", "build_optional?/build_enabled"],
957                ),
958            ],
959            Some(Dependency {
960                name: "optional".to_string(),
961                package: RefCell::new(optional.clone()).into(),
962                optional: true,
963                uses_default_features: false,
964                features: vec![],
965            }),
966        );
967        child.build_dependencies.push(Dependency {
968            name: "build_optional".to_string(),
969            package: RefCell::new(build_optional.clone()).into(),
970            optional: true,
971            uses_default_features: false,
972            features: vec![],
973        });
974
975        let mut input = make_package_node(
976            "parent",
977            vec![],
978            Some(Dependency {
979                name: "child".to_string(),
980                package: RefCell::new(child.clone()).into(),
981                optional: false,
982                uses_default_features: true,
983                features: vec![
984                    "optional".to_string(),
985                    "build_optional".to_string(),
986                    "hi".to_string(),
987                ],
988            }),
989        );
990
991        input.resolve();
992
993        child.dependencies[0].optional = false;
994        child.dependencies[0].package = RefCell::new(optional).into();
995        child.dependencies[0]
996            .package
997            .borrow_mut()
998            .enabled_features
999            .extend(["enabled".to_string()]);
1000        child.dependencies[0].features = vec!["enabled".to_string()];
1001        child.build_dependencies[0].optional = false;
1002        child.build_dependencies[0].package = RefCell::new(build_optional).into();
1003        child.build_dependencies[0]
1004            .package
1005            .borrow_mut()
1006            .enabled_features
1007            .extend(["build_enabled".to_string()]);
1008        child.build_dependencies[0].features = vec!["build_enabled".to_string()];
1009        child.enabled_features.extend([
1010            "optional".to_string(),
1011            "build_optional".to_string(),
1012            "hi".to_string(),
1013        ]);
1014
1015        let expected = make_package_node(
1016            "parent",
1017            vec![],
1018            Some(Dependency {
1019                name: "child".to_string(),
1020                package: RefCell::new(child.clone()).into(),
1021                optional: false,
1022                uses_default_features: true,
1023                features: vec![
1024                    "optional".to_string(),
1025                    "build_optional".to_string(),
1026                    "hi".to_string(),
1027                ],
1028            }),
1029        );
1030
1031        assert_eq!(input, expected);
1032    }
1033
1034    // Check that a no default dependency does not removing an existing default
1035    //
1036    // Imagine a child dependency that has two other crates dependant on it. The first crate has defaults turned on,
1037    // and the second crate has defaults turned off. The the result of turning off the defaults should not override
1038    // the already on defaults.
1039    //
1040    // Here is a graphical representation
1041    //
1042    //              parent
1043    //              /     \
1044    //             /       \
1045    //       layer1_1     layer1_2
1046    //            \        /
1047    //      (defaults)   (no_defaults)
1048    //              \    /
1049    //              child
1050    #[test]
1051    fn no_default_correctly() {
1052        let mut child = make_package_node(
1053            "child",
1054            vec![("default", vec!["std"]), ("other", vec!["who"])],
1055            None,
1056        );
1057        let child_rc = RefCell::new(child.clone()).into();
1058
1059        let layer1_1 = make_package_node(
1060            "layer1_1",
1061            vec![],
1062            Some(Dependency {
1063                name: "child".to_string(),
1064                package: Rc::clone(&child_rc),
1065                optional: false,
1066                uses_default_features: true,
1067                features: vec!["other".to_string()],
1068            }),
1069        );
1070
1071        let layer1_2 = make_package_node(
1072            "layer1_2",
1073            vec![],
1074            Some(Dependency {
1075                name: "child".to_string(),
1076                package: Rc::clone(&child_rc),
1077                optional: false,
1078                uses_default_features: false,
1079                features: vec!["other".to_string()],
1080            }),
1081        );
1082
1083        let mut input = make_package_node(
1084            "parent",
1085            vec![],
1086            Some(Dependency {
1087                name: "layer1_1".to_string(),
1088                package: RefCell::new(layer1_1).into(),
1089                optional: false,
1090                uses_default_features: true,
1091                features: vec![],
1092            }),
1093        );
1094        input.dependencies.push(Dependency {
1095            name: "layer1_2".to_string(),
1096            package: RefCell::new(layer1_2).into(),
1097            optional: false,
1098            uses_default_features: true,
1099            features: vec![],
1100        });
1101
1102        input.resolve();
1103
1104        child.enabled_features.extend([
1105            "std".to_string(),
1106            "default".to_string(),
1107            "other".to_string(),
1108            "who".to_string(),
1109        ]);
1110
1111        let child_rc = RefCell::new(child).into();
1112
1113        let layer1_1 = make_package_node(
1114            "layer1_1",
1115            vec![],
1116            Some(Dependency {
1117                name: "child".to_string(),
1118                package: Rc::clone(&child_rc),
1119                optional: false,
1120                uses_default_features: true,
1121                features: vec!["other".to_string()],
1122            }),
1123        );
1124
1125        let layer1_2 = make_package_node(
1126            "layer1_2",
1127            vec![],
1128            Some(Dependency {
1129                name: "child".to_string(),
1130                package: Rc::clone(&child_rc),
1131                optional: false,
1132                uses_default_features: false,
1133                features: vec!["other".to_string()],
1134            }),
1135        );
1136
1137        let mut expected = make_package_node(
1138            "parent",
1139            vec![],
1140            Some(Dependency {
1141                name: "layer1_1".to_string(),
1142                package: RefCell::new(layer1_1).into(),
1143                optional: false,
1144                uses_default_features: true,
1145                features: vec![],
1146            }),
1147        );
1148        expected.dependencies.push(Dependency {
1149            name: "layer1_2".to_string(),
1150            package: RefCell::new(layer1_2).into(),
1151            optional: false,
1152            uses_default_features: true,
1153            features: vec![],
1154        });
1155
1156        assert_eq!(input, expected);
1157    }
1158}