Revision 1cb92fac

b/htools/Ganeti/HTools/QC.hs
334 334
        tlist = map (\e -> (True, e)) lst2
335 335
        cndlist = flist ++ tlist ++ [undefined]
336 336

  
337
prop_Utils_parseUnit (NonNegative n) =
338
    Utils.parseUnit (show n) == Types.Ok n &&
339
    Utils.parseUnit (show n ++ "m") == Types.Ok n &&
340
    (case Utils.parseUnit (show n ++ "M") of
341
      Types.Ok m -> if n > 0
342
                    then m < n  -- for positive values, X MB is less than X MiB
343
                    else m == 0 -- but for 0, 0 MB == 0 MiB
344
      Types.Bad _ -> False) &&
345
    Utils.parseUnit (show n ++ "g") == Types.Ok (n*1024) &&
346
    Utils.parseUnit (show n ++ "t") == Types.Ok (n*1048576) &&
347
    Types.isBad (Utils.parseUnit (show n ++ "x")::Types.Result Int)
348
    where _types = (n::Int)
349

  
337 350
-- | Test list for the Utils module.
338 351
testUtils =
339 352
  [ run prop_Utils_commaJoinSplit
......
343 356
  , run prop_Utils_select
344 357
  , run prop_Utils_select_undefd
345 358
  , run prop_Utils_select_undefv
359
  , run prop_Utils_parseUnit
346 360
  ]
347 361

  
348 362
-- ** PeerMap tests
b/htools/Ganeti/HTools/Types.hs
264 264
data Result a
265 265
    = Bad String
266 266
    | Ok a
267
    deriving (Show, Read)
267
    deriving (Show, Read, Eq)
268 268

  
269 269
instance Monad Result where
270 270
    (>>=) (Bad x) _ = Bad x
b/htools/Ganeti/HTools/Utils.hs
46 46
    , formatTable
47 47
    , annotateResult
48 48
    , defaultGroupID
49
    , parseUnit
49 50
    ) where
50 51

  
51 52
import Control.Monad (liftM)
53
import Data.Char (toUpper)
52 54
import Data.List
53 55
import Data.Maybe (fromMaybe)
54 56
import qualified Text.JSON as J
......
252 254
-- | Default group UUID (just a string, not a real UUID).
253 255
defaultGroupID :: GroupID
254 256
defaultGroupID = "00000000-0000-0000-0000-000000000000"
257

  
258
-- | Tries to extract number and scale from the given string.
259
--
260
-- Input must be in the format NUMBER+ SPACE* [UNIT]. If no unit is
261
-- specified, it defaults to MiB. Return value is always an integral
262
-- value in MiB.
263
parseUnit :: (Monad m, Integral a, Read a) => String -> m a
264
parseUnit str =
265
    -- TODO: enhance this by splitting the unit parsing code out and
266
    -- accepting floating-point numbers
267
    case reads str of
268
      [(v, suffix)] ->
269
          let unit = dropWhile (== ' ') suffix
270
              upper = map toUpper unit
271
              siConvert x = x * 1000000 `div` 1048576
272
          in case () of
273
               _ | null unit -> return v
274
                 | unit == "m" || upper == "MIB" -> return v
275
                 | unit == "M" || upper == "MB"  -> return $ siConvert v
276
                 | unit == "g" || upper == "GIB" -> return $ v * 1024
277
                 | unit == "G" || upper == "GB"  -> return $ siConvert
278
                                                    (v * 1000)
279
                 | unit == "t" || upper == "TIB" -> return $ v * 1048576
280
                 | unit == "T" || upper == "TB"  -> return $
281
                                                    siConvert (v * 1000000)
282
                 | otherwise -> fail $ "Unknown unit '" ++ unit ++ "'"
283
      _ -> fail $ "Can't parse string '" ++ str ++ "'"

Also available in: Unified diff