Skip to content

Commit 2c0f271

Browse files
committed
Add more unit tests
1 parent 08888dd commit 2c0f271

File tree

4 files changed

+408
-4
lines changed

4 files changed

+408
-4
lines changed

libdd-crashtracker/src/collector/crash_handler.rs

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,3 +266,98 @@ fn handle_posix_signal_impl(
266266

267267
Ok(())
268268
}
269+
270+
#[cfg(test)]
271+
mod tests {
272+
use super::*;
273+
274+
#[test]
275+
fn test_register_panic_hook() {
276+
assert!(PREVIOUS_PANIC_HOOK.load(SeqCst).is_null());
277+
278+
let result = register_panic_hook();
279+
assert!(result.is_ok());
280+
281+
assert!(!PREVIOUS_PANIC_HOOK.load(SeqCst).is_null());
282+
}
283+
284+
#[test]
285+
fn test_panic_message_storage_and_retrieval() {
286+
// Test that panic messages can be stored and retrieved via atomic pointer
287+
let test_message = "test panic message".to_string();
288+
let message_ptr = Box::into_raw(Box::new(test_message.clone()));
289+
290+
// Store the message
291+
let old_ptr = PANIC_MESSAGE.swap(message_ptr, SeqCst);
292+
assert!(old_ptr.is_null()); // Should be null initially
293+
294+
// Retrieve and verify
295+
let retrieved_ptr = PANIC_MESSAGE.swap(ptr::null_mut(), SeqCst);
296+
assert!(!retrieved_ptr.is_null());
297+
298+
unsafe {
299+
let retrieved_message = *Box::from_raw(retrieved_ptr);
300+
assert_eq!(retrieved_message, test_message);
301+
}
302+
}
303+
304+
#[test]
305+
fn test_panic_message_null_handling() {
306+
// Test that null message pointers are handled correctly
307+
PANIC_MESSAGE.store(ptr::null_mut(), SeqCst);
308+
309+
let message_ptr = PANIC_MESSAGE.load(SeqCst);
310+
assert!(message_ptr.is_null());
311+
312+
// Swapping null with null should be safe
313+
let old_ptr = PANIC_MESSAGE.swap(ptr::null_mut(), SeqCst);
314+
assert!(old_ptr.is_null());
315+
}
316+
317+
#[test]
318+
fn test_panic_message_replacement() {
319+
// Test that replacing an existing message cleans up the old one
320+
let message1 = "first message".to_string();
321+
let message2 = "second message".to_string();
322+
323+
let ptr1 = Box::into_raw(Box::new(message1));
324+
let ptr2 = Box::into_raw(Box::new(message2.clone()));
325+
326+
PANIC_MESSAGE.store(ptr1, SeqCst);
327+
let old_ptr = PANIC_MESSAGE.swap(ptr2, SeqCst);
328+
329+
// Old pointer should be the first one
330+
assert_eq!(old_ptr, ptr1);
331+
332+
// Clean up both
333+
unsafe {
334+
drop(Box::from_raw(old_ptr));
335+
let final_ptr = PANIC_MESSAGE.swap(ptr::null_mut(), SeqCst);
336+
let final_message = *Box::from_raw(final_ptr);
337+
assert_eq!(final_message, message2);
338+
}
339+
}
340+
341+
#[test]
342+
fn test_metadata_update_atomic() {
343+
// Test that metadata updates are atomic
344+
let metadata = Metadata {
345+
library_name: "test".to_string(),
346+
library_version: "1.0.0".to_string(),
347+
family: "test_family".to_string(),
348+
tags: vec![],
349+
};
350+
351+
let result = update_metadata(metadata.clone());
352+
assert!(result.is_ok());
353+
354+
// Verify metadata was stored
355+
let metadata_ptr = METADATA.load(SeqCst);
356+
assert!(!metadata_ptr.is_null());
357+
358+
unsafe {
359+
let (stored_metadata, _) = &*metadata_ptr;
360+
assert_eq!(stored_metadata.library_name, "test");
361+
}
362+
}
363+
}

libdd-crashtracker/src/collector/emitters.rs

