diff options
| author | Mike Buland <mike@xagasoft.com> | 2026-08-19 13:05:01 -0700 |
|---|---|---|
| committer | Mike Buland <mike@xagasoft.com> | 2026-08-19 13:05:01 -0700 |
| commit | d1e78b4a3454984db74ebf2a302a64b985ce6de4 (patch) | |
| tree | d3953cd8aad144a1be131ff3c38688f93cbccbb5 /deepcrow/tests/basic.rs | |
| parent | 5602585e7afe431f25e68f30ac54761db2a710e5 (diff) | |
| download | deepcrow-d1e78b4a3454984db74ebf2a302a64b985ce6de4.tar.gz deepcrow-d1e78b4a3454984db74ebf2a302a64b985ce6de4.tar.bz2 deepcrow-d1e78b4a3454984db74ebf2a302a64b985ce6de4.tar.xz deepcrow-d1e78b4a3454984db74ebf2a302a64b985ce6de4.zip | |
Rearranged and renamed some bits.
Diffstat (limited to '')
| -rw-r--r-- | deepcrow/tests/basic.rs | 246 |
1 files changed, 246 insertions, 0 deletions
diff --git a/deepcrow/tests/basic.rs b/deepcrow/tests/basic.rs new file mode 100644 index 0000000..37cc21f --- /dev/null +++ b/deepcrow/tests/basic.rs | |||
| @@ -0,0 +1,246 @@ | |||
| 1 | use std::collections::HashMap; | ||
| 2 | |||
| 3 | use deepcrow::*; | ||
| 4 | |||
| 5 | /* | ||
| 6 | #[test] | ||
| 7 | fn lexing() { | ||
| 8 | let data = r#"Leading comment: [|view "basic" something="yeup"|>Hello there <|view|] Trailing text"#; | ||
| 9 | let ll = Lexer::new( &data ); | ||
| 10 | for sym in ll { | ||
| 11 | if let SymbolType::Error{what} = sym.symbol() { | ||
| 12 | println!("Error {}:{}: {:?}", sym.start().line, sym.start().column, what ); | ||
| 13 | break; | ||
| 14 | } else { | ||
| 15 | println!("Symbol: {:?}", sym ); | ||
| 16 | } | ||
| 17 | } | ||
| 18 | } | ||
| 19 | */ | ||
| 20 | |||
| 21 | #[test] | ||
| 22 | fn parsing() { | ||
| 23 | let mut ct = DeepCrow::new(); | ||
| 24 | if let Err(e) = ct.load_static(r#"Here is a sample | ||
| 25 | [|view "index" theme="standard"|><html><body>Hi</body></html><|view|] | ||
| 26 | That was fun! now a placeholder: [|view "placeholder"|] and now one with an implicit [|view "simple"|>Body -> [|show content|] <- and end<|view|] aoeu | ||
| 27 | |||
| 28 | [|view "person" layout="simple"|>Welcome [|show person.last_name|], [|show person.first_name|]! It's lovely to see you again.<|view|] | ||
| 29 | |||
| 30 | Now with explicit outputs: | ||
| 31 | [|view "complex"|> | ||
| 32 | [|output "content"|> | ||
| 33 | Here's a [|show name|]. | ||
| 34 | <|output|] | ||
| 35 | [|output "sidebar"|> | ||
| 36 | What's up world? | ||
| 37 | <|output|] | ||
| 38 | [|output "footer"|> | ||
| 39 | Same, I guess! | ||
| 40 | <|output|] | ||
| 41 | <|view|]"#) { | ||
| 42 | println!("Error: {:?}", e ); | ||
| 43 | } else { | ||
| 44 | println!("It finished"); | ||
| 45 | if let Ok(v) = ct.render( | ||
| 46 | "person", | ||
| 47 | &Context::from([ | ||
| 48 | ("hi".to_string(),Value::String("hi".to_string())), | ||
| 49 | ("person".to_string(),Value::Dictionary(HashMap::from([ | ||
| 50 | ("first_name".to_string(), Value::String("Bob".to_string())), | ||
| 51 | ("last_name".to_string(), Value::String("Smith".to_string())), | ||
| 52 | ]))), | ||
| 53 | ]) | ||
| 54 | ) { | ||
| 55 | println!("View result: {:?}", v ); | ||
| 56 | } else { | ||
| 57 | println!("Error?"); | ||
| 58 | } | ||
| 59 | } | ||
| 60 | } | ||
| 61 | |||
| 62 | #[test] | ||
| 63 | fn loops() -> Result<()> { | ||
| 64 | let mut ct = DeepCrow::new(); | ||
| 65 | ct.load_static(r#"Looping code: | ||
| 66 | [|view "index"|>We will enumerate people here:[|loop people|> | ||
| 67 | - [|show last_name|], [|show first_name|][|if show_title |>: [|show title|] <|else|> **title redacted** <|if|] ::>[|loop tags|> [|show tag|]<|loop|] <:: <|loop|] | ||
| 68 | <|view|] | ||
| 69 | "#)?; | ||
| 70 | |||
| 71 | let ctx = Context::from([ | ||
| 72 | ("people".to_string(), vec![ | ||
| 73 | [ | ||
| 74 | ("first_name".into(), "Joe".into()), | ||
| 75 | ("last_name".into(), "Smith".into()), | ||
| 76 | ("show_title".into(), true.into()), | ||
| 77 | ("title".into(), "CEO".into()), | ||
| 78 | ("tags".into(), vec![ | ||
| 79 | Context::from([("tag".into(), "jerk".into()),]).into(), | ||
| 80 | Context::from([("tag".into(), "ugly".into()),]).into(), | ||
| 81 | ].into()), | ||
| 82 | ].into(), | ||
| 83 | [ | ||
| 84 | ("first_name".into(), "Chris".into()), | ||
| 85 | ("last_name".into(), "Perkens".into()), | ||
| 86 | ("show_title".into(), false.into()), | ||
| 87 | ("title".into(), "Baconeer".into()), | ||
| 88 | ("tags".into(), vec![ | ||
| 89 | Context::from([("tag".into(), "jerk".into()),]).into(), | ||
| 90 | Context::from([("tag".into(), "ugly".into()),]).into(), | ||
| 91 | ].into()), | ||
| 92 | ].into(), | ||
| 93 | [ | ||
| 94 | ("first_name".into(), "Will".into()), | ||
| 95 | ("last_name".into(), "Power".into()), | ||
| 96 | ("show_title".into(), false.into()), | ||
| 97 | ("title".into(), "CFO".into()), | ||
| 98 | ("tags".into(), vec![ | ||
| 99 | Context::from([("tag".into(), "jerk".into()),]).into(), | ||
| 100 | Context::from([("tag".into(), "ugly".into()),]).into(), | ||
| 101 | ].into()), | ||
| 102 | ].into(), | ||
| 103 | [ | ||
| 104 | ("first_name".into(), "Justin".into()), | ||
| 105 | ("last_name".into(), "Time".into()), | ||
| 106 | ("show_title".into(), true.into()), | ||
| 107 | ("title".into(), "CIO".into()), | ||
| 108 | ("tags".into(), vec![ | ||
| 109 | Context::from([("tag".into(), "jerk".into()),]).into(), | ||
| 110 | Context::from([("tag".into(), "ugly".into()),]).into(), | ||
| 111 | ].into()), | ||
| 112 | ].into(), | ||
| 113 | ].into()), | ||
| 114 | ]); | ||
| 115 | |||
| 116 | println!("View result: {}", ct.render("index", &ctx)? ); | ||
| 117 | |||
| 118 | Ok(()) | ||
| 119 | } | ||
| 120 | |||
| 121 | #[test] | ||
| 122 | fn conditional() -> Result<()> { | ||
| 123 | let mut ct = DeepCrow::new(); | ||
| 124 | ct.load_static(r#"Hi there | ||
| 125 | [|view "index"|> | ||
| 126 | Color: [|if is_red|> red <|elif is_blue |> blue <|else|> green <|if|] | ||
| 127 | <|view|]"#)?; | ||
| 128 | |||
| 129 | let ctx = Context::from([ | ||
| 130 | ("is_red".into(), false.into()), | ||
| 131 | ("is_blue".into(), false.into()), | ||
| 132 | ("color".into(), "purple".into()), | ||
| 133 | ]); | ||
| 134 | |||
| 135 | println!("View result: {}", ct.render("index", &ctx)? ); | ||
| 136 | |||
| 137 | Ok(()) | ||
| 138 | } | ||
| 139 | |||
| 140 | struct Item { | ||
| 141 | pub id: i32, | ||
| 142 | pub title: String, | ||
| 143 | pub body: String, | ||
| 144 | } | ||
| 145 | |||
| 146 | struct Person { | ||
| 147 | pub id: i32, | ||
| 148 | pub username: String, | ||
| 149 | pub name: String, | ||
| 150 | } | ||
| 151 | |||
| 152 | struct Page { | ||
| 153 | pub user: Person, | ||
| 154 | pub total_items: i32, | ||
| 155 | pub total_pages: i32, | ||
| 156 | pub cur_page: i32, | ||
| 157 | pub items: Vec<Item>, | ||
| 158 | } | ||
| 159 | |||
| 160 | impl Page { | ||
| 161 | fn new() -> Page { | ||
| 162 | Page { | ||
| 163 | user: Person { | ||
| 164 | id: 443, | ||
| 165 | username: "eichlan".into(), | ||
| 166 | name: "Mike".into(), | ||
| 167 | }, | ||
| 168 | total_items: 4000, | ||
| 169 | total_pages: 400, | ||
| 170 | cur_page: 35, | ||
| 171 | items: vec![ | ||
| 172 | Item{ | ||
| 173 | id: 123, | ||
| 174 | title: "hi".into(), | ||
| 175 | body: "body".into(), | ||
| 176 | }, | ||
| 177 | Item{ | ||
| 178 | id: 124, | ||
| 179 | title: "bye".into(), | ||
| 180 | body: "wooo".into(), | ||
| 181 | }, | ||
| 182 | Item{ | ||
| 183 | id: 125, | ||
| 184 | title: "ciao".into(), | ||
| 185 | body: "whatever".into(), | ||
| 186 | } | ||
| 187 | ], | ||
| 188 | } | ||
| 189 | } | ||
| 190 | } | ||
| 191 | |||
| 192 | impl<'a> MappedStructure<'a> for Page { | ||
| 193 | fn get_value(&'a self, id: &str) -> Option<MappedValue<'a>> { | ||
| 194 | match id { | ||
| 195 | "user" => Some(MappedValue::Struct(&self.user)), | ||
| 196 | "total_items" => Some(MappedValue::Int32(self.total_items)), | ||
| 197 | "total_pages" => Some(MappedValue::Int32(self.total_pages)), | ||
| 198 | "cur_page" => Some(MappedValue::Int32(self.cur_page)), | ||
| 199 | "items" => Some(MappedValue::<'a>::List(&self.items)), | ||
| 200 | _ => None, | ||
| 201 | } | ||
| 202 | } | ||
| 203 | } | ||
| 204 | |||
| 205 | impl<'a> MappedStructure<'a> for Person { | ||
| 206 | fn get_value(&'a self, id: &str) -> Option<MappedValue<'a>> { | ||
| 207 | match id { | ||
| 208 | "id" => Some(MappedValue::Int32(self.id)), | ||
| 209 | "username" => Some(MappedValue::String(&self.username)), | ||
| 210 | "name" => Some(MappedValue::String(&self.name)), | ||
| 211 | _ => None, | ||
| 212 | } | ||
| 213 | } | ||
| 214 | } | ||
| 215 | |||
| 216 | impl<'a> MappedStructure<'a> for Item { | ||
| 217 | fn get_value(&'a self, id: &str) -> Option<MappedValue<'a>> { | ||
| 218 | match id { | ||
| 219 | "id" => Some(MappedValue::Int32(self.id)), | ||
| 220 | "title" => Some(MappedValue::String(&self.title)), | ||
| 221 | "body" => Some(MappedValue::String(&self.body)), | ||
| 222 | _ => None, | ||
| 223 | } | ||
| 224 | } | ||
| 225 | } | ||
| 226 | |||
| 227 | #[test] | ||
| 228 | fn custom() -> Result<()> { | ||
| 229 | let page = Page::new(); | ||
| 230 | |||
| 231 | println!("{:?}", | ||
| 232 | page.get_value(&"total_pages") | ||
| 233 | ); | ||
| 234 | |||
| 235 | if let Some(MappedValue::List(l)) = page.get_value(&"items") { | ||
| 236 | l.for_each(&|x: &MappedValue, buf: &mut String| { | ||
| 237 | if let MappedValue::Struct(s) = x { | ||
| 238 | println!(" - {:?}", s.get_value(&"title")); | ||
| 239 | buf.push_str(&format!("{:?}",s.get_value(&"title"))); | ||
| 240 | } | ||
| 241 | Ok(()) | ||
| 242 | }).expect("loop"); | ||
| 243 | } | ||
| 244 | Ok(()) | ||
| 245 | } | ||
| 246 | |||
