#![allow(clippy::cast_precision_loss)]
extern crate alloc;
extern crate std;
use crate::*;
use alloc::vec;
#[test]
fn test_init_and_version() {
let _engine = Thorvg::init(0).expect("Failed to init ThorVG");
let (major, _minor, _micro, version_str) = Thorvg::version().expect("Failed to get version");
assert!(major >= 1);
assert!(!version_str.is_empty());
}
#[test]
fn test_canvas_create_destroy() {
let engine = Thorvg::init(0).unwrap();
let canvas = engine.sw_canvas(EngineOption::Default);
assert!(canvas.is_ok());
}
#[test]
fn test_canvas_draw_shape() {
let engine = Thorvg::init(0).unwrap();
let mut canvas = engine.sw_canvas(EngineOption::Default).unwrap();
let (width, height) = (100u32, 100u32);
let mut buffer = vec![0u32; (width * height) as usize];
unsafe { canvas.set_target(&mut buffer, width, width, height, ColorSpace::ABGR8888) }.unwrap();
let mut shape = engine.shape();
shape
.append_rect(10.0, 10.0, 50.0, 50.0, 0.0, 0.0, true)
.unwrap();
shape.set_fill_color(255, 0, 0, 255).unwrap();
canvas.push(shape).unwrap(); canvas.draw(true).unwrap();
canvas.sync().unwrap();
assert!(
buffer.iter().any(|&px| px != 0),
"Expected non-empty render output"
);
}
#[test]
fn test_canvas_clear_all() {
let engine = Thorvg::init(0).unwrap();
let mut canvas = engine.sw_canvas(EngineOption::Default).unwrap();
let mut buffer = vec![0u32; 100 * 100];
unsafe { canvas.set_target(&mut buffer, 100, 100, 100, ColorSpace::ABGR8888) }.unwrap();
for _ in 0..5 {
let mut s = engine.shape();
s.append_rect(0.0, 0.0, 10.0, 10.0, 0.0, 0.0, true).unwrap();
s.set_fill_color(255, 0, 0, 255).unwrap();
canvas.push(s).unwrap();
}
canvas.clear().unwrap();
let mut s = engine.shape();
s.append_rect(0.0, 0.0, 50.0, 50.0, 0.0, 0.0, true).unwrap();
s.set_fill_color(0, 255, 0, 255).unwrap();
canvas.push(s).unwrap();
canvas.draw(true).unwrap();
canvas.sync().unwrap();
}
#[test]
fn test_shape_ownership_transfer_to_canvas() {
let engine = Thorvg::init(0).unwrap();
let mut canvas = engine.sw_canvas(EngineOption::Default).unwrap();
let mut buffer = vec![0u32; 100 * 100];
unsafe { canvas.set_target(&mut buffer, 100, 100, 100, ColorSpace::ABGR8888) }.unwrap();
let mut shape = engine.shape();
shape
.append_rect(0.0, 0.0, 50.0, 50.0, 0.0, 0.0, true)
.unwrap();
shape.set_fill_color(255, 0, 0, 255).unwrap();
canvas.push(shape).unwrap();
}
#[test]
fn test_shape_ownership_transfer_to_scene() {
let engine = Thorvg::init(0).unwrap();
let mut scene = engine.scene();
let mut s1 = engine.shape();
s1.append_rect(0.0, 0.0, 10.0, 10.0, 0.0, 0.0, true)
.unwrap();
s1.set_fill_color(255, 0, 0, 255).unwrap();
let mut s2 = engine.shape();
s2.append_circle(50.0, 50.0, 20.0, 20.0, true).unwrap();
s2.set_fill_color(0, 0, 255, 255).unwrap();
scene.push(s1).unwrap();
scene.push(s2).unwrap();
}
#[test]
fn test_shape_not_transferred_is_freed() {
let engine = Thorvg::init(0).unwrap();
let mut shape = engine.shape();
shape
.append_rect(0.0, 0.0, 100.0, 100.0, 0.0, 0.0, true)
.unwrap();
shape.set_fill_color(255, 255, 0, 255).unwrap();
shape.set_stroke_width(3.0).unwrap();
shape.set_stroke_color(0, 0, 0, 255).unwrap();
}
#[test]
fn test_gradient_ownership_transfer_to_shape() {
let engine = Thorvg::init(0).unwrap();
let mut grad = engine.linear_gradient();
grad.set_bounds(0.0, 0.0, 100.0, 100.0).unwrap();
grad.set_color_stops(&[
ColorStop {
offset: 0.0,
r: 255,
g: 0,
b: 0,
a: 255,
},
ColorStop {
offset: 1.0,
r: 0,
g: 0,
b: 255,
a: 255,
},
])
.unwrap();
let mut shape = engine.shape();
shape
.append_rect(0.0, 0.0, 100.0, 100.0, 0.0, 0.0, true)
.unwrap();
shape.set_linear_gradient(grad).unwrap();
}
#[test]
fn test_gradient_not_transferred_is_freed() {
let engine = Thorvg::init(0).unwrap();
let mut grad = engine.radial_gradient();
grad.set_radial(50.0, 50.0, 30.0, 50.0, 50.0, 0.0).unwrap();
grad.set_color_stops(&[
ColorStop {
offset: 0.0,
r: 255,
g: 255,
b: 255,
a: 255,
},
ColorStop {
offset: 1.0,
r: 0,
g: 0,
b: 0,
a: 255,
},
])
.unwrap();
}
#[test]
fn test_gradient_duplicate() {
let engine = Thorvg::init(0).unwrap();
let mut grad = engine.linear_gradient();
grad.set_bounds(0.0, 0.0, 200.0, 200.0).unwrap();
grad.set_color_stops(&[
ColorStop {
offset: 0.0,
r: 255,
g: 0,
b: 0,
a: 255,
},
ColorStop {
offset: 0.5,
r: 0,
g: 255,
b: 0,
a: 255,
},
ColorStop {
offset: 1.0,
r: 0,
g: 0,
b: 255,
a: 255,
},
])
.unwrap();
let dup = grad.duplicate();
assert!(dup.is_some());
let dup = dup.unwrap();
let (x1, y1, x2, y2) = dup.bounds().unwrap();
assert!((x1 - 0.0).abs() < f32::EPSILON);
assert!((y1 - 0.0).abs() < f32::EPSILON);
assert!((x2 - 200.0).abs() < f32::EPSILON);
assert!((y2 - 200.0).abs() < f32::EPSILON);
}
#[test]
fn test_scene_nested_drop() {
let engine = Thorvg::init(0).unwrap();
let mut canvas = engine.sw_canvas(EngineOption::Default).unwrap();
let mut buffer = vec![0u32; 200 * 200];
unsafe { canvas.set_target(&mut buffer, 200, 200, 200, ColorSpace::ABGR8888) }.unwrap();
let mut scene = engine.scene();
for i in 0..10 {
let mut s = engine.shape();
s.append_circle(i as f32 * 20.0, 50.0, 10.0, 10.0, true)
.unwrap();
s.set_fill_color(255, 0, 0, 255).unwrap();
scene.push(s).unwrap();
}
canvas.push(scene).unwrap();
canvas.draw(true).unwrap();
canvas.sync().unwrap();
}
#[test]
fn test_scene_clear_and_reuse() {
let engine = Thorvg::init(0).unwrap();
let mut scene = engine.scene();
for _ in 0..5 {
let mut s = engine.shape();
s.append_rect(0.0, 0.0, 10.0, 10.0, 0.0, 0.0, true).unwrap();
scene.push(s).unwrap();
}
scene.clear().unwrap();
let mut s = engine.shape();
s.append_rect(0.0, 0.0, 50.0, 50.0, 0.0, 0.0, true).unwrap();
scene.push(s).unwrap();
}
#[test]
fn test_shape_fill_color_roundtrip() {
let engine = Thorvg::init(0).unwrap();
let mut shape = engine.shape();
shape.set_fill_color(100, 150, 200, 255).unwrap();
let (r, g, b, a) = shape.fill_color().unwrap();
assert_eq!((r, g, b, a), (100, 150, 200, 255));
}
#[test]
fn test_shape_stroke_roundtrip() {
let engine = Thorvg::init(0).unwrap();
let mut shape = engine.shape();
shape.append_circle(50.0, 50.0, 30.0, 30.0, true).unwrap();
shape.set_stroke_width(3.0).unwrap();
shape.set_stroke_color(0, 255, 0, 255).unwrap();
shape.set_stroke_cap(StrokeCap::Round).unwrap();
shape.set_stroke_join(StrokeJoin::Bevel).unwrap();
shape.set_stroke_miterlimit(8.0).unwrap();
assert!((shape.stroke_width().unwrap() - 3.0).abs() < f32::EPSILON);
let (r, g, b, a) = shape.stroke_color().unwrap();
assert_eq!((r, g, b, a), (0, 255, 0, 255));
assert_eq!(shape.stroke_cap().unwrap(), StrokeCap::Round);
assert_eq!(shape.stroke_join().unwrap(), StrokeJoin::Bevel);
assert!((shape.stroke_miterlimit().unwrap() - 8.0).abs() < f32::EPSILON);
}
#[test]
fn test_shape_fill_rule_roundtrip() {
let engine = Thorvg::init(0).unwrap();
let mut shape = engine.shape();
assert_eq!(shape.fill_rule().unwrap(), FillRule::NonZero);
shape.set_fill_rule(FillRule::EvenOdd).unwrap();
assert_eq!(shape.fill_rule().unwrap(), FillRule::EvenOdd);
}
#[test]
fn test_paint_opacity_roundtrip() {
let engine = Thorvg::init(0).unwrap();
let mut shape = engine.shape();
shape.set_opacity(128).unwrap();
assert_eq!(shape.opacity().unwrap(), 128);
}
#[test]
fn test_paint_visibility_roundtrip() {
let engine = Thorvg::init(0).unwrap();
let mut shape = engine.shape();
assert!(shape.visible());
shape.set_visible(false).unwrap();
assert!(!shape.visible());
shape.set_visible(true).unwrap();
assert!(shape.visible());
}
#[test]
fn test_paint_transform_roundtrip() {
let engine = Thorvg::init(0).unwrap();
let mut shape = engine.shape();
let m = Matrix {
e11: 2.0,
e12: 0.5,
e13: 10.0,
e21: 0.0,
e22: 3.0,
e23: 20.0,
e31: 0.0,
e32: 0.0,
e33: 1.0,
};
shape.set_transform(&m).unwrap();
let got = shape.transform().unwrap();
assert!((got.e11 - 2.0).abs() < f32::EPSILON);
assert!((got.e12 - 0.5).abs() < f32::EPSILON);
assert!((got.e13 - 10.0).abs() < f32::EPSILON);
assert!((got.e22 - 3.0).abs() < f32::EPSILON);
assert!((got.e23 - 20.0).abs() < f32::EPSILON);
}
#[test]
fn test_paint_id_roundtrip() {
let engine = Thorvg::init(0).unwrap();
let mut shape = engine.shape();
shape.set_id(42).unwrap();
assert_eq!(shape.id(), 42);
}
#[test]
fn test_paint_type() {
let engine = Thorvg::init(0).unwrap();
let shape = engine.shape();
assert_eq!(shape.paint_type().unwrap(), PaintType::Shape);
let scene = engine.scene();
assert_eq!(scene.paint_type().unwrap(), PaintType::Scene);
let picture = engine.picture();
assert_eq!(picture.paint_type().unwrap(), PaintType::Picture);
let text = engine.text();
assert_eq!(text.paint_type().unwrap(), PaintType::Text);
}
#[test]
fn test_linear_gradient_roundtrip() {
let engine = Thorvg::init(0).unwrap();
let mut grad = engine.linear_gradient();
grad.set_bounds(10.0, 20.0, 300.0, 400.0).unwrap();
let (x1, y1, x2, y2) = grad.bounds().unwrap();
assert!((x1 - 10.0).abs() < f32::EPSILON);
assert!((y1 - 20.0).abs() < f32::EPSILON);
assert!((x2 - 300.0).abs() < f32::EPSILON);
assert!((y2 - 400.0).abs() < f32::EPSILON);
}
#[test]
fn test_radial_gradient_roundtrip() {
let engine = Thorvg::init(0).unwrap();
let mut grad = engine.radial_gradient();
grad.set_radial(100.0, 120.0, 50.0, 10.0, 20.0, 5.0)
.unwrap();
let (cx, cy, r, fx, fy, fr) = grad.radial().unwrap();
assert!((cx - 100.0).abs() < f32::EPSILON);
assert!((cy - 120.0).abs() < f32::EPSILON);
assert!((r - 50.0).abs() < f32::EPSILON);
assert!((fx - 10.0).abs() < f32::EPSILON);
assert!((fy - 20.0).abs() < f32::EPSILON);
assert!((fr - 5.0).abs() < f32::EPSILON);
}
#[test]
fn test_gradient_spread_roundtrip() {
let engine = Thorvg::init(0).unwrap();
let mut grad = engine.linear_gradient();
assert_eq!(grad.spread().unwrap(), FillSpread::Pad);
grad.set_spread(FillSpread::Reflect).unwrap();
assert_eq!(grad.spread().unwrap(), FillSpread::Reflect);
grad.set_spread(FillSpread::Repeat).unwrap();
assert_eq!(grad.spread().unwrap(), FillSpread::Repeat);
}
#[test]
fn test_gradient_color_stops_roundtrip() {
let engine = Thorvg::init(0).unwrap();
let mut grad = engine.linear_gradient();
let stops = [
ColorStop {
offset: 0.0,
r: 10,
g: 20,
b: 30,
a: 40,
},
ColorStop {
offset: 0.5,
r: 100,
g: 110,
b: 120,
a: 130,
},
ColorStop {
offset: 1.0,
r: 200,
g: 210,
b: 220,
a: 230,
},
];
grad.set_color_stops(&stops).unwrap();
let got = grad.color_stops().unwrap();
assert_eq!(got.len(), 3);
for (a, b) in stops.iter().zip(got.iter()) {
assert!((a.offset - b.offset).abs() < f32::EPSILON);
assert_eq!(a.r, b.r);
assert_eq!(a.g, b.g);
assert_eq!(a.b, b.b);
}
}
#[test]
fn test_stroke_dash_roundtrip() {
let engine = Thorvg::init(0).unwrap();
let mut shape = engine.shape();
shape.set_stroke_width(2.0).unwrap();
shape.set_stroke_dash(&[10.0, 5.0, 3.0], 2.5).unwrap();
let (pattern, offset) = shape.stroke_dash().unwrap();
assert_eq!(pattern.len(), 3);
assert!((pattern[0] - 10.0).abs() < f32::EPSILON);
assert!((pattern[1] - 5.0).abs() < f32::EPSILON);
assert!((pattern[2] - 3.0).abs() < f32::EPSILON);
assert!((offset - 2.5).abs() < f32::EPSILON);
}
#[test]
fn test_picture_create_destroy() {
let engine = Thorvg::init(0).unwrap();
let _pic = engine.picture();
}
#[test]
fn test_picture_load_svg_from_memory() {
let engine = Thorvg::init(0).unwrap();
let svg = b"<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 100 100\"><rect width=\"100\" height=\"100\" fill=\"red\"/></svg>";
let mut pic = engine.picture();
pic.load_data(svg, "svg", None, true).unwrap();
let (w, h) = pic.size().unwrap();
assert!(w > 0.0);
assert!(h > 0.0);
}
#[test]
fn test_animation_create_destroy() {
let engine = Thorvg::init(0).unwrap();
let _anim = engine.animation();
}
#[test]
fn test_saver_create_destroy() {
let engine = Thorvg::init(0).unwrap();
let _saver = engine.saver();
}
#[test]
fn test_accessor_create_destroy() {
let engine = Thorvg::init(0).unwrap();
let _acc = engine.accessor();
}
#[test]
fn test_accessor_generate_id() {
let _engine = Thorvg::init(0).unwrap();
let id = Accessor::generate_id("test_layer");
assert!(id.is_some());
let id2 = Accessor::generate_id("test_layer");
assert_eq!(id, id2); let id3 = Accessor::generate_id("other_layer");
assert_ne!(id, id3); }
#[test]
fn test_invalid_picture_load() {
let engine = Thorvg::init(0).unwrap();
let mut pic = engine.picture();
let result = pic.load_from_str("/nonexistent/path.svg");
assert!(result.is_err());
}
#[test]
fn test_shape_stroke_color_without_stroke() {
let engine = Thorvg::init(0).unwrap();
let shape = engine.shape();
let result = shape.stroke_color();
assert!(result.is_err());
}
#[test]
fn test_clip_lifecycle() {
let engine = Thorvg::init(0).unwrap();
let mut canvas = engine.sw_canvas(EngineOption::Default).unwrap();
let mut buffer = vec![0u32; 100 * 100];
unsafe { canvas.set_target(&mut buffer, 100, 100, 100, ColorSpace::ABGR8888) }.unwrap();
let mut shape = engine.shape();
shape
.append_rect(0.0, 0.0, 100.0, 100.0, 0.0, 0.0, true)
.unwrap();
shape.set_fill_color(255, 0, 0, 255).unwrap();
let mut clipper = engine.shape();
clipper.append_circle(50.0, 50.0, 30.0, 30.0, true).unwrap();
shape.set_clip(&clipper).unwrap();
canvas.push(shape).unwrap();
canvas.draw(true).unwrap();
canvas.sync().unwrap();
}
#[test]
fn test_full_pipeline_scene_with_effects() {
let engine = Thorvg::init(0).unwrap();
let mut canvas = engine.sw_canvas(EngineOption::Default).unwrap();
let mut buffer = vec![0u32; 200 * 200];
unsafe { canvas.set_target(&mut buffer, 200, 200, 200, ColorSpace::ABGR8888) }.unwrap();
let mut scene = engine.scene();
let mut s1 = engine.shape();
s1.append_rect(10.0, 10.0, 80.0, 80.0, 5.0, 5.0, true)
.unwrap();
s1.set_fill_color(255, 0, 0, 255).unwrap();
scene.push(s1).unwrap();
let mut s2 = engine.shape();
s2.append_circle(120.0, 50.0, 30.0, 30.0, true).unwrap();
s2.set_fill_color(0, 0, 255, 255).unwrap();
scene.push(s2).unwrap();
scene.add_gaussian_blur(2.0, 0, 0, 50).unwrap();
scene.translate(10.0, 10.0).unwrap();
canvas.push(scene).unwrap();
canvas.draw(true).unwrap();
canvas.sync().unwrap();
assert!(buffer.iter().any(|&px| px != 0));
}