Revision 1cdcf8f3
b/htools/Ganeti/HTools/QC.hs | ||
---|---|---|
537 | 537 |
cndlist = flist ++ tlist ++ [undefined] |
538 | 538 |
|
539 | 539 |
prop_Utils_parseUnit (NonNegative n) = |
540 |
Utils.parseUnit (show n) == Types.Ok n && |
|
541 |
Utils.parseUnit (show n ++ "m") == Types.Ok n && |
|
542 |
(case Utils.parseUnit (show n ++ "M") of |
|
543 |
Types.Ok m -> if n > 0 |
|
544 |
then m < n -- for positive values, X MB is < than X MiB |
|
545 |
else m == 0 -- but for 0, 0 MB == 0 MiB |
|
546 |
Types.Bad _ -> False) && |
|
547 |
Utils.parseUnit (show n ++ "g") == Types.Ok (n*1024) && |
|
548 |
Utils.parseUnit (show n ++ "t") == Types.Ok (n*1048576) && |
|
549 |
Types.isBad (Utils.parseUnit (show n ++ "x")::Types.Result Int) |
|
550 |
where _types = n::Int |
|
540 |
Utils.parseUnit (show n) ==? Types.Ok n .&&. |
|
541 |
Utils.parseUnit (show n ++ "m") ==? Types.Ok n .&&. |
|
542 |
Utils.parseUnit (show n ++ "M") ==? Types.Ok (truncate n_mb::Int) .&&. |
|
543 |
Utils.parseUnit (show n ++ "g") ==? Types.Ok (n*1024) .&&. |
|
544 |
Utils.parseUnit (show n ++ "G") ==? Types.Ok (truncate n_gb::Int) .&&. |
|
545 |
Utils.parseUnit (show n ++ "t") ==? Types.Ok (n*1048576) .&&. |
|
546 |
Utils.parseUnit (show n ++ "T") ==? Types.Ok (truncate n_tb::Int) .&&. |
|
547 |
printTestCase "Internal error/overflow?" |
|
548 |
(n_mb >=0 && n_gb >= 0 && n_tb >= 0) .&&. |
|
549 |
property (Types.isBad (Utils.parseUnit (show n ++ "x")::Types.Result Int)) |
|
550 |
where _types = (n::Int) |
|
551 |
n_mb = (fromIntegral n::Rational) * 1000 * 1000 / 1024 / 1024 |
|
552 |
n_gb = n_mb * 1000 |
|
553 |
n_tb = n_gb * 1000 |
|
551 | 554 |
|
552 | 555 |
-- | Test list for the Utils module. |
553 | 556 |
testSuite "Utils" |
b/htools/Ganeti/HTools/Utils.hs | ||
---|---|---|
40 | 40 |
|
41 | 41 |
import Data.Char (toUpper) |
42 | 42 |
import Data.List |
43 |
import Data.Ratio ((%)) |
|
43 | 44 |
|
44 | 45 |
import Debug.Trace |
45 | 46 |
|
... | ... | |
163 | 164 |
unlines . map ((++) lp) . map ((:) ' ' . unwords) $ |
164 | 165 |
formatTable (header:rows) isnum |
165 | 166 |
|
167 |
-- | Converts a unit (e.g. m or GB) into a scaling factor. |
|
168 |
parseUnitValue :: (Monad m) => String -> m Rational |
|
169 |
parseUnitValue unit |
|
170 |
-- binary conversions first |
|
171 |
| null unit = return 1 |
|
172 |
| unit == "m" || upper == "MIB" = return 1 |
|
173 |
| unit == "g" || upper == "GIB" = return kbBinary |
|
174 |
| unit == "t" || upper == "TIB" = return $ kbBinary * kbBinary |
|
175 |
-- SI conversions |
|
176 |
| unit == "M" || upper == "MB" = return mbFactor |
|
177 |
| unit == "G" || upper == "GB" = return $ mbFactor * kbDecimal |
|
178 |
| unit == "T" || upper == "TB" = return $ mbFactor * kbDecimal * kbDecimal |
|
179 |
| otherwise = fail $ "Unknown unit '" ++ unit ++ "'" |
|
180 |
where upper = map toUpper unit |
|
181 |
kbBinary = 1024 |
|
182 |
kbDecimal = 1000 |
|
183 |
decToBin = kbDecimal / kbBinary -- factor for 1K conversion |
|
184 |
mbFactor = decToBin * decToBin -- twice the factor for just 1K |
|
185 |
|
|
166 | 186 |
-- | Tries to extract number and scale from the given string. |
167 | 187 |
-- |
168 | 188 |
-- Input must be in the format NUMBER+ SPACE* [UNIT]. If no unit is |
... | ... | |
172 | 192 |
parseUnit str = |
173 | 193 |
-- TODO: enhance this by splitting the unit parsing code out and |
174 | 194 |
-- accepting floating-point numbers |
175 |
case reads str of
|
|
195 |
case (reads str::[(Int, String)]) of
|
|
176 | 196 |
[(v, suffix)] -> |
177 | 197 |
let unit = dropWhile (== ' ') suffix |
178 |
upper = map toUpper unit |
|
179 |
siConvert x = x * 1000000 `div` 1048576 |
|
180 |
in case () of |
|
181 |
_ | null unit -> return v |
|
182 |
| unit == "m" || upper == "MIB" -> return v |
|
183 |
| unit == "M" || upper == "MB" -> return $ siConvert v |
|
184 |
| unit == "g" || upper == "GIB" -> return $ v * 1024 |
|
185 |
| unit == "G" || upper == "GB" -> return $ siConvert |
|
186 |
(v * 1000) |
|
187 |
| unit == "t" || upper == "TIB" -> return $ v * 1048576 |
|
188 |
| unit == "T" || upper == "TB" -> return $ |
|
189 |
siConvert (v * 1000000) |
|
190 |
| otherwise -> fail $ "Unknown unit '" ++ unit ++ "'" |
|
198 |
in do |
|
199 |
scaling <- parseUnitValue unit |
|
200 |
return $ truncate (fromIntegral v * scaling) |
|
191 | 201 |
_ -> fail $ "Can't parse string '" ++ str ++ "'" |
Also available in: Unified diff