@@ -15,6 +15,7 @@ import qualified Data.ByteString.Lazy as L
1515import Data.String (IsString (.. ))
1616import Data.Monoid ((<>) )
1717import qualified Data.ByteString.Base64 as B64
18+ import GHC.IsList (IsList (fromList ))
1819
1920#if !MIN_VERSION_base(4, 8, 0)
2021import Control.Applicative ((*>) )
@@ -341,3 +342,106 @@ spec = do
341342 ++ " puppy\n "
342343 ++ " Standard error:\n "
343344 ++ " doggy"
345+
346+ it " decodes UTF-8" $ do
347+ let exitCodeException =
348+ ExitCodeException
349+ { eceExitCode = ExitFailure 1
350+ , eceProcessConfig = proc " puppy" []
351+ , eceStdout = fromList [0x61 , 0xc2 , 0xa9 , 0xe2 , 0x82 , 0xac , 0xf0 , 0x9f , 0x92 , 0xa9 , 0x0a ]
352+ , eceStderr = fromList [0x61 , 0xc2 , 0xa9 , 0xe2 , 0x82 , 0xac , 0xf0 , 0x9f , 0x92 , 0xa9 , 0x0a ]
353+ }
354+ show exitCodeException `shouldBe`
355+ " Received ExitFailure 1 when running\n "
356+ ++ " Raw command: puppy\n "
357+ ++ " \n "
358+ ++ " Standard output:\n "
359+ ++ " a©€💩\n "
360+ ++ " \n "
361+ ++ " Standard error:\n "
362+ ++ " a©€💩\n "
363+
364+ it " decodes UTF-8 leniently (overlong)" $ do
365+ let exitCodeException =
366+ ExitCodeException
367+ { eceExitCode = ExitFailure 1
368+ , eceProcessConfig = proc " puppy" []
369+ , -- Overlong sequence, U+20AC € encoded as 4 bytes.
370+ -- We get four U+FFFD � replacement characters out, one
371+ -- for each byte in the sequence.
372+ eceStdout = fromList [ 0xf0 , 0x82 , 0x82 , 0xac , 0x0a ]
373+ , eceStderr = L. empty
374+ }
375+ show exitCodeException `shouldBe`
376+ " Received ExitFailure 1 when running\n "
377+ ++ " Raw command: puppy\n "
378+ ++ " \n "
379+ ++ " Standard output:\n "
380+ ++ " ����\n "
381+
382+ it " decodes UTF-8 leniently (lone surrogate)" $ do
383+ let exitCodeException =
384+ ExitCodeException
385+ { eceExitCode = ExitFailure 1
386+ , eceProcessConfig = proc " puppy" []
387+ , -- Half of a surrogate pair, invalid in UTF-8. (U+D800)
388+ eceStdout = fromList [ 0xed , 0xa0 , 0x80 , 0x0a ]
389+ , eceStderr = L. empty
390+ }
391+ show exitCodeException `shouldBe`
392+ " Received ExitFailure 1 when running\n "
393+ ++ " Raw command: puppy\n "
394+ ++ " \n "
395+ ++ " Standard output:\n "
396+ ++ " ���\n "
397+
398+ it " decodes UTF-8 leniently (unexpected continuation)" $ do
399+ let exitCodeException =
400+ ExitCodeException
401+ { eceExitCode = ExitFailure 1
402+ , eceProcessConfig = proc " puppy" []
403+ , -- An unexpected continuation byte.
404+ eceStdout = fromList [ 0xa0 , 0x80 , 0x0a ]
405+ , eceStderr = L. empty
406+ }
407+ show exitCodeException `shouldBe`
408+ " Received ExitFailure 1 when running\n "
409+ ++ " Raw command: puppy\n "
410+ ++ " \n "
411+ ++ " Standard output:\n "
412+ ++ " ��\n "
413+
414+ it " decodes UTF-8 leniently (missing continuation)" $ do
415+ let exitCodeException =
416+ ExitCodeException
417+ { eceExitCode = ExitFailure 1
418+ , eceProcessConfig = proc " puppy" []
419+ , -- Missing a continuation byte.
420+ eceStdout = fromList [ 0xf0 , 0x9f , 0x90 , 0x0a ]
421+ , eceStderr = L. empty
422+ }
423+ show exitCodeException `shouldBe`
424+ " Received ExitFailure 1 when running\n "
425+ ++ " Raw command: puppy\n "
426+ ++ " \n "
427+ ++ " Standard output:\n "
428+ ++ " ���\n "
429+
430+ it " decodes UTF-8 leniently (invalid byte)" $ do
431+ let exitCodeException =
432+ ExitCodeException
433+ { eceExitCode = ExitFailure 1
434+ , eceProcessConfig = proc " puppy" []
435+ , -- Invalid bytes (no defined meaning in UTF-8).
436+ eceStdout = fromList [ 0xc0 , 0x0a , 0xc1 , 0x0a , 0xf5 , 0x0a , 0xff , 0x0a ]
437+ , eceStderr = L. empty
438+ }
439+ show exitCodeException `shouldBe`
440+ " Received ExitFailure 1 when running\n "
441+ ++ " Raw command: puppy\n "
442+ ++ " \n "
443+ ++ " Standard output:\n "
444+ ++ " �\n "
445+ ++ " �\n "
446+ ++ " �\n "
447+ ++ " �\n "
0 commit comments