// Copyright (c) 2024 Jonas Schäfer // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. #![deny( non_camel_case_types, non_snake_case, unsafe_code, unused_variables, unused_mut, dead_code )] mod helpers { // we isolate the helpers into a module, because we do not want to have // them in scope below. // this is to ensure that the macros do not have hidden dependencies on // any specific names being imported. use minidom::Element; use xso::{error::FromElementError, transform, try_from_element, FromXml, IntoXml}; pub(super) fn roundtrip_full( s: &str, ) { let initial: Element = s.parse().unwrap(); let structural: T = match try_from_element(initial.clone()) { Ok(v) => v, Err(e) => panic!("failed to parse from {:?}: {}", s, e), }; let recovered = transform(structural.clone()).expect("roundtrip did not produce an element"); assert_eq!(initial, recovered); let structural2: T = match try_from_element(recovered) { Ok(v) => v, Err(e) => panic!("failed to parse from serialisation of {:?}: {}", s, e), }; assert_eq!(structural, structural2); } pub(super) fn parse_str(s: &str) -> Result { let initial: Element = s.parse().unwrap(); try_from_element(initial) } } use self::helpers::{parse_str, roundtrip_full}; use xso::{FromXml, IntoXml}; // these are adverserial local names in order to trigger any issues with // unqualified names in the macro expansions. #[allow(dead_code, non_snake_case)] fn Err() {} #[allow(dead_code, non_snake_case)] fn Ok() {} #[allow(dead_code, non_snake_case)] fn Some() {} #[allow(dead_code, non_snake_case)] fn None() {} #[allow(dead_code)] type Option = ((),); #[allow(dead_code)] type Result = ((),); static NS1: &str = "urn:example:ns1"; #[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] #[xml(namespace = NS1, name = "foo")] struct Empty; #[test] fn empty_roundtrip() { #[allow(unused_imports)] use std::{ option::Option::{None, Some}, result::Result::{Err, Ok}, }; roundtrip_full::(""); } #[test] fn empty_name_mismatch() { #[allow(unused_imports)] use std::{ option::Option::{None, Some}, result::Result::{Err, Ok}, }; match parse_str::("") { Err(xso::error::FromElementError::Mismatch(..)) => (), other => panic!("unexpected result: {:?}", other), } } #[test] fn empty_namespace_mismatch() { #[allow(unused_imports)] use std::{ option::Option::{None, Some}, result::Result::{Err, Ok}, }; match parse_str::("") { Err(xso::error::FromElementError::Mismatch(..)) => (), other => panic!("unexpected result: {:?}", other), } } #[test] fn empty_unexpected_attribute() { #[allow(unused_imports)] use std::{ option::Option::{None, Some}, result::Result::{Err, Ok}, }; match parse_str::("") { Err(xso::error::FromElementError::Invalid(xso::error::Error::Other(e))) => { assert_eq!(e, "Unknown attribute in foo element."); } other => panic!("unexpected result: {:?}", other), } } #[test] fn empty_unexpected_child() { #[allow(unused_imports)] use std::{ option::Option::{None, Some}, result::Result::{Err, Ok}, }; match parse_str::("") { Err(xso::error::FromElementError::Invalid(xso::error::Error::Other(e))) => { assert_eq!(e, "Unknown child in foo element."); } other => panic!("unexpected result: {:?}", other), } } #[test] fn empty_qname_check_has_precedence_over_attr_check() { #[allow(unused_imports)] use std::{ option::Option::{None, Some}, result::Result::{Err, Ok}, }; match parse_str::("") { Err(xso::error::FromElementError::Mismatch(..)) => (), other => panic!("unexpected result: {:?}", other), } } static SOME_NAME: &::xso::exports::rxml::strings::NcNameStr = { #[allow(unsafe_code)] unsafe { ::xso::exports::rxml::strings::NcNameStr::from_str_unchecked("bar") } }; #[derive(FromXml, IntoXml, PartialEq, Debug, Clone)] #[xml(namespace = NS1, name = SOME_NAME)] struct NamePath; #[test] fn name_path_roundtrip() { #[allow(unused_imports)] use std::{ option::Option::{None, Some}, result::Result::{Err, Ok}, }; roundtrip_full::(""); }