Skip to main content

apache_avro/
types.rs

1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements.  See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership.  The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License.  You may obtain a copy of the License at
8//
9//   http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied.  See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18//! Logic handling the intermediate representation of Avro values.
19use crate::schema::{InnerDecimalSchema, NamespaceRef, UuidSchema};
20use crate::{
21    AvroResult, Error,
22    bigdecimal::{deserialize_big_decimal, serialize_big_decimal},
23    decimal::Decimal,
24    duration::Duration,
25    error::Details,
26    schema::{
27        DecimalSchema, EnumSchema, FixedSchema, Name, Precision, RecordField, RecordSchema,
28        ResolvedSchema, Scale, Schema, SchemaKind, UnionSchema,
29    },
30};
31use bigdecimal::BigDecimal;
32use log::{debug, error};
33use serde_json::{Number, Value as JsonValue};
34use std::{
35    borrow::Borrow,
36    collections::{BTreeMap, HashMap},
37    fmt::Debug,
38    hash::BuildHasher,
39    str::FromStr,
40};
41use uuid::Uuid;
42
43/// Compute the maximum decimal value precision of a byte array of length `len` could hold.
44fn max_prec_for_len(len: usize) -> Result<usize, Error> {
45    let len = i32::try_from(len).map_err(|e| Details::ConvertLengthToI32(e, len))?;
46    Ok((2.0_f64.powi(8 * len - 1) - 1.0).log10().floor() as usize)
47}
48
49/// A valid Avro value.
50///
51/// More information about Avro values can be found in the [Avro
52/// Specification](https://avro.apache.org/docs/++version++/specification/#schema-declaration)
53#[derive(Clone, Debug, PartialEq, strum::EnumDiscriminants)]
54#[strum_discriminants(name(ValueKind))]
55pub enum Value {
56    /// A `null` Avro value.
57    Null,
58    /// A `boolean` Avro value.
59    Boolean(bool),
60    /// A `int` Avro value.
61    Int(i32),
62    /// A `long` Avro value.
63    Long(i64),
64    /// A `float` Avro value.
65    Float(f32),
66    /// A `double` Avro value.
67    Double(f64),
68    /// A `bytes` Avro value.
69    Bytes(Vec<u8>),
70    /// A `string` Avro value.
71    String(String),
72    /// A `fixed` Avro value.
73    /// The size of the fixed value is represented as a `usize`.
74    Fixed(usize, Vec<u8>),
75    /// An `enum` Avro value.
76    ///
77    /// An Enum is represented by a symbol and its position in the symbols list
78    /// of its corresponding schema.
79    /// This allows schema-less encoding, as well as schema resolution while
80    /// reading values.
81    Enum(u32, String),
82    /// An `union` Avro value.
83    ///
84    /// A Union is represented by the value it holds and its position in the type list
85    /// of its corresponding schema
86    /// This allows schema-less encoding, as well as schema resolution while
87    /// reading values.
88    Union(u32, Box<Value>),
89    /// An `array` Avro value.
90    Array(Vec<Value>),
91    /// A `map` Avro value.
92    Map(HashMap<String, Value>),
93    /// A `record` Avro value.
94    ///
95    /// A Record is represented by a vector of (`<record name>`, `value`).
96    /// This allows schema-less encoding.
97    ///
98    /// See [Record](types.Record) for a more user-friendly support.
99    Record(Vec<(String, Value)>),
100    /// A date value.
101    ///
102    /// Serialized and deserialized as `i32` directly. Can only be deserialized properly with a
103    /// schema.
104    Date(i32),
105    /// An Avro Decimal value. Bytes are in big-endian order, per the Avro spec.
106    Decimal(Decimal),
107    /// An Avro Decimal value.
108    BigDecimal(BigDecimal),
109    /// Time in milliseconds.
110    TimeMillis(i32),
111    /// Time in microseconds.
112    TimeMicros(i64),
113    /// Timestamp in milliseconds.
114    TimestampMillis(i64),
115    /// Timestamp in microseconds.
116    TimestampMicros(i64),
117    /// Timestamp in nanoseconds.
118    TimestampNanos(i64),
119    /// Local timestamp in milliseconds.
120    LocalTimestampMillis(i64),
121    /// Local timestamp in microseconds.
122    LocalTimestampMicros(i64),
123    /// Local timestamp in nanoseconds.
124    LocalTimestampNanos(i64),
125    /// Avro Duration. An amount of time defined by months, days and milliseconds.
126    Duration(Duration),
127    /// Universally unique identifier.
128    Uuid(Uuid),
129}
130
131macro_rules! to_value(
132    ($type:ty, $variant_constructor:expr) => (
133        impl From<$type> for Value {
134            fn from(value: $type) -> Self {
135                $variant_constructor(value)
136            }
137        }
138    );
139);
140
141to_value!(bool, Value::Boolean);
142to_value!(i32, Value::Int);
143to_value!(i64, Value::Long);
144to_value!(f32, Value::Float);
145to_value!(f64, Value::Double);
146to_value!(String, Value::String);
147to_value!(Vec<u8>, Value::Bytes);
148to_value!(Uuid, Value::Uuid);
149to_value!(Decimal, Value::Decimal);
150to_value!(BigDecimal, Value::BigDecimal);
151to_value!(Duration, Value::Duration);
152
153impl From<()> for Value {
154    fn from(_: ()) -> Self {
155        Self::Null
156    }
157}
158
159impl TryFrom<usize> for Value {
160    type Error = Error;
161
162    fn try_from(value: usize) -> Result<Self, Self::Error> {
163        Ok(i64::try_from(value)
164            .map_err(|e| Details::ConvertUsizeToI64(e, value))?
165            .into())
166    }
167}
168
169impl From<&str> for Value {
170    fn from(value: &str) -> Self {
171        Self::String(value.to_owned())
172    }
173}
174
175impl From<&[u8]> for Value {
176    fn from(value: &[u8]) -> Self {
177        Self::Bytes(value.to_owned())
178    }
179}
180
181impl<T> From<Option<T>> for Value
182where
183    T: Into<Self>,
184{
185    fn from(value: Option<T>) -> Self {
186        // FIXME: this is incorrect in case first type in union is not "none"
187        Self::Union(
188            value.is_some() as u32,
189            Box::new(value.map_or_else(|| Self::Null, Into::into)),
190        )
191    }
192}
193
194impl<K, V, S> From<HashMap<K, V, S>> for Value
195where
196    K: Into<String>,
197    V: Into<Self>,
198    S: BuildHasher,
199{
200    fn from(value: HashMap<K, V, S>) -> Self {
201        Self::Map(
202            value
203                .into_iter()
204                .map(|(key, value)| (key.into(), value.into()))
205                .collect(),
206        )
207    }
208}
209
210/// Utility interface to build `Value::Record` objects.
211#[derive(Debug, Clone)]
212pub struct Record<'a> {
213    /// List of fields contained in the record.
214    /// Ordered according to the fields in the schema given to create this
215    /// `Record` object. Any unset field defaults to `Value::Null`.
216    pub fields: Vec<(String, Value)>,
217    schema_lookup: &'a BTreeMap<String, usize>,
218}
219
220impl Record<'_> {
221    /// Create a `Record` given a `Schema`.
222    ///
223    /// If the `Schema` is not a `Schema::Record` variant, `None` will be returned.
224    pub fn new(schema: &Schema) -> Option<Record<'_>> {
225        match *schema {
226            Schema::Record(RecordSchema {
227                fields: ref schema_fields,
228                lookup: ref schema_lookup,
229                ..
230            }) => {
231                let mut fields = Vec::with_capacity(schema_fields.len());
232                for schema_field in schema_fields.iter() {
233                    fields.push((schema_field.name.clone(), Value::Null));
234                }
235
236                Some(Record {
237                    fields,
238                    schema_lookup,
239                })
240            }
241            _ => None,
242        }
243    }
244
245    /// Add a field to the `Record`.
246    ///
247    // TODO: This should return an error at least panic
248    /// **NOTE**: If the field name does not exist in the schema, the value is silently dropped.
249    pub fn put<V>(&mut self, field: &str, value: V)
250    where
251        V: Into<Value>,
252    {
253        if let Some(&position) = self.schema_lookup.get(field) {
254            self.fields[position].1 = value.into();
255        }
256    }
257
258    /// Get the value for a given field name.
259    ///
260    /// Returns `None` if the field is not present in the schema
261    pub fn get(&self, field: &str) -> Option<&Value> {
262        self.schema_lookup
263            .get(field)
264            .map(|&position| &self.fields[position].1)
265    }
266}
267
268impl<'a> From<Record<'a>> for Value {
269    fn from(value: Record<'a>) -> Self {
270        Self::Record(value.fields)
271    }
272}
273
274impl TryFrom<JsonValue> for Value {
275    type Error = Error;
276
277    fn try_from(value: JsonValue) -> Result<Self, Self::Error> {
278        match value {
279            JsonValue::Null => Ok(Self::Null),
280            JsonValue::Bool(b) => Ok(b.into()),
281            JsonValue::Number(ref n) if n.is_i64() => {
282                let n = n.as_i64().unwrap();
283                if n >= i32::MIN as i64 && n <= i32::MAX as i64 {
284                    Ok(Value::Int(n as i32))
285                } else {
286                    Ok(Value::Long(n))
287                }
288            }
289            JsonValue::Number(ref n) if n.is_f64() => Ok(Value::Double(n.as_f64().unwrap())),
290            JsonValue::Number(n) => Err(Details::JsonNumberTooLarge(n).into()),
291            JsonValue::String(s) => Ok(s.into()),
292            JsonValue::Array(items) => {
293                let items = items
294                    .into_iter()
295                    .map(Value::try_from)
296                    .collect::<Result<Vec<_>, _>>()?;
297                Ok(Value::Array(items))
298            }
299            JsonValue::Object(items) => {
300                let items = items
301                    .into_iter()
302                    .map(|(key, value)| Value::try_from(value).map(|v| (key, v)))
303                    .collect::<Result<HashMap<_, _>, _>>()?;
304                Ok(Value::Map(items))
305            }
306        }
307    }
308}
309
310/// Convert Avro values to Json values
311impl TryFrom<Value> for JsonValue {
312    type Error = crate::error::Error;
313    fn try_from(value: Value) -> AvroResult<Self> {
314        match value {
315            Value::Null => Ok(Self::Null),
316            Value::Boolean(b) => Ok(Self::Bool(b)),
317            Value::Int(i) => Ok(Self::Number(i.into())),
318            Value::Long(l) => Ok(Self::Number(l.into())),
319            Value::Float(f) => Number::from_f64(f.into())
320                .map(Self::Number)
321                .ok_or_else(|| Details::ConvertF64ToJson(f.into()).into()),
322            Value::Double(d) => Number::from_f64(d)
323                .map(Self::Number)
324                .ok_or_else(|| Details::ConvertF64ToJson(d).into()),
325            Value::Bytes(bytes) => Ok(Self::Array(bytes.into_iter().map(|b| b.into()).collect())),
326            Value::String(s) => Ok(Self::String(s)),
327            Value::Fixed(_size, items) => {
328                Ok(Self::Array(items.into_iter().map(|v| v.into()).collect()))
329            }
330            Value::Enum(_i, s) => Ok(Self::String(s)),
331            Value::Union(_i, b) => Self::try_from(*b),
332            Value::Array(items) => items
333                .into_iter()
334                .map(Self::try_from)
335                .collect::<Result<Vec<_>, _>>()
336                .map(Self::Array),
337            Value::Map(items) => items
338                .into_iter()
339                .map(|(key, value)| Self::try_from(value).map(|v| (key, v)))
340                .collect::<Result<Vec<_>, _>>()
341                .map(|v| Self::Object(v.into_iter().collect())),
342            Value::Record(items) => items
343                .into_iter()
344                .map(|(key, value)| Self::try_from(value).map(|v| (key, v)))
345                .collect::<Result<Vec<_>, _>>()
346                .map(|v| Self::Object(v.into_iter().collect())),
347            Value::Date(d) => Ok(Self::Number(d.into())),
348            Value::Decimal(ref d) => <Vec<u8>>::try_from(d)
349                .map(|vec| Self::Array(vec.into_iter().map(|v| v.into()).collect())),
350            Value::BigDecimal(ref bg) => {
351                let vec1: Vec<u8> = serialize_big_decimal(bg)?;
352                Ok(Self::Array(vec1.into_iter().map(|b| b.into()).collect()))
353            }
354            Value::TimeMillis(t) => Ok(Self::Number(t.into())),
355            Value::TimeMicros(t) => Ok(Self::Number(t.into())),
356            Value::TimestampMillis(t) => Ok(Self::Number(t.into())),
357            Value::TimestampMicros(t) => Ok(Self::Number(t.into())),
358            Value::TimestampNanos(t) => Ok(Self::Number(t.into())),
359            Value::LocalTimestampMillis(t) => Ok(Self::Number(t.into())),
360            Value::LocalTimestampMicros(t) => Ok(Self::Number(t.into())),
361            Value::LocalTimestampNanos(t) => Ok(Self::Number(t.into())),
362            Value::Duration(d) => Ok(Self::Array(
363                <[u8; 12]>::from(d).iter().map(|&v| v.into()).collect(),
364            )),
365            Value::Uuid(uuid) => Ok(Self::String(uuid.as_hyphenated().to_string())),
366        }
367    }
368}
369
370impl Value {
371    /// Validate the value against the given [`Schema`].
372    ///
373    /// See the [Avro specification](https://avro.apache.org/docs/++version++/specification)
374    /// for the full set of rules of schema validation.
375    ///
376    /// # Panics
377    /// Will panic if the schema contain unresolved references or duplicate named types.
378    pub fn validate(&self, schema: &Schema) -> bool {
379        self.validate_schemata(&[schema])
380    }
381
382    /// Validate the value against the given schemata.
383    ///
384    /// # Panics
385    /// Will panic if the schemata contain unresolved references or duplicate schemas.
386    pub fn validate_schemata(&self, schemata: &[&Schema]) -> bool {
387        let rs = ResolvedSchema::try_from(schemata.to_vec())
388            .expect("Schemata didn't successfully resolve");
389        let schemata_len = schemata.len();
390        schemata.iter().any(
391            |schema| match self.validate_internal(schema, rs.get_names(), None) {
392                Some(reason) => {
393                    let log_message =
394                        format!("Invalid value: {self:?} for schema: {schema:?}. Reason: {reason}");
395                    if schemata_len == 1 {
396                        error!("{log_message}");
397                    } else {
398                        debug!("{log_message}");
399                    };
400                    false
401                }
402                None => true,
403            },
404        )
405    }
406
407    fn accumulate(accumulator: Option<String>, other: Option<String>) -> Option<String> {
408        match (accumulator, other) {
409            (None, None) => None,
410            (None, s @ Some(_)) => s,
411            (s @ Some(_), None) => s,
412            (Some(reason1), Some(reason2)) => Some(format!("{reason1}\n{reason2}")),
413        }
414    }
415
416    /// Validates the value against the provided schema.
417    pub(crate) fn validate_internal<S: Borrow<Schema> + Debug>(
418        &self,
419        schema: &Schema,
420        names: &HashMap<Name, S>,
421        enclosing_namespace: NamespaceRef,
422    ) -> Option<String> {
423        match (self, schema) {
424            (_, Schema::Ref { name }) => {
425                let name = name.fully_qualified_name(enclosing_namespace);
426                names.get(&name).map_or_else(
427                    || {
428                        Some(format!(
429                            "Unresolved schema reference: '{:?}'. Parsed names: {:?}",
430                            name,
431                            names.keys()
432                        ))
433                    },
434                    |s| self.validate_internal(s.borrow(), names, name.namespace()),
435                )
436            }
437            (&Value::Null, &Schema::Null) => None,
438            (&Value::Boolean(_), &Schema::Boolean) => None,
439            (&Value::Int(_), &Schema::Int) => None,
440            (&Value::Int(_), &Schema::Date) => None,
441            (&Value::Int(_), &Schema::TimeMillis) => None,
442            (&Value::Int(_), &Schema::Long) => None,
443            (&Value::Long(_), &Schema::Long) => None,
444            (&Value::Long(_), &Schema::TimeMicros) => None,
445            (&Value::Long(_), &Schema::TimestampMillis) => None,
446            (&Value::Long(_), &Schema::TimestampMicros) => None,
447            (&Value::Long(_), &Schema::LocalTimestampMillis) => None,
448            (&Value::Long(_), &Schema::LocalTimestampMicros) => None,
449            (&Value::TimestampMicros(_), &Schema::TimestampMicros) => None,
450            (&Value::TimestampMillis(_), &Schema::TimestampMillis) => None,
451            (&Value::TimestampNanos(_), &Schema::TimestampNanos) => None,
452            (&Value::LocalTimestampMicros(_), &Schema::LocalTimestampMicros) => None,
453            (&Value::LocalTimestampMillis(_), &Schema::LocalTimestampMillis) => None,
454            (&Value::LocalTimestampNanos(_), &Schema::LocalTimestampNanos) => None,
455            (&Value::TimeMicros(_), &Schema::TimeMicros) => None,
456            (&Value::TimeMillis(_), &Schema::TimeMillis) => None,
457            (&Value::Date(_), &Schema::Date) => None,
458            (&Value::Decimal(_), &Schema::Decimal { .. }) => None,
459            (&Value::BigDecimal(_), &Schema::BigDecimal) => None,
460            (&Value::Duration(_), &Schema::Duration(_)) => None,
461            (&Value::Uuid(_), &Schema::Uuid(_)) => None,
462            (&Value::Float(_), &Schema::Float) => None,
463            (&Value::Float(_), &Schema::Double) => None,
464            (&Value::Double(_), &Schema::Double) => None,
465            (&Value::Bytes(_), &Schema::Bytes) => None,
466            (&Value::Bytes(_), &Schema::Decimal { .. }) => None,
467            (Value::Bytes(bytes), &Schema::Uuid(UuidSchema::Bytes)) => {
468                if bytes.len() != 16 {
469                    Some(format!(
470                        "The value's size ({}) is not the right length for a bytes UUID (16)",
471                        bytes.len()
472                    ))
473                } else {
474                    None
475                }
476            }
477            (&Value::String(_), &Schema::String) => None,
478            (Value::String(string), &Schema::Uuid(UuidSchema::String)) => {
479                // Non-hyphenated is 32 characters, hyphenated is longer
480                if string.len() < 32 {
481                    Some(format!(
482                        "The value's size ({}) is not the right length for a string UUID (>=32)",
483                        string.len()
484                    ))
485                } else {
486                    None
487                }
488            }
489            (&Value::Fixed(n, _), &Schema::Fixed(FixedSchema { size, .. })) => {
490                if n != size {
491                    Some(format!(
492                        "The value's size ({n}) is different than the schema's size ({size})"
493                    ))
494                } else {
495                    None
496                }
497            }
498            (Value::Bytes(b), &Schema::Fixed(FixedSchema { size, .. })) => {
499                if b.len() != size {
500                    Some(format!(
501                        "The bytes' length ({}) is different than the schema's size ({})",
502                        b.len(),
503                        size
504                    ))
505                } else {
506                    None
507                }
508            }
509            (&Value::Fixed(n, _), &Schema::Duration(_)) => {
510                if n != 12 {
511                    Some(format!(
512                        "The value's size ('{n}') must be exactly 12 to be a Duration"
513                    ))
514                } else {
515                    None
516                }
517            }
518            (&Value::Fixed(n, _), Schema::Uuid(UuidSchema::Fixed(size, ..))) => {
519                if size.size != 16 {
520                    Some(format!(
521                        "The schema's size ('{}') must be exactly 16 to be a Uuid",
522                        size.size
523                    ))
524                } else if n != 16 {
525                    Some(format!(
526                        "The value's size ('{n}') must be exactly 16 to be a Uuid"
527                    ))
528                } else {
529                    None
530                }
531            }
532            // TODO: check precision against n
533            (&Value::Fixed(_n, _), &Schema::Decimal { .. }) => None,
534            (Value::String(s), Schema::Enum(EnumSchema { symbols, .. })) => {
535                if !symbols.contains(s) {
536                    Some(format!("'{s}' is not a member of the possible symbols"))
537                } else {
538                    None
539                }
540            }
541            (
542                &Value::Enum(i, ref s),
543                Schema::Enum(EnumSchema {
544                    symbols, default, ..
545                }),
546            ) => symbols
547                .get(i as usize)
548                .map(|ref symbol| {
549                    if symbol != &s {
550                        Some(format!("Symbol '{s}' is not at position '{i}'"))
551                    } else {
552                        None
553                    }
554                })
555                .unwrap_or_else(|| match default {
556                    Some(_) => None,
557                    None => Some(format!("No symbol at position '{i}'")),
558                }),
559            // (&Value::Union(None), &Schema::Union(_)) => None,
560            (&Value::Union(i, ref value), Schema::Union(inner)) => inner
561                .variants()
562                .get(i as usize)
563                .map(|schema| value.validate_internal(schema, names, enclosing_namespace))
564                .unwrap_or_else(|| Some(format!("No schema in the union at position '{i}'"))),
565            (v, Schema::Union(inner)) => {
566                match inner.find_schema_with_known_schemata(v, Some(names), enclosing_namespace) {
567                    Some(_) => None,
568                    None => Some("Could not find matching type in union".to_string()),
569                }
570            }
571            (Value::Array(items), Schema::Array(inner)) => items.iter().fold(None, |acc, item| {
572                Value::accumulate(
573                    acc,
574                    item.validate_internal(&inner.items, names, enclosing_namespace),
575                )
576            }),
577            (Value::Map(items), Schema::Map(inner)) => {
578                items.iter().fold(None, |acc, (_, value)| {
579                    Value::accumulate(
580                        acc,
581                        value.validate_internal(&inner.types, names, enclosing_namespace),
582                    )
583                })
584            }
585            (
586                Value::Record(record_fields),
587                Schema::Record(RecordSchema {
588                    fields,
589                    lookup,
590                    name,
591                    ..
592                }),
593            ) => {
594                let non_nullable_fields_count =
595                    fields.iter().filter(|&rf| !rf.is_nullable()).count();
596
597                // If the record contains fewer fields as required fields by the schema, it is invalid.
598                if record_fields.len() < non_nullable_fields_count {
599                    return Some(format!(
600                        "The value's records length ({}) doesn't match the schema ({} non-nullable fields)",
601                        record_fields.len(),
602                        non_nullable_fields_count
603                    ));
604                } else if record_fields.len() > fields.len() {
605                    return Some(format!(
606                        "The value's records length ({}) is greater than the schema's ({} fields)",
607                        record_fields.len(),
608                        fields.len(),
609                    ));
610                }
611
612                record_fields
613                    .iter()
614                    .fold(None, |acc, (field_name, record_field)| {
615                        let record_namespace = name.namespace().or(enclosing_namespace);
616                        match lookup.get(field_name) {
617                            Some(idx) => {
618                                let field = &fields[*idx];
619                                Value::accumulate(
620                                    acc,
621                                    record_field.validate_internal(
622                                        &field.schema,
623                                        names,
624                                        record_namespace,
625                                    ),
626                                )
627                            }
628                            None => Value::accumulate(
629                                acc,
630                                Some(format!("There is no schema field for field '{field_name}'")),
631                            ),
632                        }
633                    })
634            }
635            (Value::Map(items), Schema::Record(RecordSchema { fields, .. })) => {
636                fields.iter().fold(None, |acc, field| {
637                    if let Some(item) = items.get(&field.name) {
638                        let res = item.validate_internal(&field.schema, names, enclosing_namespace);
639                        Value::accumulate(acc, res)
640                    } else if !field.is_nullable() {
641                        Value::accumulate(
642                            acc,
643                            Some(format!(
644                                "Field with name '{:?}' is not a member of the map items",
645                                field.name
646                            )),
647                        )
648                    } else {
649                        acc
650                    }
651                })
652            }
653            (v, s) => Some(format!(
654                "Unsupported value-schema combination! Value: {v:?}, schema: {s:?}"
655            )),
656        }
657    }
658
659    /// Attempt to perform schema resolution on the value, with the given
660    /// [Schema](../schema/enum.Schema.html).
661    ///
662    /// See [Schema Resolution](https://avro.apache.org/docs/++version++/specification/#schema-resolution)
663    /// in the Avro specification for the full set of rules of schema
664    /// resolution.
665    pub fn resolve(self, schema: &Schema) -> AvroResult<Self> {
666        self.resolve_schemata(schema, Vec::with_capacity(0))
667    }
668
669    /// Attempt to perform schema resolution on the value, with the given
670    /// [Schema](../schema/enum.Schema.html) and set of schemas to use for Refs resolution.
671    ///
672    /// See [Schema Resolution](https://avro.apache.org/docs/++version++/specification/#schema-resolution)
673    /// in the Avro specification for the full set of rules of schema
674    /// resolution.
675    pub fn resolve_schemata(self, schema: &Schema, schemata: Vec<&Schema>) -> AvroResult<Self> {
676        let enclosing_namespace = schema.namespace();
677        let rs = if schemata.is_empty() {
678            ResolvedSchema::try_from(schema)?
679        } else {
680            ResolvedSchema::try_from(schemata)?
681        };
682        self.resolve_internal(schema, rs.get_names(), enclosing_namespace, &None)
683    }
684
685    pub(crate) fn resolve_internal<S: Borrow<Schema> + Debug>(
686        mut self,
687        schema: &Schema,
688        names: &HashMap<Name, S>,
689        enclosing_namespace: NamespaceRef,
690        field_default: &Option<JsonValue>,
691    ) -> AvroResult<Self> {
692        // Check if this schema is a union, and if the reader schema is not.
693        if SchemaKind::from(&self) == SchemaKind::Union
694            && SchemaKind::from(schema) != SchemaKind::Union
695        {
696            // Pull out the Union, and attempt to resolve against it.
697            let v = match self {
698                Value::Union(_i, b) => *b,
699                _ => unreachable!(),
700            };
701            self = v;
702        }
703        match schema {
704            Schema::Ref { name } => {
705                let name = name.fully_qualified_name(enclosing_namespace);
706
707                if let Some(resolved) = names.get(&name) {
708                    debug!("Resolved {name:?}");
709                    self.resolve_internal(resolved.borrow(), names, name.namespace(), field_default)
710                } else {
711                    error!("Failed to resolve schema {name:?}");
712                    Err(Details::SchemaResolutionError(name.into_owned()).into())
713                }
714            }
715            Schema::Null => self.resolve_null(),
716            Schema::Boolean => self.resolve_boolean(),
717            Schema::Int => self.resolve_int(),
718            Schema::Long => self.resolve_long(),
719            Schema::Float => self.resolve_float(),
720            Schema::Double => self.resolve_double(),
721            Schema::Bytes => self.resolve_bytes(),
722            Schema::String => self.resolve_string(),
723            Schema::Fixed(FixedSchema { size, .. }) => self.resolve_fixed(*size),
724            Schema::Union(inner) => {
725                self.resolve_union(inner, names, enclosing_namespace, field_default)
726            }
727            Schema::Enum(EnumSchema {
728                symbols, default, ..
729            }) => self.resolve_enum(symbols, default, field_default),
730            Schema::Array(inner) => self.resolve_array(&inner.items, names, enclosing_namespace),
731            Schema::Map(inner) => self.resolve_map(&inner.types, names, enclosing_namespace),
732            Schema::Record(RecordSchema { fields, .. }) => {
733                self.resolve_record(fields, names, enclosing_namespace)
734            }
735            Schema::Decimal(DecimalSchema {
736                scale,
737                precision,
738                inner,
739            }) => self.resolve_decimal(*precision, *scale, inner),
740            Schema::BigDecimal => self.resolve_bigdecimal(),
741            Schema::Date => self.resolve_date(),
742            Schema::TimeMillis => self.resolve_time_millis(),
743            Schema::TimeMicros => self.resolve_time_micros(),
744            Schema::TimestampMillis => self.resolve_timestamp_millis(),
745            Schema::TimestampMicros => self.resolve_timestamp_micros(),
746            Schema::TimestampNanos => self.resolve_timestamp_nanos(),
747            Schema::LocalTimestampMillis => self.resolve_local_timestamp_millis(),
748            Schema::LocalTimestampMicros => self.resolve_local_timestamp_micros(),
749            Schema::LocalTimestampNanos => self.resolve_local_timestamp_nanos(),
750            Schema::Duration(_) => self.resolve_duration(),
751            Schema::Uuid(inner) => self.resolve_uuid(inner),
752        }
753    }
754
755    fn resolve_uuid(self, inner: &UuidSchema) -> Result<Self, Error> {
756        let value = match (self, inner) {
757            (uuid @ Value::Uuid(_), _) => uuid,
758            (Value::String(ref string), UuidSchema::String) => {
759                Value::Uuid(Uuid::from_str(string).map_err(Details::ConvertStrToUuid)?)
760            }
761            (Value::Bytes(ref bytes), UuidSchema::Bytes) => {
762                Value::Uuid(Uuid::from_slice(bytes).map_err(Details::ConvertSliceToUuid)?)
763            }
764            (Value::Fixed(n, ref bytes), UuidSchema::Fixed(_)) => {
765                if n != 16 {
766                    return Err(Details::ConvertFixedToUuid(n).into());
767                }
768                Value::Uuid(Uuid::from_slice(bytes).map_err(Details::ConvertSliceToUuid)?)
769            }
770            (Value::String(ref string), UuidSchema::Fixed(_)) => {
771                let bytes = string.as_bytes();
772                if bytes.len() != 16 {
773                    return Err(Details::ConvertFixedToUuid(bytes.len()).into());
774                }
775                Value::Uuid(Uuid::from_slice(bytes).map_err(Details::ConvertSliceToUuid)?)
776            }
777            (other, _) => return Err(Details::GetUuid(other).into()),
778        };
779        Ok(value)
780    }
781
782    fn resolve_bigdecimal(self) -> Result<Self, Error> {
783        Ok(match self {
784            bg @ Value::BigDecimal(_) => bg,
785            Value::Bytes(b) => Value::BigDecimal(deserialize_big_decimal(&b)?),
786            other => return Err(Details::GetBigDecimal(other).into()),
787        })
788    }
789
790    fn resolve_duration(self) -> Result<Self, Error> {
791        Ok(match self {
792            duration @ Value::Duration { .. } => duration,
793            Value::Fixed(size, bytes) => {
794                if size != 12 {
795                    return Err(Details::GetDurationFixedBytes(size).into());
796                }
797                Value::Duration(Duration::from([
798                    bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7],
799                    bytes[8], bytes[9], bytes[10], bytes[11],
800                ]))
801            }
802            other => return Err(Details::ResolveDuration(other).into()),
803        })
804    }
805
806    fn resolve_decimal(
807        self,
808        precision: Precision,
809        scale: Scale,
810        inner: &InnerDecimalSchema,
811    ) -> Result<Self, Error> {
812        if scale > precision {
813            return Err(Details::GetScaleAndPrecision { scale, precision }.into());
814        }
815        match inner {
816            &InnerDecimalSchema::Fixed(FixedSchema { size, .. }) => {
817                if max_prec_for_len(size)? < precision {
818                    return Err(Details::GetScaleWithFixedSize { size, precision }.into());
819                }
820            }
821            InnerDecimalSchema::Bytes => (),
822        };
823        match self {
824            Value::Decimal(num) => {
825                let num_bytes = num.len();
826                if max_prec_for_len(num_bytes)? < precision {
827                    Err(Details::ComparePrecisionAndSize {
828                        precision,
829                        num_bytes,
830                    }
831                    .into())
832                } else {
833                    Ok(Value::Decimal(num))
834                }
835                // check num.bits() here
836            }
837            Value::Fixed(_, bytes) | Value::Bytes(bytes) => {
838                if max_prec_for_len(bytes.len())? < precision {
839                    Err(Details::ComparePrecisionAndSize {
840                        precision,
841                        num_bytes: bytes.len(),
842                    }
843                    .into())
844                } else {
845                    // precision and scale match, can we assume the underlying type can hold the data?
846                    Ok(Value::Decimal(Decimal::from(bytes)))
847                }
848            }
849            other => Err(Details::ResolveDecimal(other).into()),
850        }
851    }
852
853    fn resolve_date(self) -> Result<Self, Error> {
854        match self {
855            Value::Date(d) | Value::Int(d) => Ok(Value::Date(d)),
856            other => Err(Details::GetDate(other).into()),
857        }
858    }
859
860    fn resolve_time_millis(self) -> Result<Self, Error> {
861        match self {
862            Value::TimeMillis(t) | Value::Int(t) => Ok(Value::TimeMillis(t)),
863            other => Err(Details::GetTimeMillis(other).into()),
864        }
865    }
866
867    fn resolve_time_micros(self) -> Result<Self, Error> {
868        match self {
869            Value::TimeMicros(t) | Value::Long(t) => Ok(Value::TimeMicros(t)),
870            Value::Int(t) => Ok(Value::TimeMicros(i64::from(t))),
871            other => Err(Details::GetTimeMicros(other).into()),
872        }
873    }
874
875    fn resolve_timestamp_millis(self) -> Result<Self, Error> {
876        match self {
877            Value::TimestampMillis(ts) | Value::Long(ts) => Ok(Value::TimestampMillis(ts)),
878            Value::Int(ts) => Ok(Value::TimestampMillis(i64::from(ts))),
879            other => Err(Details::GetTimestampMillis(other).into()),
880        }
881    }
882
883    fn resolve_timestamp_micros(self) -> Result<Self, Error> {
884        match self {
885            Value::TimestampMicros(ts) | Value::Long(ts) => Ok(Value::TimestampMicros(ts)),
886            Value::Int(ts) => Ok(Value::TimestampMicros(i64::from(ts))),
887            other => Err(Details::GetTimestampMicros(other).into()),
888        }
889    }
890
891    fn resolve_timestamp_nanos(self) -> Result<Self, Error> {
892        match self {
893            Value::TimestampNanos(ts) | Value::Long(ts) => Ok(Value::TimestampNanos(ts)),
894            Value::Int(ts) => Ok(Value::TimestampNanos(i64::from(ts))),
895            other => Err(Details::GetTimestampNanos(other).into()),
896        }
897    }
898
899    fn resolve_local_timestamp_millis(self) -> Result<Self, Error> {
900        match self {
901            Value::LocalTimestampMillis(ts) | Value::Long(ts) => {
902                Ok(Value::LocalTimestampMillis(ts))
903            }
904            Value::Int(ts) => Ok(Value::LocalTimestampMillis(i64::from(ts))),
905            other => Err(Details::GetLocalTimestampMillis(other).into()),
906        }
907    }
908
909    fn resolve_local_timestamp_micros(self) -> Result<Self, Error> {
910        match self {
911            Value::LocalTimestampMicros(ts) | Value::Long(ts) => {
912                Ok(Value::LocalTimestampMicros(ts))
913            }
914            Value::Int(ts) => Ok(Value::LocalTimestampMicros(i64::from(ts))),
915            other => Err(Details::GetLocalTimestampMicros(other).into()),
916        }
917    }
918
919    fn resolve_local_timestamp_nanos(self) -> Result<Self, Error> {
920        match self {
921            Value::LocalTimestampNanos(ts) | Value::Long(ts) => Ok(Value::LocalTimestampNanos(ts)),
922            Value::Int(ts) => Ok(Value::LocalTimestampNanos(i64::from(ts))),
923            other => Err(Details::GetLocalTimestampNanos(other).into()),
924        }
925    }
926
927    fn resolve_null(self) -> Result<Self, Error> {
928        match self {
929            Value::Null => Ok(Value::Null),
930            other => Err(Details::GetNull(other).into()),
931        }
932    }
933
934    fn resolve_boolean(self) -> Result<Self, Error> {
935        match self {
936            Value::Boolean(b) => Ok(Value::Boolean(b)),
937            other => Err(Details::GetBoolean(other).into()),
938        }
939    }
940
941    fn resolve_int(self) -> Result<Self, Error> {
942        match self {
943            Value::Int(n) => Ok(Value::Int(n)),
944            Value::Long(n) => {
945                let n = i32::try_from(n).map_err(|e| Details::ZagI32(e, n))?;
946                Ok(Value::Int(n))
947            }
948            other => Err(Details::GetInt(other).into()),
949        }
950    }
951
952    fn resolve_long(self) -> Result<Self, Error> {
953        match self {
954            Value::Int(n) => Ok(Value::Long(i64::from(n))),
955            Value::Long(n) => Ok(Value::Long(n)),
956            other => Err(Details::GetLong(other).into()),
957        }
958    }
959
960    fn resolve_float(self) -> Result<Self, Error> {
961        match self {
962            Value::Int(n) => Ok(Value::Float(n as f32)),
963            Value::Long(n) => Ok(Value::Float(n as f32)),
964            Value::Float(x) => Ok(Value::Float(x)),
965            Value::Double(x) => Ok(Value::Float(x as f32)),
966            Value::String(ref x) => match Self::parse_special_float(x) {
967                Some(f) => Ok(Value::Float(f)),
968                None => Err(Details::GetFloat(self).into()),
969            },
970            other => Err(Details::GetFloat(other).into()),
971        }
972    }
973
974    fn resolve_double(self) -> Result<Self, Error> {
975        match self {
976            Value::Int(n) => Ok(Value::Double(f64::from(n))),
977            Value::Long(n) => Ok(Value::Double(n as f64)),
978            Value::Float(x) => Ok(Value::Double(f64::from(x))),
979            Value::Double(x) => Ok(Value::Double(x)),
980            Value::String(ref x) => match Self::parse_special_float(x) {
981                Some(f) => Ok(Value::Double(f64::from(f))),
982                None => Err(Details::GetDouble(self).into()),
983            },
984            other => Err(Details::GetDouble(other).into()),
985        }
986    }
987
988    /// IEEE 754 NaN and infinities are not valid JSON numbers.
989    /// So they are represented in JSON as strings.
990    fn parse_special_float(value: &str) -> Option<f32> {
991        match value {
992            "NaN" => Some(f32::NAN),
993            "INF" | "Infinity" => Some(f32::INFINITY),
994            "-INF" | "-Infinity" => Some(f32::NEG_INFINITY),
995            _ => None,
996        }
997    }
998
999    fn resolve_bytes(self) -> Result<Self, Error> {
1000        match self {
1001            Value::Bytes(bytes) => Ok(Value::Bytes(bytes)),
1002            Value::String(s) => Ok(Value::Bytes(s.into_bytes())),
1003            Value::Array(items) => Ok(Value::Bytes(
1004                items
1005                    .into_iter()
1006                    .map(Value::try_u8)
1007                    .collect::<Result<Vec<_>, _>>()?,
1008            )),
1009            other => Err(Details::GetBytes(other).into()),
1010        }
1011    }
1012
1013    fn resolve_string(self) -> Result<Self, Error> {
1014        match self {
1015            Value::String(s) => Ok(Value::String(s)),
1016            Value::Bytes(bytes) | Value::Fixed(_, bytes) => Ok(Value::String(
1017                String::from_utf8(bytes).map_err(Details::ConvertToUtf8)?,
1018            )),
1019            other => Err(Details::GetString(other).into()),
1020        }
1021    }
1022
1023    fn resolve_fixed(self, size: usize) -> Result<Self, Error> {
1024        match self {
1025            Value::Fixed(n, bytes) => {
1026                if n == size {
1027                    Ok(Value::Fixed(n, bytes))
1028                } else {
1029                    Err(Details::CompareFixedSizes { size, n }.into())
1030                }
1031            }
1032            Value::String(s) => Ok(Value::Fixed(s.len(), s.into_bytes())),
1033            Value::Bytes(s) => {
1034                if s.len() == size {
1035                    Ok(Value::Fixed(size, s))
1036                } else {
1037                    Err(Details::CompareFixedSizes { size, n: s.len() }.into())
1038                }
1039            }
1040            other => Err(Details::GetStringForFixed(other).into()),
1041        }
1042    }
1043
1044    pub(crate) fn resolve_enum(
1045        self,
1046        symbols: &[String],
1047        enum_default: &Option<String>,
1048        _field_default: &Option<JsonValue>,
1049    ) -> Result<Self, Error> {
1050        let validate_symbol = |symbol: String, symbols: &[String]| {
1051            if let Some(index) = symbols.iter().position(|item| item == &symbol) {
1052                Ok(Value::Enum(index as u32, symbol))
1053            } else {
1054                match enum_default {
1055                    Some(default) => {
1056                        if let Some(index) = symbols.iter().position(|item| item == default) {
1057                            Ok(Value::Enum(index as u32, default.clone()))
1058                        } else {
1059                            Err(Details::GetEnumDefault {
1060                                symbol,
1061                                symbols: symbols.into(),
1062                            }
1063                            .into())
1064                        }
1065                    }
1066                    _ => Err(Details::GetEnumDefault {
1067                        symbol,
1068                        symbols: symbols.into(),
1069                    }
1070                    .into()),
1071                }
1072            }
1073        };
1074
1075        match self {
1076            Value::Enum(_raw_index, s) => validate_symbol(s, symbols),
1077            Value::String(s) => validate_symbol(s, symbols),
1078            other => Err(Details::GetEnum(other).into()),
1079        }
1080    }
1081
1082    fn resolve_union<S: Borrow<Schema> + Debug>(
1083        self,
1084        schema: &UnionSchema,
1085        names: &HashMap<Name, S>,
1086        enclosing_namespace: NamespaceRef,
1087        field_default: &Option<JsonValue>,
1088    ) -> Result<Self, Error> {
1089        let v = match self {
1090            // Both are unions case.
1091            Value::Union(_i, v) => *v,
1092            // Reader is a union, but writer is not.
1093            v => v,
1094        };
1095        let (i, inner) = schema
1096            .find_schema_with_known_schemata(&v, Some(names), enclosing_namespace)
1097            .ok_or_else(|| Details::FindUnionVariant {
1098                schema: schema.clone(),
1099                value: v.clone(),
1100            })?;
1101
1102        Ok(Value::Union(
1103            i as u32,
1104            Box::new(v.resolve_internal(inner, names, enclosing_namespace, field_default)?),
1105        ))
1106    }
1107
1108    fn resolve_array<S: Borrow<Schema> + Debug>(
1109        self,
1110        schema: &Schema,
1111        names: &HashMap<Name, S>,
1112        enclosing_namespace: NamespaceRef,
1113    ) -> Result<Self, Error> {
1114        match self {
1115            Value::Array(items) => Ok(Value::Array(
1116                items
1117                    .into_iter()
1118                    .map(|item| item.resolve_internal(schema, names, enclosing_namespace, &None))
1119                    .collect::<Result<_, _>>()?,
1120            )),
1121            other => Err(Details::GetArray {
1122                expected: schema.into(),
1123                other,
1124            }
1125            .into()),
1126        }
1127    }
1128
1129    fn resolve_map<S: Borrow<Schema> + Debug>(
1130        self,
1131        schema: &Schema,
1132        names: &HashMap<Name, S>,
1133        enclosing_namespace: NamespaceRef,
1134    ) -> Result<Self, Error> {
1135        match self {
1136            Value::Map(items) => Ok(Value::Map(
1137                items
1138                    .into_iter()
1139                    .map(|(key, value)| {
1140                        value
1141                            .resolve_internal(schema, names, enclosing_namespace, &None)
1142                            .map(|value| (key, value))
1143                    })
1144                    .collect::<Result<_, _>>()?,
1145            )),
1146            other => Err(Details::GetMap {
1147                expected: schema.into(),
1148                other,
1149            }
1150            .into()),
1151        }
1152    }
1153
1154    fn resolve_record<S: Borrow<Schema> + Debug>(
1155        self,
1156        fields: &[RecordField],
1157        names: &HashMap<Name, S>,
1158        enclosing_namespace: NamespaceRef,
1159    ) -> Result<Self, Error> {
1160        let mut items = match self {
1161            Value::Map(items) => Ok(items),
1162            Value::Record(fields) => Ok(fields.into_iter().collect::<HashMap<_, _>>()),
1163            other => Err(Error::new(Details::GetRecord {
1164                expected: fields
1165                    .iter()
1166                    .map(|field| (field.name.clone(), field.schema.clone().into()))
1167                    .collect(),
1168                other,
1169            })),
1170        }?;
1171
1172        let new_fields = fields
1173            .iter()
1174            .map(|field| {
1175                let value = match items.remove(&field.name) {
1176                    Some(value) => value,
1177                    None => match field.default {
1178                        Some(ref value) => match field.schema {
1179                            Schema::Enum(EnumSchema {
1180                                ref symbols,
1181                                ref default,
1182                                ..
1183                            }) => Value::try_from(value.clone())?.resolve_enum(
1184                                symbols,
1185                                default,
1186                                &field.default.clone(),
1187                            )?,
1188                            Schema::Union(ref union_schema) => {
1189                                let first = &union_schema.variants()[0];
1190                                // NOTE: this match exists only to optimize null defaults for large
1191                                // backward-compatible schemas with many nullable fields
1192                                match first {
1193                                    Schema::Null => Value::Union(0, Box::new(Value::Null)),
1194                                    _ => Value::Union(
1195                                        0,
1196                                        Box::new(
1197                                            Value::try_from(value.clone())?.resolve_internal(
1198                                                first,
1199                                                names,
1200                                                enclosing_namespace,
1201                                                &field.default,
1202                                            )?,
1203                                        ),
1204                                    ),
1205                                }
1206                            }
1207                            _ => Value::try_from(value.clone())?,
1208                        },
1209                        None => {
1210                            return Err(Details::GetField(field.name.clone()).into());
1211                        }
1212                    },
1213                };
1214                value
1215                    .resolve_internal(&field.schema, names, enclosing_namespace, &field.default)
1216                    .map(|value| (field.name.clone(), value))
1217            })
1218            .collect::<Result<Vec<_>, _>>()?;
1219
1220        Ok(Value::Record(new_fields))
1221    }
1222
1223    fn try_u8(self) -> AvroResult<u8> {
1224        let int = self.resolve(&Schema::Int)?;
1225        if let Value::Int(n) = int
1226            && n >= 0
1227            && n <= i32::from(u8::MAX)
1228        {
1229            return Ok(n as u8);
1230        }
1231
1232        Err(Details::GetU8(int).into())
1233    }
1234}
1235
1236#[cfg(test)]
1237mod tests {
1238    use super::*;
1239    use crate::{
1240        duration::{Days, Millis, Months},
1241        error::Details,
1242        to_value,
1243    };
1244    use apache_avro_test_helper::{
1245        TestResult,
1246        logger::{assert_logged, assert_not_logged},
1247    };
1248    use num_bigint::BigInt;
1249    use pretty_assertions::assert_eq;
1250    use serde_json::json;
1251
1252    #[test]
1253    fn avro_3809_validate_nested_records_with_implicit_namespace() -> TestResult {
1254        let schema = Schema::parse_str(
1255            r#"{
1256            "name": "record_name",
1257            "namespace": "space",
1258            "type": "record",
1259            "fields": [
1260              {
1261                "name": "outer_field_1",
1262                "type": {
1263                  "type": "record",
1264                  "name": "middle_record_name",
1265                  "namespace": "middle_namespace",
1266                  "fields": [
1267                    {
1268                      "name": "middle_field_1",
1269                      "type": {
1270                        "type": "record",
1271                        "name": "inner_record_name",
1272                        "fields": [
1273                          { "name": "inner_field_1", "type": "double" }
1274                        ]
1275                      }
1276                    },
1277                    { "name": "middle_field_2", "type": "inner_record_name" }
1278                  ]
1279                }
1280              }
1281            ]
1282          }"#,
1283        )?;
1284        let value = Value::Record(vec![(
1285            "outer_field_1".into(),
1286            Value::Record(vec![
1287                (
1288                    "middle_field_1".into(),
1289                    Value::Record(vec![("inner_field_1".into(), Value::Double(1.2f64))]),
1290                ),
1291                (
1292                    "middle_field_2".into(),
1293                    Value::Record(vec![("inner_field_1".into(), Value::Double(1.6f64))]),
1294                ),
1295            ]),
1296        )]);
1297
1298        assert!(value.validate(&schema));
1299        Ok(())
1300    }
1301
1302    #[test]
1303    fn validate() -> TestResult {
1304        let value_schema_valid = vec![
1305            (Value::Int(42), Schema::Int, true, ""),
1306            (Value::Int(43), Schema::Long, true, ""),
1307            (Value::Float(43.2), Schema::Float, true, ""),
1308            (Value::Float(45.9), Schema::Double, true, ""),
1309            (
1310                Value::Int(42),
1311                Schema::Boolean,
1312                false,
1313                "Invalid value: Int(42) for schema: Boolean. Reason: Unsupported value-schema combination! Value: Int(42), schema: Boolean",
1314            ),
1315            (
1316                Value::Union(0, Box::new(Value::Null)),
1317                Schema::Union(UnionSchema::new(vec![Schema::Null, Schema::Int])?),
1318                true,
1319                "",
1320            ),
1321            (
1322                Value::Union(1, Box::new(Value::Int(42))),
1323                Schema::Union(UnionSchema::new(vec![Schema::Null, Schema::Int])?),
1324                true,
1325                "",
1326            ),
1327            (
1328                Value::Union(0, Box::new(Value::Null)),
1329                Schema::Union(UnionSchema::new(vec![Schema::Double, Schema::Int])?),
1330                false,
1331                "Invalid value: Union(0, Null) for schema: Union(UnionSchema { schemas: [Double, Int] }). Reason: Unsupported value-schema combination! Value: Null, schema: Double",
1332            ),
1333            (
1334                Value::Union(3, Box::new(Value::Int(42))),
1335                Schema::Union(UnionSchema::new(vec![
1336                    Schema::Null,
1337                    Schema::Double,
1338                    Schema::String,
1339                    Schema::Int,
1340                ])?),
1341                true,
1342                "",
1343            ),
1344            (
1345                Value::Union(1, Box::new(Value::Long(42i64))),
1346                Schema::Union(UnionSchema::new(vec![
1347                    Schema::Null,
1348                    Schema::TimestampMillis,
1349                ])?),
1350                true,
1351                "",
1352            ),
1353            (
1354                Value::Union(2, Box::new(Value::Long(1_i64))),
1355                Schema::Union(UnionSchema::new(vec![Schema::Null, Schema::Int])?),
1356                false,
1357                "Invalid value: Union(2, Long(1)) for schema: Union(UnionSchema { schemas: [Null, Int] }). Reason: No schema in the union at position '2'",
1358            ),
1359            (
1360                Value::Array(vec![Value::Long(42i64)]),
1361                Schema::array(Schema::Long).build(),
1362                true,
1363                "",
1364            ),
1365            (
1366                Value::Array(vec![Value::Boolean(true)]),
1367                Schema::array(Schema::Long).build(),
1368                false,
1369                "Invalid value: Array([Boolean(true)]) for schema: Array(ArraySchema { items: Long, .. }). Reason: Unsupported value-schema combination! Value: Boolean(true), schema: Long",
1370            ),
1371            (
1372                Value::Record(vec![]),
1373                Schema::Null,
1374                false,
1375                "Invalid value: Record([]) for schema: Null. Reason: Unsupported value-schema combination! Value: Record([]), schema: Null",
1376            ),
1377            (
1378                Value::Fixed(12, vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]),
1379                Schema::Duration(FixedSchema {
1380                    name: Name::try_from("TestName")?,
1381                    aliases: None,
1382                    doc: None,
1383                    size: 12,
1384                    attributes: BTreeMap::new(),
1385                }),
1386                true,
1387                "",
1388            ),
1389            (
1390                Value::Fixed(11, vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]),
1391                Schema::Duration(FixedSchema {
1392                    name: Name::try_from("TestName")?,
1393                    aliases: None,
1394                    doc: None,
1395                    size: 12,
1396                    attributes: BTreeMap::new(),
1397                }),
1398                false,
1399                r#"Invalid value: Fixed(11, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) for schema: Duration(FixedSchema { name: Name { name: "TestName", .. }, size: 12, .. }). Reason: The value's size ('11') must be exactly 12 to be a Duration"#,
1400            ),
1401            (
1402                Value::Record(vec![("unknown_field_name".to_string(), Value::Null)]),
1403                Schema::Record(RecordSchema {
1404                    name: Name::new("record_name")?,
1405                    aliases: None,
1406                    doc: None,
1407                    fields: vec![
1408                        RecordField::builder()
1409                            .name("field_name".to_string())
1410                            .schema(Schema::Int)
1411                            .build(),
1412                    ],
1413                    lookup: Default::default(),
1414                    attributes: Default::default(),
1415                }),
1416                false,
1417                r#"Invalid value: Record([("unknown_field_name", Null)]) for schema: Record(RecordSchema { name: Name { name: "record_name", .. }, fields: [RecordField { name: "field_name", schema: Int, .. }], .. }). Reason: There is no schema field for field 'unknown_field_name'"#,
1418            ),
1419            (
1420                Value::Record(vec![("field_name".to_string(), Value::Null)]),
1421                Schema::Record(RecordSchema {
1422                    name: Name::new("record_name")?,
1423                    aliases: None,
1424                    doc: None,
1425                    fields: vec![
1426                        RecordField::builder()
1427                            .name("field_name".to_string())
1428                            .schema(Schema::Ref {
1429                                name: Name::new("missing")?,
1430                            })
1431                            .build(),
1432                    ],
1433                    lookup: [("field_name".to_string(), 0)].iter().cloned().collect(),
1434                    attributes: Default::default(),
1435                }),
1436                false,
1437                r#"Invalid value: Record([("field_name", Null)]) for schema: Record(RecordSchema { name: Name { name: "record_name", .. }, fields: [RecordField { name: "field_name", schema: Ref { name: Name { name: "missing", .. } }, .. }], .. }). Reason: Unresolved schema reference: 'Name { name: "missing", .. }'. Parsed names: []"#,
1438            ),
1439        ];
1440
1441        for (value, schema, valid, expected_err_message) in value_schema_valid.into_iter() {
1442            let err_message = value.validate_internal::<Schema>(&schema, &HashMap::default(), None);
1443            assert_eq!(valid, err_message.is_none());
1444            if !valid {
1445                let full_err_message = format!(
1446                    "Invalid value: {:?} for schema: {:?}. Reason: {}",
1447                    value,
1448                    schema,
1449                    err_message.unwrap()
1450                );
1451                assert_eq!(expected_err_message, full_err_message);
1452            }
1453        }
1454
1455        Ok(())
1456    }
1457
1458    #[test]
1459    fn validate_fixed() -> TestResult {
1460        let schema = Schema::Fixed(FixedSchema {
1461            size: 4,
1462            name: Name::new("some_fixed")?,
1463            aliases: None,
1464            doc: None,
1465            attributes: Default::default(),
1466        });
1467
1468        assert!(Value::Fixed(4, vec![0, 0, 0, 0]).validate(&schema));
1469        let value = Value::Fixed(5, vec![0, 0, 0, 0, 0]);
1470        assert!(!value.validate(&schema));
1471        assert_logged(
1472            format!(
1473                "Invalid value: {:?} for schema: {:?}. Reason: {}",
1474                value, schema, "The value's size (5) is different than the schema's size (4)"
1475            )
1476            .as_str(),
1477        );
1478
1479        assert!(Value::Bytes(vec![0, 0, 0, 0]).validate(&schema));
1480        let value = Value::Bytes(vec![0, 0, 0, 0, 0]);
1481        assert!(!value.validate(&schema));
1482        assert_logged(
1483            format!(
1484                "Invalid value: {:?} for schema: {:?}. Reason: {}",
1485                value, schema, "The bytes' length (5) is different than the schema's size (4)"
1486            )
1487            .as_str(),
1488        );
1489
1490        Ok(())
1491    }
1492
1493    #[test]
1494    fn validate_enum() -> TestResult {
1495        let schema = Schema::Enum(EnumSchema {
1496            name: Name::new("some_enum")?,
1497            aliases: None,
1498            doc: None,
1499            symbols: vec![
1500                "spades".to_string(),
1501                "hearts".to_string(),
1502                "diamonds".to_string(),
1503                "clubs".to_string(),
1504            ],
1505            default: None,
1506            attributes: Default::default(),
1507        });
1508
1509        assert!(Value::Enum(0, "spades".to_string()).validate(&schema));
1510        assert!(Value::String("spades".to_string()).validate(&schema));
1511
1512        let value = Value::Enum(1, "spades".to_string());
1513        assert!(!value.validate(&schema));
1514        assert_logged(
1515            format!(
1516                "Invalid value: {:?} for schema: {:?}. Reason: {}",
1517                value, schema, "Symbol 'spades' is not at position '1'"
1518            )
1519            .as_str(),
1520        );
1521
1522        let value = Value::Enum(1000, "spades".to_string());
1523        assert!(!value.validate(&schema));
1524        assert_logged(
1525            format!(
1526                "Invalid value: {:?} for schema: {:?}. Reason: {}",
1527                value, schema, "No symbol at position '1000'"
1528            )
1529            .as_str(),
1530        );
1531
1532        let value = Value::String("lorem".to_string());
1533        assert!(!value.validate(&schema));
1534        assert_logged(
1535            format!(
1536                "Invalid value: {:?} for schema: {:?}. Reason: {}",
1537                value, schema, "'lorem' is not a member of the possible symbols"
1538            )
1539            .as_str(),
1540        );
1541
1542        let other_schema = Schema::Enum(EnumSchema {
1543            name: Name::new("some_other_enum")?,
1544            aliases: None,
1545            doc: None,
1546            symbols: vec![
1547                "hearts".to_string(),
1548                "diamonds".to_string(),
1549                "clubs".to_string(),
1550                "spades".to_string(),
1551            ],
1552            default: None,
1553            attributes: Default::default(),
1554        });
1555
1556        let value = Value::Enum(0, "spades".to_string());
1557        assert!(!value.validate(&other_schema));
1558        assert_logged(
1559            format!(
1560                "Invalid value: {:?} for schema: {:?}. Reason: {}",
1561                value, other_schema, "Symbol 'spades' is not at position '0'"
1562            )
1563            .as_str(),
1564        );
1565
1566        Ok(())
1567    }
1568
1569    #[test]
1570    fn validate_record() -> TestResult {
1571        // {
1572        //    "type": "record",
1573        //    "fields": [
1574        //      {"type": "long", "name": "a"},
1575        //      {"type": "string", "name": "b"},
1576        //      {
1577        //          "type": ["null", "int"]
1578        //          "name": "c",
1579        //          "default": null
1580        //      }
1581        //    ]
1582        // }
1583        let schema = Schema::Record(RecordSchema {
1584            name: Name::new("some_record")?,
1585            aliases: None,
1586            doc: None,
1587            fields: vec![
1588                RecordField::builder()
1589                    .name("a".to_string())
1590                    .schema(Schema::Long)
1591                    .build(),
1592                RecordField::builder()
1593                    .name("b".to_string())
1594                    .schema(Schema::String)
1595                    .build(),
1596                RecordField::builder()
1597                    .name("c".to_string())
1598                    .default(JsonValue::Null)
1599                    .schema(Schema::Union(UnionSchema::new(vec![
1600                        Schema::Null,
1601                        Schema::Int,
1602                    ])?))
1603                    .build(),
1604            ],
1605            lookup: [
1606                ("a".to_string(), 0),
1607                ("b".to_string(), 1),
1608                ("c".to_string(), 2),
1609            ]
1610            .iter()
1611            .cloned()
1612            .collect(),
1613            attributes: Default::default(),
1614        });
1615
1616        assert!(
1617            Value::Record(vec![
1618                ("a".to_string(), Value::Long(42i64)),
1619                ("b".to_string(), Value::String("foo".to_string())),
1620            ])
1621            .validate(&schema)
1622        );
1623
1624        let value = Value::Record(vec![
1625            ("b".to_string(), Value::String("foo".to_string())),
1626            ("a".to_string(), Value::Long(42i64)),
1627        ]);
1628        assert!(value.validate(&schema));
1629
1630        let value = Value::Record(vec![
1631            ("a".to_string(), Value::Boolean(false)),
1632            ("b".to_string(), Value::String("foo".to_string())),
1633        ]);
1634        assert!(!value.validate(&schema));
1635        assert_logged(
1636            r#"Invalid value: Record([("a", Boolean(false)), ("b", String("foo"))]) for schema: Record(RecordSchema { name: Name { name: "some_record", .. }, fields: [RecordField { name: "a", schema: Long, .. }, RecordField { name: "b", schema: String, .. }, RecordField { name: "c", default: Null, schema: Union(UnionSchema { schemas: [Null, Int] }), .. }], .. }). Reason: Unsupported value-schema combination! Value: Boolean(false), schema: Long"#,
1637        );
1638
1639        let value = Value::Record(vec![
1640            ("a".to_string(), Value::Long(42i64)),
1641            ("c".to_string(), Value::String("foo".to_string())),
1642        ]);
1643        assert!(!value.validate(&schema));
1644        assert_logged(
1645            r#"Invalid value: Record([("a", Long(42)), ("c", String("foo"))]) for schema: Record(RecordSchema { name: Name { name: "some_record", .. }, fields: [RecordField { name: "a", schema: Long, .. }, RecordField { name: "b", schema: String, .. }, RecordField { name: "c", default: Null, schema: Union(UnionSchema { schemas: [Null, Int] }), .. }], .. }). Reason: Could not find matching type in union"#,
1646        );
1647        assert_not_logged(
1648            r#"Invalid value: String("foo") for schema: Int. Reason: Unsupported value-schema combination"#,
1649        );
1650
1651        let value = Value::Record(vec![
1652            ("a".to_string(), Value::Long(42i64)),
1653            ("d".to_string(), Value::String("foo".to_string())),
1654        ]);
1655        assert!(!value.validate(&schema));
1656        assert_logged(
1657            r#"Invalid value: Record([("a", Long(42)), ("d", String("foo"))]) for schema: Record(RecordSchema { name: Name { name: "some_record", .. }, fields: [RecordField { name: "a", schema: Long, .. }, RecordField { name: "b", schema: String, .. }, RecordField { name: "c", default: Null, schema: Union(UnionSchema { schemas: [Null, Int] }), .. }], .. }). Reason: There is no schema field for field 'd'"#,
1658        );
1659
1660        let value = Value::Record(vec![
1661            ("a".to_string(), Value::Long(42i64)),
1662            ("b".to_string(), Value::String("foo".to_string())),
1663            ("c".to_string(), Value::Null),
1664            ("d".to_string(), Value::Null),
1665        ]);
1666        assert!(!value.validate(&schema));
1667        assert_logged(
1668            r#"Invalid value: Record([("a", Long(42)), ("b", String("foo")), ("c", Null), ("d", Null)]) for schema: Record(RecordSchema { name: Name { name: "some_record", .. }, fields: [RecordField { name: "a", schema: Long, .. }, RecordField { name: "b", schema: String, .. }, RecordField { name: "c", default: Null, schema: Union(UnionSchema { schemas: [Null, Int] }), .. }], .. }). Reason: The value's records length (4) is greater than the schema's (3 fields)"#,
1669        );
1670
1671        assert!(
1672            Value::Map(
1673                vec![
1674                    ("a".to_string(), Value::Long(42i64)),
1675                    ("b".to_string(), Value::String("foo".to_string())),
1676                ]
1677                .into_iter()
1678                .collect()
1679            )
1680            .validate(&schema)
1681        );
1682
1683        assert!(
1684            !Value::Map(
1685                vec![("d".to_string(), Value::Long(123_i64)),]
1686                    .into_iter()
1687                    .collect()
1688            )
1689            .validate(&schema)
1690        );
1691        assert_logged(
1692            r#"Invalid value: Map({"d": Long(123)}) for schema: Record(RecordSchema { name: Name { name: "some_record", .. }, fields: [RecordField { name: "a", schema: Long, .. }, RecordField { name: "b", schema: String, .. }, RecordField { name: "c", default: Null, schema: Union(UnionSchema { schemas: [Null, Int] }), .. }], .. }). Reason: Field with name '"a"' is not a member of the map items
1693Field with name '"b"' is not a member of the map items"#,
1694        );
1695
1696        let union_schema = Schema::Union(UnionSchema::new(vec![Schema::Null, schema])?);
1697
1698        assert!(
1699            Value::Union(
1700                1,
1701                Box::new(Value::Record(vec![
1702                    ("a".to_string(), Value::Long(42i64)),
1703                    ("b".to_string(), Value::String("foo".to_string())),
1704                ]))
1705            )
1706            .validate(&union_schema)
1707        );
1708
1709        assert!(
1710            Value::Union(
1711                1,
1712                Box::new(Value::Map(
1713                    vec![
1714                        ("a".to_string(), Value::Long(42i64)),
1715                        ("b".to_string(), Value::String("foo".to_string())),
1716                    ]
1717                    .into_iter()
1718                    .collect()
1719                ))
1720            )
1721            .validate(&union_schema)
1722        );
1723
1724        Ok(())
1725    }
1726
1727    #[test]
1728    fn resolve_bytes_ok() -> TestResult {
1729        let value = Value::Array(vec![Value::Int(0), Value::Int(42)]);
1730        assert_eq!(
1731            value.resolve(&Schema::Bytes)?,
1732            Value::Bytes(vec![0u8, 42u8])
1733        );
1734
1735        Ok(())
1736    }
1737
1738    #[test]
1739    fn resolve_string_from_bytes() -> TestResult {
1740        let value = Value::Bytes(vec![97, 98, 99]);
1741        assert_eq!(
1742            value.resolve(&Schema::String)?,
1743            Value::String("abc".to_string())
1744        );
1745
1746        Ok(())
1747    }
1748
1749    #[test]
1750    fn resolve_string_from_fixed() -> TestResult {
1751        let value = Value::Fixed(3, vec![97, 98, 99]);
1752        assert_eq!(
1753            value.resolve(&Schema::String)?,
1754            Value::String("abc".to_string())
1755        );
1756
1757        Ok(())
1758    }
1759
1760    #[test]
1761    fn resolve_bytes_failure() {
1762        let value = Value::Array(vec![Value::Int(2000), Value::Int(-42)]);
1763        assert!(value.resolve(&Schema::Bytes).is_err());
1764    }
1765
1766    #[test]
1767    fn resolve_decimal_bytes() -> TestResult {
1768        let value = Value::Decimal(Decimal::from(vec![1, 2, 3, 4, 5]));
1769        value.clone().resolve(&Schema::Decimal(DecimalSchema {
1770            precision: 10,
1771            scale: 4,
1772            inner: InnerDecimalSchema::Bytes,
1773        }))?;
1774        assert!(value.resolve(&Schema::String).is_err());
1775
1776        Ok(())
1777    }
1778
1779    #[test]
1780    fn resolve_decimal_invalid_scale() {
1781        let value = Value::Decimal(Decimal::from(vec![1, 2]));
1782        assert!(
1783            value
1784                .resolve(&Schema::Decimal(DecimalSchema {
1785                    precision: 2,
1786                    scale: 3,
1787                    inner: InnerDecimalSchema::Bytes,
1788                }))
1789                .is_err()
1790        );
1791    }
1792
1793    #[test]
1794    fn resolve_decimal_invalid_precision_for_length() {
1795        let value = Value::Decimal(Decimal::from((1u8..=8u8).rev().collect::<Vec<_>>()));
1796        assert!(
1797            value
1798                .resolve(&Schema::Decimal(DecimalSchema {
1799                    precision: 1,
1800                    scale: 0,
1801                    inner: InnerDecimalSchema::Bytes,
1802                }))
1803                .is_ok()
1804        );
1805    }
1806
1807    #[test]
1808    fn resolve_decimal_fixed() {
1809        let value = Value::Decimal(Decimal::from(vec![1, 2, 3, 4, 5]));
1810        assert!(
1811            value
1812                .clone()
1813                .resolve(&Schema::Decimal(DecimalSchema {
1814                    precision: 10,
1815                    scale: 1,
1816                    inner: InnerDecimalSchema::Fixed(FixedSchema {
1817                        name: Name::new("decimal").unwrap(),
1818                        aliases: None,
1819                        size: 20,
1820                        doc: None,
1821                        attributes: Default::default(),
1822                    })
1823                }))
1824                .is_ok()
1825        );
1826        assert!(value.resolve(&Schema::String).is_err());
1827    }
1828
1829    #[test]
1830    fn resolve_date() {
1831        let value = Value::Date(2345);
1832        assert!(value.clone().resolve(&Schema::Date).is_ok());
1833        assert!(value.resolve(&Schema::String).is_err());
1834    }
1835
1836    #[test]
1837    fn resolve_time_millis() {
1838        let value = Value::TimeMillis(10);
1839        assert!(value.clone().resolve(&Schema::TimeMillis).is_ok());
1840        assert!(value.resolve(&Schema::TimeMicros).is_err());
1841    }
1842
1843    #[test]
1844    fn resolve_time_micros() {
1845        let value = Value::TimeMicros(10);
1846        assert!(value.clone().resolve(&Schema::TimeMicros).is_ok());
1847        assert!(value.resolve(&Schema::TimeMillis).is_err());
1848    }
1849
1850    #[test]
1851    fn resolve_timestamp_millis() {
1852        let value = Value::TimestampMillis(10);
1853        assert!(value.clone().resolve(&Schema::TimestampMillis).is_ok());
1854        assert!(value.resolve(&Schema::Float).is_err());
1855
1856        let value = Value::Float(10.0f32);
1857        assert!(value.resolve(&Schema::TimestampMillis).is_err());
1858    }
1859
1860    #[test]
1861    fn resolve_timestamp_micros() {
1862        let value = Value::TimestampMicros(10);
1863        assert!(value.clone().resolve(&Schema::TimestampMicros).is_ok());
1864        assert!(value.resolve(&Schema::Int).is_err());
1865
1866        let value = Value::Double(10.0);
1867        assert!(value.resolve(&Schema::TimestampMicros).is_err());
1868    }
1869
1870    #[test]
1871    fn test_avro_3914_resolve_timestamp_nanos() {
1872        let value = Value::TimestampNanos(10);
1873        assert!(value.clone().resolve(&Schema::TimestampNanos).is_ok());
1874        assert!(value.resolve(&Schema::Int).is_err());
1875
1876        let value = Value::Double(10.0);
1877        assert!(value.resolve(&Schema::TimestampNanos).is_err());
1878    }
1879
1880    #[test]
1881    fn test_avro_3853_resolve_timestamp_millis() {
1882        let value = Value::LocalTimestampMillis(10);
1883        assert!(value.clone().resolve(&Schema::LocalTimestampMillis).is_ok());
1884        assert!(value.resolve(&Schema::Float).is_err());
1885
1886        let value = Value::Float(10.0f32);
1887        assert!(value.resolve(&Schema::LocalTimestampMillis).is_err());
1888    }
1889
1890    #[test]
1891    fn test_avro_3853_resolve_timestamp_micros() {
1892        let value = Value::LocalTimestampMicros(10);
1893        assert!(value.clone().resolve(&Schema::LocalTimestampMicros).is_ok());
1894        assert!(value.resolve(&Schema::Int).is_err());
1895
1896        let value = Value::Double(10.0);
1897        assert!(value.resolve(&Schema::LocalTimestampMicros).is_err());
1898    }
1899
1900    #[test]
1901    fn test_avro_3916_resolve_timestamp_nanos() {
1902        let value = Value::LocalTimestampNanos(10);
1903        assert!(value.clone().resolve(&Schema::LocalTimestampNanos).is_ok());
1904        assert!(value.resolve(&Schema::Int).is_err());
1905
1906        let value = Value::Double(10.0);
1907        assert!(value.resolve(&Schema::LocalTimestampNanos).is_err());
1908    }
1909
1910    #[test]
1911    fn resolve_duration() {
1912        let value = Value::Duration(Duration::new(
1913            Months::new(10),
1914            Days::new(5),
1915            Millis::new(3000),
1916        ));
1917        assert!(
1918            value
1919                .clone()
1920                .resolve(&Schema::Duration(FixedSchema {
1921                    name: Name::try_from("TestName").expect("Name is valid"),
1922                    aliases: None,
1923                    doc: None,
1924                    size: 12,
1925                    attributes: BTreeMap::new()
1926                }))
1927                .is_ok()
1928        );
1929        assert!(value.resolve(&Schema::TimestampMicros).is_err());
1930        assert!(
1931            Value::Long(1i64)
1932                .resolve(&Schema::Duration(FixedSchema {
1933                    name: Name::try_from("TestName").expect("Name is valid"),
1934                    aliases: None,
1935                    doc: None,
1936                    size: 12,
1937                    attributes: BTreeMap::new()
1938                }))
1939                .is_err()
1940        );
1941    }
1942
1943    #[test]
1944    fn resolve_uuid() -> TestResult {
1945        let value = Value::Uuid(Uuid::parse_str("1481531d-ccc9-46d9-a56f-5b67459c0537")?);
1946        assert!(
1947            value
1948                .clone()
1949                .resolve(&Schema::Uuid(UuidSchema::String))
1950                .is_ok()
1951        );
1952        assert!(
1953            value
1954                .clone()
1955                .resolve(&Schema::Uuid(UuidSchema::Bytes))
1956                .is_ok()
1957        );
1958        assert!(
1959            value
1960                .clone()
1961                .resolve(&Schema::Uuid(UuidSchema::Fixed(FixedSchema {
1962                    name: Name::new("some_name")?,
1963                    aliases: None,
1964                    doc: None,
1965                    size: 16,
1966                    attributes: Default::default(),
1967                })))
1968                .is_ok()
1969        );
1970        assert!(value.resolve(&Schema::TimestampMicros).is_err());
1971
1972        Ok(())
1973    }
1974
1975    #[test]
1976    fn avro_3678_resolve_float_to_double() {
1977        let value = Value::Float(2345.1);
1978        assert!(value.resolve(&Schema::Double).is_ok());
1979    }
1980
1981    #[test]
1982    fn test_avro_3621_resolve_to_nullable_union() -> TestResult {
1983        let schema = Schema::parse_str(
1984            r#"{
1985            "type": "record",
1986            "name": "root",
1987            "fields": [
1988                {
1989                    "name": "event",
1990                    "type": [
1991                        "null",
1992                        {
1993                            "type": "record",
1994                            "name": "event",
1995                            "fields": [
1996                                {
1997                                    "name": "amount",
1998                                    "type": "int"
1999                                },
2000                                {
2001                                    "name": "size",
2002                                    "type": [
2003                                        "null",
2004                                        "int"
2005                                    ],
2006                                    "default": null
2007                                }
2008                            ]
2009                        }
2010                    ],
2011                    "default": null
2012                }
2013            ]
2014        }"#,
2015        )?;
2016
2017        let value = Value::Record(vec![(
2018            "event".to_string(),
2019            Value::Record(vec![("amount".to_string(), Value::Int(200))]),
2020        )]);
2021        assert!(value.resolve(&schema).is_ok());
2022
2023        let value = Value::Record(vec![(
2024            "event".to_string(),
2025            Value::Record(vec![("size".to_string(), Value::Int(1))]),
2026        )]);
2027        assert!(value.resolve(&schema).is_err());
2028
2029        Ok(())
2030    }
2031
2032    #[test]
2033    fn json_from_avro() -> TestResult {
2034        assert_eq!(JsonValue::try_from(Value::Null)?, JsonValue::Null);
2035        assert_eq!(
2036            JsonValue::try_from(Value::Boolean(true))?,
2037            JsonValue::Bool(true)
2038        );
2039        assert_eq!(
2040            JsonValue::try_from(Value::Int(1))?,
2041            JsonValue::Number(1.into())
2042        );
2043        assert_eq!(
2044            JsonValue::try_from(Value::Long(1))?,
2045            JsonValue::Number(1.into())
2046        );
2047        assert_eq!(
2048            JsonValue::try_from(Value::Float(1.0))?,
2049            JsonValue::Number(Number::from_f64(1.0).unwrap())
2050        );
2051        assert_eq!(
2052            JsonValue::try_from(Value::Double(1.0))?,
2053            JsonValue::Number(Number::from_f64(1.0).unwrap())
2054        );
2055        assert_eq!(
2056            JsonValue::try_from(Value::Bytes(vec![1, 2, 3]))?,
2057            JsonValue::Array(vec![
2058                JsonValue::Number(1.into()),
2059                JsonValue::Number(2.into()),
2060                JsonValue::Number(3.into())
2061            ])
2062        );
2063        assert_eq!(
2064            JsonValue::try_from(Value::String("test".into()))?,
2065            JsonValue::String("test".into())
2066        );
2067        assert_eq!(
2068            JsonValue::try_from(Value::Fixed(3, vec![1, 2, 3]))?,
2069            JsonValue::Array(vec![
2070                JsonValue::Number(1.into()),
2071                JsonValue::Number(2.into()),
2072                JsonValue::Number(3.into())
2073            ])
2074        );
2075        assert_eq!(
2076            JsonValue::try_from(Value::Enum(1, "test_enum".into()))?,
2077            JsonValue::String("test_enum".into())
2078        );
2079        assert_eq!(
2080            JsonValue::try_from(Value::Union(1, Box::new(Value::String("test_enum".into()))))?,
2081            JsonValue::String("test_enum".into())
2082        );
2083        assert_eq!(
2084            JsonValue::try_from(Value::Array(vec![
2085                Value::Int(1),
2086                Value::Int(2),
2087                Value::Int(3)
2088            ]))?,
2089            JsonValue::Array(vec![
2090                JsonValue::Number(1.into()),
2091                JsonValue::Number(2.into()),
2092                JsonValue::Number(3.into())
2093            ])
2094        );
2095        assert_eq!(
2096            JsonValue::try_from(Value::Map(
2097                vec![
2098                    ("v1".to_string(), Value::Int(1)),
2099                    ("v2".to_string(), Value::Int(2)),
2100                    ("v3".to_string(), Value::Int(3))
2101                ]
2102                .into_iter()
2103                .collect()
2104            ))?,
2105            JsonValue::Object(
2106                vec![
2107                    ("v1".to_string(), JsonValue::Number(1.into())),
2108                    ("v2".to_string(), JsonValue::Number(2.into())),
2109                    ("v3".to_string(), JsonValue::Number(3.into()))
2110                ]
2111                .into_iter()
2112                .collect()
2113            )
2114        );
2115        assert_eq!(
2116            JsonValue::try_from(Value::Record(vec![
2117                ("v1".to_string(), Value::Int(1)),
2118                ("v2".to_string(), Value::Int(2)),
2119                ("v3".to_string(), Value::Int(3))
2120            ]))?,
2121            JsonValue::Object(
2122                vec![
2123                    ("v1".to_string(), JsonValue::Number(1.into())),
2124                    ("v2".to_string(), JsonValue::Number(2.into())),
2125                    ("v3".to_string(), JsonValue::Number(3.into()))
2126                ]
2127                .into_iter()
2128                .collect()
2129            )
2130        );
2131        assert_eq!(
2132            JsonValue::try_from(Value::Date(1))?,
2133            JsonValue::Number(1.into())
2134        );
2135        assert_eq!(
2136            JsonValue::try_from(Value::Decimal(vec![1, 2, 3].into()))?,
2137            JsonValue::Array(vec![
2138                JsonValue::Number(1.into()),
2139                JsonValue::Number(2.into()),
2140                JsonValue::Number(3.into())
2141            ])
2142        );
2143        assert_eq!(
2144            JsonValue::try_from(Value::TimeMillis(1))?,
2145            JsonValue::Number(1.into())
2146        );
2147        assert_eq!(
2148            JsonValue::try_from(Value::TimeMicros(1))?,
2149            JsonValue::Number(1.into())
2150        );
2151        assert_eq!(
2152            JsonValue::try_from(Value::TimestampMillis(1))?,
2153            JsonValue::Number(1.into())
2154        );
2155        assert_eq!(
2156            JsonValue::try_from(Value::TimestampMicros(1))?,
2157            JsonValue::Number(1.into())
2158        );
2159        assert_eq!(
2160            JsonValue::try_from(Value::TimestampNanos(1))?,
2161            JsonValue::Number(1.into())
2162        );
2163        assert_eq!(
2164            JsonValue::try_from(Value::LocalTimestampMillis(1))?,
2165            JsonValue::Number(1.into())
2166        );
2167        assert_eq!(
2168            JsonValue::try_from(Value::LocalTimestampMicros(1))?,
2169            JsonValue::Number(1.into())
2170        );
2171        assert_eq!(
2172            JsonValue::try_from(Value::LocalTimestampNanos(1))?,
2173            JsonValue::Number(1.into())
2174        );
2175        assert_eq!(
2176            JsonValue::try_from(Value::Duration(
2177                [
2178                    1u8, 2u8, 3u8, 4u8, 5u8, 6u8, 7u8, 8u8, 9u8, 10u8, 11u8, 12u8
2179                ]
2180                .into()
2181            ))?,
2182            JsonValue::Array(vec![
2183                JsonValue::Number(1.into()),
2184                JsonValue::Number(2.into()),
2185                JsonValue::Number(3.into()),
2186                JsonValue::Number(4.into()),
2187                JsonValue::Number(5.into()),
2188                JsonValue::Number(6.into()),
2189                JsonValue::Number(7.into()),
2190                JsonValue::Number(8.into()),
2191                JsonValue::Number(9.into()),
2192                JsonValue::Number(10.into()),
2193                JsonValue::Number(11.into()),
2194                JsonValue::Number(12.into()),
2195            ])
2196        );
2197        assert_eq!(
2198            JsonValue::try_from(Value::Uuid(Uuid::parse_str(
2199                "936DA01F-9ABD-4D9D-80C7-02AF85C822A8"
2200            )?))?,
2201            JsonValue::String("936da01f-9abd-4d9d-80c7-02af85c822a8".into())
2202        );
2203
2204        Ok(())
2205    }
2206
2207    #[test]
2208    fn test_avro_3433_recursive_resolves_record() -> TestResult {
2209        let schema = Schema::parse_str(
2210            r#"
2211        {
2212            "type":"record",
2213            "name":"TestStruct",
2214            "fields": [
2215                {
2216                    "name":"a",
2217                    "type":{
2218                        "type":"record",
2219                        "name": "Inner",
2220                        "fields": [ {
2221                            "name":"z",
2222                            "type":"int"
2223                        }]
2224                    }
2225                },
2226                {
2227                    "name":"b",
2228                    "type":"Inner"
2229                }
2230            ]
2231        }"#,
2232        )?;
2233
2234        let inner_value1 = Value::Record(vec![("z".into(), Value::Int(3))]);
2235        let inner_value2 = Value::Record(vec![("z".into(), Value::Int(6))]);
2236        let outer = Value::Record(vec![("a".into(), inner_value1), ("b".into(), inner_value2)]);
2237        outer
2238            .resolve(&schema)
2239            .expect("Record definition defined in one field must be available in other field");
2240
2241        Ok(())
2242    }
2243
2244    #[test]
2245    fn test_avro_3433_recursive_resolves_array() -> TestResult {
2246        let schema = Schema::parse_str(
2247            r#"
2248        {
2249            "type":"record",
2250            "name":"TestStruct",
2251            "fields": [
2252                {
2253                    "name":"a",
2254                    "type":{
2255                        "type":"array",
2256                        "items": {
2257                            "type":"record",
2258                            "name": "Inner",
2259                            "fields": [ {
2260                                "name":"z",
2261                                "type":"int"
2262                            }]
2263                        }
2264                    }
2265                },
2266                {
2267                    "name":"b",
2268                    "type": {
2269                        "type":"map",
2270                        "values":"Inner"
2271                    }
2272                }
2273            ]
2274        }"#,
2275        )?;
2276
2277        let inner_value1 = Value::Record(vec![("z".into(), Value::Int(3))]);
2278        let inner_value2 = Value::Record(vec![("z".into(), Value::Int(6))]);
2279        let outer_value = Value::Record(vec![
2280            ("a".into(), Value::Array(vec![inner_value1])),
2281            (
2282                "b".into(),
2283                Value::Map(vec![("akey".into(), inner_value2)].into_iter().collect()),
2284            ),
2285        ]);
2286        outer_value
2287            .resolve(&schema)
2288            .expect("Record defined in array definition must be resolvable from map");
2289
2290        Ok(())
2291    }
2292
2293    #[test]
2294    fn test_avro_3433_recursive_resolves_map() -> TestResult {
2295        let schema = Schema::parse_str(
2296            r#"
2297        {
2298            "type":"record",
2299            "name":"TestStruct",
2300            "fields": [
2301                {
2302                    "name":"a",
2303                    "type":{
2304                        "type":"record",
2305                        "name": "Inner",
2306                        "fields": [ {
2307                            "name":"z",
2308                            "type":"int"
2309                        }]
2310                    }
2311                },
2312                {
2313                    "name":"b",
2314                    "type": {
2315                        "type":"map",
2316                        "values":"Inner"
2317                    }
2318                }
2319            ]
2320        }"#,
2321        )?;
2322
2323        let inner_value1 = Value::Record(vec![("z".into(), Value::Int(3))]);
2324        let inner_value2 = Value::Record(vec![("z".into(), Value::Int(6))]);
2325        let outer_value = Value::Record(vec![
2326            ("a".into(), inner_value1),
2327            (
2328                "b".into(),
2329                Value::Map(vec![("akey".into(), inner_value2)].into_iter().collect()),
2330            ),
2331        ]);
2332        outer_value
2333            .resolve(&schema)
2334            .expect("Record defined in record field must be resolvable from map field");
2335
2336        Ok(())
2337    }
2338
2339    #[test]
2340    fn test_avro_3433_recursive_resolves_record_wrapper() -> TestResult {
2341        let schema = Schema::parse_str(
2342            r#"
2343        {
2344            "type":"record",
2345            "name":"TestStruct",
2346            "fields": [
2347                {
2348                    "name":"a",
2349                    "type":{
2350                        "type":"record",
2351                        "name": "Inner",
2352                        "fields": [ {
2353                            "name":"z",
2354                            "type":"int"
2355                        }]
2356                    }
2357                },
2358                {
2359                    "name":"b",
2360                    "type": {
2361                        "type":"record",
2362                        "name": "InnerWrapper",
2363                        "fields": [ {
2364                            "name":"j",
2365                            "type":"Inner"
2366                        }]
2367                    }
2368                }
2369            ]
2370        }"#,
2371        )?;
2372
2373        let inner_value1 = Value::Record(vec![("z".into(), Value::Int(3))]);
2374        let inner_value2 = Value::Record(vec![(
2375            "j".into(),
2376            Value::Record(vec![("z".into(), Value::Int(6))]),
2377        )]);
2378        let outer_value =
2379            Value::Record(vec![("a".into(), inner_value1), ("b".into(), inner_value2)]);
2380        outer_value.resolve(&schema).expect("Record schema defined in field must be resolvable in Record schema defined in other field");
2381
2382        Ok(())
2383    }
2384
2385    #[test]
2386    fn test_avro_3433_recursive_resolves_map_and_array() -> TestResult {
2387        let schema = Schema::parse_str(
2388            r#"
2389        {
2390            "type":"record",
2391            "name":"TestStruct",
2392            "fields": [
2393                {
2394                    "name":"a",
2395                    "type":{
2396                        "type":"map",
2397                        "values": {
2398                            "type":"record",
2399                            "name": "Inner",
2400                            "fields": [ {
2401                                "name":"z",
2402                                "type":"int"
2403                            }]
2404                        }
2405                    }
2406                },
2407                {
2408                    "name":"b",
2409                    "type": {
2410                        "type":"array",
2411                        "items":"Inner"
2412                    }
2413                }
2414            ]
2415        }"#,
2416        )?;
2417
2418        let inner_value1 = Value::Record(vec![("z".into(), Value::Int(3))]);
2419        let inner_value2 = Value::Record(vec![("z".into(), Value::Int(6))]);
2420        let outer_value = Value::Record(vec![
2421            (
2422                "a".into(),
2423                Value::Map(vec![("akey".into(), inner_value2)].into_iter().collect()),
2424            ),
2425            ("b".into(), Value::Array(vec![inner_value1])),
2426        ]);
2427        outer_value
2428            .resolve(&schema)
2429            .expect("Record defined in map definition must be resolvable from array");
2430
2431        Ok(())
2432    }
2433
2434    #[test]
2435    fn test_avro_3433_recursive_resolves_union() -> TestResult {
2436        let schema = Schema::parse_str(
2437            r#"
2438        {
2439            "type":"record",
2440            "name":"TestStruct",
2441            "fields": [
2442                {
2443                    "name":"a",
2444                    "type":["null", {
2445                        "type":"record",
2446                        "name": "Inner",
2447                        "fields": [ {
2448                            "name":"z",
2449                            "type":"int"
2450                        }]
2451                    }]
2452                },
2453                {
2454                    "name":"b",
2455                    "type":"Inner"
2456                }
2457            ]
2458        }"#,
2459        )?;
2460
2461        let inner_value1 = Value::Record(vec![("z".into(), Value::Int(3))]);
2462        let inner_value2 = Value::Record(vec![("z".into(), Value::Int(6))]);
2463        let outer1 = Value::Record(vec![
2464            ("a".into(), inner_value1),
2465            ("b".into(), inner_value2.clone()),
2466        ]);
2467        outer1
2468            .resolve(&schema)
2469            .expect("Record definition defined in union must be resolved in other field");
2470        let outer2 = Value::Record(vec![("a".into(), Value::Null), ("b".into(), inner_value2)]);
2471        outer2
2472            .resolve(&schema)
2473            .expect("Record definition defined in union must be resolved in other field");
2474
2475        Ok(())
2476    }
2477
2478    #[test]
2479    fn test_avro_3461_test_multi_level_resolve_outer_namespace() -> TestResult {
2480        let schema = r#"
2481        {
2482          "name": "record_name",
2483          "namespace": "space",
2484          "type": "record",
2485          "fields": [
2486            {
2487              "name": "outer_field_1",
2488              "type": [
2489                        "null",
2490                        {
2491                            "type": "record",
2492                            "name": "middle_record_name",
2493                            "fields":[
2494                                {
2495                                    "name":"middle_field_1",
2496                                    "type":[
2497                                        "null",
2498                                        {
2499                                            "type":"record",
2500                                            "name":"inner_record_name",
2501                                            "fields":[
2502                                                {
2503                                                    "name":"inner_field_1",
2504                                                    "type":"double"
2505                                                }
2506                                            ]
2507                                        }
2508                                    ]
2509                                }
2510                            ]
2511                        }
2512                    ]
2513            },
2514            {
2515                "name": "outer_field_2",
2516                "type" : "space.inner_record_name"
2517            }
2518          ]
2519        }
2520        "#;
2521        let schema = Schema::parse_str(schema)?;
2522        let inner_record = Value::Record(vec![("inner_field_1".into(), Value::Double(5.4))]);
2523        let middle_record_variation_1 = Value::Record(vec![(
2524            "middle_field_1".into(),
2525            Value::Union(0, Box::new(Value::Null)),
2526        )]);
2527        let middle_record_variation_2 = Value::Record(vec![(
2528            "middle_field_1".into(),
2529            Value::Union(1, Box::new(inner_record.clone())),
2530        )]);
2531        let outer_record_variation_1 = Value::Record(vec![
2532            (
2533                "outer_field_1".into(),
2534                Value::Union(0, Box::new(Value::Null)),
2535            ),
2536            ("outer_field_2".into(), inner_record.clone()),
2537        ]);
2538        let outer_record_variation_2 = Value::Record(vec![
2539            (
2540                "outer_field_1".into(),
2541                Value::Union(1, Box::new(middle_record_variation_1)),
2542            ),
2543            ("outer_field_2".into(), inner_record.clone()),
2544        ]);
2545        let outer_record_variation_3 = Value::Record(vec![
2546            (
2547                "outer_field_1".into(),
2548                Value::Union(1, Box::new(middle_record_variation_2)),
2549            ),
2550            ("outer_field_2".into(), inner_record),
2551        ]);
2552
2553        outer_record_variation_1
2554            .resolve(&schema)
2555            .expect("Should be able to resolve value to the schema that is it's definition");
2556        outer_record_variation_2
2557            .resolve(&schema)
2558            .expect("Should be able to resolve value to the schema that is it's definition");
2559        outer_record_variation_3
2560            .resolve(&schema)
2561            .expect("Should be able to resolve value to the schema that is it's definition");
2562
2563        Ok(())
2564    }
2565
2566    #[test]
2567    fn test_avro_3461_test_multi_level_resolve_middle_namespace() -> TestResult {
2568        let schema = r#"
2569        {
2570          "name": "record_name",
2571          "namespace": "space",
2572          "type": "record",
2573          "fields": [
2574            {
2575              "name": "outer_field_1",
2576              "type": [
2577                        "null",
2578                        {
2579                            "type": "record",
2580                            "name": "middle_record_name",
2581                            "namespace":"middle_namespace",
2582                            "fields":[
2583                                {
2584                                    "name":"middle_field_1",
2585                                    "type":[
2586                                        "null",
2587                                        {
2588                                            "type":"record",
2589                                            "name":"inner_record_name",
2590                                            "fields":[
2591                                                {
2592                                                    "name":"inner_field_1",
2593                                                    "type":"double"
2594                                                }
2595                                            ]
2596                                        }
2597                                    ]
2598                                }
2599                            ]
2600                        }
2601                    ]
2602            },
2603            {
2604                "name": "outer_field_2",
2605                "type" : "middle_namespace.inner_record_name"
2606            }
2607          ]
2608        }
2609        "#;
2610        let schema = Schema::parse_str(schema)?;
2611        let inner_record = Value::Record(vec![("inner_field_1".into(), Value::Double(5.4))]);
2612        let middle_record_variation_1 = Value::Record(vec![(
2613            "middle_field_1".into(),
2614            Value::Union(0, Box::new(Value::Null)),
2615        )]);
2616        let middle_record_variation_2 = Value::Record(vec![(
2617            "middle_field_1".into(),
2618            Value::Union(1, Box::new(inner_record.clone())),
2619        )]);
2620        let outer_record_variation_1 = Value::Record(vec![
2621            (
2622                "outer_field_1".into(),
2623                Value::Union(0, Box::new(Value::Null)),
2624            ),
2625            ("outer_field_2".into(), inner_record.clone()),
2626        ]);
2627        let outer_record_variation_2 = Value::Record(vec![
2628            (
2629                "outer_field_1".into(),
2630                Value::Union(1, Box::new(middle_record_variation_1)),
2631            ),
2632            ("outer_field_2".into(), inner_record.clone()),
2633        ]);
2634        let outer_record_variation_3 = Value::Record(vec![
2635            (
2636                "outer_field_1".into(),
2637                Value::Union(1, Box::new(middle_record_variation_2)),
2638            ),
2639            ("outer_field_2".into(), inner_record),
2640        ]);
2641
2642        outer_record_variation_1
2643            .resolve(&schema)
2644            .expect("Should be able to resolve value to the schema that is it's definition");
2645        outer_record_variation_2
2646            .resolve(&schema)
2647            .expect("Should be able to resolve value to the schema that is it's definition");
2648        outer_record_variation_3
2649            .resolve(&schema)
2650            .expect("Should be able to resolve value to the schema that is it's definition");
2651
2652        Ok(())
2653    }
2654
2655    #[test]
2656    fn test_avro_3461_test_multi_level_resolve_inner_namespace() -> TestResult {
2657        let schema = r#"
2658        {
2659          "name": "record_name",
2660          "namespace": "space",
2661          "type": "record",
2662          "fields": [
2663            {
2664              "name": "outer_field_1",
2665              "type": [
2666                        "null",
2667                        {
2668                            "type": "record",
2669                            "name": "middle_record_name",
2670                            "namespace":"middle_namespace",
2671                            "fields":[
2672                                {
2673                                    "name":"middle_field_1",
2674                                    "type":[
2675                                        "null",
2676                                        {
2677                                            "type":"record",
2678                                            "name":"inner_record_name",
2679                                            "namespace":"inner_namespace",
2680                                            "fields":[
2681                                                {
2682                                                    "name":"inner_field_1",
2683                                                    "type":"double"
2684                                                }
2685                                            ]
2686                                        }
2687                                    ]
2688                                }
2689                            ]
2690                        }
2691                    ]
2692            },
2693            {
2694                "name": "outer_field_2",
2695                "type" : "inner_namespace.inner_record_name"
2696            }
2697          ]
2698        }
2699        "#;
2700        let schema = Schema::parse_str(schema)?;
2701
2702        let inner_record = Value::Record(vec![("inner_field_1".into(), Value::Double(5.4))]);
2703        let middle_record_variation_1 = Value::Record(vec![(
2704            "middle_field_1".into(),
2705            Value::Union(0, Box::new(Value::Null)),
2706        )]);
2707        let middle_record_variation_2 = Value::Record(vec![(
2708            "middle_field_1".into(),
2709            Value::Union(1, Box::new(inner_record.clone())),
2710        )]);
2711        let outer_record_variation_1 = Value::Record(vec![
2712            (
2713                "outer_field_1".into(),
2714                Value::Union(0, Box::new(Value::Null)),
2715            ),
2716            ("outer_field_2".into(), inner_record.clone()),
2717        ]);
2718        let outer_record_variation_2 = Value::Record(vec![
2719            (
2720                "outer_field_1".into(),
2721                Value::Union(1, Box::new(middle_record_variation_1)),
2722            ),
2723            ("outer_field_2".into(), inner_record.clone()),
2724        ]);
2725        let outer_record_variation_3 = Value::Record(vec![
2726            (
2727                "outer_field_1".into(),
2728                Value::Union(1, Box::new(middle_record_variation_2)),
2729            ),
2730            ("outer_field_2".into(), inner_record),
2731        ]);
2732
2733        outer_record_variation_1
2734            .resolve(&schema)
2735            .expect("Should be able to resolve value to the schema that is it's definition");
2736        outer_record_variation_2
2737            .resolve(&schema)
2738            .expect("Should be able to resolve value to the schema that is it's definition");
2739        outer_record_variation_3
2740            .resolve(&schema)
2741            .expect("Should be able to resolve value to the schema that is it's definition");
2742
2743        Ok(())
2744    }
2745
2746    #[test]
2747    fn test_avro_3460_validation_with_refs() -> TestResult {
2748        let schema = Schema::parse_str(
2749            r#"
2750        {
2751            "type":"record",
2752            "name":"TestStruct",
2753            "fields": [
2754                {
2755                    "name":"a",
2756                    "type":{
2757                        "type":"record",
2758                        "name": "Inner",
2759                        "fields": [ {
2760                            "name":"z",
2761                            "type":"int"
2762                        }]
2763                    }
2764                },
2765                {
2766                    "name":"b",
2767                    "type":"Inner"
2768                }
2769            ]
2770        }"#,
2771        )?;
2772
2773        let inner_value_right = Value::Record(vec![("z".into(), Value::Int(3))]);
2774        let inner_value_wrong1 = Value::Record(vec![("z".into(), Value::Null)]);
2775        let inner_value_wrong2 = Value::Record(vec![("a".into(), Value::String("testing".into()))]);
2776        let outer1 = Value::Record(vec![
2777            ("a".into(), inner_value_right.clone()),
2778            ("b".into(), inner_value_wrong1),
2779        ]);
2780
2781        let outer2 = Value::Record(vec![
2782            ("a".into(), inner_value_right),
2783            ("b".into(), inner_value_wrong2),
2784        ]);
2785
2786        assert!(
2787            !outer1.validate(&schema),
2788            "field b record is invalid against the schema"
2789        ); // this should pass, but doesn't
2790        assert!(
2791            !outer2.validate(&schema),
2792            "field b record is invalid against the schema"
2793        ); // this should pass, but doesn't
2794
2795        Ok(())
2796    }
2797
2798    #[test]
2799    fn test_avro_3460_validation_with_refs_real_struct() -> TestResult {
2800        use serde::Serialize;
2801
2802        #[derive(Serialize, Clone)]
2803        struct TestInner {
2804            z: i32,
2805        }
2806
2807        #[derive(Serialize)]
2808        struct TestRefSchemaStruct1 {
2809            a: TestInner,
2810            b: String, // could be literally anything
2811        }
2812
2813        #[derive(Serialize)]
2814        struct TestRefSchemaStruct2 {
2815            a: TestInner,
2816            b: i32, // could be literally anything
2817        }
2818
2819        #[derive(Serialize)]
2820        struct TestRefSchemaStruct3 {
2821            a: TestInner,
2822            b: Option<TestInner>, // could be literally anything
2823        }
2824
2825        let schema = Schema::parse_str(
2826            r#"
2827        {
2828            "type":"record",
2829            "name":"TestStruct",
2830            "fields": [
2831                {
2832                    "name":"a",
2833                    "type":{
2834                        "type":"record",
2835                        "name": "Inner",
2836                        "fields": [ {
2837                            "name":"z",
2838                            "type":"int"
2839                        }]
2840                    }
2841                },
2842                {
2843                    "name":"b",
2844                    "type":"Inner"
2845                }
2846            ]
2847        }"#,
2848        )?;
2849
2850        let test_inner = TestInner { z: 3 };
2851        let test_outer1 = TestRefSchemaStruct1 {
2852            a: test_inner.clone(),
2853            b: "testing".into(),
2854        };
2855        let test_outer2 = TestRefSchemaStruct2 {
2856            a: test_inner.clone(),
2857            b: 24,
2858        };
2859        let test_outer3 = TestRefSchemaStruct3 {
2860            a: test_inner,
2861            b: None,
2862        };
2863
2864        let test_outer1: Value = to_value(test_outer1)?;
2865        let test_outer2: Value = to_value(test_outer2)?;
2866        let test_outer3: Value = to_value(test_outer3)?;
2867
2868        assert!(
2869            !test_outer1.validate(&schema),
2870            "field b record is invalid against the schema"
2871        );
2872        assert!(
2873            !test_outer2.validate(&schema),
2874            "field b record is invalid against the schema"
2875        );
2876        assert!(
2877            !test_outer3.validate(&schema),
2878            "field b record is invalid against the schema"
2879        );
2880
2881        Ok(())
2882    }
2883
2884    fn avro_3674_with_or_without_namespace(with_namespace: bool) -> TestResult {
2885        use serde::Serialize;
2886
2887        let schema_str = r#"
2888        {
2889            "type": "record",
2890            "name": "NamespacedMessage",
2891            [NAMESPACE]
2892            "fields": [
2893                {
2894                    "name": "field_a",
2895                    "type": {
2896                        "type": "record",
2897                        "name": "NestedMessage",
2898                        "fields": [
2899                            {
2900                                "name": "enum_a",
2901                                "type": {
2902                                "type": "enum",
2903                                "name": "EnumType",
2904                                "symbols": ["SYMBOL_1", "SYMBOL_2"],
2905                                "default": "SYMBOL_1"
2906                                }
2907                            },
2908                            {
2909                                "name": "enum_b",
2910                                "type": "EnumType"
2911                            }
2912                        ]
2913                    }
2914                }
2915            ]
2916        }
2917        "#;
2918        let schema_str = schema_str.replace(
2919            "[NAMESPACE]",
2920            if with_namespace {
2921                r#""namespace": "com.domain","#
2922            } else {
2923                ""
2924            },
2925        );
2926
2927        let schema = Schema::parse_str(&schema_str)?;
2928
2929        #[derive(Serialize)]
2930        enum EnumType {
2931            #[serde(rename = "SYMBOL_1")]
2932            Symbol1,
2933            #[serde(rename = "SYMBOL_2")]
2934            Symbol2,
2935        }
2936
2937        #[derive(Serialize)]
2938        struct FieldA {
2939            enum_a: EnumType,
2940            enum_b: EnumType,
2941        }
2942
2943        #[derive(Serialize)]
2944        struct NamespacedMessage {
2945            field_a: FieldA,
2946        }
2947
2948        let msg = NamespacedMessage {
2949            field_a: FieldA {
2950                enum_a: EnumType::Symbol2,
2951                enum_b: EnumType::Symbol1,
2952            },
2953        };
2954
2955        let test_value: Value = to_value(msg)?;
2956        assert!(test_value.validate(&schema), "test_value should validate");
2957        assert!(
2958            test_value.resolve(&schema).is_ok(),
2959            "test_value should resolve"
2960        );
2961
2962        Ok(())
2963    }
2964
2965    #[test]
2966    fn test_avro_3674_validate_no_namespace_resolution() -> TestResult {
2967        avro_3674_with_or_without_namespace(false)
2968    }
2969
2970    #[test]
2971    fn test_avro_3674_validate_with_namespace_resolution() -> TestResult {
2972        avro_3674_with_or_without_namespace(true)
2973    }
2974
2975    fn avro_3688_schema_resolution_panic(set_field_b: bool) -> TestResult {
2976        use serde::{Deserialize, Serialize};
2977
2978        let schema_str = r#"{
2979            "type": "record",
2980            "name": "Message",
2981            "fields": [
2982                {
2983                    "name": "field_a",
2984                    "type": [
2985                        "null",
2986                        {
2987                            "name": "Inner",
2988                            "type": "record",
2989                            "fields": [
2990                                {
2991                                    "name": "inner_a",
2992                                    "type": "string"
2993                                }
2994                            ]
2995                        }
2996                    ],
2997                    "default": null
2998                },
2999                {
3000                    "name": "field_b",
3001                    "type": [
3002                        "null",
3003                        "Inner"
3004                    ],
3005                    "default": null
3006                }
3007            ]
3008        }"#;
3009
3010        #[derive(Serialize, Deserialize)]
3011        struct Inner {
3012            inner_a: String,
3013        }
3014
3015        #[derive(Serialize, Deserialize)]
3016        struct Message {
3017            field_a: Option<Inner>,
3018            field_b: Option<Inner>,
3019        }
3020
3021        let schema = Schema::parse_str(schema_str)?;
3022
3023        let msg = Message {
3024            field_a: Some(Inner {
3025                inner_a: "foo".to_string(),
3026            }),
3027            field_b: if set_field_b {
3028                Some(Inner {
3029                    inner_a: "bar".to_string(),
3030                })
3031            } else {
3032                None
3033            },
3034        };
3035
3036        let test_value: Value = to_value(msg)?;
3037        assert!(test_value.validate(&schema), "test_value should validate");
3038        assert!(
3039            test_value.resolve(&schema).is_ok(),
3040            "test_value should resolve"
3041        );
3042
3043        Ok(())
3044    }
3045
3046    #[test]
3047    fn test_avro_3688_field_b_not_set() -> TestResult {
3048        avro_3688_schema_resolution_panic(false)
3049    }
3050
3051    #[test]
3052    fn test_avro_3688_field_b_set() -> TestResult {
3053        avro_3688_schema_resolution_panic(true)
3054    }
3055
3056    #[test]
3057    fn test_avro_3764_use_resolve_schemata() -> TestResult {
3058        let referenced_schema =
3059            r#"{"name": "enumForReference", "type": "enum", "symbols": ["A", "B"]}"#;
3060        let main_schema = r#"{"name": "recordWithReference", "type": "record", "fields": [{"name": "reference", "type": "enumForReference"}]}"#;
3061
3062        let value: serde_json::Value = serde_json::from_str(
3063            r#"
3064            {
3065                "reference": "A"
3066            }
3067        "#,
3068        )?;
3069
3070        let avro_value = Value::try_from(value)?;
3071
3072        let schemas = Schema::parse_list([main_schema, referenced_schema])?;
3073
3074        let main_schema = schemas.first().unwrap();
3075        let schemata: Vec<_> = schemas.iter().skip(1).collect();
3076
3077        let resolve_result = avro_value.clone().resolve_schemata(main_schema, schemata);
3078
3079        assert!(
3080            resolve_result.is_ok(),
3081            "result of resolving with schemata should be ok, got: {resolve_result:?}"
3082        );
3083
3084        let resolve_result = avro_value.resolve(main_schema);
3085        assert!(
3086            resolve_result.is_err(),
3087            "result of resolving without schemata should be err, got: {resolve_result:?}"
3088        );
3089
3090        Ok(())
3091    }
3092
3093    #[test]
3094    fn test_avro_3767_union_resolve_complex_refs() -> TestResult {
3095        let referenced_enum =
3096            r#"{"name": "enumForReference", "type": "enum", "symbols": ["A", "B"]}"#;
3097        let referenced_record = r#"{"name": "recordForReference", "type": "record", "fields": [{"name": "refInRecord", "type": "enumForReference"}]}"#;
3098        let main_schema = r#"{"name": "recordWithReference", "type": "record", "fields": [{"name": "reference", "type": ["null", "recordForReference"]}]}"#;
3099
3100        let value: serde_json::Value = serde_json::from_str(
3101            r#"
3102            {
3103                "reference": {
3104                    "refInRecord": "A"
3105                }
3106            }
3107        "#,
3108        )?;
3109
3110        let avro_value = Value::try_from(value)?;
3111
3112        let schemata = Schema::parse_list([referenced_enum, referenced_record, main_schema])?;
3113
3114        let main_schema = schemata.last().unwrap();
3115        let other_schemata: Vec<&Schema> = schemata.iter().take(2).collect();
3116
3117        let resolve_result = avro_value.resolve_schemata(main_schema, other_schemata)?;
3118
3119        let schemata_ref = schemata.iter().collect::<Vec<_>>();
3120        assert!(
3121            resolve_result.validate_schemata(&schemata_ref),
3122            "result of validation with schemata should be true"
3123        );
3124
3125        Ok(())
3126    }
3127
3128    #[test]
3129    fn test_avro_3782_incorrect_decimal_resolving() -> TestResult {
3130        let schema = r#"{"name": "decimalSchema", "logicalType": "decimal", "type": "fixed", "precision": 8, "scale": 0, "size": 8}"#;
3131
3132        let avro_value = Value::Decimal(Decimal::from(
3133            BigInt::from(12345678u32).to_signed_bytes_be(),
3134        ));
3135        let schema = Schema::parse_str(schema)?;
3136        let resolve_result = avro_value.resolve(&schema);
3137        assert!(
3138            resolve_result.is_ok(),
3139            "resolve result must be ok, got: {resolve_result:?}"
3140        );
3141
3142        Ok(())
3143    }
3144
3145    #[test]
3146    fn test_avro_3779_bigdecimal_resolving() -> TestResult {
3147        let schema =
3148            r#"{"name": "bigDecimalSchema", "logicalType": "big-decimal", "type": "bytes" }"#;
3149
3150        let avro_value = Value::BigDecimal(BigDecimal::from(12345678u32));
3151        let schema = Schema::parse_str(schema)?;
3152        let resolve_result: AvroResult<Value> = avro_value.resolve(&schema);
3153        assert!(
3154            resolve_result.is_ok(),
3155            "resolve result must be ok, got: {resolve_result:?}"
3156        );
3157
3158        Ok(())
3159    }
3160
3161    #[test]
3162    fn test_avro_3892_resolve_fixed_from_bytes() -> TestResult {
3163        let value = Value::Bytes(vec![97, 98, 99]);
3164        assert_eq!(
3165            value.resolve(&Schema::Fixed(FixedSchema {
3166                name: "test".try_into()?,
3167                aliases: None,
3168                doc: None,
3169                size: 3,
3170                attributes: Default::default()
3171            }))?,
3172            Value::Fixed(3, vec![97, 98, 99])
3173        );
3174
3175        let value = Value::Bytes(vec![97, 99]);
3176        assert!(
3177            value
3178                .resolve(&Schema::Fixed(FixedSchema {
3179                    name: "test".try_into()?,
3180                    aliases: None,
3181                    doc: None,
3182                    size: 3,
3183                    attributes: Default::default()
3184                }))
3185                .is_err(),
3186        );
3187
3188        let value = Value::Bytes(vec![97, 98, 99, 100]);
3189        assert!(
3190            value
3191                .resolve(&Schema::Fixed(FixedSchema {
3192                    name: "test".try_into()?,
3193                    aliases: None,
3194                    doc: None,
3195                    size: 3,
3196                    attributes: Default::default()
3197                }))
3198                .is_err(),
3199        );
3200
3201        Ok(())
3202    }
3203
3204    #[test]
3205    fn avro_3928_from_serde_value_to_types_value() -> TestResult {
3206        assert_eq!(Value::try_from(serde_json::Value::Null)?, Value::Null);
3207        assert_eq!(Value::try_from(json!(true))?, Value::Boolean(true));
3208        assert_eq!(Value::try_from(json!(false))?, Value::Boolean(false));
3209        assert_eq!(Value::try_from(json!(0))?, Value::Int(0));
3210        assert_eq!(Value::try_from(json!(i32::MIN))?, Value::Int(i32::MIN));
3211        assert_eq!(Value::try_from(json!(i32::MAX))?, Value::Int(i32::MAX));
3212        assert_eq!(
3213            Value::try_from(json!(i32::MIN as i64 - 1))?,
3214            Value::Long(i32::MIN as i64 - 1)
3215        );
3216        assert_eq!(
3217            Value::try_from(json!(i32::MAX as i64 + 1))?,
3218            Value::Long(i32::MAX as i64 + 1)
3219        );
3220        assert_eq!(Value::try_from(json!(1.23))?, Value::Double(1.23));
3221        assert_eq!(Value::try_from(json!(-1.23))?, Value::Double(-1.23));
3222        assert_eq!(
3223            Value::try_from(json!(u64::MIN))?,
3224            Value::Int(u64::MIN as i32)
3225        );
3226        assert_eq!(
3227            Value::try_from(json!("some text"))?,
3228            Value::String("some text".into())
3229        );
3230        assert_eq!(
3231            Value::try_from(json!(["text1", "text2", "text3"]))?,
3232            Value::Array(vec![
3233                Value::String("text1".into()),
3234                Value::String("text2".into()),
3235                Value::String("text3".into())
3236            ])
3237        );
3238        assert_eq!(
3239            Value::try_from(json!({"key1": "value1", "key2": "value2"}))?,
3240            Value::Map(
3241                vec![
3242                    ("key1".into(), Value::String("value1".into())),
3243                    ("key2".into(), Value::String("value2".into()))
3244                ]
3245                .into_iter()
3246                .collect()
3247            )
3248        );
3249        Ok(())
3250    }
3251
3252    #[test]
3253    fn avro_4024_resolve_double_from_unknown_string_err() -> TestResult {
3254        let schema = Schema::parse_str(r#"{"type": "double"}"#)?;
3255        let value = Value::String("unknown".to_owned());
3256        match value.resolve(&schema).map_err(Error::into_details) {
3257            Err(err @ Details::GetDouble(_)) => {
3258                assert_eq!(
3259                    format!("{err:?}"),
3260                    r#"Expected Value::Double, Value::Float, Value::Int, Value::Long or Value::String ("NaN", "INF", "Infinity", "-INF" or "-Infinity"), got: String("unknown")"#
3261                );
3262            }
3263            other => {
3264                panic!("Expected Details::GetDouble, got {other:?}");
3265            }
3266        }
3267        Ok(())
3268    }
3269
3270    #[test]
3271    fn avro_4024_resolve_float_from_unknown_string_err() -> TestResult {
3272        let schema = Schema::parse_str(r#"{"type": "float"}"#)?;
3273        let value = Value::String("unknown".to_owned());
3274        match value.resolve(&schema).map_err(Error::into_details) {
3275            Err(err @ Details::GetFloat(_)) => {
3276                assert_eq!(
3277                    format!("{err:?}"),
3278                    r#"Expected Value::Float, Value::Double, Value::Int, Value::Long or Value::String ("NaN", "INF", "Infinity", "-INF" or "-Infinity"), got: String("unknown")"#
3279                );
3280            }
3281            other => {
3282                panic!("Expected Details::GetFloat, got {other:?}");
3283            }
3284        }
3285        Ok(())
3286    }
3287
3288    #[test]
3289    fn avro_4029_resolve_from_unsupported_err() -> TestResult {
3290        let data: Vec<(&str, Value, &str)> = vec![
3291            (
3292                r#"{ "name": "NAME", "type": "int" }"#,
3293                Value::Float(123_f32),
3294                "Expected Value::Int, got: Float(123.0)",
3295            ),
3296            (
3297                r#"{ "name": "NAME", "type": "fixed", "size": 3 }"#,
3298                Value::Float(123_f32),
3299                "String expected for fixed, got: Float(123.0)",
3300            ),
3301            (
3302                r#"{ "name": "NAME", "type": "bytes" }"#,
3303                Value::Float(123_f32),
3304                "Expected Value::Bytes, got: Float(123.0)",
3305            ),
3306            (
3307                r#"{ "name": "NAME", "type": "string", "logicalType": "uuid" }"#,
3308                Value::String("abc-1234".into()),
3309                "Failed to convert &str to UUID: invalid group count: expected 5, found 2",
3310            ),
3311            (
3312                r#"{ "name": "NAME", "type": "string", "logicalType": "uuid" }"#,
3313                Value::Float(123_f32),
3314                "Expected Value::Uuid, got: Float(123.0)",
3315            ),
3316            (
3317                r#"{ "name": "NAME", "type": "bytes", "logicalType": "big-decimal" }"#,
3318                Value::Float(123_f32),
3319                "Expected Value::BigDecimal, got: Float(123.0)",
3320            ),
3321            (
3322                r#"{ "name": "NAME", "type": "fixed", "size": 12, "logicalType": "duration" }"#,
3323                Value::Float(123_f32),
3324                "Expected Value::Duration or Value::Fixed(12), got: Float(123.0)",
3325            ),
3326            (
3327                r#"{ "name": "NAME", "type": "bytes", "logicalType": "decimal", "precision": 4, "scale": 3 }"#,
3328                Value::Float(123_f32),
3329                "Expected Value::Decimal, Value::Bytes or Value::Fixed, got: Float(123.0)",
3330            ),
3331            (
3332                r#"{ "name": "NAME", "type": "bytes" }"#,
3333                Value::Array(vec![Value::Long(256_i64)]),
3334                "Unable to convert to u8, got Int(256)",
3335            ),
3336            (
3337                r#"{ "name": "NAME", "type": "int", "logicalType": "date" }"#,
3338                Value::Float(123_f32),
3339                "Expected Value::Date or Value::Int, got: Float(123.0)",
3340            ),
3341            (
3342                r#"{ "name": "NAME", "type": "int", "logicalType": "time-millis" }"#,
3343                Value::Float(123_f32),
3344                "Expected Value::TimeMillis or Value::Int, got: Float(123.0)",
3345            ),
3346            (
3347                r#"{ "name": "NAME", "type": "long", "logicalType": "time-micros" }"#,
3348                Value::Float(123_f32),
3349                "Expected Value::TimeMicros, Value::Long or Value::Int, got: Float(123.0)",
3350            ),
3351            (
3352                r#"{ "name": "NAME", "type": "long", "logicalType": "timestamp-millis" }"#,
3353                Value::Float(123_f32),
3354                "Expected Value::TimestampMillis, Value::Long or Value::Int, got: Float(123.0)",
3355            ),
3356            (
3357                r#"{ "name": "NAME", "type": "long", "logicalType": "timestamp-micros" }"#,
3358                Value::Float(123_f32),
3359                "Expected Value::TimestampMicros, Value::Long or Value::Int, got: Float(123.0)",
3360            ),
3361            (
3362                r#"{ "name": "NAME", "type": "long", "logicalType": "timestamp-nanos" }"#,
3363                Value::Float(123_f32),
3364                "Expected Value::TimestampNanos, Value::Long or Value::Int, got: Float(123.0)",
3365            ),
3366            (
3367                r#"{ "name": "NAME", "type": "long", "logicalType": "local-timestamp-millis" }"#,
3368                Value::Float(123_f32),
3369                "Expected Value::LocalTimestampMillis, Value::Long or Value::Int, got: Float(123.0)",
3370            ),
3371            (
3372                r#"{ "name": "NAME", "type": "long", "logicalType": "local-timestamp-micros" }"#,
3373                Value::Float(123_f32),
3374                "Expected Value::LocalTimestampMicros, Value::Long or Value::Int, got: Float(123.0)",
3375            ),
3376            (
3377                r#"{ "name": "NAME", "type": "long", "logicalType": "local-timestamp-nanos" }"#,
3378                Value::Float(123_f32),
3379                "Expected Value::LocalTimestampNanos, Value::Long or Value::Int, got: Float(123.0)",
3380            ),
3381            (
3382                r#"{ "name": "NAME", "type": "null" }"#,
3383                Value::Float(123_f32),
3384                "Expected Value::Null, got: Float(123.0)",
3385            ),
3386            (
3387                r#"{ "name": "NAME", "type": "boolean" }"#,
3388                Value::Float(123_f32),
3389                "Expected Value::Boolean, got: Float(123.0)",
3390            ),
3391            (
3392                r#"{ "name": "NAME", "type": "int" }"#,
3393                Value::Float(123_f32),
3394                "Expected Value::Int, got: Float(123.0)",
3395            ),
3396            (
3397                r#"{ "name": "NAME", "type": "long" }"#,
3398                Value::Float(123_f32),
3399                "Expected Value::Long or Value::Int, got: Float(123.0)",
3400            ),
3401            (
3402                r#"{ "name": "NAME", "type": "float" }"#,
3403                Value::Boolean(false),
3404                r#"Expected Value::Float, Value::Double, Value::Int, Value::Long or Value::String ("NaN", "INF", "Infinity", "-INF" or "-Infinity"), got: Boolean(false)"#,
3405            ),
3406            (
3407                r#"{ "name": "NAME", "type": "double" }"#,
3408                Value::Boolean(false),
3409                r#"Expected Value::Double, Value::Float, Value::Int, Value::Long or Value::String ("NaN", "INF", "Infinity", "-INF" or "-Infinity"), got: Boolean(false)"#,
3410            ),
3411            (
3412                r#"{ "name": "NAME", "type": "string" }"#,
3413                Value::Boolean(false),
3414                "Expected Value::String, Value::Bytes or Value::Fixed, got: Boolean(false)",
3415            ),
3416            (
3417                r#"{ "name": "NAME", "type": "enum", "symbols": ["one", "two"] }"#,
3418                Value::Boolean(false),
3419                "Expected Value::Enum, got: Boolean(false)",
3420            ),
3421        ];
3422
3423        for (schema_str, value, expected_error) in data {
3424            let schema = Schema::parse_str(schema_str)?;
3425            match value.resolve(&schema) {
3426                Err(error) => {
3427                    assert_eq!(format!("{error}"), expected_error);
3428                }
3429                other => {
3430                    panic!("Expected '{expected_error}', got {other:?}");
3431                }
3432            }
3433        }
3434        Ok(())
3435    }
3436
3437    #[test]
3438    fn avro_rs_130_get_from_record() -> TestResult {
3439        let schema = r#"
3440        {
3441            "type": "record",
3442            "name": "NamespacedMessage",
3443            "namespace": "space",
3444            "fields": [
3445                {
3446                    "name": "foo",
3447                    "type": "string"
3448                },
3449                {
3450                    "name": "bar",
3451                    "type": "long"
3452                }
3453            ]
3454        }
3455        "#;
3456
3457        let schema = Schema::parse_str(schema)?;
3458        let mut record = Record::new(&schema).unwrap();
3459        record.put("foo", "hello");
3460        record.put("bar", 123_i64);
3461
3462        assert_eq!(
3463            record.get("foo").unwrap(),
3464            &Value::String("hello".to_string())
3465        );
3466        assert_eq!(record.get("bar").unwrap(), &Value::Long(123));
3467
3468        // also make sure it doesn't fail but return None for non-existing field
3469        assert_eq!(record.get("baz"), None);
3470
3471        Ok(())
3472    }
3473
3474    #[test]
3475    fn avro_rs_392_resolve_long_to_int() {
3476        // Values that are valid as in i32 should work
3477        let value = Value::Long(0);
3478        value.resolve(&Schema::Int).unwrap();
3479        // Values that are outside the i32 range should not
3480        let value = Value::Long(i64::MAX);
3481        assert!(matches!(
3482            value.resolve(&Schema::Int).unwrap_err().details(),
3483            Details::ZagI32(_, _)
3484        ));
3485    }
3486
3487    #[test]
3488    fn avro_rs_450_serde_json_number_u64_max() {
3489        assert_eq!(
3490            Value::try_from(json!(u64::MAX))
3491                .unwrap_err()
3492                .into_details()
3493                .to_string(),
3494            "JSON number 18446744073709551615 could not be converted into an Avro value as it's too large"
3495        );
3496    }
3497}