1use eure_document::document::NodeId;
22use eure_document::identifier::Identifier;
23use eure_document::parse::{FromEure, ParseContext, ParseError, ParseErrorKind};
24use indexmap::{IndexMap, IndexSet};
25use num_bigint::BigInt;
26
27use crate::interop::UnionInterop;
28use crate::{BindingStyle, Description, FieldCodegen, TextSchema, TypeReference};
29
30impl FromEure<'_> for TypeReference {
31 type Error = ParseError;
32 fn parse(ctx: &ParseContext<'_>) -> Result<Self, Self::Error> {
33 let path: &str = ctx.parse()?;
36
37 let path = path.strip_prefix("$types.").ok_or_else(|| ParseError {
39 node_id: ctx.node_id(),
40 kind: ParseErrorKind::InvalidPattern {
41 kind: "type reference".to_string(),
42 reason: format!(
43 "expected '$types.<name>' or '$types.<namespace>.<name>', got '{}'",
44 path
45 ),
46 },
47 })?;
48
49 let parts: Vec<&str> = path.split('.').collect();
51 match parts.as_slice() {
52 [name] => {
53 let name: Identifier = name.parse().map_err(|e| ParseError {
54 node_id: ctx.node_id(),
55 kind: ParseErrorKind::InvalidIdentifier(e),
56 })?;
57 Ok(TypeReference::Named {
58 namespace: None,
59 name,
60 })
61 }
62 [namespace, name] => {
63 let namespace: Identifier = namespace.parse().map_err(|e| ParseError {
64 node_id: ctx.node_id(),
65 kind: ParseErrorKind::InvalidIdentifier(e),
66 })?;
67 let name: Identifier = name.parse().map_err(|e| ParseError {
68 node_id: ctx.node_id(),
69 kind: ParseErrorKind::InvalidIdentifier(e),
70 })?;
71 Ok(TypeReference::Named {
72 namespace: Some(namespace),
73 name,
74 })
75 }
76 _ => Err(ParseError {
77 node_id: ctx.node_id(),
78 kind: ParseErrorKind::InvalidPattern {
79 kind: "type reference".to_string(),
80 reason: format!(
81 "expected '$types.<name>' or '$types.<namespace>.<name>', got '$types.{}'",
82 path
83 ),
84 },
85 }),
86 }
87 }
88}
89
90impl FromEure<'_> for crate::SchemaRef {
91 type Error = ParseError;
92
93 fn parse(ctx: &ParseContext<'_>) -> Result<Self, Self::Error> {
94 let schema_ctx = ctx.ext("schema")?;
95
96 let path: String = schema_ctx.parse()?;
97 Ok(crate::SchemaRef {
98 path,
99 node_id: schema_ctx.node_id(),
100 })
101 }
102}
103
104#[derive(Debug, Clone)]
110pub struct ParsedImportEntry {
111 pub raw_path: String,
113}
114
115#[derive(Debug, Clone, Default)]
117pub struct ParsedImports {
118 pub entries: IndexMap<Identifier, ParsedImportEntry>,
120}
121
122#[derive(Debug, Clone)]
124pub enum ParsedExports {
125 Explicit { names: Vec<Identifier> },
127}
128
129pub fn parse_root_imports(ctx: &ParseContext<'_>) -> Result<ParsedImports, ParseError> {
131 let Some(import_ctx) = ctx.ext_optional("import") else {
132 return Ok(ParsedImports::default());
133 };
134
135 let rec = import_ctx.parse_record()?;
136 let mut entries: IndexMap<Identifier, ParsedImportEntry> = IndexMap::new();
137
138 for result in rec.unknown_fields() {
139 let (alias, alias_ctx) = result.map_err(|(key, ctx)| ParseError {
140 node_id: ctx.node_id(),
141 kind: ParseErrorKind::InvalidKeyType(key.clone()),
142 })?;
143 let alias_ident: Identifier = alias.parse().map_err(|e| ParseError {
144 node_id: alias_ctx.node_id(),
145 kind: ParseErrorKind::InvalidIdentifier(e),
146 })?;
147 let raw_path: String = alias_ctx.parse()?;
148 entries.insert(alias_ident, ParsedImportEntry { raw_path });
149 }
150 rec.allow_unknown_fields()?;
151
152 Ok(ParsedImports { entries })
153}
154
155pub fn parse_root_exports(ctx: &ParseContext<'_>) -> Result<Option<ParsedExports>, ParseError> {
158 let Some(export_ctx) = ctx.ext_optional("export") else {
159 return Ok(None);
160 };
161 let origin = export_ctx.node_id();
162 let node = export_ctx.node();
163
164 use eure_document::document::node::NodeValue;
165 match &node.content {
166 NodeValue::Array(_) => {
167 let raw: Vec<String> = export_ctx.parse()?;
168 let mut names = Vec::with_capacity(raw.len());
169 for entry in raw {
170 let id: Identifier = entry.parse().map_err(|e| ParseError {
171 node_id: origin,
172 kind: ParseErrorKind::InvalidIdentifier(e),
173 })?;
174 names.push(id);
175 }
176 Ok(Some(ParsedExports::Explicit { names }))
177 }
178 other => Err(ParseError {
179 node_id: origin,
180 kind: ParseErrorKind::InvalidPattern {
181 kind: "$export value".to_string(),
182 reason: format!("expected [\"name\", ...] array, got {}", other.value_kind()),
183 },
184 }),
185 }
186}
187
188#[derive(Debug, Clone, eure_macros::FromEure)]
194#[eure(crate = eure_document, rename_all = "kebab-case")]
195pub struct ParsedIntegerSchema {
196 #[eure(default)]
198 pub range: Option<String>,
199 #[eure(default)]
201 pub multiple_of: Option<BigInt>,
202}
203
204#[derive(Debug, Clone, eure_macros::FromEure)]
206#[eure(crate = eure_document, rename_all = "kebab-case")]
207pub struct ParsedFloatSchema {
208 #[eure(default)]
210 pub range: Option<String>,
211 #[eure(default)]
213 pub multiple_of: Option<f64>,
214 #[eure(default)]
216 pub precision: Option<String>,
217}
218
219#[derive(Debug, Clone, eure_macros::FromEure)]
221#[eure(crate = eure_document, rename_all = "kebab-case")]
222pub struct ParsedArraySchema {
223 pub item: NodeId,
225 #[eure(default)]
227 pub min_length: Option<u32>,
228 #[eure(default)]
230 pub max_length: Option<u32>,
231 #[eure(default)]
233 pub unique: bool,
234 #[eure(default)]
236 pub contains: Option<NodeId>,
237 #[eure(ext, default)]
239 pub binding_style: Option<BindingStyle>,
240}
241
242#[derive(Debug, Clone, eure_macros::FromEure)]
244#[eure(crate = eure_document, rename_all = "kebab-case")]
245pub struct ParsedMapSchema {
246 pub key: NodeId,
248 pub value: NodeId,
250 #[eure(default)]
252 pub min_size: Option<u32>,
253 #[eure(default)]
255 pub max_size: Option<u32>,
256}
257
258#[derive(Debug, Clone, eure_macros::FromEure)]
260#[eure(crate = eure_document, parse_ext, rename_all = "kebab-case")]
261pub struct ParsedRecordFieldSchema {
262 #[eure(flatten_ext)]
264 pub schema: NodeId,
265 #[eure(default)]
267 pub optional: bool,
268 #[eure(default)]
270 pub binding_style: Option<BindingStyle>,
271 #[eure(default)]
273 pub codegen: Option<FieldCodegen>,
274}
275
276#[derive(Debug, Clone, Default)]
278pub enum ParsedUnknownFieldsPolicy {
279 #[default]
281 Deny,
282 Allow,
284 Schema(NodeId),
286}
287
288impl FromEure<'_> for ParsedUnknownFieldsPolicy {
289 type Error = ParseError;
290 fn parse(ctx: &ParseContext<'_>) -> Result<Self, Self::Error> {
291 let node = ctx.node();
292 let node_id = ctx.node_id();
293
294 if let NodeValue::Primitive(PrimitiveValue::Text(text)) = &node.content {
296 if text.language == Language::Plaintext {
298 return match text.as_str() {
299 "deny" => Ok(ParsedUnknownFieldsPolicy::Deny),
300 "allow" => Ok(ParsedUnknownFieldsPolicy::Allow),
301 _ => Err(ParseError {
302 node_id,
303 kind: ParseErrorKind::UnknownVariant(text.as_str().to_string()),
304 }),
305 };
306 }
307 }
308
309 Ok(ParsedUnknownFieldsPolicy::Schema(node_id))
311 }
312}
313
314#[derive(Debug, Clone, Default)]
316pub struct ParsedRecordSchema {
317 pub properties: IndexMap<String, ParsedRecordFieldSchema>,
319 pub flatten: Vec<NodeId>,
321 pub unknown_fields: ParsedUnknownFieldsPolicy,
323}
324
325impl FromEure<'_> for ParsedRecordSchema {
326 type Error = ParseError;
327 fn parse(ctx: &ParseContext<'_>) -> Result<Self, Self::Error> {
328 let unknown_fields = ctx
330 .parse_ext_optional::<ParsedUnknownFieldsPolicy>("unknown-fields")?
331 .unwrap_or_default();
332
333 let flatten = ctx
335 .parse_ext_optional::<Vec<NodeId>>("flatten")?
336 .unwrap_or_default();
337
338 let rec = ctx.parse_record()?;
340 let mut properties = IndexMap::new();
341
342 for result in rec.unknown_fields() {
343 let (field_name, field_ctx) = result.map_err(|(key, ctx)| ParseError {
344 node_id: ctx.node_id(),
345 kind: ParseErrorKind::InvalidKeyType(key.clone()),
346 })?;
347 let field_schema = ParsedRecordFieldSchema::parse(&field_ctx)?;
348 properties.insert(field_name.to_string(), field_schema);
349 }
350
351 Ok(ParsedRecordSchema {
352 properties,
353 flatten,
354 unknown_fields,
355 })
356 }
357}
358
359#[derive(Debug, Clone, eure_macros::FromEure)]
361#[eure(crate = eure_document, rename_all = "kebab-case")]
362pub struct ParsedTupleSchema {
363 pub elements: Vec<NodeId>,
365 #[eure(ext, default)]
367 pub binding_style: Option<BindingStyle>,
368}
369
370#[derive(Debug, Clone)]
372pub struct ParsedUnionSchema {
373 pub variants: IndexMap<String, NodeId>,
375 pub unambiguous: IndexSet<String>,
378 pub interop: UnionInterop,
380 pub deny_untagged: IndexSet<String>,
382}
383
384impl FromEure<'_> for ParsedUnionSchema {
385 type Error = ParseError;
386 fn parse(ctx: &ParseContext<'_>) -> Result<Self, Self::Error> {
387 let rec = ctx.parse_record()?;
388 let mut variants = IndexMap::new();
389 let mut unambiguous = IndexSet::new();
390 let mut deny_untagged = IndexSet::new();
391
392 if let Some(variants_ctx) = rec.field_optional("variants") {
394 let variants_rec = variants_ctx.parse_record()?;
395 for result in variants_rec.unknown_fields() {
396 let (name, var_ctx) = result.map_err(|(key, ctx)| ParseError {
397 node_id: ctx.node_id(),
398 kind: ParseErrorKind::InvalidKeyType(key.clone()),
399 })?;
400 variants.insert(name.to_string(), var_ctx.node_id());
401
402 if var_ctx
404 .parse_ext_optional::<bool>("deny-untagged")?
405 .unwrap_or(false)
406 {
407 deny_untagged.insert(name.to_string());
408 }
409 if var_ctx
410 .parse_ext_optional::<bool>("unambiguous")?
411 .unwrap_or(false)
412 {
413 unambiguous.insert(name.to_string());
414 }
415 }
416 }
417
418 rec.allow_unknown_fields()?;
419
420 if ctx.ext_optional("variant-repr").is_some() {
422 return Err(ParseError {
423 node_id: ctx.node_id(),
424 kind: ParseErrorKind::InvalidPattern {
425 kind: "legacy extension".to_string(),
426 reason: "`$variant-repr` is removed; use `$interop.variant-repr`".to_string(),
427 },
428 });
429 }
430
431 let interop = ctx
432 .parse_ext_optional::<UnionInterop>("interop")?
433 .unwrap_or_default();
434
435 Ok(ParsedUnionSchema {
436 variants,
437 unambiguous,
438 interop,
439 deny_untagged,
440 })
441 }
442}
443
444#[derive(Debug, Clone, eure_macros::FromEure)]
446#[eure(crate = eure_document, parse_ext)]
447pub struct ParsedExtTypeSchema {
448 #[eure(flatten_ext)]
450 pub schema: NodeId,
451 #[eure(default)]
453 pub optional: bool,
454 #[eure(default)]
456 pub binding_style: Option<BindingStyle>,
457}
458
459#[derive(Debug, Clone, Default)]
461pub struct ParsedSchemaMetadata {
462 pub description: Option<Description>,
464 pub deprecated: bool,
466 pub default: Option<NodeId>,
468 pub examples: Option<Vec<NodeId>>,
470}
471
472impl ParsedSchemaMetadata {
473 pub fn parse_from_extensions(ctx: &ParseContext<'_>) -> Result<Self, ParseError> {
475 let description = ctx.parse_ext_optional::<Description>("description")?;
476 let deprecated = ctx
477 .parse_ext_optional::<bool>("deprecated")?
478 .unwrap_or(false);
479 let default = ctx.ext_optional("default").map(|ctx| ctx.node_id());
480 let examples = ctx.parse_ext_optional::<Vec<NodeId>>("examples")?;
481
482 Ok(ParsedSchemaMetadata {
483 description,
484 deprecated,
485 default,
486 examples,
487 })
488 }
489}
490
491#[derive(Debug, Clone)]
493pub enum ParsedSchemaNodeContent {
494 Any,
496 Text(TextSchema),
498 Integer(ParsedIntegerSchema),
500 Float(ParsedFloatSchema),
502 Boolean,
504 Null,
506 Literal(NodeId),
508 Array(ParsedArraySchema),
510 Map(ParsedMapSchema),
512 Record(ParsedRecordSchema),
514 Tuple(ParsedTupleSchema),
516 Union(ParsedUnionSchema),
518 Reference(TypeReference),
520}
521
522#[derive(Debug, Clone)]
524pub struct ParsedSchemaNode {
525 pub content: ParsedSchemaNodeContent,
527 pub metadata: ParsedSchemaMetadata,
529 pub ext_types: IndexMap<Identifier, ParsedExtTypeSchema>,
531 pub codegen: Option<NodeId>,
533}
534
535use eure_document::document::node::NodeValue;
540use eure_document::text::Language;
541use eure_document::value::{PrimitiveValue, ValueKind};
542
543fn get_variant_string(ctx: &ParseContext<'_>) -> Result<Option<String>, ParseError> {
545 let variant_ctx = ctx.ext_optional("variant");
546
547 match variant_ctx {
548 Some(var_ctx) => {
549 let node = var_ctx.node();
550 match &node.content {
551 NodeValue::Primitive(PrimitiveValue::Text(t)) => Ok(Some(t.as_str().to_string())),
552 _ => Err(ParseError {
553 node_id: var_ctx.node_id(),
554 kind: ParseErrorKind::TypeMismatch {
555 expected: ValueKind::Text,
556 actual: node.content.value_kind(),
557 },
558 }),
559 }
560 }
561 None => Ok(None),
562 }
563}
564
565fn parse_type_reference_string(
568 node_id: NodeId,
569 s: &str,
570) -> Result<ParsedSchemaNodeContent, ParseError> {
571 if s.is_empty() {
572 return Err(ParseError {
573 node_id,
574 kind: ParseErrorKind::InvalidPattern {
575 kind: "type reference".to_string(),
576 reason: "expected non-empty type reference, got empty string".to_string(),
577 },
578 });
579 }
580
581 let segments: Vec<&str> = s.split('.').collect();
582 match segments.as_slice() {
583 ["text"] => Ok(ParsedSchemaNodeContent::Text(TextSchema::default())),
585 ["integer"] => Ok(ParsedSchemaNodeContent::Integer(ParsedIntegerSchema {
586 range: None,
587 multiple_of: None,
588 })),
589 ["float"] => Ok(ParsedSchemaNodeContent::Float(ParsedFloatSchema {
590 range: None,
591 multiple_of: None,
592 precision: None,
593 })),
594 ["boolean"] => Ok(ParsedSchemaNodeContent::Boolean),
595 ["null"] => Ok(ParsedSchemaNodeContent::Null),
596 ["any"] => Ok(ParsedSchemaNodeContent::Any),
597
598 ["text", lang] => Ok(ParsedSchemaNodeContent::Text(TextSchema {
600 language: Some((*lang).to_string()),
601 ..Default::default()
602 })),
603
604 ["$types", type_name] => {
606 let name: Identifier = type_name.parse().map_err(|e| ParseError {
607 node_id,
608 kind: ParseErrorKind::InvalidIdentifier(e),
609 })?;
610 Ok(ParsedSchemaNodeContent::Reference(TypeReference::Named {
611 namespace: None,
612 name,
613 }))
614 }
615
616 ["$types", namespace, type_name] => {
618 let name: Identifier = type_name.parse().map_err(|e| ParseError {
619 node_id,
620 kind: ParseErrorKind::InvalidIdentifier(e),
621 })?;
622 let namespace: Identifier = namespace.parse().map_err(|e| ParseError {
623 node_id,
624 kind: ParseErrorKind::InvalidIdentifier(e),
625 })?;
626 Ok(ParsedSchemaNodeContent::Reference(TypeReference::Named {
627 namespace: Some(namespace),
628 name,
629 }))
630 }
631
632 _ => Err(ParseError {
634 node_id,
635 kind: ParseErrorKind::InvalidPattern {
636 kind: "type reference".to_string(),
637 reason: format!(
638 "expected 'text', 'integer', '$types.name', etc., got '{}'",
639 s
640 ),
641 },
642 }),
643 }
644}
645
646fn parse_primitive_as_schema(
648 ctx: &ParseContext<'_>,
649 prim: &PrimitiveValue,
650) -> Result<ParsedSchemaNodeContent, ParseError> {
651 let node_id = ctx.node_id();
652 match prim {
653 PrimitiveValue::Text(t) => {
654 match &t.language {
655 Language::Implicit => parse_type_reference_string(node_id, t.as_str()),
657 Language::Other(lang) if lang == "eure-path" => {
658 parse_type_reference_string(node_id, t.as_str())
659 }
660 _ => Ok(ParsedSchemaNodeContent::Literal(node_id)),
662 }
663 }
664 _ => Ok(ParsedSchemaNodeContent::Literal(node_id)),
666 }
667}
668
669fn parse_map_as_schema(
671 ctx: &ParseContext<'_>,
672 variant: Option<String>,
673) -> Result<ParsedSchemaNodeContent, ParseError> {
674 let node_id = ctx.node_id();
675 match variant.as_deref() {
676 Some("text") => Ok(ParsedSchemaNodeContent::Text(ctx.parse()?)),
677 Some("integer") => Ok(ParsedSchemaNodeContent::Integer(ctx.parse()?)),
678 Some("float") => Ok(ParsedSchemaNodeContent::Float(ctx.parse()?)),
679 Some("boolean") => Ok(ParsedSchemaNodeContent::Boolean),
680 Some("null") => Ok(ParsedSchemaNodeContent::Null),
681 Some("any") => Ok(ParsedSchemaNodeContent::Any),
682 Some("array") => Ok(ParsedSchemaNodeContent::Array(ctx.parse()?)),
683 Some("map") => Ok(ParsedSchemaNodeContent::Map(ctx.parse()?)),
684 Some("tuple") => Ok(ParsedSchemaNodeContent::Tuple(ctx.parse()?)),
685 Some("union") => Ok(ParsedSchemaNodeContent::Union(ctx.parse()?)),
686 Some("literal") => Ok(ParsedSchemaNodeContent::Literal(node_id)),
687 Some("record") | None => Ok(ParsedSchemaNodeContent::Record(ctx.parse()?)),
688 Some(other) => Err(ParseError {
689 node_id,
690 kind: ParseErrorKind::UnknownVariant(other.to_string()),
691 }),
692 }
693}
694
695impl FromEure<'_> for ParsedSchemaNodeContent {
696 type Error = ParseError;
697 fn parse(ctx: &ParseContext<'_>) -> Result<Self, Self::Error> {
698 let node_id = ctx.node_id();
699 let node = ctx.node();
700 let variant = get_variant_string(ctx)?;
701
702 match &node.content {
703 NodeValue::Hole(_) => Err(ParseError {
704 node_id,
705 kind: ParseErrorKind::UnexpectedHole,
706 }),
707
708 NodeValue::Primitive(prim) => {
709 if variant.as_deref() == Some("literal") {
711 return Ok(ParsedSchemaNodeContent::Literal(node_id));
712 }
713 parse_primitive_as_schema(ctx, prim)
714 }
715
716 NodeValue::Array(arr) => {
717 if arr.len() == 1 {
719 Ok(ParsedSchemaNodeContent::Array(ParsedArraySchema {
720 item: arr.get(0).unwrap(),
721 min_length: None,
722 max_length: None,
723 unique: false,
724 contains: None,
725 binding_style: None,
726 }))
727 } else {
728 Err(ParseError {
729 node_id,
730 kind: ParseErrorKind::InvalidPattern {
731 kind: "array schema shorthand".to_string(),
732 reason: format!(
733 "expected single-element array [type], got {}-element array",
734 arr.len()
735 ),
736 },
737 })
738 }
739 }
740
741 NodeValue::Tuple(tup) => {
742 Ok(ParsedSchemaNodeContent::Tuple(ParsedTupleSchema {
744 elements: tup.to_vec(),
745 binding_style: None,
746 }))
747 }
748
749 NodeValue::Map(_) => parse_map_as_schema(ctx, variant),
750 NodeValue::PartialMap(_) => Err(ParseError {
751 node_id,
752 kind: ParseErrorKind::TypeMismatch {
753 expected: ValueKind::Map,
754 actual: ValueKind::PartialMap,
755 },
756 }),
757 }
758 }
759}
760
761impl FromEure<'_> for ParsedSchemaNode {
762 type Error = ParseError;
763 fn parse(ctx: &ParseContext<'_>) -> Result<Self, Self::Error> {
764 let flatten_ctx = ctx.flatten();
767
768 let ext_types = parse_ext_types(&flatten_ctx)?;
770 let metadata = ParsedSchemaMetadata::parse_from_extensions(&flatten_ctx)?;
771 let codegen = flatten_ctx.ext_optional("codegen").map(|ctx| ctx.node_id());
772
773 let content = flatten_ctx.parse::<ParsedSchemaNodeContent>()?;
775
776 Ok(ParsedSchemaNode {
782 content,
783 metadata,
784 ext_types,
785 codegen,
786 })
787 }
788}
789
790fn parse_ext_types(
792 ctx: &ParseContext<'_>,
793) -> Result<IndexMap<Identifier, ParsedExtTypeSchema>, ParseError> {
794 let ext_type_ctx = ctx.ext_optional("ext-type");
795
796 let mut result = IndexMap::new();
797
798 if let Some(ext_type_ctx) = ext_type_ctx {
799 let rec = ext_type_ctx.parse_record()?;
800 let ext_fields: Vec<_> = rec
802 .unknown_fields()
803 .map(|r| {
804 r.map_err(|(key, ctx)| ParseError {
805 node_id: ctx.node_id(),
806 kind: ParseErrorKind::InvalidKeyType(key.clone()),
807 })
808 })
809 .collect::<Result<Vec<_>, _>>()?;
810
811 for (name, type_ctx) in ext_fields {
812 let ident: Identifier = name.parse().map_err(|e| ParseError {
813 node_id: ext_type_ctx.node_id(),
814 kind: ParseErrorKind::InvalidIdentifier(e),
815 })?;
816 let schema = type_ctx.parse::<ParsedExtTypeSchema>()?;
817 result.insert(ident, schema);
818 }
819
820 rec.allow_unknown_fields()?;
823 }
824
825 Ok(result)
826}
827
828#[cfg(test)]
829mod tests {
830 use super::*;
831 use crate::interop::VariantRepr;
832 use eure_document::document::EureDocument;
833 use eure_document::document::node::NodeValue;
834 use eure_document::text::Text;
835 use eure_document::value::PrimitiveValue;
836
837 fn create_text_node(doc: &mut EureDocument, text: &str) -> NodeId {
838 let root_id = doc.get_root_id();
839 doc.node_mut(root_id).content =
840 NodeValue::Primitive(PrimitiveValue::Text(Text::plaintext(text.to_string())));
841 root_id
842 }
843
844 #[test]
845 fn test_binding_style_parse() {
846 let mut doc = EureDocument::new();
847 let node_id = create_text_node(&mut doc, "section");
848
849 let result: BindingStyle = doc.parse(node_id).unwrap();
850 assert_eq!(result, BindingStyle::Section);
851 }
852
853 #[test]
854 fn test_binding_style_parse_unknown() {
855 let mut doc = EureDocument::new();
856 let node_id = create_text_node(&mut doc, "unknown");
857
858 let result: Result<BindingStyle, _> = doc.parse(node_id);
859 let err = result.unwrap_err();
860 assert_eq!(
861 err.kind,
862 ParseErrorKind::UnknownVariant("unknown".to_string())
863 );
864 }
865
866 #[test]
867 fn test_description_parse_default() {
868 let mut doc = EureDocument::new();
869 let node_id = create_text_node(&mut doc, "Hello world");
870
871 let result: Description = doc.parse(node_id).unwrap();
872 assert!(matches!(result, Description::String(s) if s == "Hello world"));
873 }
874
875 #[test]
876 fn test_variant_repr_parse_string() {
877 let mut doc = EureDocument::new();
878 let node_id = create_text_node(&mut doc, "untagged");
879
880 let result: VariantRepr = doc.parse(node_id).unwrap();
881 assert_eq!(result, VariantRepr::Untagged);
882 }
883}