//! Stable Cycle 0 feature identifiers and source-level regression gates. //! //! **Purpose:** Prevents the highest-risk placeholder behaviors from returning while broader GUI //! parity work proceeds. **Logic & Workflow:** Each test owns a stable feature ID and inspects the //! production source for architectural invariants that complement module-level behavior tests. //! **Side Effects / Dependencies:** Reads source files from the crate at test time; performs no //! writes and does not launch the GUI. use std::path::PathBuf; const MENU_SEMANTIC_DISPATCH: &str = "shell.menu.semantic_dispatch"; const MENU_NO_CUT_COPY_ALIAS: &str = "clipboard.cut.no_copy_alias"; const SCREENSHOT_NATIVE_CAPTURE: &str = "audit.screenshot.native_capture"; const SCREENSHOT_PANEL_CROP: &str = "audit.screenshot.panel_crop"; const PANE_FULL_DROP_TARGETS: &str = "cycle1.pane.full_drop_targets"; const THEME_SYNC_ISOLATION: &str = "cycle1.theme.sync_isolation"; const SIDEBAR_MODE_PERSISTENCE: &str = "cycle1.sidebar.mode_persistence"; const VECTOR_SCREEN_CONSTANT_HANDLES: &str = "cycle2.vector.screen_constant_handles"; const VECTOR_CONSTRAINED_DRAG: &str = "cycle2.vector.constrained_drag"; const VECTOR_LAYER_BOUND_CANCEL: &str = "cycle2.vector.layer_bound_cancel"; const VECTOR_BOOLEAN_RESULT: &str = "cycle2.vector.boolean_result_selection"; const VECTOR_CLAMPED_CONTROLS: &str = "cycle2.vector.clamped_controls"; const SELECTION_IRREGULAR_EDGES: &str = "cycle3.selection.irregular_edges"; const CLIPBOARD_DISTINCT_CUT: &str = "cycle3.clipboard.distinct_cut"; const RASTER_TRANSFORM_PLACEMENT: &str = "cycle3.raster.transform_placement"; const CROP_LIFECYCLE: &str = "cycle3.crop.lifecycle"; const TEXT_MULTILINE: &str = "cycle3.text.multiline"; const TRUE_GRADIENT: &str = "cycle3.gradient.linear_radial"; const CANVAS_INPUT_PARITY: &str = "cycle3.canvas.input_parity"; const PEN_SPRAY_DISTINCT: &str = "cycle3.tools.pen_spray_distinct"; const LAYERS_HIERARCHY_CONTROLS: &str = "cycle4.layers.hierarchy_controls"; const LAYER_STYLES_CANCEL_RESTORE: &str = "cycle4.layer_styles.cancel_restore"; const IMMUTABLE_PIXEL_PREVIEW: &str = "cycle4.preview.immutable_baseline"; const FILTER_SCHEMA_COVERAGE: &str = "cycle4.filters.schema_coverage"; const DOCUMENT_PATH_IDENTITY: &str = "cycle4.documents.path_identity"; const CLOSE_SAVE_CONTINUATION: &str = "cycle4.documents.close_save_continuation"; const AI_REAL_STREAMING: &str = "cycle5.ai.real_streaming"; const AI_REASONING_TRANSCRIPT: &str = "cycle5.ai.reasoning_transcript"; const SCRIPT_VALIDATED_OUTPUT: &str = "cycle5.script.validated_output"; const VIEWER_DETERMINISTIC_NAV: &str = "cycle5.viewer.deterministic_navigation"; const VIEWER_SAFE_EDIT: &str = "cycle5.viewer.safe_edit_document"; /// Reads a crate-relative source file for structural audit assertions. /// /// **Arguments:** `relative` is a path beneath the package manifest directory. /// **Returns:** The complete UTF-8 source text. /// **Side Effects / Dependencies:** Reads one local source file and panics on missing test input. fn source(relative: &str) -> String { let path = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join(relative); std::fs::read_to_string(&path) .unwrap_or_else(|error| panic!("failed to read {}: {error}", path.display())) } #[test] fn semantic_menu_dispatch_has_no_positional_message() { let app = source("src/app.rs"); let menus = source("src/panels/menus.rs"); assert!( app.contains("Message::MenuCommand(command)"), "{MENU_SEMANTIC_DISPATCH}" ); assert!( !app.contains("MenuAction(usize, usize)"), "{MENU_SEMANTIC_DISPATCH}" ); assert!( menus.contains("command: Option"), "{MENU_SEMANTIC_DISPATCH}" ); } #[test] fn cut_does_not_dispatch_copy() { let app = source("src/app.rs"); let menus = source("src/panels/menus.rs"); assert!( app.contains("MenuCommand::Cut => return Task::perform(async {}, |_| Message::CutImage)"), "{MENU_NO_CUT_COPY_ALIAS}" ); assert!( menus.contains("MenuCommand::Cut"), "{MENU_NO_CUT_COPY_ALIAS}" ); assert!( !menus.contains("MenuItem::with_shortcut(\"Cut\", \"Ctrl+X\")"), "{MENU_NO_CUT_COPY_ALIAS}" ); } #[test] fn cycle_three_canvas_selection_clipboard_crop_text_paths_are_connected() { let app = source("src/app.rs"); let canvas = source("src/canvas/mod.rs"); let shader = source("src/canvas/shader_canvas.rs"); let state = source("src/selection/state.rs"); let clipboard = source("src/selection/clipboard.rs"); let crop = source("src/selection/crop.rs"); let raster = source("src/raster.rs"); assert!( state.contains("pub fn selected_spans") && canvas.contains("selection_fill_spans") && canvas.contains("Fill exact mask runs"), "{SELECTION_IRREGULAR_EDGES}" ); assert!( app.contains("Message::CutImage") && app.contains("Message::ClearPixels") && app.contains("Some(Message::CutImage)"), "{CLIPBOARD_DISTINCT_CUT}" ); assert!( clipboard.contains("pub fn centered_transform") && app.contains("placed.pos.x += 10.0") && app.contains("tr.sanitize_geometry(self.modifiers.shift())"), "{RASTER_TRANSFORM_PLACEMENT}" ); assert!( crop.contains("start_drag_clamped") && app.contains("Message::CropConfirm"), "{CROP_LIFECYCLE}" ); assert!( canvas.contains("iced::widget::text_editor(&draft.editor)") && app.contains("Message::TextEditorAction(action)"), "{TEXT_MULTILINE}" ); assert!( raster.contains("pub fn apply_gradient") && app.contains("self.settings.tool_settings.gradient_type == 1"), "{TRUE_GRADIENT}" ); assert!( app.contains("paint_tool && (self.modifiers.control()") && app.contains("paint_tool && self.modifiers.shift()") && app.contains("Message::FitToArea") && shader.contains("state.space_left_pan = true"), "{CANVAS_INPUT_PARITY}" ); assert!( app.contains(".draw_pen_segment(") && app.contains("tip.spray_particle_size") && app.contains("tip.spray_density"), "{PEN_SPRAY_DISTINCT}" ); } #[test] fn screenshot_cli_uses_native_capture_and_panel_crop() { let app = source("src/app.rs"); let screenshot = source("src/screenshot.rs"); assert!( app.contains("iced::window::screenshot(id)"), "{SCREENSHOT_NATIVE_CAPTURE}" ); assert!( app.contains("crate::screenshot::crop_panel("), "{SCREENSHOT_PANEL_CROP}" ); assert!( screenshot.contains(".layout()\n .pane_regions"), "{SCREENSHOT_PANEL_CROP}" ); } #[test] fn cycle_one_state_paths_are_complete_and_persisted() { let app = source("src/app.rs"); let settings = source("src/settings.rs"); assert!( app.contains("self.dock.pane_grid.drop(pane, target)"), "{PANE_FULL_DROP_TARGETS}" ); assert!( !app.contains("Task::perform(async move { theme }, Message::ThemeChanged)"), "{THEME_SYNC_ISOLATION}" ); assert!( app.contains("self.settings.theme_preset = theme"), "{THEME_SYNC_ISOLATION}" ); assert!( settings.contains("pub theme_preset: crate::theme::ThemePreset"), "{THEME_SYNC_ISOLATION}" ); assert!( app.contains("settings.panel_layout.sidebar_expanded"), "{SIDEBAR_MODE_PERSISTENCE}" ); assert!( app.contains("self.settings.panel_layout.sidebar_expanded = self.sidebar_expanded"), "{SIDEBAR_MODE_PERSISTENCE}" ); } /// Verifies the Cycle 2 vector completion paths remain connected to pure calculations and UI. /// /// Purpose: Provides stable source-level scorecard evidence in addition to calculation unit tests. /// Logic & Workflow: Checks semantic state/session types and reachable handlers rather than fragile /// line positions. Side Effects / Dependencies: Reads local production sources only. #[test] fn cycle_two_vector_completion_paths_are_connected() { let app = source("src/app.rs"); let canvas = source("src/canvas/mod.rs"); let edit = source("src/vector_edit.rs"); assert!( edit.contains("HANDLE_HIT_HALF_PX / zoom") && edit.contains("ROTATE_HIT_RADIUS_PX / zoom"), "{VECTOR_SCREEN_CONSTANT_HANDLES}" ); assert!( app.contains("crate::vector_edit::transform_shape(") && app.contains("self.modifiers.shift()") && app.contains("self.modifiers.alt()") && app.contains("engine.set_vector_shape_bounds(") && app.contains("engine.set_vector_shape_angle(") && edit.contains("MIN_VECTOR_SIZE"), "{VECTOR_CONSTRAINED_DRAG}" ); assert!( app.contains("get_layer_shapes_direct(snapshot.layer_id)") && app.contains("self.vector_drag_session = None"), "{VECTOR_LAYER_BOUND_CANCEL}" ); assert!( app.contains("let succeeded = valid") && app.contains("selected_vector_shape = Some(result_index)"), "{VECTOR_BOOLEAN_RESULT}" ); assert!( canvas.contains("pane_w - controls_width") && canvas.contains("Message::VectorShapeDelete"), "{VECTOR_CLAMPED_CONTROLS}" ); } /// Verifies Cycle 4 panel and document-lifecycle paths remain semantic and non-destructive. /// /// Purpose: Records stable evidence for immutable previews, style cancellation, layer hierarchy, /// filter schema coverage, and successful-save identity. Logic & Workflow: Inspects the GUI-only /// implementations for their explicit state and engine-API routing. Side Effects / Dependencies: /// Reads production source files only. #[test] fn cycle_four_panel_and_document_paths_are_connected() { let app = source("src/app.rs"); let layers = source("src/panels/layers.rs"); let filters = source("src/panels/filters.rs"); let filter_params = source("src/panels/filter_params.rs"); let title_bar = source("src/panels/title_bar.rs"); assert!( layers.contains("Message::LayerToggleCollapse(info.id)") && layers.contains("Message::LayerToggleVisibility(info.id)") && layers.contains("Message::LayerToggleLock(info.id)") && app.contains("set_layer_parent(active_id, Some(group_id))") && app.contains("move_layer(id, target_idx)"), "{LAYERS_HIERARCHY_CONTROLS}" ); assert!( layers.contains("Fill opacity: unavailable in hcie-engine-api") && layers.contains("Disabled (engine API): duplicate / mask / rasterize") && layers.contains("button(text(\"Dup\")") && layers.contains("button(text(\"Mask\")") && layers.contains("button(text(\"Raster\")"), "{LAYERS_HIERARCHY_CONTROLS}: unsupported operations must be visibly disabled" ); assert!( app.contains("layer_style_baseline: Option") && app.contains("remove_layer_style_by_index(baseline.layer_id, index)") && app.contains("doc.engine.update_layer_style(baseline.layer_id, style)"), "{LAYER_STYLES_CANCEL_RESTORE}" ); assert!( app.contains("preview_baseline: Option") && app.contains("reset_preview_to_baseline()") && app.contains("set_layer_pixels(baseline.layer_id, baseline.pixels.clone())"), "{IMMUTABLE_PIXEL_PREVIEW}" ); for variant in [ "BoxBlurGamma", "GaussianBlurGamma", "MedianFilter", "SelectiveColor", "NoisePattern", ] { assert!( filters.contains(variant) && filter_params.contains(variant), "{FILTER_SCHEMA_COVERAGE}: missing {variant}" ); } assert!( app.contains("fn save_document_to(") && app.contains("\"hcie\" => engine.save_native(&path_str)") && app.contains("finish_successful_save") && title_bar.contains("if modified"), "{DOCUMENT_PATH_IDENTITY}" ); assert!( app.contains("PendingFileOperation::SaveAs { close_after: true }") && app.contains("continue_close_after_save()") && app.contains("Some(PendingFileOperation::Open)"), "{CLOSE_SAVE_CONTINUATION}" ); } /// Verifies Cycle 5 AI, script, and viewer workflows have semantic handlers and safety gates. #[test] fn cycle_five_practical_paths_are_connected() { let app = source("src/app.rs"); let chat = source("src/ai_chat.rs"); let ai_script = source("src/ai_script.rs"); let viewer = source("src/viewer/mod.rs"); assert!( chat.contains("iced::stream::channel") && app.contains("Task::run(") && app.contains("task.abortable()") && app.contains("Message::AiChatStreamChunk(chunk)"), "{AI_REAL_STREAMING}" ); assert!( app.contains("Message::AiChatReasoningChunk") && app.contains("Message::AiChatCopyTranscript") && chat.contains("pub fn transcript_text"), "{AI_REASONING_TRANSCRIPT}" ); assert!( ai_script.contains("pub fn validate_script_output") && ai_script.contains("ANTHROPIC_API_KEY") && ai_script.contains("OPENAI_API_KEY"), "{SCRIPT_VALIDATED_OUTPUT}" ); assert!( viewer.contains("Message::ViewerPrev") && viewer.contains("Message::ViewerNext") && app.contains("Message::ViewerSetMode(mode)"), "{VIEWER_DETERMINISTIC_NAV}" ); assert!( app.contains("Open into a new editor document") && app.contains("self.documents.remove(document_index)"), "{VIEWER_SAFE_EDIT}" ); }