{-# LANGUAGE OverloadedStrings #-}
{-# OPTIONS -Wno-type-defaults #-}
import Control.Monad
import Data.Char (isSpace)
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 "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 "replaced" $ format (replaced "Bruce" "<redacted>" stext) "Bruce replied that Bruce's name was, in fact, '<redacted>'." `shouldBe` "<redacted> replied that <redacted>'s name was, in fact, '<redacted>'."
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` "<!--an html comment-->"
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` "[<html>, <head>, <title>, <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"