1#![allow(non_upper_case_globals)]
2#![allow(non_camel_case_types)]
3#![allow(non_snake_case)]
4
5include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
6
7#[cfg(test)]
8mod tests {
9 use crate::{
10 xmlCleanupParser, xmlError, xmlInitParser, xmlSchemaCleanupTypes, xmlSchemaFree,
11 xmlSchemaFreeParserCtxt, xmlSchemaNewParserCtxt, xmlSchemaParse, xmlSchemaParserCtxtPtr,
12 xmlSchemaPtr, xmlSchemaSetParserStructuredErrors,
13 };
14 use ctor::{ctor, dtor};
15 use serial_test::serial;
16 use std::ffi::{c_void, CStr, CString};
17 use std::path::Path;
18 use workspace_root::get_workspace_root;
19
20 struct ValidationErrors {
21 errors: Vec<String>,
22 }
23
24 unsafe extern "C" fn structured_error_handler(
25 user_data: *mut c_void,
26 #[cfg(not(target_os = "windows"))] error: *mut xmlError,
27 #[cfg(target_os = "windows")] error: *const xmlError,
28 ) {
29 if error.is_null() {
30 return;
31 }
32
33 let line = unsafe { (*error).line };
34 let column = unsafe { (*error).int2 };
35 let message = unsafe { CStr::from_ptr((*error).message).to_str().unwrap() };
36
37 let context = unsafe { &mut *(user_data as *mut ValidationErrors) };
38
39 let error = format!("Error: Line {}, column {}: {}", line, column, message);
40
41 context.errors.push(error);
42 }
43
44 struct SchemaParserContext(xmlSchemaParserCtxtPtr);
45
46 impl SchemaParserContext {
47 fn new(path: &Path) -> Result<Self, Vec<String>> {
48 let path_str = match path.to_str() {
49 Some(str) => str,
50 None => return Err(vec![format!("Invalid path: {}", path.to_str().unwrap())]),
51 };
52
53 let c_path = match CString::new(path_str) {
54 Ok(str) => str,
55 Err(e) => return Err(vec![format!("Error: {}", e.to_string())]),
56 };
57
58 let context_ptr = unsafe { xmlSchemaNewParserCtxt(c_path.as_ptr()) };
59
60 if context_ptr.is_null() {
61 let err: Vec<String> =
62 Vec::from(["Failed to create schema parser context".to_string()]);
63
64 Err(err)
65 } else {
66 Ok(Self(context_ptr))
67 }
68 }
69 }
70
71 impl Drop for SchemaParserContext {
72 fn drop(&mut self) {
73 unsafe { xmlSchemaFreeParserCtxt(self.0) };
74 }
75 }
76
77 struct Schema(xmlSchemaPtr);
78
79 impl Drop for Schema {
80 fn drop(&mut self) {
81 unsafe { xmlSchemaFree(self.0) };
82 }
83 }
84
85 #[ctor]
86 fn init() {
87 println!("Setting up xml schema environment");
88 unsafe { xmlInitParser() };
89 }
90
91 #[dtor]
92 fn clean_up() {
93 println!("Cleaning up xml schema");
94 unsafe {
95 xmlSchemaCleanupTypes();
96 xmlCleanupParser();
97 }
98 }
99
100 fn validate_xsd_schema(schema_file: &Path) -> Result<(), Vec<String>> {
101 let mut error_context = ValidationErrors { errors: Vec::new() };
102
103 let result: Result<(), Vec<String>> = (|| {
104 let parser_context = SchemaParserContext::new(schema_file)?;
106
107 unsafe {
109 xmlSchemaSetParserStructuredErrors(
110 parser_context.0,
111 Some(structured_error_handler),
112 &mut error_context as *mut _ as *mut c_void,
113 );
114 }
115
116 let schema_ptr = unsafe { xmlSchemaParse(parser_context.0) };
118 if schema_ptr.is_null() {
119 return Err(vec![
122 "Schema parsing failed: file is not a valid XSD schema.".to_string(),
123 ]);
124 }
125
126 let _schema = Schema(schema_ptr);
128
129 if !error_context.errors.is_empty() {
131 return Err(Vec::new()); }
133
134 Ok(())
135 })();
136
137 match result {
138 Ok(()) => Ok(()),
139 Err(mut e) => {
140 e.extend(error_context.errors);
141
142 Err(e)
143 }
144 }
145 }
146
147 #[serial]
148 #[test]
149 fn test_xsd() {
150 let root = get_workspace_root();
151 let path = root.join("examples").join("valid.xsd");
152 println!("Path: {}", path.display());
153
154 let result = validate_xsd_schema(path.as_path());
155 assert!(result.is_ok());
156 }
157
158 #[serial]
159 #[test]
160 fn test_invalid_xsd() {
161 let root = get_workspace_root();
162 let path = root.join("examples").join("invalid.xsd");
163 println!("Path: {}", path.display());
164
165 let result = validate_xsd_schema(path.as_path());
166 assert!(result.is_err());
167 }
168}