Skip to main content

git_checks/
submodule_watch.rs

1// Copyright Kitware, Inc.
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
9use derive_builder::Builder;
10use git_checks_core::impl_prelude::*;
11
12/// Check that submodules are reachable from a given branch and available.
13#[derive(Builder, Debug, Default, Clone, Copy)]
14#[builder(field(private))]
15pub struct SubmoduleWatch {
16    /// Whether to reject new submodules or not.
17    ///
18    /// Configuration: Optional
19    /// Default: `false`
20    #[builder(default = "false")]
21    reject_additions: bool,
22    /// Whether to reject deletion of submodules or not.
23    ///
24    /// Configuration: Optional
25    /// Default: `false`
26    #[builder(default = "false")]
27    reject_removals: bool,
28}
29
30impl SubmoduleWatch {
31    /// Checks that submodules in the project are available.
32    pub fn builder() -> SubmoduleWatchBuilder {
33        Default::default()
34    }
35}
36
37impl ContentCheck for SubmoduleWatch {
38    fn name(&self) -> &str {
39        "submodule-watch"
40    }
41
42    fn check(
43        &self,
44        ctx: &CheckGitContext,
45        content: &dyn Content,
46    ) -> Result<CheckResult, Box<dyn Error>> {
47        let mut result = CheckResult::new();
48
49        for diff in content.diffs() {
50            let added = diff.new_mode == "160000";
51            let removed = diff.old_mode == "160000";
52
53            // Ignore diffs which are not submodules.
54            if !added && !removed {
55                continue;
56            }
57
58            let is_configured = SubmoduleContext::new(ctx, diff.name.as_ref()).is_some();
59
60            // Ignore changes which don't change the submodule status.
61            if added && removed {
62                // However, check if the submodule is not configured and warn if it isn't.
63                if !is_configured {
64                    result.add_warning(format!(
65                        "{}modifies an unconfigured submodule at `{}`.",
66                        commit_prefix(content),
67                        diff.name,
68                    ));
69
70                    // Configuring the submodule can resolve the problem.
71                    result.make_temporary();
72                }
73
74                continue;
75            }
76
77            if added && !is_configured {
78                if self.reject_additions {
79                    result.add_error(format!(
80                        "{}adds a submodule at `{}` which is not allowed.",
81                        commit_prefix(content),
82                        diff.name,
83                    ));
84                } else {
85                    result.add_alert(
86                        format!(
87                            "{}adds a submodule at `{}`.",
88                            commit_prefix(content),
89                            diff.name,
90                        ),
91                        false,
92                    );
93                }
94
95                // Configuring the submodule can resolve the problem.
96                result.make_temporary();
97            }
98
99            if removed {
100                if self.reject_removals {
101                    result.add_error(format!(
102                        "{}removes the submodule at `{}` which is not allowed.",
103                        commit_prefix(content),
104                        diff.name,
105                    ));
106                } else {
107                    result.add_alert(
108                        format!(
109                            "{}removes the submodule at `{}`.",
110                            commit_prefix(content),
111                            diff.name,
112                        ),
113                        false,
114                    );
115                }
116            }
117        }
118
119        Ok(result)
120    }
121}
122
123#[cfg(feature = "config")]
124pub(crate) mod config {
125    use git_checks_config::{register_checks, CommitCheckConfig, IntoCheck, TopicCheckConfig};
126    use serde::Deserialize;
127    #[cfg(test)]
128    use serde_json::json;
129
130    use crate::SubmoduleWatch;
131
132    /// Configuration for the `SubmoduleWatch` check.
133    ///
134    /// The `reject_additions` and `reject_removals` keys are both booleans which default to
135    /// `false`.
136    ///
137    /// This check is registered as a commit check with the name `"submodule_watch"`.
138    ///
139    /// # Example
140    ///
141    /// ```json
142    /// {
143    ///     "reject_additions": false,
144    ///     "reject_removals": false
145    /// }
146    /// ```
147    #[derive(Deserialize, Debug)]
148    pub struct SubmoduleWatchConfig {
149        #[serde(default)]
150        reject_additions: Option<bool>,
151        #[serde(default)]
152        reject_removals: Option<bool>,
153    }
154
155    impl IntoCheck for SubmoduleWatchConfig {
156        type Check = SubmoduleWatch;
157
158        fn into_check(self) -> Self::Check {
159            let mut builder = SubmoduleWatch::builder();
160
161            if let Some(reject_additions) = self.reject_additions {
162                builder.reject_additions(reject_additions);
163            }
164
165            if let Some(reject_removals) = self.reject_removals {
166                builder.reject_removals(reject_removals);
167            }
168
169            builder
170                .build()
171                .expect("configuration mismatch for `SubmoduleWatch`")
172        }
173    }
174
175    register_checks! {
176        SubmoduleWatchConfig {
177            "submodule_watch" => CommitCheckConfig,
178            "submodule_watch/topic" => TopicCheckConfig,
179        },
180    }
181
182    #[test]
183    fn test_submodule_watch_config_empty() {
184        let json = json!({});
185        let check: SubmoduleWatchConfig = serde_json::from_value(json).unwrap();
186
187        assert_eq!(check.reject_additions, None);
188        assert_eq!(check.reject_removals, None);
189
190        let check = check.into_check();
191
192        assert!(!check.reject_additions);
193        assert!(!check.reject_removals);
194    }
195
196    #[test]
197    fn test_submodule_watch_config_all_fields() {
198        let json = json!({
199            "reject_additions": true,
200            "reject_removals": true,
201        });
202        let check: SubmoduleWatchConfig = serde_json::from_value(json).unwrap();
203
204        assert_eq!(check.reject_additions, Some(true));
205        assert_eq!(check.reject_removals, Some(true));
206
207        let check = check.into_check();
208
209        assert!(check.reject_additions);
210        assert!(check.reject_removals);
211    }
212}
213
214#[cfg(test)]
215mod tests {
216    use git_checks_core::{Check, TopicCheck};
217
218    use crate::test::*;
219    use crate::SubmoduleWatch;
220
221    const ADD_SUBMODULE_TOPIC: &str = "fe90ee22ae3ce4b4dc41f8d0876e59355ff1e21c";
222    const ADD_SUBMODULE_TOPIC_FIXED: &str = "07e235d362487f96c767d831002821071fb99cff";
223    const REMOVE_SUBMODULE_TOPIC: &str = "336dbaa31d512033fe77eaba7f92ebfecbd17a39";
224    const REMOVE_SUBMODULE_TOPIC_FIXED: &str = "284e22618ec8d31c7b3c7554ced3cf90c1bdca71";
225    const REMOVE_SUBMODULE_AS_FILE: &str = "24573935ac8f352893022e454d03a6450a9e5fe5";
226    const REMOVE_SUBMODULE_AS_FILE_FIXED: &str = "b2be039b1ce04e9b231cddb694da4bbb9d2a9a50";
227    const ADD_SUBMODULE_FROM_FILE: &str = "dab435c23d367c6288540cd97017a0dcd3ac042d";
228    const ADD_SUBMODULE_FROM_FILE_FIXED: &str = "69f3424ca6c0716695247ec210b6e44947a52fd4";
229    const MOVE_SUBMODULE: &str = "2088079e35503be3be41dbdca55080ced95614e1";
230    const MOVE_SUBMODULE_FIXED: &str = "5fee29e00eaa8c142f42ab6137e45edb12c9beda";
231
232    #[test]
233    fn test_submodule_watch_builder_default() {
234        assert!(SubmoduleWatch::builder().build().is_ok());
235    }
236
237    #[test]
238    fn test_submodule_watch_name_commit() {
239        let check = SubmoduleWatch::default();
240        assert_eq!(Check::name(&check), "submodule-watch");
241    }
242
243    #[test]
244    fn test_submodule_watch_name_topic() {
245        let check = SubmoduleWatch::default();
246        assert_eq!(TopicCheck::name(&check), "submodule-watch");
247    }
248
249    #[test]
250    fn test_submodule_watch_add() {
251        let check = SubmoduleWatch::default();
252        let result = run_check("test_submodule_watch_add", ADD_SUBMODULE_TOPIC, check);
253
254        assert_eq!(result.warnings().len(), 0);
255        assert_eq!(result.alerts().len(), 1);
256        assert_eq!(
257            result.alerts()[0],
258            "commit fe90ee22ae3ce4b4dc41f8d0876e59355ff1e21c adds a submodule at `submodule`.",
259        );
260        assert_eq!(result.errors().len(), 0);
261        assert!(result.temporary());
262        assert!(!result.allowed());
263        assert!(result.pass());
264    }
265
266    #[test]
267    fn test_submodule_watch_add_topic() {
268        let check = SubmoduleWatch::default();
269        let result = run_topic_check("test_submodule_watch_add_topic", ADD_SUBMODULE_TOPIC, check);
270
271        assert_eq!(result.warnings().len(), 0);
272        assert_eq!(result.alerts().len(), 1);
273        assert_eq!(result.alerts()[0], "adds a submodule at `submodule`.");
274        assert_eq!(result.errors().len(), 0);
275        assert!(result.temporary());
276        assert!(!result.allowed());
277        assert!(result.pass());
278    }
279
280    #[test]
281    fn test_submodule_watch_add_topic_fixed() {
282        let check = SubmoduleWatch::default();
283        run_topic_check_ok(
284            "test_submodule_watch_add_topic",
285            ADD_SUBMODULE_TOPIC_FIXED,
286            check,
287        );
288    }
289
290    #[test]
291    fn test_submodule_watch_add_from_file() {
292        let check = SubmoduleWatch::default();
293        let conf = make_check_conf(&check);
294
295        let result = test_check_base(
296            "test_submodule_watch_add_from_file",
297            ADD_SUBMODULE_FROM_FILE,
298            REMOVE_SUBMODULE_AS_FILE,
299            &conf,
300        );
301
302        assert_eq!(result.warnings().len(), 0);
303        assert_eq!(result.alerts().len(), 1);
304        assert_eq!(
305            result.alerts()[0],
306            "commit dab435c23d367c6288540cd97017a0dcd3ac042d adds a submodule at `submodule`.",
307        );
308        assert_eq!(result.errors().len(), 0);
309        assert!(result.temporary());
310        assert!(!result.allowed());
311        assert!(result.pass());
312    }
313
314    #[test]
315    fn test_submodule_watch_add_from_file_topic() {
316        let check = SubmoduleWatch::default();
317        let conf = make_topic_check_conf(&check);
318
319        let result = test_check_base(
320            "test_submodule_watch_add_from_file_topic",
321            ADD_SUBMODULE_FROM_FILE,
322            REMOVE_SUBMODULE_AS_FILE,
323            &conf,
324        );
325
326        assert_eq!(result.warnings().len(), 0);
327        assert_eq!(result.alerts().len(), 1);
328        assert_eq!(result.alerts()[0], "adds a submodule at `submodule`.");
329        assert_eq!(result.errors().len(), 0);
330        assert!(result.temporary());
331        assert!(!result.allowed());
332        assert!(result.pass());
333    }
334
335    #[test]
336    fn test_submodule_watch_add_reject() {
337        let check = SubmoduleWatch::builder()
338            .reject_additions(true)
339            .build()
340            .unwrap();
341        let result = run_check(
342            "test_submodule_watch_add_reject",
343            ADD_SUBMODULE_TOPIC,
344            check,
345        );
346
347        assert_eq!(result.warnings().len(), 0);
348        assert_eq!(result.alerts().len(), 0);
349        assert_eq!(result.errors().len(), 1);
350        assert_eq!(
351            result.errors()[0],
352            "commit fe90ee22ae3ce4b4dc41f8d0876e59355ff1e21c adds a submodule at `submodule` \
353             which is not allowed.",
354        );
355        assert!(result.temporary());
356        assert!(!result.allowed());
357        assert!(!result.pass());
358    }
359
360    #[test]
361    fn test_submodule_watch_add_reject_topic() {
362        let check = SubmoduleWatch::builder()
363            .reject_additions(true)
364            .build()
365            .unwrap();
366        let result = run_topic_check(
367            "test_submodule_watch_add_reject_topic",
368            ADD_SUBMODULE_TOPIC,
369            check,
370        );
371
372        assert_eq!(result.warnings().len(), 0);
373        assert_eq!(result.alerts().len(), 0);
374        assert_eq!(result.errors().len(), 1);
375        assert_eq!(
376            result.errors()[0],
377            "adds a submodule at `submodule` which is not allowed.",
378        );
379        assert!(result.temporary());
380        assert!(!result.allowed());
381        assert!(!result.pass());
382    }
383
384    #[test]
385    fn test_submodule_watch_add_reject_topic_fixed() {
386        let check = SubmoduleWatch::builder()
387            .reject_additions(true)
388            .build()
389            .unwrap();
390        let result = run_topic_check(
391            "test_submodule_watch_add_reject_topic_fixed",
392            ADD_SUBMODULE_TOPIC_FIXED,
393            check,
394        );
395        test_result_ok(result);
396    }
397
398    #[test]
399    fn test_submodule_watch_add_from_file_reject() {
400        let check = SubmoduleWatch::builder()
401            .reject_additions(true)
402            .build()
403            .unwrap();
404        let conf = make_check_conf(&check);
405
406        let result = test_check_base(
407            "test_submodule_watch_add_from_file_reject",
408            ADD_SUBMODULE_FROM_FILE,
409            REMOVE_SUBMODULE_AS_FILE,
410            &conf,
411        );
412
413        assert_eq!(result.warnings().len(), 0);
414        assert_eq!(result.alerts().len(), 0);
415        assert_eq!(result.errors().len(), 1);
416        assert_eq!(
417            result.errors()[0],
418            "commit dab435c23d367c6288540cd97017a0dcd3ac042d adds a submodule at `submodule` \
419             which is not allowed.",
420        );
421        assert!(result.temporary());
422        assert!(!result.allowed());
423        assert!(!result.pass());
424    }
425
426    #[test]
427    fn test_submodule_watch_add_from_file_reject_topic() {
428        let check = SubmoduleWatch::builder()
429            .reject_additions(true)
430            .build()
431            .unwrap();
432        let conf = make_topic_check_conf(&check);
433
434        let result = test_check_base(
435            "test_submodule_watch_add_from_file_reject_topic",
436            ADD_SUBMODULE_FROM_FILE,
437            REMOVE_SUBMODULE_AS_FILE,
438            &conf,
439        );
440
441        assert_eq!(result.warnings().len(), 0);
442        assert_eq!(result.alerts().len(), 0);
443        assert_eq!(result.errors().len(), 1);
444        assert_eq!(
445            result.errors()[0],
446            "adds a submodule at `submodule` which is not allowed.",
447        );
448        assert!(result.temporary());
449        assert!(!result.allowed());
450        assert!(!result.pass());
451    }
452
453    #[test]
454    fn test_submodule_watch_add_from_file_reject_topic_fixed() {
455        let check = SubmoduleWatch::builder()
456            .reject_additions(true)
457            .build()
458            .unwrap();
459        let conf = make_topic_check_conf(&check);
460
461        let result = test_check_base(
462            "test_submodule_watch_add_from_file_reject_topic_fixed",
463            ADD_SUBMODULE_FROM_FILE_FIXED,
464            REMOVE_SUBMODULE_AS_FILE,
465            &conf,
466        );
467        test_result_ok(result);
468    }
469
470    #[test]
471    fn test_submodule_watch_add_configured() {
472        let check = SubmoduleWatch::default();
473        let conf = make_check_conf(&check);
474
475        let result = test_check_submodule_configure(
476            "test_submodule_watch_add_configured",
477            ADD_SUBMODULE_TOPIC,
478            &conf,
479            "submodule",
480        );
481        test_result_ok(result);
482    }
483
484    #[test]
485    fn test_submodule_watch_add_configured_topic() {
486        let check = SubmoduleWatch::default();
487        let conf = make_topic_check_conf(&check);
488
489        let result = test_check_submodule_configure(
490            "test_submodule_watch_add_configured_topic",
491            ADD_SUBMODULE_TOPIC,
492            &conf,
493            "submodule",
494        );
495        test_result_ok(result);
496    }
497
498    #[test]
499    fn test_submodule_watch_add_from_file_configured() {
500        let check = SubmoduleWatch::default();
501        let conf = make_check_conf(&check);
502
503        let result = test_check_submodule_base_configure(
504            "test_submodule_watch_add_from_file_configured",
505            ADD_SUBMODULE_FROM_FILE,
506            REMOVE_SUBMODULE_AS_FILE,
507            &conf,
508            "submodule",
509        );
510        test_result_ok(result);
511    }
512
513    #[test]
514    fn test_submodule_watch_add_from_file_configured_topic() {
515        let check = SubmoduleWatch::default();
516        let conf = make_topic_check_conf(&check);
517
518        let result = test_check_submodule_base_configure(
519            "test_submodule_watch_add_from_file_configured_topic",
520            ADD_SUBMODULE_FROM_FILE,
521            REMOVE_SUBMODULE_AS_FILE,
522            &conf,
523            "submodule",
524        );
525        test_result_ok(result);
526    }
527
528    #[test]
529    fn test_submodule_watch_add_configured_reject() {
530        let check = SubmoduleWatch::builder()
531            .reject_additions(true)
532            .build()
533            .unwrap();
534        let conf = make_check_conf(&check);
535
536        let result = test_check_submodule_configure(
537            "test_submodule_watch_add_configured_reject",
538            ADD_SUBMODULE_TOPIC,
539            &conf,
540            "submodule",
541        );
542        test_result_ok(result);
543    }
544
545    #[test]
546    fn test_submodule_watch_add_configured_reject_topic() {
547        let check = SubmoduleWatch::builder()
548            .reject_additions(true)
549            .build()
550            .unwrap();
551        let conf = make_topic_check_conf(&check);
552
553        let result = test_check_submodule_configure(
554            "test_submodule_watch_add_configured_reject_topic",
555            ADD_SUBMODULE_TOPIC,
556            &conf,
557            "submodule",
558        );
559        test_result_ok(result);
560    }
561
562    #[test]
563    fn test_submodule_watch_add_from_file_configured_reject() {
564        let check = SubmoduleWatch::builder()
565            .reject_additions(true)
566            .build()
567            .unwrap();
568        let conf = make_check_conf(&check);
569
570        let result = test_check_submodule_base_configure(
571            "test_submodule_watch_add_from_file_configured_reject",
572            ADD_SUBMODULE_FROM_FILE,
573            REMOVE_SUBMODULE_AS_FILE,
574            &conf,
575            "submodule",
576        );
577        test_result_ok(result);
578    }
579
580    #[test]
581    fn test_submodule_watch_add_from_file_configured_reject_topic() {
582        let check = SubmoduleWatch::builder()
583            .reject_additions(true)
584            .build()
585            .unwrap();
586        let conf = make_topic_check_conf(&check);
587
588        let result = test_check_submodule_base_configure(
589            "test_submodule_watch_add_from_file_configured_reject_topic",
590            ADD_SUBMODULE_FROM_FILE,
591            REMOVE_SUBMODULE_AS_FILE,
592            &conf,
593            "submodule",
594        );
595        test_result_ok(result);
596    }
597
598    #[test]
599    fn test_submodule_watch_remove() {
600        let check = SubmoduleWatch::default();
601        let conf = make_check_conf(&check);
602
603        let result = test_check_submodule_base(
604            "test_submodule_watch_remove",
605            REMOVE_SUBMODULE_TOPIC,
606            ADD_SUBMODULE_TOPIC,
607            &conf,
608        );
609
610        assert_eq!(result.warnings().len(), 0);
611        assert_eq!(result.alerts().len(), 1);
612        assert_eq!(
613            result.alerts()[0],
614            "commit 336dbaa31d512033fe77eaba7f92ebfecbd17a39 removes the submodule at `submodule`.",
615        );
616        assert_eq!(result.errors().len(), 0);
617        assert!(!result.temporary());
618        assert!(!result.allowed());
619        assert!(result.pass());
620    }
621
622    #[test]
623    fn test_submodule_watch_remove_topic() {
624        let check = SubmoduleWatch::default();
625        let conf = make_topic_check_conf(&check);
626
627        let result = test_check_submodule_base(
628            "test_submodule_watch_remove_topic",
629            REMOVE_SUBMODULE_TOPIC,
630            ADD_SUBMODULE_TOPIC,
631            &conf,
632        );
633
634        assert_eq!(result.warnings().len(), 0);
635        assert_eq!(result.alerts().len(), 1);
636        assert_eq!(result.alerts()[0], "removes the submodule at `submodule`.");
637        assert_eq!(result.errors().len(), 0);
638        assert!(!result.temporary());
639        assert!(!result.allowed());
640        assert!(result.pass());
641    }
642
643    #[test]
644    fn test_submodule_watch_remove_topic_fixed() {
645        let check = SubmoduleWatch::default();
646        let conf = make_topic_check_conf(&check);
647
648        let result = test_check_submodule_base(
649            "test_submodule_watch_remove_topic_fixed",
650            REMOVE_SUBMODULE_TOPIC_FIXED,
651            ADD_SUBMODULE_TOPIC,
652            &conf,
653        );
654        test_result_ok(result);
655    }
656
657    #[test]
658    fn test_submodule_watch_remove_as_file() {
659        let check = SubmoduleWatch::default();
660        let conf = make_check_conf(&check);
661
662        let result = test_check_submodule_base(
663            "test_submodule_watch_remove_as_file",
664            REMOVE_SUBMODULE_AS_FILE,
665            ADD_SUBMODULE_TOPIC,
666            &conf,
667        );
668
669        assert_eq!(result.warnings().len(), 0);
670        assert_eq!(result.alerts().len(), 1);
671        assert_eq!(
672            result.alerts()[0],
673            "commit 24573935ac8f352893022e454d03a6450a9e5fe5 removes the submodule at `submodule`.",
674        );
675        assert_eq!(result.errors().len(), 0);
676        assert!(!result.temporary());
677        assert!(!result.allowed());
678        assert!(result.pass());
679    }
680
681    #[test]
682    fn test_submodule_watch_remove_as_file_topic() {
683        let check = SubmoduleWatch::default();
684        let conf = make_topic_check_conf(&check);
685
686        let result = test_check_submodule_base(
687            "test_submodule_watch_remove_as_file_topic",
688            REMOVE_SUBMODULE_AS_FILE,
689            ADD_SUBMODULE_TOPIC,
690            &conf,
691        );
692
693        assert_eq!(result.warnings().len(), 0);
694        assert_eq!(result.alerts().len(), 1);
695        assert_eq!(result.alerts()[0], "removes the submodule at `submodule`.");
696        assert_eq!(result.errors().len(), 0);
697        assert!(!result.temporary());
698        assert!(!result.allowed());
699        assert!(result.pass());
700    }
701
702    #[test]
703    fn test_submodule_watch_remove_as_file_topic_fixed() {
704        let check = SubmoduleWatch::default();
705        let conf = make_topic_check_conf(&check);
706
707        let result = test_check_submodule_base(
708            "test_submodule_watch_remove_as_file_topic_fixed",
709            REMOVE_SUBMODULE_AS_FILE_FIXED,
710            ADD_SUBMODULE_TOPIC,
711            &conf,
712        );
713        test_result_ok(result);
714    }
715
716    #[test]
717    fn test_submodule_watch_remove_reject() {
718        let check = SubmoduleWatch::builder()
719            .reject_removals(true)
720            .build()
721            .unwrap();
722        let conf = make_check_conf(&check);
723
724        let result = test_check_submodule_base(
725            "test_submodule_watch_remove_reject",
726            REMOVE_SUBMODULE_TOPIC,
727            ADD_SUBMODULE_TOPIC,
728            &conf,
729        );
730        test_result_errors(result, &[
731            "commit 336dbaa31d512033fe77eaba7f92ebfecbd17a39 removes the submodule at `submodule` \
732             which is not allowed.",
733        ]);
734    }
735
736    #[test]
737    fn test_submodule_watch_remove_reject_topic() {
738        let check = SubmoduleWatch::builder()
739            .reject_removals(true)
740            .build()
741            .unwrap();
742        let conf = make_topic_check_conf(&check);
743
744        let result = test_check_submodule_base(
745            "test_submodule_watch_remove_reject_topic",
746            REMOVE_SUBMODULE_TOPIC,
747            ADD_SUBMODULE_TOPIC,
748            &conf,
749        );
750        test_result_errors(
751            result,
752            &["removes the submodule at `submodule` which is not allowed."],
753        );
754    }
755
756    #[test]
757    fn test_submodule_watch_remove_reject_topic_fixed() {
758        let check = SubmoduleWatch::builder()
759            .reject_removals(true)
760            .build()
761            .unwrap();
762        let conf = make_topic_check_conf(&check);
763
764        let result = test_check_submodule_base(
765            "test_submodule_watch_remove_reject_topic_fixed",
766            REMOVE_SUBMODULE_TOPIC_FIXED,
767            ADD_SUBMODULE_TOPIC,
768            &conf,
769        );
770        test_result_ok(result);
771    }
772
773    #[test]
774    fn test_submodule_watch_remove_as_file_reject() {
775        let check = SubmoduleWatch::builder()
776            .reject_removals(true)
777            .build()
778            .unwrap();
779        let conf = make_check_conf(&check);
780
781        let result = test_check_submodule_base(
782            "test_submodule_watch_remove_as_file_reject",
783            REMOVE_SUBMODULE_AS_FILE,
784            ADD_SUBMODULE_TOPIC,
785            &conf,
786        );
787        test_result_errors(result, &[
788            "commit 24573935ac8f352893022e454d03a6450a9e5fe5 removes the submodule at `submodule` \
789             which is not allowed.",
790        ]);
791    }
792
793    #[test]
794    fn test_submodule_watch_remove_as_file_reject_topic() {
795        let check = SubmoduleWatch::builder()
796            .reject_removals(true)
797            .build()
798            .unwrap();
799        let conf = make_topic_check_conf(&check);
800
801        let result = test_check_submodule_base(
802            "test_submodule_watch_remove_as_file_reject_topic",
803            REMOVE_SUBMODULE_AS_FILE,
804            ADD_SUBMODULE_TOPIC,
805            &conf,
806        );
807        test_result_errors(
808            result,
809            &["removes the submodule at `submodule` which is not allowed."],
810        );
811    }
812
813    #[test]
814    fn test_submodule_watch_remove_as_file_reject_topic_fixed() {
815        let check = SubmoduleWatch::builder()
816            .reject_removals(true)
817            .build()
818            .unwrap();
819        let conf = make_topic_check_conf(&check);
820
821        let result = test_check_submodule_base(
822            "test_submodule_watch_remove_as_file_reject_topic_fixed",
823            REMOVE_SUBMODULE_AS_FILE_FIXED,
824            ADD_SUBMODULE_TOPIC,
825            &conf,
826        );
827        test_result_ok(result);
828    }
829
830    #[test]
831    fn test_submodule_watch_modified() {
832        let check = SubmoduleWatch::builder()
833            .reject_removals(true)
834            .build()
835            .unwrap();
836        let conf = make_check_conf(&check);
837
838        let result = test_check_base(
839            "test_submodule_watch_modified",
840            MOVE_SUBMODULE,
841            ADD_SUBMODULE_TOPIC,
842            &conf,
843        );
844
845        assert_eq!(result.warnings().len(), 1);
846        assert_eq!(
847            result.warnings()[0],
848            "commit 2088079e35503be3be41dbdca55080ced95614e1 modifies an unconfigured submodule \
849             at `submodule`.",
850        );
851        assert_eq!(result.alerts().len(), 0);
852        assert_eq!(result.errors().len(), 0);
853        assert!(result.temporary());
854        assert!(!result.allowed());
855        assert!(result.pass());
856    }
857
858    #[test]
859    fn test_submodule_watch_modified_topic() {
860        let check = SubmoduleWatch::builder()
861            .reject_removals(true)
862            .build()
863            .unwrap();
864        let conf = make_topic_check_conf(&check);
865
866        let result = test_check_base(
867            "test_submodule_watch_modified_topic",
868            MOVE_SUBMODULE,
869            ADD_SUBMODULE_TOPIC,
870            &conf,
871        );
872
873        assert_eq!(result.warnings().len(), 1);
874        assert_eq!(
875            result.warnings()[0],
876            "modifies an unconfigured submodule at `submodule`.",
877        );
878        assert_eq!(result.alerts().len(), 0);
879        assert_eq!(result.errors().len(), 0);
880        assert!(result.temporary());
881        assert!(!result.allowed());
882        assert!(result.pass());
883    }
884
885    #[test]
886    fn test_submodule_watch_modified_topic_fixed() {
887        let check = SubmoduleWatch::builder()
888            .reject_removals(true)
889            .build()
890            .unwrap();
891        let conf = make_topic_check_conf(&check);
892
893        let result = test_check_base(
894            "test_submodule_watch_modified_topic_fixed",
895            MOVE_SUBMODULE_FIXED,
896            ADD_SUBMODULE_TOPIC,
897            &conf,
898        );
899        test_result_ok(result);
900    }
901
902    #[test]
903    fn test_submodule_watch_configure_modified() {
904        let check = SubmoduleWatch::builder()
905            .reject_removals(true)
906            .build()
907            .unwrap();
908        let conf = make_check_conf(&check);
909
910        let result = test_check_submodule_base_configure(
911            "test_submodule_watch_configure_modified",
912            MOVE_SUBMODULE,
913            ADD_SUBMODULE_TOPIC,
914            &conf,
915            "submodule",
916        );
917        test_result_ok(result);
918    }
919
920    #[test]
921    fn test_submodule_watch_configure_modified_topic() {
922        let check = SubmoduleWatch::builder()
923            .reject_removals(true)
924            .build()
925            .unwrap();
926        let conf = make_topic_check_conf(&check);
927
928        let result = test_check_submodule_base_configure(
929            "test_submodule_watch_configure_modified_topic",
930            MOVE_SUBMODULE,
931            ADD_SUBMODULE_TOPIC,
932            &conf,
933            "submodule",
934        );
935        test_result_ok(result);
936    }
937
938    // TODO: Test submodule.path setting changes.
939}