1use std::char::REPLACEMENT_CHARACTER;
112use std::str::from_utf8;
113
114use anyhow::{anyhow, Error};
115use ariadne::{Config, Label, Report, ReportKind, Source};
116use bytes::{BufMut, BytesMut};
117use itertools::Either;
118use logos::{Lexer, Logos, Span};
119use semver::Version;
120use tracing::{instrument, trace, warn};
121
122use crate::expression_parser::DataType;
123use crate::generators::Generator;
124use crate::generators::Generator::ProviderStateGenerator;
125use crate::matchingrules::MatchingRule;
126use crate::matchingrules::MatchingRule::{MaxType, MinType, NotEmpty};
127
128#[derive(Debug, Copy, Clone, PartialEq, Eq)]
130pub enum ValueType {
131 Unknown,
132 String,
133 Number,
134 Integer,
135 Decimal,
136 Boolean
137}
138
139impl ValueType {
140 pub fn merge(self, other: ValueType) -> ValueType {
142 match (self, other) {
143 (ValueType::String, ValueType::String) => ValueType::String,
144 (ValueType::Number, ValueType::Number) => ValueType::Number,
145 (ValueType::Number, ValueType::Boolean) => ValueType::Number,
146 (ValueType::Number, ValueType::Unknown) => ValueType::Number,
147 (ValueType::Number, ValueType::Integer) => ValueType::Integer,
148 (ValueType::Number, ValueType::Decimal) => ValueType::Decimal,
149 (ValueType::Number, ValueType::String) => ValueType::String,
150 (ValueType::Integer, ValueType::Number) => ValueType::Integer,
151 (ValueType::Integer, ValueType::Boolean) => ValueType::Integer,
152 (ValueType::Integer, ValueType::Unknown) => ValueType::Integer,
153 (ValueType::Integer, ValueType::Integer) => ValueType::Integer,
154 (ValueType::Integer, ValueType::Decimal) => ValueType::Decimal,
155 (ValueType::Integer, ValueType::String) => ValueType::String,
156 (ValueType::Decimal, ValueType::Number) => ValueType::Decimal,
157 (ValueType::Decimal, ValueType::Boolean) => ValueType::Decimal,
158 (ValueType::Decimal, ValueType::Unknown) => ValueType::Decimal,
159 (ValueType::Decimal, ValueType::Integer) => ValueType::Decimal,
160 (ValueType::Decimal, ValueType::Decimal) => ValueType::Decimal,
161 (ValueType::Decimal, ValueType::String) => ValueType::String,
162 (ValueType::Boolean, ValueType::Number) => ValueType::Number,
163 (ValueType::Boolean, ValueType::Integer) => ValueType::Integer,
164 (ValueType::Boolean, ValueType::Decimal) => ValueType::Decimal,
165 (ValueType::Boolean, ValueType::Unknown) => ValueType::Boolean,
166 (ValueType::Boolean, ValueType::String) => ValueType::String,
167 (ValueType::Boolean, ValueType::Boolean) => ValueType::Boolean,
168 (ValueType::String, _) => ValueType::String,
169 (_, _) => other
170 }
171 }
172}
173
174impl Into<DataType> for ValueType {
175 fn into(self) -> DataType {
176 match self {
177 ValueType::Unknown => DataType::RAW,
178 ValueType::String => DataType::STRING,
179 ValueType::Number => DataType::DECIMAL,
180 ValueType::Integer => DataType::INTEGER,
181 ValueType::Decimal => DataType::DECIMAL,
182 ValueType::Boolean => DataType::BOOLEAN
183 }
184 }
185}
186
187#[derive(Clone, Debug, PartialEq, Eq)]
189pub struct MatchingReference {
190 pub name: String
192}
193
194#[derive(Clone, Debug, PartialEq, Eq)]
196pub struct MatchingRuleDefinition {
197 pub value: String,
198 pub value_type: ValueType,
199 pub rules: Vec<Either<MatchingRule, MatchingReference>>,
200 pub generator: Option<Generator>,
201 pub expression: String
202}
203
204impl MatchingRuleDefinition {
205 pub fn new(
207 value: String,
208 value_type: ValueType,
209 matching_rule: MatchingRule,
210 generator: Option<Generator>,
211 expression: String
212 ) -> Self {
213 MatchingRuleDefinition {
214 value,
215 value_type,
216 rules: vec![ Either::Left(matching_rule) ],
217 generator,
218 expression
219 }
220 }
221
222 pub fn merge(&self, other: &MatchingRuleDefinition) -> MatchingRuleDefinition {
225 trace!("Merging {:?} with {:?}", self, other);
226 if !self.value.is_empty() && !other.value.is_empty() {
227 warn!("There are multiple matching rules with values for the same value. There is no \
228 reliable way to combine them, so the later value ('{}') will be ignored.", other.value)
229 }
230
231 if self.generator.is_some() && other.generator.is_some() {
232 warn!("There are multiple generators for the same value. There is no reliable way to combine \
233 them, so the later generator ({:?}) will be ignored.", other.generator)
234 }
235
236 MatchingRuleDefinition {
237 value: if self.value.is_empty() { other.value.clone() } else { self.value.clone() },
238 value_type: self.value_type.merge(other.value_type),
239 rules: [self.rules.clone(), other.rules.clone()].concat(),
240 generator: self.generator.as_ref().or_else(|| other.generator.as_ref()).cloned(),
241 expression: if self.expression.is_empty() {
242 other.expression.clone()
243 } else if other.expression.is_empty() || self.expression == other.expression {
244 self.expression.clone()
245 } else {
246 format!("{}, {}", self.expression, other.expression)
247 }
248 }
249 }
250
251 pub fn expression(&self) -> String {
252 self.expression.clone()
253 }
254}
255
256#[derive(Logos, Debug, PartialEq)]
257#[logos(skip r"[ \t\n\f]+")]
258enum MatcherDefinitionToken {
259 #[token("matching")]
260 Matching,
261
262 #[token("notEmpty")]
263 NotEmpty,
264
265 #[token("eachKey")]
266 EachKey,
267
268 #[token("eachValue")]
269 EachValue,
270
271 #[token("atLeast")]
272 AtLeast,
273
274 #[token("atMost")]
275 AtMost,
276
277 #[token("(")]
278 LeftBracket,
279
280 #[token(")")]
281 RightBracket,
282
283 #[token(",")]
284 Comma,
285
286 #[regex(r"'(?:[^']|\\')*'")]
287 String,
288
289 #[regex("[a-zA-Z]+")]
290 Id,
291
292 #[regex("-[0-9]+", |lex| lex.slice().parse().ok())]
293 Int(i64),
294
295 #[regex("[0-9]+", |lex| lex.slice().parse().ok())]
296 Num(usize),
297
298 #[regex(r"-?[0-9]\.[0-9]+")]
299 Decimal,
300
301 #[regex(r"\.[0-9]+")]
302 DecimalPart,
303
304 #[regex(r"true|false")]
305 Boolean,
306
307 #[regex(r"null")]
308 Null,
309
310 #[token("$")]
311 Dollar
312}
313
314#[instrument(level = "debug", ret)]
321pub fn parse_matcher_def(v: &str) -> anyhow::Result<MatchingRuleDefinition> {
322 if v.is_empty() {
323 Err(anyhow!("Expected a matching rule definition, but got an empty string"))
324 } else {
325 let mut lex = MatcherDefinitionToken::lexer(v);
326 matching_definition(&mut lex, v)
327 }
328}
329
330pub fn is_matcher_def(v: &str) -> bool {
333 if v.is_empty() {
334 false
335 } else {
336 let mut lex = MatcherDefinitionToken::lexer(v);
337 let next = lex.next();
338 if let Some(Ok(token)) = next {
339 if token == MatcherDefinitionToken::Matching || token == MatcherDefinitionToken::NotEmpty ||
340 token == MatcherDefinitionToken::EachKey || token == MatcherDefinitionToken::EachValue {
341 true
342 } else {
343 false
344 }
345 } else {
346 false
347 }
348 }
349}
350
351fn matching_definition(lex: &mut Lexer<MatcherDefinitionToken>, v: &str) -> anyhow::Result<MatchingRuleDefinition> {
355 let mut value = matching_definition_exp(lex, v)?;
356 while let Some(Ok(next)) = lex.next() {
357 if next == MatcherDefinitionToken::Comma {
358 value = value.merge(&matching_definition_exp(lex, v)?);
359 } else {
360 return Err(anyhow!("expected comma, got '{}'", lex.slice()));
361 }
362 }
363
364 let remainder = lex.remainder();
365 if !remainder.is_empty() {
366 Err(anyhow!("expected not more tokens, got '{}' with '{}' remaining", lex.slice(), remainder))
367 } else {
368 Ok(value)
369 }
370}
371
372fn matching_definition_exp(lex: &mut Lexer<MatcherDefinitionToken>, v: &str) -> anyhow::Result<MatchingRuleDefinition> {
383 let next = lex.next();
384 if let Some(Ok(token)) = &next {
385 if token == &MatcherDefinitionToken::Matching {
386 let (value, value_type, matching_rule, generator, reference) = parse_matching(lex, v)?;
387 if let Some(reference) = reference {
388 Ok(MatchingRuleDefinition {
389 value,
390 value_type: ValueType::Unknown,
391 rules: vec![ Either::Right(reference) ],
392 generator,
393 expression: v.to_string()
394 })
395 } else {
396 Ok(MatchingRuleDefinition {
397 value,
398 value_type,
399 rules: vec![ Either::Left(matching_rule.unwrap()) ],
400 generator,
401 expression: v.to_string()
402 })
403 }
404 } else if token == &MatcherDefinitionToken::NotEmpty {
405 let (value, value_type, generator) = parse_not_empty(lex, v)?;
406 Ok(MatchingRuleDefinition {
407 value,
408 value_type,
409 rules: vec![Either::Left(NotEmpty)],
410 generator,
411 expression: v.to_string()
412 })
413 } else if token == &MatcherDefinitionToken::EachKey {
414 let definition = parse_each_key(lex, v)?;
415 Ok(definition)
416 } else if token == &MatcherDefinitionToken::EachValue {
417 let definition = parse_each_value(lex, v)?;
418 Ok(definition)
419 } else if token == &MatcherDefinitionToken::AtLeast {
420 let length = parse_length_param(lex, v)?;
421 Ok(MatchingRuleDefinition {
422 value: String::default(),
423 value_type: ValueType::Unknown,
424 rules: vec![Either::Left(MinType(length))],
425 generator: None,
426 expression: v.to_string()
427 })
428 } else if token == &MatcherDefinitionToken::AtMost {
429 let length = parse_length_param(lex, v)?;
430 Ok(MatchingRuleDefinition {
431 value: String::default(),
432 value_type: ValueType::Unknown,
433 rules: vec![Either::Left(MaxType(length))],
434 generator: None,
435 expression: v.to_string()
436 })
437 } else {
438 let mut buffer = BytesMut::new().writer();
439 let span = lex.span();
440 let report = Report::build(ReportKind::Error, ("expression", span.start..span.start))
441 .with_config(Config::default().with_color(false))
442 .with_message(format!("Expected a type of matching rule definition, but got '{}'", lex.slice()))
443 .with_label(Label::new(("expression", span)).with_message("Expected a matching rule definition here"))
444 .with_note("valid matching rule definitions are: matching, notEmpty, eachKey, eachValue, atLeast, atMost")
445 .finish();
446 report.write(("expression", Source::from(v)), &mut buffer)?;
447 let message = from_utf8(&*buffer.get_ref())?.to_string();
448 Err(anyhow!(message))
449 }
450 } else {
451 let mut buffer = BytesMut::new().writer();
452 let span = lex.span();
453 let report = Report::build(ReportKind::Error, ("expression", span.start..span.start))
454 .with_config(Config::default().with_color(false))
455 .with_message(format!("Expected a type of matching rule definition but got the end of the expression"))
456 .with_label(Label::new(("expression", span)).with_message("Expected a matching rule definition here"))
457 .with_note("valid matching rule definitions are: matching, notEmpty, eachKey, eachValue, atLeast, atMost")
458 .finish();
459 report.write(("expression", Source::from(v)), &mut buffer)?;
460 let message = from_utf8(&*buffer.get_ref())?.to_string();
461 Err(anyhow!(message))
462 }
463}
464
465fn parse_each_value(lex: &mut Lexer<MatcherDefinitionToken>, v: &str) -> anyhow::Result<MatchingRuleDefinition> {
471 let next = lex.next()
472 .ok_or_else(|| end_of_expression(v, "an opening bracket"))?;
473 if let Ok(MatcherDefinitionToken::LeftBracket) = next {
474 let result = matching_definition_exp(lex, v)?;
475 let next = lex.next().ok_or_else(|| end_of_expression(v, "a closing bracket"))?;
476 if let Ok(MatcherDefinitionToken::RightBracket) = next {
477 Ok(MatchingRuleDefinition {
478 value: "".to_string(),
479 value_type: ValueType::Unknown,
480 rules: vec![ Either::Left(MatchingRule::EachValue(result)) ],
481 generator: None,
482 expression: v.to_string()
483 })
484 } else {
485 Err(anyhow!(error_message(lex, v, "Expected a closing bracket", "Expected a closing bracket before this")?))
486 }
487 } else {
488 let mut buffer = BytesMut::new().writer();
489 let span = lex.span();
490 let report = Report::build(ReportKind::Error, ("expression", span.start..span.start))
491 .with_config(Config::default().with_color(false))
492 .with_message(format!("Expected an opening bracket, got '{}'", lex.slice()))
493 .with_label(Label::new(("expression", span)).with_message("Expected an opening bracket before this"))
494 .finish();
495 report.write(("expression", Source::from(v)), &mut buffer)?;
496 let message = from_utf8(&*buffer.get_ref())?.to_string();
497 Err(anyhow!(message))
498 }
499}
500
501fn error_message(lex: &mut Lexer<MatcherDefinitionToken>, v: &str, error: &str, additional: &str) -> Result<String, Error> {
502 let mut buffer = BytesMut::new().writer();
503 let span = lex.span();
504 let report = Report::build(ReportKind::Error, ("expression", span.start..span.start))
505 .with_config(Config::default().with_color(false))
506 .with_message(format!("{}, got '{}'", error, lex.slice()))
507 .with_label(Label::new(("expression", span)).with_message(additional))
508 .finish();
509 report.write(("expression", Source::from(v)), &mut buffer)?;
510 let message = from_utf8(&*buffer.get_ref())?.to_string();
511 Ok(message)
512}
513
514fn parse_each_key(lex: &mut Lexer<MatcherDefinitionToken>, v: &str) -> anyhow::Result<MatchingRuleDefinition> {
516 let next = lex.next()
517 .ok_or_else(|| end_of_expression(v, "an opening bracket"))?;
518 if let Ok(MatcherDefinitionToken::LeftBracket) = next {
519 let result = matching_definition_exp(lex, v)?;
520 let next = lex.next().ok_or_else(|| end_of_expression(v, "a closing bracket"))?;
521 if let Ok(MatcherDefinitionToken::RightBracket) = next {
522 Ok(MatchingRuleDefinition {
523 value: "".to_string(),
524 value_type: ValueType::Unknown,
525 rules: vec![ Either::Left(MatchingRule::EachKey(result)) ],
526 generator: None,
527 expression: v.to_string()
528 })
529 } else {
530 let mut buffer = BytesMut::new().writer();
531 let span = lex.span();
532 let report = Report::build(ReportKind::Error, ("expression", span.start..span.start))
533 .with_config(Config::default().with_color(false))
534 .with_message(format!("Expected a closing bracket, got '{}'", lex.slice()))
535 .with_label(Label::new(("expression", span)).with_message("Expected a closing bracket before this"))
536 .finish();
537 report.write(("expression", Source::from(v)), &mut buffer)?;
538 let message = from_utf8(&*buffer.get_ref())?.to_string();
539 Err(anyhow!(message))
540 }
541 } else {
542 let mut buffer = BytesMut::new().writer();
543 let span = lex.span();
544 let report = Report::build(ReportKind::Error, ("expression", span.start..span.start))
545 .with_config(Config::default().with_color(false))
546 .with_message(format!("Expected an opening bracket, got '{}'", lex.slice()))
547 .with_label(Label::new(("expression", span)).with_message("Expected an opening bracket before this"))
548 .finish();
549 report.write(("expression", Source::from(v)), &mut buffer)?;
550 let message = from_utf8(&*buffer.get_ref())?.to_string();
551 Err(anyhow!(message))
552 }
553}
554
555fn parse_not_empty(
557 lex: &mut Lexer<MatcherDefinitionToken>,
558 v: &str
559) -> anyhow::Result<(String, ValueType, Option<Generator>)> {
560 let next = lex.next().ok_or_else(|| end_of_expression(v, "'('"))?;
561 if let Ok(MatcherDefinitionToken::LeftBracket) = next {
562 let result = parse_primitive_value(lex, v, false)?;
563 let next = lex.next().ok_or_else(|| end_of_expression(v, "')'"))?;
564 if let Ok(MatcherDefinitionToken::RightBracket) = next {
565 Ok(result)
566 } else {
567 Err(anyhow!("expected closing bracket, got '{}'", lex.slice()))
568 }
569 } else {
570 Err(anyhow!("expected '(', got '{}'", lex.remainder()))
571 }
572}
573
574fn parse_matching(lex: &mut Lexer<MatcherDefinitionToken>, v: &str) -> anyhow::Result<(String, ValueType, Option<MatchingRule>, Option<Generator>, Option<MatchingReference>)> {
576 let next = lex.next().ok_or_else(|| end_of_expression(v, "'('"))?;
577 if let Ok(MatcherDefinitionToken::LeftBracket) = next {
578 let result = parse_matching_rule(lex, v)?;
579 let next = lex.next().ok_or_else(|| end_of_expression(v, "')'"))?;
580 if let Ok(MatcherDefinitionToken::RightBracket) = next {
581 Ok(result)
582 } else {
583 Err(anyhow!(error_message(lex, v, "Expected a closing bracket", "Expected a closing bracket before this")?))
584 }
585 } else {
586 Err(anyhow!(error_message(lex, v, "Expected an opening bracket", "Expected an opening bracket before this")?))
587 }
588}
589
590fn parse_matching_rule(lex: &mut logos::Lexer<MatcherDefinitionToken>, v: &str) -> anyhow::Result<(String, ValueType, Option<MatchingRule>, Option<Generator>, Option<MatchingReference>)> {
611 let next = lex.next()
612 .ok_or_else(|| end_of_expression(v, "a matcher (equalTo, regex, etc.)"))?;
613 if let Ok(MatcherDefinitionToken::Id) = next {
614 match lex.slice() {
615 "equalTo" => parse_equality(lex, v),
616 "regex" => parse_regex(lex, v),
617 "type" => parse_type(lex, v),
618 "datetime" => parse_datetime(lex, v),
619 "date" => parse_date(lex, v),
620 "time" => parse_time(lex, v),
621 "include" => parse_include(lex, v),
622 "number" => parse_number(lex, v),
623 "integer" => parse_integer(lex, v),
624 "decimal" => parse_decimal(lex, v),
625 "boolean" => parse_boolean(lex, v),
626 "contentType" => parse_content_type(lex, v),
627 "semver" => parse_semver(lex, v),
628 _ => {
629 let mut buffer = BytesMut::new().writer();
630 let span = lex.span();
631 let report = Report::build(ReportKind::Error, ("expression", span.start..span.start))
632 .with_config(Config::default().with_color(false))
633 .with_message(format!("Expected the type of matcher, got '{}'", lex.slice()))
634 .with_label(Label::new(("expression", span)).with_message("This is not a valid matcher type"))
635 .with_note("Valid matchers are: equalTo, regex, type, datetime, date, time, include, number, integer, decimal, boolean, contentType, semver")
636 .finish();
637 report.write(("expression", Source::from(v)), &mut buffer)?;
638 let message = from_utf8(&*buffer.get_ref())?.to_string();
639 Err(anyhow!(message))
640 }
641 }
642 } else if let Ok(MatcherDefinitionToken::Dollar) = next {
643 parse_reference(lex, v)
644 } else {
645 let mut buffer = BytesMut::new().writer();
646 let span = lex.span();
647 let report = Report::build(ReportKind::Error, ("expression", span.start..span.start))
648 .with_config(Config::default().with_color(false))
649 .with_message(format!("Expected the type of matcher, got '{}'", lex.slice()))
650 .with_label(Label::new(("expression", span)).with_message("Expected a matcher (equalTo, regex, etc.) here"))
651 .finish();
652 report.write(("expression", Source::from(v)), &mut buffer)?;
653 let message = from_utf8(&*buffer.get_ref())?.to_string();
654 Err(anyhow!(message))
655 }
656}
657
658fn parse_reference(lex: &mut Lexer<MatcherDefinitionToken>, v: &str) -> anyhow::Result<(String, ValueType, Option<MatchingRule>, Option<Generator>, Option<MatchingReference>)> {
659 let name = parse_string(lex, v)?;
660 Ok((name.clone(), ValueType::Unknown, None, None, Some(MatchingReference { name })))
661}
662
663fn parse_semver(lex: &mut Lexer<MatcherDefinitionToken>, v: &str) -> anyhow::Result<(String, ValueType, Option<MatchingRule>, Option<Generator>, Option<MatchingReference>)> {
665 parse_comma(lex, v)?;
666 let value = parse_string(lex, v)?;
667
668 match Version::parse(value.as_str()) {
669 Ok(_) => Ok((value, ValueType::String, Some(MatchingRule::Semver), None, None)),
670 Err(err) => {
671 let mut buffer = BytesMut::new().writer();
672 let span = lex.span();
673 let report = Report::build(ReportKind::Error, ("expression", span.start..span.start))
674 .with_config(Config::default().with_color(false))
675 .with_message(format!("Expected a semver compatible string, got {} - {}", lex.slice(), err))
676 .with_label(Label::new(("expression", span)).with_message("This is not a valid semver value"))
677 .finish();
678 report.write(("expression", Source::from(v)), &mut buffer)?;
679 let message = from_utf8(&*buffer.get_ref())?.to_string();
680 Err(anyhow!(message))
681 }
682 }
683}
684
685fn parse_equality(
687 lex: &mut Lexer<MatcherDefinitionToken>,
688 v: &str
689) -> anyhow::Result<(String, ValueType, Option<MatchingRule>, Option<Generator>, Option<MatchingReference>)> {
690 parse_comma(lex, v)?;
691 let (value, value_type, generator) = parse_primitive_value(lex, v, false)?;
692 Ok((value, value_type, Some(MatchingRule::Equality), generator, None))
693}
694
695fn parse_regex(lex: &mut Lexer<MatcherDefinitionToken>, v: &str) -> anyhow::Result<(String, ValueType, Option<MatchingRule>, Option<Generator>, Option<MatchingReference>)> {
697 parse_comma(lex, v)?;
698 let regex = parse_string(lex, v)?;
699 parse_comma(lex, v)?;
700 let value = parse_string(lex, v)?;
701 Ok((value, ValueType::String, Some(MatchingRule::Regex(regex)), None, None))
702}
703
704fn parse_type(
706 lex: &mut Lexer<MatcherDefinitionToken>,
707 v: &str
708) -> anyhow::Result<(String, ValueType, Option<MatchingRule>, Option<Generator>, Option<MatchingReference>)> {
709 parse_comma(lex, v)?;
710 let (value, value_type, generator) = parse_primitive_value(lex, v, false)?;
711 Ok((value, value_type, Some(MatchingRule::Type), generator, None))
712}
713
714fn parse_datetime(lex: &mut Lexer<MatcherDefinitionToken>, v: &str) -> anyhow::Result<(String, ValueType, Option<MatchingRule>, Option<Generator>, Option<MatchingReference>)> {
716 parse_comma(lex, v)?;
717 let format = parse_string(lex, v)?;
718 parse_comma(lex, v)?;
719
720 let remainder = lex.remainder().trim_start();
721 let (value, value_type, generator) = if remainder.starts_with("fromProviderState") {
722 lex.next();
723 from_provider_state(lex, v)?
724 } else {
725 (parse_string(lex, v)?, ValueType::String, Some(Generator::DateTime(Some(format.clone()), None)))
726 };
727
728 Ok((value, value_type, Some(MatchingRule::Timestamp(format.clone())), generator, None))
729}
730
731fn parse_date(lex: &mut Lexer<MatcherDefinitionToken>, v: &str) -> anyhow::Result<(String, ValueType, Option<MatchingRule>, Option<Generator>, Option<MatchingReference>)> {
733 parse_comma(lex, v)?;
734 let format = parse_string(lex, v)?;
735 parse_comma(lex, v)?;
736
737 let remainder = lex.remainder().trim_start();
738 let (value, value_type, generator) = if remainder.starts_with("fromProviderState") {
739 lex.next();
740 from_provider_state(lex, v)?
741 } else {
742 (parse_string(lex, v)?, ValueType::String, Some(Generator::Date(Some(format.clone()), None)))
743 };
744
745 Ok((value, value_type, Some(MatchingRule::Date(format.clone())), generator, None))
746}
747
748fn parse_time(lex: &mut Lexer<MatcherDefinitionToken>, v: &str) -> anyhow::Result<(String, ValueType, Option<MatchingRule>, Option<Generator>, Option<MatchingReference>)> {
750 parse_comma(lex, v)?;
751 let format = parse_string(lex, v)?;
752 parse_comma(lex, v)?;
753
754 let remainder = lex.remainder().trim_start();
755 let (value, value_type, generator) = if remainder.starts_with("fromProviderState") {
756 lex.next();
757 from_provider_state(lex, v)?
758 } else {
759 (parse_string(lex, v)?, ValueType::String, Some(Generator::Time(Some(format.clone()), None)))
760 };
761
762 Ok((value, value_type, Some(MatchingRule::Time(format.clone())), generator, None))
763}
764
765fn parse_include(lex: &mut Lexer<MatcherDefinitionToken>, v: &str) -> anyhow::Result<(String, ValueType, Option<MatchingRule>, Option<Generator>, Option<MatchingReference>)> {
767 parse_comma(lex, v)?;
768 let value = parse_string(lex, v)?;
769 Ok((value.clone(), ValueType::String, Some(MatchingRule::Include(value)), None, None))
770}
771
772fn parse_content_type(lex: &mut Lexer<MatcherDefinitionToken>, v: &str) -> anyhow::Result<(String, ValueType, Option<MatchingRule>, Option<Generator>, Option<MatchingReference>)> {
774 parse_comma(lex, v)?;
775 let ct = parse_string(lex, v)?;
776 parse_comma(lex, v)?;
777 let value = parse_string(lex, v)?;
778 Ok((value, ValueType::Unknown, Some(MatchingRule::ContentType(ct)), None, None))
779}
780
781fn parse_primitive_value(
794 lex: &mut Lexer<MatcherDefinitionToken>,
795 v: &str,
796 already_called: bool
797) -> anyhow::Result<(String, ValueType, Option<Generator>)> {
798 let next = lex.next().ok_or_else(|| end_of_expression(v, "expected a primitive value"))?;
799 match next {
800 Ok(MatcherDefinitionToken::String) => Ok((lex.slice().trim_matches('\'').to_string(), ValueType::String, None)),
801 Ok(MatcherDefinitionToken::Null) => Ok((String::new(), ValueType::String, None)),
802 Ok(MatcherDefinitionToken::Int(_)) => {
803 if lex.remainder().starts_with('.') {
806 let int_part = lex.slice();
807 let _ = lex.next().ok_or_else(|| end_of_expression(v, "expected a number"))?;
808 Ok((format!("{}{}", int_part, lex.slice()), ValueType::Decimal, None))
809 } else {
810 Ok((lex.slice().to_string(), ValueType::Integer, None))
811 }
812 },
813 Ok(MatcherDefinitionToken::Num(_)) => {
814 if lex.remainder().starts_with('.') {
817 let int_part = lex.slice();
818 let _ = lex.next().ok_or_else(|| end_of_expression(v, "expected a number"))?;
819 Ok((format!("{}{}", int_part, lex.slice()), ValueType::Decimal, None))
820 } else {
821 Ok((lex.slice().to_string(), ValueType::Integer, None))
822 }
823 },
824 Ok(MatcherDefinitionToken::Decimal) => Ok((lex.slice().to_string(), ValueType::Decimal, None)),
825 Ok(MatcherDefinitionToken::Boolean) => Ok((lex.slice().to_string(), ValueType::Boolean, None)),
826 Ok(MatcherDefinitionToken::Id) if lex.slice() == "fromProviderState" && !already_called => {
827 from_provider_state(lex, v)
828 },
829 _ => Err(anyhow!(error_message(lex, v, "Expected a primitive value", "Expected a primitive value here")?))
830 }
831}
832
833#[allow(clippy::if_same_then_else)]
835fn parse_number(lex: &mut Lexer<MatcherDefinitionToken>, v: &str) -> anyhow::Result<(String, ValueType, Option<MatchingRule>, Option<Generator>, Option<MatchingReference>)> {
836 parse_comma(lex, v)?;
837 let next = lex.next().ok_or_else(|| end_of_expression(v, "expected a number"))?;
838 if let Ok(MatcherDefinitionToken::Decimal) = next {
839 Ok((lex.slice().to_string(), ValueType::Number, Some(MatchingRule::Number), None, None))
840 } else if let Ok(MatcherDefinitionToken::Int(_) | MatcherDefinitionToken::Num(_)) = next {
841 if lex.remainder().starts_with('.') {
844 let int_part = lex.slice();
845 let _ = lex.next().ok_or_else(|| end_of_expression(v, "expected a number"))?;
846 Ok((format!("{}{}", int_part, lex.slice()), ValueType::Number, Some(MatchingRule::Number), None, None))
847 } else {
848 Ok((lex.slice().to_string(), ValueType::Number, Some(MatchingRule::Number), None, None))
849 }
850 } else if let Ok(MatcherDefinitionToken::Id) = next {
851 if lex.slice() == "fromProviderState" {
852 let (value, value_type, generator) = from_provider_state(lex, v)?;
853 Ok((value, value_type, Some(MatchingRule::Number), generator, None))
854 } else {
855 Err(anyhow!(error_message(lex, v, "Expected a number", "Expected a number here")?))
856 }
857 } else {
858 Err(anyhow!(error_message(lex, v, "Expected a number", "Expected a number here")?))
859 }
860}
861
862fn parse_integer(lex: &mut Lexer<MatcherDefinitionToken>, v: &str) -> anyhow::Result<(String, ValueType, Option<MatchingRule>, Option<Generator>, Option<MatchingReference>)> {
864 parse_comma(lex, v)?;
865 let next = lex.next().ok_or_else(|| end_of_expression(v, "expected an integer"))?;
866 if let Ok(MatcherDefinitionToken::Int(_) | MatcherDefinitionToken::Num(_)) = next {
867 Ok((lex.slice().to_string(), ValueType::Integer, Some(MatchingRule::Integer), None, None))
868 } else if let Ok(MatcherDefinitionToken::Id) = next {
869 if lex.slice() == "fromProviderState" {
870 let (value, value_type, generator) = from_provider_state(lex, v)?;
871 Ok((value, value_type, Some(MatchingRule::Integer), generator, None))
872 } else {
873 Err(anyhow!(error_message(lex, v, "Expected an integer", "Expected an integer here")?))
874 }
875 } else {
876 Err(anyhow!(error_message(lex, v, "Expected an integer", "Expected an integer here")?))
877 }
878}
879
880#[allow(clippy::if_same_then_else)]
882fn parse_decimal(lex: &mut Lexer<MatcherDefinitionToken>, v: &str) -> anyhow::Result<(String, ValueType, Option<MatchingRule>, Option<Generator>, Option<MatchingReference>)> {
883 parse_comma(lex, v)?;
884 let next = lex.next().ok_or_else(|| end_of_expression(v, "expected a decimal number"))?;
885 if let Ok(MatcherDefinitionToken::Int(_) | MatcherDefinitionToken::Num(_)) = next {
886 if lex.remainder().starts_with('.') {
889 let int_part = lex.slice();
890 let _ = lex.next().ok_or_else(|| end_of_expression(v, "expected a number"))?;
891 Ok((format!("{}{}", int_part, lex.slice()), ValueType::Decimal, Some(MatchingRule::Decimal), None, None))
892 } else {
893 Ok((lex.slice().to_string(), ValueType::Decimal, Some(MatchingRule::Decimal), None, None))
894 }
895 } else if let Ok(MatcherDefinitionToken::Decimal) = next {
896 Ok((lex.slice().to_string(), ValueType::Decimal, Some(MatchingRule::Decimal), None, None))
897 } else if let Ok(MatcherDefinitionToken::Id) = next {
898 if lex.slice() == "fromProviderState" {
899 let (value, value_type, generator) = from_provider_state(lex, v)?;
900 Ok((value, value_type, Some(MatchingRule::Number), generator, None))
901 } else {
902 Err(anyhow!(error_message(lex, v, "Expected a decimal number", "Expected a decimal number here")?))
903 }
904 } else {
905 Err(anyhow!(error_message(lex, v, "Expected a decimal number", "Expected a decimal number here")?))
906 }
907}
908
909fn parse_boolean(lex: &mut Lexer<MatcherDefinitionToken>, v: &str) -> anyhow::Result<(String, ValueType, Option<MatchingRule>, Option<Generator>, Option<MatchingReference>)> {
911 parse_comma(lex, v)?;
912 let next = lex.next().ok_or_else(|| end_of_expression(v, "expected a boolean"))?;
913 if let Ok(MatcherDefinitionToken::Boolean) = next {
914 Ok((lex.slice().to_string(), ValueType::Boolean, Some(MatchingRule::Boolean), None, None))
915 } else {
916 Err(anyhow!(error_message(lex, v, "Expected a boolean", "Expected a boolean here")?))
917 }
918}
919
920fn parse_string(lex: &mut Lexer<MatcherDefinitionToken>, v: &str) -> anyhow::Result<String> {
921 let next = lex.next().ok_or_else(|| end_of_expression(v, "a string"))?;
922 if let Ok(MatcherDefinitionToken::String) = next {
923 let span = lex.span();
924 let raw_str = lex.slice().trim_matches('\'');
925 process_raw_string(raw_str, span, v)
926 } else {
927 let mut buffer = BytesMut::new().writer();
928 let span = lex.span();
929 let report = Report::build(ReportKind::Error, ("expression", span.start..span.start))
930 .with_config(Config::default().with_color(false))
931 .with_message(format!("Expected a string value, got {}", lex.slice()))
932 .with_label(Label::new(("expression", span.clone())).with_message("Expected this to be a string"))
933 .with_note(format!("Surround the value in quotes: {}'{}'{}", &v[..span.start], lex.slice(), &v[span.end..]))
934 .finish();
935 report.write(("expression", Source::from(v)), &mut buffer)?;
936 let message = from_utf8(&*buffer.get_ref())?.to_string();
937 Err(anyhow!(message))
938 }
939}
940
941fn process_raw_string(raw_str: &str, span: Span, v: &str) -> anyhow::Result<String> {
942 let mut buffer = String::with_capacity(raw_str.len());
943 let mut chars = raw_str.chars();
944 while let Some(ch) = chars.next() {
945 if ch == '\\' {
946 match chars.next() {
947 None => buffer.push(ch),
948 Some(ch2) => {
949 match ch2 {
950 '\\' => buffer.push(ch),
951 'b' => buffer.push('\x08'),
952 'f' => buffer.push('\x0C'),
953 'n' => buffer.push('\n'),
954 'r' => buffer.push('\r'),
955 't' => buffer.push('\t'),
956 'u' => {
957 let code1 = char_or_error(chars.next(), &span, v)?;
958 let mut b = String::with_capacity(4);
959 if code1 == '{' {
960 loop {
961 let c = char_or_error(chars.next(), &span, v)?;
962 if c == '}' {
963 break;
964 } else {
965 b.push(c);
966 }
967 }
968 } else {
969 b.push(code1);
970 let code2 = char_or_error(chars.next(), &span, v)?;
971 b.push(code2);
972 let code3 = char_or_error(chars.next(), &span, v)?;
973 b.push(code3);
974 let code4 = char_or_error(chars.next(), &span, v)?;
975 b.push(code4);
976 }
977 let code = match u32::from_str_radix(b.as_str(), 16) {
978 Ok(c) => c,
979 Err(err) => return string_error(&err, &span, v)
980 };
981 let c = char::from_u32(code).unwrap_or(REPLACEMENT_CHARACTER);
982 buffer.push(c);
983 }
984 _ => {
985 buffer.push(ch);
986 buffer.push(ch2);
987 }
988 }
989 }
990 }
991 } else {
992 buffer.push(ch);
993 }
994 }
995 Ok(buffer)
996}
997
998fn string_error(err: &dyn std::error::Error, span: &Span, v: &str) -> anyhow::Result<String> {
999 let mut buffer = BytesMut::new().writer();
1000 let report = Report::build(ReportKind::Error, ("expression", span.start..span.start))
1001 .with_config(Config::default().with_color(false))
1002 .with_message(format!("Invalid unicode character escape sequence: {}", err))
1003 .with_label(Label::new(("expression", span.clone())).with_message("This string contains an invalid escape sequence"))
1004 .with_note("Unicode escape sequences must be in the form \\uXXXX (4 digits) or \\u{X..} (enclosed in braces)")
1005 .finish();
1006 report.write(("expression", Source::from(v)), &mut buffer)?;
1007 let message = from_utf8(&*buffer.get_ref())?.to_string();
1008 Err(anyhow!(message))
1009}
1010
1011fn char_or_error(ch: Option<char>, span: &Span, v: &str) -> anyhow::Result<char> {
1012 match ch {
1013 Some(ch) => Ok(ch),
1014 None => {
1015 let mut buffer = BytesMut::new().writer();
1016 let report = Report::build(ReportKind::Error, ("expression", span.start..span.start))
1017 .with_config(Config::default().with_color(false))
1018 .with_message("Invalid unicode character escape sequence")
1019 .with_label(Label::new(("expression", span.clone())).with_message("This string contains an invalid escape sequence"))
1020 .with_note("Unicode escape sequences must be in the form \\uXXXX (4 digits) or \\u{X..} (enclosed in braces)")
1021 .finish();
1022 report.write(("expression", Source::from(v)), &mut buffer)?;
1023 let message = from_utf8(&*buffer.get_ref())?.to_string();
1024 Err(anyhow!(message))
1025 }
1026 }
1027}
1028
1029fn parse_comma(lex: &mut Lexer<MatcherDefinitionToken>, v: &str) -> anyhow::Result<()> {
1030 let next = lex.next().ok_or_else(|| end_of_expression(v, "a comma"))?;
1031 if let Ok(MatcherDefinitionToken::Comma) = next {
1032 Ok(())
1033 } else {
1034 let mut buffer = BytesMut::new().writer();
1035 let span = lex.span();
1036 let report = Report::build(ReportKind::Error, ("expression", span.start..span.start))
1037 .with_config(Config::default().with_color(false))
1038 .with_message(format!("Expected a comma, got '{}'", lex.slice()))
1039 .with_label(Label::new(("expression", span)).with_message("Expected a comma before this"))
1040 .finish();
1041 report.write(("expression", Source::from(v)), &mut buffer)?;
1042 let message = from_utf8(&*buffer.get_ref())?.to_string();
1043 Err(anyhow!(message))
1044 }
1045}
1046
1047fn end_of_expression(v: &str, expected: &str) -> Error {
1048 let mut buffer = BytesMut::new().writer();
1049 let i = v.len();
1050 let report = Report::build(ReportKind::Error, ("expression", i..i))
1051 .with_config(Config::default().with_color(false))
1052 .with_message(format!("Expected {}, got the end of the expression", expected))
1053 .with_label(Label::new(("expression", i..i)).with_message(format!("Expected {} here", expected)))
1054 .finish();
1055 report.write(("expression", Source::from(v)), &mut buffer).unwrap();
1056 let message = from_utf8(&*buffer.get_ref()).unwrap().to_string();
1057 anyhow!(message)
1058}
1059
1060fn parse_length_param(lex: &mut Lexer<MatcherDefinitionToken>, v: &str) -> anyhow::Result<usize> {
1062 let next = lex.next().ok_or_else(|| end_of_expression(v, "an opening bracket"))?;
1063 if let Ok(MatcherDefinitionToken::LeftBracket) = next {
1064 let next = lex.next().ok_or_else(|| end_of_expression(v, "an unsized integer"))?;
1065 if let Ok(MatcherDefinitionToken::Num(length)) = next {
1066 let next = lex.next().ok_or_else(|| end_of_expression(v, "')'"))?;
1067 if let Ok(MatcherDefinitionToken::RightBracket) = next {
1068 Ok(length)
1069 } else {
1070 Err(anyhow!(error_message(lex, v, "Expected a closing bracket", "Expected a closing bracket before this")?))
1071 }
1072 } else {
1073 Err(anyhow!(error_message(lex, v, "Expected an unsigned number", "Expected an unsigned number here")?))
1074 }
1075 } else {
1076 Err(anyhow!(error_message(lex, v, "Expected an opening bracket", "Expected an opening bracket here")?))
1077 }
1078}
1079
1080fn from_provider_state(lex: &mut Lexer<MatcherDefinitionToken>, v: &str) -> anyhow::Result<(String, ValueType, Option<Generator>)> {
1082 let next = lex.next().ok_or_else(|| end_of_expression(v, "'('"))?;
1083 if let Ok(MatcherDefinitionToken::LeftBracket) = next {
1084 let expression = parse_string(lex, v)?;
1085 parse_comma(lex, v)?;
1086 let (value, val_type, _) = parse_primitive_value(lex, v, true)?;
1087 let next = lex.next().ok_or_else(|| end_of_expression(v, "')'"))?;
1088 if let Ok(MatcherDefinitionToken::RightBracket) = next {
1089 Ok((value, val_type, Some(ProviderStateGenerator(expression, Some(val_type.into())))))
1090 } else {
1091 Err(anyhow!(error_message(lex, v, "Expected a closing bracket", "Expected a closing bracket before this")?))
1092 }
1093 } else {
1094 Err(anyhow!(error_message(lex, v, "Expected an opening bracket", "Expected an opening bracket before this")?))
1095 }
1096}
1097
1098#[cfg(test)]
1099mod test {
1100 use expectest::prelude::*;
1101 use pretty_assertions::assert_eq;
1102 use rstest::rstest;
1103 use trim_margin::MarginTrimmable;
1104
1105 use crate::generators::Generator::{Date, DateTime, Time};
1106 use crate::matchingrules::MatchingRule;
1107 use crate::matchingrules::MatchingRule::{Regex, Type};
1108
1109 use super::*;
1110
1111 macro_rules! as_string {
1112 ($e:expr) => {{ $e.map_err(|err| err.to_string()) }};
1113 }
1114
1115 #[test]
1116 fn does_not_start_with_matching() {
1117 expect!(super::parse_matcher_def("")).to(be_err());
1118 expect!(super::parse_matcher_def("a, b, c")).to(be_err());
1119 expect!(super::parse_matcher_def("matching some other text")).to(be_err());
1120 }
1121
1122 #[test]
1123 fn parse_type_matcher() {
1124 let exp = "matching(type,'Name')";
1125 expect!(parse_matcher_def(exp).unwrap()).to(
1126 be_equal_to(MatchingRuleDefinition::new("Name".to_string(), ValueType::String, MatchingRule::Type, None, exp.to_string())));
1127 let exp = "matching( type, 'Name' )";
1128 expect!(parse_matcher_def(exp).unwrap()).to(
1129 be_equal_to(MatchingRuleDefinition::new("Name".to_string(), ValueType::String, MatchingRule::Type, None, exp.to_string())));
1130 let exp = "matching(type,123.4)";
1131 expect!(parse_matcher_def(exp).unwrap()).to(
1132 be_equal_to(MatchingRuleDefinition::new("123.4".to_string(), ValueType::Decimal, MatchingRule::Type, None, exp.to_string())));
1133 let exp = "matching(type, fromProviderState('exp', 3))";
1134 expect!(parse_matcher_def(exp).unwrap()).to(
1135 be_equal_to(MatchingRuleDefinition::new("3".to_string(), ValueType::Integer, MatchingRule::Type,
1136 Some(ProviderStateGenerator("exp".to_string(), Some(DataType::INTEGER))), exp.to_string())));
1137 }
1138
1139 #[test]
1140 fn parse_number_matcher() {
1141 let exp = "matching(number,100)";
1142 expect!(super::parse_matcher_def(exp).unwrap()).to(
1143 be_equal_to(MatchingRuleDefinition::new("100".to_string(), ValueType::Number, MatchingRule::Number, None, exp.to_string())));
1144 let exp = "matching(number,200.22)";
1145 expect!(super::parse_matcher_def(exp).unwrap()).to(
1146 be_equal_to(MatchingRuleDefinition::new("200.22".to_string(), ValueType::Number, MatchingRule::Number, None, exp.to_string())));
1147 let exp = "matching(integer,-100)";
1148 expect!(super::parse_matcher_def(exp).unwrap()).to(
1149 be_equal_to(MatchingRuleDefinition::new("-100".to_string(), ValueType::Integer, MatchingRule::Integer, None, exp.to_string())));
1150 let exp = "matching(decimal,100)";
1151 expect!(super::parse_matcher_def(exp).unwrap()).to(
1152 be_equal_to(MatchingRuleDefinition::new("100".to_string(), ValueType::Decimal, MatchingRule::Decimal, None, exp.to_string())));
1153 let exp = "matching(decimal,100.22)";
1154 expect!(super::parse_matcher_def(exp).unwrap()).to(
1155 be_equal_to(MatchingRuleDefinition::new("100.22".to_string(), ValueType::Decimal, MatchingRule::Decimal, None, exp.to_string())));
1156 let exp = "matching(number, fromProviderState('exp', 3))";
1157 expect!(parse_matcher_def(exp).unwrap()).to(
1158 be_equal_to(MatchingRuleDefinition::new("3".to_string(), ValueType::Integer, MatchingRule::Number,
1159 Some(ProviderStateGenerator("exp".to_string(), Some(DataType::INTEGER))), exp.to_string())));
1160 }
1161
1162 #[test]
1163 fn parse_datetime_matcher() {
1164 let exp = "matching(datetime, 'yyyy-MM-dd','2000-01-01')";
1165 expect!(super::parse_matcher_def(exp).unwrap()).to(
1166 be_equal_to(MatchingRuleDefinition::new("2000-01-01".to_string(),
1167 ValueType::String,
1168 MatchingRule::Timestamp("yyyy-MM-dd".to_string()),
1169 Some(DateTime(Some("yyyy-MM-dd".to_string()), None)), exp.to_string())));
1170 let exp = "matching(date, 'yyyy-MM-dd','2000-01-01')";
1171 expect!(super::parse_matcher_def(exp).unwrap()).to(
1172 be_equal_to(MatchingRuleDefinition::new("2000-01-01".to_string(),
1173 ValueType::String,
1174 MatchingRule::Date("yyyy-MM-dd".to_string()),
1175 Some(Date(Some("yyyy-MM-dd".to_string()), None)), exp.to_string())));
1176 let exp = "matching(time, 'HH:mm:ss','12:00:00')";
1177 expect!(super::parse_matcher_def(exp).unwrap()).to(
1178 be_equal_to(MatchingRuleDefinition::new("12:00:00".to_string(),
1179 ValueType::String,
1180 MatchingRule::Time("HH:mm:ss".to_string()),
1181 Some(Time(Some("HH:mm:ss".to_string()), None)), exp.to_string())));
1182 let exp = "matching(datetime, 'yyyy-MM-dd', fromProviderState('exp', '2000-01-01'))";
1183 expect!(super::parse_matcher_def(exp).unwrap()).to(
1184 be_equal_to(MatchingRuleDefinition::new("2000-01-01".to_string(),
1185 ValueType::String,
1186 MatchingRule::Timestamp("yyyy-MM-dd".to_string()),
1187 Some(ProviderStateGenerator("exp".to_string(), Some(DataType::STRING))),
1188 exp.to_string())));
1189 }
1190
1191 #[test]
1192 fn parse_regex_matcher() {
1193 let exp = "matching(regex,'\\w+', 'Fred')";
1194 expect!(super::parse_matcher_def(exp).unwrap()).to(
1195 be_equal_to(MatchingRuleDefinition::new("Fred".to_string(),
1196 ValueType::String,
1197 MatchingRule::Regex("\\w+".to_string()),
1198 None, exp.to_string())));
1199 }
1200
1201 #[test]
1202 fn parse_boolean_matcher() {
1203 let exp = "matching(boolean,true)";
1204 expect!(super::parse_matcher_def(exp).unwrap()).to(
1205 be_equal_to(MatchingRuleDefinition::new("true".to_string(),
1206 ValueType::Boolean,
1207 MatchingRule::Boolean,
1208 None, exp.to_string())));
1209 }
1210
1211 #[test]
1212 fn parse_include_matcher() {
1213 let exp = "matching(include,'Name')";
1214 expect!(super::parse_matcher_def(exp).unwrap()).to(
1215 be_equal_to(MatchingRuleDefinition::new("Name".to_string(),
1216 ValueType::String,
1217 MatchingRule::Include("Name".to_string()),
1218 None, exp.to_string())));
1219 }
1220
1221 #[test]
1222 fn parse_equals_matcher() {
1223 let exp = "matching(equalTo,'Name')";
1224 expect!(super::parse_matcher_def(exp).unwrap()).to(
1225 be_equal_to(MatchingRuleDefinition::new("Name".to_string(),
1226 ValueType::String,
1227 MatchingRule::Equality,
1228 None, exp.to_string())));
1229 let exp = "matching(equalTo,123.4)";
1230 expect!(super::parse_matcher_def(exp).unwrap()).to(
1231 be_equal_to(MatchingRuleDefinition::new("123.4".to_string(),
1232 ValueType::Decimal,
1233 MatchingRule::Equality,
1234 None, exp.to_string())));
1235 let exp = "matching(equalTo, fromProviderState('exp', 3))";
1236 expect!(parse_matcher_def(exp).unwrap()).to(
1237 be_equal_to(MatchingRuleDefinition::new("3".to_string(), ValueType::Integer, MatchingRule::Equality,
1238 Some(ProviderStateGenerator("exp".to_string(), Some(DataType::INTEGER))), exp.to_string())));
1239 }
1240
1241 #[test]
1242 fn parse_content_type_matcher() {
1243 let exp = "matching(contentType,'Name', 'Value')";
1244 expect!(super::parse_matcher_def(exp).unwrap()).to(
1245 be_equal_to(MatchingRuleDefinition::new("Value".to_string(),
1246 ValueType::Unknown,
1247 MatchingRule::ContentType("Name".to_string()),
1248 None, exp.to_string())));
1249 }
1250
1251 #[test]
1252 fn parse_not_empty() {
1253 let exp = "notEmpty('Value')";
1254 expect!(super::parse_matcher_def(exp).unwrap()).to(
1255 be_equal_to(MatchingRuleDefinition::new("Value".to_string(),
1256 ValueType::String,
1257 MatchingRule::NotEmpty,
1258 None, exp.to_string())));
1259 let exp = "notEmpty(100)";
1260 expect!(super::parse_matcher_def(exp).unwrap()).to(
1261 be_equal_to(MatchingRuleDefinition::new("100".to_string(),
1262 ValueType::Integer,
1263 MatchingRule::NotEmpty,
1264 None, exp.to_string())));
1265 let exp = "notEmpty(fromProviderState('exp', 3))";
1266 expect!(parse_matcher_def(exp).unwrap()).to(
1267 be_equal_to(MatchingRuleDefinition::new("3".to_string(), ValueType::Integer, MatchingRule::NotEmpty,
1268 Some(ProviderStateGenerator("exp".to_string(), Some(DataType::INTEGER))), exp.to_string())));
1269 }
1270
1271 #[test]
1272 fn parse_comma() {
1273 expect!(super::parse_comma(&mut MatcherDefinitionToken::lexer(", notEmpty('Value')"), ", notEmpty('Value')")).to(be_ok());
1274
1275 let mut lex = super::MatcherDefinitionToken::lexer("100 notEmpty(100)");
1276 lex.next();
1277 expect!(as_string!(super::parse_comma(&mut lex, "100 notEmpty(100)"))).to(
1278 be_err().value(
1279 "|Error: Expected a comma, got 'notEmpty'
1280 | ╭─[ expression:1:5 ]
1281 | │
1282 | 1 │ 100 notEmpty(100)
1283 | │ ────┬─── \u{0020}
1284 | │ ╰───── Expected a comma before this
1285 |───╯
1286 |
1287 ".trim_margin_with("|").unwrap()
1288 ));
1289
1290 let mut lex2 = super::MatcherDefinitionToken::lexer("100");
1291 lex2.next();
1292 expect!(as_string!(super::parse_comma(&mut lex2, "100"))).to(
1293 be_err().value(
1294 "|Error: Expected a comma, got the end of the expression
1295 | ╭─[ expression:1:4 ]
1296 | │
1297 | 1 │ 100
1298 | │ │\u{0020}
1299 | │ ╰─ Expected a comma here
1300 |───╯
1301 |
1302 ".trim_margin_with("|").unwrap()
1303 ));
1304 }
1305
1306 #[test]
1307 fn merging_types() {
1308 expect!(ValueType::String.merge(ValueType::Unknown)).to(be_equal_to(ValueType::String));
1309 expect!(ValueType::Unknown.merge(ValueType::String )).to(be_equal_to(ValueType::String));
1310 expect!(ValueType::Unknown.merge(ValueType::Number )).to(be_equal_to(ValueType::Number));
1311 expect!(ValueType::Number .merge(ValueType::Unknown)).to(be_equal_to(ValueType::Number));
1312 expect!(ValueType::Unknown.merge(ValueType::Integer)).to(be_equal_to(ValueType::Integer));
1313 expect!(ValueType::Integer.merge(ValueType::Unknown)).to(be_equal_to(ValueType::Integer));
1314 expect!(ValueType::Unknown.merge(ValueType::Decimal)).to(be_equal_to(ValueType::Decimal));
1315 expect!(ValueType::Decimal.merge(ValueType::Unknown)).to(be_equal_to(ValueType::Decimal));
1316 expect!(ValueType::Unknown.merge(ValueType::Boolean)).to(be_equal_to(ValueType::Boolean));
1317 expect!(ValueType::Boolean.merge(ValueType::Unknown)).to(be_equal_to(ValueType::Boolean));
1318 expect!(ValueType::Unknown.merge(ValueType::Unknown)).to(be_equal_to(ValueType::Unknown));
1319 expect!(ValueType::String .merge(ValueType::String )).to(be_equal_to(ValueType::String));
1320 expect!(ValueType::Number .merge(ValueType::Number )).to(be_equal_to(ValueType::Number));
1321 expect!(ValueType::Integer.merge(ValueType::Integer)).to(be_equal_to(ValueType::Integer));
1322 expect!(ValueType::Decimal.merge(ValueType::Decimal)).to(be_equal_to(ValueType::Decimal));
1323 expect!(ValueType::Boolean.merge(ValueType::Boolean)).to(be_equal_to(ValueType::Boolean));
1324 expect!(ValueType::Number .merge(ValueType::String )).to(be_equal_to(ValueType::String));
1325 expect!(ValueType::Integer.merge(ValueType::String )).to(be_equal_to(ValueType::String));
1326 expect!(ValueType::Decimal.merge(ValueType::String )).to(be_equal_to(ValueType::String));
1327 expect!(ValueType::Boolean.merge(ValueType::String )).to(be_equal_to(ValueType::String));
1328 expect!(ValueType::String .merge(ValueType::Number )).to(be_equal_to(ValueType::String));
1329 expect!(ValueType::String .merge(ValueType::Integer)).to(be_equal_to(ValueType::String));
1330 expect!(ValueType::String .merge(ValueType::Decimal)).to(be_equal_to(ValueType::String));
1331 expect!(ValueType::String .merge(ValueType::Boolean)).to(be_equal_to(ValueType::String));
1332 expect!(ValueType::Number .merge(ValueType::Integer)).to(be_equal_to(ValueType::Integer));
1333 expect!(ValueType::Number .merge(ValueType::Decimal)).to(be_equal_to(ValueType::Decimal));
1334 expect!(ValueType::Number .merge(ValueType::Boolean)).to(be_equal_to(ValueType::Number));
1335 expect!(ValueType::Integer.merge(ValueType::Number )).to(be_equal_to(ValueType::Integer));
1336 expect!(ValueType::Integer.merge(ValueType::Decimal)).to(be_equal_to(ValueType::Decimal));
1337 expect!(ValueType::Integer.merge(ValueType::Boolean)).to(be_equal_to(ValueType::Integer));
1338 expect!(ValueType::Decimal.merge(ValueType::Number )).to(be_equal_to(ValueType::Decimal));
1339 expect!(ValueType::Decimal.merge(ValueType::Integer)).to(be_equal_to(ValueType::Decimal));
1340 expect!(ValueType::Decimal.merge(ValueType::Boolean)).to(be_equal_to(ValueType::Decimal));
1341 expect!(ValueType::Boolean.merge(ValueType::Number )).to(be_equal_to(ValueType::Number));
1342 expect!(ValueType::Boolean.merge(ValueType::Integer)).to(be_equal_to(ValueType::Integer));
1343 expect!(ValueType::Boolean.merge(ValueType::Decimal)).to(be_equal_to(ValueType::Decimal));
1344 }
1345
1346 #[test]
1347 fn parse_semver_matcher() {
1348 let exp = "matching(semver, '1.0.0')";
1349 expect!(super::parse_matcher_def(exp).unwrap()).to(
1350 be_equal_to(MatchingRuleDefinition::new("1.0.0".to_string(),
1351 ValueType::String,
1352 MatchingRule::Semver,
1353 None, exp.to_string())));
1354
1355 expect!(as_string!(super::parse_matcher_def("matching(semver, '100')"))).to(
1356 be_err().value(
1357 "|Error: Expected a semver compatible string, got '100' - unexpected end of input while parsing major version number
1358 | ╭─[ expression:1:18 ]
1359 | │
1360 | 1 │ matching(semver, '100')
1361 | │ ──┬── \u{0020}
1362 | │ ╰──── This is not a valid semver value
1363 |───╯
1364 |
1365 ".trim_margin().unwrap()));
1366
1367 expect!(as_string!(super::parse_matcher_def("matching(semver, 100)"))).to(
1368 be_err().value(
1369 "|Error: Expected a string value, got 100
1370 | ╭─[ expression:1:18 ]
1371 | │
1372 | 1 │ matching(semver, 100)
1373 | │ ─┬─ \u{0020}
1374 | │ ╰─── Expected this to be a string
1375 | │\u{0020}
1376 | │ Note: Surround the value in quotes: matching(semver, '100')
1377 |───╯
1378 |
1379 ".trim_margin().unwrap()
1380 ));
1381 }
1382
1383 #[test]
1384 fn parse_matching_rule_test() {
1385 let mut lex = super::MatcherDefinitionToken::lexer("type, '1.0.0')");
1386 expect!(super::parse_matching_rule(&mut lex, "matching(type, '1.0.0')").unwrap()).to(
1387 be_equal_to(("1.0.0".to_string(), ValueType::String, Some(Type), None, None)));
1388
1389 let mut lex = super::MatcherDefinitionToken::lexer("match(");
1390 lex.next();
1391 lex.next();
1392 expect!(as_string!(super::parse_matching_rule(&mut lex, "matching("))).to(
1393 be_err().value(
1394 "|Error: Expected a matcher (equalTo, regex, etc.), got the end of the expression
1395 | ╭─[ expression:1:10 ]
1396 | │
1397 | 1 │ matching(
1398 | │ │\u{0020}
1399 | │ ╰─ Expected a matcher (equalTo, regex, etc.) here
1400 |───╯
1401 |
1402 ".trim_margin().unwrap()));
1403
1404 let mut lex = super::MatcherDefinitionToken::lexer("match(100, '100')");
1405 lex.next();
1406 lex.next();
1407 expect!(as_string!(super::parse_matching_rule(&mut lex, "match(100, '100')"))).to(
1408 be_err().value(
1409 "|Error: Expected the type of matcher, got '100'
1410 | ╭─[ expression:1:7 ]
1411 | │
1412 | 1 │ match(100, '100')
1413 | │ ─┬─ \u{0020}
1414 | │ ╰─── Expected a matcher (equalTo, regex, etc.) here
1415 |───╯
1416 |
1417 ".trim_margin().unwrap()));
1418
1419 let mut lex = super::MatcherDefinitionToken::lexer("match(testABBC, '100')");
1420 lex.next();
1421 lex.next();
1422 expect!(as_string!(super::parse_matching_rule(&mut lex, "match(testABBC, '100')"))).to(
1423 be_err().value(
1424 "|Error: Expected the type of matcher, got 'testABBC'
1425 | ╭─[ expression:1:7 ]
1426 | │
1427 | 1 │ match(testABBC, '100')
1428 | │ ────┬─── \u{0020}
1429 | │ ╰───── This is not a valid matcher type
1430 | │\u{0020}
1431 | │ Note: Valid matchers are: equalTo, regex, type, datetime, date, time, include, number, integer, decimal, boolean, contentType, semver
1432 |───╯
1433 |
1434 ".trim_margin().unwrap()));
1435 }
1436
1437 #[test]
1438 fn parse_matching_rule_with_reference_test() {
1439 let mut lex = super::MatcherDefinitionToken::lexer("$'bob'");
1440 expect!(super::parse_matching_rule(&mut lex, "matching($'bob')").unwrap()).to(
1441 be_equal_to(("bob".to_string(), ValueType::Unknown, None, None, Some(MatchingReference {
1442 name: "bob".to_string()
1443 }))));
1444
1445 let mut lex = super::MatcherDefinitionToken::lexer("match($");
1446 lex.next();
1447 lex.next();
1448 expect!(as_string!(super::parse_matching_rule(&mut lex, "matching($"))).to(
1449 be_err().value(
1450 "|Error: Expected a string, got the end of the expression
1451 | ╭─[ expression:1:11 ]
1452 | │
1453 | 1 │ matching($
1454 | │ │\u{0020}
1455 | │ ╰─ Expected a string here
1456 |───╯
1457 |
1458 ".trim_margin().unwrap()));
1459
1460 let mut lex = super::MatcherDefinitionToken::lexer("match($100)");
1461 lex.next();
1462 lex.next();
1463 expect!(as_string!(super::parse_matching_rule(&mut lex, "match($100)"))).to(
1464 be_err().value(
1465 "|Error: Expected a string value, got 100
1466 | ╭─[ expression:1:8 ]
1467 | │
1468 | 1 │ match($100)
1469 | │ ─┬─ \u{0020}
1470 | │ ╰─── Expected this to be a string
1471 | │\u{0020}
1472 | │ Note: Surround the value in quotes: match($'100')
1473 |───╯
1474 |
1475 ".trim_margin().unwrap()));
1476 }
1477
1478 #[test]
1479 fn matching_definition_exp_test() {
1480 let exp = "notEmpty('test')";
1481 let mut lex = MatcherDefinitionToken::lexer(exp);
1482 expect!(super::matching_definition_exp(&mut lex, exp)).to(
1483 be_ok().value(MatchingRuleDefinition {
1484 value: "test".to_string(),
1485 value_type: ValueType::String,
1486 rules: vec![ Either::Left(NotEmpty) ],
1487 generator: None,
1488 expression: exp.to_string()
1489 })
1490 );
1491
1492 let exp = "matching(regex, '.*', 'aaabbb')";
1493 let mut lex = MatcherDefinitionToken::lexer(exp);
1494 expect!(super::matching_definition_exp(&mut lex, exp)).to(
1495 be_ok().value(MatchingRuleDefinition {
1496 value: "aaabbb".to_string(),
1497 value_type: ValueType::String,
1498 rules: vec![ Either::Left(Regex(".*".to_string())) ],
1499 generator: None,
1500 expression: exp.to_string()
1501 })
1502 );
1503
1504 let exp = "matching($'test')";
1505 let mut lex = MatcherDefinitionToken::lexer(exp);
1506 expect!(super::matching_definition_exp(&mut lex, exp)).to(
1507 be_ok().value(MatchingRuleDefinition {
1508 value: "test".to_string(),
1509 value_type: ValueType::Unknown,
1510 rules: vec![ Either::Right(MatchingReference { name: "test".to_string() }) ],
1511 generator: None,
1512 expression: exp.to_string(),
1513 })
1514 );
1515
1516 let exp = "eachKey(matching(regex, '.*', 'aaabbb'))";
1517 let mut lex = MatcherDefinitionToken::lexer(exp);
1518 expect!(super::matching_definition_exp(&mut lex, exp)).to(
1519 be_ok().value(MatchingRuleDefinition {
1520 value: "".to_string(),
1521 value_type: ValueType::Unknown,
1522 rules: vec![ Either::Left(MatchingRule::EachKey(MatchingRuleDefinition {
1523 value: "aaabbb".to_string(),
1524 value_type: ValueType::String,
1525 rules: vec![ Either::Left(Regex(".*".to_string())) ],
1526 generator: None,
1527 expression: exp.to_string()
1528 })) ],
1529 generator: None,
1530 expression: exp.to_string()
1531 })
1532 );
1533
1534 let exp = "eachValue(matching(regex, '.*', 'aaabbb'))";
1535 let mut lex = MatcherDefinitionToken::lexer(exp);
1536 expect!(super::matching_definition_exp(&mut lex, exp)).to(
1537 be_ok().value(MatchingRuleDefinition {
1538 value: "".to_string(),
1539 value_type: ValueType::Unknown,
1540 rules: vec![ Either::Left(MatchingRule::EachValue(MatchingRuleDefinition {
1541 value: "aaabbb".to_string(),
1542 value_type: ValueType::String,
1543 rules: vec![ Either::Left(Regex(".*".to_string())) ],
1544 generator: None,
1545 expression: exp.to_string()
1546 })) ],
1547 generator: None,
1548 expression: exp.to_string()
1549 })
1550 );
1551
1552 let mut lex = MatcherDefinitionToken::lexer("100");
1553 lex.next();
1554 expect!(as_string!(super::matching_definition_exp(&mut lex, "100"))).to(
1555 be_err().value(
1556 "|Error: Expected a type of matching rule definition but got the end of the expression
1557 | ╭─[ expression:1:4 ]
1558 | │
1559 | 1 │ 100
1560 | │ │\u{0020}
1561 | │ ╰─ Expected a matching rule definition here
1562 | │\u{0020}
1563 | │ Note: valid matching rule definitions are: matching, notEmpty, eachKey, eachValue, atLeast, atMost
1564 |───╯
1565 |
1566 ".trim_margin().unwrap()));
1567
1568 let mut lex = MatcherDefinitionToken::lexer("somethingElse('to test')");
1569 expect!(as_string!(super::matching_definition_exp(&mut lex, "somethingElse('to test')"))).to(
1570 be_err().value(
1571 "|Error: Expected a type of matching rule definition, but got 'somethingElse'
1572 | ╭─[ expression:1:1 ]
1573 | │
1574 | 1 │ somethingElse('to test')
1575 | │ ──────┬────── \u{0020}
1576 | │ ╰──────── Expected a matching rule definition here
1577 | │\u{0020}
1578 | │ Note: valid matching rule definitions are: matching, notEmpty, eachKey, eachValue, atLeast, atMost
1579 |───╯
1580 |
1581 ".trim_margin().unwrap()));
1582 }
1583
1584 #[test]
1585 fn parse_each_key_test() {
1586 let exp = "(matching($'bob'))";
1587 let mut lex = MatcherDefinitionToken::lexer(exp);
1588 expect!(super::parse_each_key(&mut lex, exp).unwrap()).to(
1589 be_equal_to(MatchingRuleDefinition {
1590 value: "".to_string(),
1591 value_type: ValueType::Unknown,
1592 rules: vec![ Either::Left(MatchingRule::EachKey(MatchingRuleDefinition {
1593 value: "bob".to_string(),
1594 value_type: ValueType::Unknown,
1595 rules: vec![ Either::Right(MatchingReference { name: "bob".to_string() }) ],
1596 generator: None,
1597 expression: exp.to_string()
1598 }))
1599 ],
1600 generator: None,
1601 expression: exp.to_string()
1602 }));
1603
1604 let mut lex = MatcherDefinitionToken::lexer("eachKey");
1605 lex.next();
1606 expect!(as_string!(super::parse_each_key(&mut lex, "eachKey"))).to(
1607 be_err().value(
1608 "|Error: Expected an opening bracket, got the end of the expression
1609 | ╭─[ expression:1:8 ]
1610 | │
1611 | 1 │ eachKey
1612 | │ │\u{0020}
1613 | │ ╰─ Expected an opening bracket here
1614 |───╯
1615 |
1616 ".trim_margin().unwrap()));
1617
1618 let mut lex = MatcherDefinitionToken::lexer("eachKey matching");
1619 lex.next();
1620 expect!(as_string!(super::parse_each_key(&mut lex, "eachKey matching"))).to(
1621 be_err().value(
1622 "|Error: Expected an opening bracket, got 'matching'
1623 | ╭─[ expression:1:9 ]
1624 | │
1625 | 1 │ eachKey matching
1626 | │ ────┬─── \u{0020}
1627 | │ ╰───── Expected an opening bracket before this
1628 |───╯
1629 |
1630 ".trim_margin().unwrap()));
1631
1632 let mut lex = MatcherDefinitionToken::lexer("eachKey(matching(type, 'test') stuff");
1633 lex.next();
1634 expect!(as_string!(super::parse_each_key(&mut lex, "eachKey(matching(type, 'test') stuff"))).to(
1635 be_err().value(
1636 "|Error: Expected a closing bracket, got 'stuff'
1637 | ╭─[ expression:1:32 ]
1638 | │
1639 | 1 │ eachKey(matching(type, 'test') stuff
1640 | │ ──┬── \u{0020}
1641 | │ ╰──── Expected a closing bracket before this
1642 |───╯
1643 |
1644 ".trim_margin().unwrap()));
1645
1646 let mut lex = MatcherDefinitionToken::lexer("eachKey(matching(type, 'test')");
1647 lex.next();
1648 expect!(as_string!(super::parse_each_key(&mut lex, "eachKey(matching(type, 'test')"))).to(
1649 be_err().value(
1650 "|Error: Expected a closing bracket, got the end of the expression
1651 | ╭─[ expression:1:31 ]
1652 | │
1653 | 1 │ eachKey(matching(type, 'test')
1654 | │ │\u{0020}
1655 | │ ╰─ Expected a closing bracket here
1656 |───╯
1657 |
1658 ".trim_margin().unwrap()));
1659 }
1660
1661 #[test]
1662 fn parse_each_value_test() {
1663 let exp = "(matching($'bob'))";
1664 let mut lex = MatcherDefinitionToken::lexer(exp);
1665 expect!(super::parse_each_value(&mut lex, exp).unwrap()).to(
1666 be_equal_to(MatchingRuleDefinition {
1667 value: "".to_string(),
1668 value_type: ValueType::Unknown,
1669 rules: vec![ Either::Left(MatchingRule::EachValue(MatchingRuleDefinition {
1670 value: "bob".to_string(),
1671 value_type: ValueType::Unknown,
1672 rules: vec![ Either::Right(MatchingReference { name: "bob".to_string() }) ],
1673 generator: None,
1674 expression: exp.to_string()
1675 }))
1676 ],
1677 generator: None,
1678 expression: exp.to_string()
1679 }));
1680
1681 let mut lex = MatcherDefinitionToken::lexer("eachKey");
1682 lex.next();
1683 expect!(as_string!(super::parse_each_value(&mut lex, "eachKey"))).to(
1684 be_err().value(
1685 "|Error: Expected an opening bracket, got the end of the expression
1686 | ╭─[ expression:1:8 ]
1687 | │
1688 | 1 │ eachKey
1689 | │ │\u{0020}
1690 | │ ╰─ Expected an opening bracket here
1691 |───╯
1692 |
1693 ".trim_margin().unwrap()));
1694
1695 let mut lex = MatcherDefinitionToken::lexer("eachKey matching");
1696 lex.next();
1697 expect!(as_string!(super::parse_each_value(&mut lex, "eachKey matching"))).to(
1698 be_err().value(
1699 "|Error: Expected an opening bracket, got 'matching'
1700 | ╭─[ expression:1:9 ]
1701 | │
1702 | 1 │ eachKey matching
1703 | │ ────┬─── \u{0020}
1704 | │ ╰───── Expected an opening bracket before this
1705 |───╯
1706 |
1707 ".trim_margin().unwrap()));
1708
1709 let mut lex = MatcherDefinitionToken::lexer("eachKey(matching(type, 'test') stuff");
1710 lex.next();
1711 expect!(as_string!(super::parse_each_value(&mut lex, "eachKey(matching(type, 'test') stuff"))).to(
1712 be_err().value(
1713 "|Error: Expected a closing bracket, got 'stuff'
1714 | ╭─[ expression:1:32 ]
1715 | │
1716 | 1 │ eachKey(matching(type, 'test') stuff
1717 | │ ──┬── \u{0020}
1718 | │ ╰──── Expected a closing bracket before this
1719 |───╯
1720 |
1721 ".trim_margin().unwrap()));
1722
1723 let mut lex = MatcherDefinitionToken::lexer("eachKey(matching(type, 'test')");
1724 lex.next();
1725 expect!(as_string!(super::parse_each_value(&mut lex, "eachKey(matching(type, 'test')"))).to(
1726 be_err().value(
1727 "|Error: Expected a closing bracket, got the end of the expression
1728 | ╭─[ expression:1:31 ]
1729 | │
1730 | 1 │ eachKey(matching(type, 'test')
1731 | │ │\u{0020}
1732 | │ ╰─ Expected a closing bracket here
1733 |───╯
1734 |
1735 ".trim_margin().unwrap()));
1736 }
1737
1738 #[test_log::test]
1739 fn parse_multiple_matcher_definitions() {
1740 let exp = "eachKey(matching(regex, '\\$(\\.\\w+)+', '$.test.one')), eachValue(matching(type, null))";
1741 assert_eq!(super::parse_matcher_def(exp).unwrap(),
1742 MatchingRuleDefinition {
1743 value: "".to_string(),
1744 value_type: ValueType::Unknown,
1745 rules: vec![
1746 Either::Left(MatchingRule::EachKey(MatchingRuleDefinition {
1747 value: "$.test.one".to_string(),
1748 value_type: ValueType::String,
1749 rules: vec![Either::Left(MatchingRule::Regex("\\$(\\.\\w+)+".to_string()))],
1750 generator: None,
1751 expression: exp.to_string()
1752 })),
1753 Either::Left(MatchingRule::EachValue(MatchingRuleDefinition {
1754 value: "".to_string(),
1755 value_type: ValueType::String,
1756 rules: vec![Either::Left(MatchingRule::Type)],
1757 generator: None,
1758 expression: exp.to_string()
1759 }))
1760 ],
1761 generator: None,
1762 expression: exp.to_string()
1763 });
1764 }
1765
1766 #[test_log::test]
1767 fn merge_definitions() {
1768 let basic = MatchingRuleDefinition {
1769 value: "".to_string(),
1770 value_type: ValueType::Unknown,
1771 rules: vec![],
1772 generator: None,
1773 expression: "".to_string()
1774 };
1775 let with_value = MatchingRuleDefinition {
1776 value: "value".to_string(),
1777 value_type: ValueType::Unknown,
1778 rules: vec![],
1779 generator: None,
1780 expression: "".to_string()
1781 };
1782 let with_type = MatchingRuleDefinition {
1783 value: "value".to_string(),
1784 value_type: ValueType::String,
1785 rules: vec![],
1786 generator: None,
1787 expression: "".to_string()
1788 };
1789 let with_generator = MatchingRuleDefinition {
1790 value: "".to_string(),
1791 value_type: ValueType::String,
1792 rules: vec![],
1793 generator: Some(Date(None, None)),
1794 expression: "".to_string()
1795 };
1796 let with_matching_rule = MatchingRuleDefinition {
1797 value: "".to_string(),
1798 value_type: ValueType::String,
1799 rules: vec![ Either::Left(Type) ],
1800 generator: None,
1801 expression: "".to_string()
1802 };
1803 expect!(basic.merge(&basic)).to(be_equal_to(basic.clone()));
1804 expect!(basic.merge(&with_value)).to(be_equal_to(with_value.clone()));
1805 expect!(basic.merge(&with_type)).to(be_equal_to(with_type.clone()));
1806 expect!(basic.merge(&with_generator)).to(be_equal_to(with_generator.clone()));
1807 expect!(basic.merge(&with_matching_rule)).to(be_equal_to(with_matching_rule.clone()));
1808 expect!(with_matching_rule.merge(&with_matching_rule)).to(be_equal_to(MatchingRuleDefinition {
1809 value: "".to_string(),
1810 value_type: ValueType::String,
1811 rules: vec![ Either::Left(Type), Either::Left(Type) ],
1812 generator: None,
1813 expression: "".to_string()
1814 }));
1815
1816 let each_key = MatchingRuleDefinition {
1817 value: "".to_string(),
1818 value_type: ValueType::Unknown,
1819 rules: vec![
1820 Either::Left(MatchingRule::EachKey(MatchingRuleDefinition {
1821 value: "$.test.one".to_string(),
1822 value_type: ValueType::String,
1823 rules: vec![ Either::Left(Regex("\\$(\\.\\w+)+".to_string())) ],
1824 generator: None,
1825 expression: "".to_string()
1826 }))
1827 ],
1828 generator: None,
1829 expression: "".to_string()
1830 };
1831 let each_value = MatchingRuleDefinition {
1832 value: "".to_string(),
1833 value_type: ValueType::Unknown,
1834 rules: vec![
1835 Either::Left(MatchingRule::EachValue(MatchingRuleDefinition {
1836 value: "".to_string(),
1837 value_type: ValueType::String,
1838 rules: vec![ Either::Left(Type) ],
1839 generator: None,
1840 expression: "".to_string()
1841 }))
1842 ],
1843 generator: None,
1844 expression: "".to_string()
1845 };
1846 expect!(each_key.merge(&each_value)).to(be_equal_to(MatchingRuleDefinition {
1847 value: "".to_string(),
1848 value_type: ValueType::Unknown,
1849 rules: vec![
1850 Either::Left(MatchingRule::EachKey(MatchingRuleDefinition {
1851 value: "$.test.one".to_string(),
1852 value_type: ValueType::String,
1853 rules: vec![ Either::Left(Regex("\\$(\\.\\w+)+".to_string())) ],
1854 generator: None,
1855 expression: "".to_string()
1856 })),
1857 Either::Left(MatchingRule::EachValue(MatchingRuleDefinition {
1858 value: "".to_string(),
1859 value_type: ValueType::String,
1860 rules: vec![ Either::Left(Type) ],
1861 generator: None,
1862 expression: "".to_string()
1863 }))
1864 ],
1865 generator: None,
1866 expression: "".to_string()
1867 }));
1868 }
1869
1870 #[rstest]
1871 #[case("''", "")]
1873 #[case("'Example value'", "Example value")]
1874 #[case("'yyyy-MM-dd HH:mm:ssZZZZZ'", "yyyy-MM-dd HH:mm:ssZZZZZ")]
1875 #[case("'2020-05-21 16:44:32+10:00'", "2020-05-21 16:44:32+10:00")]
1876 #[case("'\\w{3}\\d+'", "\\w{3}\\d+")]
1877 #[case("'<?xml?><test/>'", "<?xml?><test/>")]
1878 #[case(r"'\$(\.\w+)+'", r"\$(\.\w+)+")]
1879 #[case(r"'we don\'t currently support parallelograms'", r"we don\'t currently support parallelograms")]
1880 #[case(r"'\b backspace'", "\x08 backspace")]
1881 #[case(r"'\f formfeed'", "\x0C formfeed")]
1882 #[case(r"'\n linefeed'", "\n linefeed")]
1883 #[case(r"'\r carriage return'", "\r carriage return")]
1884 #[case(r"'\t tab'", "\t tab")]
1885 #[case(r"'\u0109 unicode hex code'", "\u{0109} unicode hex code")]
1886 #[case(r"'\u{1DF0B} unicode hex code'", "\u{1DF0B} unicode hex code")]
1887 fn parse_string_test(#[case] expression: &str, #[case] expected: &str) {
1888 let mut lex = MatcherDefinitionToken::lexer(expression);
1889 expect!(parse_string(&mut lex, expression)).to(be_ok().value(expected.to_string()));
1890 }
1891
1892 #[rstest]
1893 #[case("", "")]
1895 #[case("Example value", "Example value")]
1896 #[case(r"not escaped \$(\.\w+)+", r"not escaped \$(\.\w+)+")]
1897 #[case(r"escaped \\", r"escaped \")]
1898 #[case(r"slash at end \", r"slash at end \")]
1899 fn process_raw_string_test(#[case] expression: &str, #[case] expected: &str) {
1900 expect!(process_raw_string(expression, 0..(expression.len()), expression)).to(be_ok().value(expected.to_string()));
1901 }
1902
1903 #[test]
1904 fn process_raw_string_error_test() {
1905 assert_eq!(
1906 ">Error: Invalid unicode character escape sequence
1907 > ╭─[ expression:1:2 ]
1908 > │
1909 > 1 │ 'invalid escape \\u in string'
1910 > │ ─────────────┬──────────── \u{0020}
1911 > │ ╰────────────── This string contains an invalid escape sequence
1912 > │\u{0020}
1913 > │ Note: Unicode escape sequences must be in the form \\uXXXX (4 digits) or \\u{X..} (enclosed in braces)
1914 >───╯
1915 >".trim_margin_with(">").unwrap(),
1916 process_raw_string(r"\u", 1..27, r"'invalid escape \u in string'").unwrap_err().to_string());
1917
1918 expect!(process_raw_string(r"\u0", 0..2, r"\u0")).to(be_err());
1919 expect!(process_raw_string(r"\u00", 0..3, r"\u00")).to(be_err());
1920 expect!(process_raw_string(r"\u000", 0..4, r"\u000")).to(be_err());
1921 expect!(process_raw_string(r"\u{000", 0..4, r"\u{000")).to(be_err());
1922 }
1923
1924 #[test]
1925 fn parse_at_least_test() {
1926 let exp = "atLeast(1)";
1927 let mut lex = MatcherDefinitionToken::lexer(exp);
1928 assert_eq!(super::matching_definition_exp(&mut lex, exp).unwrap(),
1929 MatchingRuleDefinition {
1930 value: "".to_string(),
1931 value_type: ValueType::Unknown,
1932 rules: vec![ Either::Left(MatchingRule::MinType(1)) ],
1933 generator: None,
1934 expression: exp.to_string()
1935 }
1936 );
1937
1938 let mut lex = MatcherDefinitionToken::lexer("atLeast");
1939 let result = super::matching_definition(&mut lex, "atLeast");
1940 assert_eq!(as_string!(result).unwrap_err(),
1941 "|Error: Expected an opening bracket, got the end of the expression
1942 | ╭─[ expression:1:8 ]
1943 | │
1944 | 1 │ atLeast
1945 | │ │\u{0020}
1946 | │ ╰─ Expected an opening bracket here
1947 |───╯
1948 |
1949 ".trim_margin().unwrap());
1950
1951 let mut lex = MatcherDefinitionToken::lexer("atLeast(-10)");
1952 assert_eq!(as_string!(super::matching_definition_exp(&mut lex, "atLeast(-10)")).unwrap_err(),
1953 "|Error: Expected an unsigned number, got '-10'
1954 | ╭─[ expression:1:9 ]
1955 | │
1956 | 1 │ atLeast(-10)
1957 | │ ─┬─ \u{0020}
1958 | │ ╰─── Expected an unsigned number here
1959 |───╯
1960 |
1961 ".trim_margin().unwrap());
1962
1963 let mut lex = MatcherDefinitionToken::lexer("atLeast('10')");
1964 assert_eq!(as_string!(super::matching_definition_exp(&mut lex, "atLeast('10')")).unwrap_err(),
1965 "|Error: Expected an unsigned number, got ''10''
1966 | ╭─[ expression:1:9 ]
1967 | │
1968 | 1 │ atLeast('10')
1969 | │ ──┬─ \u{0020}
1970 | │ ╰─── Expected an unsigned number here
1971 |───╯
1972 |
1973 ".trim_margin().unwrap());
1974
1975 let mut lex = MatcherDefinitionToken::lexer("atLeast(10");
1976 assert_eq!(as_string!(super::matching_definition_exp(&mut lex, "atLeast(10")).unwrap_err(),
1977 "|Error: Expected ')', got the end of the expression
1978 | ╭─[ expression:1:11 ]
1979 | │
1980 | 1 │ atLeast(10
1981 | │ │\u{0020}
1982 | │ ╰─ Expected ')' here
1983 |───╯
1984 |
1985 ".trim_margin().unwrap());
1986 }
1987
1988 #[test]
1989 fn parse_at_most_test() {
1990 let exp = "atMost(100)";
1991 let mut lex = MatcherDefinitionToken::lexer(exp);
1992 assert_eq!(super::matching_definition_exp(&mut lex, exp).unwrap(),
1993 MatchingRuleDefinition {
1994 value: "".to_string(),
1995 value_type: ValueType::Unknown,
1996 rules: vec![ Either::Left(MatchingRule::MaxType(100)) ],
1997 generator: None,
1998 expression: exp.to_string()
1999 }
2000 );
2001
2002 let mut lex = MatcherDefinitionToken::lexer("atMost");
2003 let result = super::matching_definition(&mut lex, "atMost");
2004 assert_eq!(as_string!(result).unwrap_err(),
2005 "|Error: Expected an opening bracket, got the end of the expression
2006 | ╭─[ expression:1:7 ]
2007 | │
2008 | 1 │ atMost
2009 | │ │\u{0020}
2010 | │ ╰─ Expected an opening bracket here
2011 |───╯
2012 |
2013 ".trim_margin().unwrap());
2014
2015 let mut lex = MatcherDefinitionToken::lexer("atMost(-10)");
2016 assert_eq!(as_string!(super::matching_definition_exp(&mut lex, "atMost(-10)")).unwrap_err(),
2017 "|Error: Expected an unsigned number, got '-10'
2018 | ╭─[ expression:1:8 ]
2019 | │
2020 | 1 │ atMost(-10)
2021 | │ ─┬─ \u{0020}
2022 | │ ╰─── Expected an unsigned number here
2023 |───╯
2024 |
2025 ".trim_margin().unwrap());
2026
2027 let mut lex = MatcherDefinitionToken::lexer("atMost('10')");
2028 assert_eq!(as_string!(super::matching_definition_exp(&mut lex, "atMost('10')")).unwrap_err(),
2029 "|Error: Expected an unsigned number, got ''10''
2030 | ╭─[ expression:1:8 ]
2031 | │
2032 | 1 │ atMost('10')
2033 | │ ──┬─ \u{0020}
2034 | │ ╰─── Expected an unsigned number here
2035 |───╯
2036 |
2037 ".trim_margin().unwrap());
2038
2039 let mut lex = MatcherDefinitionToken::lexer("atMost(10");
2040 assert_eq!(as_string!(super::matching_definition_exp(&mut lex, "atMost(10")).unwrap_err(),
2041 "|Error: Expected ')', got the end of the expression
2042 | ╭─[ expression:1:10 ]
2043 | │
2044 | 1 │ atMost(10
2045 | │ │\u{0020}
2046 | │ ╰─ Expected ')' here
2047 |───╯
2048 |
2049 ".trim_margin().unwrap());
2050 }
2051}