Lightweight tagged data library.
1//! Tests for the crate's APIs.
2
3use crate::label::Label;
4use crate::parse::*;
5use crate::storage::Storage;
6use crate::tag::KeyValueSep;
7use crate::tag::PathSep;
8use crate::tag::Tag;
9use crate::tag::TagKind;
10use crate::TagManager;
11use anyhow::anyhow as err;
12use anyhow::Result;
13use string_interner::Symbol;
14
15// Helper function to test that a tag that's parsed and then resolved
16// back into a string results in the same string that was originally
17// put into the manager.
18fn test_roundtrip<L, S, T, P>(manager: &TagManager<L, S, T, P>, input: &str) -> Result<()>
19where
20 L: Label,
21 S: Symbol,
22 T: Tag<Label = L, Symbol = S>,
23 P: Parser<Tag = T> + Send + Sync,
24{
25 let tag = manager.parse_tag(input)?;
26 let output = manager.resolve_tag(&tag)?;
27 assert_eq!(input, output);
28 Ok(())
29}
30
31#[test]
32fn roundtrip_plain_tag() -> Result<()> {
33 let manager = TagManager::builder()
34 .parser(Plain::new())
35 .storage(Storage::default())
36 .build();
37
38 test_roundtrip(&manager, "hello")
39}
40
41#[test]
42fn transform_tag() -> Result<()> {
43 let parser = Trim(
44 TrimBounds::Both,
45 ChangeCase(Case::Snake, KeyValue::new(KvPolicy::NoAmbiguousSep)),
46 );
47
48 let manager = TagManager::builder()
49 .parser(parser)
50 .storage(Storage::default())
51 .key_value_separator(KeyValueSep("/"))
52 .build();
53
54 let tag = manager.parse_tag(" \t HELLO_WORLD/GOODBYE_WORLD ")?;
55 let interner = manager.storage().lock()?;
56 let (key, value) = tag.resolve_key_value(&interner)?;
57
58 assert_eq!(key, "hello_world");
59 assert_eq!(value, "goodbye_world");
60
61 Ok(())
62}
63
64#[test]
65fn roundtrip_key_value_tag_unambiguous() -> Result<()> {
66 let manager = TagManager::builder()
67 .parser(KeyValue::new(KvPolicy::NoAmbiguousSep))
68 .storage(Storage::default())
69 .build();
70
71 test_roundtrip(&manager, "hello:world")
72}
73
74#[test]
75fn key_part_key_value_tag_unambiguous() -> Result<()> {
76 let manager = TagManager::builder()
77 .parser(KeyValue::new(KvPolicy::NoAmbiguousSep))
78 .storage(Storage::default())
79 .build();
80
81 let input = "hello:world";
82 let tag = manager.parse_tag(input)?;
83 let lock = manager.storage().lock()?;
84 let (key, value) = tag.resolve_key_value(&lock)?;
85 assert_eq!(key, "hello");
86 assert_eq!(value, "world");
87
88 Ok(())
89}
90
91#[test]
92fn roundtrip_key_value_tag_split_first() -> Result<()> {
93 let manager = TagManager::builder()
94 .parser(KeyValue::new(KvPolicy::SplitOnFirstSep))
95 .storage(Storage::default())
96 .build();
97
98 test_roundtrip(&manager, "hello:world")
99}
100
101#[test]
102fn key_part_key_value_tag_split_first() -> Result<()> {
103 let manager = TagManager::builder()
104 .parser(KeyValue::new(KvPolicy::SplitOnFirstSep))
105 .storage(Storage::default())
106 .build();
107
108 let input = "hello:world:today";
109 let tag = manager.parse_tag(input)?;
110 let lock = manager.storage().lock()?;
111 let (key, value) = tag.resolve_key_value(&lock)?;
112 assert_eq!(key, "hello");
113 assert_eq!(value, "world:today");
114 Ok(())
115}
116
117#[test]
118fn roundtrip_key_value_tag_split_last() -> Result<()> {
119 let manager = TagManager::builder()
120 .parser(KeyValue::new(KvPolicy::SplitOnLastSep))
121 .storage(Storage::default())
122 .build();
123
124 test_roundtrip(&manager, "hello:world")
125}
126
127#[test]
128fn key_part_key_value_tag_split_last() -> Result<()> {
129 let manager = TagManager::builder()
130 .parser(KeyValue::new(KvPolicy::SplitOnLastSep))
131 .storage(Storage::default())
132 .build();
133
134 let input = "hello:world:today";
135 let tag = manager.parse_tag(input)?;
136 let lock = manager.storage().lock()?;
137 let (key, value) = tag.resolve_key_value(&lock)?;
138 assert_eq!(key, "hello:world");
139 assert_eq!(value, "today");
140 Ok(())
141}
142
143#[test]
144fn roundtrip_multipart_tag() -> Result<()> {
145 let manager = TagManager::builder()
146 .parser(Multipart::new(MultipartPolicy::RequireMultipart))
147 .storage(Storage::default())
148 .path_separator(PathSep(":"))
149 .build();
150
151 test_roundtrip(&manager, "hello:world:today:its:me")
152}
153
154#[test]
155fn complex_parser() -> Result<()> {
156 let manager = TagManager::builder()
157 .parser(Trim(
158 TrimBounds::Both,
159 ChangeCase(
160 Case::Snake,
161 Or(
162 Multipart::new(MultipartPolicy::RequireMultipart),
163 Or(KeyValue::new(KvPolicy::NoAmbiguousSep), Plain::new()),
164 ),
165 ),
166 ))
167 .storage(Storage::default())
168 .build();
169
170 let tags: Vec<_> =
171 manager.parse_tags_into_with_kind(["lotr/legolas/friends", "score:5", "rustlang"]);
172
173 let mut iter = tags.into_iter();
174 let (t1, t2, t3) = (
175 iter.next().ok_or(err!("nothing"))??,
176 iter.next().ok_or(err!("nothing"))??,
177 iter.next().ok_or(err!("nothing"))??,
178 );
179
180 assert_eq!(t1.1, TagKind::Multipart);
181 assert_eq!(t2.1, TagKind::KeyValue);
182 assert_eq!(t3.1, TagKind::Plain);
183
184 Ok(())
185}