Lines changed: 103 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -203,10 +203,12 @@ fn emit_metadata(w: &mut impl Write, metadata_str: &str) -> Result<(), EmitterEr
203203
fn emit_message(w: &mut impl Write, message_ptr: *mut String) -> Result<(), EmitterError> {
204204
if !message_ptr.is_null() {
205205
let message = unsafe { &*message_ptr };
206-
writeln!(w, "{DD_CRASHTRACK_BEGIN_MESSAGE}")?;
207-
writeln!(w, "{message}")?;
208-
writeln!(w, "{DD_CRASHTRACK_END_MESSAGE}")?;
209-
w.flush()?;
206+
if !message.trim().is_empty() {
207+
writeln!(w, "{DD_CRASHTRACK_BEGIN_MESSAGE}")?;
208+
writeln!(w, "{message}")?;
209+
writeln!(w, "{DD_CRASHTRACK_END_MESSAGE}")?;
210+
w.flush()?;
211+
}
210212
}
211213
Ok(())
212214
}
@@ -498,4 +500,101 @@ mod tests {
498500
// Clean up the allocated String
499501
unsafe { drop(Box::from_raw(message_ptr)) };
500502
}
503+
504+
#[test]
505+
#[cfg_attr(miri, ignore)]
506+
fn test_emit_message_empty_string() {
507+
let empty_message = String::new();
508+
let message_ptr = Box::into_raw(Box::new(empty_message));
509+
let mut buf = Vec::new();
510+
511+
emit_message(&mut buf, message_ptr).expect("to work");
512+
513+
// Empty messages should not emit anything
514+
assert!(buf.is_empty());
515+
516+
unsafe { drop(Box::from_raw(message_ptr)) };
517+
}
518+
519+
#[test]
520+
#[cfg_attr(miri, ignore)]
521+
fn test_emit_message_whitespace_only() {
522+
// Whitespace-only messages should not be emitted
523+
let whitespace_message = " \n\t ".to_string();
524+
let message_ptr = Box::into_raw(Box::new(whitespace_message));
525+
let mut buf = Vec::new();
526+
527+
emit_message(&mut buf, message_ptr).expect("to work");
528+
529+
// Whitespace-only messages should not emit anything
530+
assert!(buf.is_empty());
531+
532+
unsafe { drop(Box::from_raw(message_ptr)) };
533+
}
534+
535+
#[test]
536+
#[cfg_attr(miri, ignore)]
537+
fn test_emit_message_with_leading_trailing_whitespace() {
538+
// Messages with content and whitespace should be emitted (with the whitespace)
539+
let message_with_whitespace = " error message ".to_string();
540+
let message_ptr = Box::into_raw(Box::new(message_with_whitespace.clone()));
541+
let mut buf = Vec::new();
542+
543+
emit_message(&mut buf, message_ptr).expect("to work");
544+
let out = str::from_utf8(&buf).expect("to be valid UTF8");
545+
546+
// Should emit markers and preserve whitespace in content
547+
assert!(out.contains("BEGIN_MESSAGE"));
548+
assert!(out.contains("END_MESSAGE"));
549+
assert!(out.contains(&message_with_whitespace));
550+
551+
unsafe { drop(Box::from_raw(message_ptr)) };
552+
}
553+
554+
#[test]
555+
#[cfg_attr(miri, ignore)]
556+
fn test_emit_message_with_newlines() {
557+
let message_with_newlines = "line1\nline2\nline3".to_string();
558+
let message_ptr = Box::into_raw(Box::new(message_with_newlines));
559+
let mut buf = Vec::new();
560+
561+
emit_message(&mut buf, message_ptr).expect("to work");
562+
let out = str::from_utf8(&buf).expect("to be valid UTF8");
563+
564+
assert!(out.contains("line1"));
565+
assert!(out.contains("line2"));
566+
assert!(out.contains("line3"));
567+
568+
unsafe { drop(Box::from_raw(message_ptr)) };
569+
}
570+
571+
#[test]
572+
#[cfg_attr(miri, ignore)]
573+
fn test_emit_message_unicode() {
574+
let unicode_message = "Hello 世界 🦀 Rust!".to_string();
575+
let message_ptr = Box::into_raw(Box::new(unicode_message.clone()));
576+
let mut buf = Vec::new();
577+
578+
emit_message(&mut buf, message_ptr).expect("to work");
579+
let out = str::from_utf8(&buf).expect("to be valid UTF8");
580+
581+
assert!(out.contains(&unicode_message));
582+
583+
unsafe { drop(Box::from_raw(message_ptr)) };
584+
}
585+
586+
#[test]
587+
#[cfg_attr(miri, ignore)]
588+
fn test_emit_message_very_long() {
589+
let long_message = "x".repeat(100000); // 100KB
590+
let message_ptr = Box::into_raw(Box::new(long_message.clone()));
591+
let mut buf = Vec::new();
592+
593+
emit_message(&mut buf, message_ptr).expect("to work");
594+
let out = str::from_utf8(&buf).expect("to be valid UTF8");
595+
596+
assert!(out.contains(&long_message[..100])); // At least first 100 chars
597+
598+
unsafe { drop(Box::from_raw(message_ptr)) };
599+
}
501600
}

