diff --git a/.idea/.gitignore b/.idea/.gitignore
deleted file mode 100644
index 13566b8..0000000
--- a/.idea/.gitignore
+++ /dev/null
@@ -1,8 +0,0 @@
-# Default ignored files
-/shelf/
-/workspace.xml
-# Editor-based HTTP Client requests
-/httpRequests/
-# Datasource local storage ignored files
-/dataSources/
-/dataSources.local.xml
diff --git a/.idea/modules.xml b/.idea/modules.xml
index 79ebebb..69d68df 100644
--- a/.idea/modules.xml
+++ b/.idea/modules.xml
@@ -2,7 +2,7 @@
-
+
\ No newline at end of file
diff --git a/.idea/undeepend2.iml b/.idea/undeepend2.iml
deleted file mode 100644
index cf84ae4..0000000
--- a/.idea/undeepend2.iml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/Cargo.lock b/Cargo.lock
index ea589e4..9540641 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -238,12 +238,13 @@ dependencies = [
]
[[package]]
-name = "undeepend2"
+name = "undeepend"
version = "0.1.0"
dependencies = [
"anyhow",
"env_logger",
"log",
+ "regex",
]
[[package]]
diff --git a/Cargo.toml b/Cargo.toml
index cbfd1e6..f7ae982 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,9 +1,10 @@
[package]
-name = "undeepend2"
+name = "undeepend"
version = "0.1.0"
edition = "2024"
[dependencies]
anyhow = "1.0"
log = "0.4"
-env_logger = "0.11"
\ No newline at end of file
+env_logger = "0.11"
+regex="1.11"
\ No newline at end of file
diff --git a/src/lib.rs b/src/lib.rs
index 5fc062e..decf235 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1 +1,2 @@
-mod maven;
\ No newline at end of file
+pub mod maven;
+pub mod xml;
diff --git a/src/main.rs b/src/main.rs
index e7a11a9..a4a0162 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,3 +1,4 @@
fn main() {
- println!("Hello, world!");
+ let message = &"xmlns:Hello, world!"[6..];
+ println!("{}",message);
}
diff --git a/src/maven/metadata.rs b/src/maven/metadata.rs
new file mode 100644
index 0000000..3b5365c
--- /dev/null
+++ b/src/maven/metadata.rs
@@ -0,0 +1,72 @@
+use crate::maven::pom::{ArtifactId, GroupId, Version};
+
+/// The Maven variant to parse poms
+/// These structs is directly modelled after the XML because that is what strong-xml plugin requires
+#[derive(PartialEq, Debug)]
+pub struct Metadata {
+ pub group_id: GroupId,
+ pub artifact_id: ArtifactId,
+ pub version: Version,
+ pub versioning: Versioning,
+}
+
+#[derive(PartialEq, Debug)]
+pub struct Versioning {
+ pub snapshot: Snapshot,
+ pub last_updated: LastUpdated,
+ pub snapshot_versions: SnapshotVersions,
+}
+
+#[derive(PartialEq, Debug)]
+pub struct Snapshot {
+ pub timestamp: Timestamp,
+ pub build_number: BuildNumber,
+}
+
+#[derive(PartialEq, Debug)]
+pub struct SnapshotVersions {
+ pub snapshot_versions: Vec,
+}
+
+#[derive(PartialEq, Debug)]
+pub struct SnapshotVersion {
+ pub classifier: Option,
+ pub extension: Extension,
+ pub value: Value,
+ pub updated: Updated,
+}
+
+#[derive(PartialEq, Debug)]
+pub struct Timestamp {
+ pub value: String,
+}
+
+#[derive(PartialEq, Debug)]
+pub struct BuildNumber {
+ pub value: String,
+}
+
+#[derive(PartialEq, Debug)]
+pub struct LastUpdated {
+ pub value: String,
+}
+
+#[derive(PartialEq, Debug)]
+pub struct Updated {
+ pub value: String,
+}
+
+#[derive(PartialEq, Debug)]
+pub struct Extension {
+ pub value: String,
+}
+
+#[derive(PartialEq, Debug)]
+pub struct Classifier {
+ pub value: String,
+}
+
+#[derive(PartialEq, Debug)]
+pub struct Value {
+ pub value: String,
+}
diff --git a/src/maven/mod.rs b/src/maven/mod.rs
index d1be782..9b5bc2a 100644
--- a/src/maven/mod.rs
+++ b/src/maven/mod.rs
@@ -1 +1,4 @@
-mod xml;
\ No newline at end of file
+pub mod metadata;
+pub mod pom;
+pub mod pom_view;
+mod pom_reader;
diff --git a/src/maven/pom.rs b/src/maven/pom.rs
new file mode 100644
index 0000000..8dac278
--- /dev/null
+++ b/src/maven/pom.rs
@@ -0,0 +1,132 @@
+/// The Maven variant to parse poms
+/// These structs is directly modelled after the XML because that is what strong-xml plugin requires
+#[derive(PartialEq, Debug)]
+pub struct Pom {
+ pub(crate) model_version: ModelVersion,
+ pub(crate) parent: Option,
+ pub(crate) group_id: Option,
+ pub(crate) artifact_id: ArtifactId,
+ pub(crate) version: Option,
+ pub(crate) name: Name,
+ pub(crate) packaging: Option,
+ pub(crate) url: Option,
+ pub(crate) description: Description,
+ pub(crate) licences: Option,
+ pub(crate) scm: Option,
+ pub(crate) developers: Option,
+ pub(crate) dependencies: Option,
+ pub(crate) dependency_management: Option,
+}
+
+#[derive(PartialEq, Debug)]
+pub struct ModelVersion {
+ pub value: String,
+}
+
+#[derive(PartialEq, Debug, Clone)]
+pub struct GroupId {
+ pub(crate) value: String,
+}
+
+#[derive(PartialEq, Debug, Clone)]
+pub struct ArtifactId {
+ pub(crate) value: String,
+}
+
+#[derive(PartialEq, Debug, Clone)]
+pub struct Version {
+ pub(crate) value: String,
+}
+
+#[derive(PartialEq, Debug)]
+pub struct Name {
+ pub(crate) value: String,
+}
+
+#[derive(PartialEq, Debug)]
+pub struct Id {
+ pub(crate) value: String,
+}
+
+#[derive(PartialEq, Debug)]
+pub struct Packaging {
+ pub(crate) value: String,
+}
+
+#[derive(PartialEq, Debug)]
+pub struct Url {
+ pub(crate) value: String,
+}
+
+#[derive(PartialEq, Debug)]
+pub struct Description {
+ pub(crate) value: String,
+}
+
+#[derive(PartialEq, Debug)]
+pub struct Licenses {
+ pub(crate) licenses: Vec,
+}
+
+#[derive(PartialEq, Debug)]
+pub struct Distribution {
+ pub(crate) value: String,
+}
+
+#[derive(PartialEq, Debug)]
+pub struct License {
+ pub(crate) name: Name,
+ pub(crate) url: Url,
+ pub(crate) distribution: Option,
+}
+
+#[derive(PartialEq, Debug)]
+pub struct Parent {
+ pub(crate) group_id: GroupId,
+ pub(crate) artifact_id: ArtifactId,
+ pub(crate) version: Version,
+}
+
+#[derive(PartialEq, Debug)]
+pub struct Scm {
+ pub(crate) url: Url,
+}
+
+#[derive(PartialEq, Debug)]
+pub struct Developers {
+ pub(crate) developers: Vec,
+}
+
+#[derive(PartialEq, Debug)]
+struct Developer {
+ pub(crate) id: Option,
+ pub(crate) name: Name,
+}
+
+#[derive(PartialEq, Debug, Clone)]
+pub struct Dependencies {
+ pub(crate) value: Vec,
+}
+
+#[derive(PartialEq, Debug, Clone)]
+pub struct DependencyManagement {
+ pub(crate) value: Dependencies,
+}
+
+#[derive(PartialEq, Debug, Clone)]
+pub struct Dependency {
+ pub(crate) group_id: GroupId,
+ pub(crate) artifact_id: ArtifactId,
+ pub(crate) version: Option,
+}
+
+#[cfg(test)]
+mod test {
+
+ use crate::maven::pom::Pom;
+
+ #[test]
+ fn parse_should_not_fail() {
+
+ }
+}
diff --git a/src/maven/pom_reader.rs b/src/maven/pom_reader.rs
new file mode 100644
index 0000000..7e70033
--- /dev/null
+++ b/src/maven/pom_reader.rs
@@ -0,0 +1,44 @@
+use crate::maven::pom::Pom;
+use crate::xml::{Attribute, SaxHandler};
+
+fn read(xml: &str){
+
+}
+
+struct PomReader{
+
+}
+
+impl SaxHandler for PomReader{
+ fn start_document(&mut self) {
+ todo!()
+ }
+
+ fn end_document(&mut self) {
+ todo!()
+ }
+
+ fn start_prefix_mapping(&mut self, prefix: &str, uri: &str) {
+ todo!()
+ }
+
+ fn end_prefix_mapping(&mut self, prefix: &str, uri: &str) {
+ todo!()
+ }
+
+ fn start_element(&mut self, uri: Option, local_name: &str, qualified_name: &str, attributes: Vec) {
+ todo!()
+ }
+
+ fn end_element(&mut self, uri: Option, local_name: &str, qualified_name: &str) {
+ todo!()
+ }
+
+ fn characters(&mut self, chars: &[char]) {
+ todo!()
+ }
+
+ fn error(&mut self, error: &str) {
+ todo!()
+ }
+}
\ No newline at end of file
diff --git a/src/maven/pom_view.rs b/src/maven/pom_view.rs
new file mode 100644
index 0000000..39b92ef
--- /dev/null
+++ b/src/maven/pom_view.rs
@@ -0,0 +1,30 @@
+use regex::Regex;
+
+use crate::maven::pom::{Dependency, Parent, Pom};
+
+/// offers a (non-mutable) view on the pom-as-xml-representation
+/// the main use of this is that it resolves the parent information when needed
+///
+
+#[derive(Debug)]
+pub struct Artifact {
+ pub group: String,
+ pub name: String,
+ pub version: String,
+ pub path: String,
+}
+
+impl Artifact {
+ pub fn new(group: &str, name: &str, version: &str) -> Self {
+ Self {
+ group: group.into(),
+ name: name.into(),
+ version: version.into(),
+ path: format!("{}/{}/{}", group.replace(".", "/"), name, version),
+ }
+ }
+
+ pub fn is_snapshot(&self) -> bool {
+ self.version.ends_with("-SNAPSHOT")
+ }
+}
diff --git a/src/maven/xml/sax_parser_test.rs b/src/maven/xml/sax_parser_test.rs
deleted file mode 100644
index 77a2b69..0000000
--- a/src/maven/xml/sax_parser_test.rs
+++ /dev/null
@@ -1,192 +0,0 @@
-use crate::maven::xml::{Attribute, SaxHandler, SaxError};
-
-#[cfg(test)]
-mod tests {
- use crate::maven::xml::sax_parser::parse_string;
- use crate::maven::xml::sax_parser_test::TestHandler;
- use crate::maven::xml::SaxError;
-
- #[test]
- fn test_xml_header() {
- let test_xml = include_str!("test/header.xml");
- let mut testhandler = TestHandler::new();
- parse_string(test_xml.to_string(), Box::new(&mut testhandler))
- .expect("Failed to parse test xml");
- println!("{:?}", testhandler);
- assert_eq!(testhandler.start_document_called, 1);
- assert_eq!(testhandler.end_document_called, 1);
- }
-
- #[test]
- fn test_single_element_short() {
- let test_xml = include_str!("test/header.xml");
- let mut testhandler = TestHandler::new();
- parse_string(test_xml.to_string(), Box::new(&mut testhandler))
- .expect("Failed to parse test xml");
- assert_eq!(testhandler.start_document_called, 1);
- assert_eq!(testhandler.start_element_called, 1);
- assert!(!testhandler.elements.is_empty());
- assert_eq!(testhandler.elements[0], "");
- assert_eq!(testhandler.end_document_called, 1);
- }
-
- #[test]
- fn test_single_element() {
- let test_xml = include_str!("test/element.xml");
- let mut testhandler = TestHandler::new();
- parse_string(test_xml.to_string(), Box::new(&mut testhandler))
- .expect("Failed to parse test xml");
- assert_eq!(testhandler.start_document_called, 1);
- assert_eq!(testhandler.start_element_called, 1);
- assert!(!testhandler.elements.is_empty());
- assert_eq!(testhandler.elements[0], "");
- assert_eq!(testhandler.end_document_called, 1);
- }
-
- #[test]
- fn test_single_element_single_attribute() {
- let test_xml = include_str!("test/element_with_attribute.xml");
- let mut testhandler = TestHandler::new();
- parse_string(test_xml.to_string(), Box::new(&mut testhandler))
- .expect("Failed to parse test xml");
- assert_eq!(testhandler.start_document_called, 1);
- assert_eq!(testhandler.start_element_called, 1);
- assert!(!testhandler.elements.is_empty());
- assert_eq!(testhandler.elements[0], r#""#);
- assert_eq!(testhandler.end_element_called, 1);
- assert_eq!(testhandler.end_document_called, 1);
- }
-
- #[test]
- fn test_ignore_comment() {
- let test_xml = include_str!("test/comment.xml");
- let mut testhandler = TestHandler::new();
- parse_string(test_xml.to_string(), Box::new(&mut testhandler))
- .expect("Failed to parse test xml");
- assert_eq!(testhandler.start_document_called, 1);
- assert_eq!(testhandler.start_element_called, 1);
- assert!(!testhandler.elements.is_empty());
- assert_eq!(
- testhandler.elements[0],
- r#""#
- );
- assert_eq!(testhandler.end_element_called, 1);
- assert_eq!(testhandler.end_document_called, 1);
- }
-
- #[test]
- fn test_bad_comment() {
- let test_xml = include_str!("test/illegal_dashes_comment.xml");
- let mut testhandler = TestHandler::new();
- match parse_string(test_xml.to_string(), Box::new(&mut testhandler)){
- Err(e)=> assert_eq!(e, SaxError::BadCharacter),
- Ok(_) => assert!(false),
- }
-
- }
-
- #[test]
- fn test_namespaces() {
- let test_xml = include_str!("test/namespaces.xml");
- let mut testhandler = TestHandler::new();
- parse_string(test_xml.to_string(), Box::new(&mut testhandler))
- .expect("Failed to parse test xml");
- assert_eq!(testhandler.start_document_called, 1);
- assert_eq!(testhandler.start_element_called, 4);
- assert!(!testhandler.elements.is_empty());
- assert_eq!(
- testhandler.elements[0],
- r#""#
- );
- assert_eq!(
- testhandler.elements[1],
- r#""#
- );
- assert_eq!(
- testhandler.elements[2],
- r#""#
- );
- assert_eq!(
- testhandler.elements[3],
- r#""#
- );
- assert_eq!(testhandler.end_element_called, 4);
- assert_eq!(testhandler.end_document_called, 1);
- }
-}
-
-#[derive(Debug)]
-struct TestHandler {
- start_document_called: usize,
- end_document_called: usize,
- start_element_called: usize,
- end_element_called: usize,
- elements: Vec,
-}
-
-impl TestHandler {
- pub fn new() -> Self {
- Self {
- start_document_called: 0,
- end_document_called: 0,
- start_element_called: 0,
- end_element_called: 0,
- elements: vec![],
- }
- }
-}
-
-impl SaxHandler for TestHandler {
- fn start_document(&mut self) {
- self.start_document_called += 1;
- }
-
- fn end_document(&mut self) {
- self.end_document_called += 1;
- }
-
- fn start_prefix_mapping(&mut self, _prefix: &str, _uri: &str) {
- todo!()
- }
-
- fn end_prefix_mapping(&mut self, _prefix: &str, _uri: &str) {
- todo!()
- }
-
- fn start_element(
- &mut self,
- uri: Option,
- local_name: &str,
- _qualified_name: &str,
- attributes: Vec,
- ) {
- self.start_element_called += 1;
- let atts = attributes
- .iter()
- .map(|att| format!(r#"{}="{}""#, att.name, att.value))
- .collect::>()
- .join(" ");
-
- let uri = if let Some(uri) = uri {
- format!("{}:", uri)
- } else {
- "".to_string()
- };
-
- let divider = if atts.is_empty() { "" } else { " " };
- self.elements
- .push(format!("<{}{}{}{}>", uri, local_name, divider, atts));
- }
-
- fn end_element(&mut self, _uri: Option, _local_name: &str, _qualified_name: &str) {
- self.end_element_called += 1;
- }
-
- fn characters(&mut self, _chars: &[char]) {
- todo!()
- }
-
- fn error(&mut self, _error: &str) {
- todo!()
- }
-}
diff --git a/src/maven/xml/debug.rs b/src/xml/debug.rs
similarity index 91%
rename from src/maven/xml/debug.rs
rename to src/xml/debug.rs
index 67641e1..89030b0 100644
--- a/src/maven/xml/debug.rs
+++ b/src/xml/debug.rs
@@ -1,5 +1,5 @@
use log::debug;
-use crate::maven::xml::SaxHandler;
+use crate::xml::SaxHandler;
pub struct DebugHandler {}
@@ -21,7 +21,7 @@ impl SaxHandler for DebugHandler {
_uri: Option,
local_name: &str,
_qualified_name: &str,
- attributes: Vec,
+ attributes: Vec,
) {
debug!("start_element {}, {:?}", local_name, attributes);
}
diff --git a/src/maven/xml/mod.rs b/src/xml/mod.rs
similarity index 82%
rename from src/maven/xml/mod.rs
rename to src/xml/mod.rs
index 221c9d5..8c9af14 100644
--- a/src/maven/xml/mod.rs
+++ b/src/xml/mod.rs
@@ -1,12 +1,11 @@
-mod sax_parser;
-mod sax_parser_test;
+pub mod sax_parser;
mod debug;
#[derive(Debug)]
pub struct Attribute {
- name: String,
- namespace: Option,
- value: String,
+ pub name: String,
+ pub namespace: Option,
+ pub value: String,
}
pub trait SaxHandler {
@@ -33,6 +32,7 @@ pub enum SaxError {
BadCharacter,
UnexpectedEof,
UnexpectedCharacter(String),
+ UndeclaredNamespacePrefix(String),
}
impl fmt::Display for SaxError {
@@ -41,6 +41,7 @@ impl fmt::Display for SaxError {
SaxError::BadCharacter => write!(f, "Bad character"),
SaxError::UnexpectedEof => write!(f, "Unexpected end of document"),
SaxError::UnexpectedCharacter(c) => write!(f, "Unexpected character {}",c),
+ SaxError::UndeclaredNamespacePrefix(prefix) => write!(f, "Undeclared namespace prefix{}", prefix),
}
}
}
diff --git a/src/maven/xml/sax_parser.rs b/src/xml/sax_parser.rs
similarity index 79%
rename from src/maven/xml/sax_parser.rs
rename to src/xml/sax_parser.rs
index c52e594..2f0c3ea 100644
--- a/src/maven/xml/sax_parser.rs
+++ b/src/xml/sax_parser.rs
@@ -1,17 +1,17 @@
-use crate::maven::xml::{Attribute, SaxError, SaxHandler};
-use anyhow::anyhow;
+use crate::xml::{Attribute, SaxError, SaxHandler};
+use std::collections::HashMap;
pub fn parse_string(xml: String, handler: Box<&mut dyn SaxHandler>) -> Result<(), SaxError> {
- let mut parser = SAXParser::new(xml, handler);
- parser.parse()
+ SAXParser::new(xml, handler).parse()
}
-struct SAXParser<'a> {
+pub struct SAXParser<'a> {
xml: Vec,
handler: Box<&'a mut dyn SaxHandler>,
position: usize,
current: char,
namespace_stack: Vec<(String, isize)>,
+ prefix_mapping: HashMap,
}
impl<'a> SAXParser<'a> {
@@ -22,6 +22,7 @@ impl<'a> SAXParser<'a> {
position: 0,
current: '\0',
namespace_stack: Vec::new(),
+ prefix_mapping: HashMap::new(),
}
}
@@ -36,7 +37,7 @@ impl<'a> SAXParser<'a> {
self.parse_elements()
}
- fn parse_elements(&mut self) -> Result<(), SaxError> {
+ fn parse_elements(&mut self) -> Result<(), SaxError> {
while self.position < self.xml.len() {
if self.current == '<' {
self.advance()?;
@@ -80,7 +81,8 @@ impl<'a> SAXParser<'a> {
}
fn parse_start_element(&mut self) -> Result<(), SaxError> {
- let name = self.read_until(" \t\n/>")?;
+ let qname = self.read_until(" \t\n/>")?;
+
let mut atts = vec![];
let mut c = self.current;
@@ -90,21 +92,38 @@ impl<'a> SAXParser<'a> {
c = self.advance()?;
}
- let namespace = if !self.namespace_stack.is_empty() {
+ let (namespace, lname) = if qname.contains(":") {
+ let tokens = qname.splitn(2, ":").collect::>();
+ let prefix = tokens[0].to_string();
+ let name = tokens[1].to_string();
+ let namespace = self.prefix_mapping.get(&prefix);
+ if let Some(namespace) = namespace {
+ (Some(namespace.to_string()), name)
+ } else {
+ return Err(SaxError::UndeclaredNamespacePrefix(prefix));
+ }
+ } else if !self.namespace_stack.is_empty() {
let (name, count) = self.namespace_stack.pop().unwrap();
self.namespace_stack.push((name.clone(), count + 1));
- Some(name.clone())
+ (Some(name.clone()), qname)
} else {
- None
+ (None, qname)
+ };
+
+ let qualified_name = if let Some(namespace) = &namespace{
+ &format!("{}:{}", namespace.clone(), &lname)
+ } else {
+ &lname
};
self.handler
- .start_element(namespace.clone(), name.as_str(), "", atts);
+ .start_element(namespace.clone(), lname.as_str(), qualified_name, atts);
self.skip_whitespace()?;
+
if self.current == '/' {
self.advance()?;
let namespace = self.pop_namespace();
- self.handler.end_element(namespace, name.as_str(), "");
+ self.handler.end_element(namespace, lname.as_str(), qualified_name);
}
self.expect_char('>')?;
self.skip_whitespace()?;
@@ -118,6 +137,11 @@ impl<'a> SAXParser<'a> {
self.expect("\"", "Expected start of attribute value")?;
let att_value = self.read_until("\"")?;
+ if att_name.starts_with("xmlns:") {
+ let prefix = att_name[6..].to_string();
+ self.prefix_mapping.insert(prefix, att_value.to_string());
+ }
+
let namespace = if att_name == "xmlns" {
self.namespace_stack.push((att_value.clone(), -1));
Some(att_value.clone())
@@ -200,7 +224,7 @@ impl<'a> SAXParser<'a> {
fn expect(&mut self, expected: &str, message: &str) -> Result<(), SaxError> {
for c in expected.chars() {
if !self.expect_char(c)? {
- return Err(SaxError::UnexpectedCharacter(message.to_string()))
+ return Err(SaxError::UnexpectedCharacter(message.to_string()));
}
}
Ok(())
@@ -216,4 +240,4 @@ impl<'a> SAXParser<'a> {
}
Ok(same)
}
-}
\ No newline at end of file
+}
diff --git a/tests/mod.rs b/tests/mod.rs
new file mode 100644
index 0000000..d1be782
--- /dev/null
+++ b/tests/mod.rs
@@ -0,0 +1 @@
+mod xml;
\ No newline at end of file
diff --git a/tests/pom/pom.xml b/tests/pom/pom.xml
new file mode 100644
index 0000000..5894332
--- /dev/null
+++ b/tests/pom/pom.xml
@@ -0,0 +1,40 @@
+
+
+ 4.0.0
+ org.mockito
+ mockito-core
+ 1.9.5
+ Mockito
+ jar
+ http://www.mockito.org
+ Mock objects library for java
+
+
+ The MIT License
+ http://code.google.com/p/mockito/wiki/License
+ repo
+
+
+
+ http://code.google.com/p/mockito/source/browse/
+
+
+
+ szczepiq
+ Szczepan Faber
+
+
+
+
+ org.hamcrest
+ hamcrest-core
+ 1.1
+
+
+ org.objenesis
+ objenesis
+ 1.0
+
+
+
\ No newline at end of file
diff --git a/tests/xml/mod.rs b/tests/xml/mod.rs
new file mode 100644
index 0000000..c05eada
--- /dev/null
+++ b/tests/xml/mod.rs
@@ -0,0 +1 @@
+mod sax_parser_test;
\ No newline at end of file
diff --git a/src/maven/xml/test/comment.xml b/tests/xml/resources/comment.xml
similarity index 100%
rename from src/maven/xml/test/comment.xml
rename to tests/xml/resources/comment.xml
diff --git a/src/maven/xml/test/element.xml b/tests/xml/resources/element.xml
similarity index 100%
rename from src/maven/xml/test/element.xml
rename to tests/xml/resources/element.xml
diff --git a/src/maven/xml/test/element_with_attribute.xml b/tests/xml/resources/element_with_attribute.xml
similarity index 100%
rename from src/maven/xml/test/element_with_attribute.xml
rename to tests/xml/resources/element_with_attribute.xml
diff --git a/src/maven/xml/test/full.xml b/tests/xml/resources/full.xml
similarity index 100%
rename from src/maven/xml/test/full.xml
rename to tests/xml/resources/full.xml
diff --git a/src/maven/xml/test/header.xml b/tests/xml/resources/header.xml
similarity index 100%
rename from src/maven/xml/test/header.xml
rename to tests/xml/resources/header.xml
diff --git a/src/maven/xml/test/illegal_dashes_comment.xml b/tests/xml/resources/illegal_dashes_comment.xml
similarity index 100%
rename from src/maven/xml/test/illegal_dashes_comment.xml
rename to tests/xml/resources/illegal_dashes_comment.xml
diff --git a/tests/xml/resources/namespaces-prefix.xml b/tests/xml/resources/namespaces-prefix.xml
new file mode 100644
index 0000000..e4e24d1
--- /dev/null
+++ b/tests/xml/resources/namespaces-prefix.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
diff --git a/src/maven/xml/test/namespaces.xml b/tests/xml/resources/namespaces.xml
similarity index 100%
rename from src/maven/xml/test/namespaces.xml
rename to tests/xml/resources/namespaces.xml
diff --git a/tests/xml/sax_parser_test.rs b/tests/xml/sax_parser_test.rs
new file mode 100644
index 0000000..d77bc63
--- /dev/null
+++ b/tests/xml/sax_parser_test.rs
@@ -0,0 +1,197 @@
+use undeepend::xml::sax_parser::parse_string;
+use undeepend::xml::{Attribute, SaxError, SaxHandler};
+
+#[test]
+fn test_xml_header() {
+ let test_xml = include_str!("resources/header.xml");
+ let mut testhandler = TestHandler::new();
+ parse_string(test_xml.to_string(), Box::new(&mut testhandler))
+ .expect("Failed to parse test xml");
+ println!("{:?}", testhandler);
+ assert_eq!(testhandler.start_document_called, 1);
+ assert_eq!(testhandler.end_document_called, 1);
+}
+
+#[test]
+fn test_single_element_short() {
+ let test_xml = include_str!("resources/header.xml");
+ let mut testhandler = TestHandler::new();
+ parse_string(test_xml.to_string(), Box::new(&mut testhandler))
+ .expect("Failed to parse test xml");
+ assert_eq!(testhandler.start_document_called, 1);
+ assert_eq!(testhandler.start_element_called, 1);
+ assert!(!testhandler.elements.is_empty());
+ assert_eq!(testhandler.elements[0], "");
+ assert_eq!(testhandler.end_document_called, 1);
+}
+
+#[test]
+fn test_single_element() {
+ let test_xml = include_str!("resources/element.xml");
+ let mut testhandler = TestHandler::new();
+ parse_string(test_xml.to_string(), Box::new(&mut testhandler))
+ .expect("Failed to parse test xml");
+ assert_eq!(testhandler.start_document_called, 1);
+ assert_eq!(testhandler.start_element_called, 1);
+ assert!(!testhandler.elements.is_empty());
+ assert_eq!(testhandler.elements[0], "");
+ assert_eq!(testhandler.end_document_called, 1);
+}
+
+#[test]
+fn test_single_element_single_attribute() {
+ let test_xml = include_str!("resources/element_with_attribute.xml");
+ let mut testhandler = TestHandler::new();
+ parse_string(test_xml.to_string(), Box::new(&mut testhandler))
+ .expect("Failed to parse test xml");
+ assert_eq!(testhandler.start_document_called, 1);
+ assert_eq!(testhandler.start_element_called, 1);
+ assert!(!testhandler.elements.is_empty());
+ assert_eq!(testhandler.elements[0], r#""#);
+ assert_eq!(testhandler.end_element_called, 1);
+ assert_eq!(testhandler.end_document_called, 1);
+}
+
+#[test]
+fn test_ignore_comment() {
+ let test_xml = include_str!("resources/comment.xml");
+ let mut testhandler = TestHandler::new();
+ parse_string(test_xml.to_string(), Box::new(&mut testhandler))
+ .expect("Failed to parse test xml");
+ assert_eq!(testhandler.start_document_called, 1);
+ assert_eq!(testhandler.start_element_called, 1);
+ assert!(!testhandler.elements.is_empty());
+ assert_eq!(
+ testhandler.elements[0],
+ r#""#
+ );
+ assert_eq!(testhandler.end_element_called, 1);
+ assert_eq!(testhandler.end_document_called, 1);
+}
+
+#[test]
+fn test_bad_comment() {
+ let test_xml = include_str!("resources/illegal_dashes_comment.xml");
+ let mut testhandler = TestHandler::new();
+ match parse_string(test_xml.to_string(), Box::new(&mut testhandler)) {
+ Err(e) => assert_eq!(e, SaxError::BadCharacter),
+ Ok(_) => assert!(false),
+ }
+}
+
+#[test]
+fn test_namespaces() {
+ let test_xml = include_str!("resources/namespaces.xml");
+ let mut testhandler = TestHandler::new();
+ parse_string(test_xml.to_string(), Box::new(&mut testhandler))
+ .expect("Failed to parse test xml");
+ assert_eq!(testhandler.start_document_called, 1);
+ assert_eq!(testhandler.start_element_called, 4);
+ assert!(!testhandler.elements.is_empty());
+ assert_eq!(testhandler.elements[0], r#""#);
+ assert_eq!(
+ testhandler.elements[1],
+ r#""#
+ );
+ assert_eq!(
+ testhandler.elements[2],
+ r#""#
+ );
+ assert_eq!(testhandler.elements[3], r#""#);
+ assert_eq!(testhandler.end_element_called, 4);
+ assert_eq!(testhandler.end_document_called, 1);
+}
+
+#[test]
+fn test_namespace_prefixes() {
+ let test_xml = include_str!("resources/namespaces-prefix.xml");
+ let mut testhandler = TestHandler::new();
+ parse_string(test_xml.to_string(), Box::new(&mut testhandler))
+ .expect("Failed to parse test xml");
+ assert_eq!(testhandler.start_document_called, 1);
+ assert_eq!(testhandler.start_element_called, 5);
+ assert!(!testhandler.elements.is_empty());
+ assert_eq!(testhandler.elements[0], r#""#);
+ assert_eq!(
+ testhandler.elements[1],
+ r#""#
+ );
+ assert_eq!(
+ testhandler.elements[2],
+ r#""#
+ );
+ assert_eq!(testhandler.elements[3], r#""#);
+ assert_eq!(testhandler.elements[4], r#""#);
+ assert_eq!(testhandler.end_element_called, 5);
+ assert_eq!(testhandler.end_document_called, 1);
+}
+
+#[derive(Debug)]
+struct TestHandler {
+ start_document_called: usize,
+ end_document_called: usize,
+ start_element_called: usize,
+ end_element_called: usize,
+ elements: Vec,
+}
+
+impl TestHandler {
+ pub fn new() -> Self {
+ Self {
+ start_document_called: 0,
+ end_document_called: 0,
+ start_element_called: 0,
+ end_element_called: 0,
+ elements: vec![],
+ }
+ }
+}
+
+impl SaxHandler for TestHandler {
+ fn start_document(&mut self) {
+ self.start_document_called += 1;
+ }
+
+ fn end_document(&mut self) {
+ self.end_document_called += 1;
+ }
+
+ fn start_prefix_mapping(&mut self, _prefix: &str, _uri: &str) {
+ todo!()
+ }
+
+ fn end_prefix_mapping(&mut self, _prefix: &str, _uri: &str) {
+ todo!()
+ }
+
+ fn start_element(
+ &mut self,
+ uri: Option,
+ _local_name: &str,
+ qualified_name: &str,
+ attributes: Vec,
+ ) {
+ self.start_element_called += 1;
+ let atts = attributes
+ .iter()
+ .map(|att| format!(r#"{}="{}""#, att.name, att.value))
+ .collect::>()
+ .join(" ");
+
+ let divider = if atts.is_empty() { "" } else { " " };
+ self.elements
+ .push(format!("<{}{}{}>", qualified_name, divider, atts));
+ }
+
+ fn end_element(&mut self, _uri: Option, _local_name: &str, _qualified_name: &str) {
+ self.end_element_called += 1;
+ }
+
+ fn characters(&mut self, _chars: &[char]) {
+ todo!()
+ }
+
+ fn error(&mut self, _error: &str) {
+ todo!()
+ }
+}