• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

kaidokert / xacro / 20655671689

02 Jan 2026 10:13AM UTC coverage: 85.776%. First build
20655671689

Pull #10

github

web-flow
Merge ef8b6d016 into f43e4ad58
Pull Request #10: Fix namespace output handling

43 of 56 new or added lines in 3 files covered. (76.79%)

995 of 1160 relevant lines covered (85.78%)

64.39 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

69.49
/src/processor.rs
1
use crate::{
2
    error::XacroError,
3
    features::{
4
        conditions::ConditionProcessor, includes::IncludeProcessor, loops::LoopProcessor,
5
        macros::MacroProcessor, properties::PropertyProcessor,
6
    },
7
};
8

9
pub struct XacroProcessor {
10
    macros: MacroProcessor,
11
    properties: PropertyProcessor,
12
    conditions: ConditionProcessor,
13
    loops: LoopProcessor,
14
    includes: IncludeProcessor,
15
}
16

17
impl XacroProcessor {
18
    #[allow(clippy::new_without_default)]
19
    pub fn new() -> Self {
7✔
20
        Self {
7✔
21
            includes: IncludeProcessor::new(),
7✔
22
            macros: MacroProcessor::new(),
7✔
23
            properties: PropertyProcessor::new(),
7✔
24
            conditions: ConditionProcessor::new(),
7✔
25
            loops: LoopProcessor::new(),
7✔
26
        }
7✔
27
    }
7✔
28

29
    /// Process xacro content from a file path
30
    pub fn run<P: AsRef<std::path::Path>>(
×
31
        &self,
×
32
        path: P,
×
33
    ) -> Result<String, XacroError> {
×
34
        let xml = XacroProcessor::parse_file(&path)?;
×
NEW
35
        self.run_impl(xml, path.as_ref())
×
NEW
36
    }
×
37

38
    /// Process xacro content from a string
39
    ///
40
    /// # Note
41
    /// Any `<xacro:include>` directives with relative paths will be resolved
42
    /// relative to the current working directory.
43
    pub fn run_from_string(
7✔
44
        &self,
7✔
45
        content: &str,
7✔
46
    ) -> Result<String, XacroError> {
7✔
47
        let xml = xmltree::Element::parse(content.as_bytes())?;
7✔
48
        // Use current directory as base path for any includes in test content
49
        self.run_impl(xml, std::path::Path::new("."))
7✔
50
    }
7✔
51

52
    /// Internal implementation
53
    fn run_impl(
7✔
54
        &self,
7✔
55
        xml: xmltree::Element,
7✔
56
        base_path: &std::path::Path,
7✔
57
    ) -> Result<String, XacroError> {
7✔
58
        // Process features in order
59
        let xml = self.includes.process(xml, base_path)?;
7✔
60

61
        // The HashMap contains all properties for use by subsequent processors
62
        let (xml, properties) = self.properties.process(xml)?;
7✔
63

64
        // Pass properties to MacroProcessor so macros can reference global properties
65
        let xml = self.macros.process(xml, &properties)?;
7✔
66

67
        // Pass properties to ConditionProcessor for expression evaluation
68
        let xml = self.conditions.process(xml, &properties)?;
3✔
69
        let mut xml = self.loops.process(xml)?;
3✔
70

71
        // Final cleanup: check for unprocessed xacro:* elements and remove xacro namespace
72
        // Does both in a single recursive pass for efficiency
73
        Self::finalize_tree(&mut xml)?;
3✔
74

75
        XacroProcessor::serialize(xml)
3✔
76
    }
7✔
77

78
    fn finalize_tree(element: &mut xmltree::Element) -> Result<(), XacroError> {
20✔
79
        // Check if this element is in the xacro namespace (indicates unprocessed feature)
80
        // Must check namespace URI, not prefix, to handle namespace aliasing (e.g., xmlns:x="...")
81
        use crate::utils::xml::XACRO_NAMESPACE;
82
        if element.namespace.as_deref() == Some(XACRO_NAMESPACE) {
20✔
83
            // Use centralized feature lists for consistent error messages
84
            use crate::error::{IMPLEMENTED_FEATURES, UNIMPLEMENTED_FEATURES};
NEW
85
            return Err(XacroError::UnimplementedFeature(format!(
×
NEW
86
                "<xacro:{}>\n\
×
NEW
87
                     This element was not processed. Either:\n\
×
NEW
88
                     1. The feature is not implemented yet (known unimplemented: {})\n\
×
NEW
89
                     2. There's a bug in the processor\n\
×
NEW
90
                     \n\
×
NEW
91
                     Currently implemented: {}",
×
NEW
92
                element.name,
×
NEW
93
                UNIMPLEMENTED_FEATURES.join(", "),
×
NEW
94
                IMPLEMENTED_FEATURES.join(", ")
×
NEW
95
            )));
×
96
        }
20✔
97

98
        // Remove xacro namespace declaration
99
        // Keep all other namespaces (gazebo, ignition, etc.)
100
        if let Some(ref mut ns) = element.namespaces {
20✔
101
            ns.0.remove("xacro");
20✔
102
        }
20✔
103

104
        // Recursively process children
105
        for child in &mut element.children {
39✔
106
            if let Some(child_elem) = child.as_mut_element() {
19✔
107
                Self::finalize_tree(child_elem)?;
17✔
108
            }
2✔
109
        }
110

111
        Ok(())
20✔
112
    }
20✔
113
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc