@@ -699,4 +699,222 @@ mod tests {
699699 panic ! ( "Expected error response" ) ;
700700 }
701701 }
702+
703+ #[ test]
704+ fn detect_process_exit_non_standard_panic ( ) {
705+ let detector = CrashDetector :: new ( 5000 ) ;
706+ // Non-zero exit code that isn't one of the special ones (139, 134, 137)
707+ let response = FuzzResponse :: process_exit ( 1 ) ;
708+
709+ let analysis = detector. analyze ( & response) ;
710+ assert ! ( matches!(
711+ analysis,
712+ CrashAnalysis :: Crash ( CrashInfo {
713+ crash_type: CrashType :: Panic ,
714+ ..
715+ } )
716+ ) ) ;
717+ }
718+
719+ #[ test]
720+ fn extract_stack_trace_with_at_pattern ( ) {
721+ let detector = CrashDetector :: new ( 5000 ) ;
722+ // Test stack trace extraction with "at " pattern and .rs: file reference
723+ let response = FuzzResponse :: error (
724+ -32603 ,
725+ "assertion failed: x > 0\n at main.rs:42:5 in function foo" ,
726+ ) ;
727+
728+ let analysis = detector. analyze ( & response) ;
729+ if let CrashAnalysis :: Crash ( info) = analysis {
730+ assert_eq ! ( info. crash_type, CrashType :: AssertionFailure ) ;
731+ assert ! ( info. stack_trace. is_some( ) ) ;
732+ let trace = info. stack_trace . unwrap ( ) ;
733+ assert ! ( trace. contains( "at main.rs:42:5" ) ) ;
734+ } else {
735+ panic ! ( "Expected Crash analysis" ) ;
736+ }
737+ }
738+
739+ #[ test]
740+ fn analyze_success_with_error_code_field ( ) {
741+ let detector = CrashDetector :: new ( 5000 ) ;
742+ // Test success response with "errorCode" field (not just "error")
743+ let response = FuzzResponse :: success ( serde_json:: json!( {
744+ "errorCode" : 404 ,
745+ "status" : "failed"
746+ } ) ) ;
747+
748+ let analysis = detector. analyze ( & response) ;
749+ assert ! ( matches!(
750+ analysis,
751+ CrashAnalysis :: Interesting ( InterestingReason :: UnexpectedSuccess )
752+ ) ) ;
753+ }
754+
755+ #[ test]
756+ fn analyze_success_with_stack_backtrace ( ) {
757+ let detector = CrashDetector :: new ( 5000 ) ;
758+ // Test success response with "stack backtrace" in message
759+ let response = FuzzResponse :: success ( serde_json:: json!( {
760+ "message" : "stack backtrace:\n 0: foo\n 1: bar"
761+ } ) ) ;
762+
763+ let analysis = detector. analyze ( & response) ;
764+ assert ! ( matches!(
765+ analysis,
766+ CrashAnalysis :: Interesting ( InterestingReason :: ProtocolViolation )
767+ ) ) ;
768+ }
769+
770+ #[ test]
771+ fn analyze_success_with_error_prefix ( ) {
772+ let detector = CrashDetector :: new ( 5000 ) ;
773+ // Test success response with "Error:" prefix in message
774+ let response = FuzzResponse :: success ( serde_json:: json!( {
775+ "message" : "Error: something went wrong"
776+ } ) ) ;
777+
778+ let analysis = detector. analyze ( & response) ;
779+ assert ! ( matches!(
780+ analysis,
781+ CrashAnalysis :: Interesting ( InterestingReason :: ProtocolViolation )
782+ ) ) ;
783+ }
784+
785+ #[ test]
786+ fn detect_reserved_error_code_range_server_error ( ) {
787+ let detector = CrashDetector :: new ( 5000 ) ;
788+ // Test error code in reserved range -32099 to -32000 (Server error)
789+ let response = FuzzResponse :: error ( -32050 , "Server error" ) ;
790+
791+ let analysis = detector. analyze ( & response) ;
792+ // Reserved codes in this range are not interesting
793+ assert ! ( matches!( analysis, CrashAnalysis :: None ) ) ;
794+ }
795+
796+ #[ test]
797+ fn detect_reserved_error_code_range_jsonrpc ( ) {
798+ let detector = CrashDetector :: new ( 5000 ) ;
799+ // Test error code in reserved range -32768 to -32600 (JSON-RPC reserved)
800+ let response = FuzzResponse :: error ( -32650 , "Reserved error" ) ;
801+
802+ let analysis = detector. analyze ( & response) ;
803+ // Reserved codes in this range are not interesting
804+ assert ! ( matches!( analysis, CrashAnalysis :: None ) ) ;
805+ }
806+
807+ #[ test]
808+ fn detect_short_internal_error ( ) {
809+ let detector = CrashDetector :: new ( 5000 ) ;
810+ // Short internal error message (<=100 chars) should not be interesting
811+ let response = FuzzResponse :: error ( -32603 , "Internal error" ) ;
812+
813+ let analysis = detector. analyze ( & response) ;
814+ assert ! ( matches!( analysis, CrashAnalysis :: None ) ) ;
815+ }
816+
817+ #[ test]
818+ fn detect_panic_panicked_at_variant ( ) {
819+ let detector = CrashDetector :: new ( 5000 ) ;
820+ // Test "panicked at" variant specifically
821+ let response = FuzzResponse :: error ( -32603 , "panicked at 'index out of bounds'" ) ;
822+
823+ let analysis = detector. analyze ( & response) ;
824+ assert ! ( analysis. is_crash( ) ) ;
825+ if let CrashAnalysis :: Crash ( info) = analysis {
826+ assert_eq ! ( info. crash_type, CrashType :: Panic ) ;
827+ }
828+ }
829+
830+ #[ test]
831+ fn detect_oom_allocation_variant ( ) {
832+ let detector = CrashDetector :: new ( 5000 ) ;
833+ // Test "allocation" variant specifically
834+ let response = FuzzResponse :: error ( -32603 , "allocation failed" ) ;
835+
836+ let analysis = detector. analyze ( & response) ;
837+ assert ! ( analysis. is_crash( ) ) ;
838+ if let CrashAnalysis :: Crash ( info) = analysis {
839+ assert_eq ! ( info. crash_type, CrashType :: OutOfMemory ) ;
840+ }
841+ }
842+
843+ #[ test]
844+ fn detect_oom_memory_exhausted_variant ( ) {
845+ let detector = CrashDetector :: new ( 5000 ) ;
846+ // Test "memory exhausted" variant
847+ let response = FuzzResponse :: error ( -32603 , "memory exhausted" ) ;
848+
849+ let analysis = detector. analyze ( & response) ;
850+ assert ! ( analysis. is_crash( ) ) ;
851+ if let CrashAnalysis :: Crash ( info) = analysis {
852+ assert_eq ! ( info. crash_type, CrashType :: OutOfMemory ) ;
853+ }
854+ }
855+
856+ #[ test]
857+ fn detect_oom_variant ( ) {
858+ let detector = CrashDetector :: new ( 5000 ) ;
859+ // Test "OOM" variant
860+ let response = FuzzResponse :: error ( -32603 , "OOM killer activated" ) ;
861+
862+ let analysis = detector. analyze ( & response) ;
863+ assert ! ( analysis. is_crash( ) ) ;
864+ if let CrashAnalysis :: Crash ( info) = analysis {
865+ assert_eq ! ( info. crash_type, CrashType :: OutOfMemory ) ;
866+ }
867+ }
868+
869+ #[ test]
870+ fn detect_assertion_assert_variant ( ) {
871+ let detector = CrashDetector :: new ( 5000 ) ;
872+ // Test "assert!" variant
873+ let response = FuzzResponse :: error ( -32603 , "assert! failed in module" ) ;
874+
875+ let analysis = detector. analyze ( & response) ;
876+ assert ! ( analysis. is_crash( ) ) ;
877+ if let CrashAnalysis :: Crash ( info) = analysis {
878+ assert_eq ! ( info. crash_type, CrashType :: AssertionFailure ) ;
879+ }
880+ }
881+
882+ #[ test]
883+ fn detect_assertion_debug_assert_variant ( ) {
884+ let detector = CrashDetector :: new ( 5000 ) ;
885+ // Test "debug_assert" variant
886+ let response = FuzzResponse :: error ( -32603 , "debug_assert triggered" ) ;
887+
888+ let analysis = detector. analyze ( & response) ;
889+ assert ! ( analysis. is_crash( ) ) ;
890+ if let CrashAnalysis :: Crash ( info) = analysis {
891+ assert_eq ! ( info. crash_type, CrashType :: AssertionFailure ) ;
892+ }
893+ }
894+
895+ #[ test]
896+ fn detect_segfault_invalid_memory_variant ( ) {
897+ let detector = CrashDetector :: new ( 5000 ) ;
898+ // Test "invalid memory" variant
899+ let response = FuzzResponse :: error ( -32603 , "invalid memory reference" ) ;
900+
901+ let analysis = detector. analyze ( & response) ;
902+ assert ! ( analysis. is_crash( ) ) ;
903+ if let CrashAnalysis :: Crash ( info) = analysis {
904+ assert_eq ! ( info. crash_type, CrashType :: Segfault ) ;
905+ }
906+ }
907+
908+ #[ test]
909+ fn detect_segfault_segmentation_fault_variant ( ) {
910+ let detector = CrashDetector :: new ( 5000 ) ;
911+ // Test "segmentation fault" variant
912+ let response = FuzzResponse :: error ( -32603 , "segmentation fault occurred" ) ;
913+
914+ let analysis = detector. analyze ( & response) ;
915+ assert ! ( analysis. is_crash( ) ) ;
916+ if let CrashAnalysis :: Crash ( info) = analysis {
917+ assert_eq ! ( info. crash_type, CrashType :: Segfault ) ;
918+ }
919+ }
702920}
0 commit comments