#![feature(c_variadic)] use core::{ffi::*, ptr::null_mut}; extern "C" { fn asprintf(s: *mut *mut u8, format: *const u8, ...) -> c_int; fn free(p: *mut c_void); } unsafe extern "C" fn rust_fmt(str: *const u8, mut args: ...) -> Box<(c_int, String)> { let mut s = String::new(); let bytes_written = printf_compat::format( str as _, args.clone().as_va_list(), printf_compat::output::fmt_write(&mut s), ); assert!(bytes_written >= 0); let mut s2 = std::io::Cursor::new(vec![]); assert_eq!( bytes_written, printf_compat::format( str as _, args.as_va_list(), printf_compat::output::io_write(&mut s2), ) ); assert_eq!(s.as_bytes(), s2.get_ref()); Box::new((bytes_written, s)) } macro_rules! c_fmt { ($format:expr $(, $p:expr)*) => {{ let mut ptr = null_mut(); let bytes_written = asprintf(&mut ptr, $format $(, $p)*); assert!(bytes_written >= 0); let s: String = CStr::from_ptr(ptr as *const _).to_string_lossy().into(); free(ptr as _); (bytes_written, s) }}; } macro_rules! assert_eq_fmt { ($format:expr $(, $p:expr)*) => { assert_eq!( c_fmt!($format.as_ptr().cast() $(, $p)*), *rust_fmt($format.as_ptr().cast(), $($p),*) ); }; } #[test] fn test_plain() { unsafe { assert_eq_fmt!(c"abc"); assert_eq_fmt!(c""); assert_eq_fmt!(c"%%"); assert_eq_fmt!(c"%% def"); assert_eq_fmt!(c"abc %%"); assert_eq_fmt!(c"abc %% def"); assert_eq_fmt!(c"abc %%%% def"); assert_eq_fmt!(c"%%%%%%"); } } #[test] fn test_str() { unsafe { assert_eq_fmt!(c"hello %s", c"world"); assert_eq_fmt!(c"hello %%%s", c"world"); assert_eq_fmt!(c"%10s", c"world"); assert_eq_fmt!(c"%.4s", c"world"); assert_eq_fmt!(c"%10.4s", c"world"); assert_eq_fmt!(c"%-10.4s", c"world"); assert_eq_fmt!(c"%-10s", c"world"); assert_eq_fmt!(c"%s", null_mut::()); } } #[test] fn test_int() { unsafe { assert_eq_fmt!(c"% 0*i", 23125, 17); assert_eq_fmt!(c"% 010i", 23125); assert_eq_fmt!(c"% 10i", 23125); assert_eq_fmt!(c"% 5i", 23125); assert_eq_fmt!(c"% 4i", 23125); assert_eq_fmt!(c"%- 010i", 23125); assert_eq_fmt!(c"%- 10i", 23125); assert_eq_fmt!(c"%- 5i", 23125); assert_eq_fmt!(c"%- 4i", 23125); assert_eq_fmt!(c"%+ 010i", 23125); assert_eq_fmt!(c"%+ 10i", 23125); assert_eq_fmt!(c"%+ 5i", 23125); assert_eq_fmt!(c"%+ 4i", 23125); assert_eq_fmt!(c"%-010i", 23125); assert_eq_fmt!(c"%-10i", 23125); assert_eq_fmt!(c"%-5i", 23125); assert_eq_fmt!(c"%-4i", 23125); } } #[test] fn test_octal() { unsafe { assert_eq_fmt!(c"% 010o", 23125); assert_eq_fmt!(c"% 10o", 23125); assert_eq_fmt!(c"% 5o", 23125); assert_eq_fmt!(c"% 4o", 23125); assert_eq_fmt!(c"%- 010o", 23125); assert_eq_fmt!(c"%- 10o", 23125); assert_eq_fmt!(c"%- 5o", 23125); assert_eq_fmt!(c"%- 4o", 23125); assert_eq_fmt!(c"%+ 010o", 23125); assert_eq_fmt!(c"%+ 10o", 23125); assert_eq_fmt!(c"%+ 5o", 23125); assert_eq_fmt!(c"%+ 4o", 23125); assert_eq_fmt!(c"%-010o", 23125); assert_eq_fmt!(c"%-10o", 23125); assert_eq_fmt!(c"%-5o", 23125); assert_eq_fmt!(c"%-4o", 23125); } } #[test] fn test_hex() { unsafe { assert_eq_fmt!(c"% 010x", 23125); assert_eq_fmt!(c"% 10x", 23125); assert_eq_fmt!(c"% 5x", 23125); assert_eq_fmt!(c"% 4x", 23125); assert_eq_fmt!(c"%- 010x", 23125); assert_eq_fmt!(c"%- 10x", 23125); assert_eq_fmt!(c"%- 5x", 23125); assert_eq_fmt!(c"%- 4x", 23125); assert_eq_fmt!(c"%+ 010x", 23125); assert_eq_fmt!(c"%+ 10x", 23125); assert_eq_fmt!(c"%+ 5x", 23125); assert_eq_fmt!(c"%+ 4x", 23125); assert_eq_fmt!(c"%-010x", 23125); assert_eq_fmt!(c"%-10x", 23125); assert_eq_fmt!(c"%-5x", 23125); assert_eq_fmt!(c"%-4x", 23125); assert_eq_fmt!(c"%# 010x", 23125); assert_eq_fmt!(c"%# 10x", 23125); assert_eq_fmt!(c"%# 5x", 23125); assert_eq_fmt!(c"%# 4x", 23125); assert_eq_fmt!(c"%#- 010x", 23125); assert_eq_fmt!(c"%#- 10x", 23125); assert_eq_fmt!(c"%#- 5x", 23125); assert_eq_fmt!(c"%#- 4x", 23125); assert_eq_fmt!(c"%#+ 010x", 23125); assert_eq_fmt!(c"%#+ 10x", 23125); assert_eq_fmt!(c"%#+ 5x", 23125); assert_eq_fmt!(c"%#+ 4x", 23125); assert_eq_fmt!(c"%#-010x", 23125); assert_eq_fmt!(c"%#-10x", 23125); assert_eq_fmt!(c"%#-5x", 23125); assert_eq_fmt!(c"%#-4x", 23125); assert_eq_fmt!(c"% 010X", 23125); assert_eq_fmt!(c"% 10X", 23125); assert_eq_fmt!(c"% 5X", 23125); assert_eq_fmt!(c"% 4X", 23125); assert_eq_fmt!(c"%- 010X", 23125); assert_eq_fmt!(c"%- 10X", 23125); assert_eq_fmt!(c"%- 5X", 23125); assert_eq_fmt!(c"%- 4X", 23125); assert_eq_fmt!(c"%+ 010X", 23125); assert_eq_fmt!(c"%+ 10X", 23125); assert_eq_fmt!(c"%+ 5X", 23125); assert_eq_fmt!(c"%+ 4X", 23125); assert_eq_fmt!(c"%-010X", 23125); assert_eq_fmt!(c"%-10X", 23125); assert_eq_fmt!(c"%-5X", 23125); assert_eq_fmt!(c"%-4X", 23125); } } #[test] fn test_float() { unsafe { assert_eq_fmt!(c"%f", 1234f64); assert_eq_fmt!(c"%.5f", 1234f64); assert_eq_fmt!(c"%.*f", 1234f64, 3); } } #[test] fn test_char() { unsafe { assert_eq_fmt!(c"%c", b'a' as c_int); assert_eq_fmt!(c"%10c", b'a' as c_int); assert_eq_fmt!(c"%-10c", b'a' as c_int); } }