Files
oak-editor/crates/oakengine/tests/render.rs
T
Mike-Solar 18ff60f147 feat(engine): clip move, clip effect_input, mandatory static FFmpeg
- oakengine_sequence_move_clip implemented for real (oaktimeline
  TrackMoveBlockCommand; fixes the graph-ownership/gap-anchor/ripple
  trim bugs the stub was hiding); same-track via the frozen C ABI,
  cross-track supported by the module command
- oaknode clip blocks now declare a tex_in texture input and set
  effect_input to it, so timeline clips can host effect chains; facade
  test covers effect insert/remove on a real clip
- oakffmpeg-link: FFMPEG_DIR is now mandatory with a clear panic (a
  Homebrew upgrade left the system ffmpeg .pc pointing at a deleted
  dav1d Cellar path, breaking links); reads a git-ignored workspace
  .env for IDEs that cannot inject env vars (RustRover); links the C++
  stdlib for C++ codec libs (svt-av1)
- oakengine re-exports oaknode so tests share one crate instance;
  it_node uses the direct instance's value type where it calls the
  module FFI (the --workspace dev-dependency feature split builds
  oaknode twice)
2026-08-11 23:04:48 +08:00

180 lines
5.6 KiB
Rust

// Oak Video Editor - Non-Linear Video Editor
// Copyright (C) 2026 Oak Team
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//! Smoke tests for the render family (`engine/include/oakengine/
//! {renderer,color,lut}.h`). The render manager is not initialized in
//! tests, so the manager/cacher families exercise the module's STATE
//! error path and the renderer/color families exercise the NULL/invalid
//! argument paths (real rendering needs the deferred node family plus an
//! initialized render manager).
#[path = "common/mod.rs"]
mod common;
use std::ffi::{c_char, c_double};
use oakengine::render::{
oakengine_color_last_error, oakengine_color_manager_get_config_filename,
oakengine_color_processor_convert_color, oakengine_color_processor_create,
oakengine_color_processor_free, oakengine_color_processor_is_valid,
oakengine_frame_channel_count, oakengine_frame_data, oakengine_frame_free,
oakengine_frame_height, oakengine_frame_width, oakengine_lut_directory_count,
oakengine_lut_set_directories, oakengine_render_cache_set_display_color_processor,
oakengine_render_cache_set_multicam_node, oakengine_render_manager_requested_backend,
oakengine_render_manager_set_aggressive_garbage_collection, oakengine_renderer_create,
oakengine_renderer_free, oakengine_renderer_last_error, oakengine_renderer_set_mode,
OakColorTransformPod,
};
/// Render manager state without initialization: the module reports its
/// STATE error, passed through untranslated (-70002).
#[test]
fn render_manager_not_initialized() {
assert_eq!(
unsafe { oakengine_render_manager_set_aggressive_garbage_collection(1) },
-70002
);
// Cache setters with NULL handles → same module STATE.
assert_eq!(
unsafe { oakengine_render_cache_set_display_color_processor(std::ptr::null_mut()) },
-70002
);
assert_eq!(
unsafe { oakengine_render_cache_set_multicam_node(std::ptr::null_mut()) },
-70002
);
// The requested-backend stub reports 0 (k_open_gl) when unavailable.
assert_eq!(unsafe { oakengine_render_manager_requested_backend() }, 0);
}
/// Renderer lifecycle: NULL sequence is rejected; mode validation.
#[test]
fn renderer_lifecycle() {
// NULL seq → NULL renderer.
let r = unsafe {
oakengine_renderer_create(
std::ptr::null_mut(),
1920,
1080,
4,
30000,
1001,
std::ptr::null(),
)
};
assert!(r.is_null());
// NULL free / last_error are safe.
unsafe { oakengine_renderer_free(std::ptr::null_mut()) };
let mut buf = [0 as c_char; 64];
assert_eq!(
unsafe { oakengine_renderer_last_error(std::ptr::null(), buf.as_mut_ptr(), 64) },
-1
);
assert_eq!(
unsafe { oakengine_renderer_set_mode(std::ptr::null_mut(), 0) },
-1
);
}
/// Frame accessors on NULL / empty handles report zero/NULL safely.
#[test]
fn frame_accessors_null_safe() {
assert_eq!(unsafe { oakengine_frame_width(std::ptr::null()) }, 0);
assert_eq!(unsafe { oakengine_frame_height(std::ptr::null()) }, 0);
assert_eq!(
unsafe { oakengine_frame_channel_count(std::ptr::null()) },
0
);
assert!(unsafe { oakengine_frame_data(std::ptr::null()) }.is_null());
unsafe { oakengine_frame_free(std::ptr::null_mut()) };
}
/// Color processor: NULL input is rejected; a valid-argument call either
/// returns a handle (possibly invalid — OCIO may be a stub bridge) or
/// NULL; freeing is safe either way.
#[test]
fn color_processor_lifecycle() {
// NULL input → NULL.
let p = unsafe {
oakengine_color_processor_create(std::ptr::null(), std::ptr::null(), std::ptr::null(), 0)
};
assert!(p.is_null());
// Valid arguments: the engine contract allows NULL (OCIO unavailable)
// or a handle whose is_valid may be 0.
let mut dest = OakColorTransformPod {
is_display: 0,
output: c"ACEScg".as_ptr(),
view: std::ptr::null(),
look: std::ptr::null(),
};
let p = unsafe {
oakengine_color_processor_create(
std::ptr::null(),
c"Linear Rec.709 (sRGB)".as_ptr(),
&dest,
0,
)
};
if !p.is_null() {
let valid = unsafe { oakengine_color_processor_is_valid(p) };
assert!(valid == 0 || valid == 1);
unsafe { oakengine_color_processor_free(p) };
}
// NULL free is a no-op.
unsafe { oakengine_color_processor_free(std::ptr::null_mut()) };
// convert_color with a NULL processor → E_INVALID.
let mut out_rgba = [0.0_f64; 4];
let in_rgba = [0.5_f64, 0.5, 0.5, 1.0];
assert_eq!(
unsafe {
oakengine_color_processor_convert_color(
std::ptr::null(),
in_rgba.as_ptr(),
out_rgba.as_mut_ptr(),
)
},
-1
);
let _ = dest;
}
/// Color manager config path: without a configured manager the module
/// reports STATE; the last-error string starts empty.
#[test]
fn color_manager_and_error() {
let mut buf = [0 as c_char; 64];
let rc = unsafe {
oakengine_color_manager_get_config_filename(std::ptr::null(), buf.as_mut_ptr(), 64)
};
assert_eq!(rc, -70002);
let len = unsafe { oakengine_color_last_error(buf.as_mut_ptr(), 64) };
assert_eq!(len, 0);
}
/// LUT library stubs report the documented neutral values.
#[test]
fn lut_library_stubs() {
assert_eq!(unsafe { oakengine_lut_directory_count() }, 0);
assert_eq!(
unsafe { oakengine_lut_set_directories(std::ptr::null(), 0) },
-3
);
}