Oregami
Repositories/oxedyne/fe2o3

oxedyne/fe2o3/fe2o3_syntax/tests/msg.rs

36.8 KiB, 324 runs

created by r1870400018:1063, which is this file's identity for as long as the history lasts, whatever it is later renamed to

download · who wrote it · its history

1use oxedyne_fe2o3_syntax::{
2 arg::{
3 Arg,
4 ArgConfig,
5 },
6 cmd::{
7 Cmd,
8 CmdConfig,
9 },
10 core::{
11 Syntax,
12 SyntaxRef,
13 SyntaxConfig,
14 },
15 key::Key,
16 msg::Msg,
17};
18
19use oxedyne_fe2o3_core::{
20 prelude::*,
21 byte::{
22 Encoding,
23 IntoBytes,
24 ToBytes,
25 FromBytes,
26 },
27 map::MapRec,
28 test::test_it,
29};
30use oxedyne_fe2o3_jdat::{
31 prelude::*,
32 version::SemVer,
33};
34
35fn make_test_syntax_00() -> Outcome<SyntaxRef> {
36 let a1 = Arg::from(ArgConfig {
37 name: fmt!("Arg_c1a1"),
38 hyph1: Some(fmt!("c")),
39 hyph2: Some(fmt!("c1a1")),
40 reqd: true,
41 vals: vec![
42 (Kind::Str, fmt!("A string value for Arg_c1a1.")).into(),
43 (Kind::I16, fmt!("A number for c1a1.")).into(),
44 ],
45 help: Some(fmt!("Some help text")),
46 ..Default::default()
47 });
48 let a2 = Arg::from(ArgConfig {
49 name: fmt!("Arg_c1a2"),
50 hyph1: Some(fmt!("d")),
51 hyph2: Some(fmt!("c1a2")),
52 reqd: false,
53 help: Some(fmt!("Some help text")),
54 ..Default::default()
55 });
56 let a3 = Arg::from(ArgConfig {
57 name: fmt!("Arg_c1a3"),
58 hyph1: Some(fmt!("e")),
59 hyph2: Some(fmt!("c1a3")),
60 reqd: false,
61 help: Some(fmt!("Some help text")),
62 ..Default::default()
63 });
64
65 let mut c = Cmd::from(CmdConfig {
66 name: fmt!("cmd1"),
67 help: Some(fmt!("Command One help text")),
68 ..Default::default()
69 });
70 c = res!(c.add_arg(a1));
71 c = res!(c.add_arg(a2));
72 c = res!(c.add_arg(a3));
73
74 let a1 = Arg::from(ArgConfig {
75 name: fmt!("Arg_a"),
76 hyph1: Some(fmt!("a")),
77 hyph2: Some(fmt!("a0")),
78 reqd: true,
79 vals: vec![
80 (Kind::Str, fmt!("A string value for Arg_a.")).into(),
81 ],
82 help: Some(fmt!("Some help text")),
83 ..Default::default()
84 });
85 let a2 = Arg::from(ArgConfig {
86 name: fmt!("Arg_b"),
87 hyph1: Some(fmt!("b")),
88 hyph2: Some(fmt!("b0")),
89 reqd: false,
90 help: Some(fmt!("Some help text")),
91 ..Default::default()
92 });
93
94 let mut p = Syntax::from(SyntaxConfig {
95 name: fmt!("TestSyntax"),
96 ver: SemVer::new(0, 1, 0),
97 about: Some(fmt!("Testing")),
98 ..Default::default()
99 });
100
101 p = res!(p.add_arg(a1));
102 p = res!(p.add_arg(a2));
103 p = res!(p.add_cmd(c));
104
105 Ok(SyntaxRef::new(p))
106}
107
108fn make_test_syntax_01() -> Outcome<SyntaxRef> {
109 let a1 = Arg::from(ArgConfig {
110 name: fmt!("Arga"),
111 hyph1: Some(fmt!("a")),
112 hyph2: Some(fmt!("arga")),
113 vals: vec![
114 (Kind::Str, fmt!("A string value for Arga.")).into(),
115 (Kind::I16, fmt!("A number value for Arga.")).into(),
116 ],
117 help: Some(fmt!("Activate the a argument")),
118 ..Default::default()
119 });
120 let a2 = Arg::from(ArgConfig {
121 name: fmt!("Argb"),
122 hyph1: Some(fmt!("b")),
123 hyph2: Some(fmt!("argb")),
124 help: Some(fmt!("Activate the b argument")),
125 ..Default::default()
126 });
127 let a3 = Arg::from(ArgConfig {
128 name: fmt!("Argc"),
129 hyph1: Some(fmt!("c")),
130 hyph2: Some(fmt!("argc")),
131 vals: vec![
132 (Kind::Str, fmt!("A string value for Argc.")).into(),
133 ],
134 help: Some(fmt!("Activate the c argument")),
135 ..Default::default()
136 });
137 let a4 = Arg::from(ArgConfig {
138 name: fmt!("Argd"),
139 hyph1: Some(fmt!("d")),
140 hyph2: Some(fmt!("argd")),
141 vals: vec![
142 (Kind::I32, fmt!("A number value for Argd.")).into(),
143 ],
144 help: Some(fmt!("Activate the d argument")),
145 ..Default::default()
146 });
147
148 let mut cmd1 = Cmd::from(CmdConfig {
149 name: fmt!("cmd1"),
150 help: Some(fmt!("Do the first thing")),
151 vals: vec![
152 (Kind::U8, fmt!("A number value for cmd1.")).into(),
153 ],
154 ..Default::default()
155 });
156 cmd1 = res!(cmd1.add_arg(a1.required(true)));
157 cmd1 = res!(cmd1.add_arg(a2));
158
159 let mut cmd2 = Cmd::from(CmdConfig {
160 name: fmt!("cmd2"),
161 help: Some(fmt!("Do the second thing")),
162 ..Default::default()
163 });
164 cmd2 = res!(cmd2.add_arg(a3));
165
166 let mut p = Syntax::from(SyntaxConfig {
167 name: fmt!("TestSyntax"),
168 ver: SemVer::new(0, 1, 0),
169 about: Some(fmt!("Testing")),
170 ..Default::default()
171 });
172
173 p = res!(p.add_arg(a4));
174 p = res!(p.add_cmd(cmd1));
175 p = res!(p.add_cmd(cmd2));
176
177 Ok(SyntaxRef::new(p))
178}
179
180pub fn test_msg(filter: &'static str) -> Outcome<()> {
181
182 res!(test_it(filter, &["Default help", "all", "help"], || {
183 let p = res!(Syntax::new("test").with_default_help_arg());
184 let msgrx = Msg::new(SyntaxRef::new(p));
185 let msgrx = res!(msgrx.from_str("help", None));
186 //for line in Stringer::new(fmt!("{:?}", msgrx)).to_lines(" ") {
187 // debug!("{}", line);
188 //}
189 assert!(msgrx.has_arg("help"));
190 Ok(())
191 }));
192
193 res!(test_it(filter, &["Msgrx read simple 000", "all", "msgrx"], || {
194 let p = res!(make_test_syntax_00());
195
196 if let Some(arg) = p.args.get_recursive(&Key::from("-b")) {
197 req!(arg.config().name, "Arg_b".to_string());
198 }
199
200 let msgrx = Msg::new(p);
201 let msgrx = res!(msgrx.from_str("-a av1 -b cmd1 --c1a3 --c1a1 \" c1a1v1 \" (I16|-945)", None));
202
203 if let Some(list) = msgrx.get_arg_vals("Arg_a") {
204 req!(*list, vec![ dat!("av1") ]);
205 } else {
206 return Err(err!(
207 "Could not find the argument '-a'.";
208 Input, Missing));
209 }
210
211 if let Some(cmdrx) = msgrx.get_cmd("cmd1") {
212 if let Some(list) = cmdrx.get_arg_vals("Arg_c1a1") {
213 req!(*list, vec![ dat!(" c1a1v1 "), dat!(-945i16) ]);
214 } else {
215 return Err(err!(
216 "Could not find the command 'cmd1' argument '-c'.";
217 Input, Missing));
218 }
219 } else {
220 return Err(err!(
221 "Could not find the command 'cmd1'.";
222 Input, Missing));
223 }
224 Ok(())
225 }));
226
227 res!(test_it(filter, &["Msgrx read simple 001", "all", "msgrx"], || {
228
229 let p = res!(make_test_syntax_00());
230 let msgrx = Msg::new(p);
231
232 match msgrx.from_str("-a av1 av2 -b cmd1 --c1a3 --c1a1 \" c1a1v1 \" (I16|-945)", None) {
233 Ok(_) => Err(err!(
234 "The additional value 'av2' should have triggered an error.";
235 Invalid, Output)),
236 _ => Ok(()),
237 }
238 }));
239
240 res!(test_it(filter, &["Msgrx read simple 002", "all", "msgrx"], || {
241
242 let p = res!(make_test_syntax_00());
243 let msgrx = Msg::new(p);
244
245 match msgrx.from_str("-a -b cmd1 --c1a3 --c1a1 \" c1a1v1 \" (I16|-945)", None) {
246 Ok(_) => Err(err!(
247 "The appearance of -b in the place of an expected value \
248 for -a should trigger an error.";
249 Invalid, Output)),
250 _ => Ok(()),
251 }
252 }));
253
254 res!(test_it(filter, &["Msgrx read simple 003", "all", "msgrx"], || {
255
256 let p = res!(make_test_syntax_00());
257 let msgrx = Msg::new(p);
258
259 match msgrx.from_str("-b cmd1 --c1a3 --c1a1 \" c1a1v1 \" (I16|-945)", None) {
260 Ok(_) => Err(err!(
261 "The missing message argument Arg_a should trigger an error";
262 Invalid, Output)),
263 _ => Ok(()),
264 }
265 }));
266
267 res!(test_it(filter, &["Msgrx read simple 004", "all", "msgrx"], || {
268
269 let p = res!(make_test_syntax_00());
270 let msgrx = Msg::new(p);
271
272 match msgrx.from_str("-a av1 -b cmd2", None) {
273 Ok(_) => Err(err!(
274 "The unknown word cmd2 should trigger an error.";
275 Invalid, Output)),
276 _ => Ok(()),
277 }
278 }));
279
280 res!(test_it(filter, &["Msgrx empty arg", "all", "msgrx"], || {
281 let mut p = Syntax::from(SyntaxConfig {
282 name: fmt!("TestSyntax"),
283 ver: SemVer::new(0, 1, 0),
284 about: Some(fmt!("Testing")),
285 ..Default::default()
286 });
287 let a1 = Arg::from(ArgConfig {
288 name: fmt!("Arg_a"),
289 hyph1: Some(fmt!("a")),
290 hyph2: Some(fmt!("a0")),
291 reqd: false,
292 vals: vec![
293 (Kind::Str, fmt!("A string value for Arg_a.")).into(),
294 ],
295 help: Some(fmt!("Some help text")),
296 ..Default::default()
297 });
298 let a2 = Arg::from(ArgConfig {
299 name: fmt!("Arg_b"),
300 hyph1: Some(fmt!("b")),
301 hyph2: Some(fmt!("b0")),
302 reqd: false,
303 help: Some(fmt!("Some help text")),
304 ..Default::default()
305 });
306 p = res!(p.add_arg(a1));
307 p = res!(p.add_arg(a2));
308 let p = SyntaxRef::new(p);
309 let msgrx = Msg::new(p);
310
311 if msgrx.from_str("-a -b", None).is_ok() {
312 return Err(err!(
313 "The syntax incorrectly accepted an empty -a value.";
314 Invalid, Output));
315 }
316
317 let msgrx = res!(msgrx.from_str("Arg_a", None));
318 if let Some(argrx) = &msgrx.end.arg {
319 if argrx == &fmt!("Arg_a") {
320 if msgrx.end.vals.len() != 1 {
321 return Err(err!(
322 "The message processor correctly identified the \
323 incomplete argument but found {} outstanding \
324 arg values, when 1 was expected",
325 msgrx.end.vals.len();
326 Invalid, Output));
327 }
328 } else {
329 return Err(err!(
330 "The message processor incorrectly identified the \
331 outstanding argument as {}, it should have been '-a'",
332 argrx;
333 Invalid, Output));
334 }
335 } else {
336 return Err(err!(
337 "The message processor did not detect the incomplete argument: {:?}",
338 msgrx.end;
339 Invalid, Output));
340 }
341 Ok(())
342 }));
343
344 // p v v
345 res!(test_it(filter, &["Msgrx 010", "all", "msgrx"], || {
346 let p = Syntax::new("TestSyntax").expected_vals(vec![
347 (Kind::Str, fmt!("A string value for TestSyntax.")),
348 (Kind::U16, fmt!("A number value for TestSyntax.")),
349 ]);
350 let p = SyntaxRef::new(p);
351 let msgrx = Msg::new(p);
352
353 let msgrx = res!(msgrx.from_str("hello 420 ", None));
354 req!(msgrx.vals, vec![dat!("hello"), dat!(420u16)]);
355
356 let msgrx = res!(msgrx.from_str(" hello ", None));
357 if msgrx.end.vals.len() == 0 {
358 return Err(err!(
359 "The message processor did not detect the outstanding cmd value.";
360 Invalid, Output));
361 }
362
363 let msgrx = res!(msgrx.from_str(" ", None));
364 if msgrx.end.vals.len() != 2 {
365 return Err(err!(
366 "The message processor did not detect the outstanding msg values.";
367 Invalid, Output));
368 }
369
370 Ok(())
371 }));
372
373 // p v v a v v
374 res!(test_it(filter, &["Msgrx 020", "all", "msgrx"], || {
375 let mut p = Syntax::from(SyntaxConfig {
376 name: fmt!("TestSyntax"),
377 vals: vec![
378 (Kind::Str, fmt!("A string value for TestSyntax.")).into(),
379 (Kind::U8, fmt!("A number value for TestSyntax.")).into(),
380 ],
381 ..Default::default()
382 });
383 let a = Arg::from(ArgConfig {
384 name: fmt!("Arg_a"),
385 hyph1: Some(fmt!("a")),
386 hyph2: Some(fmt!("a0")),
387 reqd: false,
388 vals: vec![
389 (Kind::Str, fmt!("A string value for Arg_a.")).into(),
390 (Kind::I8, fmt!("A number value for Arg_a.")).into(),
391 ],
392 ..Default::default()
393 });
394 p = res!(p.add_arg(a));
395 let p = SyntaxRef::new(p);
396 let msgrx = Msg::new(p);
397
398 let msgrx = res!(msgrx.from_str("hello 42 -a goodbye 1", None));
399 req!(msgrx.vals, vec![dat!("hello"), dat!(42u8)]);
400 let argrx_vals = res!(msgrx.get_arg_vals("Arg_a").ok_or_else(|| err!(
401 "Failed to detect message argument '-a'."; Invalid, Output)));
402 req!(argrx_vals.len(), 2);
403 req!(argrx_vals[0], dat!("goodbye"));
404 req!(argrx_vals[1], dat!(1i8));
405 // An argument has one set of values, whichever of its names is used to
406 // ask for them. It used to have as many as it has names, and which one
407 // answered depended on whether the message had been parsed or built.
408 for alias in ["Arg_a", "-a", "--a0"] {
409 let by_alias = res!(msgrx.get_arg_vals(alias).ok_or_else(|| err!(
410 "Failed to detect message argument '{}'.", alias; Invalid, Output)));
411 req!(by_alias.len(), 2);
412 req!(by_alias[0], dat!("goodbye"));
413 req!(msgrx.has_arg(alias), true);
414 }
415 // A message built by hand files its arguments under the same name a
416 // parsed one does, so what is required is found and what is added can
417 // be read back.
418 let built = Msg::new(msgrx.syntaxref());
419 let built = res!(built.add_msg_val(dat!("hello")));
420 let built = res!(built.add_msg_val(dat!(42u8)));
421 let built = res!(built.add_arg_val("-a", Some(dat!("goodbye"))));
422 let built = res!(built.add_arg_val("-a", Some(dat!(1i8))));
423 res!(built.validate());
424 let built_vals = res!(built.get_arg_vals("Arg_a").ok_or_else(|| err!(
425 "An argument added as '-a' could not be read back as 'Arg_a'.";
426 Invalid, Output)));
427 req!(built_vals.len(), 2);
428 req!(built_vals[0], dat!("goodbye"));
429
430 let msgrx = res!(msgrx.from_str("hello 42 --a0 goodbye ", None));
431 if let Some(argrx) = &msgrx.end.arg {
432 if argrx == &fmt!("Arg_a") {
433 if msgrx.end.vals.len() != 1 {
434 return Err(err!(
435 "The message processor correctly identified the \
436 incomplete argument but found {} outstanding \
437 arg values, when 1 was expected.",
438 msgrx.end.vals.len();
439 Invalid, Output));
440 }
441 } else {
442 return Err(err!(
443 "The message processor incorrectly identified the \
444 outstanding argument as {}, it should have been '-a'.",
445 argrx;
446 Invalid, Output));
447 }
448 } else {
449 return Err(err!(
450 "The message processor did not detect the incomplete argument: {:?}",
451 msgrx.end;
452 Invalid, Output));
453 }
454 Ok(())
455 }));
456
457 // p v v a v v c v v
458 res!(test_it(filter, &["Msgrx 030", "all", "msgrx"], || {
459 let mut p = Syntax::from(SyntaxConfig {
460 name: fmt!("TestSyntax"),
461 vals: vec![
462 (Kind::Str, fmt!("A string value for TestSyntax.")).into(),
463 (Kind::U8, fmt!("A number value for TestSyntax.")).into(),
464 ],
465 ..Default::default()
466 });
467 let a = Arg::from(ArgConfig {
468 name: fmt!("Arg_a"),
469 hyph1: Some(fmt!("a")),
470 hyph2: Some(fmt!("a0")),
471 reqd: false,
472 vals: vec![
473 (Kind::Str, fmt!("A string value for Arg_a.")).into(),
474 (Kind::I8, fmt!("A number value for Arg_a.")).into(),
475 ],
476 ..Default::default()
477 });
478 let c = Cmd::from(CmdConfig {
479 name: fmt!("cmd"),
480 vals: vec![
481 (Kind::Str, fmt!("A string value for cmd.")).into(),
482 (Kind::I16, fmt!("A number value for cmd.")).into(),
483 ],
484 ..Default::default()
485 });
486 p = res!(p.add_arg(a));
487 p = res!(p.add_cmd(c));
488 let p = SyntaxRef::new(p);
489 let msgrx = Msg::new(p);
490
491 let msgrx = res!(msgrx.from_str("hello 42 -a goodbye 1 cmd again -3", None));
492 req!(msgrx.vals, vec![dat!("hello"), dat!(42u8)]);
493 let argrx_vals = res!(msgrx.get_arg_vals("Arg_a").ok_or_else(|| err!(
494 "Failed to detect message argument '-a'."; Invalid, Output)));
495 req!(argrx_vals.len(), 2);
496 req!(argrx_vals[0], dat!("goodbye"));
497 req!(argrx_vals[1], dat!(1i8));
498 let cmdrx = res!(msgrx.get_cmd("cmd").ok_or_else(|| err!(
499 "Failed to detect command 'cmd'."; Invalid, Output)));
500 req!(cmdrx.vals.len(), 2);
501 req!(cmdrx.vals[0], dat!("again"));
502 req!(cmdrx.vals[1], dat!(-3i16));
503
504 let msgrx = res!(msgrx.from_str("hello 42 --a0 goodbye 1 cmd again", None));
505 if let Some(cmdrx) = &msgrx.end.cmd {
506 if cmdrx == &fmt!("cmd") {
507 if msgrx.end.vals.len() != 1 {
508 return Err(err!(
509 "The message processor correctly identified the \
510 incomplete command but found {} outstanding \
511 cmd values, when 1 was expected.",
512 msgrx.end.vals.len();
513 Invalid, Output));
514 }
515 } else {
516 return Err(err!(
517 "The message processor incorrectly identified the \
518 outstanding command as {}, it should have been 'cmd'.",
519 cmdrx;
520 Invalid, Output));
521 }
522 } else {
523 return Err(err!(
524 "The message processor did not detect the incomplete command: {:?}.",
525 msgrx.end;
526 Invalid, Output));
527 }
528
529 let msgrx = res!(msgrx.from_str("hello 42 --a0 goodbye 1 cmd ", None));
530 if let Some(cmdrx) = &msgrx.end.cmd {
531 if cmdrx == &fmt!("cmd") {
532 if msgrx.end.vals.len() != 2 {
533 return Err(err!(
534 "The message processor correctly identified the \
535 incomplete command but found {} outstanding \
536 cmd values, when 2 was expected.",
537 msgrx.end.vals.len();
538 Invalid, Output));
539 }
540 } else {
541 return Err(err!(
542 "The message processor incorrectly identified the \
543 outstanding command as {}, it should have been 'cmd'.",
544 cmdrx;
545 Invalid, Output));
546 }
547 } else {
548 return Err(err!(
549 "The message processor did not detect the incomplete command: {:?}.",
550 msgrx.end;
551 Invalid, Output));
552 }
553
554 Ok(())
555 }));
556
557 // p v v a v v c v v a v v
558 res!(test_it(filter, &["Msgrx 040", "all", "msgrx"], || {
559 let mut p = Syntax::from(SyntaxConfig {
560 name: fmt!("TestSyntax"),
561 vals: vec![
562 (Kind::Str, fmt!("A string value for TestSyntax.")).into(),
563 (Kind::I128, fmt!("A number value for TestSyntax.")).into(),
564 ],
565 ..Default::default()
566 });
567 let a = Arg::from(ArgConfig {
568 name: fmt!("Arg_a"),
569 hyph1: Some(fmt!("a")),
570 hyph2: Some(fmt!("a0")),
571 reqd: false,
572 vals: vec![
573 (Kind::Str, fmt!("A string value for Arg_a.")).into(),
574 (Kind::I32, fmt!("A number value for Arg_a.")).into(),
575 ],
576 ..Default::default()
577 });
578 p = res!(p.add_arg(a));
579
580 let mut c = Cmd::from(CmdConfig {
581 name: fmt!("cmd"),
582 vals: vec![
583 (Kind::Str, fmt!("A string value for cmd.")).into(),
584 (Kind::I16, fmt!("A number value for cmd.")).into(),
585 ],
586 ..Default::default()
587 });
588 let a = Arg::from(ArgConfig {
589 name: fmt!("Arg_b"),
590 hyph1: Some(fmt!("b")),
591 hyph2: Some(fmt!("b0")),
592 reqd: false,
593 vals: vec![
594 (Kind::Str, fmt!("A string value for Arg_b.")).into(),
595 (Kind::U8, fmt!("A number value for Arg_b.")).into(),
596 ],
597 ..Default::default()
598 });
599 c = res!(c.add_arg(a));
600 p = res!(p.add_cmd(c));
601 let p = SyntaxRef::new(p);
602 let msgrx = Msg::new(p);
603
604 let msgrx = res!(msgrx.from_str("hello 42 -a goodbye 1 cmd again -3 -b dejavu 42", None));
605 req!(msgrx.vals, vec![dat!("hello"), dat!(42i128)]);
606 let argrx_vals = res!(msgrx.get_arg_vals("Arg_a").ok_or_else(|| err!(
607 "Failed to detect message argument '-a'."; Invalid, Output)));
608 req!(argrx_vals.len(), 2);
609 req!(argrx_vals[0], dat!("goodbye"));
610 req!(argrx_vals[1], dat!(1i32));
611 let cmdrx = res!(msgrx.get_cmd("cmd").ok_or_else(|| err!(
612 "Failed to detect command 'cmd'."; Invalid, Output)));
613 req!(cmdrx.vals.len(), 2);
614 req!(cmdrx.vals[0], dat!("again"));
615 req!(cmdrx.vals[1], dat!(-3i16));
616 let argrx_vals = res!(cmdrx.get_arg_vals("Arg_b").ok_or_else(|| err!(
617 "Failed to detect command 'cmd' argument '-b'."; Invalid, Output)));
618 req!(argrx_vals.len(), 2);
619 req!(argrx_vals[0], dat!("dejavu"));
620 req!(argrx_vals[1], dat!(42u8));
621
622 let msgrx = res!(msgrx.from_str("hello 42 --a0 goodbye 1 cmd again -3 -b dejavu ", None));
623 if let Some(argrx) = &msgrx.end.arg {
624 if argrx == &fmt!("Arg_b") {
625 if msgrx.end.vals.len() != 1 {
626 return Err(err!(
627 "The message processor correctly identified the \
628 incomplete argument but found {} outstanding \
629 arg values, when 1 was expected.",
630 msgrx.end.vals.len();
631 Invalid, Output));
632 }
633 } else {
634 return Err(err!(
635 "The message processor incorrectly identified the \
636 outstanding argument as {}, it should have been '-b'.",
637 argrx;
638 Invalid, Output));
639 }
640 } else {
641 return Err(err!(
642 "The message processor did not detect the incomplete argument: {:?}.",
643 msgrx.end;
644 Invalid, Output));
645 }
646
647 let msgrx = res!(msgrx.from_str("hello 42 --a0 goodbye 1 cmd again -3 -b", None));
648 if let Some(argrx) = &msgrx.end.arg {
649 if argrx == &fmt!("Arg_b") {
650 if msgrx.end.vals.len() != 2 {
651 return Err(err!(
652 "The message processor correctly identified the \
653 incomplete argument but found {} outstanding \
654 arg values, when 2 was expected.",
655 msgrx.end.vals.len();
656 Invalid, Output));
657 }
658 } else {
659 return Err(err!(
660 "The message processor incorrectly identified the \
661 outstanding argument as {}, it should have been '-b'.",
662 argrx;
663 Invalid, Output));
664 }
665 } else {
666 return Err(err!(
667 "The message processor did not detect the incomplete argument: {:?}.",
668 msgrx.end;
669 Invalid, Output));
670 }
671
672 Ok(())
673 }));
674
675 // test multiple commands
676 // p v c v c v v a a v
677 res!(test_it(filter, &["Msgrx 100", "all", "msgrx"], || {
678 let mut p = Syntax::from(SyntaxConfig {
679 name: fmt!("TestSyntax"),
680 vals: vec![
681 (Kind::U8, fmt!("A number value for TestSyntax.")).into(),
682 ],
683 ..Default::default()
684 });
685 let c = Cmd::from(CmdConfig {
686 name: fmt!("cmd1"),
687 vals: vec![
688 (Kind::Str, fmt!("A string value for cmd1.")).into(),
689 ],
690 ..Default::default()
691 });
692 p = res!(p.add_cmd(c));
693
694 let mut c = Cmd::from(CmdConfig {
695 name: fmt!("cmd2"),
696 vals: vec![
697 (Kind::Str, fmt!("A string value for cmd2.")).into(),
698 (Kind::I8, fmt!("A number value for cmd2.")).into(),
699 ],
700 ..Default::default()
701 });
702 let a1 = Arg::from(ArgConfig {
703 name: fmt!("arg1"),
704 hyph1: Some(fmt!("a1")),
705 ..Default::default()
706 });
707 let a2 = Arg::from(ArgConfig {
708 name: fmt!("arg2"),
709 hyph1: Some(fmt!("a2")),
710 hyph2: Some(fmt!("arg2")),
711 vals: vec![
712 (Kind::Str, fmt!("A string value for arg2.")).into(),
713 ],
714 ..Default::default()
715 });
716 c = res!(c.add_arg(a1));
717 c = res!(c.add_arg(a2));
718 p = res!(p.add_cmd(c));
719 let p = SyntaxRef::new(p);
720 let msgrx = Msg::new(p);
721
722 let msgrx = res!(msgrx.from_str("42 cmd1 hello cmd2 goodbye -42 -a1 --arg2 done ", None));
723 req!(msgrx.vals, vec![dat!(42u8)]);
724 let cmdrx = res!(msgrx.get_cmd("cmd1").ok_or_else(|| err!(
725 "Failed to detect command 'cmd1'."; Invalid, Output)));
726 req!(cmdrx.vals.len(), 1);
727 req!(cmdrx.vals[0], dat!("hello"));
728 let cmdrx = res!(msgrx.get_cmd("cmd2").ok_or_else(|| err!(
729 "Failed to detect command 'cmd2'."; Invalid, Output)));
730 req!(cmdrx.vals.len(), 2);
731 req!(cmdrx.vals[0], dat!("goodbye"));
732 req!(cmdrx.vals[1], dat!(-42i8));
733 assert!(cmdrx.has_arg("arg1"));
734 let argrx_vals = res!(cmdrx.get_arg_vals("arg2").ok_or_else(|| err!(
735 "Failed to detect command 'cmd2' argument '-a2'.";
736 Invalid, Output)));
737 req!(argrx_vals.len(), 1);
738 req!(argrx_vals[0], dat!("done"));
739
740 if msgrx.from_str("hello 42 --a0 goodbye 1 cmd again -3 -b dejavu ", None).is_ok() {
741 return Err(err!(
742 "The syntax incorrectly accepted too few values.";
743 Invalid, Output));
744 }
745
746 if msgrx.from_str("hello 42 --a0 goodbye 1 cmd again -3 -b", None).is_ok() {
747 return Err(err!(
748 "The syntax incorrectly accepted too few values.";
749 Invalid, Output));
750 }
751 Ok(())
752 }));
753
754 res!(test_it(filter, &["Msgrx 110", "all", "msgrx"], || {
755 let mut p = Syntax::from(SyntaxConfig {
756 name: fmt!("repl"),
757 ver: SemVer::new(0, 1, 0),
758 about: Some(fmt!("Demonstration REPL")),
759 ..Default::default()
760 });
761 p = res!(p.with_default_help_cmd());
762
763 let c = Cmd::from(CmdConfig {
764 name: fmt!("cd"),
765 vals: vec![
766 (Kind::Str, fmt!("A string value for cd.")).into(),
767 ],
768 help: Some(fmt!("Change directory")),
769 ..Default::default()
770 });
771 p = res!(p.add_cmd(c));
772
773 let c = Cmd::from(CmdConfig {
774 name: fmt!("pwd"),
775 help: Some(fmt!("Print path of current/working directory")),
776 ..Default::default()
777 });
778 p = res!(p.add_cmd(c));
779
780 let c = Cmd::from(CmdConfig {
781 name: fmt!("who"),
782 help: Some(fmt!("Dump variable names and values")),
783 ..Default::default()
784 });
785 p = res!(p.add_cmd(c));
786
787 let mut c = Cmd::from(CmdConfig {
788 name: fmt!("ls"),
789 ..Default::default()
790 });
791 let a1 = Arg::from(ArgConfig {
792 name: fmt!("sort"),
793 hyph1: Some(fmt!("s")),
794 vals: vec![
795 (Kind::Str, fmt!("A string value for sort.")).into(),
796 ],
797 help: Some(fmt!("Sort by 'size', 'type' or 'name'")),
798 ..Default::default()
799 });
800 let a2 = Arg::from(ArgConfig {
801 name: fmt!("reverse"),
802 hyph1: Some(fmt!("r")),
803 help: Some(fmt!("Reverse any sort")),
804 ..Default::default()
805 });
806 c = res!(c.add_arg(a1));
807 c = res!(c.add_arg(a2));
808 p = res!(p.add_cmd(c));
809 let p = SyntaxRef::new(p);
810 let msgrx = Msg::new(p);
811
812 let msg = "ls -r -s name";
813 let msgrx = res!(msgrx.from_str(msg, None));
814 if let Some(cmdrx) = msgrx.get_cmd("ls") {
815 req!(cmdrx.vals.len(), 0);
816 if let Some(argrx_vals) = cmdrx.get_arg_vals("sort") {
817 req!(argrx_vals.len(), 1);
818 req!(argrx_vals[0], dat!("name"));
819 } else {
820 return Err(err!(
821 "Expected capture of command 'ls' argument '-s'.";
822 Invalid, Output));
823 }
824 if cmdrx.get_arg_vals("-r").is_some() {
825 return Err(err!(
826 "Expected capture of command 'ls' argument '-r' with no values.";
827 Invalid, Output));
828 }
829 } else {
830 return Err(err!(
831 "Expected capture of command 'ls'.";
832 Invalid, Output));
833 }
834
835 Ok(())
836 }));
837
838 res!(test_it(filter, &["Binary msgrx 010", "all", "msgrx", "binary"], || {
839 let mut p = Syntax::from(SyntaxConfig {
840 name: fmt!("TestSyntax"),
841 vals: vec![
842 (Kind::I16, fmt!("A number value for TestSyntax.")).into(),
843 ],
844 ..Default::default()
845 });
846 let a = Arg::from(ArgConfig {
847 name: fmt!("arg00"),
848 hyph1: Some(fmt!("a00")),
849 ..Default::default()
850 }).required(true);
851 p = res!(p.add_arg(a));
852
853 let mut c = Cmd::from(CmdConfig {
854 name: fmt!("cmd1"),
855 vals: vec![
856 (Kind::Str, fmt!("A string value for cmd1.")).into(),
857 ],
858 ..Default::default()
859 });
860 let a = Arg::from(ArgConfig {
861 name: fmt!("arg10"),
862 hyph1: Some(fmt!("a10")),
863 ..Default::default()
864 });
865 c = res!(c.add_arg(a));
866 p = res!(p.add_cmd(c)); // 0
867
868 let mut c = Cmd::from(CmdConfig {
869 name: fmt!("cmd2"),
870 vals: vec![
871 (Kind::Str, fmt!("A string value for cmd2.")).into(),
872 (Kind::I32, fmt!("A number value for cmd2.")).into(),
873 ],
874 ..Default::default()
875 });
876 let a1 = Arg::from(ArgConfig {
877 name: fmt!("arg20"),
878 hyph1: Some(fmt!("a20")),
879 ..Default::default()
880 });
881 let a2 = Arg::from(ArgConfig {
882 name: fmt!("arg21"),
883 hyph1: Some(fmt!("a21")),
884 hyph2: Some(fmt!("arg21")),
885 vals: vec![
886 (Kind::Str, fmt!("A string value for arg21.")).into(),
887 ],
888 ..Default::default()
889 });
890 c = res!(c.add_arg(a1)); // 0
891 c = res!(c.add_arg(a2)); // 1
892 p = res!(p.add_cmd(c)); // 1
893 let p = SyntaxRef::new(p);
894 let msgrx = Msg::new(p);
895
896 let msg = "(I16|42) -a00 cmd1 hello cmd2 goodbye (I32|-42) -a20 --arg21 done ";
897 let mut msgtx = res!(msgrx.from_str(msg, None));
898 // Side check: Msg validator. In this case from_str validates, but
899 // in theory a binary Msg can be constructed and may need to be validated.
900 res!(msgtx.validate());
901 let mut buf = Vec::new();
902 msgtx.set_encoding(Encoding::Binary);
903 buf = res!(msgtx.to_bytes(buf));
904 debug!("String: {}", msg);
905 debug!("From string: {}", msgtx);
906 for line in msgtx.to_lines() {
907 debug!("{}", line);
908 }
909 let msgrx = res!(msgrx.from_bytes(&buf, None));
910 debug!("Rx: {}", msgrx);
911 req!(msgrx.vals.len(), 1);
912 req!(msgtx.vals[0], Dat::I16(42));
913 req!(msgrx.args.len(), 1);
914 req!(msgrx.cmds.len(), 2);
915 match msgrx.get_cmd("cmd1") {
916 Some(msgcmd) => {
917 req!(msgcmd.vals.len(), 1);
918 req!(msgcmd.vals[0], Dat::from("hello"));
919 req!(msgcmd.args.len(), 0);
920 },
921 None => return Err(err!(
922 "Expected command 'cmd1'.";
923 Input, Invalid)),
924 }
925 match msgrx.get_cmd("cmd2") {
926 Some(msgcmd) => {
927 req!(msgcmd.vals.len(), 2);
928 req!(msgcmd.vals[0], Dat::from("goodbye"));
929 req!(msgcmd.vals[1], Dat::from(-42i32));
930 req!(msgcmd.args.len(), 2);
931 if msgcmd.get_arg_vals("arg20").is_some() {
932 return Err(err!(
933 "Expected command 'cmd2' to have an argument \
934 '-a20' but no values.";
935 Input, Invalid));
936 }
937 match msgcmd.get_arg_vals("arg21") {
938 Some(vals) => {
939 req!(vals.len(), 1);
940 req!(vals[0], Dat::from("done"));
941 },
942 None => return Err(err!(
943 "Expected command 'cmd2' to have an argument '-a21'.";
944 Input, Invalid)),
945 }
946 },
947 None => return Err(err!(
948 "Expected command 'cmd2'.";
949 Input, Invalid)),
950 }
951
952 Ok(())
953 }));
954
955 res!(test_it(filter, &["Msg display 010", "all", "display"], || {
956 let mut p = Syntax::from(SyntaxConfig {
957 name: fmt!("TestSyntax"),
958 vals: vec![
959 (Kind::I16, fmt!("A number value for TestSyntax.")).into(),
960 ],
961 ..Default::default()
962 });
963 let a = Arg::from(ArgConfig {
964 name: fmt!("arg00"),
965 hyph1: Some(fmt!("a00")),
966 ..Default::default()
967 });
968 p = res!(p.add_arg(a));
969
970 let mut c = Cmd::from(CmdConfig {
971 name: fmt!("cmd1"),
972 vals: vec![
973 (Kind::Str, fmt!("A string value for cmd1.")).into(),
974 ],
975 ..Default::default()
976 });
977 let a = Arg::from(ArgConfig {
978 name: fmt!("arg10"),
979 hyph1: Some(fmt!("a10")),
980 ..Default::default()
981 });
982 c = res!(c.add_arg(a));
983 p = res!(p.add_cmd(c));
984
985 let mut c = Cmd::from(CmdConfig {
986 name: fmt!("cmd2"),
987 vals: vec![
988 (Kind::Str, fmt!("A string value for cmd2.")).into(),
989 (Kind::I32, fmt!("A number value for cmd2.")).into(),
990 ],
991 ..Default::default()
992 });
993 let a1 = Arg::from(ArgConfig {
994 name: fmt!("arg20"),
995 hyph1: Some(fmt!("a20")),
996 ..Default::default()
997 }).required(true);
998 let a2 = Arg::from(ArgConfig {
999 name: fmt!("arg21"),
1000 hyph1: Some(fmt!("a21")),
1001 hyph2: Some(fmt!("arg21")),
1002 vals: vec![
1003 (Kind::Str, fmt!("A string value for arg21.")).into(),
1004 ],
1005 ..Default::default()
1006 });
1007 c = res!(c.add_arg(a1));
1008 c = res!(c.add_arg(a2));
1009 p = res!(p.add_cmd(c));
1010 let p = SyntaxRef::new(p);
1011 let msgrx = Msg::new(p);
1012
1013 let msg = "(I16|42) -a00 cmd1 hello cmd2 goodbye (I32|-42) -a20 --arg21 done ";
1014
1015 debug!("Tx: {}", msg);
1016 let msgrx = res!(msgrx.from_str(
1017 "(I16|42) -a00 cmd1 hello cmd2 goodbye (I32|-42) -a20 --arg21 done ", None
1018 ));
1019 debug!("Rx: {}", msgrx);
1020 //for line in msgrx.to_lines() {
1021 // debug!("{}", line);
1022 //}
1023 let msgrx2 = res!(msgrx.from_str(&msgrx.to_string(), None));
1024 debug!("Tx: {}", msgrx);
1025 debug!("Rx: {}", msgrx2);
1026 //for line in msgrx2.to_lines() {
1027 // debug!("{}", line);
1028 //}
1029
1030 Ok(())
1031 }));
1032
1033 res!(test_it(filter, &["Msg build 010", "all", "build"], || {
1034 let p = res!(make_test_syntax_01());
1035 let mut msg = Msg::new(p);
1036 let expected = "-d (i32|-42) cmd1 (u8|3) -a (str|\"hello\") (i16|42) -b cmd2 -c (str|\"world\")";
1037
1038 msg = res!(msg.add_arg("-d")); // Redundant, just making sure these two work together.
1039 msg = res!(msg.add_arg_val("-d", Some(dat!(-42i32))));
1040
1041 let mut cmd2 = res!(msg.new_cmd("cmd2"));
1042 //cmd2 = res!(cmd2.add_arg("-c"));
1043 cmd2 = res!(cmd2.add_arg_val("-c", Some(dat!("world"))));
1044 msg = res!(msg.add_cmd(cmd2));
1045
1046 let mut cmd1 = res!(msg.new_cmd("cmd1"));
1047 cmd1 = res!(cmd1.add_cmd_val(dat!(3u8)));
1048 cmd1 = res!(cmd1.add_arg_val("-a", Some(dat!("hello"))));
1049 cmd1 = res!(cmd1.add_arg_val("-a", Some(dat!(42i16))));
1050 cmd1 = res!(cmd1.add_arg("-b"));
1051 msg = res!(msg.add_cmd(cmd1));
1052
1053 let result = fmt!("{}", msg);
1054 debug!("Expected : {}", expected);
1055 debug!("Constructed: {}", result);
1056 req!(&result, expected);
1057
1058 Ok(())
1059 }));
1060
1061 Ok(())
1062}