// Copyright 2022 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::borrow::Borrow; use std::ops::Deref; use std::str; use lazy_static::lazy_static; use maplit::hashset; use gradiff::codec::{decode_from_str, encode_to_str, Attribute, Change, Chunk, CreateChange, File, FileHeader, FormatVersion, Identifier, ParameterPath, RGBAColor, SetChange, Timestamp, UTCOffset, Value}; use gradiff::model::{BoundingBox, BoxAnchorPositionX, BoxAnchorPositionY, BoxCorners, Diagram, DiagramObject, DiagramObjectCommon, FontStyle, Point, TextHAlignment, TextVAlignment}; const HELLO_WORLD_DIAGRAM_BYTES: &[u8] = include_bytes!("hello_world.gdff"); //REUSE-IgnoreStart lazy_static! { static ref HELLO_WORLD_DIAGRAM: File = File::new( FileHeader::new( Some(" Copyright 2022 The GRADIS Project Contributors\n SPDX-License-Identifier: CC0-1.0\n SPDX-FileContributor: Lucas Hinderberger \n\n Each abovementioned SPDX-FileContributor has contributed to and/or modified this file.\n Please add your name and email address to the list above, if you publish modifications.".to_string()), FormatVersion{major: 0, minor: 1} ), vec![ Chunk::new( vec![ Attribute{key: "Author".parse().unwrap(), value: Value::String("John Doe ".to_string())}, Attribute{key: "Timestamp".parse().unwrap(), value: Value::Timestamp(Timestamp::new(2022, 8, 30, 17, 30, 0, 0, UTCOffset::Zulu).unwrap())} ], vec![ Change::Create(CreateChange::new("canvas".parse().unwrap(), "Canvas".parse().unwrap(), vec![Value::Number(100.0.try_into().unwrap()), Value::Number(100.0.try_into().unwrap())])), Change::Create(CreateChange::new("ptBoxHelloAnchor".parse().unwrap(), "PointAbsolute".parse().unwrap(), vec![Value::Number(30.0.try_into().unwrap()), Value::Number(70.0.try_into().unwrap())])), Change::Create(CreateChange::new("boxHello".parse().unwrap(), "Box".parse().unwrap(), vec![Value::Identifier("ptBoxHelloAnchor".parse().unwrap()), Value::Number(40.0.try_into().unwrap()), Value::Number(40.0.try_into().unwrap())])), Change::Set(SetChange::new(ParameterPath("boxHello".parse().unwrap(), "Text".parse().unwrap()), Value::String("Hello World!".to_string()))) ] ) ] ); } //REUSE-IgnoreEnd #[test] fn hello_world_diagram_can_be_de_and_encoded() { let expected_encoded = str::from_utf8(HELLO_WORLD_DIAGRAM_BYTES).unwrap(); let actual_encoded = encode_to_str(&*HELLO_WORLD_DIAGRAM).unwrap(); let actual_decoded: File = decode_from_str(expected_encoded).unwrap(); assert_eq!(expected_encoded, actual_encoded); assert_eq!(&*HELLO_WORLD_DIAGRAM, &actual_decoded); for n in 1..10 { let actual_decoded_trailing_lfs: File = decode_from_str((expected_encoded.to_string() + "\n".repeat(n).as_str()).as_str()).unwrap(); assert_eq!(&*HELLO_WORLD_DIAGRAM, &actual_decoded_trailing_lfs); } } #[test] fn hello_world_diagram_is_processed_correctly() { let parsed_file: File = str::from_utf8(HELLO_WORLD_DIAGRAM_BYTES).unwrap().parse().unwrap(); let mut diagram = Diagram::new(); for chunk in parsed_file.chunks().iter() { for change in chunk.changes().iter() { diagram.apply_change(change).unwrap(); } } let view = diagram.view(); assert_eq!(view.objects().len(), 3); assert_eq!(view.dependent_object_ids().len(), 2); let canvas_name: Identifier = "canvas".parse().unwrap(); let box_hello_name: Identifier = "boxHello".parse().unwrap(); let pt_box_hello_anchor_name: Identifier = "ptBoxHelloAnchor".parse().unwrap(); let raw_canvas = view.objects().get(&canvas_name).unwrap().borrow(); let canvas = match raw_canvas.deref() { DiagramObject::Canvas(obj) => obj, _ => panic!("canvas is not a Canvas") }; let raw_box_hello = view.objects().get(&box_hello_name).unwrap().borrow(); let box_hello = match raw_box_hello.deref() { DiagramObject::Box(obj) => obj, _ => panic!("boxHello is not a Box") }; let raw_pt_box_hello_anchor = view.objects().get(&pt_box_hello_anchor_name).unwrap().borrow(); let pt_box_hello_anchor = match raw_pt_box_hello_anchor.deref() { DiagramObject::Point(outer) => match outer { Point::Absolute(obj) => obj, _ => panic!("ptBoxHelloAnchor is not a PointAbsolute") }, _ => panic!("ptBoxHelloAnchor is not a Point") }; assert_eq!(view.current_canvas_id(), Some(&canvas_name)); assert_eq!(view.current_canvas().unwrap().borrow().deref(), raw_canvas.deref()); assert_eq!(canvas.width(), 100.0); assert_eq!(canvas.height(), 100.0); assert_eq!(canvas.background_color(), &RGBAColor{r: 0xff, g: 0xff, b: 0xff, a: 0xff}); assert_eq!(raw_canvas.bounding_box(), BoundingBox{top_left: (0.0, 100.0), bottom_right: (100.0, 0.0)}); assert_eq!(raw_canvas.metadata().canvas_id(), None); assert_eq!(raw_canvas.metadata().object_id(), &canvas_name); assert!(raw_canvas.metadata().dependency_ids().is_empty()); assert_eq!(view.dependent_object_ids().get(&canvas_name).unwrap(), &hashset!{box_hello_name.clone(), pt_box_hello_anchor_name.clone()}); assert_eq!(pt_box_hello_anchor.x(), 30.0); assert_eq!(pt_box_hello_anchor.y(), 70.0); assert_eq!(pt_box_hello_anchor.position(), (30.0, 70.0)); assert_eq!(raw_pt_box_hello_anchor.bounding_box(), BoundingBox{top_left: (30.0, 70.0), bottom_right: (30.0, 70.0)}); assert_eq!(raw_pt_box_hello_anchor.metadata().canvas_id(), Some(&canvas_name)); assert_eq!(raw_pt_box_hello_anchor.metadata().object_id(), &pt_box_hello_anchor_name); assert_eq!(raw_pt_box_hello_anchor.metadata().dependency_ids(), &hashset!{canvas_name.clone()}); assert_eq!(view.dependent_object_ids().get(&pt_box_hello_anchor_name).unwrap(), &hashset!{box_hello_name.clone()}); assert_eq!(box_hello.anchor_point_id(), &pt_box_hello_anchor_name); assert_eq!(box_hello.anchor_position_x(), BoxAnchorPositionX::Left); assert_eq!(box_hello.anchor_position_y(), BoxAnchorPositionY::Top); assert_eq!(box_hello.width(), 40.0); assert_eq!(box_hello.height(), 40.0); assert_eq!(box_hello.background_color(), &RGBAColor{r: 0xff, g: 0xff, b: 0xff, a: 0xff}); assert_eq!(box_hello.border_color(), &RGBAColor{r: 0x00, g: 0x00, b: 0x00, a: 0xff}); assert_eq!(box_hello.border_thickness(), 0.5); assert_eq!(box_hello.font_family(), "sans-serif"); assert_eq!(box_hello.font_size(), 12.0); assert_eq!(box_hello.font_stretch(), 1.0); assert_eq!(box_hello.font_style(), FontStyle::Normal); assert_eq!(box_hello.font_weight(), 400.0); assert_eq!(box_hello.line_height(), 1.0); assert_eq!(box_hello.padding_bottom(), 4.0); assert_eq!(box_hello.padding_left(), 4.0); assert_eq!(box_hello.padding_right(), 4.0); assert_eq!(box_hello.padding_top(), 4.0); assert_eq!(box_hello.text(), "Hello World!"); assert_eq!(box_hello.text_color(), &RGBAColor{r: 0x00, g: 0x00, b: 0x00, a: 0xff}); assert_eq!(box_hello.text_h_alignment(), TextHAlignment::Center); assert_eq!(box_hello.text_v_alignment(), TextVAlignment::Center); assert_eq!(box_hello.corners(), BoxCorners{a: (30.0, 70.0), b: (30.0, 30.0), c: (70.0, 30.0), d: (70.0, 70.0)}); assert_eq!(raw_box_hello.bounding_box(), BoundingBox{top_left: (29.75, 70.25), bottom_right: (70.25, 29.75)}); assert_eq!(raw_box_hello.metadata().canvas_id(), Some(&canvas_name)); assert_eq!(raw_box_hello.metadata().object_id(), &box_hello_name); assert_eq!(raw_box_hello.metadata().dependency_ids(), &hashset!{canvas_name.clone(), pt_box_hello_anchor_name.clone()}); }