Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -369,13 +369,8 @@ impl NodeNetworkInterface {
return None;
};
// TODO: Get downstream connections from all outputs
let Some(downstream_connections) = outward_wires.get(&OutputConnector::node(*node_id, 0)) else {
log::error!("Could not get outward wires in copy_nodes");
return None;
};
let has_selected_node_downstream = downstream_connections
.iter()
.any(|input_connector| input_connector.node_id().is_some_and(|upstream_id| new_ids.keys().any(|key| *key == upstream_id)));
let mut downstream_connections = outward_wires.get(&OutputConnector::node(*node_id, 0)).map_or([].iter(), |outputs| outputs.iter());
let has_selected_node_downstream = downstream_connections.any(|input_connector| input_connector.node_id().is_some_and(|upstream_id| new_ids.keys().any(|key| *key == upstream_id)));
// If the copied node does not have a downstream connection to another copied node, then set the position to absolute
if !has_selected_node_downstream {
let Some(position) = self.position(node_id, network_path) else {
Expand Down Expand Up @@ -6916,3 +6911,34 @@ pub enum TransactionStatus {
#[default]
Finished,
}

#[cfg(test)]
mod network_interface_tests {
use crate::test_utils::test_prelude::*;
#[tokio::test]
async fn copy_isolated_node() {
let mut editor = EditorTestUtils::create();
editor.new_document().await;
let rectangle = editor.create_node_by_name("Rectangle").await;
editor.handle_message(NodeGraphMessage::SelectedNodesSet { nodes: vec![rectangle] }).await;
let frontend_messages = editor.handle_message(NodeGraphMessage::Copy).await;
let serialized_nodes = frontend_messages
.into_iter()
.find_map(|msg| match msg {
FrontendMessage::TriggerTextCopy { copy_text } => Some(copy_text),
_ => None,
})
.expect("copy message should be dispatched")
.strip_prefix("graphite/nodes: ")
.expect("should start with magic string")
.to_string();
println!("Serialized: {serialized_nodes}");
editor.handle_message(NodeGraphMessage::PasteNodes { serialized_nodes }).await;
let nodes = &mut editor.active_document_mut().network_interface.network_mut(&[]).unwrap().nodes;
let orignal = nodes.remove(&rectangle).expect("original node should exist");
assert!(
nodes.values().any(|other| *other == orignal),
"duplicated node should exist\nother nodes: {nodes:#?}\norignal {orignal:#?}"
);
}
}
21 changes: 18 additions & 3 deletions editor/src/test_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use glam::{DVec2, UVec2};
use graph_craft::document::DocumentNode;
use graphene_std::InputAccessor;
use graphene_std::raster::color::Color;
use graphene_std::uuid::NodeId;

/// A set of utility functions to make the writing of editor test more declarative
pub struct EditorTestUtils {
Expand Down Expand Up @@ -68,13 +69,15 @@ impl EditorTestUtils {
run(&mut self.editor, &mut self.runtime)
}

pub async fn handle_message(&mut self, message: impl Into<Message>) {
self.editor.handle_message(message);
pub async fn handle_message(&mut self, message: impl Into<Message>) -> Vec<FrontendMessage> {
let frontend_messages_from_msg = self.editor.handle_message(message);

// Required to process any buffered messages
if let Err(e) = self.eval_graph().await {
panic!("Failed to evaluate graph: {e}");
}

frontend_messages_from_msg
}

pub async fn new_document(&mut self) {
Expand Down Expand Up @@ -222,7 +225,7 @@ impl EditorTestUtils {
ToolType::Rectangle => self.handle_message(Message::Tool(ToolMessage::ActivateToolShapeRectangle)).await,
ToolType::Ellipse => self.handle_message(Message::Tool(ToolMessage::ActivateToolShapeEllipse)).await,
_ => self.handle_message(Message::Tool(ToolMessage::ActivateTool { tool_type })).await,
}
};
}

pub async fn select_primary_color(&mut self, color: Color) {
Expand Down Expand Up @@ -303,6 +306,18 @@ impl EditorTestUtils {
})
.await;
}

pub async fn create_node_by_name(&mut self, name: impl Into<String>) -> NodeId {
let node_id = NodeId::new();
self.handle_message(NodeGraphMessage::CreateNodeFromContextMenu {
node_id: Some(node_id),
node_type: name.into(),
xy: None,
add_transaction: true,
})
.await;
node_id
}
}

pub trait FrontendMessageTestUtils {
Expand Down
Loading