Skip to content

Commit 6196dbf

Browse files
Add Gradient tool test for select and delete removes a stop (#2571)
* Add Gradient tool test for select and delete removes a stop * refactor fills and double click into functions * refactor
1 parent b45f7ef commit 6196dbf

File tree

2 files changed

+124
-83
lines changed

2 files changed

+124
-83
lines changed

editor/src/messages/tool/tool_messages/gradient_tool.rs

+112-83
Original file line numberDiff line numberDiff line change
@@ -539,6 +539,7 @@ mod test_gradient {
539539
pub use crate::test_utils::test_prelude::*;
540540
use glam::DAffine2;
541541
use graphene_core::vector::fill;
542+
use graphene_core::vector::style::Gradient;
542543
use graphene_std::vector::style::Fill;
543544

544545
use super::gradient_space_transform;
@@ -557,6 +558,30 @@ mod test_gradient {
557558
.collect()
558559
}
559560

561+
async fn get_gradient(editor: &mut EditorTestUtils) -> (Gradient, DAffine2) {
562+
let fills = get_fills(editor).await;
563+
assert_eq!(fills.len(), 1, "Expected 1 gradient fill, found {}", fills.len());
564+
565+
let (fill, transform) = fills.first().unwrap();
566+
let gradient = fill.as_gradient().expect("Expected gradient fill type");
567+
568+
(gradient.clone(), transform.clone())
569+
}
570+
571+
fn assert_stops_at_positions(actual_positions: &[f64], expected_positions: &[f64], tolerance: f64) {
572+
assert_eq!(
573+
actual_positions.len(),
574+
expected_positions.len(),
575+
"Expected {} stops, found {}",
576+
expected_positions.len(),
577+
actual_positions.len()
578+
);
579+
580+
for (i, (actual, expected)) in actual_positions.iter().zip(expected_positions.iter()).enumerate() {
581+
assert!((actual - expected).abs() < tolerance, "Stop {}: Expected position near {}, got {}", i, expected, actual);
582+
}
583+
}
584+
560585
#[tokio::test]
561586
async fn ignore_artboard() {
562587
let mut editor = EditorTestUtils::create();
@@ -583,10 +608,9 @@ mod test_gradient {
583608
editor.select_primary_color(Color::GREEN).await;
584609
editor.select_secondary_color(Color::BLUE).await;
585610
editor.drag_tool(ToolType::Gradient, 2., 3., 24., 4., ModifierKeys::empty()).await;
586-
let fills = get_fills(&mut editor).await;
587-
assert_eq!(fills.len(), 1);
588-
let (fill, transform) = fills.first().unwrap();
589-
let gradient = fill.as_gradient().unwrap();
611+
612+
let (gradient, transform) = get_gradient(&mut editor).await;
613+
590614
// Gradient goes from secondary colour to primary colour
591615
let stops = gradient.stops.iter().map(|stop| (stop.0, stop.1.to_rgba8_srgb())).collect::<Vec<_>>();
592616
assert_eq!(stops, vec![(0., Color::BLUE.to_rgba8_srgb()), (1., Color::GREEN.to_rgba8_srgb())]);
@@ -607,9 +631,9 @@ mod test_gradient {
607631
let end = DVec2::new(24., 4.);
608632
editor.drag_tool(ToolType::Rectangle, -5., -3., 100., 100., ModifierKeys::empty()).await;
609633
editor.drag_tool(ToolType::Gradient, start.x, start.y, end.x, end.y, ModifierKeys::SHIFT).await;
610-
let fills = get_fills(&mut editor).await;
611-
let (fill, transform) = fills.first().unwrap();
612-
let gradient = fill.as_gradient().unwrap();
634+
635+
let (gradient, transform) = get_gradient(&mut editor).await;
636+
613637
assert!(transform.transform_point2(gradient.start).abs_diff_eq(start, 1e-10));
614638

615639
// 15 degrees from horizontal
@@ -649,10 +673,9 @@ mod test_gradient {
649673
.await;
650674

651675
editor.drag_tool(ToolType::Gradient, 2., 3., 24., 4., ModifierKeys::empty()).await;
652-
let fills = get_fills(&mut editor).await;
653-
assert_eq!(fills.len(), 1);
654-
let (fill, transform) = fills.first().unwrap();
655-
let gradient = fill.as_gradient().unwrap();
676+
677+
let (gradient, transform) = get_gradient(&mut editor).await;
678+
656679
assert!(transform.transform_point2(gradient.start).abs_diff_eq(DVec2::new(2., 3.), 1e-10));
657680
assert!(transform.transform_point2(gradient.end).abs_diff_eq(DVec2::new(24., 4.), 1e-10));
658681
}
@@ -663,44 +686,20 @@ mod test_gradient {
663686
editor.new_document().await;
664687

665688
editor.drag_tool(ToolType::Rectangle, -5., -3., 100., 100., ModifierKeys::empty()).await;
666-
667689
editor.select_primary_color(Color::GREEN).await;
668690
editor.select_secondary_color(Color::BLUE).await;
669-
670691
editor.drag_tool(ToolType::Gradient, 0., 0., 100., 0., ModifierKeys::empty()).await;
671692

672693
// Get initial gradient state (should have 2 stops)
673-
let initial_fills = get_fills(&mut editor).await;
674-
assert_eq!(initial_fills.len(), 1);
675-
let (initial_fill, _) = initial_fills.first().unwrap();
676-
let initial_gradient = initial_fill.as_gradient().unwrap();
677-
assert_eq!(initial_gradient.stops.len(), 2);
694+
let (initial_gradient, _) = get_gradient(&mut editor).await;
695+
assert_eq!(initial_gradient.stops.len(), 2, "Expected 2 stops, found {}", initial_gradient.stops.len());
678696

679697
editor.select_tool(ToolType::Gradient).await;
680-
681-
// Simulate a double click
682-
let click_position = DVec2::new(50., 0.);
683-
let modifier_keys = ModifierKeys::empty();
684-
685-
// Send the DoubleClick event
686-
editor
687-
.handle_message(InputPreprocessorMessage::DoubleClick {
688-
editor_mouse_state: EditorMouseState {
689-
editor_position: click_position,
690-
mouse_keys: MouseKeys::LEFT,
691-
scroll_delta: ScrollDelta::default(),
692-
},
693-
modifier_keys,
694-
})
695-
.await;
698+
editor.double_click(DVec2::new(50., 0.)).await;
696699

697700
// Check that a new stop has been added
698-
let updated_fills = get_fills(&mut editor).await;
699-
assert_eq!(updated_fills.len(), 1);
700-
let (updated_fill, _) = updated_fills.first().unwrap();
701-
let updated_gradient = updated_fill.as_gradient().unwrap();
702-
703-
assert_eq!(updated_gradient.stops.len(), 3);
701+
let (updated_gradient, _) = get_gradient(&mut editor).await;
702+
assert_eq!(updated_gradient.stops.len(), 3, "Expected 3 stops, found {}", updated_gradient.stops.len());
704703

705704
let positions: Vec<f64> = updated_gradient.stops.iter().map(|(pos, _)| *pos).collect();
706705
assert!(
@@ -735,11 +734,9 @@ mod test_gradient {
735734

736735
editor.drag_tool(ToolType::Gradient, 0., 0., 100., 0., ModifierKeys::empty()).await;
737736

738-
// Get the initial gradient state (should have 2 stops)
739-
let initial_fills = get_fills(&mut editor).await;
740-
assert_eq!(initial_fills.len(), 1);
741-
let (initial_fill, transform) = initial_fills.first().unwrap();
742-
let initial_gradient = initial_fill.as_gradient().unwrap();
737+
// Get the initial gradient state
738+
let (initial_gradient, transform) = get_gradient(&mut editor).await;
739+
assert_eq!(initial_gradient.stops.len(), 2, "Expected 2 stops, found {}", initial_gradient.stops.len());
743740

744741
// Verify initial gradient endpoints in viewport space
745742
let initial_start = transform.transform_point2(initial_gradient.start);
@@ -755,9 +752,7 @@ mod test_gradient {
755752

756753
editor.move_mouse(start_pos.x, start_pos.y, ModifierKeys::empty(), MouseKeys::empty()).await;
757754
editor.left_mousedown(start_pos.x, start_pos.y, ModifierKeys::empty()).await;
758-
759755
editor.move_mouse(end_pos.x, end_pos.y, ModifierKeys::empty(), MouseKeys::LEFT).await;
760-
761756
editor
762757
.mouseup(
763758
EditorMouseState {
@@ -770,10 +765,7 @@ mod test_gradient {
770765
.await;
771766

772767
// Check the updated gradient
773-
let updated_fills = get_fills(&mut editor).await;
774-
assert_eq!(updated_fills.len(), 1);
775-
let (updated_fill, transform) = updated_fills.first().unwrap();
776-
let updated_gradient = updated_fill.as_gradient().unwrap();
768+
let (updated_gradient, transform) = get_gradient(&mut editor).await;
777769

778770
// Verify the start point hasn't changed
779771
let updated_start = transform.transform_point2(updated_gradient.start);
@@ -790,46 +782,29 @@ mod test_gradient {
790782
editor.new_document().await;
791783

792784
editor.drag_tool(ToolType::Rectangle, -5., -3., 100., 100., ModifierKeys::empty()).await;
793-
794785
editor.select_primary_color(Color::GREEN).await;
795786
editor.select_secondary_color(Color::BLUE).await;
796-
797787
editor.drag_tool(ToolType::Gradient, 0., 0., 100., 0., ModifierKeys::empty()).await;
798788

799789
editor.select_tool(ToolType::Gradient).await;
800-
let click_position = DVec2::new(50., 0.);
801-
let modifier_keys = ModifierKeys::empty();
802790

803-
editor
804-
.handle_message(InputPreprocessorMessage::DoubleClick {
805-
editor_mouse_state: EditorMouseState {
806-
editor_position: click_position,
807-
mouse_keys: MouseKeys::LEFT,
808-
scroll_delta: ScrollDelta::default(),
809-
},
810-
modifier_keys,
811-
})
812-
.await;
791+
// Add a middle stop at 50%
792+
editor.double_click(DVec2::new(50., 0.)).await;
813793

814-
let fills = get_fills(&mut editor).await;
815-
assert_eq!(fills.len(), 1);
816-
let (initial_fill, _) = fills.first().unwrap();
817-
let initial_gradient = initial_fill.as_gradient().unwrap();
818-
assert_eq!(initial_gradient.stops.len(), 3);
794+
let (initial_gradient, _) = get_gradient(&mut editor).await;
795+
assert_eq!(initial_gradient.stops.len(), 3, "Expected 3 stops, found {}", initial_gradient.stops.len());
819796

820797
// Verify initial stop positions and colors
821798
let mut stops = initial_gradient.stops.clone();
822799
stops.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap());
823800

824-
assert!((stops[0].0 - 0.0).abs() < 0.001);
825-
assert!((stops[1].0 - 0.5).abs() < 0.1);
826-
assert!((stops[2].0 - 1.0).abs() < 0.001);
801+
let positions: Vec<f64> = stops.iter().map(|(pos, _)| *pos).collect();
802+
assert_stops_at_positions(&positions, &[0.0, 0.5, 1.0], 0.1);
827803

828804
let middle_color = stops[1].1.to_rgba8_srgb();
829805

830806
// Simulate dragging the middle stop to position 0.8
831-
editor.select_tool(ToolType::Gradient).await;
832-
807+
let click_position = DVec2::new(50., 0.);
833808
editor
834809
.mousedown(
835810
EditorMouseState {
@@ -855,24 +830,78 @@ mod test_gradient {
855830
)
856831
.await;
857832

858-
let fills_after_drag = get_fills(&mut editor).await;
859-
assert_eq!(fills_after_drag.len(), 1);
860-
let (updated_fill, _) = fills_after_drag.first().unwrap();
861-
let updated_gradient = updated_fill.as_gradient().unwrap();
862-
assert_eq!(updated_gradient.stops.len(), 3);
833+
let (updated_gradient, _) = get_gradient(&mut editor).await;
834+
assert_eq!(updated_gradient.stops.len(), 3, "Expected 3 stops after dragging, found {}", updated_gradient.stops.len());
863835

864836
// Verify updated stop positions and colors
865837
let mut updated_stops = updated_gradient.stops.clone();
866838
updated_stops.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap());
867839

868840
// Check positions are now correctly ordered
869-
assert!((updated_stops[0].0 - 0.0).abs() < 0.001);
870-
assert!((updated_stops[1].0 - 0.8).abs() < 0.1);
871-
assert!((updated_stops[2].0 - 1.0).abs() < 0.001);
841+
let updated_positions: Vec<f64> = updated_stops.iter().map(|(pos, _)| *pos).collect();
842+
assert_stops_at_positions(&updated_positions, &[0.0, 0.8, 1.0], 0.1);
872843

873844
// Colors should maintain their associations with the stop points
874845
assert_eq!(updated_stops[0].1.to_rgba8_srgb(), Color::BLUE.to_rgba8_srgb());
875846
assert_eq!(updated_stops[1].1.to_rgba8_srgb(), middle_color);
876847
assert_eq!(updated_stops[2].1.to_rgba8_srgb(), Color::GREEN.to_rgba8_srgb());
877848
}
849+
850+
#[tokio::test]
851+
async fn select_and_delete_removes_stop() {
852+
let mut editor = EditorTestUtils::create();
853+
editor.new_document().await;
854+
855+
editor.drag_tool(ToolType::Rectangle, -5., -3., 100., 100., ModifierKeys::empty()).await;
856+
editor.select_primary_color(Color::GREEN).await;
857+
editor.select_secondary_color(Color::BLUE).await;
858+
editor.drag_tool(ToolType::Gradient, 0., 0., 100., 0., ModifierKeys::empty()).await;
859+
860+
// Get initial gradient state (should have 2 stops)
861+
let (initial_gradient, _) = get_gradient(&mut editor).await;
862+
assert_eq!(initial_gradient.stops.len(), 2, "Expected 2 stops, found {}", initial_gradient.stops.len());
863+
864+
editor.select_tool(ToolType::Gradient).await;
865+
866+
// Add two middle stops
867+
editor.double_click(DVec2::new(25., 0.)).await;
868+
editor.double_click(DVec2::new(75., 0.)).await;
869+
870+
let (updated_gradient, _) = get_gradient(&mut editor).await;
871+
assert_eq!(updated_gradient.stops.len(), 4, "Expected 4 stops, found {}", updated_gradient.stops.len());
872+
873+
let positions: Vec<f64> = updated_gradient.stops.iter().map(|(pos, _)| *pos).collect();
874+
875+
// Use helper function to verify positions
876+
assert_stops_at_positions(&positions, &[0.0, 0.25, 0.75, 1.0], 0.05);
877+
878+
// Select the stop at position 0.75 and delete it
879+
let position2 = DVec2::new(75., 0.);
880+
editor.move_mouse(position2.x, position2.y, ModifierKeys::empty(), MouseKeys::empty()).await;
881+
editor.left_mousedown(position2.x, position2.y, ModifierKeys::empty()).await;
882+
editor
883+
.mouseup(
884+
EditorMouseState {
885+
editor_position: position2,
886+
mouse_keys: MouseKeys::empty(),
887+
scroll_delta: ScrollDelta::default(),
888+
},
889+
ModifierKeys::empty(),
890+
)
891+
.await;
892+
893+
editor.press(Key::Delete, ModifierKeys::empty()).await;
894+
895+
// Verify we now have 3 stops
896+
let (final_gradient, _) = get_gradient(&mut editor).await;
897+
assert_eq!(final_gradient.stops.len(), 3, "Expected 3 stops after deletion, found {}", final_gradient.stops.len());
898+
899+
let final_positions: Vec<f64> = final_gradient.stops.iter().map(|(pos, _)| *pos).collect();
900+
901+
// Verify final positions with helper function
902+
assert_stops_at_positions(&final_positions, &[0.0, 0.25, 1.0], 0.05);
903+
904+
// Additional verification that 0.75 stop is gone
905+
assert!(!final_positions.iter().any(|pos| (pos - 0.75).abs() < 0.05), "Stop at position 0.75 should have been deleted");
906+
}
878907
}

editor/src/test_utils.rs

+12
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,18 @@ impl EditorTestUtils {
243243
pub async fn get_selected_layer(&mut self) -> Option<LayerNodeIdentifier> {
244244
self.active_document().network_interface.selected_nodes().selected_layers(self.active_document().metadata()).next()
245245
}
246+
247+
pub async fn double_click(&mut self, position: DVec2) {
248+
self.handle_message(InputPreprocessorMessage::DoubleClick {
249+
editor_mouse_state: EditorMouseState {
250+
editor_position: position,
251+
mouse_keys: MouseKeys::LEFT,
252+
scroll_delta: ScrollDelta::default(),
253+
},
254+
modifier_keys: ModifierKeys::empty(),
255+
})
256+
.await;
257+
}
246258
}
247259

248260
pub trait FrontendMessageTestUtils {

0 commit comments

Comments
 (0)