{-# LANGUAGE OverloadedStrings #-} {-# OPTIONS -Wno-type-defaults #-} import Control.Monad import Data.Char (isSpace, isUpper) import Data.Int import qualified Data.Monoid import Data.Scientific import qualified Data.Semigroup import qualified Data.Text.Lazy as LT import Formatting as F import Formatting.Time import Test.Hspec main :: IO () main = hspec spec spec :: Spec spec = do describe "Regression tests" $ do describe "https://github.com/AJChapman/formatting/issues/36" $ do it "format (later id <> later id) \"x\"" $ format (later id Data.Monoid.<> later id) "x" `shouldBe` "xx" it "format (later id <> later id) \"x\"" $ format (later id Data.Semigroup.<> later id) "x" `shouldBe` "xx" describe "https://github.com/AJChapman/formatting/issues/31" $ it "10^6-1" $ F.format F.int (10 ^ (16 :: Int) - 1 :: Int) `shouldBe` "9999999999999999" describe "https://github.com/AJChapman/formatting/issues/28" $ do it "-100" $ sformat (groupInt 3 ',') (-100 :: Int) `shouldBe` "-100" it "-100,000,000" $ sformat (groupInt 3 ',') (-100000000 :: Int) `shouldBe` "-100,000,000" it "100,000,000" $ sformat (groupInt 3 ',') (-100000000 :: Int) `shouldBe` "-100,000,000" describe "https://github.com/bos/text-format/issues/18" $ do it "build (minBound :: Int)" $ format build (minBound :: Int64) `shouldBe` "-9223372036854775808" it "build (maxBound :: Int)" $ format build (maxBound :: Int) `shouldBe` "9223372036854775807" describe "https://github.com/AJChapman/formatting/issues/62" $ do it "left 3 '0' (0 :: Int)" $ format (left 3 '0') (0 ::Int) `shouldBe` "000" it "left 3 '0' (0 :: Word)" $ format (left 3 '0') (0 ::Word) `shouldBe` "000" describe "https://github.com/AJChapman/formatting/issues/60" $ it "build (minBound :: Word)" $ format build (minBound :: Word) `shouldBe` "0" describe "https://github.com/AJChapman/formatting/issues/59" $ it "shortest not scientific" $ format shortest (0.01 :: Double) `shouldBe` "0.01" describe "Floating point" $ do it "Fixed" $ format (fixed 4) (12.123456 :: Double) `shouldBe` "12.1235" it "Variable" $ format float (12.123456 :: Double) `shouldBe` "12.123456" it "Shortest" $ format shortest (12.0000 :: Double) `shouldBe` "12" describe "Scientific" $ do it "sci" $ format sci (scientific 60221409 16) `shouldBe` "6.0221409e23" it "scifmt" $ format (scifmt Exponent (Just 3)) (scientific 60221409 16) `shouldBe` "6.022e23" it "scifmt" $ format (scifmt Exponent Nothing) (scientific 60221409 16) `shouldBe` "6.0221409e23" it "scifmt" $ format (scifmt Fixed Nothing) (scientific 60221409 16) `shouldBe` "602214090000000000000000.0" it "scifmt" $ format (scifmt Generic (Just 5)) (scientific 60221409 16) `shouldBe` "6.02214e23" describe "Bytes" $ do it "1KB" $ format (bytes shortest) (1024 :: Int) `shouldBe` "1KB" it "1.15GB" $ format (bytes (fixed 2)) (1234567890 :: Int) `shouldBe` "1.15GB" describe "Buildable a => Buildable [a]" (do it "\"\" :: [Char] (backwards compatibility)" (shouldBe (format build ("" :: String)) "") it "\"hi\" :: [Char] (backwards compatibility)" (shouldBe (format build ("hi" :: String)) "hi") it "[1,2,3] :: [Int]" (shouldBe (format build ([1,2,3] :: [Int])) "[1,2,3]") it "[] :: [Int]" (shouldBe (format build ([] :: [Int])) "[]")) describe "ords" $ do let tests :: [(Int, String)] tests = [ ( 1, "1st") , ( 2, "2nd") , ( 3, "3rd") , ( 4, "4th") , ( 5, "5th") , ( 6, "6th") , ( 7, "7th") , ( 8, "8th") , ( 9, "9th") , (10, "10th") , (11, "11th") , (12, "12th") , (13, "13th") , (14, "14th") , (15, "15th") , (16, "16th") , (17, "17th") , (18, "18th") , (19, "19th") , (20, "20th") , (21, "21st") , (22, "22nd") , (23, "23rd") , (24, "24th") , (25, "25th") , (26, "26th") , (27, "27th") , (28, "28th") , (29, "29th") , (30, "30th") , (31, "31st") , (31, "31st") , (32, "32nd") , (33, "33rd") , (34, "34th") ] forM_ tests $ \(input, output) -> it output $ format ords input `shouldBe` LT.pack output describe "plural" $ do let formatPeople = format (int % " " <> plural "person" "people" % ".") it "formats a person" $ formatPeople (1 :: Int) `shouldBe` "1 person." it "formats a person" $ formatPeople (3 :: Int) `shouldBe` "3 people." describe "diffComponents" $ do it "59s" $ flip shouldBe "00:00:00:59" $ format diffComponents (59 :: Double) it "minute" $ flip shouldBe "00:00:01:00" $ format diffComponents (60 :: Double) it "90s" $ flip shouldBe "00:00:01:30" $ format diffComponents (90 :: Double) it "hour" $ flip shouldBe "00:01:00:00" $ format diffComponents (3600 :: Double) it "day" $ flip shouldBe "01:00:00:00" $ format diffComponents (86400 :: Double) describe "container formatters" $ do it "maybed Nothing" $ format (maybed "Goodbye" text) Nothing `shouldBe` "Goodbye" it "maybed Just" $ format (maybed "Goodbye" text) (Just "Hello") `shouldBe` "Hello" it "optioned Nothing" $ format (optioned text) Nothing `shouldBe` "" it "optioned Just" $ format (optioned text) (Just "Hello") `shouldBe` "Hello" it "eithered Left" $ format (eithered text int) (Left "Error!") `shouldBe` "Error!" it "eithered Right" $ format (eithered text int) (Right 69) `shouldBe` "69" it "lefted Left" $ format (lefted text) (Left "bingo") `shouldBe` "bingo" it "lefted Right" $ format (lefted text) (Right 16) `shouldBe` "" it "righted Left" $ format (righted text) (Left 16) `shouldBe` "" it "righted Right" $ format (righted text) (Right "bingo") `shouldBe` "bingo" describe "list formatters" $ do it "concatenated" $ format (concatenated text) ["one", "two", "three"] `shouldBe` "onetwothree" it "joinedWith" $ format (joinedWith (mconcat . reverse) int) [123, 456, 789] `shouldBe` "789456123" it "intercalated" $ format (intercalated "||" int) [1, 2, 3] `shouldBe` "1||2||3" it "unworded" $ format (unworded int) [1, 2, 3] `shouldBe` "1 2 3" it "unlined" $ format (unlined char) ['a'..'c'] `shouldBe` "a\nb\nc\n" it "spaced" $ format (spaced int) [1, 2, 3] `shouldBe` "1 2 3" it "commaSep" $ format (took 5 (commaSep int)) [1..] `shouldBe` "1,2,3,4,5" it "commaSpaceSep" $ format (took 3 (commaSpaceSep ords)) [1..] `shouldBe` "1st, 2nd, 3rd" it "list" $ format (list stext) ["one", "two", "three"] `shouldBe` "[one, two, three]" it "qlist" $ format (qlist stext) ["one", "two", "three"] `shouldBe` "[\"one\", \"two\", \"three\"]" it "took" $ format (took 7 (list bin)) [1..] `shouldBe` "[1, 10, 11, 100, 101, 110, 111]" it "dropped" $ format (dropped 3 (list int)) [1..6] `shouldBe` "[4, 5, 6]" describe "splitting formatters" $ do it "splat" $ format (splat isSpace commaSpaceSep stext) "This\t is\n\t\t poorly formatted " `shouldBe` "This, , , is, , , , , poorly, formatted, , , " it "splatWith" $ format (splatWith (LT.chunksOf 3) list int) 1234567890 `shouldBe` "[123, 456, 789, 0]" it "splatOn" $ format (splatOn "," unlined text) "one,two,three" `shouldBe` "one\ntwo\nthree\n" it "worded" $ format (worded list text) "one two three " `shouldBe` "[one, two, three]" it "lined" $ format (lined qlist text) "one two three\n\nfour five six\nseven eight nine\n\n" `shouldBe` "[\"one two three\", \"\", \"four five six\", \"seven eight nine\", \"\"]" describe "altering combinators" $ do it "alteredWith" $ format (alteredWith LT.reverse int) 123456 `shouldBe` "654321" it "charsKeptIf" $ format (charsKeptIf isUpper text) "Data.Char.isUpper" `shouldBe` "DCU" it "charsRemovedIf" $ format (charsRemovedIf isUpper text) "Data.Char.isUpper" `shouldBe` "ata.har.ispper" it "replaced" $ format (replaced "Bruce" "" stext) "Bruce replied that Bruce's name was, in fact, ''." `shouldBe` " replied that 's name was, in fact, ''." it "uppercased" $ format (uppercased text) "I'm not shouting, you're shouting." `shouldBe` "I'M NOT SHOUTING, YOU'RE SHOUTING." it "lowercased" $ format (lowercased text) "Cd SrC/; Rm -Rf *" `shouldBe` "cd src/; rm -rf *" it "titlecased" $ format (titlecased string) "the life of brian" `shouldBe` "The Life Of Brian" it "ltruncated" $ format (ltruncated 5 text) "hellos" `shouldBe` "he..." it "ltruncated, non-truncated" $ format (ltruncated 5 text) "hello" `shouldBe` "hello" it "rtruncated" $ format (rtruncated 5 text) "hellos" `shouldBe` "...os" it "rtruncated, non-truncated" $ format (rtruncated 5 text) "hello" `shouldBe` "hello" it "ctruncated" $ format (ctruncated 15 4 text) "The quick brown fox jumps over the lazy dog." `shouldBe` "The quick brown...dog." it "ctruncated, non-truncated" $ format (ctruncated 15 4 text) "The quick brown fox" `shouldBe` "The quick brown fox" it "lpadded" $ format (lpadded 7 ' ' int) 1 `shouldBe` " 1" it "lpadded doesn't shorten" $ format (lpadded 7 ' ' int) 123456789 `shouldBe` "123456789" it "rpadded" $ format (rpadded 7 ' ' int) 1 `shouldBe` "1 " it "cpadded" $ format (cpadded 7 ' ' int) 1 `shouldBe` " 1 " it "lfixed short" $ format (lfixed 10 ' ' int) 123 `shouldBe` "123 " it "lfixed at length" $ format (lfixed 10 ' ' int) 1234567890 `shouldBe` "1234567890" it "lfixed long" $ format (lfixed 10 ' ' int) 123456789012345 `shouldBe` "1234567..." it "rfixed short" $ format (rfixed 10 ' ' int) 123 `shouldBe` " 123" it "rfixed at length" $ format (rfixed 10 ' ' int) 1234567890 `shouldBe` "1234567890" it "rfixed long" $ format (rfixed 10 ' ' int) 123456789012345 `shouldBe` "...9012345" it "cfixed short" $ format (cfixed 4 3 ' ' int) 123 `shouldBe` " 123 " it "cfixed at length" $ format (cfixed 4 3 ' ' int) 1234567890 `shouldBe` "1234567890" it "cfixed long" $ format (cfixed 4 3 ' ' int) 123456789012345 `shouldBe` "1234...345" describe "wrapping combinators" $ do it "prefixed" $ format ("The answer is: " % prefixed "wait for it... " int) 42 `shouldBe` "The answer is: wait for it... 42" it "prefixed, combining" $ format (unlined (indented 4 (prefixed "- " int))) [1, 2, 3] `shouldBe` " - 1\n - 2\n - 3\n" it "suffixed" $ format (suffixed "!!!" int) 7 `shouldBe` "7!!!" it "surrounded" $ format (surrounded "***" string) "glue" `shouldBe` "***glue***" it "enclosed" $ format (enclosed "" text) "an html comment" `shouldBe` "" it "squoted" $ let obj :: Maybe (Maybe Int); obj = Just Nothing in format ("The object is: " % squoted shown % ".") obj `shouldBe` "The object is: 'Just Nothing'." it "dquoted" $ format ("He said it was based on " % dquoted stext % ".") "science" `shouldBe` "He said it was based on \"science\"." it "parenthesised" $ format (took 5 (list (parenthesised int))) [1..] `shouldBe` "[(1), (2), (3), (4), (5)]" it "squared" $ format (squared int) 7 `shouldBe` "[7]" it "braced" $ format ("\\begin" % braced text) "section" `shouldBe` "\\begin{section}" it "angled" $ format (list (angled text)) ["html", "head", "title", "body", "div", "span"] `shouldBe` "[, , , <body>, <div>, <span>]" it "backticked" $ format ("Be sure to run " % backticked builder % " as root.") ":(){:|:&};:" `shouldBe` "Be sure to run `:(){:|:&};:` as root." describe "indenters" $ do it "indented" $ format (indented 4 int) 7 `shouldBe` " 7" it "indentedLines" $ format ("The lucky numbers are:\n" % indentedLines 4 int) [7, 13, 1, 42] `shouldBe` "The lucky numbers are:\n 7\n 13\n 1\n 42\n" it "reindented" $ format (reindented 2 text) "one\ntwo\nthree" `shouldBe` " one\n two\n three\n" describe "numerical adapters" $ do it "roundedTo" $ format (list (roundedTo int)) [10.66, 6.66, 1.0, 3.4] `shouldBe` "[11, 7, 1, 3]" it "truncatedTo" $ format (list (truncatedTo int)) [10.66, 6.66, 1.0, 3.4] `shouldBe` "[10, 6, 1, 3]" it "ceilingedTo" $ format (list (ceilingedTo int)) [10.66, 6.66, 1.0, 3.4] `shouldBe` "[11, 7, 1, 4]" it "flooredTo" $ format (list (flooredTo int)) [10.66, 6.66, 1.0, 3.4] `shouldBe` "[10, 6, 1, 3]" describe "structure formatting" $ it "accessed" $ format (accessed fst int) (1, "hello") `shouldBe` "1" -- describe "lens formatters" $ do -- it "viewed" $ flip shouldBe "(viewed _1 int) (1, "hello")" $ format describe "fixed-width numbers" $ do it "binPrefix" $ format (binPrefix 16) 4097 `shouldBe` "0b0001000000000001" it "octPrefix" $ format (octPrefix 16) 4097 `shouldBe` "0o0000000000010001" it "hexPrefix" $ format (hexPrefix 16) 4097 `shouldBe` "0x0000000000001001"