Skip to main content

overlay_file/
lib.rs

1pub mod error;
2pub mod overlay_registry;
3pub mod validator;
4
5use self::error::ParseError;
6use self::validator::OverlayfileValidator;
7
8use log::debug;
9use pest::Parser;
10use serde::{Deserialize, Serialize};
11use std::collections::HashMap;
12
13#[derive(pest_derive::Parser)]
14#[grammar = "overlay.pest"]
15struct OverlayParser;
16
17pub type Pair<'a> = pest::iterators::Pair<'a, Rule>;
18
19#[derive(Debug, Clone)]
20pub struct OverlayFile {
21    pub overlays_def: Vec<OverlayDef>,
22    pub meta: HashMap<String, String>,
23}
24
25impl OverlayFile {
26    pub fn new() -> Self {
27        OverlayFile {
28            overlays_def: Vec::new(),
29            meta: HashMap::new(),
30        }
31    }
32}
33
34impl Default for OverlayFile {
35    fn default() -> Self {
36        Self::new()
37    }
38}
39
40#[derive(Hash, Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
41pub struct OverlayDef {
42    pub namespace: Option<String>,
43    pub name: String,
44    pub version: String,
45    #[serde(default, skip_serializing_if = "Vec::is_empty")]
46    pub unique_keys: Vec<String>,
47    /// enahnce attributes from capture base with semantic information
48    pub elements: Vec<OverlayElementDef>,
49}
50
51impl Default for OverlayDef {
52    fn default() -> Self {
53        OverlayDef {
54            namespace: None,
55            name: String::new(),
56            version: "1.0.0".to_string(),
57            unique_keys: Vec::new(),
58            elements: Vec::new(),
59        }
60    }
61}
62
63impl OverlayDef {
64    /// Return elements that are defined as capture base attributes
65    pub fn get_attr_elements(&self) -> Vec<String> {
66        self.elements
67            .iter()
68            .filter(|el| el.keys == KeyType::AttrNames)
69            .map(|el| el.name.clone())
70            .collect()
71    }
72    /// Return ordered list of element names as they should appear in serialization
73    pub fn get_ordered_element_names(&self) -> Vec<String> {
74        self.elements.iter().map(|el| el.name.clone()).collect()
75    }
76    pub fn get_full_name(&self) -> String {
77        if let Some(namespace) = self.namespace.as_ref() {
78            format!(
79                "{}:{}/{}",
80                &namespace,
81                self.name,
82                self.version
83            )
84        } else {
85            format!("{}/{}", self.name, self.version)
86        }
87    }
88    pub fn get_name(&self) -> &str {
89        &self.name
90    }
91}
92
93#[derive(Debug, Clone, Eq, PartialEq)]
94pub struct KeyPair {
95    pub name: String,
96    pub kind: ElementType,
97}
98
99#[derive(Hash, Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
100pub struct OverlayElementDef {
101    pub name: String,
102    pub keys: KeyType,
103    pub values: ElementType,
104}
105
106#[derive(Hash, Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
107/// Type of the keys allowed for Overlay Object
108pub enum KeyType {
109    /// Keys names needs to correspond to the attribute names from Capture Base
110    AttrNames,
111    /// Keys are any arbitrary string
112    Text,
113    /// Key type for attribtues which are simple pairs, and do not have keys
114    None,
115}
116
117#[derive(Hash, Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
118/// Type of the values allowed for Overlay Object
119pub enum ElementType {
120    Object(Option<Box<OverlayElementDef>>),
121    Array(Option<Vec<ConstraintKind>>),
122    Binary,
123    Text,
124    /// Language code according to ISO 639-1 or ISO 639-3
125    Lang,
126    /// Reference in form of SAID to another object
127    Ref,
128    Complex(Vec<ElementType>),
129    /// Allow for any type
130    Any,
131}
132
133#[derive(Hash, Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
134pub enum ConstraintKind {
135    /// Only defined values are allowed
136    Closed(Option<Vec<String>>),
137    /// Defined values are allowed and any other value
138    Open(Option<Vec<String>>),
139    /// Any value is allowed
140    None,
141}
142
143#[derive(Debug)]
144pub struct FieldConstraint {
145    pub name: String,
146    pub required: bool,
147}
148
149pub fn parse_from_string(unparsed_file: String) -> Result<OverlayFile, ParseError> {
150    let file = OverlayParser::parse(Rule::file, &unparsed_file)
151        .map_err(|e| {
152            let (line_number, column_number) = match e.line_col {
153                pest::error::LineColLocation::Pos((line, column)) => (line, column),
154                pest::error::LineColLocation::Span((line, column), _) => (line, column),
155            };
156            ParseError::GrammarError {
157                line_number,
158                column_number,
159                raw_line: e.line().to_string(),
160                message: e.variant.to_string(),
161            }
162        })?
163        .next()
164        .unwrap();
165
166    let mut overlays_file = OverlayFile::new();
167
168    // TODO let validator = ... create validator for definition syntax
169
170    for line in file.into_inner() {
171        if let Rule::EOI = line.as_rule() {
172            continue;
173        }
174        if let Rule::comment = line.as_rule() {
175            continue;
176        }
177        if let Rule::meta_comment = line.as_rule() {
178            let mut key = "".to_string();
179            let mut value = "".to_string();
180            for attr in line.into_inner() {
181                match attr.as_rule() {
182                    Rule::meta_attr_key => {
183                        key = attr.as_str().to_string();
184                    }
185                    Rule::meta_attr_value => {
186                        value = attr.as_str().to_string();
187                    }
188                    _ => {
189                        return Err(ParseError::MetaError(attr.as_str().to_string()));
190                    }
191                }
192            }
193            if key.is_empty() {
194                return Err(ParseError::MetaError("key is empty".to_string()));
195            }
196            if value.is_empty() {
197                return Err(ParseError::MetaError("value is empty".to_string()));
198            }
199            overlays_file.meta.insert(key, value);
200            continue;
201        }
202        if let Rule::overlay_block = line.as_rule() {
203            let mut overlay_def = OverlayDef {
204                namespace: None,
205                name: "".to_string(),
206                version: "".to_string(),
207                unique_keys: Vec::new(),
208                elements: Vec::new(),
209            };
210            for attr in line.into_inner() {
211                match attr.as_rule() {
212                    Rule::overlay_name => {
213                        let (namespace, name): (Option<String>, String) =
214                            match attr.as_str().split_once(':') {
215                                Some((ns, n)) if !ns.is_empty() => {
216                                    (Some(ns.to_string()), n.to_string())
217                                }
218                                Some((_, n)) => (None, n.to_string()),
219                                None => (None, attr.as_str().to_string()),
220                            };
221                        match namespace {
222                            Some(ns) => {
223                                overlay_def.namespace = Some(ns.to_lowercase());
224                            }
225                            None => {
226                                overlay_def.namespace = None;
227                            }
228                        };
229                        overlay_def.name = name.to_lowercase();
230                    }
231                    Rule::version => {
232                        overlay_def.version = attr.as_str().to_string();
233                    }
234                    Rule::unique_keys_command => {
235                        overlay_def.unique_keys = parse_unique_keys_command(attr);
236                    }
237                    Rule::overlay_object => {
238                        let mut name: Option<String> = None;
239                        let mut keys_type: Option<KeyType> = None;
240                        let mut values_type: Option<ElementType> = None;
241                        debug!("Parsing overlay object: {:?}", attr);
242
243                        for e in attr.into_inner() {
244                            match e.as_rule() {
245                                Rule::overlay_object_header => {
246                                    e.into_inner().for_each(|header| match header.as_rule() {
247                                        Rule::attr_name => {
248                                            name = Some(header.as_str().to_string());
249                                        }
250                                        _ => {
251                                            panic!(
252                                                "Missing name for an object: {:?}",
253                                                header.as_rule()
254                                            )
255                                        }
256                                    });
257                                }
258                                Rule::overlay_object_body => {
259                                    (keys_type, values_type) = parse_object_body(e)?;
260                                }
261                                _ => {}
262                            }
263                        }
264                        let overlay_element = OverlayElementDef {
265                            name: name.clone().unwrap_or_default(),
266                            keys: keys_type.clone().unwrap_or(KeyType::Text),
267                            values: values_type.clone().unwrap_or(ElementType::Object(None)),
268                        };
269                        overlay_def.elements.push(overlay_element);
270                    }
271                    Rule::overlay_attributes => {
272                        let attrs = process_overlay_attributes(attr);
273                        overlay_def.elements.extend(attrs);
274                    }
275                    Rule::overlay_array => {
276                        let mut name: Option<String> = None;
277                        let mut values: Option<ElementType> = None;
278                        debug!("Parsing overlay array: {:?}", attr);
279                        for a in attr.into_inner() {
280                            debug!("Parsing overlay array element: {:?}", a);
281                            match a.as_rule() {
282                                Rule::overlay_array_header => {
283                                    for header_item in a.into_inner() {
284                                        if let Rule::attr_name = header_item.as_rule() {
285                                            name = Some(header_item.as_str().to_string());
286                                        }
287                                    }
288                                }
289                                Rule::overlay_array_body => {
290                                    for body_item in a.into_inner() {
291                                        if let Rule::value_type = body_item.as_rule() {
292                                            match body_item.into_inner().next() {
293                                                Some(v) => match v.as_rule() {
294                                                    Rule::array_type => {
295                                                        values = Some(ElementType::Array(None));
296                                                    }
297                                                    Rule::TEXT_TYPE => {
298                                                        values = Some(ElementType::Text);
299                                                    }
300                                                    Rule::REF_TYPE => {
301                                                        values = Some(ElementType::Ref);
302                                                    }
303                                                    Rule::LANG_TYPE => {
304                                                        values = Some(ElementType::Lang);
305                                                    }
306                                                    Rule::ANY_TYPE => {
307                                                        values = Some(ElementType::Any);
308                                                    }
309                                                    _ => continue,
310                                                },
311                                                None => {
312                                                    return Err(ParseError::MetaError(
313                                                        "value type is empty".to_string(),
314                                                    ));
315                                                }
316                                            }
317                                        }
318                                    }
319                                }
320                                _ => continue,
321                            }
322                        }
323                        let overlay_element = OverlayElementDef {
324                            name: name.clone().unwrap_or_default(),
325                            keys: KeyType::Text,
326                            values: values.clone().unwrap_or(ElementType::Array(None)),
327                        };
328                        overlay_def.elements.push(overlay_element);
329                    }
330                    _ => {}
331                }
332            }
333            overlays_file.overlays_def.push(overlay_def);
334            continue;
335        }
336        if let Rule::empty_line = line.as_rule() {
337            continue;
338        }
339    }
340
341    let overlays_file = OverlayFile {
342        overlays_def: overlays_file.overlays_def,
343        meta: overlays_file.meta,
344    };
345
346    // Validate the parsed OverlayFile
347    match OverlayfileValidator::validate(&overlays_file) {
348        Ok(_) => Ok(overlays_file),
349        Err(validation_errors) => Err(ParseError::ValidationError(validation_errors)),
350    }
351}
352
353fn parse_unique_keys_command(cmd: Pair) -> Vec<String> {
354    fn collect_attr_names(pair: Pair, out: &mut Vec<String>) {
355        for inner in pair.into_inner() {
356            if let Rule::attr_name = inner.as_rule() {
357                out.push(inner.as_str().to_string());
358            } else {
359                collect_attr_names(inner, out);
360            }
361        }
362    }
363
364    let mut keys = Vec::new();
365    collect_attr_names(cmd, &mut keys);
366    keys
367}
368
369fn process_overlay_attributes(attr: Pair) -> Vec<OverlayElementDef> {
370    debug!("Parsing overlay attribute: {:?}", attr);
371    let mut elements = Vec::new();
372    for a in attr.into_inner() {
373        match a.as_rule() {
374            Rule::key_pair => {
375                let element = process_key_pair(a);
376                debug!("-------- Found element {:?}", element);
377                elements.push(element);
378            }
379            Rule::ATTR_ARRAY => {
380                let result = process_attributes_array(a);
381                elements.extend(result);
382            }
383            _ => unreachable!(),
384        }
385    }
386    elements
387}
388
389fn parse_object_body(
390    object_body: Pair,
391) -> Result<(Option<KeyType>, Option<ElementType>), ParseError> {
392    let mut keys_type: Option<KeyType> = None;
393    let mut values_type: Option<ElementType> = None;
394
395    for key in object_body.into_inner() {
396        match key.as_rule() {
397            Rule::key_type => match key.into_inner().next() {
398                Some(k) => match k.as_rule() {
399                    Rule::ATTR_NAMES_TYPE => keys_type = Some(KeyType::AttrNames),
400                    Rule::TEXT_TYPE => keys_type = Some(KeyType::Text),
401                    Rule::ARRAY_KEY_TYPE => todo!(),
402                    _ => continue,
403                },
404                None => {
405                    return Err(ParseError::MetaError("key type is empty".to_string()));
406                }
407            },
408            Rule::value_type => match key.into_inner().next() {
409                Some(k) => match k.as_rule() {
410                    Rule::object_type => {
411                        let (nested_keys, nested_values) =
412                            parse_object_body(k.into_inner().next().unwrap())?;
413                        let nested_def = OverlayElementDef {
414                            name: "".to_string(), // Nested objects don't have a name in this context
415                            keys: nested_keys.unwrap_or(KeyType::Text),
416                            values: nested_values.unwrap_or(ElementType::Any),
417                        };
418                        values_type = Some(ElementType::Object(Some(Box::new(nested_def))));
419                    }
420                    Rule::array_type => {
421                        todo!()
422                    }
423                    Rule::TEXT_TYPE => {
424                        values_type = Some(ElementType::Text);
425                    }
426                    Rule::REF_TYPE => {
427                        values_type = Some(ElementType::Ref);
428                    }
429                    Rule::LANG_TYPE => {
430                        values_type = Some(ElementType::Lang);
431                    }
432                    Rule::ANY_TYPE => {
433                        values_type = Some(ElementType::Any);
434                    }
435                    Rule::complex_value_type => {
436                        let mut complex_types = Vec::new();
437                        for complex_type in k.into_inner() {
438                            match complex_type.as_rule() {
439                                Rule::array_type => complex_types.push(ElementType::Array(None)),
440                                Rule::object_type => {
441                                    let (nested_keys, nested_values) = parse_object_body(
442                                        complex_type.into_inner().next().unwrap(),
443                                    )?;
444                                    let nested_def = OverlayElementDef {
445                                        name: "".to_string(),
446                                        keys: nested_keys.unwrap_or(KeyType::Text),
447                                        values: nested_values.unwrap_or(ElementType::Any),
448                                    };
449                                    complex_types
450                                        .push(ElementType::Object(Some(Box::new(nested_def))));
451                                }
452                                Rule::REF_TYPE => complex_types.push(ElementType::Ref),
453                                Rule::TEXT_TYPE => complex_types.push(ElementType::Text),
454                                Rule::LANG_TYPE => complex_types.push(ElementType::Lang),
455                                _ => {}
456                            }
457                        }
458                        values_type = Some(ElementType::Complex(complex_types));
459                    }
460                    _ => {
461                        todo!("Value type not supported yet: {:?}", k)
462                    }
463                },
464                None => {
465                    return Err(ParseError::MetaError("value type is empty".to_string()));
466                }
467            },
468            _ => continue,
469        };
470    }
471    Ok((keys_type, values_type))
472}
473
474fn process_attributes_array(attr: Pair) -> Vec<OverlayElementDef> {
475    let mut attributes: Vec<OverlayElementDef> = Vec::new();
476    // Parse the list of attributes from array
477    for array in attr.into_inner() {
478        match array.as_rule() {
479            Rule::ARRAY_KEY_TYPE => {
480                for item in array.into_inner() {
481                    match item.as_rule() {
482                        Rule::array_content => {
483                            let mut items = Vec::new();
484                            let mut has_ellipsis = false;
485                            debug!("Parsing array items: {:?}", item);
486
487                            for content in item.into_inner() {
488                                match content.as_rule() {
489                                    Rule::array_items => {
490                                        for item in content.into_inner() {
491                                            if let Rule::key_item = item.as_rule() {
492                                                items.push(item.as_str().to_string());
493                                            }
494                                        }
495                                    }
496                                    Rule::trailing_ellipsis => {
497                                        has_ellipsis = true;
498                                    }
499                                    _ => {
500                                        panic!(
501                                            "Unexpected rule in array content: {:?}",
502                                            content.as_rule()
503                                        );
504                                    }
505                                }
506                            }
507
508                            for i in items {
509                                attributes.push(OverlayElementDef {
510                                    name: i.clone(),
511                                    keys: KeyType::None,
512                                    values: ElementType::Text, // Default value which would be overrided when we process WITH VALUES if present
513                                });
514                            }
515                            // if ellipsis is present in array we crate an empty string element in attributes list representing any element
516                            if has_ellipsis {
517                                attributes.push(OverlayElementDef {
518                                    name: "".to_string(),
519                                    keys: KeyType::None,
520                                    values: ElementType::Text,
521                                });
522                            }
523                        }
524                        _ => {
525                            debug!("Unexpected rule in array type: {:?}", item.as_rule());
526                        }
527                    }
528                }
529            }
530            Rule::keys_with_values => {
531                debug!("Parsing overlay array with values: {:?}", array);
532                for el in array.into_inner() {
533                    match el.as_rule() {
534                        Rule::value_type => {
535                            debug!("process value type for attribute array");
536                            let mut value_type = ElementType::Text;
537                            match el.as_str().to_lowercase().as_str() {
538                                "text" => value_type = ElementType::Text,
539                                "ref" => value_type = ElementType::Ref,
540                                "binary" => value_type = ElementType::Binary,
541                                "array" => value_type = ElementType::Array(None),
542                                "lang" => value_type = ElementType::Lang,
543                                "any" => value_type = ElementType::Any,
544                                _ => {}
545                            }
546                            for attribute in &mut attributes {
547                                attribute.values = value_type.clone();
548                            }
549                        }
550                        _ => unreachable!(),
551                    }
552                }
553            }
554            _ => unreachable!(),
555        }
556    }
557    attributes
558}
559
560fn process_key_pair(pair: Pair) -> OverlayElementDef {
561    let mut key_pair = KeyPair {
562        name: "".to_string(),
563        kind: ElementType::Text,
564    };
565    pair.into_inner().for_each(|kp| match kp.as_rule() {
566        Rule::attr_name => {
567            key_pair.name = kp.as_str().to_string();
568        }
569        Rule::attr_value_type => match kp.as_str() {
570            "Text" => key_pair.kind = ElementType::Text,
571            "Ref" => key_pair.kind = ElementType::Ref,
572            "Binary" => key_pair.kind = ElementType::Binary,
573            "Array" => key_pair.kind = ElementType::Array(None),
574            "Lang" => key_pair.kind = ElementType::Lang,
575            _ => {}
576        },
577        _ => {
578            panic!("Incorrect key pair for attribute: {:?}", kp.as_rule())
579        }
580    });
581
582    OverlayElementDef {
583        name: key_pair.name.clone(),
584        keys: KeyType::Text,
585        values: key_pair.kind.clone(),
586    }
587}
588
589#[cfg(test)]
590mod tests {
591    use super::*;
592
593    #[test]
594    fn test_overlay_name() {
595        let input = r#"
596ADD OVERLAY ReferenceValues
597  VERSION 1.0.0
598  ADD OBJECT attribute_reference_values
599    WITH KEYS attr-names
600    WITH VALUES Text
601"#;
602        let result = parse_from_string(input.to_string()).unwrap();
603        let overlay = result.overlays_def.first().unwrap();
604        assert_eq!(overlay.name, "referencevalues");
605        assert_eq!(overlay.namespace, None);
606
607        let input = r#"
608ADD OVERLAY :ReferenceValues
609  VERSION 1.0.0
610  ADD OBJECT attribute_reference_values
611    WITH KEYS attr-names
612    WITH VALUES Text"#;
613        let result = parse_from_string(input.to_string()).unwrap();
614        let overlay = result.overlays_def.first().unwrap();
615        assert_eq!(overlay.name, "referencevalues");
616        assert_eq!(overlay.namespace, None);
617
618        let input = r#"
619ADD OVERLAY hcf:ReferenceValues
620  VERSION 1.0.0
621  ADD OBJECT attribute_reference_values
622    WITH KEYS attr-names
623    WITH VALUES Text
624"#;
625        let result = parse_from_string(input.to_string()).unwrap();
626        let overlay = result.overlays_def.first().unwrap();
627        assert_eq!(overlay.name, "referencevalues");
628        assert_eq!(overlay.namespace.clone().unwrap(), "hcf".to_string());
629    }
630    #[test]
631    fn test_parsing_overlayfile() {
632        let input = r#"
633--name=HCF
634# Create new overlay
635ADD OVERLAY ReferenceValues
636  VERSION 1.0.1
637  UNIQUE KEYS [language, region]
638  ADD ATTRIBUTES language=Lang
639  ADD ATTRIBUTES region=Text
640  ADD OBJECT attribute_reference_values
641    WITH KEYS attr-names
642    WITH VALUES OBJECT
643      WITH KEYS Text
644      WITH VALUES Text
645
646ADD OVERLAY hcf:Information
647  VERSION 1.2.2
648  ADD ATTRIBUTES language=Lang
649  ADD OBJECT attr
650    WITH KEYS Text
651    WITH VALUES Text
652  ADD OBJECT attribute_information
653    WITH KEYS attr-names
654    WITH VALUES Text
655
656ADD OVERLAY hcf:Meta
657  VERSION 1.2.2
658  ADD ATTRIBUTES language=Lang photo=Binary
659  ADD ATTRIBUTES [name, description]
660    WITH VALUES TEXT
661  ADD ATTRIBUTES [...]
662    WITH VALUES ANY
663
664ADD OVERLAY ENTRY
665  VERSION 1.2.2
666  ADD ATTRIBUTES language=Lang
667  ADD OBJECT attr_entries
668    with keys attr-names
669    with values Object
670      with keys Text
671      with values Object
672        with keys Text
673        with values Any
674
675ADD OVERLAY hcf:EntryCodeMapping
676  VERSION 1.0.0
677  ADD ARRAY attr_entry_codes_mapping
678    WITH VALUES Text
679
680"#;
681
682        let result = parse_from_string(input.to_string()).unwrap();
683
684        let ref_overlay = result.overlays_def.first().unwrap();
685        let information = result.overlays_def.get(1).unwrap();
686        let meta = result.overlays_def.get(2).unwrap();
687        let entry = result.overlays_def.get(3).unwrap();
688        let entry_code_mapping = result.overlays_def.get(4).unwrap();
689        assert_eq!(result.overlays_def.len(), 5);
690        assert_eq!(ref_overlay.name, "referencevalues");
691        assert_eq!(ref_overlay.version, "1.0.1");
692        assert_eq!(ref_overlay.namespace, None);
693        assert_eq!(ref_overlay.unique_keys, vec!["language", "region"]);
694        assert_eq!(ref_overlay.elements.len(), 3);
695        assert_eq!(ref_overlay.elements[0].name, "language");
696        assert_eq!(ref_overlay.elements[0].values, ElementType::Lang);
697        assert_eq!(ref_overlay.elements[1].name, "region");
698        assert_eq!(ref_overlay.elements[1].values, ElementType::Text);
699        let ref_element = ref_overlay
700            .elements
701            .iter()
702            .find(|e| e.name == "attribute_reference_values")
703            .unwrap();
704        assert_eq!(ref_element.keys, KeyType::AttrNames);
705        assert_eq!(
706            ref_element.values,
707            ElementType::Object(Some(Box::new(OverlayElementDef {
708                name: "".to_string(),
709                keys: KeyType::Text,
710                values: ElementType::Text
711            })))
712        );
713
714        assert_eq!(information.version, "1.2.2");
715        assert_eq!(information.namespace.clone().unwrap(), "hcf".to_string());
716        debug!(">>>> {:?}", information);
717        assert_eq!(information.elements[0].name, "language");
718        assert_eq!(information.elements[0].values, ElementType::Lang);
719        assert_eq!(information.elements[2].name, "attribute_information");
720        assert_eq!(information.elements.len(), 3);
721        assert_eq!(information.name, "information");
722
723        assert_eq!(meta.version, "1.2.2");
724        assert_eq!(meta.elements.len(), 5);
725        assert_eq!(
726            meta.elements
727                .iter()
728                .find(|e| e.name == "name")
729                .unwrap()
730                .values,
731            ElementType::Text
732        );
733        assert_eq!(meta.elements.first().unwrap().name, "language");
734        assert_eq!(meta.elements.first().unwrap().values, ElementType::Lang);
735        assert_eq!(meta.elements.get(2).unwrap().name, "name");
736        assert_eq!(meta.elements.get(2).unwrap().values, ElementType::Text);
737        assert_eq!(meta.elements.last().unwrap().name, "");
738        assert_eq!(meta.elements.last().unwrap().values, ElementType::Any);
739
740        assert_eq!(entry.version, "1.2.2");
741        assert_eq!(entry.elements.len(), 2);
742        assert_eq!(entry.elements[1].name, "attr_entries");
743        assert_eq!(
744            entry.elements[1].values,
745            ElementType::Object(Some(Box::new(OverlayElementDef {
746                name: "".to_string(),
747                keys: KeyType::Text,
748                values: ElementType::Object(Some(Box::new(OverlayElementDef {
749                    name: "".to_string(),
750                    keys: KeyType::Text,
751                    values: ElementType::Any
752                })))
753            })))
754        );
755
756        assert_eq!(entry_code_mapping.name, "entrycodemapping");
757        assert_eq!(entry_code_mapping.version, "1.0.0");
758        assert_eq!(entry_code_mapping.elements.len(), 1);
759        assert_eq!(entry_code_mapping.elements[0].values, ElementType::Text);
760    }
761}