@@ -15,6 +15,7 @@ import qualified Data.ByteString.Lazy as L
15
15
import Data.String (IsString (.. ))
16
16
import Data.Monoid ((<>) )
17
17
import qualified Data.ByteString.Base64 as B64
18
+ import GHC.Exts (IsList (fromList ))
18
19
19
20
#if !MIN_VERSION_base(4, 8, 0)
20
21
import Control.Applicative ((*>) )
@@ -341,3 +342,106 @@ spec = do
341
342
++ " puppy\n "
342
343
++ " Standard error:\n "
343
344
++ " 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