dt_core/
lib.rs

1//! This is a helper library, containing shared utilities used by [`DT`].
2//!
3//! [`DT`]: https://github.com/blurgyy/dt
4
5/// Definitions for configuration structures and rules.
6#[deny(missing_docs)]
7pub mod config;
8
9/// Definitions for errors
10#[deny(missing_docs)]
11pub mod error;
12
13/// Operations and abstractions for items.
14#[deny(missing_docs)]
15pub mod item;
16
17/// Helper utilities used internally (the [`Register`] trait and the register
18/// type [`Registry`] with cache for templates and rendered contents) and
19/// exposed for templating uses (additional [built-in helpers]).
20///
21/// [`Register`]: registry::Register
22/// [`Registry`]: registry::Registry
23/// [built-in helpers]: registry::helpers
24#[deny(missing_docs)]
25pub mod registry;
26
27/// Definitions for syncing behaviours.
28#[deny(missing_docs)]
29pub mod syncing;
30
31/// Miscellaneous utilities.
32#[deny(missing_docs)]
33pub mod utils;
34
35#[cfg(test)]
36mod inline_helpers {
37    mod get_mine {
38        use std::str::FromStr;
39
40        use crate::{
41            config::DTConfig,
42            registry::{Register, Registry},
43            syncing::expand,
44            utils::testing::{get_testroot, prepare_directory, prepare_file},
45        };
46
47        use color_eyre::Report;
48        use pretty_assertions::assert_eq;
49
50        #[test]
51        fn no_param() -> Result<(), Report> {
52            let base = prepare_directory(
53                get_testroot("inline_helpers")
54                    .join("get_mine")
55                    .join("no_param"),
56                0o755,
57            )?;
58            let src_name = "template";
59            let template_path = prepare_file(base.join(src_name), 0o644)?;
60            let target = prepare_directory(base.join("target"), 0o755)?;
61            let config = expand(DTConfig::from_str(&format!(
62                r#"
63[[local]]
64name = "group"
65base = "{}"
66target = "{}"
67sources = ["{}"]
68"#,
69                base.display(),
70                target.display(),
71                src_name,
72            ))?)?;
73            std::fs::write(&template_path, r#"Hi, {{get_mine}}!"#)?;
74            let reg = Registry::default().register_helpers()?.load(&config)?;
75            assert_eq!(
76                "Hi, r2d2!",
77                std::str::from_utf8(&reg.get(&template_path.to_string_lossy())?)?,
78            );
79            Ok(())
80        }
81
82        #[test]
83        fn lookup() -> Result<(), Report> {
84            let base = prepare_directory(
85                get_testroot("inline_helpers")
86                    .join("get_mine")
87                    .join("lookup"),
88                0o755,
89            )?;
90            let src_name = "template";
91            let template_path = prepare_file(base.join(src_name), 0o644)?;
92            let target = prepare_directory(base.join("target"), 0o755)?;
93            let config = expand(DTConfig::from_str(&format!(
94                r#"
95[context.testing_group]
96origin.HAL9000 = "2001: a Space Odyssey"
97origin.c-3po = "Star Wars"
98origin.r2d2 = "Star Wars"
99
100[[local]]
101name = "testing_group"
102base = "{}"
103target = "{}"
104sources = ["{}"]
105"#,
106                base.display(),
107                target.display(),
108                src_name,
109            ))?)?;
110            std::fs::write(
111                &template_path,
112                r#"The name r2d2 comes from _{{get_mine testing_group.origin "None"}}_"#,
113            )?;
114            let reg = Registry::default().register_helpers()?.load(&config)?;
115            assert_eq!(
116                "The name r2d2 comes from _Star Wars_",
117                std::str::from_utf8(&reg.get(&template_path.to_string_lossy())?)?,
118            );
119            Ok(())
120        }
121    }
122}
123
124#[cfg(test)]
125mod block_helpers {
126    mod user {
127        use std::str::FromStr;
128
129        use crate::{
130            config::DTConfig,
131            registry::{Register, Registry},
132            syncing::expand,
133            utils::testing::{get_testroot, prepare_directory, prepare_file},
134        };
135
136        use color_eyre::Report;
137        use pretty_assertions::assert_eq;
138
139        #[test]
140        fn if_user_exact() -> Result<(), Report> {
141            let base = prepare_directory(
142                get_testroot("block_helpers")
143                    .join("user")
144                    .join("if_user_exact"),
145                0o755,
146            )?;
147            let src_name = "template";
148            let template_path = prepare_file(base.join(src_name), 0o644)?;
149            let target = prepare_directory(base.join("target"), 0o755)?;
150            let config = expand(DTConfig::from_str(&format!(
151                r#"
152[[local]]
153name = "user"
154base = "{}"
155target = "{}"
156sources = ["{}"]
157"#,
158                base.display(),
159                target.display(),
160                src_name,
161            ))?)?;
162            std::fs::write(
163                &template_path,
164                r#"Hi, {{#if_user "luke"}}Luke Skywalker{{else}}random person{{/if_user}}!"#,
165            )?;
166            let reg = Registry::default().register_helpers()?.load(&config)?;
167            assert_eq!(
168                "Hi, Luke Skywalker!",
169                std::str::from_utf8(&reg.get(&template_path.to_string_lossy())?)?,
170            );
171
172            let config = expand(DTConfig::from_str(&format!(
173                r#"
174[context.user]
175name = "luke"
176
177[[local]]
178name = "user"
179base = "{}"
180target = "{}"
181sources = ["{}"]
182"#,
183                base.display(),
184                target.display(),
185                src_name,
186            ))?)?;
187            std::fs::write(
188                &template_path,
189                r#"Welcome back, {{#if_user user.name}}Luke Skywalker{{else}}random person{{/if_user}}!"#,
190            )?;
191            let reg = Registry::default().register_helpers()?.load(&config)?;
192            assert_eq!(
193                "Welcome back, Luke Skywalker!",
194                std::str::from_utf8(&reg.get(&template_path.to_string_lossy())?)?,
195            );
196            Ok(())
197        }
198
199        #[test]
200        fn if_user_any() -> Result<(), Report> {
201            let base = prepare_directory(
202                get_testroot("block_helpers")
203                    .join("user")
204                    .join("if_user_any"),
205                0o755,
206            )?;
207            let src_name = "template";
208            let template_path = prepare_file(base.join(src_name), 0o644)?;
209            let target = prepare_directory(base.join("target"), 0o755)?;
210            let config = expand(DTConfig::from_str(&format!(
211                r#"
212[[local]]
213name = "user"
214base = "{}"
215target = "{}"
216sources = ["{}"]
217"#,
218                base.display(),
219                target.display(),
220                src_name,
221            ))?)?;
222
223            std::fs::write(
224                &template_path,
225                r#"Hi, {{#if_user "luke,skywalker"}}Luke Skywalker{{else}}random person{{/if_user}}!"#,
226            )?;
227            let reg = Registry::default().register_helpers()?.load(&config)?;
228            assert_eq!(
229                "Hi, Luke Skywalker!",
230                std::str::from_utf8(&reg.get(&template_path.to_string_lossy())?)?,
231            );
232
233            let config = expand(DTConfig::from_str(&format!(
234                r#"
235[context.user]
236allowed_names = [
237    "skywalker",
238    "luke",
239]
240
241[[local]]
242name = "user"
243base = "{}"
244target = "{}"
245sources = ["{}"]
246"#,
247                base.display(),
248                target.display(),
249                src_name,
250            ))?)?;
251            std::fs::write(
252                &template_path,
253                "Welcome back, {{#if_user user.allowed_names}}Luke Skywalker{{else}}random person{{/if_user}}!",
254            )?;
255            let reg = Registry::default().register_helpers()?.load(&config)?;
256            assert_eq!(
257                "Welcome back, Luke Skywalker!",
258                std::str::from_utf8(&reg.get(&template_path.to_string_lossy())?)?,
259            );
260            Ok(())
261        }
262
263        #[test]
264        fn unless_user_exact() -> Result<(), Report> {
265            let base = prepare_directory(
266                get_testroot("block_helpers")
267                    .join("user")
268                    .join("unless_user_exact"),
269                0o755,
270            )?;
271            let src_name = "template";
272            let template_path = prepare_file(base.join(src_name), 0o644)?;
273            let target = prepare_directory(base.join("target"), 0o755)?;
274            let config = expand(DTConfig::from_str(&format!(
275                r#"
276[[local]]
277name = "user"
278base = "{}"
279target = "{}"
280sources = ["{}"]
281"#,
282                base.display(),
283                target.display(),
284                src_name,
285            ))?)?;
286            std::fs::write(
287                &template_path,
288                r#"Hi, {{#unless_user "luke"}}random person{{else}}Luke Skywalker{{/unless_user}}!"#,
289            )?;
290            let reg = Registry::default().register_helpers()?.load(&config)?;
291            assert_eq!(
292                "Hi, Luke Skywalker!",
293                std::str::from_utf8(&reg.get(&template_path.to_string_lossy())?)?,
294            );
295
296            let config = expand(DTConfig::from_str(&format!(
297                r#"
298[context.user]
299name = "luke"
300
301[[local]]
302name = "user"
303base = "{}"
304target = "{}"
305sources = ["{}"]
306"#,
307                base.display(),
308                target.display(),
309                src_name,
310            ))?)?;
311            std::fs::write(
312                &template_path,
313                "Welcome back, {{#unless_user user.name}}random person{{else}}Luke Skywalker{{/unless_user}}!",
314            )?;
315            let reg = Registry::default().register_helpers()?.load(&config)?;
316            assert_eq!(
317                "Welcome back, Luke Skywalker!",
318                std::str::from_utf8(&reg.get(&template_path.to_string_lossy())?)?,
319            );
320            Ok(())
321        }
322
323        #[test]
324        fn unless_user_any() -> Result<(), Report> {
325            let base = prepare_directory(
326                get_testroot("block_helpers")
327                    .join("user")
328                    .join("unless_user_any"),
329                0o755,
330            )?;
331            let src_name = "template";
332            let template_path = prepare_file(base.join(src_name), 0o644)?;
333            let target = prepare_directory(base.join("target"), 0o755)?;
334            let config = expand(DTConfig::from_str(&format!(
335                r#"
336[[local]]
337name = "user"
338base = "{}"
339target = "{}"
340sources = ["{}"]
341"#,
342                base.display(),
343                target.display(),
344                src_name,
345            ))?)?;
346
347            std::fs::write(
348                &template_path,
349                r#"Hi, {{#unless_user "luke,skywalker"}}random person{{else}}Luke Skywalker{{/unless_user}}!"#,
350            )?;
351            let reg = Registry::default().register_helpers()?.load(&config)?;
352            assert_eq!(
353                "Hi, Luke Skywalker!",
354                std::str::from_utf8(&reg.get(&template_path.to_string_lossy())?)?,
355            );
356
357            let config = expand(DTConfig::from_str(&format!(
358                r#"
359[context.user]
360allowed_names = [
361    "luke",
362    "skywalker"
363]
364
365[[local]]
366name = "user"
367base = "{}"
368target = "{}"
369sources = ["{}"]
370"#,
371                base.display(),
372                target.display(),
373                src_name,
374            ))?)?;
375            std::fs::write(
376                &template_path,
377                r#"Welcome back, {{#unless_user user.allowed_names}}random person{{else}}Luke Skywalker{{/unless_user}}!"#,
378            )?;
379            let reg = Registry::default().register_helpers()?.load(&config)?;
380            assert_eq!(
381                "Welcome back, Luke Skywalker!",
382                std::str::from_utf8(&reg.get(&template_path.to_string_lossy())?)?,
383            );
384            Ok(())
385        }
386    }
387
388    mod uid {
389        use std::str::FromStr;
390
391        use crate::{
392            config::DTConfig,
393            registry::{Register, Registry},
394            syncing::expand,
395            utils::testing::{get_testroot, prepare_directory, prepare_file},
396        };
397
398        use color_eyre::Report;
399        use pretty_assertions::assert_eq;
400
401        #[test]
402        fn if_uid_exact() -> Result<(), Report> {
403            let base = prepare_directory(
404                get_testroot("block_helpers")
405                    .join("uid")
406                    .join("if_uid_exact"),
407                0o755,
408            )?;
409            let src_name = "template";
410            let template_path = prepare_file(base.join(src_name), 0o644)?;
411            let target = prepare_directory(base.join("target"), 0o755)?;
412            let config = expand(DTConfig::from_str(&format!(
413                r#"
414[[local]]
415name = "uid"
416base = "{}"
417target = "{}"
418sources = ["{}"]
419"#,
420                base.display(),
421                target.display(),
422                src_name,
423            ))?)?;
424
425            std::fs::write(
426                &template_path,
427                "Hi, {{#if_uid 418}}teapot{{else}}random user{{/if_uid}}",
428            )?;
429            let reg = Registry::default().register_helpers()?.load(&config)?;
430            assert_eq!(
431                "Hi, teapot",
432                std::str::from_utf8(&reg.get(&template_path.to_string_lossy())?)?,
433            );
434
435            let config = expand(DTConfig::from_str(&format!(
436                r#"
437[context.uid]
438number = 418
439
440[[local]]
441name = "uid"
442base = "{}"
443target = "{}"
444sources = ["{}"]
445"#,
446                base.display(),
447                target.display(),
448                src_name,
449            ))?)?;
450            std::fs::write(
451                &template_path,
452                r#"Hello {{#if_uid uid.number}}teapot{{else}}there{{/if_uid}}"#,
453            )?;
454            let reg = Registry::default().register_helpers()?.load(&config)?;
455            assert_eq!(
456                "Hello teapot",
457                std::str::from_utf8(&reg.get(&template_path.to_string_lossy())?)?,
458            );
459            Ok(())
460        }
461
462        #[test]
463        fn if_uid_any() -> Result<(), Report> {
464            let base = prepare_directory(
465                get_testroot("block_helpers").join("uid").join("if_uid_any"),
466                0o755,
467            )?;
468            let src_name = "template";
469            let template_path = prepare_file(base.join(src_name), 0o644)?;
470            let target = prepare_directory(base.join("target"), 0o755)?;
471            let config = expand(DTConfig::from_str(&format!(
472                r#"
473[context]
474uid = true
475
476[[local]]
477name = "uid"
478base = "{}"
479target = "{}"
480sources = ["{}"]
481"#,
482                base.display(),
483                target.display(),
484                src_name,
485            ))?)?;
486
487            std::fs::write(
488                &template_path,
489                r#"Hi, {{#if_uid "410,412,418"}}user#410/412/418{{else}}random person{{/if_uid}}!"#,
490            )?;
491            let reg = Registry::default().register_helpers()?.load(&config)?;
492            assert_eq!(
493                "Hi, user#410/412/418!",
494                std::str::from_utf8(&reg.get(&template_path.to_string_lossy())?)?,
495            );
496
497            // Match inverse block
498            let config = expand(DTConfig::from_str(&format!(
499                r#"
500[context.uid]
501allowed_numbers = [1000, 1001]
502
503[[local]]
504name = "uid"
505base = "{}"
506target = "{}"
507sources = ["{}"]
508"#,
509                base.display(),
510                target.display(),
511                src_name,
512            ))?)?;
513            std::fs::write(
514                &template_path,
515                r#"You are {{#if_uid uid.allowed_numbers}}{{else}}not {{/if_uid}}user#1000/1001"#,
516            )?;
517            let reg = Registry::default().register_helpers()?.load(&config)?;
518            assert_eq!(
519                "You are not user#1000/1001",
520                std::str::from_utf8(&reg.get(&template_path.to_string_lossy())?)?,
521            );
522            Ok(())
523        }
524
525        #[test]
526        fn unless_uid_exact() -> Result<(), Report> {
527            let base = prepare_directory(
528                get_testroot("block_helpers")
529                    .join("uid")
530                    .join("unless_uid_exact"),
531                0o755,
532            )?;
533            let src_name = "template";
534            let template_path = prepare_file(base.join(src_name), 0o644)?;
535            let target = prepare_directory(base.join("target"), 0o755)?;
536            let config = expand(DTConfig::from_str(&format!(
537                r#"
538[[local]]
539name = "uid"
540base = "{}"
541target = "{}"
542sources = ["{}"]
543"#,
544                base.display(),
545                target.display(),
546                src_name,
547            ))?)?;
548
549            std::fs::write(
550                &template_path,
551                "Hi, {{#unless_uid 418}}random user{{else}}teapot{{/unless_uid}}",
552            )?;
553            let reg = Registry::default().register_helpers()?.load(&config)?;
554            assert_eq!(
555                "Hi, teapot",
556                std::str::from_utf8(&reg.get(&template_path.to_string_lossy())?)?,
557            );
558
559            let config = expand(DTConfig::from_str(&format!(
560                r#"
561[context.uid]
562number = 418
563
564[[local]]
565name = "uid"
566base = "{}"
567target = "{}"
568sources = ["{}"]
569"#,
570                base.display(),
571                target.display(),
572                src_name,
573            ))?)?;
574            std::fs::write(
575                &template_path,
576                r#"Hello {{#if_uid uid.number}}teapot{{else}}there{{/if_uid}}"#,
577            )?;
578            let reg = Registry::default().register_helpers()?.load(&config)?;
579            assert_eq!(
580                "Hello teapot",
581                std::str::from_utf8(&reg.get(&template_path.to_string_lossy())?)?,
582            );
583            Ok(())
584        }
585
586        #[test]
587        fn unless_uid_any() -> Result<(), Report> {
588            let base = prepare_directory(
589                get_testroot("block_helpers")
590                    .join("uid")
591                    .join("unless_uid_any"),
592                0o755,
593            )?;
594            let src_name = "template";
595            let template_path = prepare_file(base.join(src_name), 0o644)?;
596            let target = prepare_directory(base.join("target"), 0o755)?;
597            let config = expand(DTConfig::from_str(&format!(
598                r#"
599[[local]]
600name = "uid"
601base = "{}"
602target = "{}"
603sources = ["{}"]
604"#,
605                base.display(),
606                target.display(),
607                src_name,
608            ))?)?;
609
610            std::fs::write(
611                &template_path,
612                r#"You {{#unless_uid "410,412,418"}}can't{{else}}might{{/unless_uid}} be a teapot"#,
613            )?;
614            let reg = Registry::default().register_helpers()?.load(&config)?;
615            assert_eq!(
616                "You might be a teapot",
617                std::str::from_utf8(&reg.get(&template_path.to_string_lossy())?)?,
618            );
619
620            let config = expand(DTConfig::from_str(&format!(
621                r#"
622[context.uid]
623allowed_numbers = [410, 418, 412, 416]
624
625[[local]]
626name = "uid"
627base = "{}"
628target = "{}"
629sources = ["{}"]
630"#,
631                base.display(),
632                target.display(),
633                src_name,
634            ))?)?;
635            std::fs::write(
636                &template_path,
637                r#"You {{#unless_uid uid.allowed_numbers}}can't{{else}}might{{/unless_uid}} be a teapot"#,
638            )?;
639            let reg = Registry::default().register_helpers()?.load(&config)?;
640            assert_eq!(
641                "You might be a teapot",
642                std::str::from_utf8(&reg.get(&template_path.to_string_lossy())?)?,
643            );
644            Ok(())
645        }
646    }
647
648    mod host {
649        use std::str::FromStr;
650
651        use crate::{
652            config::DTConfig,
653            registry::{Register, Registry},
654            syncing::expand,
655            utils::testing::{get_testroot, prepare_directory, prepare_file},
656        };
657
658        use color_eyre::Report;
659        use pretty_assertions::assert_eq;
660
661        #[test]
662        fn if_host_exact() -> Result<(), Report> {
663            let base = prepare_directory(
664                get_testroot("block_helpers")
665                    .join("host")
666                    .join("if_host_exact"),
667                0o755,
668            )?;
669            let src_name = "template";
670            let template_path = prepare_file(base.join(src_name), 0o644)?;
671            let target = prepare_directory(base.join("target"), 0o755)?;
672            let config = expand(DTConfig::from_str(&format!(
673                r#"
674[[local]]
675name = "host"
676base = "{}"
677target = "{}"
678sources = ["{}"]
679"#,
680                base.display(),
681                target.display(),
682                src_name,
683            ))?)?;
684
685            std::fs::write(
686                &template_path,
687                r#"I have {{#if_host "c-3po"}}a bad{{else}}beep boop bop{{/if_host}} feeling about this"#,
688            )?;
689            let reg = Registry::default().register_helpers()?.load(&config)?;
690            assert_eq!(
691                "I have beep boop bop feeling about this",
692                std::str::from_utf8(&reg.get(&template_path.to_string_lossy())?)?,
693            );
694
695            let config = expand(DTConfig::from_str(&format!(
696                r#"
697[context.host]
698name = "r2d2"
699
700[[local]]
701name = "host"
702base = "{}"
703target = "{}"
704sources = ["{}"]
705"#,
706                base.display(),
707                target.display(),
708                src_name,
709            ))?)?;
710            std::fs::write(
711                &template_path,
712                r#"This is a {{#if_host host.name}}blue-white{{else}}golden{{/if_host}} one"#,
713            )?;
714            let reg = Registry::default().register_helpers()?.load(&config)?;
715            assert_eq!(
716                "This is a blue-white one",
717                std::str::from_utf8(&reg.get(&template_path.to_string_lossy())?)?,
718            );
719            Ok(())
720        }
721
722        #[test]
723        fn if_host_any() -> Result<(), Report> {
724            let base = prepare_directory(
725                get_testroot("block_helpers")
726                    .join("host")
727                    .join("if_host_any"),
728                0o755,
729            )?;
730            let src_name = "template";
731            let template_path = prepare_file(base.join(src_name), 0o644)?;
732            let target = prepare_directory(base.join("target"), 0o755)?;
733            let config = expand(DTConfig::from_str(&format!(
734                r#"
735[[local]]
736name = "host"
737base = "{}"
738target = "{}"
739sources = ["{}"]
740"#,
741                base.display(),
742                target.display(),
743                src_name,
744            ))?)?;
745
746            std::fs::write(
747                &template_path,
748                r#"I {{#if_host "c-3po,r2d2"}}{{else}}don't {{/if_host}}know Luke"#,
749            )?;
750            let reg = Registry::default().register_helpers()?.load(&config)?;
751            assert_eq!(
752                "I know Luke",
753                std::str::from_utf8(&reg.get(&template_path.to_string_lossy())?)?,
754            );
755
756            let config = expand(DTConfig::from_str(&format!(
757                r#"
758[context.host]
759allowed_names = [
760    "r2d2",
761    "bb8",
762]
763
764[[local]]
765name = "host"
766base = "{}"
767target = "{}"
768sources = ["{}"]
769"#,
770                base.display(),
771                target.display(),
772                src_name,
773            ))?)?;
774            std::fs::write(
775                &template_path,
776                r#"I have {{#if_host host.allowed_names}}beep boop bop{{else}}a bad{{/if_host}} feeling about this"#,
777            )?;
778            let reg = Registry::default().register_helpers()?.load(&config)?;
779            assert_eq!(
780                "I have beep boop bop feeling about this",
781                std::str::from_utf8(&reg.get(&template_path.to_string_lossy())?)?,
782            );
783            Ok(())
784        }
785
786        #[test]
787        fn unless_host_exact() -> Result<(), Report> {
788            let base = prepare_directory(
789                get_testroot("block_helpers")
790                    .join("host")
791                    .join("unless_host_exact"),
792                0o755,
793            )?;
794            let src_name = "template";
795            let template_path = prepare_file(base.join(src_name), 0o644)?;
796            let target = prepare_directory(base.join("target"), 0o755)?;
797            let config = expand(DTConfig::from_str(&format!(
798                r#"
799[[local]]
800name = "host"
801base = "{}"
802target = "{}"
803sources = ["{}"]
804"#,
805                base.display(),
806                target.display(),
807                src_name,
808            ))?)?;
809
810            std::fs::write(
811                &template_path,
812                r#"I have {{#unless_host "c-3po"}}beep boop bop{{else}}a bad{{/unless_host}} feeling about this"#,
813            )?;
814            let reg = Registry::default().register_helpers()?.load(&config)?;
815            assert_eq!(
816                "I have beep boop bop feeling about this",
817                std::str::from_utf8(&reg.get(&template_path.to_string_lossy())?)?,
818            );
819
820            let config = expand(DTConfig::from_str(&format!(
821                r#"
822[context.host]
823name = "r2d2"
824
825[[local]]
826name = "host"
827base = "{}"
828target = "{}"
829sources = ["{}"]
830"#,
831                base.display(),
832                target.display(),
833                src_name,
834            ))?)?;
835            std::fs::write(
836                &template_path,
837                r#"This is a {{#unless_host host.name}}golden{{else}}blue-white{{/unless_host}} one"#,
838            )?;
839            let reg = Registry::default().register_helpers()?.load(&config)?;
840            assert_eq!(
841                "This is a blue-white one",
842                std::str::from_utf8(&reg.get(&template_path.to_string_lossy())?)?,
843            );
844            Ok(())
845        }
846
847        #[test]
848        fn unless_host_any() -> Result<(), Report> {
849            let base = prepare_directory(
850                get_testroot("block_helpers")
851                    .join("host")
852                    .join("unless_host_any"),
853                0o755,
854            )?;
855            let src_name = "template";
856            let template_path = prepare_file(base.join(src_name), 0o644)?;
857            let target = prepare_directory(base.join("target"), 0o755)?;
858            let config = expand(DTConfig::from_str(&format!(
859                r#"
860[[local]]
861name = "host"
862base = "{}"
863target = "{}"
864sources = ["{}"]
865"#,
866                base.display(),
867                target.display(),
868                src_name,
869            ))?)?;
870
871            std::fs::write(
872                &template_path,
873                r#"I {{#unless_host "c-3po,r2d2"}}don't {{/unless_host}}know Luke"#,
874            )?;
875            let reg = Registry::default().register_helpers()?.load(&config)?;
876            assert_eq!(
877                "I know Luke",
878                std::str::from_utf8(&reg.get(&template_path.to_string_lossy())?)?,
879            );
880
881            let config = expand(DTConfig::from_str(&format!(
882                r#"
883[context.host]
884allowed_names = [
885    "r2d2",
886    "bb8",
887]
888
889[[local]]
890name = "host"
891base = "{}"
892target = "{}"
893sources = ["{}"]
894"#,
895                base.display(),
896                target.display(),
897                src_name,
898            ))?)?;
899            std::fs::write(
900                &template_path,
901                r#"I have {{#unless_host host.allowed_names}}a bad{{else}}beep boop bop{{/unless_host}} feeling about this"#,
902            )?;
903            let reg = Registry::default().register_helpers()?.load(&config)?;
904            println!("{:?}", crate::utils::testing::gethostname());
905            assert_eq!(
906                "I have beep boop bop feeling about this",
907                std::str::from_utf8(&reg.get(&template_path.to_string_lossy())?)?,
908            );
909            Ok(())
910        }
911    }
912
913    mod os {
914        use std::str::FromStr;
915
916        use crate::{
917            config::DTConfig,
918            registry::{Register, Registry},
919            syncing::expand,
920            utils::testing::{get_testroot, prepare_directory, prepare_file},
921        };
922
923        use color_eyre::Report;
924        use pretty_assertions::assert_eq;
925
926        #[test]
927        fn if_os_exact() -> Result<(), Report> {
928            let base = prepare_directory(
929                get_testroot("block_helpers").join("os").join("if_os_exact"),
930                0o755,
931            )?;
932            let src_name = "template";
933            let template_path = prepare_file(base.join(src_name), 0o644)?;
934            let target = prepare_directory(base.join("target"), 0o755)?;
935            let config = expand(DTConfig::from_str(&format!(
936                r#"
937[[local]]
938name = "os"
939base = "{}"
940target = "{}"
941sources = ["{}"]
942"#,
943                base.display(),
944                target.display(),
945                src_name,
946            ))?)?;
947
948            std::fs::write(
949                &template_path,
950                r#"{{#if_os "id" "dt"}}It works{{else}}Nope it's not working{{/if_os}}"#,
951            )?;
952            let reg = Registry::default().register_helpers()?.load(&config)?;
953            assert_eq!(
954                "It works",
955                std::str::from_utf8(&reg.get(&template_path.to_string_lossy())?)?,
956            );
957
958            let config = expand(DTConfig::from_str(&format!(
959                r#"
960[context.os]
961version = "latest"
962
963[[local]]
964name = "host"
965base = "{}"
966target = "{}"
967sources = ["{}"]
968"#,
969                base.display(),
970                target.display(),
971                src_name,
972            ))?)?;
973            std::fs::write(
974                &template_path,
975                r#"{{#if_os "version" os.version}}It works{{else}}Not working{{/if_os}}"#,
976            )?;
977            let reg = Registry::default().register_helpers()?.load(&config)?;
978            assert_eq!(
979                "It works",
980                std::str::from_utf8(&reg.get(&template_path.to_string_lossy())?)?,
981            );
982            Ok(())
983        }
984
985        #[test]
986        fn if_os_any() -> Result<(), Report> {
987            let base = prepare_directory(
988                get_testroot("block_helpers").join("os").join("if_os_any"),
989                0o755,
990            )?;
991            let src_name = "template";
992            let template_path = prepare_file(base.join(src_name), 0o644)?;
993            let target = prepare_directory(base.join("target"), 0o755)?;
994            let config = expand(DTConfig::from_str(&format!(
995                r#"
996[[local]]
997name = "os"
998base = "{}"
999target = "{}"
1000sources = ["{}"]
1001"#,
1002                base.display(),
1003                target.display(),
1004                src_name,
1005            ))?)?;
1006
1007            std::fs::write(
1008                &template_path,
1009                r#"{{#if_os "id" "dummy-version,dt"}}It works{{else}}Nope it's not working{{/if_os}}"#,
1010            )?;
1011            let reg = Registry::default().register_helpers()?.load(&config)?;
1012            assert_eq!(
1013                "It works",
1014                std::str::from_utf8(&reg.get(&template_path.to_string_lossy())?)?,
1015            );
1016
1017            let config = expand(DTConfig::from_str(&format!(
1018                r#"
1019[context.os]
1020version = ["0.99.99", "99.0.0"]
1021
1022[[local]]
1023name = "host"
1024base = "{}"
1025target = "{}"
1026sources = ["{}"]
1027"#,
1028                base.display(),
1029                target.display(),
1030                src_name,
1031            ))?)?;
1032            std::fs::write(
1033                &template_path,
1034                r#"{{#if_os "version_id" os.version}}It works{{else}}Not working{{/if_os}}"#,
1035            )?;
1036            let reg = Registry::default().register_helpers()?.load(&config)?;
1037            assert_eq!(
1038                "It works",
1039                std::str::from_utf8(&reg.get(&template_path.to_string_lossy())?)?,
1040            );
1041            Ok(())
1042        }
1043
1044        #[test]
1045        fn unless_os_exact() -> Result<(), Report> {
1046            let base = prepare_directory(
1047                get_testroot("block_helpers")
1048                    .join("os")
1049                    .join("unless_os_exact"),
1050                0o755,
1051            )?;
1052            let src_name = "template";
1053            let template_path = prepare_file(base.join(src_name), 0o644)?;
1054            let target = prepare_directory(base.join("target"), 0o755)?;
1055            let config = expand(DTConfig::from_str(&format!(
1056                r#"
1057[[local]]
1058name = "os"
1059base = "{}"
1060target = "{}"
1061sources = ["{}"]
1062"#,
1063                base.display(),
1064                target.display(),
1065                src_name,
1066            ))?)?;
1067
1068            std::fs::write(
1069                &template_path,
1070                r##"{{#unless_os "build_id" "#somethingsomething"}}Nope it's not working properly{{else}}It's working{{/unless_os}}"##,
1071            )?;
1072            let reg = Registry::default().register_helpers()?.load(&config)?;
1073            assert_eq!(
1074                "It's working",
1075                std::str::from_utf8(&reg.get(&template_path.to_string_lossy())?)?,
1076            );
1077
1078            let config = expand(DTConfig::from_str(&format!(
1079                r#"
1080[context.os]
1081logo = "Buzz Lightyear"
1082
1083[[local]]
1084name = "host"
1085base = "{}"
1086target = "{}"
1087sources = ["{}"]
1088"#,
1089                base.display(),
1090                target.display(),
1091                src_name,
1092            ))?)?;
1093            std::fs::write(
1094                &template_path,
1095                r#"{{#unless_os "logo" os.logo}}Broken{{else}}Up and running{{/unless_os}}"#,
1096            )?;
1097            let reg = Registry::default().register_helpers()?.load(&config)?;
1098            assert_eq!(
1099                "Up and running",
1100                std::str::from_utf8(&reg.get(&template_path.to_string_lossy())?)?,
1101            );
1102            Ok(())
1103        }
1104
1105        #[test]
1106        fn unless_os_any() -> Result<(), Report> {
1107            let base = prepare_directory(
1108                get_testroot("block_helpers")
1109                    .join("os")
1110                    .join("unless_os_any"),
1111                0o755,
1112            )?;
1113            let src_name = "template";
1114            let template_path = prepare_file(base.join(src_name), 0o644)?;
1115            let target = prepare_directory(base.join("target"), 0o755)?;
1116            let config = expand(DTConfig::from_str(&format!(
1117                r#"
1118[[local]]
1119name = "os"
1120base = "{}"
1121target = "{}"
1122sources = ["{}"]
1123"#,
1124                base.display(),
1125                target.display(),
1126                src_name,
1127            ))?)?;
1128
1129            std::fs::write(
1130                &template_path,
1131                r##"{{#unless_os "home_url" "https://example.com/,https://github.com/blurgyy/dt/"}}Nope it's not working properly{{else}}It's working{{/unless_os}}"##,
1132            )?;
1133            let reg = Registry::default().register_helpers()?.load(&config)?;
1134            assert_eq!(
1135                "It's working",
1136                std::str::from_utf8(&reg.get(&template_path.to_string_lossy())?)?,
1137            );
1138
1139            let config = expand(DTConfig::from_str(&format!(
1140                r#"
1141[context.os.documentation]
1142url = ["https://dt.cli.rs/", "https://github.com/blurgyy/dt/wiki/"]
1143
1144[[local]]
1145name = "host"
1146base = "{}"
1147target = "{}"
1148sources = ["{}"]
1149"#,
1150                base.display(),
1151                target.display(),
1152                src_name,
1153            ))?)?;
1154            std::fs::write(
1155                &template_path,
1156                r#"{{#unless_os "documentation_url" os.documentation.url}}xxxBroken{{else}}Up and running{{/unless_os}}"#,
1157            )?;
1158            let reg = Registry::default().register_helpers()?.load(&config)?;
1159            assert_eq!(
1160                "Up and running",
1161                std::str::from_utf8(&reg.get(&template_path.to_string_lossy())?)?,
1162            );
1163            Ok(())
1164        }
1165    }
1166}
1167
1168// Author: Blurgy <gy@blurgy.xyz>
1169// Date:   Sep 17 2021, 21:32 [CST]