pub trait Visualizable {
fn to_dot(&self) -> crate::result::hex_result::HexResult<String>;
fn to_mermaid(&self) -> crate::result::hex_result::HexResult<String>;
fn to_ascii_art(&self) -> String;
}
impl Visualizable for crate::graph::hex_graph::HexGraph {
fn to_dot(&self) -> crate::result::hex_result::HexResult<String> {
#[cfg(feature = "visualization")]
{
crate::graph::hex_graph::HexGraph::to_dot(self)
}
#[cfg(not(feature = "visualization"))]
{
std::result::Result::Err(
crate::error::hex_error::Hexserror::port(
"E_HEX_VIZ_001",
"DOT export requires the `visualization` feature, which is not enabled",
)
.with_next_step("Enable the `visualization` feature on the hexser dependency"),
)
}
}
fn to_mermaid(&self) -> crate::result::hex_result::HexResult<String> {
#[cfg(feature = "visualization")]
{
crate::graph::hex_graph::HexGraph::to_mermaid(self)
}
#[cfg(not(feature = "visualization"))]
{
std::result::Result::Err(
crate::error::hex_error::Hexserror::port(
"E_HEX_VIZ_002",
"Mermaid export requires the `visualization` feature, which is not enabled",
)
.with_next_step("Enable the `visualization` feature on the hexser dependency"),
)
}
}
fn to_ascii_art(&self) -> String {
let mut output = String::new();
output.push_str("Architecture:\n");
for layer in [
crate::graph::layer::Layer::Application,
crate::graph::layer::Layer::Port,
crate::graph::layer::Layer::Adapter,
crate::graph::layer::Layer::Domain,
crate::graph::layer::Layer::Infrastructure,
] {
let nodes = self.nodes_by_layer(layer);
if !nodes.is_empty() {
output.push_str(&format!("\n{layer:?} Layer:\n"));
for node in nodes {
output.push_str(&format!(" └─ {}\n", node.type_name));
}
}
}
output
}
}
#[cfg(test)]
mod tests {
use super::*;
fn sample_graph() -> crate::graph::hex_graph::HexGraph {
crate::graph::builder::GraphBuilder::new()
.add_node(crate::graph::hex_node::HexNode::new(
crate::graph::node_id::NodeId::from_name("Test"),
crate::graph::layer::Layer::Domain,
crate::graph::role::Role::Entity,
"Test",
"test",
))
.build()
}
#[test]
#[cfg(feature = "visualization")]
fn test_visualizable_trait_enabled() {
let graph = sample_graph();
let ascii = graph.to_ascii_art();
assert!(ascii.contains("Domain Layer"));
assert!(ascii.contains("Test"));
assert!(Visualizable::to_dot(&graph).is_ok());
assert!(Visualizable::to_mermaid(&graph).is_ok());
assert!(graph.to_json().is_ok());
}
#[test]
#[cfg(not(feature = "visualization"))]
fn test_visualizable_trait_disabled_returns_error_not_stack_overflow() {
let graph = sample_graph();
assert!(graph.to_ascii_art().contains("Domain Layer"));
let dot = Visualizable::to_dot(&graph);
let mermaid = Visualizable::to_mermaid(&graph);
assert!(
dot.is_err(),
"to_dot must error, not recurse, when feature is off"
);
assert!(
mermaid.is_err(),
"to_mermaid must error, not recurse, when feature is off"
);
}
}