#![allow(clippy::items_after_statements)]
use screencapturekit::prelude::*;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
fn init_cg() {
extern "C" {
fn sc_initialize_core_graphics();
}
unsafe { sc_initialize_core_graphics() }
}
#[test]
fn test_shareable_content_drop() {
init_cg();
for _ in 0..10 {
let content = SCShareableContent::get().expect("Failed to get content");
let _displays = content.displays();
let _windows = content.windows();
let _apps = content.applications();
}
}
#[test]
fn test_clone_and_drop() {
init_cg();
let content = SCShareableContent::get().expect("Failed to get content");
let displays = content.displays();
if let Some(display) = displays.first() {
let clones: Vec<_> = (0..100).map(|_| display.clone()).collect();
drop(clones);
let _ = display.display_id();
}
let windows = content.windows();
if let Some(window) = windows.first() {
let clones: Vec<_> = (0..100).map(|_| window.clone()).collect();
drop(clones);
let _ = window.window_id();
}
}
#[test]
fn test_content_filter_memory() {
init_cg();
let content = SCShareableContent::get().expect("Failed to get content");
let displays = content.displays();
if let Some(display) = displays.first() {
let filters: Vec<_> = (0..50)
.map(|_| {
SCContentFilter::create()
.with_display(display)
.with_excluding_windows(&[])
.build()
})
.collect();
let cloned: Vec<_> = filters.clone();
drop(cloned);
drop(filters);
}
}
#[test]
fn test_stream_configuration_memory() {
let configs: Vec<_> = (0..100)
.map(|i: i32| {
SCStreamConfiguration::new()
.with_width(1920)
.with_height(1080)
.with_fps(30 + (i.unsigned_abs() % 30))
.with_shows_cursor(true)
.with_captures_audio(true)
})
.collect();
let cloned: Vec<_> = configs.clone();
drop(cloned);
drop(configs);
}
#[test]
fn test_stream_lifecycle() {
init_cg();
let content = SCShareableContent::get().expect("Failed to get content");
let displays = content.displays();
if let Some(display) = displays.first() {
let filter = SCContentFilter::create()
.with_display(display)
.with_excluding_windows(&[])
.build();
let config = SCStreamConfiguration::new()
.with_width(640)
.with_height(480);
for _ in 0..5 {
let stream = SCStream::new(&filter, &config);
drop(stream);
}
}
}
#[test]
fn test_handler_registration_cleanup() {
init_cg();
struct TestHandler {
count: Arc<AtomicUsize>,
}
impl SCStreamOutputTrait for TestHandler {
fn did_output_sample_buffer(&self, _sample: CMSampleBuffer, _of_type: SCStreamOutputType) {
self.count.fetch_add(1, Ordering::Relaxed);
}
}
let content = SCShareableContent::get().expect("Failed to get content");
let displays = content.displays();
if let Some(display) = displays.first() {
let filter = SCContentFilter::create()
.with_display(display)
.with_excluding_windows(&[])
.build();
let config = SCStreamConfiguration::new()
.with_width(640)
.with_height(480);
for _ in 0..10 {
let mut stream = SCStream::new(&filter, &config);
let count = Arc::new(AtomicUsize::new(0));
let handler = TestHandler {
count: count.clone(),
};
let id = stream.add_output_handler(handler, SCStreamOutputType::Screen);
if let Some(handler_id) = id {
stream.remove_output_handler(handler_id, SCStreamOutputType::Screen);
}
drop(stream);
}
}
}
#[test]
fn test_closure_handler_memory() {
init_cg();
let content = SCShareableContent::get().expect("Failed to get content");
let displays = content.displays();
if let Some(display) = displays.first() {
let filter = SCContentFilter::create()
.with_display(display)
.with_excluding_windows(&[])
.build();
let config = SCStreamConfiguration::new()
.with_width(640)
.with_height(480);
for _ in 0..10 {
let mut stream = SCStream::new(&filter, &config);
let count = Arc::new(AtomicUsize::new(0));
let count_clone = count.clone();
stream.add_output_handler(
move |_sample: CMSampleBuffer, _of_type: SCStreamOutputType| {
count_clone.fetch_add(1, Ordering::Relaxed);
},
SCStreamOutputType::Screen,
);
drop(stream);
drop(count);
}
}
}
#[test]
fn test_geometry_types() {
use screencapturekit::cg::{CGPoint, CGRect, CGSize};
for _ in 0..1000 {
let point = CGPoint { x: 100.0, y: 200.0 };
let size = CGSize {
width: 1920.0,
height: 1080.0,
};
let rect = CGRect::new(point.x, point.y, size.width, size.height);
let _ = rect.origin.x;
let _ = rect.origin.y;
let _ = rect.size.width;
let _ = rect.size.height;
}
}
#[test]
fn test_cmtime_memory() {
use screencapturekit::cm::CMTime;
for _ in 0..1000 {
let time = CMTime::new(1, 30);
let _ = time.as_seconds();
let _ = time.is_valid();
let time2 = CMTime::new(0, 1);
let _ = time2.is_zero();
}
}
#[test]
fn test_dispatch_queue_memory() {
use screencapturekit::dispatch_queue::{DispatchQoS, DispatchQueue};
for i in 0..20 {
let queue = DispatchQueue::new(&format!("com.test.queue.{i}"), DispatchQoS::Default);
let cloned = queue.clone();
drop(cloned);
drop(queue);
}
}
#[test]
fn test_multiple_streams_memory() {
init_cg();
let content = SCShareableContent::get().expect("Failed to get content");
let displays = content.displays();
if let Some(display) = displays.first() {
let filter = SCContentFilter::create()
.with_display(display)
.with_excluding_windows(&[])
.build();
let config = SCStreamConfiguration::new()
.with_width(320)
.with_height(240);
let streams: Vec<_> = (0..5)
.map(|_| {
let mut stream = SCStream::new(&filter, &config);
let count = Arc::new(AtomicUsize::new(0));
let count_clone = count.clone();
stream.add_output_handler(
move |_: CMSampleBuffer, _: SCStreamOutputType| {
count_clone.fetch_add(1, Ordering::Relaxed);
},
SCStreamOutputType::Screen,
);
(stream, count)
})
.collect();
drop(streams);
}
}
#[test]
fn test_window_filter_memory() {
init_cg();
let content = SCShareableContent::get().expect("Failed to get content");
let windows = content.windows();
if let Some(window) = windows.first() {
let filters: Vec<_> = (0..50)
.map(|_| SCContentFilter::create().with_window(window).build())
.collect();
drop(filters);
}
}
#[test]
#[cfg(feature = "macos_15_0")]
fn test_audio_config_memory() {
for _ in 0..100 {
let config = SCStreamConfiguration::new()
.with_captures_audio(true)
.with_sample_rate(48000)
.with_channel_count(2)
.with_captures_microphone(true)
.with_excludes_current_process_audio(true);
let _ = config.captures_audio();
let _ = config.sample_rate();
let _ = config.channel_count();
drop(config);
}
}
#[cfg(feature = "macos_14_0")]
mod macos_14_tests {
use super::*;
use screencapturekit::shareable_content::SCShareableContentInfo;
#[test]
fn test_content_info_memory() {
init_cg();
let content = SCShareableContent::get().expect("Failed to get content");
let displays = content.displays();
if let Some(display) = displays.first() {
let filter = SCContentFilter::create()
.with_display(display)
.with_excluding_windows(&[])
.build();
for _ in 0..20 {
if let Some(info) = SCShareableContentInfo::for_filter(&filter) {
let _ = info.style();
let _ = info.point_pixel_scale();
let _ = info.pixel_size();
}
}
}
}
#[test]
fn test_picker_config_memory() {
use screencapturekit::content_sharing_picker::{
SCContentSharingPickerConfiguration, SCContentSharingPickerMode,
};
for _ in 0..50 {
let mut config = SCContentSharingPickerConfiguration::new();
config.set_allowed_picker_modes(&[
SCContentSharingPickerMode::SingleWindow,
SCContentSharingPickerMode::SingleDisplay,
]);
let cloned = config.clone();
drop(cloned);
drop(config);
}
}
}
#[cfg(feature = "macos_15_0")]
mod macos_15_tests {
#[test]
fn test_recording_config_memory() {
use screencapturekit::recording_output::{
SCRecordingOutputCodec, SCRecordingOutputConfiguration, SCRecordingOutputFileType,
};
for _ in 0..50 {
let config = SCRecordingOutputConfiguration::new()
.with_video_codec(SCRecordingOutputCodec::H264)
.with_output_file_type(SCRecordingOutputFileType::MP4);
let _ = config.video_codec();
let _ = config.output_file_type();
let cloned = config.clone();
drop(cloned);
drop(config);
}
}
}
#[test]
fn test_metal_texture_clone_soak() {
use screencapturekit::cm::IOSurface;
use screencapturekit::metal::{IOSurfaceMetalExt, MetalDevice};
let Some(device) = MetalDevice::system_default() else {
eprintln!("skipping: no Metal device in this environment");
return;
};
let surface = IOSurface::create(64, 64, 0x4247_5241, 4).expect("Failed to create IOSurface");
let textures = surface
.create_metal_textures(&device)
.expect("Failed to create textures");
for _ in 0..10_000 {
let clones: Vec<_> = (0..8).map(|_| textures.plane0.clone()).collect();
drop(clones);
}
assert_eq!(textures.plane0.width(), 64);
assert_eq!(textures.plane0.height(), 64);
assert!(!textures.plane0.as_ptr().is_null());
}