pact_models/matchingrules/
expressions.rs

1//! # Matching Rule definition expressions
2//!
3//! Parser for parsing matching rule definitions into a value, matching rules and generator tuple.
4//!
5//! The following are examples of matching rule definitions:
6//! * `matching(type,'Name')` - type matcher
7//! * `matching(number,100)` - number matcher
8//! * `matching(datetime, 'yyyy-MM-dd','2000-01-01')` - datetime matcher with format string
9//!
10//! ## Primitive values
11//!
12//! Primitive (or scalar) values can be strings (quoted with single quotes), numbers, booleans or null.
13//! Characters in strings can be escaped using a backslash. The standard escape sequences are
14//! supported:
15//! * `\'` quote
16//! * `\b` backspace
17//! * `\f` formfeed
18//! * `\n` linefeed
19//! * `\r` carriage return
20//! * `\t` tab
21//! * `\uXXXX` unicode hex code (4 digits)
22//! * `\u{X...}` unicode hex code (can be more than 4 digits)
23//!
24//! ## Expressions
25//!
26//! The main types of expressions are one of the following:
27//!
28//! ### matching(TYPE [, CONFIG], EXAMPLE) or matching($'NAME')
29//!
30//! Expression that defines a matching rule. Each matching rule requires the type of matching rule, and can contain an optional
31//! configuration value. The final value is the example value to use.
32//!
33//! Supported matching rules:
34//!
35//! | Rule        | Description                                                                                           | Config Value       | Example                                                                       |
36//! |-------------|-------------------------------------------------------------------------------------------------------|--------------------|-------------------------------------------------------------------------------|
37//! | equalTo     | Value must be equal to the example                                                                    |                    | `matching(equalTo, 'Example value')`                                          |
38//! | type        | Value must be the same type as the example                                                            |                    | `matching(type, 'Example value')`                                             |
39//! | number      | Value must be a numeric value                                                                         |                    | `matching(number, 100.09)`                                                    |
40//! | integer     | Value must be an integer value (no decimals)                                                          |                    | `matching(integer, 100)`                                                      |
41//! | decimal     | Value must be a decimal number (must have at least one significant figure after the decimal point)    |                    | `matching(decimnal, 100.01)`                                                  |
42//! | datetime    | Value must match a date-time format string                                                            | Format String      | `matching(datetime, 'yyyy-MM-dd HH:mm:ssZZZZZ', '2020-05-21 16:44:32+10:00')` |
43//! | date        | Value must match a date format string                                                                 | Format String      | `matching(date, 'yyyy-MM-dd', '2020-05-21')`                                       |
44//! | time        | Value must match a time format string                                                                 | Format String      | `matching(time, 'HH:mm', '22:04')`                                            |
45//! | regex       | Value must match a regular expression                                                                 | Regular expression | `matching(regex, '\\w{3}\\d+', 'abc123')`                                     |
46//! | include     | Value must include the example value as a substring                                                   |                    | `matching(include, 'testing')`                                                |
47//! | boolean     | Value must be a boolean                                                                               |                    | `matching(boolean, true)`                                                     |
48//! | server      | Value must match the semver specification                                                             |                    | `matching(semver, '1.0.0')`                                                   |
49//! | contentType | Value must be of the provided content type. This will preform a magic test on the bytes of the value. | Content type       | `matching(contentType, 'application/xml', '<?xml?><test/>')`                  |
50//!
51//! The final form is a reference to another key. This is used to setup type matching using an example value, and is normally
52//! used for collections. The name of the key must be a string value in single quotes.
53//!
54//! For example, to configure a type matcher where each value in a list must match the definition of a person:
55//!
56//! ```json
57//! {
58//!   "pact:match": "eachValue(matching($'person'))",
59//!   "person": {
60//!     "name": "Fred",
61//!     "age": 100
62//!   }
63//! }
64//! ```
65//!
66//! ### notEmpty(EXAMPLE)
67//!
68//! Expression that defines the value the same type as the example, must be present and not empty. This is used to defined
69//! required fields.
70//!
71//! Example: `notEmpty('test')`
72//!
73//! ### eachKey(EXPRESSION)
74//!
75//! Configures a matching rule to be applied to each key in a map.
76//!
77//! For example: `eachKey(matching(regex, '\$(\.\w+)+', '$.test.one'))`
78//!
79//! ### eachValue(EXPRESSION)
80//!
81//! Configures a matching rule to be applied to each value in a map or list.
82//!
83//! For example: `eachValue(matching(type, 100))`
84//!
85//! ### atLeast(SIZE)
86//!
87//! Configures a type matching rule to be applied to a map or list (if another rule is not applied),
88//! and asserts the length is at least the given size.
89//!
90//! For example: `atLeast(2)`
91//!
92//! ### atMost(SIZE)
93//!
94//! Configures a type matching rule to be applied to a map or list (if another rule is not applied), and asserts the
95//! length is at most the given size.
96//!
97//! For example: `atMost(2)`
98//!
99//! ## Composing expressions
100//!
101//! Expressions can be composed by separating them with a comma. For example
102//! `atLeast(2), atMost(10), eachValue(matching(regex, '\d+', '1234'))`. This will configure an
103//! array to have to have at least 2 items, at most 10, and each item in the array must match the
104//! given regex.
105//!
106//! ## Grammar
107//!
108//! There is a grammar for the definitions in [ANTLR4 format](https://github.com/pact-foundation/pact-plugins/blob/main/docs/matching-rule-definition.g4).
109//!
110
111use 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/// Type to associate with an expression element
129#[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  /// Merge this value type with the other one
141  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/// Reference to another attribute that defines the structure of the matching rule
188#[derive(Clone, Debug, PartialEq, Eq)]
189pub struct MatchingReference {
190  /// Name of the attribute that the reference is to
191  pub name: String
192}
193
194/// Matching rule definition constructed from parsing a matching rule definition expression
195#[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  /// Construct a new MatchingRuleDefinition
206  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  /// Merges two matching rules definitions. This is used when multiple matching rules are
223  /// provided for a single element.
224  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/// Parse a matcher definition into a MatchingRuleDefinition containing the example value, matching rules and any
315/// generator.
316/// The following are examples of matching rule definitions:
317/// * `matching(type,'Name')` - type matcher
318/// * `matching(number,100)` - number matcher
319/// * `matching(datetime, 'yyyy-MM-dd','2000-01-01')` - datetime matcher with format string
320#[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
330/// Determines if a sting starts with a valid matching rule definition. This is used in the case
331/// where a value can be a matching rule definition or a plain string value
332pub 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
351// matchingDefinition returns [ MatchingRuleDefinition value ] :
352//     matchingDefinitionExp ( COMMA matchingDefinitionExp )* EOF
353//     ;
354fn 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
372// matchingDefinitionExp returns [ MatchingRuleDefinition value ] :
373//     (
374//       'matching' LEFT_BRACKET matchingRule RIGHT_BRACKET
375//       | 'notEmpty' LEFT_BRACKET string RIGHT_BRACKET
376//       | 'eachKey' LEFT_BRACKET e=matchingDefinitionExp RIGHT_BRACKET
377//       | 'eachValue' LEFT_BRACKET e=matchingDefinitionExp RIGHT_BRACKET
378//       | 'atLeast' LEFT_BRACKET DIGIT+ RIGHT_BRACKET
379//       | 'atMost' LEFT_BRACKET DIGIT+ RIGHT_BRACKET
380//     )
381//     ;
382fn 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
465// LEFT_BRACKET e=matchingDefinitionExp RIGHT_BRACKET {
466//   if ($e.value != null) {
467//     $value = new MatchingRuleDefinition(null, ValueType.Unknown, List.of((Either<MatchingRule, MatchingReference>) new Either.A(new EachValueMatcher($e.value))), null);
468//   }
469// }
470fn 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
514// LEFT_BRACKET e=matchingDefinitionExp RIGHT_BRACKET
515fn 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
555// LEFT_BRACKET primitiveValue RIGHT_BRACKET
556fn 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
574// LEFT_BRACKET matchingRule RIGHT_BRACKET
575fn 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
590// matchingRule returns [ String value, ValueType type, MatchingRule rule, Generator generator, MatchingReference reference ] :
591//   (
592//     ( 'equalTo' { $rule = EqualsMatcher.INSTANCE; }
593//     | 'type'  { $rule = TypeMatcher.INSTANCE; } )
594//     COMMA v=primitiveValue { $value = $v.value; $type = $v.type; } )
595//   | 'number' { $rule = new NumberTypeMatcher(NumberTypeMatcher.NumberType.NUMBER); } COMMA val=( DECIMAL_LITERAL | INTEGER_LITERAL ) { $value = $val.getText(); $type = ValueType.Number; }
596//   | 'integer' { $rule = new NumberTypeMatcher(NumberTypeMatcher.NumberType.INTEGER); } COMMA val=INTEGER_LITERAL { $value = $val.getText(); $type = ValueType.Integer; }
597//   | 'decimal' { $rule = new NumberTypeMatcher(NumberTypeMatcher.NumberType.DECIMAL); } COMMA val=DECIMAL_LITERAL { $value = $val.getText(); $type = ValueType.Decimal; }
598//   | matcherType=( 'datetime' | 'date' | 'time' ) COMMA format=string {
599//     if ($matcherType.getText().equals("datetime")) { $rule = new TimestampMatcher($format.contents); }
600//     if ($matcherType.getText().equals("date")) { $rule = new DateMatcher($format.contents); }
601//     if ($matcherType.getText().equals("time")) { $rule = new TimeMatcher($format.contents); }
602//     } COMMA s=string { $value = $s.contents; $type = ValueType.String; }
603//   | 'regex' COMMA r=string COMMA s=string { $rule = new RegexMatcher($r.contents); $value = $s.contents; $type = ValueType.String; }
604//   | 'include' COMMA s=string { $rule = new IncludeMatcher($s.contents); $value = $s.contents; $type = ValueType.String; }
605//   | 'boolean' COMMA BOOLEAN_LITERAL { $rule = BooleanMatcher.INSTANCE; $value = $BOOLEAN_LITERAL.getText(); $type = ValueType.Boolean; }
606//   | 'semver' COMMA s=string { $rule = SemverMatcher.INSTANCE; $value = $s.contents; $type = ValueType.String; }
607//   | 'contentType' COMMA ct=string COMMA s=string { $rule = new ContentTypeMatcher($ct.contents); $value = $s.contents; $type = ValueType.Unknown; }
608//   | DOLLAR ref=string { $reference = new MatchingReference($ref.contents); $type = ValueType.Unknown; }
609//   ;
610fn 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
663// COMMA s=string { $rule = SemverMatcher.INSTANCE; $value = $s.contents; $type = ValueType.String; }
664fn 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
685//     COMMA v=primitiveValue { $value = $v.value; $type = $v.type; } )
686fn 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
695// COMMA r=string COMMA s=string { $rule = new RegexMatcher($r.contents); $value = $s.contents; $type = ValueType.String; }
696fn 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
704// COMMA v=primitiveValue { $value = $v.value; $type = $v.type; } )
705fn 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
714// COMMA format=string COMMA s=(string | 'fromProviderState' fromProviderState)
715fn 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
731// COMMA format=string COMMA s=(string | 'fromProviderState' fromProviderState)
732fn 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
748// COMMA format=string COMMA s=(string | 'fromProviderState' fromProviderState)
749fn 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
765// COMMA s=string { $rule = new IncludeMatcher($s.contents); $value = $s.contents; $type = ValueType.String; }
766fn 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
772// COMMA ct=string COMMA s=string { $rule = new ContentTypeMatcher($ct.contents); $value = $s.contents; $type = ValueType.Unknown; }
773fn 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
781// primitiveValue returns [ String value, ValueType type ] :
782//   string { $value = $string.contents; $type = ValueType.String; }
783//   | v=DECIMAL_LITERAL { $value = $v.getText(); $type = ValueType.Decimal; }
784//   | v=INTEGER_LITERAL { $value = $v.getText(); $type = ValueType.Integer; }
785//   | v=BOOLEAN_LITERAL { $value = $v.getText(); $type = ValueType.Boolean; }
786//   | STRING_LITERAL {
787//     String contents = $STRING_LITERAL.getText();
788//     $contents = contents.substring(1, contents.length() - 1);
789//   }
790//   | 'null'
791//   | 'fromProviderState' fromProviderState
792//   ;
793fn 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      // Logos is returning an INT token when a Decimal should match. We need to now parse the
804      // remaining pattern if it is a decimal
805      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      // Logos is returning an NUM token when a Decimal should match. We need to now parse the
815      // remaining pattern if it is a decimal
816      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// COMMA val=( DECIMAL_LITERAL | INTEGER_LITERAL | 'fromProviderState' fromProviderState)
834#[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    // Logos is returning an INT token when a Decimal should match. We need to now parse the
842    // remaining pattern if it is a decimal
843    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
862// COMMA val=INTEGER_LITERAL { $value = $val.getText(); $type = ValueType.Integer; }
863fn 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// COMMA val=DECIMAL_LITERAL { $value = $val.getText(); $type = ValueType.Decimal; }
881#[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    // Logos is returning an INT token when a Decimal should match. We need to now parse the
887    // remaining pattern if it is a decimal
888    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
909// COMMA BOOLEAN_LITERAL { $rule = BooleanMatcher.INSTANCE; $value = $BOOLEAN_LITERAL.getText(); $type = ValueType.Boolean; }
910fn 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
1060// LEFT_BRACKET DIGIT+ RIGHT_BRACKET
1061fn 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
1080// '(' exp=STRING_LITERAL COMMA v=primitiveValue ')'
1081fn 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  //     expression,                                      expected
1872  #[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  //     expression,                                      expected
1894  #[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}