use super::*;
use crate::server::TEST_MSG;
use crate::test_support::server::{mock_binding, mock_server};
use sdk_raw::vcall;
use std::cell::RefCell;
use std::ffi::c_char;
thread_local! {
static PRINTED: RefCell<Vec<CString>> = const { RefCell::new(Vec::new()) };
}
unsafe extern "C" fn msg(_format: *const c_char, mut arguments: ...) {
let printed = unsafe { CStr::from_ptr(arguments.next_arg::<*const c_char>()) }.to_owned();
PRINTED.with_borrow_mut(|lines| lines.push(printed));
}
fn prepare(variable: &'static ConsoleVariable) {
unsafe { variable.prepare(mock_binding(), 0) };
}
fn set_as_engine(variable: &ConsoleVariable, text: &CStr, float: f32, int: c_int) {
unsafe {
let interface = ConVarObject::interface(variable.object_ptr()).as_ptr();
vcall!(interface => IConVar_SetValue(text.as_ptr()));
vcall!(interface => IConVar_SetValue1(float));
vcall!(interface => IConVar_SetValue2(int));
}
}
#[test]
fn the_engine_changes_a_variable() {
static VARIABLE: ConsoleVariable = ConsoleVariable::new(c"sb_test_changeable", c"idle");
let scope = ();
let server = mock_server(&scope);
prepare(&VARIABLE);
TEST_MSG.set(Some(msg));
set_as_engine(&VARIABLE, c"calm", 2.5, 3);
assert_eq!(VARIABLE.string(server), c"3");
assert_eq!(VARIABLE.int(server), 3);
assert!(PRINTED.take().is_empty());
TEST_MSG.set(None);
}
#[test]
fn the_engine_cannot_change_a_read_only_variable() {
static VARIABLE: ConsoleVariable =
ConsoleVariable::new(c"sb_test_read_only", c"idle").read_only();
let scope = ();
let server = mock_server(&scope);
prepare(&VARIABLE);
TEST_MSG.set(Some(msg));
set_as_engine(&VARIABLE, c"calm", 2.5, 3);
assert_eq!(VARIABLE.string(server), c"idle");
assert_eq!(VARIABLE.float(server), 0.0);
assert_eq!(PRINTED.take(), [c"sb_test_read_only is read-only.\n"; 3]);
VARIABLE.set_string(server, c"pregame");
assert_eq!(VARIABLE.string(server), c"pregame");
VARIABLE.revert(server);
assert_eq!(VARIABLE.string(server), c"idle");
assert!(PRINTED.take().is_empty());
TEST_MSG.set(None);
}