packages feed

hsluv-haskell-0.1.0.0: test/Spec.hs

import           Control.Exception.Base (assert)
import           Control.Monad          (liftM3)
import           Data.Aeson
import           Data.ByteString.Lazy   (readFile)
import           Data.Map               (Map, lookup, toList)
import           Data.Maybe             (fromJust)
import           HSLuv

maxDiff :: Double
maxDiff = 0.0000000001

maxRelDiff :: Double
maxRelDiff = 0.000000001

approxEqual :: Double -> Double -> Bool
approxEqual a b =
  let diff = abs (b - a)
  in diff <= maxDiff || diff <= maxRelDiff * max (abs a) (abs b)

approxEqualTriple ::
     (Double, Double, Double) -> (Double, Double, Double) -> Bool
approxEqualTriple (a, b, c) (d, e, f) =
  approxEqual a d && approxEqual b e && approxEqual c f

checkTestCase :: String -> TestCase -> Bool
checkTestCase hex cases =
  let rgb = fromJust $ Data.Map.lookup "rgb" cases
      xyz = fromJust $ Data.Map.lookup "xyz" cases
      luv = fromJust $ Data.Map.lookup "luv" cases
      lch = fromJust $ Data.Map.lookup "lch" cases
      hsluv = fromJust $ Data.Map.lookup "hsluv" cases
      hpluv = fromJust $ Data.Map.lookup "hpluv" cases
      rgb'@(RGB (RGBRed rgbr') (RGBGreen rgbg') (RGBBlue rgbb')) =
        fromJust $ hexToRgb hex
      xyz'@(XYZ (XYZX xyzx') (XYZY xyzy') (XYZZ xyzz')) = rgbToXyz rgb'
      luv'@(LUV (LUVLightness luvl') (LUVU luvu') (LUVV luvv')) = xyzToLuv xyz'
      lch'@(LCH (LCHLightness lchl') (LCHChroma lchc') (LCHHue lchh')) =
        luvToLch luv'
      hsluvLch'@(HSLuv (HSLuvHue hsluvLchh') (HSLuvSaturation hsluvLchs') (HSLuvLightness hsluvLchl')) =
        lchToHsluv lch'
      hpluvLch'@(HPLuv (HPLuvHue hpluvLchh') (HPLuvPastel hpluvLchp') (HPLuvLightness hpluvLchl')) =
        lchToHpluv lch'
      hsluvHex'@(HSLuv (HSLuvHue hsluvHexh') (HSLuvSaturation hsluvHexs') (HSLuvLightness hsluvHexl')) =
        fromJust $ hexToHsluv hex
      hpluvHex'@(HPLuv (HPLuvHue hpluvHexh') (HPLuvPastel hpluvHexp') (HPLuvLightness hpluvHexl')) =
        fromJust $ hexToHpluv hex
      lchHsluv'@(LCH (LCHLightness lchHsluvl') (LCHChroma lchHsluvc') (LCHHue lchHsluvh')) =
        hsluvToLch hsluvHex'
      lchHpluv'@(LCH (LCHLightness lchHpluvl') (LCHChroma lchHpluvc') (LCHHue lchHpluvh')) =
        hpluvToLch hpluvHex'
      luvLch'@(LUV (LUVLightness luvLchl') (LUVU luvLchu') (LUVV luvLchv')) =
        lchToLuv lchHsluv'
      xyzLuv'@(XYZ (XYZX xyzLuvx') (XYZY xyzLuvy') (XYZZ xyzLuvz')) =
        luvToXyz luvLch'
      rgbXyz'@(RGB (RGBRed rgbXyzr') (RGBGreen rgbXyzg') (RGBBlue rgbXyzb')) =
        xyzToRgb xyzLuv'
  in approxEqualTriple rgb (rgbr', rgbg', rgbb') &&
     approxEqualTriple xyz (xyzx', xyzy', xyzz') &&
     approxEqualTriple luv (luvl', luvu', luvv') &&
     approxEqualTriple lch (lchl', lchc', lchh') &&
     approxEqualTriple hsluv (hsluvLchh', hsluvLchs', hsluvLchl') &&
     approxEqualTriple hsluv (hsluvHexh', hsluvHexs', hsluvHexl') &&
     approxEqualTriple hpluv (hpluvLchh', hpluvLchp', hpluvLchl') &&
     approxEqualTriple hpluv (hpluvHexh', hpluvHexp', hpluvHexl') &&
     approxEqualTriple lch (lchHsluvl', lchHsluvc', lchHsluvh') &&
     approxEqualTriple lch (lchHpluvl', lchHpluvc', lchHpluvh') &&
     approxEqualTriple luv (luvLchl', luvLchu', luvLchv') &&
     approxEqualTriple xyz (xyzLuvx', xyzLuvy', xyzLuvz') &&
     approxEqualTriple rgb (rgbXyzr', rgbXyzg', rgbXyzb') &&
     hex == rgbToHex rgb' &&
     hex == hsluvToHex hsluvLch' &&
     hex == hpluvToHex hpluvLch' &&
     hex == hsluvToHex hsluvHex' && hex == hpluvToHex hpluvHex'

checkRgbBounds :: Bool
checkRgbBounds = all checkRgbBound $ liftM3 (,,) [0, 1] [0, 1] [0, 1]
  where
    checkRgbBound (r, g, b) =
      let RGB (RGBRed r') (RGBGreen g') (RGBBlue b') =
            hsluvToRgb . rgbToHsluv $ RGB (RGBRed r) (RGBGreen g) (RGBBlue b)
      in approxEqualTriple (r, g, b) (r', g', b')

type TestCase = Map String (Double, Double, Double)

type TestVectors = Map String TestCase

main :: IO ()
main = do
  testVectorsString <- Data.ByteString.Lazy.readFile "test/snapshot-rev4.json"
  let testVectors = fromJust (decode testVectorsString :: Maybe TestVectors)
  let vectorsCheck = all (uncurry checkTestCase) (Data.Map.toList testVectors)
  print $ assert (vectorsCheck && checkRgbBounds) "All tests pass."