Skip to content

Commit 3adc278

Browse files
committed
Add more tests to verify FFI pointers are stable over multiple API calls.
1 parent 72ca3ac commit 3adc278

3 files changed

Lines changed: 181 additions & 14 deletions

File tree

mp4parse_capi/tests/test_avis.rs

Lines changed: 176 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use mp4parse::unstable::Indice;
12
use mp4parse_capi::*;
23
use num_traits::ToPrimitive;
34
use std::io::Read;
@@ -11,19 +12,8 @@ extern "C" fn buf_read(buf: *mut u8, size: usize, userdata: *mut std::os::raw::c
1112
}
1213
}
1314

14-
unsafe fn parse_file_and_get_info(path: &str) -> (*mut Mp4parseAvifParser, Mp4parseAvifInfo) {
15-
let mut file = std::fs::File::open(path).expect("Unknown file");
16-
let io = Mp4parseIo {
17-
read: Some(buf_read),
18-
userdata: &mut file as *mut _ as *mut std::os::raw::c_void,
19-
};
20-
21-
let mut parser = std::ptr::null_mut();
22-
let mut rv = mp4parse_avif_new(&io, ParseStrictness::Normal, &mut parser);
23-
assert_eq!(rv, Mp4parseStatus::Ok);
24-
assert!(!parser.is_null());
25-
26-
let mut info = Mp4parseAvifInfo {
15+
fn default_avif_info() -> Mp4parseAvifInfo {
16+
Mp4parseAvifInfo {
2717
premultiplied_alpha: Default::default(),
2818
major_brand: Default::default(),
2919
unsupported_features_bitfield: Default::default(),
@@ -44,12 +34,44 @@ unsafe fn parse_file_and_get_info(path: &str) -> (*mut Mp4parseAvifParser, Mp4pa
4434
color_track_bit_depth: Default::default(),
4535
alpha_track_id: Default::default(),
4636
alpha_track_bit_depth: Default::default(),
37+
}
38+
}
39+
40+
fn default_avif_image() -> Mp4parseAvifImage {
41+
Mp4parseAvifImage {
42+
primary_image: Default::default(),
43+
alpha_image: Default::default(),
44+
}
45+
}
46+
47+
unsafe fn parse_file(path: &str) -> *mut Mp4parseAvifParser {
48+
let mut file = std::fs::File::open(path).expect("Unknown file");
49+
let io = Mp4parseIo {
50+
read: Some(buf_read),
51+
userdata: &mut file as *mut _ as *mut std::os::raw::c_void,
4752
};
48-
rv = mp4parse_avif_get_info(parser, &mut info);
53+
54+
let mut parser = std::ptr::null_mut();
55+
let rv = mp4parse_avif_new(&io, ParseStrictness::Normal, &mut parser);
56+
assert_eq!(rv, Mp4parseStatus::Ok);
57+
assert!(!parser.is_null());
58+
59+
parser
60+
}
61+
62+
unsafe fn parse_file_and_get_info(path: &str) -> (*mut Mp4parseAvifParser, Mp4parseAvifInfo) {
63+
let parser = parse_file(path);
64+
let mut info = default_avif_info();
65+
let rv = mp4parse_avif_get_info(parser, &mut info);
4966
assert_eq!(rv, Mp4parseStatus::Ok);
5067
(parser, info)
5168
}
5269

70+
unsafe fn assert_slice_pointer_is_readable<T>(ptr: *const T, len: usize) {
71+
let slice = std::slice::from_raw_parts(ptr, len);
72+
assert_eq!(slice.len(), len);
73+
}
74+
5375
fn check_loop_count(path: &str, expected_loop_count: i64) {
5476
let (parser, info) = unsafe { parse_file_and_get_info(path) };
5577
match info.loop_mode {
@@ -111,3 +133,143 @@ fn check_timescales() {
111133
check_timescale("tests/loop_forever.avif", 2);
112134
check_timescale("tests/no_edts.avif", 16384);
113135
}
136+
137+
#[test]
138+
fn repeated_get_info_returns_stable_pointers() {
139+
let (parser, info1) = unsafe { parse_file_and_get_info("tests/loop_1.avif") };
140+
141+
unsafe {
142+
let mut info2 = default_avif_info();
143+
let rv = mp4parse_avif_get_info(parser, &mut info2);
144+
assert_eq!(rv, Mp4parseStatus::Ok);
145+
146+
assert_eq!(info1.spatial_extents, info2.spatial_extents);
147+
assert!(!info1.spatial_extents.is_null());
148+
assert_slice_pointer_is_readable(info1.spatial_extents, 1);
149+
150+
assert_eq!(info1.nclx_colour_information, info2.nclx_colour_information);
151+
if !info1.nclx_colour_information.is_null() {
152+
assert_slice_pointer_is_readable(info1.nclx_colour_information, 1);
153+
}
154+
155+
assert_eq!(
156+
info1.icc_colour_information.length,
157+
info2.icc_colour_information.length
158+
);
159+
assert_eq!(
160+
info1.icc_colour_information.data,
161+
info2.icc_colour_information.data
162+
);
163+
if info1.icc_colour_information.length == 0 {
164+
assert!(info1.icc_colour_information.data.is_null());
165+
} else {
166+
assert_slice_pointer_is_readable(
167+
info1.icc_colour_information.data,
168+
info1.icc_colour_information.length,
169+
);
170+
}
171+
172+
assert_eq!(info1.image_mirror, info2.image_mirror);
173+
if !info1.image_mirror.is_null() {
174+
assert_slice_pointer_is_readable(info1.image_mirror, 1);
175+
}
176+
177+
assert_eq!(info1.pixel_aspect_ratio, info2.pixel_aspect_ratio);
178+
if !info1.pixel_aspect_ratio.is_null() {
179+
assert_slice_pointer_is_readable(info1.pixel_aspect_ratio, 1);
180+
}
181+
182+
mp4parse_avif_free(parser);
183+
}
184+
}
185+
186+
#[test]
187+
fn repeated_get_image_returns_stable_pointers() {
188+
let parser = unsafe { parse_file("tests/loop_1.avif") };
189+
190+
unsafe {
191+
let mut image1 = default_avif_image();
192+
let rv = mp4parse_avif_get_image(parser, &mut image1);
193+
assert_eq!(rv, Mp4parseStatus::Ok);
194+
assert!(image1.primary_image.length > 0);
195+
assert!(!image1.primary_image.data.is_null());
196+
assert!(image1.alpha_image.length > 0);
197+
assert!(!image1.alpha_image.data.is_null());
198+
199+
let mut image2 = default_avif_image();
200+
let rv = mp4parse_avif_get_image(parser, &mut image2);
201+
assert_eq!(rv, Mp4parseStatus::Ok);
202+
203+
assert_eq!(image1.primary_image.length, image2.primary_image.length);
204+
assert_eq!(image1.primary_image.data, image2.primary_image.data);
205+
assert_eq!(image1.alpha_image.length, image2.alpha_image.length);
206+
assert_eq!(image1.alpha_image.data, image2.alpha_image.data);
207+
208+
assert_slice_pointer_is_readable(image1.primary_image.data, image1.primary_image.length);
209+
assert_slice_pointer_is_readable(image1.alpha_image.data, image1.alpha_image.length);
210+
211+
mp4parse_avif_free(parser);
212+
}
213+
}
214+
215+
#[test]
216+
fn repeated_get_indice_table_returns_stable_pointer() {
217+
let (parser, info) = unsafe { parse_file_and_get_info("tests/loop_1.avif") };
218+
219+
unsafe {
220+
let mut indices1 = Mp4parseByteData::default();
221+
let mut timescale1: u64 = 0;
222+
let rv = mp4parse_avif_get_indice_table(
223+
parser,
224+
info.color_track_id,
225+
&mut indices1,
226+
&mut timescale1,
227+
);
228+
assert_eq!(rv, Mp4parseStatus::Ok);
229+
assert!(indices1.length > 0);
230+
assert!(!indices1.indices.is_null());
231+
232+
let mut indices2 = Mp4parseByteData::default();
233+
let mut timescale2: u64 = 0;
234+
let rv = mp4parse_avif_get_indice_table(
235+
parser,
236+
info.color_track_id,
237+
&mut indices2,
238+
&mut timescale2,
239+
);
240+
assert_eq!(rv, Mp4parseStatus::Ok);
241+
242+
assert_eq!(timescale1, timescale2);
243+
assert_eq!(indices1.length, indices2.length);
244+
assert_eq!(indices1.indices, indices2.indices);
245+
assert_slice_pointer_is_readable(indices1.indices, indices1.length);
246+
247+
let first1: &[Indice] = std::slice::from_raw_parts(indices1.indices, indices1.length);
248+
let first2: &[Indice] = std::slice::from_raw_parts(indices2.indices, indices2.length);
249+
assert_eq!(first1[0], first2[0]);
250+
251+
mp4parse_avif_free(parser);
252+
}
253+
}
254+
255+
#[test]
256+
fn empty_avif_byte_slices_use_null_pointers() {
257+
let (parser, info) = unsafe { parse_file_and_get_info("tests/no_edts.avif") };
258+
259+
unsafe {
260+
let mut image = default_avif_image();
261+
let rv = mp4parse_avif_get_image(parser, &mut image);
262+
assert_eq!(rv, Mp4parseStatus::Ok);
263+
264+
assert!(image.primary_image.length > 0);
265+
assert!(!image.primary_image.data.is_null());
266+
assert_eq!(image.alpha_image.length, 0);
267+
assert!(image.alpha_image.data.is_null());
268+
269+
if info.icc_colour_information.length == 0 {
270+
assert!(info.icc_colour_information.data.is_null());
271+
}
272+
273+
mp4parse_avif_free(parser);
274+
}
275+
}

mp4parse_capi/tests/test_encryption.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ fn parse_cenc() {
7070
assert_eq!(protected_data.crypt_byte_block, 0);
7171
assert_eq!(protected_data.skip_byte_block, 0);
7272
assert_eq!(protected_data.constant_iv.length, 0);
73+
assert!(protected_data.constant_iv.data.is_null());
7374

7475
// Verify audio track and crypto information
7576
let mut audio = Mp4parseTrackAudioInfo::default();
@@ -98,6 +99,7 @@ fn parse_cenc() {
9899
assert_eq!(protected_data.crypt_byte_block, 0);
99100
assert_eq!(protected_data.skip_byte_block, 0);
100101
assert_eq!(protected_data.constant_iv.length, 0);
102+
assert!(protected_data.constant_iv.data.is_null());
101103
}
102104
}
103105

@@ -246,9 +248,11 @@ fn parse_unencrypted() {
246248
assert_eq!(protected_data.is_encrypted, 0x00);
247249
assert_eq!(protected_data.iv_size, 0);
248250
assert_eq!(protected_data.kid.length, 0);
251+
assert!(protected_data.kid.data.is_null());
249252
assert_eq!(protected_data.crypt_byte_block, 0);
250253
assert_eq!(protected_data.skip_byte_block, 0);
251254
assert_eq!(protected_data.constant_iv.length, 0);
255+
assert!(protected_data.constant_iv.data.is_null());
252256
}
253257
}
254258

mp4parse_capi/tests/test_fragment.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ fn parse_opus_fragment() {
103103
assert_eq!((*audio.sample_info).bit_depth, 16);
104104
assert_eq!((*audio.sample_info).sample_rate, 48000);
105105
assert_eq!((*audio.sample_info).extra_data.length, 0);
106+
assert!((*audio.sample_info).extra_data.data.is_null());
106107
assert_eq!((*audio.sample_info).codec_specific_config.length, 19);
107108

108109
let mut is_fragmented_file: u8 = 0;

0 commit comments

Comments
 (0)