@@ -611,6 +611,71 @@ fn comm_emoji_sorted_inputs() {
611611 . stdout_only ( "💐\n \t \t 🦀\n \t 🪽\n " ) ;
612612}
613613
614+ /// Regression test for https://bugs.launchpad.net/ubuntu/+source/rust-coreutils/+bug/2138315
615+ /// When reading from FIFOs (like process substitution `<(cat file)`), comm would falsely report
616+ /// "file is not in sorted order" even when input was properly sorted.
617+ #[ test]
618+ #[ cfg( unix) ]
619+ fn test_large_sorted_input_from_fifo_no_false_sorting_warning ( ) {
620+ use std:: fmt:: Write as _;
621+ use std:: fs:: OpenOptions ;
622+ use std:: io:: Write as _;
623+ use std:: thread;
624+
625+ let scene = TestScenario :: new ( util_name ! ( ) ) ;
626+ let at = & scene. fixtures ;
627+
628+ // Create two FIFOs to simulate process substitution
629+ at. mkfifo ( "fifo_a" ) ;
630+ at. mkfifo ( "fifo_b" ) ;
631+
632+ // Content for the FIFOs
633+ let content_a = "00000\n " . to_string ( ) ;
634+ // Create a large sorted file (2000 lines of zero-padded numbers)
635+ // This is well above the ~1365 line threshold where the bug manifests
636+ let content_b: String = ( 1 ..=2000 ) . fold ( String :: new ( ) , |mut acc, n| {
637+ writeln ! ( acc, "{n:05}" ) . unwrap ( ) ;
638+ acc
639+ } ) ;
640+
641+ // Start comm reading from both FIFOs (non-blocking)
642+ let proc = scene
643+ . ucmd ( )
644+ . args ( & [ "-23" , "fifo_a" , "fifo_b" ] )
645+ . run_no_wait ( ) ;
646+
647+ // Spawn threads to write to the FIFOs
648+ let fifo_a_path = at. plus ( "fifo_a" ) ;
649+ let fifo_b_path = at. plus ( "fifo_b" ) ;
650+
651+ let thread_a = thread:: spawn ( move || {
652+ let mut pipe = OpenOptions :: new ( )
653+ . write ( true )
654+ . create ( false )
655+ . open ( fifo_a_path)
656+ . unwrap ( ) ;
657+ pipe. write_all ( content_a. as_bytes ( ) ) . unwrap ( ) ;
658+ } ) ;
659+
660+ let thread_b = thread:: spawn ( move || {
661+ let mut pipe = OpenOptions :: new ( )
662+ . write ( true )
663+ . create ( false )
664+ . open ( fifo_b_path)
665+ . unwrap ( ) ;
666+ pipe. write_all ( content_b. as_bytes ( ) ) . unwrap ( ) ;
667+ } ) ;
668+
669+ // Wait for everything to complete
670+ let result = proc. wait ( ) . unwrap ( ) ;
671+ thread_a. join ( ) . unwrap ( ) ;
672+ thread_b. join ( ) . unwrap ( ) ;
673+
674+ // Should succeed with exit code 0 and output "00000\n"
675+ // Before the fix, this would fail with "file 2 is not in sorted order"
676+ result. success ( ) . stdout_only ( "00000\n " ) ;
677+ }
678+
614679#[ test]
615680fn test_comm_eintr_handling ( ) {
616681 // Test that comm properly handles EINTR (ErrorKind::Interrupted) during file comparison
0 commit comments