mirror of
https://gitlab.freedesktop.org/dabrain34/GstPipelineStudio.git
synced 2024-12-24 08:50:29 +00:00
graphview: implement tests infra
- Implement test for graph creation, save and load. - Change xml API - Update public/private api - Add a graphview clear API
This commit is contained in:
parent
9cc40d2b7b
commit
d19387f039
5 changed files with 282 additions and 116 deletions
|
@ -18,7 +18,7 @@ variables:
|
||||||
variables:
|
variables:
|
||||||
FDO_DISTRIBUTION_VERSION: "35"
|
FDO_DISTRIBUTION_VERSION: "35"
|
||||||
# Update this to trigger a container rebuild
|
# Update this to trigger a container rebuild
|
||||||
FDO_DISTRIBUTION_TAG: "2022-01-07.2"
|
FDO_DISTRIBUTION_TAG: "2022-01-27.2"
|
||||||
|
|
||||||
build-fedora-container:
|
build-fedora-container:
|
||||||
extends:
|
extends:
|
||||||
|
@ -42,6 +42,8 @@ build-fedora-container:
|
||||||
python3-devel
|
python3-devel
|
||||||
python3-pip
|
python3-pip
|
||||||
python3-setuptools
|
python3-setuptools
|
||||||
|
util-linux
|
||||||
|
xorg-x11-server-Xvfb
|
||||||
FDO_DISTRIBUTION_EXEC: >-
|
FDO_DISTRIBUTION_EXEC: >-
|
||||||
pip3 install meson
|
pip3 install meson
|
||||||
|
|
||||||
|
@ -64,7 +66,9 @@ test-stable:
|
||||||
- meson build
|
- meson build
|
||||||
- rustc --version
|
- rustc --version
|
||||||
- cargo build --color=always --all-targets
|
- cargo build --color=always --all-targets
|
||||||
- cargo test --color=always
|
- >
|
||||||
|
xvfb-run -a -s "-screen 0 1024x768x24"
|
||||||
|
cargo test --color=always
|
||||||
|
|
||||||
rustdoc:
|
rustdoc:
|
||||||
extends:
|
extends:
|
||||||
|
|
2
Cargo.lock
generated
2
Cargo.lock
generated
|
@ -481,6 +481,8 @@ name = "gst_pipeline_studio"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
|
"futures-channel",
|
||||||
|
"futures-executor",
|
||||||
"gettext-rs",
|
"gettext-rs",
|
||||||
"gstreamer",
|
"gstreamer",
|
||||||
"gtk4",
|
"gtk4",
|
||||||
|
|
|
@ -17,3 +17,7 @@ x11 = { version = "2.18", features = ["xlib"] }
|
||||||
serde = "1.0"
|
serde = "1.0"
|
||||||
serde_any = "0.5"
|
serde_any = "0.5"
|
||||||
simplelog = "0.11.2"
|
simplelog = "0.11.2"
|
||||||
|
futures-channel = "0.3"
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
futures-executor = "0.3"
|
|
@ -33,8 +33,7 @@ use super::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use std::fs::File;
|
use std::io::Cursor;
|
||||||
use std::io::BufReader;
|
|
||||||
|
|
||||||
use gtk::{
|
use gtk::{
|
||||||
gdk::{BUTTON_PRIMARY, BUTTON_SECONDARY},
|
gdk::{BUTTON_PRIMARY, BUTTON_SECONDARY},
|
||||||
|
@ -494,11 +493,52 @@ impl GraphView {
|
||||||
private.id.set(id)
|
private.id.set(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Retrives the graphview id
|
||||||
|
///
|
||||||
pub fn id(&self) -> u32 {
|
pub fn id(&self) -> u32 {
|
||||||
let private = imp::GraphView::from_instance(self);
|
let private = imp::GraphView::from_instance(self);
|
||||||
private.id.get()
|
private.id.get()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Clear the graphview
|
||||||
|
///
|
||||||
|
pub fn clear(&self) {
|
||||||
|
self.remove_all_nodes();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Node
|
||||||
|
|
||||||
|
/// Create a new node with a new id
|
||||||
|
///
|
||||||
|
pub fn create_node(&self, name: &str, node_type: NodeType) -> Node {
|
||||||
|
let id = self.next_node_id();
|
||||||
|
self.create_node_with_id(id, name, node_type)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a new node and add it to the graphview with input/output port number.
|
||||||
|
///
|
||||||
|
pub fn create_node_with_port(
|
||||||
|
&self,
|
||||||
|
name: &str,
|
||||||
|
node_type: NodeType,
|
||||||
|
input: u32,
|
||||||
|
output: u32,
|
||||||
|
) -> Node {
|
||||||
|
let mut node = self.create_node(name, node_type);
|
||||||
|
|
||||||
|
let _i = 0;
|
||||||
|
for _i in 0..input {
|
||||||
|
let port = self.create_port("in", PortDirection::Input, PortPresence::Always);
|
||||||
|
self.add_port_to_node(&mut node, port);
|
||||||
|
}
|
||||||
|
let _i = 0;
|
||||||
|
for _i in 0..output {
|
||||||
|
let port = self.create_port("out", PortDirection::Output, PortPresence::Always);
|
||||||
|
self.add_port_to_node(&mut node, port);
|
||||||
|
}
|
||||||
|
node
|
||||||
|
}
|
||||||
|
|
||||||
/// Add node to the graphview without port
|
/// Add node to the graphview without port
|
||||||
///
|
///
|
||||||
pub fn add_node(&self, node: Node) {
|
pub fn add_node(&self, node: Node) {
|
||||||
|
@ -541,40 +581,6 @@ impl GraphView {
|
||||||
self.emit_by_name::<()>("node-added", &[&private.id.get(), &node_id]);
|
self.emit_by_name::<()>("node-added", &[&private.id.get(), &node_id]);
|
||||||
self.graph_updated();
|
self.graph_updated();
|
||||||
}
|
}
|
||||||
/// Create a new node with id
|
|
||||||
///
|
|
||||||
pub fn create_node_with_id(&self, id: u32, name: &str, node_type: NodeType) -> Node {
|
|
||||||
Node::new(id, name, node_type)
|
|
||||||
}
|
|
||||||
/// Create a new node with a new id
|
|
||||||
///
|
|
||||||
pub fn create_node(&self, name: &str, node_type: NodeType) -> Node {
|
|
||||||
let id = self.next_node_id();
|
|
||||||
self.create_node_with_id(id, name, node_type)
|
|
||||||
}
|
|
||||||
/// Create a new node and add it to the graphview with input/output port number.
|
|
||||||
///
|
|
||||||
pub fn create_node_with_port(
|
|
||||||
&self,
|
|
||||||
name: &str,
|
|
||||||
node_type: NodeType,
|
|
||||||
input: u32,
|
|
||||||
output: u32,
|
|
||||||
) -> Node {
|
|
||||||
let mut node = self.create_node(name, node_type);
|
|
||||||
|
|
||||||
let _i = 0;
|
|
||||||
for _i in 0..input {
|
|
||||||
let port = self.create_port("in", PortDirection::Input, PortPresence::Always);
|
|
||||||
self.add_port_to_node(&mut node, port);
|
|
||||||
}
|
|
||||||
let _i = 0;
|
|
||||||
for _i in 0..output {
|
|
||||||
let port = self.create_port("out", PortDirection::Output, PortPresence::Always);
|
|
||||||
self.add_port_to_node(&mut node, port);
|
|
||||||
}
|
|
||||||
node
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Remove node from the graphview
|
/// Remove node from the graphview
|
||||||
///
|
///
|
||||||
|
@ -644,19 +650,28 @@ impl GraphView {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the position of the specified node inside the graphview.
|
||||||
|
///
|
||||||
|
/// Returns `None` if the node is not in the graphview.
|
||||||
|
pub(super) fn node_position(&self, node: >k::Widget) -> Option<(f32, f32)> {
|
||||||
|
let layout_manager = self
|
||||||
|
.layout_manager()
|
||||||
|
.expect("Failed to get layout manager")
|
||||||
|
.dynamic_cast::<gtk::FixedLayout>()
|
||||||
|
.expect("Failed to cast to FixedLayout");
|
||||||
|
|
||||||
|
let node = layout_manager
|
||||||
|
.layout_child(node)
|
||||||
|
.dynamic_cast::<gtk::FixedLayoutChild>()
|
||||||
|
.expect("Could not cast to FixedLayoutChild");
|
||||||
|
let transform = node
|
||||||
|
.transform()
|
||||||
|
.expect("Failed to obtain transform from layout child");
|
||||||
|
Some(transform.to_translate())
|
||||||
|
}
|
||||||
|
|
||||||
// Port
|
// Port
|
||||||
|
|
||||||
/// Create a new port with id
|
|
||||||
///
|
|
||||||
pub fn create_port_with_id(
|
|
||||||
&self,
|
|
||||||
id: u32,
|
|
||||||
name: &str,
|
|
||||||
direction: PortDirection,
|
|
||||||
presence: PortPresence,
|
|
||||||
) -> Port {
|
|
||||||
Port::new(id, name, direction, presence)
|
|
||||||
}
|
|
||||||
/// Create a new port with a new id
|
/// Create a new port with a new id
|
||||||
///
|
///
|
||||||
pub fn create_port(
|
pub fn create_port(
|
||||||
|
@ -721,26 +736,7 @@ impl GraphView {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Link
|
// Link
|
||||||
/// Create a new link with id
|
|
||||||
pub fn create_link_with_id(
|
|
||||||
&self,
|
|
||||||
link_id: u32,
|
|
||||||
node_from_id: u32,
|
|
||||||
node_to_id: u32,
|
|
||||||
port_from_id: u32,
|
|
||||||
port_to_id: u32,
|
|
||||||
active: bool,
|
|
||||||
) -> Link {
|
|
||||||
Link::new(
|
|
||||||
link_id,
|
|
||||||
node_from_id,
|
|
||||||
node_to_id,
|
|
||||||
port_from_id,
|
|
||||||
port_to_id,
|
|
||||||
active,
|
|
||||||
false,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
/// Create a new link with a new id
|
/// Create a new link with a new id
|
||||||
///
|
///
|
||||||
pub fn create_link(
|
pub fn create_link(
|
||||||
|
@ -760,6 +756,7 @@ impl GraphView {
|
||||||
active,
|
active,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add a link to the graphView
|
/// Add a link to the graphView
|
||||||
///
|
///
|
||||||
pub fn add_link(&self, link: Link) {
|
pub fn add_link(&self, link: Link) {
|
||||||
|
@ -782,44 +779,18 @@ impl GraphView {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the position of the specified node inside the graphview.
|
/// Select all nodes according to the NodeType
|
||||||
///
|
///
|
||||||
/// Returns `None` if the node is not in the graphview.
|
/// Returns a vector of links
|
||||||
pub(super) fn node_position(&self, node: >k::Widget) -> Option<(f32, f32)> {
|
pub fn all_links(&self, link_state: bool) -> Vec<Link> {
|
||||||
let layout_manager = self
|
|
||||||
.layout_manager()
|
|
||||||
.expect("Failed to get layout manager")
|
|
||||||
.dynamic_cast::<gtk::FixedLayout>()
|
|
||||||
.expect("Failed to cast to FixedLayout");
|
|
||||||
|
|
||||||
let node = layout_manager
|
|
||||||
.layout_child(node)
|
|
||||||
.dynamic_cast::<gtk::FixedLayoutChild>()
|
|
||||||
.expect("Could not cast to FixedLayoutChild");
|
|
||||||
let transform = node
|
|
||||||
.transform()
|
|
||||||
.expect("Failed to obtain transform from layout child");
|
|
||||||
Some(transform.to_translate())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Retrieves the next node unique id.
|
|
||||||
///
|
|
||||||
pub fn next_node_id(&self) -> u32 {
|
|
||||||
let private = imp::GraphView::from_instance(self);
|
let private = imp::GraphView::from_instance(self);
|
||||||
private
|
let links = private.links.borrow();
|
||||||
.current_node_id
|
let links_list: Vec<_> = links
|
||||||
.set(private.current_node_id.get() + 1);
|
.iter()
|
||||||
private.current_node_id.get()
|
.filter(|(_, link)| link.active == link_state)
|
||||||
}
|
.map(|(_, node)| node.clone())
|
||||||
|
.collect();
|
||||||
/// Retrieves the next port unique id.
|
links_list
|
||||||
///
|
|
||||||
pub fn next_port_id(&self) -> u32 {
|
|
||||||
let private = imp::GraphView::from_instance(self);
|
|
||||||
private
|
|
||||||
.current_port_id
|
|
||||||
.set(private.current_port_id.get() + 1);
|
|
||||||
private.current_port_id.get()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Retrieves the node/port id connected to the input port id
|
/// Retrieves the node/port id connected to the input port id
|
||||||
|
@ -860,14 +831,15 @@ impl GraphView {
|
||||||
self.graph_updated();
|
self.graph_updated();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Render the graph in a file with XML format
|
/// Render the graph with XML format in a buffer
|
||||||
///
|
///
|
||||||
pub fn render_xml(&self, filename: &str) -> anyhow::Result<()> {
|
pub fn render_xml(&self) -> anyhow::Result<Vec<u8>> {
|
||||||
let private = imp::GraphView::from_instance(self);
|
let private = imp::GraphView::from_instance(self);
|
||||||
let mut file = File::create(filename).unwrap();
|
|
||||||
|
let mut buffer = Vec::new();
|
||||||
let mut writer = EmitterConfig::new()
|
let mut writer = EmitterConfig::new()
|
||||||
.perform_indent(true)
|
.perform_indent(true)
|
||||||
.create_writer(&mut file);
|
.create_writer(&mut buffer);
|
||||||
|
|
||||||
writer
|
writer
|
||||||
.write(XMLWEvent::start_element("Graph").attr("id", &private.id.get().to_string()))?;
|
.write(XMLWEvent::start_element("Graph").attr("id", &private.id.get().to_string()))?;
|
||||||
|
@ -926,15 +898,14 @@ impl GraphView {
|
||||||
writer.write(XMLWEvent::end_element())?;
|
writer.write(XMLWEvent::end_element())?;
|
||||||
}
|
}
|
||||||
writer.write(XMLWEvent::end_element())?;
|
writer.write(XMLWEvent::end_element())?;
|
||||||
Ok(())
|
Ok(buffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Load the graph from a file with XML format
|
/// Load the graph from a file with XML format
|
||||||
///
|
///
|
||||||
pub fn load_xml(&self, filename: &str) -> anyhow::Result<()> {
|
pub fn load_from_xml(&self, buffer: Vec<u8>) -> anyhow::Result<()> {
|
||||||
let file = File::open(filename)?;
|
self.clear();
|
||||||
let file = BufReader::new(file);
|
let file = Cursor::new(buffer);
|
||||||
|
|
||||||
let parser = EventReader::new(file);
|
let parser = EventReader::new(file);
|
||||||
|
|
||||||
let mut current_node: Option<Node> = None;
|
let mut current_node: Option<Node> = None;
|
||||||
|
@ -1113,6 +1084,40 @@ impl GraphView {
|
||||||
|
|
||||||
//Private
|
//Private
|
||||||
|
|
||||||
|
fn create_node_with_id(&self, id: u32, name: &str, node_type: NodeType) -> Node {
|
||||||
|
Node::new(id, name, node_type)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_port_with_id(
|
||||||
|
&self,
|
||||||
|
id: u32,
|
||||||
|
name: &str,
|
||||||
|
direction: PortDirection,
|
||||||
|
presence: PortPresence,
|
||||||
|
) -> Port {
|
||||||
|
Port::new(id, name, direction, presence)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_link_with_id(
|
||||||
|
&self,
|
||||||
|
link_id: u32,
|
||||||
|
node_from_id: u32,
|
||||||
|
node_to_id: u32,
|
||||||
|
port_from_id: u32,
|
||||||
|
port_to_id: u32,
|
||||||
|
active: bool,
|
||||||
|
) -> Link {
|
||||||
|
Link::new(
|
||||||
|
link_id,
|
||||||
|
node_from_id,
|
||||||
|
node_to_id,
|
||||||
|
port_from_id,
|
||||||
|
port_to_id,
|
||||||
|
active,
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
fn remove_link(&self, id: u32) {
|
fn remove_link(&self, id: u32) {
|
||||||
let private = imp::GraphView::from_instance(self);
|
let private = imp::GraphView::from_instance(self);
|
||||||
let mut links = private.links.borrow_mut();
|
let mut links = private.links.borrow_mut();
|
||||||
|
@ -1226,6 +1231,22 @@ impl GraphView {
|
||||||
self.emit_by_name::<()>("graph-updated", &[&private.id.get()]);
|
self.emit_by_name::<()>("graph-updated", &[&private.id.get()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn next_node_id(&self) -> u32 {
|
||||||
|
let private = imp::GraphView::from_instance(self);
|
||||||
|
private
|
||||||
|
.current_node_id
|
||||||
|
.set(private.current_node_id.get() + 1);
|
||||||
|
private.current_node_id.get()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn next_port_id(&self) -> u32 {
|
||||||
|
let private = imp::GraphView::from_instance(self);
|
||||||
|
private
|
||||||
|
.current_port_id
|
||||||
|
.set(private.current_port_id.get() + 1);
|
||||||
|
private.current_port_id.get()
|
||||||
|
}
|
||||||
|
|
||||||
fn next_link_id(&self) -> u32 {
|
fn next_link_id(&self) -> u32 {
|
||||||
let private = imp::GraphView::from_instance(self);
|
let private = imp::GraphView::from_instance(self);
|
||||||
private
|
private
|
||||||
|
|
|
@ -4,7 +4,6 @@ mod node;
|
||||||
mod port;
|
mod port;
|
||||||
mod property;
|
mod property;
|
||||||
mod selection;
|
mod selection;
|
||||||
mod tests;
|
|
||||||
|
|
||||||
pub use graphview::GraphView;
|
pub use graphview::GraphView;
|
||||||
pub use link::Link;
|
pub use link::Link;
|
||||||
|
@ -14,3 +13,139 @@ pub use port::Port;
|
||||||
pub use port::{PortDirection, PortPresence};
|
pub use port::{PortDirection, PortPresence};
|
||||||
pub use property::PropertyExt;
|
pub use property::PropertyExt;
|
||||||
pub use selection::SelectionExt;
|
pub use selection::SelectionExt;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
fn test_synced<F, R>(function: F) -> R
|
||||||
|
where
|
||||||
|
F: FnOnce() -> R + Send + std::panic::UnwindSafe + 'static,
|
||||||
|
R: Send + 'static,
|
||||||
|
{
|
||||||
|
/// No-op.
|
||||||
|
macro_rules! skip_assert_initialized {
|
||||||
|
() => {};
|
||||||
|
}
|
||||||
|
skip_assert_initialized!();
|
||||||
|
|
||||||
|
use futures_channel::oneshot;
|
||||||
|
use std::panic;
|
||||||
|
|
||||||
|
let (tx, rx) = oneshot::channel();
|
||||||
|
TEST_THREAD_WORKER
|
||||||
|
.push(move || {
|
||||||
|
tx.send(panic::catch_unwind(function))
|
||||||
|
.unwrap_or_else(|_| panic!("Failed to return result from thread pool"));
|
||||||
|
})
|
||||||
|
.expect("Failed to schedule a test call");
|
||||||
|
futures_executor::block_on(rx)
|
||||||
|
.expect("Failed to receive result from thread pool")
|
||||||
|
.unwrap_or_else(|e| std::panic::resume_unwind(e))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
static TEST_THREAD_WORKER: once_cell::sync::Lazy<gtk::glib::ThreadPool> =
|
||||||
|
once_cell::sync::Lazy::new(|| {
|
||||||
|
let pool = gtk::glib::ThreadPool::exclusive(1).unwrap();
|
||||||
|
pool.push(move || {
|
||||||
|
gtk::init().expect("Tests failed to initialize gtk");
|
||||||
|
})
|
||||||
|
.expect("Failed to schedule a test call");
|
||||||
|
pool
|
||||||
|
});
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
#[test]
|
||||||
|
fn graphview_creation() {
|
||||||
|
test_synced(|| {
|
||||||
|
let graphview = GraphView::new();
|
||||||
|
assert_eq!(graphview.id(), 0);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
#[test]
|
||||||
|
fn graphview_lifetime() {
|
||||||
|
test_synced(|| {
|
||||||
|
let graphview = GraphView::new();
|
||||||
|
assert_eq!(graphview.id(), 0);
|
||||||
|
let node = graphview.create_node("my_node1", NodeType::Source);
|
||||||
|
node.add_property("np1", "nv1");
|
||||||
|
graphview.add_node(node);
|
||||||
|
//create a port input on node 1
|
||||||
|
let port = graphview.create_port("out", PortDirection::Output, PortPresence::Always);
|
||||||
|
assert_eq!(port.name(), "out");
|
||||||
|
assert_eq!(port.id(), 1);
|
||||||
|
let mut node: Node = graphview.node(1).unwrap();
|
||||||
|
graphview.add_port_to_node(&mut node, port);
|
||||||
|
|
||||||
|
let node = graphview.create_node_with_port("my_node2", NodeType::Transform, 1, 1);
|
||||||
|
node.add_property("np2", "nv2");
|
||||||
|
graphview.add_node(node);
|
||||||
|
|
||||||
|
let node = graphview.create_node("my_node3", NodeType::Sink);
|
||||||
|
node.add_property("np3", "nv3");
|
||||||
|
graphview.add_node(node);
|
||||||
|
//create a port input on node 3
|
||||||
|
let port = graphview.create_port("in", PortDirection::Input, PortPresence::Always);
|
||||||
|
port.add_property("p1", "v1");
|
||||||
|
assert_eq!(port.name(), "in");
|
||||||
|
assert_eq!(port.id(), 4);
|
||||||
|
let mut node: Node = graphview.node(3).unwrap();
|
||||||
|
graphview.add_port_to_node(&mut node, port);
|
||||||
|
|
||||||
|
assert_eq!(graphview.all_nodes(NodeType::Source).len(), 1);
|
||||||
|
assert_eq!(graphview.all_nodes(NodeType::Transform).len(), 1);
|
||||||
|
assert_eq!(graphview.all_nodes(NodeType::Sink).len(), 1);
|
||||||
|
assert_eq!(graphview.all_nodes(NodeType::All).len(), 3);
|
||||||
|
|
||||||
|
assert_eq!(graphview.node(1).unwrap().name(), "my_node1");
|
||||||
|
assert_eq!(graphview.node(2).unwrap().name(), "my_node2");
|
||||||
|
assert_eq!(graphview.node(3).unwrap().name(), "my_node3");
|
||||||
|
|
||||||
|
// Ports have been created by create_node_with_port
|
||||||
|
|
||||||
|
//Create link between node1 and node 2
|
||||||
|
let link = graphview.create_link(1, 2, 1, 2, true);
|
||||||
|
graphview.add_link(link);
|
||||||
|
|
||||||
|
//Create link between node2 and node 3
|
||||||
|
let link = graphview.create_link(2, 3, 3, 4, true);
|
||||||
|
graphview.add_link(link);
|
||||||
|
|
||||||
|
// Save the graphview in XML into a buffer
|
||||||
|
let buffer = graphview
|
||||||
|
.render_xml()
|
||||||
|
.expect("Should be able to render graph to xml");
|
||||||
|
println!("{}", std::str::from_utf8(&buffer).unwrap());
|
||||||
|
// Load the graphview from XML buffer
|
||||||
|
graphview
|
||||||
|
.load_from_xml(buffer)
|
||||||
|
.expect("Should be able to load from XML data");
|
||||||
|
|
||||||
|
// Check that nodes and links are present
|
||||||
|
assert_eq!(graphview.all_nodes(NodeType::All).len(), 3);
|
||||||
|
assert_eq!(graphview.all_links(true).len(), 2);
|
||||||
|
|
||||||
|
// Check all nodes are linked
|
||||||
|
assert!(graphview.node_is_linked(1).is_some());
|
||||||
|
assert!(graphview.node_is_linked(2).is_some());
|
||||||
|
assert!(graphview.node_is_linked(3).is_some());
|
||||||
|
|
||||||
|
// Check all ports are linked
|
||||||
|
assert!(graphview.port_connected_to(1).is_some());
|
||||||
|
assert!(graphview.port_connected_to(3).is_some());
|
||||||
|
|
||||||
|
// Check properties
|
||||||
|
let node = graphview.node(1).expect("Should be able to get node 1");
|
||||||
|
assert_eq!(&node.property("np1").unwrap(), "nv1");
|
||||||
|
let node = graphview.node(2).expect("Should be able to get node 1");
|
||||||
|
assert_eq!(&node.property("np2").unwrap(), "nv2");
|
||||||
|
let node = graphview.node(3).expect("Should be able to get node 1");
|
||||||
|
assert_eq!(&node.property("np3").unwrap(), "nv3");
|
||||||
|
|
||||||
|
// Clear the graph and check that everything has been destroyed properly
|
||||||
|
graphview.clear();
|
||||||
|
assert_eq!(graphview.all_nodes(NodeType::All).len(), 0);
|
||||||
|
assert_eq!(graphview.all_links(true).len(), 0);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue