assignment-0.0.1.0: tests/Main.hs
module Main (main) where
import Data.Algorithm.Assignment (assign)
import Data.List qualified
import Data.Tuple (swap)
import Test.Hspec
import Test.QuickCheck
main :: IO ()
main = hspec spec
spec :: Spec
spec = do
describe "assign" $ do
it "returns the empty list if the first collection is empty" $
assign (\_ _ -> 0) ([] :: [Int]) ([1, 2, 3] :: [Int]) `shouldBe` []
it "returns the empty list if the second collection is empty" $
assign (\_ _ -> 0) ([1, 2, 3] :: [Int]) ([] :: [Int]) `shouldBe` []
it "solves the example from Wikipedia" $ do
let cost "Alice" "Clean bathroom" = 8
cost "Alice" "Sweep floors" = 4
cost "Alice" "Wash windows" = 7
cost "Bob" "Clean bathroom" = 5
cost "Bob" "Sweep floors" = 2
cost "Bob" "Wash windows" = 3
cost "Dora" "Clean bathroom" = 9
cost "Dora" "Sweep floors" = 4
cost "Dora" "Wash windows" = 8
cost _ _ = 0
Data.List.sortOn
fst
( assign
cost
["Alice", "Bob", "Dora"]
["Clean bathroom", "Sweep floors", "Wash windows"]
)
`shouldBe` [ ("Alice", "Clean bathroom"),
("Bob", "Wash windows"),
("Dora", "Sweep floors")
]
it "always finds the best assignment" $
property $ \(Fun _ cost) (as :: [Int]) (bs :: [Int]) -> do
let totalCost = sum . fmap cost
forAll (shuffle bs) $ \bs' ->
totalCost (assign (curry cost) as bs) <= totalCost (zip as bs')
it "swapping of the collections results in pairings with the same total cost" $
property $ \(Fun _ cost) (as :: [Int]) (bs :: [Int]) -> do
let cost0 = curry cost
cost1 x y = cost0 y x
totalCost = sum . fmap cost
totalCost (assign cost0 as bs) == totalCost (swap <$> assign cost1 bs as)
it "shuffling of collections results in pairings with the same total cost" $
property $ \(Fun _ cost) (xs :: [(Int, Int)]) -> do
let totalCost = sum . fmap cost
cost' = curry cost
as = Data.List.nub (fst <$> xs)
bs = Data.List.nub (snd <$> xs)
forAll (shuffle as) $ \as' ->
totalCost (assign cost' as bs) == totalCost (assign cost' as' bs)