libdd-crashtracker/src/crash_info/builder.rs

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -453,4 +453,102 @@ mod tests {
453453
assert_eq!(crash_ping.metadata(), &metadata);
454454
assert!(crash_ping.message().contains("crash processing started"));
455455
}
456+
457+
#[test]
458+
fn test_with_message() {
459+
let mut builder = CrashInfoBuilder::new();
460+
let test_message = "Test error message".to_string();
461+
462+
let result = builder.with_message(test_message.clone());
463+
assert!(result.is_ok());
464+
assert!(builder.has_message());
465+
466+
// Build and verify message is present
467+
let sig_info = SigInfo::test_instance(42);
468+
builder.with_sig_info(sig_info).unwrap();
469+
builder.with_metadata(Metadata::test_instance(1)).unwrap();
470+
471+
let crash_ping = builder.build_crash_ping().unwrap();
472+
assert!(crash_ping.message().contains(&test_message));
473+
}
474+
475+
#[test]
476+
fn test_has_message_empty() {
477+
let builder = CrashInfoBuilder::new();
478+
assert!(!builder.has_message());
479+
}
480+
481+
#[test]
482+
fn test_has_message_after_setting() {
483+
let mut builder = CrashInfoBuilder::new();
484+
builder.with_message("test".to_string()).unwrap();
485+
assert!(builder.has_message());
486+
}
487+
488+
#[test]
489+
fn test_message_overwrite() {
490+
let mut builder = CrashInfoBuilder::new();
491+
492+
builder.with_message("first message".to_string()).unwrap();
493+
assert!(builder.has_message());
494+
495+
// Overwrite with second message
496+
builder.with_message("second message".to_string()).unwrap();
497+
assert!(builder.has_message());
498+
499+
// Build and verify only second message is present
500+
let sig_info = SigInfo::test_instance(42);
501+
builder.with_sig_info(sig_info).unwrap();
502+
builder.with_metadata(Metadata::test_instance(1)).unwrap();
503+
504+
let crash_ping = builder.build_crash_ping().unwrap();
505+
assert!(crash_ping.message().contains("second message"));
506+
assert!(!crash_ping.message().contains("first message"));
507+
builder.with_kind(ErrorKind::Panic).unwrap();
508+
509+
let report = builder.build().unwrap();
510+
assert_eq!(
511+
report.error.message.as_deref(),
512+
Some("second message")
513+
);
514+
}
515+
516+
#[test]
517+
fn test_message_with_special_characters() {
518+
let mut builder = CrashInfoBuilder::new();
519+
let special_message = "Error: 'panic' with \"quotes\" and\nnewlines\t\ttabs";
520+
521+
builder.with_message(special_message.to_string()).unwrap();
522+
builder.with_sig_info(SigInfo::test_instance(42)).unwrap();
523+
builder.with_metadata(Metadata::test_instance(1)).unwrap();
524+
525+
let crash_ping = builder.build_crash_ping().unwrap();
526+
assert!(crash_ping.message().contains(&special_message));
527+
builder.with_kind(ErrorKind::UnixSignal).unwrap();
528+
529+
let report = builder.build().unwrap();
530+
assert_eq!(
531+
report.error.message.as_deref(),
532+
Some(special_message)
533+
);
534+
}
535+
536+
#[test]
537+
fn test_very_long_message() {
538+
let mut builder = CrashInfoBuilder::new();
539+
let long_message = "x".repeat(10000); // 10KB message
540+
541+
builder.with_message(long_message.clone()).unwrap();
542+
assert!(builder.has_message());
543+
544+
builder.with_sig_info(SigInfo::test_instance(42)).unwrap();
545+
builder.with_metadata(Metadata::test_instance(1)).unwrap();
546+
547+
let crash_ping = builder.build_crash_ping().unwrap();
548+
assert!(crash_ping.message().len() >= 10000);
549+
550+
builder.with_kind(ErrorKind::UnixSignal).unwrap();
551+
let report = builder.build().unwrap();
552+
assert!(report.error.message.as_ref().unwrap().len() >= 10000);
553+
}
456554
}

0 commit comments

Comments
 (0)