deb/dependency/
tests.rs

1// {{{ Copyright (c) Paul R. Tagliamonte <paultag@debian.org>, 2024
2//
3// Permission is hereby granted, free of charge, to any person obtaining a copy
4// of this software and associated documentation files (the "Software"), to deal
5// in the Software without restriction, including without limitation the rights
6// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7// copies of the Software, and to permit persons to whom the Software is
8// furnished to do so, subject to the following conditions:
9//
10// The above copyright notice and this permission notice shall be included in
11// all copies or substantial portions of the Software.
12//
13// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19// THE SOFTWARE. }}}
20
21#[cfg(test)]
22mod test {
23    use crate::{
24        architecture::{self, Architecture},
25        build_profile::BuildProfile,
26        dependency::{
27            ArchConstraint, ArchConstraints, BuildProfileConstraint, BuildProfileConstraints,
28            Dependency, Package, Relation, VersionConstraint, VersionOperator,
29        },
30        version::Version,
31    };
32
33    macro_rules! check_parse_fails {
34        ($name:ident, $dep:expr) => {
35            #[test]
36            fn $name() {
37                assert!($dep.parse::<Dependency>().is_err());
38            }
39        };
40    }
41
42    check_parse_fails!(double_arch_constraints, "foo [amd64] [arm64]");
43    check_parse_fails!(double_version_constraint, "foo (= 1.0) (= 2.0)");
44    check_parse_fails!(invalid_version_constraint, "foo (1.0)");
45    check_parse_fails!(non_alpha_package, "💩");
46    check_parse_fails!(spacy_package, "a space");
47    check_parse_fails!(unknown_relation, "foo {bar}");
48    check_parse_fails!(no_package_arch_constraints, "[amd64]");
49    check_parse_fails!(no_package_arch, ":amd64");
50
51    macro_rules! check_matches {
52        ($name:ident, ( $( $dep:expr ),+ ), $check:expr) => {
53            #[test]
54            fn $name() {
55                $(
56                {
57                    let dep: Dependency = $dep.parse().unwrap();
58                    assert_eq!($check, dep, "expected {:?}, got {:?}", $check, dep);
59                }
60                )*
61            }
62        };
63
64        ($name:ident, $dep:expr, $check:expr) => {
65            check_matches!($name, ($dep), $check);
66        };
67    }
68
69    macro_rules! check_round_trips {
70        ($name:ident, ( $( $dep:expr ),+ ), $check:expr) => {
71            #[test]
72            fn $name() {
73                $(
74                {
75                    let dep: Dependency = $dep.parse().unwrap();
76                    assert_eq!($check, dep.to_string());
77                }
78                )*
79            }
80        };
81
82        ($name:ident, $dep:expr, $check:expr) => {
83            check_round_trips!($name, ($dep), $check);
84        };
85    }
86
87    macro_rules! simple_package {
88        ($package:expr) => {
89            Dependency {
90                relations: vec![Relation {
91                    packages: vec![$package],
92                }],
93            }
94        };
95    }
96
97    check_matches!(check_empty, "", Dependency { relations: vec![] });
98    check_matches!(
99        check_simple,
100        "foo",
101        simple_package!(Package {
102            name: "foo".to_owned(),
103            ..Default::default()
104        })
105    );
106    check_matches!(
107        check_simple_arch,
108        "foo:armhf",
109        simple_package!(Package {
110            name: "foo".to_owned(),
111            arch: Some(architecture::ARMHF),
112            ..Default::default()
113        })
114    );
115    check_matches!(
116        check_simple_packages,
117        "foo, bar | baz",
118        Dependency {
119            relations: vec![
120                Relation {
121                    packages: vec![Package {
122                        name: "foo".to_owned(),
123                        ..Default::default()
124                    },]
125                },
126                Relation {
127                    packages: vec![
128                        Package {
129                            name: "bar".to_owned(),
130                            ..Default::default()
131                        },
132                        Package {
133                            name: "baz".to_owned(),
134                            ..Default::default()
135                        },
136                    ]
137                }
138            ],
139        }
140    );
141    check_matches!(
142        check_versioned_gte,
143        "foo (>= 1.0)",
144        simple_package!(Package {
145            name: "foo".to_owned(),
146            version_constraint: Some(VersionConstraint {
147                operator: VersionOperator::GreaterThanOrEqual,
148                version: Version::from_parts(None, "1.0", None).unwrap(),
149            }),
150            ..Default::default()
151        })
152    );
153
154    check_matches!(
155        check_versioned_lte,
156        "foo (<= 1.0)",
157        simple_package!(Package {
158            name: "foo".to_owned(),
159            version_constraint: Some(VersionConstraint {
160                operator: VersionOperator::LessThanOrEqual,
161                version: Version::from_parts(None, "1.0", None).unwrap(),
162            }),
163            ..Default::default()
164        })
165    );
166
167    check_matches!(
168        check_versioned_eq,
169        "foo (= 1.0)",
170        simple_package!(Package {
171            name: "foo".to_owned(),
172            version_constraint: Some(VersionConstraint {
173                operator: VersionOperator::Equal,
174                version: Version::from_parts(None, "1.0", None).unwrap(),
175            }),
176            ..Default::default()
177        })
178    );
179
180    check_matches!(
181        check_versioned_eq2,
182        "foo (== 1.0)",
183        simple_package!(Package {
184            name: "foo".to_owned(),
185            version_constraint: Some(VersionConstraint {
186                operator: VersionOperator::Equal,
187                version: Version::from_parts(None, "1.0", None).unwrap(),
188            }),
189            ..Default::default()
190        })
191    );
192
193    check_matches!(
194        check_versioned_gt,
195        "foo (>> 1.0)",
196        simple_package!(Package {
197            name: "foo".to_owned(),
198            version_constraint: Some(VersionConstraint {
199                operator: VersionOperator::GreaterThan,
200                version: Version::from_parts(None, "1.0", None).unwrap(),
201            }),
202            ..Default::default()
203        })
204    );
205
206    check_matches!(
207        check_versioned_lt,
208        "foo (<< 1.0)",
209        simple_package!(Package {
210            name: "foo".to_owned(),
211            version_constraint: Some(VersionConstraint {
212                operator: VersionOperator::LessThan,
213                version: Version::from_parts(None, "1.0", None).unwrap(),
214            }),
215            ..Default::default()
216        })
217    );
218
219    check_matches!(
220        check_arch_qualified,
221        "foo [armhf]",
222        simple_package!(Package {
223            name: "foo".to_owned(),
224            arch_constraints: Some(ArchConstraints {
225                arches: vec![ArchConstraint {
226                    negated: false,
227                    arch: architecture::ARMHF,
228                }]
229            }),
230            ..Default::default()
231        })
232    );
233    check_matches!(
234        check_arch_qualified2,
235        "foo [armhf amd64]",
236        simple_package!(Package {
237            name: "foo".to_owned(),
238            arch_constraints: Some(ArchConstraints {
239                arches: vec![
240                    ArchConstraint {
241                        negated: false,
242                        arch: architecture::ARMHF,
243                    },
244                    ArchConstraint {
245                        negated: false,
246                        arch: architecture::AMD64,
247                    },
248                ]
249            }),
250            ..Default::default()
251        })
252    );
253    check_matches!(
254        check_arch_qualified_not,
255        "foo [!armhf !amd64]",
256        simple_package!(Package {
257            name: "foo".to_owned(),
258            arch_constraints: Some(ArchConstraints {
259                arches: vec![
260                    ArchConstraint {
261                        negated: true,
262                        arch: architecture::ARMHF,
263                    },
264                    ArchConstraint {
265                        negated: true,
266                        arch: architecture::AMD64,
267                    },
268                ]
269            }),
270            ..Default::default()
271        })
272    );
273
274    check_matches!(
275        check_build_profile,
276        "foo <buildprofile1>",
277        simple_package!(Package {
278            name: "foo".to_owned(),
279            build_profile_restriction_formula: Some(
280                vec![BuildProfileConstraints {
281                    build_profiles: vec![BuildProfileConstraint {
282                        negated: false,
283                        build_profile: BuildProfile::Unknown("buildprofile1".to_owned()),
284                    }]
285                }]
286                .into()
287            ),
288            ..Default::default()
289        })
290    );
291
292    check_matches!(
293        check_build_profile_multiple,
294        "foo <buildprofile1 cross>",
295        simple_package!(Package {
296            name: "foo".to_owned(),
297            build_profile_restriction_formula: Some(
298                vec![BuildProfileConstraints {
299                    build_profiles: vec![
300                        BuildProfileConstraint {
301                            negated: false,
302                            build_profile: BuildProfile::Unknown("buildprofile1".to_owned()),
303                        },
304                        BuildProfileConstraint {
305                            negated: false,
306                            build_profile: BuildProfile::Cross,
307                        },
308                    ]
309                }]
310                .into()
311            ),
312            ..Default::default()
313        })
314    );
315    check_matches!(
316        build_profile_multiple_not,
317        "foo <buildprofile1 !cross>",
318        simple_package!(Package {
319            name: "foo".to_owned(),
320            build_profile_restriction_formula: Some(
321                vec![BuildProfileConstraints {
322                    build_profiles: vec![
323                        BuildProfileConstraint {
324                            negated: false,
325                            build_profile: BuildProfile::Unknown("buildprofile1".to_owned()),
326                        },
327                        BuildProfileConstraint {
328                            negated: true,
329                            build_profile: BuildProfile::Cross,
330                        },
331                    ]
332                }]
333                .into()
334            ),
335            ..Default::default()
336        })
337    );
338
339    check_matches!(
340        check_spaces,
341        ("foo", "  foo", "foo   "),
342        simple_package!(Package {
343            name: "foo".to_owned(),
344            ..Default::default()
345        })
346    );
347
348    check_matches!(
349        check_spaces_version,
350        (
351            "foo(=1.0)",
352            "foo (= 1.0)",
353            "foo    (=1.0)",
354            "   foo    (  =   1.0   )"
355        ),
356        simple_package!(Package {
357            name: "foo".to_owned(),
358            version_constraint: Some(VersionConstraint {
359                operator: VersionOperator::Equal,
360                version: Version::from_parts(None, "1.0", None).unwrap(),
361            }),
362            ..Default::default()
363        })
364    );
365
366    check_matches!(
367        check_spaces_build_profile,
368        (
369            "foo<foo>",
370            "foo <foo>",
371            "foo    <foo>",
372            "foo    < foo>",
373            "foo    <foo >",
374            "foo    <   foo   >"
375        ),
376        simple_package!(Package {
377            name: "foo".to_owned(),
378            build_profile_restriction_formula: Some(
379                vec![BuildProfileConstraints {
380                    build_profiles: vec![BuildProfileConstraint {
381                        negated: false,
382                        build_profile: BuildProfile::Unknown("foo".to_owned()),
383                    }],
384                }]
385                .into()
386            ),
387            ..Default::default()
388        })
389    );
390
391    check_matches!(
392        check_spaces_build_profile_not,
393        (
394            "foo<!foo>",
395            "foo <!foo>",
396            "foo    <!foo>",
397            "foo    < !foo>",
398            "foo    <!foo >",
399            "foo    < !foo >",
400            "   foo    <!foo>",
401            "   foo    < ! foo >",
402            "   foo    <   !     foo >"
403        ),
404        simple_package!(Package {
405            name: "foo".to_owned(),
406            build_profile_restriction_formula: Some(
407                vec![BuildProfileConstraints {
408                    build_profiles: vec![BuildProfileConstraint {
409                        negated: true,
410                        build_profile: BuildProfile::Unknown("foo".to_owned()),
411                    }],
412                }]
413                .into()
414            ),
415            ..Default::default()
416        })
417    );
418
419    check_matches!(
420        check_spaces_build_profiles,
421        (
422            "foo<!foo bar>",
423            "foo <!foo bar>",
424            "foo    <!foo bar>",
425            "foo    < !foo bar>",
426            "foo    <!foo bar >",
427            "foo    <!foo     bar>",
428            "foo    < !foo bar >",
429            "   foo    <!foo bar>",
430            "   foo    < ! foo    bar >",
431            "   foo    <   !     foo  bar >"
432        ),
433        simple_package!(Package {
434            name: "foo".to_owned(),
435            build_profile_restriction_formula: Some(
436                vec![BuildProfileConstraints {
437                    build_profiles: vec![
438                        BuildProfileConstraint {
439                            negated: true,
440                            build_profile: BuildProfile::Unknown("foo".to_owned()),
441                        },
442                        BuildProfileConstraint {
443                            negated: false,
444                            build_profile: BuildProfile::Unknown("bar".to_owned())
445                        }
446                    ],
447                }]
448                .into()
449            ),
450            ..Default::default()
451        })
452    );
453
454    check_round_trips!(
455        rt_build_profile_pkg,
456        "foo <pkg.foo-bar.baz>",
457        "foo <pkg.foo-bar.baz>"
458    );
459    check_round_trips!(rt_build_profile_multi, "foo <foo> <bar>", "foo <foo> <bar>");
460
461    check_round_trips!(rt_simple, ("foo", " foo", " foo "), "foo");
462    check_round_trips!(
463        rt_relations,
464        (
465            "foo, bar",
466            "foo,  bar",
467            " foo,  bar ",
468            " foo , bar ",
469            "foo, bar ",
470            " foo,  bar"
471        ),
472        "foo, bar"
473    );
474    check_round_trips!(
475        rt_poss,
476        (
477            "foo,bar|baz",
478            "foo, bar | baz",
479            "foo , bar | baz",
480            " foo, bar | baz",
481            "foo, bar | baz ",
482            " foo, bar | baz"
483        ),
484        "foo, bar | baz"
485    );
486    check_round_trips!(
487        rt_constraints,
488        (
489            "foo (= 1.0) [arch1 !arch2] <buildprofile1 !buildprofile2>",
490            "foo (== 1.0) [arch1 !arch2] <buildprofile1 !buildprofile2>",
491            "foo [arch1 !arch2] (= 1.0) <buildprofile1 !buildprofile2>",
492            "foo [arch1 !arch2] <buildprofile1 !buildprofile2> (= 1.0)",
493            "foo <buildprofile1 !buildprofile2> (= 1.0) [arch1 !arch2]",
494            "foo <buildprofile1 !buildprofile2> [arch1 !arch2] (= 1.0)"
495        ),
496        "foo (= 1.0) [arch1 !arch2] <buildprofile1 !buildprofile2>"
497    );
498
499    check_matches!(
500        check_arch_tuple_match,
501        "foo [linux-any]",
502        simple_package!(Package {
503            name: "foo".to_owned(),
504            arch_constraints: Some(ArchConstraints {
505                arches: vec![ArchConstraint {
506                    negated: false,
507                    arch: Architecture::from_parts("any", "any", "linux", "any").unwrap(),
508                },]
509            }),
510            ..Default::default()
511        })
512    );
513
514    check_matches!(
515        check_newlines,
516        "\
517foo,
518bar | baz
519",
520        Dependency {
521            relations: vec![
522                Relation {
523                    packages: vec![Package {
524                        name: "foo".to_owned(),
525                        ..Default::default()
526                    },]
527                },
528                Relation {
529                    packages: vec![
530                        Package {
531                            name: "bar".to_owned(),
532                            ..Default::default()
533                        },
534                        Package {
535                            name: "baz".to_owned(),
536                            ..Default::default()
537                        },
538                    ]
539                }
540            ],
541        }
542    );
543}
544
545// vim: foldmethod=marker