// Copyright 2023 The GRADIS Project Contributors // SPDX-License-Identifier: Apache-2.0 // SPDX-FileContributor: Lucas Hinderberger // // Each abovementioned SPDX-FileContributor has contributed to and/or modified this file. // Please add your name and email address to the list above, if you publish modifications. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. use std::str; use pretty_assertions::assert_eq; use test_case::test_case; use gradiff::codec::{File, decode_from_str}; use gradiff::model::{BoundingBox, Diagram, DiagramObject}; use gradiff::render::render; const BLANK_CANVAS_GDFF: &str = include_str!("blank_canvas.gdff"); const BLANK_CANVAS_SVG: &str = include_str!("blank_canvas.svg"); const COLORFUL_HELLO_WORLD_GDFF: &str = include_str!("colorful_hello_world.gdff"); const COLORFUL_HELLO_WORLD_SVG: &str = include_str!("colorful_hello_world.svg"); const FALLBACK_OVERLAPPING_BOXES_GDFF: &str = include_str!("fallback_overlapping_boxes.gdff"); const FALLBACK_OVERLAPPING_BOXES_SVG: &str = include_str!("fallback_overlapping_boxes.svg"); const HELLO_WORLD_GDFF: &str = include_str!("hello_world.gdff"); const HELLO_WORLD_SVG: &str = include_str!("hello_world.svg"); const HELLO_XSS_GDFF: &str = include_str!("hello_xss.gdff"); const HELLO_XSS_SVG: &str = include_str!("hello_xss.svg"); const LOTS_OF_ARROWS_GDFF: &str = include_str!("lots_of_arrows.gdff"); const LOTS_OF_ARROWS_SVG: &str = include_str!("lots_of_arrows.svg"); const LOTS_OF_ARROWS_PARTIAL_SVG: &str = include_str!("lots_of_arrows_partial.svg"); const LOTS_OF_TEXT_GDFF: &str = include_str!("lots_of_text.gdff"); const LOTS_OF_TEXT_SVG: &str = include_str!("lots_of_text.svg"); const LOTS_OF_TEXT_PARTIAL_SVG: &str = include_str!("lots_of_text_partial.svg"); const MULTI_CANVAS_GDFF: &str = include_str!("multi_canvas.gdff"); const MULTI_CANVAS_A_SVG: &str = include_str!("multi_canvas_a.svg"); const MULTI_CANVAS_B_SVG: &str = include_str!("multi_canvas_b.svg"); const OFF_CENTER_HELLO_WORLD_GDFF: &str = include_str!("off_center_hello_world.gdff"); const OFF_CENTER_HELLO_WORLD_SVG: &str = include_str!("off_center_hello_world.svg"); const OVERLAPPING_BOXES_GDFF: &str = include_str!("overlapping_boxes.gdff"); const OVERLAPPING_BOXES_SVG: &str = include_str!("overlapping_boxes.svg"); const REVERSE_OVERLAPPING_BOXES_GDFF: &str = include_str!("reverse_overlapping_boxes.gdff"); const REVERSE_OVERLAPPING_BOXES_SVG: &str = include_str!("reverse_overlapping_boxes.svg"); const SEMITRANSPARENT_HELLO_WORLD_GDFF: &str = include_str!("semitransparent_hello_world.gdff"); const SEMITRANSPARENT_HELLO_WORLD_SVG: &str = include_str!("semitransparent_hello_world.svg"); const TWO_BOXES_WITH_ARROW_GDFF: &str = include_str!("two_boxes_with_arrow.gdff"); const TWO_BOXES_WITH_ARROW_SVG: &str = include_str!("two_boxes_with_arrow.svg"); #[test_case(BLANK_CANVAS_GDFF, "canvas", None, BLANK_CANVAS_SVG ; "blank_canvas")] #[test_case(COLORFUL_HELLO_WORLD_GDFF, "canvas", None, COLORFUL_HELLO_WORLD_SVG ; "colorful_hello_world")] #[test_case(FALLBACK_OVERLAPPING_BOXES_GDFF, "canvas", None, FALLBACK_OVERLAPPING_BOXES_SVG ; "fallback_overlapping_boxes")] #[test_case(HELLO_WORLD_GDFF, "canvas", None, HELLO_WORLD_SVG ; "hello_world")] #[test_case(HELLO_XSS_GDFF, "canvas", None, HELLO_XSS_SVG ; "hello_xss")] #[test_case(LOTS_OF_ARROWS_GDFF, "canvas", None, LOTS_OF_ARROWS_SVG ; "lots_of_arrows")] #[test_case(LOTS_OF_ARROWS_GDFF, "canvas", Some(BoundingBox{top_left: (40.0,90.0), bottom_right: (80.0,50.0)}), LOTS_OF_ARROWS_PARTIAL_SVG ; "lots_of_arrows_partial")] #[test_case(LOTS_OF_TEXT_GDFF, "canvas", None, LOTS_OF_TEXT_SVG ; "lots_of_text")] #[test_case(LOTS_OF_TEXT_GDFF, "canvas", Some(BoundingBox{top_left: (40.0,90.0), bottom_right: (80.0,50.0)}), LOTS_OF_TEXT_PARTIAL_SVG ; "lots_of_text_partial")] #[test_case(MULTI_CANVAS_GDFF, "canvasA", None, MULTI_CANVAS_A_SVG ; "multi_canvas_a")] #[test_case(MULTI_CANVAS_GDFF, "canvasB", None, MULTI_CANVAS_B_SVG ; "multi_canvas_b")] #[test_case(OFF_CENTER_HELLO_WORLD_GDFF, "canvas", None, OFF_CENTER_HELLO_WORLD_SVG ; "off_center_hello_world")] #[test_case(OVERLAPPING_BOXES_GDFF, "canvas", None, OVERLAPPING_BOXES_SVG ; "overlapping_boxes")] #[test_case(REVERSE_OVERLAPPING_BOXES_GDFF, "canvas", None, REVERSE_OVERLAPPING_BOXES_SVG ; "reverse_overlapping_boxes")] #[test_case(SEMITRANSPARENT_HELLO_WORLD_GDFF, "canvas", None, SEMITRANSPARENT_HELLO_WORLD_SVG ; "semitransparent_hello_world")] #[test_case(TWO_BOXES_WITH_ARROW_GDFF, "canvas", None, TWO_BOXES_WITH_ARROW_SVG ; "two_boxes_with_arrow")] // TODO: Add partial canvas test cases, especially for infinite canvases fn render_test(input: &str, canvas_id: &str, render_area: Option, expected_svg: &str) { let decoded_input: File = decode_from_str(input).unwrap(); let mut diagram = Diagram::new(); for chunk in decoded_input.chunks().iter() { diagram.apply_changes(&mut chunk.changes().iter()).unwrap(); } let diagram_view = diagram.view(); let raw_canvas = match diagram_view.objects().get(&canvas_id.parse().unwrap()) { Some(c) => c.borrow(), None => panic!("no object for Canvas ID") }; let canvas = match &*raw_canvas { DiagramObject::Canvas(c) => c, _ => panic!("not a Canvas") }; let render_area = render_area.unwrap_or(BoundingBox { top_left: (0.0, canvas.height()), bottom_right: (canvas.width(), 0.0) }); let mut output = Vec::new(); render(&mut output, &diagram_view, canvas, &render_area).unwrap(); let actual_svg = str::from_utf8(&output).unwrap(); assert_eq!(expected_svg, actual_svg); }